Digital filter test ok.

topic/diffentiators
Vincent Samy 2018-12-17 17:16:01 +09:00
rodzic d55ee89a7d
commit 6ab21d6145
16 zmienionych plików z 121 dodań i 142 usunięć

Wyświetl plik

@ -11,9 +11,9 @@ struct BilinearTransform {
static_assert(std::is_floating_point<SubType>::value, "This struct can only accept floating point types (real and complex).");
static void SToZ(SubType fs, const T& sPlanePole, T& zPlanePole);
static void SToZ(SubType fs, const Eigen::VectorX<T>& sPlanePoles, Eigen::Ref<Eigen::VectorX<T>>& zPlanePoles); // Can be optimized
static void SToZ(SubType fs, const vectX_t<T>& sPlanePoles, Eigen::Ref<vectX_t<T>>& zPlanePoles); // Can be optimized
static void ZToS(SubType fs, const T& zPlanePole, T& sPlanePole);
static void ZToS(SubType fs, const Eigen::VectorX<T>& zPlanePoles, Eigen::Ref<Eigen::VectorX<T>>& sPlanePoles); // Can be optimized
static void ZToS(SubType fs, const vectX_t<T>& zPlanePoles, Eigen::Ref<vectX_t<T>>& sPlanePoles); // Can be optimized
};
template <typename T>
@ -24,7 +24,7 @@ void BilinearTransform<T>::SToZ(SubType fs, const T& sPlanePole, T& zPlanePole)
}
template <typename T>
void BilinearTransform<T>::SToZ(SubType fs, const Eigen::VectorX<T>& sPlanePoles, Eigen::Ref<Eigen::VectorX<T>>& zPlanePoles)
void BilinearTransform<T>::SToZ(SubType fs, const vectX_t<T>& sPlanePoles, Eigen::Ref<vectX_t<T>>& zPlanePoles)
{
assert(sPlanePoles.size() == zPlanePoles.size());
for (Eigen::Index k = 0; k < sPlanePoles.size(); ++k)
@ -39,7 +39,7 @@ void BilinearTransform<T>::ZToS(SubType fs, const T& zPlanePole, T& sPlanePole)
}
template <typename T>
void BilinearTransform<T>::ZToS(SubType fs, const Eigen::VectorX<T>& zPlanePoles, Eigen::Ref<Eigen::VectorX<T>>& sPlanePoles)
void BilinearTransform<T>::ZToS(SubType fs, const vectX_t<T>& zPlanePoles, Eigen::Ref<vectX_t<T>>& sPlanePoles)
{
assert(zPlanePoles.size() == sPlanePoles.size());
for (Eigen::Index k = 0; k < sPlanePoles.size(); ++k)

Wyświetl plik

@ -31,15 +31,15 @@ private:
void initialize(int order, T fc, T fs);
void computeDigitalRep();
std::complex<T> generateAnalogPole(T fpw, int k);
Eigen::VectorX<std::complex<T>> generateAnalogZeros();
void scaleAmplitude(Eigen::Ref<Eigen::VectorX<T>> aCoeff, Eigen::Ref<Eigen::VectorX<T>> bCoeff);
vectX_t<std::complex<T>> generateAnalogZeros();
void scaleAmplitude(Eigen::Ref<vectX_t<T>> aCoeff, Eigen::Ref<vectX_t<T>> bCoeff);
private:
Type m_type;
int m_order;
T m_fc;
T m_fs;
Eigen::VectorX<std::complex<T>> m_poles;
vectX_t<std::complex<T>> m_poles;
};
} // namespace fratio

Wyświetl plik

