#include namespace fratio { // Public static functions template std::string GenericFilter::filterStatus(FilterStatus status) { switch (status) { case FilterStatus::NONE: return "Filter is uninitialized"; case FilterStatus::READY: return "Filter is ready to be used"; case FilterStatus::ALL_COEFF_MISSING: return "Filter has none of its coefficient initialized"; case FilterStatus::A_COEFF_MISSING: return "Filter has its 'a' coefficients uninitialized"; case FilterStatus::A_COEFF_MISSING: return "Filter has its 'b' coefficients uninitialized"; case FilterStatus::BAD_CUTOFF_FREQUENCY: return "Filter has a received a bad cut-off frequency. It must be inferior to the sampling frequency"; default: return "I forgot to implement this error documentation"; } } // Public functions template T GenericFilter::stepFilter(const T& data) { assert(m_status == FilterStatus::READY); // Slide data (can't use SIMD, but should be small) for (auto rit1 = m_rawData.rbegin(), rit2 = m_rawData.rbegin() + 1; rit2 != m_rawData.rend(); ++rit1, ++rit2) *rit1 = *rit2; for (auto rit1 = m_filteredData.rbegin(), rit2 = m_filteredData.rbegin() + 1; rit2 != m_filteredData.rend(); ++rit1, ++rit2) *rit1 = *rit2; m_rawData[0] = data; m_filteredData[0] = m_bCoeff.dot(m_rawData) - m_aCoeff.dot(m_filteredData); return m_filteredData[0]; } template Eigen::VectorX GenericFilter::filter(const Eigen::VectorX& data) { Eigen::VectorX results(data.size()); if (!getFilterResults(results, data)) return Eigen::VectorX(); return results; } template bool GenericFilter::getFilterResults(Eigen::Ref> results, const Eigen::VectorX& data) { assert(m_status == FilterStatus::READY); if (results.size() != data.size()) return false; T* res = results.data(); for (T d : data) *(res++) = stepFilter(d); return true; } template void GenericFilter::resetFilter() { m_filteredData.setZero(m_aCoeff.size()); m_rawData.setZero(m_bCoeff.size()); } template bool GenericFilter::setCoeffs(const std::vector& aCoeff, const std::vector& bCoeff) { if (!checkCoeffs(aCoeff, bCoeff)) return false; m_aCoeff = Eigen::Map>(aCoeff.data(), aCoeff.size()); m_bCoeff = Eigen::Map>(bCoeff.data(), bCoeff.size()); resetFilter(); normalizeCoeffs(); return true; } template void GenericFilter::setCoeffs(const Eigen::VectorX& aCoeff, const Eigen::VectorX& bCoeff) { if (!checkCoeffs(aCoeff, bCoeff)) return false; m_aCoeff = aCoeff; m_bCoeff = bCoeff; resetFilter(); normalizeCoeffs(); return true; } template void GenericFilter::getCoeffs(std::vector& aCoeff, std::vector& bCoeff) const { aCoeff.assign(m_aCoeff.data(), m_aCoeff.data() + m_aCoeff.size()); bCoeff.assign(m_bCoeff.data(), m_bCoeff.data() + m_bCoeff.size()); } template void GenericFilter::getCoeffs(Eigen::Ref> aCoeff, Eigen::Ref> bCoeff) const { aCoeff = m_aCoeff; bCoeff = m_bCoeff; } // Protected functions template GenericFilter::GenericFilter(const Eigen::VectorX& aCoeff, const Eigen::VectorX& bCoeff) : m_aCoeff(aCoeff) , m_bCoeff(bCoeff) , m_filteredData(aCoeff.size()) , m_rawData(bCoeff.size()) { if(!checkCoeffs(aCoeff, bCoeff)) return; resetFilter(); normalizeCoeffs(); } template void GenericFilter::normalizeCoeffs() { assert(m_status == FilterStatus::READY); T a0 = m_aCoeff(0); if (std::abs(a0 - T(1)) < std::numeric_limits::epsilon()) return; m_aCoeff /= a0; m_bCoeff /= a0; } template template bool GenericFilter::checkCoeffs(const T2& aCoeff, const T2& bCoeff) { using namespace FilterStatus; m_status = NONE; if (aCoeff.size() == 0) m_status = A_COEFF_MISSING; else if (std::abs(aCoeff[0]) < std::numeric_limits::epsilon()) m_status = BAD_A_COEFF; if (bCoeff.size() == 0) m_status = (m_status == A_COEFF_MISSING ? ALL_COEFF_MISSING : B_COEFF_MISSING); if (m_status == NONE) m_status = READY; return m_status == READY; } } // namespace fratio