Skip to content

Commit cfdbb80

Browse files
Fix write_fine_calibration mangling Neuromag channel names (mne-tools#13999)
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
1 parent 5333084 commit cfdbb80

4 files changed

Lines changed: 42 additions & 0 deletions

File tree

doc/changes/dev/13999.bugfix.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fix bug where :func:`mne.preprocessing.write_fine_calibration` wrote internal ``MEG`` channel names (e.g. ``MEG0113``) instead of the bare channel numbers (e.g. ``113``) that MaxFilter expects, breaking round trips of Neuromag calibration files, by :newcontrib:`Apoorva Verma`.

doc/changes/names.inc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
.. _Antoine Gauthier: https://github.com/Okamille
3131
.. _Antti Rantala: https://github.com/Odingod
3232
.. _Apoorva Karekal: https://github.com/apoorva6262
33+
.. _Apoorva Verma: https://github.com/apoorva-01
3334
.. _Archit Singhal: https://github.com/architsinghal-mriirs
3435
.. _Arne Pelzer: https://github.com/aplzr
3536
.. _Ashley Drew: https://github.com/ashdrew

mne/preprocessing/_fine_cal.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -595,6 +595,15 @@ def write_fine_calibration(fname, calibration):
595595
keys = ("ch_names", "locs", "imb_cals")
596596
with open(fname, "wb") as cal_file:
597597
for ch_name, loc, imb_cal in zip(*(calibration[key] for key in keys)):
598+
# MaxFilter expects bare channel numbers, so undo the "MEG%04d"
599+
# renaming that read_fine_calibration applies to Neuromag channels.
600+
# Match only that 4-digit form, leaving e.g. KIT "MEG001" untouched.
601+
if (
602+
ch_name.startswith("MEG")
603+
and len(ch_name) == 7
604+
and ch_name[3:].isdigit()
605+
):
606+
ch_name = str(int(ch_name[3:]))
598607
cal_line = np.concatenate([loc, imb_cal]).round(6)
599608
cal_line = " ".join(f"{c:0.6f}" for c in cal_line)
600609
cal_file.write(f"{ch_name} {cal_line}\n".encode("ASCII"))

mne/preprocessing/tests/test_fine_cal.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,37 @@ def test_fine_cal_io(tmp_path, fname):
5959
assert object_diff(fine_cal_dict, fine_cal_dict_reload) == ""
6060

6161

62+
def test_fine_cal_io_preserves_channel_numbers(tmp_path):
63+
"""Test that writing keeps bare channel numbers MaxFilter expects (#13859)."""
64+
loc = " ".join(["0.000000"] * 12)
65+
src = tmp_path / "sss_cal.dat"
66+
# both 3-digit (zero-padded on read) and 4-digit channel numbers
67+
src.write_text(f"113\t{loc} -0.008282\n2643\t{loc} -0.005429\n")
68+
69+
cal = read_fine_calibration(src)
70+
# read_fine_calibration renames Neuromag channels to match raw.info
71+
assert cal["ch_names"] == ["MEG0113", "MEG2643"]
72+
73+
out = tmp_path / "out.dat"
74+
write_fine_calibration(out, cal)
75+
written_numbers = [line.split()[0] for line in out.read_text().splitlines()]
76+
assert written_numbers == ["113", "2643"]
77+
78+
79+
def test_fine_cal_io_keeps_non_neuromag_names(tmp_path):
80+
"""Test that writing leaves non-Neuromag channel names untouched."""
81+
loc = " ".join(["0.000000"] * 12)
82+
src = tmp_path / "sss_cal.dat"
83+
src.write_text(f"MLC11\t{loc} -0.008282\n")
84+
85+
cal = read_fine_calibration(src)
86+
assert cal["ch_names"] == ["MLC11"]
87+
88+
out = tmp_path / "out.dat"
89+
write_fine_calibration(out, cal)
90+
assert out.read_text().split()[0] == "MLC11"
91+
92+
6293
@testing.requires_testing_data
6394
@pytest.mark.parametrize(
6495
"kind",

0 commit comments

Comments
 (0)