@ -55,17 +55,17 @@ void Butterworth<T>::computeDigitalRep()
// Compute poles
std::complex<T> analogPole;
Eigen::VectorX<std::complex<T>> poles(m_order);
vectX_t<std::complex<T>> poles(m_order);
for (int k = 1; k <= m_order; ++k) {
analogPole = generateAnalogPole(fpw, k);
BilinearTransform<std::complex<T>>::SToZ(m_fs, analogPole, poles(k - 1));
}
Eigen::VectorX<std::complex<T>> zeros = generateAnalogZeros();
Eigen::VectorX<std::complex<T>> a = VietaAlgo<std::complex<T>>::polyCoeffFromRoot(poles);
Eigen::VectorX<std::complex<T>> b = VietaAlgo<std::complex<T>>::polyCoeffFromRoot(zeros);
Eigen::VectorX<T> aCoeff(m_order + 1);
Eigen::VectorX<T> bCoeff(m_order + 1);
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);
for (int i = 0; i < m_order + 1; ++i) {
aCoeff(i) = a(i).real();
bCoeff(i) = b(i).real();
@ -96,20 +96,20 @@ std::complex<T> Butterworth<T>::generateAnalogPole(T fpw, int k)
}
template <typename T>
Eigen::VectorX<std::complex<T>> Butterworth<T>::generateAnalogZeros()
vectX_t<std::complex<T>> Butterworth<T>::generateAnalogZeros()
{
switch (m_type) {
case Type::HighPass:
return Eigen::VectorX<std::complex<T>>::Constant(m_order, std::complex<T>(1));
return vectX_t<std::complex<T>>::Constant(m_order, std::complex<T>(1));
case Type::LowPass:
default:
return Eigen::VectorX<std::complex<T>>::Constant(m_order, std::complex<T>(-1));
return vectX_t<std::complex<T>>::Constant(m_order, std::complex<T>(-1));
}
}
template <typename T>
void Butterworth<T>::scaleAmplitude(Eigen::Ref<Eigen::VectorX<T>> aCoeff, Eigen::Ref<Eigen::VectorX<T>> bCoeff)
void Butterworth<T>::scaleAmplitude(Eigen::Ref<vectX_t<T>> aCoeff, Eigen::Ref<vectX_t<T>> bCoeff)
{
T scale = 0;
T sumB = 0;

Wyświetl plik

@ -5,11 +5,12 @@
namespace fratio {
// https://www.mathworks.com/help/dsp/ug/how-is-moving-average-filter-different-from-an-fir-filter.html
template <typename T>
class DigitalFilter : public GenericFilter<T> {
public:
DigitalFilter() = default;
DigitalFilter(const Eigen::VectorX<T>& aCoeff, const Eigen::VectorX<T>& bCoeff)
DigitalFilter(const vectX_t<T>& aCoeff, const vectX_t<T>& bCoeff)
: GenericFilter<T>(aCoeff, bCoeff)
{
}

Wyświetl plik

@ -17,34 +17,34 @@ public:
public:
// Careful: Only an assert check for the filter status
T stepFilter(const T& data);
Eigen::VectorX<T> filter(const Eigen::VectorX<T>& data);
bool getFilterResults(Eigen::Ref<Eigen::VectorX<T>> results, const Eigen::VectorX<T>& data);
vectX_t<T> filter(const vectX_t<T>& data);
bool getFilterResults(Eigen::Ref<vectX_t<T>> results, const vectX_t<T>& data);
void resetFilter();
template <typename T2>
bool setCoeffs(T2&& aCoeff, T2&& bCoeff);
void getCoeffs(Eigen::VectorX<T>& aCoeff, Eigen::VectorX<T>& bCoeff) const;
void getCoeffs(vectX_t<T>& aCoeff, vectX_t<T>& bCoeff) const;
FilterStatus status() const noexcept { return m_status; }
Eigen::Index aOrder() const noexcept { return m_aCoeff.size(); }
Eigen::Index bOrder() const noexcept { return m_bCoeff.size(); }
protected:
GenericFilter() = default;
GenericFilter(const Eigen::VectorX<T>& aCoeff, const Eigen::VectorX<T>& bCoeff);
GenericFilter(const vectX_t<T>& aCoeff, const vectX_t<T>& bCoeff);
virtual ~GenericFilter() = default;
void normalizeCoeffs();
bool checkCoeffs(const Eigen::VectorX<T>& aCoeff, const Eigen::VectorX<T>& bCoeff);
bool checkCoeffs(const vectX_t<T>& aCoeff, const vectX_t<T>& bCoeff);
protected:
FilterStatus m_status;
private:
Eigen::VectorX<T> m_aCoeff;
Eigen::VectorX<T> m_bCoeff;
Eigen::VectorX<T> m_filteredData;
Eigen::VectorX<T> m_rawData;
vectX_t<T> m_aCoeff;
vectX_t<T> m_bCoeff;
vectX_t<T> m_filteredData;
vectX_t<T> m_rawData;
};
} // namespace fratio

Wyświetl plik

@ -17,7 +17,7 @@ std::string GenericFilter<T>::filterStatus(FilterStatus status)
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:
case FilterStatus::B_COEFF_MISSING:
return "Filter has its 'b' coefficients uninitialized";
case FilterStatus::BAD_FREQUENCY_VALUE:
return "Filter has a received a frequency that is negative or equal to zero";
@ -37,25 +37,26 @@ T GenericFilter<T>::stepFilter(const T& data)
// Slide data (can't use SIMD, but should be small)
m_rawData.tail(m_rawData.size() - 1) = m_rawData.head(m_rawData.size() - 1);
m_filteredData.tail(m_rawData.size() - 1) = m_filteredData.head(m_rawData.size() - 1);
m_filteredData.tail(m_filteredData.size() - 1) = m_filteredData.head(m_filteredData.size() - 1);
m_rawData[0] = data;
m_filteredData[0] = 0;
m_filteredData[0] = m_bCoeff.dot(m_rawData) - m_aCoeff.dot(m_filteredData);
return m_filteredData[0];
}
template <typename T>
Eigen::VectorX<T> GenericFilter<T>::filter(const Eigen::VectorX<T>& data)
vectX_t<T> GenericFilter<T>::filter(const vectX_t<T>& data)
{
Eigen::VectorX<T> results(data.size());
vectX_t<T> results(data.size());
if (!getFilterResults(results, data))
return Eigen::VectorX<T>();
return vectX_t<T>();
return results;
}
template <typename T>
bool GenericFilter<T>::getFilterResults(Eigen::Ref<Eigen::VectorX<T>> results, const Eigen::VectorX<T>& data)
bool GenericFilter<T>::getFilterResults(Eigen::Ref<vectX_t<T>> results, const vectX_t<T>& data)
{
assert(m_status == FilterStatus::READY);
if (results.size() != data.size())
@ -78,7 +79,7 @@ template <typename T>
template <typename T2>
bool GenericFilter<T>::setCoeffs(T2&& aCoeff, T2&& bCoeff)
{
static_assert(std::is_same_v<T2, Eigen::VectorX<T>>, "The coefficents should be of type Eigen::VectorX<T>");
static_assert(std::is_same_v<T2, vectX_t<T>>, "The coefficents should be of type vectX_t<T>");
if (!checkCoeffs(aCoeff, bCoeff))
return false;
@ -91,7 +92,7 @@ bool GenericFilter<T>::setCoeffs(T2&& aCoeff, T2&& bCoeff)
}
template <typename T>
void GenericFilter<T>::getCoeffs(Eigen::VectorX<T>& aCoeff, Eigen::VectorX<T>& bCoeff) const
void GenericFilter<T>::getCoeffs(vectX_t<T>& aCoeff, vectX_t<T>& bCoeff) const
{
aCoeff = m_aCoeff;
bCoeff = m_bCoeff;
@ -100,7 +101,7 @@ void GenericFilter<T>::getCoeffs(Eigen::VectorX<T>& aCoeff, Eigen::VectorX<T>& b
// Protected functions
template <typename T>
GenericFilter<T>::GenericFilter(const Eigen::VectorX<T>& aCoeff, const Eigen::VectorX<T>& bCoeff)
GenericFilter<T>::GenericFilter(const vectX_t<T>& aCoeff, const vectX_t<T>& bCoeff)
: m_aCoeff(aCoeff)
, m_bCoeff(bCoeff)
, m_filteredData(aCoeff.size())
@ -127,7 +128,7 @@ void GenericFilter<T>::normalizeCoeffs()
}
template <typename T>
bool GenericFilter<T>::checkCoeffs(const Eigen::VectorX<T>& aCoeff, const Eigen::VectorX<T>& bCoeff)
bool GenericFilter<T>::checkCoeffs(const vectX_t<T>& aCoeff, const vectX_t<T>& bCoeff)
{
m_status = FilterStatus::NONE;
if (aCoeff.size() == 0)

Wyświetl plik

@ -10,7 +10,7 @@ class MovingAverage : public DigitalFilter<T> {
public:
MovingAverage() = default;
MovingAverage(int windowSize)
: DigitalFilter<T>(Eigen::VectorX<T>::Constant(1, T(1)), Eigen::VectorX<T>::Constant(windowSize, T(1) / windowSize))
: DigitalFilter<T>(vectX_t<T>::Constant(1, T(1)), vectX_t<T>::Constant(windowSize, T(1) / windowSize))
{
}
@ -21,7 +21,7 @@ public:
return;
}
setCoeffs(Eigen::VectorX<T>::Constant(1, T(1)), Eigen::VectorX<T>::Constant(windowSize, T(1) / windowSize));
setCoeffs(vectX_t<T>::Constant(1, T(1)), vectX_t<T>::Constant(windowSize, T(1) / windowSize));
}
int windowSize() const noexcept { return bOrder(); }
};

Wyświetl plik

@ -11,30 +11,19 @@ struct VietaAlgo {
static_assert(std::is_arithmetic<internal::complex_sub_type_t<T>>::value, "This struct can only accept arithmetic types or complex.");
// Vieta's computation: https://en.wikipedia.org/wiki/Vieta%27s_formulas
static Eigen::VectorX<T> polyCoeffFromRoot(const Eigen::VectorX<T>& poles);
static vectX_t<T> polyCoeffFromRoot(const vectX_t<T>& poles);
};
template <typename T>
Eigen::VectorX<T> VietaAlgo<T>::polyCoeffFromRoot(const Eigen::VectorX<T>& poles)
vectX_t<T> VietaAlgo<T>::polyCoeffFromRoot(const vectX_t<T>& poles)
{
Eigen::VectorX<T> coeffs = Eigen::VectorX<T>::Zero(poles.size() + 1);
vectX_t<T> coeffs = vectX_t<T>::Zero(poles.size() + 1);
coeffs(0) = T(1);
for (Eigen::Index i = 0; i < poles.size(); ++i) {
for (Eigen::Index k = i + 1; k > 0; --k) {
coeffs(k) -= poles(i) * coeffs(k - 1);
}
}
// Check for equation c(k) = sum(i=k-1, poles.size() : p(i)) * c(k-1), k>=1
// Eigen::Index pSize = poles.size();
// for (Eigen::Index k = 1; k < coeffs.size(); ++k)
// coeffs(k) -= poles.tail(pSize - (k - 1)).sum() * coeffs(k - 1);
// Maybe better
// T sum = poles.sum();
// for (Eigen::Index k = 1; k < coeffs.size(); ++k) {
// coeffs(k) -= sum * coeffs(k - 1);
// sum -= poles(k - 1);
// }
return coeffs;
}

Wyświetl plik

@ -2,14 +2,10 @@
#include <Eigen/Core>
namespace Eigen {
namespace fratio {
template <typename T>
using VectorX = Eigen::Matrix<T, Eigen::Dynamic, 1>;
} // namespace Eigen
namespace fratio {
using vectX_t = Eigen::Matrix<T, Eigen::Dynamic, 1>;
enum class FilterStatus {
// Generic filter

Wyświetl plik

@ -8,13 +8,13 @@ DISABLE_CONVERSION_WARNING_BEGIN
template <typename T>
struct System {
Eigen::VectorX<T> data = (Eigen::VectorX<T>(8) << 1, 2, 3, 4, 5, 6, 7, 8).finished();
fratio::vectX_t<T> data = (fratio::vectX_t<T>(8) << 1, 2, 3, 4, 5, 6, 7, 8).finished();
int order = 5;
T fc = 10;
T fs = 100;
Eigen::VectorX<T> aCoeffRes = (Eigen::VectorX<T>(6) << 1.000000000000000, -2.975422109745684, 3.806018119320413, -2.545252868330468, 0.881130075437837, -0.125430622155356).finished();
Eigen::VectorX<T> bCoeffRes = (Eigen::VectorX<T>(6) << 0.001282581078961, 0.006412905394803, 0.012825810789607, 0.012825810789607, 0.006412905394803, 0.001282581078961).finished();
Eigen::VectorX<T> results = (Eigen::VectorX<T>(8) << 0.001282581078961, 0.012794287652606, 0.062686244350084, 0.203933712825708, 0.502244959135609, 1.010304217144175, 1.744652693589064, 2.678087381460197).finished();
fratio::vectX_t<T> aCoeffRes = (fratio::vectX_t<T>(6) << 1.000000000000000, -2.975422109745684, 3.806018119320413, -2.545252868330468, 0.881130075437837, -0.125430622155356).finished();
fratio::vectX_t<T> bCoeffRes = (fratio::vectX_t<T>(6) << 0.001282581078961, 0.006412905394803, 0.012825810789607, 0.012825810789607, 0.006412905394803, 0.001282581078961).finished();
fratio::vectX_t<T> results = (fratio::vectX_t<T>(8) << 0.001282581078961, 0.012794287652606, 0.062686244350084, 0.203933712825708, 0.502244959135609, 1.010304217144175, 1.744652693589064, 2.678087381460197).finished();
};
DISABLE_CONVERSION_WARNING_END
@ -24,7 +24,7 @@ BOOST_FIXTURE_TEST_CASE(BUTTERWORTH_FILTER_FLOAT, System<float>)
auto bf = fratio::Butterworthf(order, fc, fs);
std::vector<float> filteredData;
Eigen::VectorX<float> aCoeff, bCoeff;
fratio::vectX_t<float> aCoeff, bCoeff;
bf.getCoeffs(aCoeff, bCoeff);
BOOST_REQUIRE_EQUAL(aCoeff.size(), aCoeffRes.size());
@ -63,7 +63,7 @@ BOOST_FIXTURE_TEST_CASE(BUTTERWORTH_FILTER_DOUBLE, System<double>)
auto bf = fratio::Butterworthd(order, fc, fs);
std::vector<double> filteredData;
Eigen::VectorX<double> aCoeff, bCoeff;
fratio::vectX_t<double> aCoeff, bCoeff;
bf.getCoeffs(aCoeff, bCoeff);
BOOST_REQUIRE_EQUAL(aCoeff.size(), aCoeffRes.size());

Wyświetl plik

@ -20,8 +20,8 @@ macro(addTest testName)
GENERATE_MSVC_DOT_USER_FILE(${testName})
endmacro(addTest)
# addTest(GenericFilterTests)
# addTest(polynome_functions_tests)
addTest(GenericFilterTests)
addTest(polynome_functions_tests)
addTest(DigitalFilterTests)
# addTest(MovingAverageFilterTests)
addTest(MovingAverageFilterTests)
# addTest(ButterWorthFilterTests)

Wyświetl plik

@ -1,6 +1,7 @@
#define BOOST_TEST_MODULE DigitalFilterTests
#include "fratio"
#include "test_functions.h"
#include "warning_macro.h"
#include <boost/test/unit_test.hpp>
@ -8,10 +9,10 @@ DISABLE_CONVERSION_WARNING_BEGIN
template <typename T>
struct System {
Eigen::VectorX<T> data = (Eigen::VectorX<T>(4) << 1, 2, 3, 4).finished();
Eigen::VectorX<T> aCoeff = (Eigen::VectorX<T>(2) << 1, -0.99993717).finished();
Eigen::VectorX<T> bCoeff = (Eigen::VectorX<T>(2) << 0.99996859, -0.99996859).finished();
Eigen::VectorX<T> results = (Eigen::VectorX<T>(4) << 0.99996859, 1.999874351973491, 2.999717289867956, 3.999497407630634).finished();
fratio::vectX_t<T> data = (fratio::vectX_t<T>(4) << 1, 2, 3, 4).finished();
fratio::vectX_t<T> aCoeff = (fratio::vectX_t<T>(2) << 1, -0.99993717).finished();
fratio::vectX_t<T> bCoeff = (fratio::vectX_t<T>(2) << 0.99996859, -0.99996859).finished();
fratio::vectX_t<T> results = (fratio::vectX_t<T>(4) << 0.99996859, 1.999874351973491, 2.999717289867956, 3.999497407630634).finished();
};
DISABLE_CONVERSION_WARNING_END
@ -19,39 +20,13 @@ DISABLE_CONVERSION_WARNING_END
BOOST_FIXTURE_TEST_CASE(DIGITAL_FILTER_FLOAT, System<float>)
{
auto df = fratio::DigitalFilterf(aCoeff, bCoeff);
BOOST_REQUIRE_EQUAL(aCoeff.size(), df.aOrder());
BOOST_REQUIRE_EQUAL(bCoeff.size(), df.bOrder());
std::vector<float> filteredData;
for (Eigen::Index i = 0; i < data.size(); ++i)
filteredData.push_back(df.stepFilter(data(i)));
for (size_t i = 0; i < filteredData.size(); ++i)
BOOST_CHECK_SMALL(std::abs(filteredData[i] - results(i)), 1e-6f);
df.resetFilter();
Eigen::VectorXf fData = df.filter(data);
for (Eigen::Index i = 0; i < fData.size(); ++i)
BOOST_CHECK_SMALL(std::abs(fData(i) - results(i)), 1e-6f);
test_coeffs(aCoeff, bCoeff, df);
test_results(results, data, df);
}
BOOST_FIXTURE_TEST_CASE(DIGITAL_FILTER_DOUBLE, System<double>)
{
auto df = fratio::DigitalFilterd(aCoeff, bCoeff);
BOOST_REQUIRE_EQUAL(aCoeff.size(), df.aOrder());
BOOST_REQUIRE_EQUAL(bCoeff.size(), df.bOrder());
std::vector<double> filteredData;
for (Eigen::Index i = 0; i < data.size(); ++i)
filteredData.push_back(df.stepFilter(data(i)));
for (size_t i = 0; i < filteredData.size(); ++i)
BOOST_CHECK_SMALL(std::abs(filteredData[i] - results(i)), 1e-14);
df.resetFilter();
Eigen::VectorXd fData = df.filter(data);
for (Eigen::Index i = 0; i < fData.size(); ++i)
BOOST_CHECK_SMALL(std::abs(fData(i) - results(i)), 1e-14);
test_coeffs(aCoeff, bCoeff, df);
test_results(results, data, df);
}

Wyświetl plik

@ -4,7 +4,7 @@
#include <boost/test/unit_test.hpp>
#include <vector>
BOOST_AUTO_TEST_CASE(FilterThrows)
BOOST_AUTO_TEST_CASE(FILTER_FAILURES)
{
auto dfd = fratio::DigitalFilterd(Eigen::VectorXd(), Eigen::VectorXd::Constant(2, 0));
BOOST_REQUIRE(dfd.status() == fratio::FilterStatus::A_COEFF_MISSING);

Wyświetl plik

@ -1,43 +1,24 @@
#define BOOST_TEST_MODULE MovingAverageFilterTests
#include "fratio"
#include "test_functions.h"
#include <boost/test/unit_test.hpp>
template <typename T>
struct System {
Eigen::VectorX<T> data = (Eigen::VectorX<T>(6) << 1, 2, 3, 4, 5, 6).finished();
size_t windowSize = 4;
Eigen::VectorX<T> results = (Eigen::VectorX<T>(6) << 0.25, 0.75, 1.5, 2.5, 3.5, 4.5).finished();
fratio::vectX_t<T> data = (fratio::vectX_t<T>(6) << 1, 2, 3, 4, 5, 6).finished();
int windowSize = 4;
fratio::vectX_t<T> results = (fratio::vectX_t<T>(6) << 0.25, 0.75, 1.5, 2.5, 3.5, 4.5).finished();
};
BOOST_FIXTURE_TEST_CASE(MOVING_AVERAGE_FLOAT, System<float>)
{
auto maf = fratio::MovingAveragef(windowSize);
std::vector<float> filteredData;
for (Eigen::Index i = 0; i < data.size(); ++i)
filteredData.push_back(maf.stepFilter(data(i)));
for (size_t i = 0; i < filteredData.size(); ++i)
BOOST_CHECK_SMALL(std::abs(filteredData[i] - results(i)), 1e-6f);
maf.resetFilter();
Eigen::VectorXf fData = maf.filter(data);
for (Eigen::Index i = 0; i < fData.size(); ++i)
BOOST_CHECK_SMALL(std::abs(fData(i) - results(i)), 1e-6f);
test_results(results, data, maf);
}
BOOST_FIXTURE_TEST_CASE(MOVING_AVERAGE_DOUBLE, System<double>)
{
auto maf = fratio::MovingAveraged(windowSize);
std::vector<double> filteredData;
for (Eigen::Index i = 0; i < data.size(); ++i)
filteredData.push_back(maf.stepFilter(data(i)));
for (size_t i = 0; i < filteredData.size(); ++i)
BOOST_CHECK_SMALL(std::abs(filteredData[i] - results[i]), 1e-14);
maf.resetFilter();
Eigen::VectorXd fData = maf.filter(data);
for (Eigen::Index i = 0; i < fData.size(); ++i)
BOOST_CHECK_SMALL(std::abs(fData(i) - results(i)), 1e-14);
test_results(results, data, maf);
}

Wyświetl plik

@ -3,33 +3,34 @@
#include "fratio"
#include "warning_macro.h"
#include <boost/test/unit_test.hpp>
#include <limits>
using c_int_t = std::complex<int>;
template <typename T>
using c_t = std::complex<T>;
struct SystemInt {
Eigen::VectorX<int> data = (Eigen::VectorX<int>(4) << 1, 1, 1, 1).finished();
Eigen::VectorX<int> results = (Eigen::VectorX<int>(5) << 1, -4, 6, -4, 1).finished();
fratio::vectX_t<int> data = (fratio::vectX_t<int>(4) << 1, 1, 1, 1).finished();
fratio::vectX_t<int> results = (fratio::vectX_t<int>(5) << 1, -4, 6, -4, 1).finished();
};
struct SystemCInt {
Eigen::VectorX<c_int_t> data = (Eigen::VectorX<c_int_t>(4) << c_int_t{ 1, 1 }, c_int_t{ -1, 4 }, c_int_t{ 12, -3 }, c_int_t{ 5, 2 }).finished();
Eigen::VectorX<c_int_t> results = (Eigen::VectorX<c_int_t>(5) << c_int_t{ 1, 0 }, c_int_t{ -17, -4 }, c_int_t{ 66, 97 }, c_int_t{ 127, -386 }, c_int_t{ -357, 153 }).finished();
fratio::vectX_t<c_int_t> data = (fratio::vectX_t<c_int_t>(4) << c_int_t{ 1, 1 }, c_int_t{ -1, 4 }, c_int_t{ 12, -3 }, c_int_t{ 5, 2 }).finished();
fratio::vectX_t<c_int_t> results = (fratio::vectX_t<c_int_t>(5) << c_int_t{ 1, 0 }, c_int_t{ -17, -4 }, c_int_t{ 66, 97 }, c_int_t{ 127, -386 }, c_int_t{ -357, 153 }).finished();
};
DISABLE_CONVERSION_WARNING_BEGIN
template <typename T>
struct SystemFloat {
Eigen::VectorX<T> data = (Eigen::VectorX<T>(4) << 0.32, -0.0518, 41.4, 0.89).finished();
Eigen::VectorX<T> results = (Eigen::VectorX<T>(5) << 1, -42.558199999999999, 48.171601999999993, -9.181098159999999, -0.610759296).finished();
fratio::vectX_t<T> data = (fratio::vectX_t<T>(4) << 0.32, -0.0518, 41.4, 0.89).finished();
fratio::vectX_t<T> results = (fratio::vectX_t<T>(5) << 1, -42.558199999999999, 48.171601999999993, -9.181098159999999, -0.610759296).finished();
};
template <typename T>
struct SystemCFloat {
Eigen::VectorX<c_t<T>> data = (Eigen::VectorX<c_t<T>>(4) << c_t<T>{ 1.35, 0.2 }, c_t<T>{ -1.5, 4.45 }, c_t<T>{ 12.8, -3.36 }, c_t<T>{ 5.156, 2.12 }).finished();
Eigen::VectorX<c_t<T>> results = (Eigen::VectorX<c_t<T>>(5) << c_t<T>{ 1, 0 }, c_t<T>{ -17.806, -3.41 }, c_t<T>{ 73.2776, 99.20074 }, c_t<T>{ 101.857496, -444.634694 }, c_t<T>{ -269.1458768, 388.7308864 }).finished();
fratio::vectX_t<c_t<T>> data = (fratio::vectX_t<c_t<T>>(4) << c_t<T>{ 1.35, 0.2 }, c_t<T>{ -1.5, 4.45 }, c_t<T>{ 12.8, -3.36 }, c_t<T>{ 5.156, 2.12 }).finished();
fratio::vectX_t<c_t<T>> results = (fratio::vectX_t<c_t<T>>(5) << c_t<T>{ 1, 0 }, c_t<T>{ -17.806, -3.41 }, c_t<T>{ 73.2776, 99.20074 }, c_t<T>{ 101.857496, -444.634694 }, c_t<T>{ -269.1458768, 388.7308864 }).finished();
};
DISABLE_CONVERSION_WARNING_END
@ -39,7 +40,7 @@ BOOST_FIXTURE_TEST_CASE(POLYNOME_FUNCTION_INT, SystemInt)
auto res = fratio::VietaAlgoi::polyCoeffFromRoot(data);
for (Eigen::Index i = 0; i < res.size(); ++i)
BOOST_CHECK_EQUAL(res(i), results(i));
BOOST_REQUIRE_EQUAL(res(i), results(i));
}
BOOST_FIXTURE_TEST_CASE(POLYNOME_FUNCTION_FLOAT, SystemFloat<float>)
@ -47,7 +48,7 @@ BOOST_FIXTURE_TEST_CASE(POLYNOME_FUNCTION_FLOAT, SystemFloat<float>)
auto res = fratio::VietaAlgof::polyCoeffFromRoot(data);
for (Eigen::Index i = 0; i < res.size(); ++i)
BOOST_CHECK_SMALL(std::abs(res(i) - results(i)), 1e-6f);
BOOST_REQUIRE_SMALL(std::abs(res(i) - results(i)), std::numeric_limits<float>::epsilon() * 1000);
}
BOOST_FIXTURE_TEST_CASE(POLYNOME_FUNCTION_DOUBLE, SystemFloat<double>)
@ -55,7 +56,7 @@ BOOST_FIXTURE_TEST_CASE(POLYNOME_FUNCTION_DOUBLE, SystemFloat<double>)
auto res = fratio::VietaAlgod::polyCoeffFromRoot(data);
for (Eigen::Index i = 0; i < res.size(); ++i)
BOOST_CHECK_SMALL(std::abs(res(i) - results(i)), 1e-14);
BOOST_REQUIRE_SMALL(std::abs(res(i) - results(i)), std::numeric_limits<double>::epsilon() * 1000);
}
BOOST_FIXTURE_TEST_CASE(POLYNOME_FUNCTION_CINT, SystemCInt)
@ -63,7 +64,7 @@ BOOST_FIXTURE_TEST_CASE(POLYNOME_FUNCTION_CINT, SystemCInt)
auto res = fratio::VietaAlgoci::polyCoeffFromRoot(data);
for (Eigen::Index i = 0; i < res.size(); ++i)
BOOST_CHECK_EQUAL(res(i), results(i));
BOOST_REQUIRE_EQUAL(res(i), results(i));
}
BOOST_FIXTURE_TEST_CASE(POLYNOME_FUNCTION_CFLOAT, SystemCFloat<float>)
@ -71,7 +72,7 @@ BOOST_FIXTURE_TEST_CASE(POLYNOME_FUNCTION_CFLOAT, SystemCFloat<float>)
auto res = fratio::VietaAlgocf::polyCoeffFromRoot(data);
for (Eigen::Index i = 0; i < res.size(); ++i)
BOOST_CHECK_SMALL(std::abs(res(i) - results(i)), 1e-4f);
BOOST_REQUIRE_SMALL(std::abs(res(i) - results(i)), std::numeric_limits<float>::epsilon() * 1000);
}
BOOST_FIXTURE_TEST_CASE(POLYNOME_FUNCTION_CDOUBLE, SystemCFloat<double>)
@ -79,5 +80,5 @@ BOOST_FIXTURE_TEST_CASE(POLYNOME_FUNCTION_CDOUBLE, SystemCFloat<double>)
auto res = fratio::VietaAlgocd::polyCoeffFromRoot(data);
for (Eigen::Index i = 0; i < res.size(); ++i)
BOOST_CHECK_SMALL(std::abs(res(i) - results(i)), 1e-12);
BOOST_REQUIRE_SMALL(std::abs(res(i) - results(i)), std::numeric_limits<double>::epsilon() * 1000);
}

