DiFipp/include/Butterworth.tpp

140 wiersze
3.3 KiB
Plaintext
Czysty Zwykły widok Historia

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