v2.0.0
Loading...
Searching...
No Matches
filter_chpi.cpp
Go to the documentation of this file.
1//=============================================================================================================
12
13//=============================================================================================================
14// INCLUDES
15//=============================================================================================================
16
17#include "filter_chpi.h"
18#include "iirfilter.h"
19
20#include <fiff/fiff_info.h>
21#include <fiff/fiff_constants.h>
22
23//=============================================================================================================
24// QT INCLUDES
25//=============================================================================================================
26
27#include <QDebug>
28
29//=============================================================================================================
30// USED NAMESPACES
31//=============================================================================================================
32
33using namespace UTILSLIB;
34using namespace FIFFLIB;
35using namespace Eigen;
36
37//=============================================================================================================
38// STATIC HELPERS
39//=============================================================================================================
40
44static QVector<int> megChannelIndices(const FiffInfo& info)
45{
46 QVector<int> indices;
47 for (int i = 0; i < info.chs.size(); ++i) {
48 if (info.chs[i].kind == FIFFV_MEG_CH) {
49 indices.append(i);
50 }
51 }
52 return indices;
53}
54
55//=============================================================================================================
56// DEFINITIONS
57//=============================================================================================================
58
59void UTILSLIB::filterChpi(MatrixXd& data,
60 const FiffInfo& info,
61 double sfreq,
62 const QVector<double>& hpiFreqs,
63 const FilterChpiParams& params)
64{
65 if (hpiFreqs.isEmpty()) {
66 return;
67 }
68
69 if (sfreq <= 0.0) {
70 qWarning() << "filterChpi: Invalid sampling frequency" << sfreq << "Hz. Skipping.";
71 return;
72 }
73
74 const double dNyquist = sfreq / 2.0;
75
76 // Collect valid frequencies
77 QVector<double> validFreqs;
78 for (const double freq : hpiFreqs) {
79 const double fLow = freq - params.dNotchWidth;
80 const double fHigh = freq + params.dNotchWidth;
81 if (freq <= 0.0 || fHigh >= dNyquist) {
82 qWarning() << "filterChpi: Skipping invalid cHPI frequency" << freq
83 << "Hz (Nyquist =" << dNyquist << "Hz).";
84 continue;
85 }
86 if (fLow <= 0.0) {
87 qWarning() << "filterChpi: Skipping cHPI frequency" << freq
88 << "Hz (notch lower edge <= 0 Hz).";
89 continue;
90 }
91 validFreqs.append(freq);
92 }
93
94 if (validFreqs.isEmpty()) {
95 return;
96 }
97
98 if (params.bMegOnly) {
99 // Filter only MEG channels
100 const QVector<int> megIdx = megChannelIndices(info);
101 if (megIdx.isEmpty()) {
102 qWarning() << "filterChpi: No MEG channels found in FiffInfo. Nothing to filter.";
103 return;
104 }
105
106 // Extract MEG submatrix
107 MatrixXd megData(megIdx.size(), data.cols());
108 for (int i = 0; i < megIdx.size(); ++i) {
109 megData.row(i) = data.row(megIdx[i]);
110 }
111
112 // Apply notch filters sequentially
113 for (const double freq : validFreqs) {
114 const double fLow = freq - params.dNotchWidth;
115 const double fHigh = freq + params.dNotchWidth;
116
117 QVector<IirBiquad> sos = IirFilter::designButterworth(
118 params.iFilterOrder, IirFilter::BandStop, fLow, fHigh, sfreq);
119
120 megData = IirFilter::applyZeroPhaseMatrix(megData, sos);
121 }
122
123 // Write back
124 for (int i = 0; i < megIdx.size(); ++i) {
125 data.row(megIdx[i]) = megData.row(i);
126 }
127 } else {
128 // Filter all channels
129 for (const double freq : validFreqs) {
130 const double fLow = freq - params.dNotchWidth;
131 const double fHigh = freq + params.dNotchWidth;
132
133 QVector<IirBiquad> sos = IirFilter::designButterworth(
134 params.iFilterOrder, IirFilter::BandStop, fLow, fHigh, sfreq);
135
136 data = IirFilter::applyZeroPhaseMatrix(data, sos);
137 }
138 }
139}
140
141//=============================================================================================================
142
143void UTILSLIB::filterChpi(MatrixXd& data,
144 const FiffInfo& info,
145 double sfreq,
146 const FilterChpiParams& params)
147{
148 // Attempt to extract HPI coil frequencies from FiffInfo.
149 // The HPI frequency information may be stored in various FIFF blocks
150 // (FIFFB_HPI_MEAS, FIFFB_HPI_SUBSYSTEM), but the FiffInfo C++ struct
151 // does not currently expose a parsed list of HPI excitation frequencies.
152 // This overload is provided for API completeness; users should prefer
153 // passing frequencies explicitly.
154 Q_UNUSED(data)
155 Q_UNUSED(info)
156 Q_UNUSED(sfreq)
157 Q_UNUSED(params)
158
159 qWarning() << "filterChpi: Automatic cHPI frequency extraction from FiffInfo is not yet "
160 "implemented. Please provide frequencies explicitly via the hpiFreqs parameter.";
161}
Symbolic FIFF tag, block, value, unit and channel-type constants shared across FIFFLIB.
#define FIFFV_MEG_CH
Full FIFF measurement metadata: everything from FIFFB_MEAS / FIFFB_MEAS_INFO needed to interpret a re...
Butterworth IIR filter design and application via numerically stable second-order sections.
Declaration of filterChpi — cHPI signal removal by notch filtering.
FIFF file I/O, in-memory data structures and high-level readers/writers.
Shared utilities (I/O helpers, spectral analysis, layout management, warp algorithms).
DSPSHARED_EXPORT void filterChpi(Eigen::MatrixXd &data, const FIFFLIB::FiffInfo &info, double sfreq, const QVector< double > &hpiFreqs, const FilterChpiParams &params=FilterChpiParams())
Remove cHPI excitation signals from MEG data by notch filtering.
Parameters for cHPI notch filtering.
Definition filter_chpi.h:56
static QVector< IirBiquad > designButterworth(int iOrder, FilterType type, double dCutoffLow, double dCutoffHigh, double dSFreq)
static Eigen::MatrixXd applyZeroPhaseMatrix(const Eigen::MatrixXd &matData, const QVector< IirBiquad > &sos)
Full FIFF measurement info: per-channel descriptors, sampling and filter setup, projectors,...
Definition fiff_info.h:88
QList< FiffChInfo > chs