Wyświetl plik

@ -0,0 +1,35 @@
#pragma once
#include "fratio"
#include <boost/test/unit_test.hpp>
#include <limits>
template <typename T>
void test_coeffs(const fratio::vectX_t<T>& aCoeff, const fratio::vectX_t<T>& bCoeff, const fratio::GenericFilter<T>& filter)
{
BOOST_REQUIRE_EQUAL(aCoeff.size(), filter.aOrder());
BOOST_REQUIRE_EQUAL(bCoeff.size(), filter.bOrder());
fratio::vectX_t<T> faCoeff, fbCoeff;
filter.getCoeffs(faCoeff, fbCoeff);
for (Eigen::Index i = 0; i < faCoeff.size(); ++i)
BOOST_REQUIRE_SMALL(std::abs(aCoeff(i) - faCoeff(i)), std::numeric_limits<T>::epsilon() * 2);
for (Eigen::Index i = 0; i < fbCoeff.size(); ++i)
BOOST_REQUIRE_SMALL(std::abs(bCoeff(i) - fbCoeff(i)), std::numeric_limits<T>::epsilon() * 2);
}
template <typename T>
void test_results(const fratio::vectX_t<T>& results, const fratio::vectX_t<T>& data, fratio::GenericFilter<T>& filter)
{
fratio::vectX_t<T> filteredData(results.size());
for (Eigen::Index i = 0; i < data.size(); ++i)
filteredData(i) = filter.stepFilter(data(i));
for (Eigen::Index i = 0; i < filteredData.size(); ++i)
BOOST_REQUIRE_SMALL(std::abs(filteredData(i) - results(i)), std::numeric_limits<T>::epsilon() * 100);
filter.resetFilter();
filteredData = filter.filter(data);
for (Eigen::Index i = 0; i < filteredData.size(); ++i)
BOOST_REQUIRE_SMALL(std::abs(filteredData(i) - results(i)), std::numeric_limits<T>::epsilon() * 100);
}