#include "BilinearTransform.h" #include "polynome_functions.h" namespace fratio { template Butterworth::Butterworth(Type type) : m_type(type) { } template Butterworth::Butterworth(int order, T fc, T fs, Type type) : m_type(type) { initialize(order, fc, fs); } template void Butterworth::setFilterParameters(int order, T fc, T fs) { initialize(order, fc, fs); } template void Butterworth::initialize(int order, T fc, T fs) { if (order <= 0) { m_status = FilterStatus::BAD_ORDER_SIZE; return; } if (fc <= 0 || fs <= 0) { m_status = FilterStatus::BAD_FREQUENCY_VALUE; return; } if (m_fc > m_fs / 2.) { m_status = FilterStatus::BAD_CUTOFF_FREQUENCY; return; } m_order = order; m_fc = fc; m_fs = fs; computeDigitalRep(); resetFilter(); } template void Butterworth::computeDigitalRep() { // Continuous pre-warped frequency T fpw = (m_fs / PI) * std::tan(PI * m_fc / m_fs); // Compute poles std::complex analogPole; vectX_t> poles(m_order); for (int k = 1; k <= m_order; ++k) { analogPole = generateAnalogPole(fpw, k); BilinearTransform>::SToZ(m_fs, analogPole, poles(k - 1)); } vectX_t> zeros = generateAnalogZeros(); vectX_t> a = VietaAlgo>::polyCoeffFromRoot(poles); vectX_t> b = VietaAlgo>::polyCoeffFromRoot(zeros); vectX_t aCoeff(m_order + 1); vectX_t bCoeff(m_order + 1); for (int i = 0; i < m_order + 1; ++i) { aCoeff(i) = a(i).real(); bCoeff(i) = b(i).real(); } scaleAmplitude(aCoeff, bCoeff); setCoeffs(std::move(aCoeff), std::move(bCoeff)); } template std::complex Butterworth::generateAnalogPole(T fpw, int k) { T scaleFactor = 2 * PI * fpw; auto thetaK = [pi = PI, order = m_order](int k) -> T { return (2 * k - 1) * pi / (2 * order); }; std::complex analogPole(-std::sin(thetaK(k)), std::cos(thetaK(k))); switch (m_type) { case Type::HighPass: return scaleFactor / analogPole; case Type::LowPass: default: return scaleFactor * analogPole; } } template vectX_t> Butterworth::generateAnalogZeros() { switch (m_type) { case Type::HighPass: return vectX_t>::Constant(m_order, std::complex(1)); case Type::LowPass: default: return vectX_t>::Constant(m_order, std::complex(-1)); } } template void Butterworth::scaleAmplitude(Eigen::Ref> aCoeff, Eigen::Ref> bCoeff) { T scale = 0; T sumB = 0; switch (m_type) { case Type::HighPass: for (int i = 0; i < m_order + 1; ++i) { if (i % 2 == 0) { scale += aCoeff(i); sumB += bCoeff(i); } else { scale -= aCoeff(i); sumB -= bCoeff(i); } } break; case Type::LowPass: default: scale = aCoeff.sum(); sumB = bCoeff.sum(); break; } bCoeff *= scale / sumB; } } // namespace fratio