161 qWarning() <<
"IirFilter::designButterworth: order must be >= 1, got" << iOrder;
165 const double dC = 2.0 * dSFreq;
168 double dOmegaLow = dC * std::tan(PI * dCutoffLow / dSFreq);
170 ? dC * std::tan(PI * dCutoffHigh / dSFreq)
174 QVector<std::complex<double>> protoPoles = butterworthPrototypePoles(iOrder);
176 QVector<IirBiquad> sos;
186 for (
int k = 0; k < iOrder; ++k) {
187 std::complex<double> proto = protoPoles[k];
190 if (proto.imag() < -1e-10) {
194 if (std::abs(proto.imag()) < 1e-10) {
196 double analogPole = (type ==
LowPass)
197 ? dOmegaLow * proto.real()
198 : dOmegaLow / proto.real();
203 IirBiquad bq = realPoleToDigitalSection(analogPole, dC, 1.0);
206 double w_pb = (type ==
LowPass) ? 0.0 : PI;
207 double num = std::abs(bq.
b0 + bq.
b1 * std::cos(-w_pb));
208 double den = std::abs(1.0 + bq.
a1 * std::cos(-w_pb));
209 double gain = (den > 1e-12 && num > 1e-12) ? den / num : 1.0;
216 std::complex<double> analogPole;
220 analogPole = dOmegaLow * proto;
221 sectionGain = dOmegaLow * dOmegaLow;
224 analogPole = dOmegaLow / proto;
229 IirBiquad bq = poleToDigitalBiquad(analogPole, dC, sectionGain);
232 double hDC = (bq.
b0 + bq.
b1 + bq.
b2) / (1.0 + bq.
a1 + bq.
a2);
233 if (std::abs(hDC) > 1e-12) {
234 double scale = 1.0 / std::abs(hDC);
235 bq.
b0 *= scale; bq.
b1 *= scale; bq.
b2 *= scale;
242 double omega0 = std::abs(analogPole);
243 double alpha = -analogPole.real();
244 double omega0sq = omega0 * omega0;
245 double d0 = dC * dC + 2.0 * alpha * dC + omega0sq;
248 bq.
b0 = dC * dC / d0;
249 bq.
b1 = -2.0 * dC * dC / d0;
250 bq.
b2 = dC * dC / d0;
251 bq.
a1 = 2.0 * (omega0sq - dC * dC) / d0;
252 bq.
a2 = (dC * dC - 2.0 * alpha * dC + omega0sq) / d0;
256 double hNy = (bq.
b0 - bq.
b1 + bq.
b2) / (1.0 - bq.
a1 + bq.
a2);
257 if (std::abs(hNy) > 1e-12) {
258 double scale = 1.0 / std::abs(hNy);
259 bq.
b0 *= scale; bq.
b1 *= scale; bq.
b2 *= scale;
273 double dOmega0 = std::sqrt(dOmegaLow * dOmegaHigh);
274 double dBw = dOmegaHigh - dOmegaLow;
276 for (
int k = 0; k < iOrder; ++k) {
277 std::complex<double> proto = protoPoles[k];
282 std::complex<double> mid;
289 std::complex<double> discriminant = mid * mid - 4.0 * dOmega0 * dOmega0;
290 std::complex<double> sqrtDisc = std::sqrt(discriminant);
291 std::complex<double> pole1 = (mid + sqrtDisc) / 2.0;
292 std::complex<double> pole2 = (mid - sqrtDisc) / 2.0;
298 for (
auto& pole : {pole1, pole2}) {
303 double omega0 = std::abs(pole);
304 double alpha = -pole.real();
305 double omega0sq = omega0 * omega0;
306 double d0 = dC * dC + 2.0 * alpha * dC + omega0sq;
310 bq.
b0 = dBw * dC / d0;
312 bq.
b2 = -dBw * dC / d0;
313 bq.
a1 = 2.0 * (omega0sq - dC * dC) / d0;
314 bq.
a2 = (dC * dC - 2.0 * alpha * dC + omega0sq) / d0;
320 double omega0 = std::abs(pole);
321 double alpha = -pole.real();
322 double omega0sq = omega0 * omega0;
323 double dOmega0sq = dOmega0 * dOmega0;
324 double d0 = dC * dC + 2.0 * alpha * dC + omega0sq;
329 bq.
b0 = (dC * dC + dOmega0sq) / d0;
330 bq.
b1 = 2.0 * (dOmega0sq - dC * dC) / d0;
331 bq.
b2 = (dC * dC + dOmega0sq) / d0;
332 bq.
a1 = 2.0 * (omega0sq - dC * dC) / d0;
333 bq.
a2 = (dC * dC - 2.0 * alpha * dC + omega0sq) / d0;
342 double omegaCheck = (type ==
BandPass)
343 ? 2.0 * std::atan(dOmega0 / dC)
345 double totalGain = evalMagnitude(sos, omegaCheck);
346 if (totalGain > 1e-12) {
347 double scale = 1.0 / totalGain;
349 double perSection = std::pow(scale, 1.0 / sos.size());