65 const double nyquist = dSFreq / 2.0;
67 double dCenterfreq = 0.0;
68 double dBandwidth = 0.0;
69 const double dParkswidth = dTransition / nyquist;
71 int iFilterType =
static_cast<int>(type);
76 dCenterfreq = dCutoffLow / nyquist;
81 dCenterfreq = (dCutoffLow + dCutoffHigh) / dSFreq;
82 dBandwidth = (dCutoffHigh - dCutoffLow) / nyquist;
89 sName = QStringLiteral(
"LP_%1Hz").arg(dCutoffLow);
92 sName = QStringLiteral(
"HP_%1Hz").arg(dCutoffLow);
95 sName = QStringLiteral(
"BP_%1-%2Hz").arg(dCutoffLow).arg(dCutoffHigh);
98 sName = QStringLiteral(
"BS_%1-%2Hz").arg(dCutoffLow).arg(dCutoffHigh);
109 static_cast<int>(method));
142 const RowVectorXi& vecPicks)
144 MatrixXd result = matData;
146 if (vecPicks.size() == 0) {
148 for (
int i = 0; i < result.rows(); ++i) {
149 RowVectorXd row = result.row(i);
153 for (
int k = 0; k < vecPicks.size(); ++k) {
155 if (i < 0 || i >= result.rows())
157 RowVectorXd row = result.row(i);
171 const double nyquist = dSFreq / 2.0;
172 const bool highPass = dLFreq > 0.0;
173 const bool lowPass = dHFreq > 0.0;
174 const double lTrans = highPass ? std::min(std::max(0.25 * dLFreq, 2.0), dLFreq) : 0.0;
175 const double hTrans = lowPass ? std::min(std::max(0.25 * dHFreq, 2.0), nyquist - dHFreq) : 0.0;
176 const double narrowest = std::min(highPass ? lTrans : INFINITY, lowPass ? hTrans : INFINITY);
178 int nTaps = std::max(
static_cast<int>(std::ceil(3.3 / narrowest * dSFreq)), 1);
179 nTaps += (nTaps - 1) % 2;
182 std::vector<double> freq{0.0};
183 std::vector<double> gain{highPass ? 0.0 : 1.0};
185 freq.insert(freq.end(), {dLFreq - lTrans, dLFreq});
186 gain.insert(gain.end(), {0.0, 1.0});
189 freq.insert(freq.end(), {dHFreq, dHFreq + hTrans});
190 gain.insert(gain.end(), {1.0, 0.0});
192 freq.push_back(nyquist);
193 gain.push_back(gain.back());
196 RowVectorXd h = RowVectorXd::Zero(nTaps);
197 if (gain.back() == 1.0) {
200 for (
int k =
static_cast<int>(freq.size()) - 2; k >= 0; --k) {
201 if (gain[k] == gain[k + 1]) {
204 const double transition = (freq[k + 1] - freq[k]) / nyquist / 2.0;
205 int nStep =
static_cast<int>(std::nearbyint(3.3 / transition));
206 nStep += 1 - nStep % 2;
207 const double cutoff = (freq[k + 1] + freq[k]) / 2.0 / nyquist;
208 RowVectorXd step(nStep);
209 for (
int n = 0; n < nStep; ++n) {
210 const double m = n - (nStep - 1) / 2.0;
211 const double sinc = m == 0.0 ? 1.0 : std::sin(
M_PI * cutoff * m) / (
M_PI * cutoff * m);
212 const double window = nStep > 1 ? 0.54 - 0.46 * std::cos(2.0 *
M_PI * n / (nStep - 1)) : 1.0;
213 step(n) = cutoff * sinc * window;
216 const int offset = (nTaps - nStep) / 2;
217 h.segment(offset, nStep) += (gain[k] == 0.0 ? -1.0 : 1.0) * step;
227 const RowVectorXd h =
designMne(dSFreq, dLFreq, dHFreq);
228 const Index nTimes = matData.cols();
229 const Index nH = h.size();
230 if (nTimes == 0 || nH == 1) {
231 return matData * (nH == 1 ? h(0) : 1.0);
233 const Index nEdge = std::min(nH, nTimes) - 1;
234 const Index nExt = nTimes + 2 * nEdge;
235 const Index nFft = nExt + nH - 1;
238 RowVectorXd hPadded = RowVectorXd::Zero(nFft);
239 hPadded.head(nH) = h;
241 fft.fwd(hSpec, hPadded);
243 MatrixXd out(matData.rows(), nTimes);
244 RowVectorXd ext = RowVectorXd::Zero(nFft);
247 for (Index r = 0; r < matData.rows(); ++r) {
248 const RowVectorXd x = matData.row(r);
251 for (Index i = 0; i < nEdge; ++i) {
252 ext(i) = 2.0 * x(0) - x(nEdge - i);
253 ext(nEdge + nTimes + i) = 2.0 * x(nTimes - 1) - x(nTimes - 2 - i);
255 ext.segment(nEdge, nTimes) = x;
257 spec = spec.cwiseProduct(hSpec);
259 out.row(r) = conv.segment(nEdge + (nH - 1) / 2, nTimes);
static FilterKernel design(int iOrder, FilterType type, double dCutoffLow, double dCutoffHigh, double dSFreq, double dTransition=5.0, DesignMethod method=Cosine)