Skip to content

Commit 9aace45

Browse files
authored
Merge pull request #49 from ajithabhks/13-support-metronix-txt-for-calibration
13 support metronix txt for calibration
2 parents 100f081 + db73c1e commit 9aace45

File tree

7 files changed

+177
-61
lines changed

7 files changed

+177
-61
lines changed

sigmt/__version__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
"""
22
Returns version of the package
33
"""
4-
__version__ = "2.0.7"
4+
__version__ = "2.1.0"

sigmt/core/band_averaging.py

Lines changed: 31 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -113,49 +113,46 @@ def __init__(self,
113113
- 'sensor_serial_number': 300 (int)
114114
- 'chopper_status': 1 (int) 1 means 0N, 0 means OFF
115115
- 'calibration_data' (dict)
116-
- '300' (dict) - key is coil number
117-
- 'chopper_on' (ndarray, shape: n,3)
118-
n - number of frequencies
119-
First column: Frequency (Hz)
120-
Second column: Magnitude (V/nT*Hz)
121-
Third column: Phase (deg)
122-
- 'chopper_off' (ndarray, shape: n,3)
123-
n - number of frequencies
124-
First column: Frequency (Hz)
125-
Second column: Magnitude (V/nT*Hz)
126-
Third column: Phase (deg)
116+
- 'chopper_on' (ndarray, shape: n,3)
117+
n - number of frequencies
118+
First column: Frequency (Hz)
119+
Second column: Magnitude (V/nT*Hz)
120+
Third column: Phase (deg)
121+
- 'chopper_off' (ndarray, shape: n,3)
122+
n - number of frequencies
123+
First column: Frequency (Hz)
124+
Second column: Magnitude (V/nT*Hz)
125+
Third column: Phase (deg)
127126
- 'hy' (dict) details of hx coil
128127
- 'sensor_type': 'MFS06e' (str)
129128
- 'sensor_serial_number': 301 (int)
130129
- 'chopper_status': 1 (int) 1 means 0N, 0 means OFF
131130
- 'calibration_data' (dict)
132-
- '301' (dict) - key is coil number
133-
- 'chopper_on' (ndarray, shape: n,3)
134-
n - number of frequencies
135-
First column: Frequency (Hz)
136-
Second column: Magnitude (V/nT*Hz)
137-
Third column: Phase (deg)
138-
- 'chopper_off' (ndarray, shape: n,3)
139-
n - number of frequencies
140-
First column: Frequency (Hz)
141-
Second column: Magnitude (V/nT*Hz)
142-
Third column: Phase (deg)
131+
- 'chopper_on' (ndarray, shape: n,3)
132+
n - number of frequencies
133+
First column: Frequency (Hz)
134+
Second column: Magnitude (V/nT*Hz)
135+
Third column: Phase (deg)
136+
- 'chopper_off' (ndarray, shape: n,3)
137+
n - number of frequencies
138+
First column: Frequency (Hz)
139+
Second column: Magnitude (V/nT*Hz)
140+
Third column: Phase (deg)
143141
- 'hz' (dict) details of hx coil
144142
- 'sensor_type': 'MFS06e' (str)
145143
- 'sensor_serial_number': 301 (int)
146144
- 'chopper_status': 1 (int) 1 means 0N, 0 means OFF
147145
- 'calibration_data' (dict)
148-
- '302' (dict) - key is coil number
149-
- 'chopper_on' (ndarray, shape: n,3)
150-
n - number of frequencies
151-
First column: Frequency (Hz)
152-
Second column: Magnitude (V/nT*Hz)
153-
Third column: Phase (deg)
154-
- 'chopper_off' (ndarray, shape: n,3)
155-
n - number of frequencies
156-
First column: Frequency (Hz)
157-
Second column: Magnitude (V/nT*Hz)
158-
Third column: Phase (deg)
146+
- 'chopper_on' (ndarray, shape: n,3)
147+
n - number of frequencies
148+
First column: Frequency (Hz)
149+
Second column: Magnitude (V/nT*Hz)
150+
Third column: Phase (deg)
151+
- 'chopper_off' (ndarray, shape: n,3)
152+
n - number of frequencies
153+
First column: Frequency (Hz)
154+
Second column: Magnitude (V/nT*Hz)
155+
Third column: Phase (deg)
159156
:type calibration_data_magnetic: dict
160157
:param apply_notch_filter: A boolean flag indicating whether a notch filter should be applied. Default is False.
161158
:type apply_notch_filter: bool
@@ -270,15 +267,13 @@ def calibrate_magnetic(self) -> None:
270267
for channel in magnetic_channels:
271268
if self.calibration_data_magnetic['instrument'] == 'metronix':
272269
sensor_type = self.calibration_data_magnetic[channel]['sensor_type']
273-
sensor_serial_number = str(self.calibration_data_magnetic[channel]['sensor_serial_number'])
274270
if self.calibration_data_magnetic[channel]['chopper_status'] == 1:
275271
chopper_status = "chopper_on"
276272
elif self.calibration_data_magnetic[channel]['chopper_status'] == 0:
277273
chopper_status = "chopper_off"
278274
else:
279275
chopper_status = None
280-
calibration_data = self.calibration_data_magnetic[channel]['calibration_data'][sensor_serial_number][
281-
chopper_status]
276+
calibration_data = self.calibration_data_magnetic[channel]['calibration_data'][chopper_status]
282277
calibration_object = MetronixCalibration(self.spectra[channel], self.fft_frequencies,
283278
sensor_type,
284279
chopper_status, calibration_data)

sigmt/gui/metronix.py

Lines changed: 66 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
import os
77
import time
8+
from pathlib import Path
89

910
import h5py
1011
import numpy as np
@@ -20,6 +21,7 @@
2021
QApplication, QProgressDialog)
2122
from scipy import signal
2223

