Skip to content

Commit 42f909a

Browse files
authored
Retain detailed info about calculations during NoisyChannels (#68)
* Collect additional debug info * Fix extra info to be order-independent
1 parent 032cad1 commit 42f909a

File tree

2 files changed

+39
-1
lines changed

2 files changed

+39
-1
lines changed

pyprep/find_noisy_channels.py

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,15 @@ def __init__(self, raw, do_detrend=True, random_state=None):
6464
self.ch_names_new = self.ch_names_original
6565
self.channels_interpolate = self.original_channels
6666

67+
# Extra data for debugging
68+
self._extra_info = {
69+
'bad_by_deviation': {},
70+
'bad_by_hf_noise': {},
71+
'bad_by_correlation': {},
72+
'bad_by_dropout': {},
73+
'bad_by_ransac': {}
74+
}
75+
6776
# random_state
6877
self.random_state = check_random_state(random_state)
6978

@@ -207,6 +216,11 @@ def find_bad_by_deviation(self, deviation_threshold=5.0):
207216
deviation_channels = self.channels_interpolate[deviation_channel_mask]
208217
for i in range(0, len(deviation_channels)):
209218
self.bad_by_deviation.append(self.ch_names_original[deviation_channels[i]])
219+
self._extra_info['bad_by_deviation'].update({
220+
'median_channel_deviation': channel_deviationMedian,
221+
'channel_deviation_sd': channel_deviationSD,
222+
'robust_channel_deviations': robust_channel_deviation
223+
})
210224

211225
def find_bad_by_hfnoise(self, HF_zscore_threshold=5.0):
212226
"""Determine noise of channel through high frequency ratio.
@@ -262,6 +276,11 @@ def find_bad_by_hfnoise(self, HF_zscore_threshold=5.0):
262276
self.EEGData = np.transpose(EEG_filt)
263277
for i in range(0, len(HFNoise_channels)):
264278
self.bad_by_hf_noise.append(self.ch_names_original[HFNoise_channels[i]])
279+
self._extra_info['bad_by_hf_noise'].update({
280+
'median_channel_noisiness': noisiness_median,
281+
'channel_noisiness_sd': noiseSD,
282+
'hf_noise_zscores': zscore_HFNoise
283+
})
265284

266285
def find_bad_by_correlation(
267286
self, correlation_secs=1.0, correlation_threshold=0.4, frac_bad=0.01
@@ -358,6 +377,17 @@ def find_bad_by_correlation(
358377
dropout_channels_idx = np.argwhere(fraction_BadDropOutWindows > frac_bad)
359378
dropout_channels_name = self.ch_names_original[dropout_channels_idx.astype(int)]
360379
self.bad_by_dropout = [i[0] for i in dropout_channels_name]
380+
self._extra_info['bad_by_correlation'] = {
381+
'max_correlations': maximum_correlations,
382+
'median_max_correlations': np.median(maximum_correlations, axis=1),
383+
'bad_window_fractions': fraction_BadCorrelationWindows
384+
}
385+
self._extra_info['bad_by_dropout'] = {
386+
'dropouts': drop_out,
387+
'bad_window_fractions': fraction_BadDropOutWindows
388+
}
389+
self._extra_info['bad_by_deviation']['channel_deviations'] = channel_deviations
390+
self._extra_info['bad_by_hf_noise']['noise_levels'] = noiselevels
361391

362392
def find_bad_by_SNR(self):
363393
"""Determine the channels that fail both by correlation and HF noise."""
@@ -426,7 +456,7 @@ def find_bad_by_ransac(
426456
self.bad_by_deviation +
427457
self.bad_by_dropout
428458
)
429-
self.bad_by_ransac, _ = find_bad_by_ransac(
459+
self.bad_by_ransac, ch_correlations = find_bad_by_ransac(
430460
self.EEGData,
431461
self.sample_rate,
432462
self.signal_len,
@@ -441,3 +471,7 @@ def find_bad_by_ransac(
441471
channel_wise,
442472
self.random_state,
443473
)
474+
self._extra_info['bad_by_ransac'] = {
475+
'ransac_correlations': ch_correlations,
476+
'bad_window_fractions': np.mean(ch_correlations < corr_thresh, axis=0)
477+
}

pyprep/reference.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ def __init__(self, raw, params, ransac=True, random_state=None):
5757
self.sfreq = self.raw.info["sfreq"]
5858
self.ransac = ransac
5959
self.random_state = check_random_state(random_state)
60+
self._extra_info = {}
6061

6162
def perform_reference(self):
6263
"""Estimate the true signal mean and interpolate bad channels.
@@ -108,6 +109,7 @@ def perform_reference(self):
108109
"bad_by_ransac": noisy_detector.bad_by_ransac,
109110
"bad_all": noisy_detector.get_bads(),
110111
}
112+
self._extra_info['interpolated'] = noisy_detector._extra_info
111113

112114
bad_channels = _union(self.bad_before_interpolation, self.unusable_channels)
113115
self.raw.info["bads"] = bad_channels
@@ -141,6 +143,7 @@ def perform_reference(self):
141143
"bad_by_ransac": noisy_detector.bad_by_ransac,
142144
"bad_all": noisy_detector.get_bads(),
143145
}
146+
self._extra_info['remaining_bad'] = noisy_detector._extra_info
144147

145148
return self
146149

@@ -183,6 +186,7 @@ def robust_reference(self):
183186
"bad_by_ransac": noisy_detector.bad_by_ransac,
184187
"bad_all": noisy_detector.get_bads(),
185188
}
189+
self._extra_info['initial_bad'] = noisy_detector._extra_info
186190

187191
self.noisy_channels = self.noisy_channels_original.copy()
188192
logger.info("Bad channels: {}".format(self.noisy_channels))

0 commit comments

Comments
 (0)