24+
import sigmt.utils.metronix.cal_from_metronix_txt
2325
from sigmt.core import data_selection_tools as dstools
2426
from sigmt.core import perform_data_selection as pds
2527
from sigmt.core import plots
@@ -804,8 +806,7 @@ def read_ts(self) -> None:
804806
for local_path in local_paths:
805807
self.header[f'ts_{num}'], ts_dict = metronix_utils.read_ts(local_path,
806808
self.project_setup)
807-
self.xml_caldata[f'ts_{num}'] = metronix_utils.read_calibration_from_xml(
808-
local_path)
809+
self.xml_caldata[f'ts_{num}'] = metronix_utils.read_calibration_from_xml(local_path)
809810
ts = f.create_group(f'ts_{num}')
810811
for key in ts_dict.keys():
811812
ts.create_dataset(key, data=ts_dict[key].values)
@@ -831,8 +832,7 @@ def read_ts(self) -> None:
831832
for local_path, remote_path in zip(local_paths, remote_paths):
832833
self.header[f'ts_{num}'], ts_dict = metronix_utils.read_ts(local_path,
833834
self.project_setup)
834-
self.xml_caldata[f'ts_{num}'] = metronix_utils.read_calibration_from_xml(
835-
local_path)
835+
self.xml_caldata[f'ts_{num}'] = metronix_utils.read_calibration_from_xml(local_path)
836836
ts = f.create_group(f'ts_{num}')
837837
for key in ts_dict.keys():
838838
ts.create_dataset(key, data=ts_dict[key].values)
@@ -1090,7 +1090,68 @@ def perform_bandavg(self) -> None:
10901090
self.header[ts][magnetic_channel]['sensor_no'][0]
10911091
calibration_data_magnetic[magnetic_channel]['chopper_status'] = \
10921092
self.header[ts][magnetic_channel]['bychopper'][0]
1093-
calibration_data_magnetic[magnetic_channel]['calibration_data'] = self.xml_caldata[ts]
1093+
1094+
if calibration_data_magnetic[magnetic_channel]['chopper_status'] == 0:
1095+
chopper_status = 'chopper_off'
1096+
elif calibration_data_magnetic[magnetic_channel]['chopper_status'] == 1:
1097+
chopper_status = 'chopper_on'
1098+
else:
1099+
chopper_status = None
1100+
1101+
print('\n')
1102+
print('====================================================')
1103+
print(f'Working on calibration data for {magnetic_channel}')
1104+
print(f'Coil serial number: {str(calibration_data_magnetic[magnetic_channel]['sensor_serial_number'])}')
1105+
print('\n')
1106+
1107+
cal_data_xml = self.xml_caldata[ts][
1108+
str(calibration_data_magnetic[magnetic_channel]['sensor_serial_number'])]
1109+
1110+
metronix_txt_filename = (calibration_data_magnetic[magnetic_channel]["sensor_type"].lower()
1111+
+ "_"
1112+
+ str(calibration_data_magnetic[magnetic_channel]["sensor_serial_number"])
1113+
)
1114+
cal_txt_path = Path(self.project_dir) / "calibration_files" / f"{metronix_txt_filename}.txt"
1115+
if cal_txt_path.exists():
1116+
print('Metronix txt calibration file found.')
1117+
cal_data_txt = sigmt.utils.metronix.cal_from_metronix_txt.read_calibration_metronix_txt(
1118+
filepath=cal_txt_path)
1119+
else:
1120+
cal_data_txt = None
1121+
print(f'Metronix txt calibration file not found at {cal_txt_path}')
1122+
1123+
if self.project_setup['preferred_cal_file'] == 'xml':
1124+
print('Preferred calibration file selected: xml')
1125+
if cal_data_xml[chopper_status].size != 0:
1126+
print('Using calibration data from XML file.')
1127+
calibration_data_magnetic[magnetic_channel]['calibration_data'] = cal_data_xml
1128+
else:
1129+
print('No calibration data is available from XML file.')
1130+
print('Trying metronix txt.')
1131+
if (cal_data_txt is None) or (cal_data_txt[chopper_status].size == 0):
1132+
print('No calibration data is available from Metronix txt.')
1133+
calibration_data_magnetic[magnetic_channel]['calibration_data'] = None
1134+
else:
1135+
print('Calibration data found from Metronix txt. Using it.')
1136+
calibration_data_magnetic[magnetic_channel]['calibration_data'] = cal_data_txt
1137+
elif self.project_setup['preferred_cal_file'] == 'metronix_txt':
1138+
print('Preferred calibration file selected: metronix_txt')
1139+
if (cal_data_txt is not None) and (cal_data_txt[chopper_status].size != 0):
1140+
print('Using calibration data from metronix_txt file.')
1141+
calibration_data_magnetic[magnetic_channel]['calibration_data'] = cal_data_txt
1142+
else:
1143+
print('No calibration data is available from metronix_txt file.')
1144+
print('Trying XML.')
1145+
if cal_data_xml[chopper_status].size == 0:
1146+
print('No calibration data is available from XML.')
1147+
calibration_data_magnetic[magnetic_channel]['calibration_data'] = None
1148+
else:
1149+
print('Calibration data found from XML. Using it.')
1150+
calibration_data_magnetic[magnetic_channel]['calibration_data'] = cal_data_xml
1151+
else:
1152+
calibration_data_magnetic[magnetic_channel]['calibration_data'] = None
1153+
print('====================================================')
1154+
print('\n')
10941155

10951156
# Get the bandavg object
10961157
bandavg = BandAveraging(time_series=metronix_utils.prepare_ts_from_h5(self.h5file, ts),

sigmt/gui/project_related/create_project.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,7 @@ def __init__(self, parent=None, interface=None):
4545
self.notch_frequency = QLineEdit('50')
4646
self.preferred_cal_file = QComboBox()
4747
self.preferred_cal_file.addItem('xml')
48-
# TODO: Support use of metronix text file in future
49-
# self.preferred_cal_file.addItem('metronix txt')
48+
self.preferred_cal_file.addItem('metronix_txt')
5049

5150
layout.addWidget(QLabel("Project Name:"))
5251
layout.addWidget(self.project_name)

sigmt/gui/project_related/edit_project.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,7 @@ def __init__(self, parent=None, interface=None, project_setup=None):
4141
self.notch_frequency = QLineEdit(self.project_setup['notch_frequency'])
4242
self.preferred_cal_file = QComboBox()
4343
self.preferred_cal_file.addItem('xml')
44-
# TODO: Add this in future
45-
# self.preferred_cal_file.addItem('metronix txt')
44+
self.preferred_cal_file.addItem('metronix_txt')
4645
self.preferred_cal_file.setCurrentText(self.project_setup['preferred_cal_file'])
4746

4847
layout.addWidget(QLabel("Project Name:"))
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
import numpy as np
2+
3+
4+
def read_calibration_metronix_txt(filepath):
5+
"""
6+
Read calibration data "chopper_on" and "chopper_off" from Metronix calibration
7+
txt file.
8+
9+
:param filepath: File path
10+
:type filepath: str or Path
11+
12+
:return: Dictionary containing chopper_off and chopper_on data as numpy arrays
13+
:rtype: dict
14+
15+
"""
16+
calibration_data = {}
17+
with open(filepath, "r") as f:
18+
lines = f.readlines()
19+
20+
chopper_on = []
21+
chopper_off = []
22+
23+
current_section = None
24+
25+
for line in lines:
26+
line = line.strip()
27+
28+
# Detect section headers
29+
if line.startswith("Chopper On"):
30+
current_section = "on"
31+
continue
32+
elif line.startswith("Chopper Off"):
33+
current_section = "off"
34+
continue
35+
36+
# Skip empty or non-data lines
37+
if not line or line.startswith("FREQUENCY"):
38+
continue
39+
40+
# Parse numeric rows
41+
try:
42+
parts = line.split()
43+
if len(parts) == 3:
44+
freq, mag, phase = map(float, parts)
45+
if current_section == "on":
46+
chopper_on.append([freq, mag, phase])
47+
elif current_section == "off":
48+
chopper_off.append([freq, mag, phase])
49+
except ValueError:
50+
continue
51+
52+
# Convert to numpy arrays
53+
chopper_on = np.array(chopper_on)
54+
chopper_off = np.array(chopper_off)
55+
56+
calibration_data['chopper_on'] = chopper_on
57+
calibration_data['chopper_off'] = chopper_off
58+
59+
return calibration_data

sigmt/utils/metronix/metronix_utils.py

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -277,23 +277,26 @@ def read_calibration_from_xml(meas_path: str) -> dict:
277277
:rtype: dict
278278
279279
"""
280-
caldata = {}
281-
xmlfiles = []
280+
calibration_data = {}
281+
xml_files = []
282282
for file in os.listdir(meas_path):
283283
if file.endswith(".xml"):
284-
xmlfiles.append(file)
285-
xmlfile = os.path.join(meas_path, xmlfiles[0])
286-
287-
channels_info = cal_from_xml.extract_channel_info(xmlfile)
288-
289-
# Filter out channels with types 'Ex' and 'Ey'
290-
filtered_channels = cal_from_xml.filter_channels(channels_info, ['Ex', 'Ey'])
291-
filtered_channel_ids = [channel[0] for channel in filtered_channels]
292-
293-
for filtered_channel_id, val in zip(filtered_channel_ids, filtered_channels):
294-
caldata[val[2]] = cal_from_xml.read_cal_data(xmlfile, filtered_channel_id)
295-
296-
return caldata
284+
xml_files.append(file)
285+
if len(xml_files) == 0:
286+
print("No XML found.")
287+
calibration_data = None
288+
else:
289+
print("XML found. Attempting to read calibration data.")
290+
xml_file = os.path.join(meas_path, xml_files[0])
291+
channels_info = cal_from_xml.extract_channel_info(xml_file)
292+
# Filter out channels with types 'Ex' and 'Ey'
293+
filtered_channels = cal_from_xml.filter_channels(channels_info, ['Ex', 'Ey'])
294+
filtered_channel_ids = [channel[0] for channel in filtered_channels]
295+
for filtered_channel_id, val in zip(filtered_channel_ids, filtered_channels):
296+
calibration_data[val[2]] = cal_from_xml.read_cal_data(xml_file, filtered_channel_id)
297+
print("Calibration data reading from XML done!")
298+
299+
return calibration_data
297300

298301

299302
def prepare_ts_from_h5(h5file_path: str, ts_key: str) -> dict:

0 commit comments

Comments
 (0)