Split Bilinear tranform and update type checks.

topic/diffentiators
Vincent Samy 2018-10-26 16:18:08 +09:00
rodzic a6105fa9ff
commit 001f25f1cc
12 zmienionych plików z 116 dodań i 30 usunięć

Wyświetl plik

@ -0,0 +1,48 @@
#pragma once
#include <vector>
namespace fratio {
template <typename T>
struct BilinearTransform {
using SubType = internal::complex_sub_type_t<T>;
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 std::vector<T>& sPlanePoles, std::vector<T>& zPlanePoles);
static void ZToS(SubType fs, const T& zPlanePole, T& sPlanePole);
static void ZToS(SubType fs, const std::vector<T>& zPlanePoles, std::vector<T>& sPlanePoles);
};
template <typename T>
void BilinearTransform<T>::SToZ(SubType fs, const T& sPlanePole, T& zPlanePole)
{
T scalePole = sPlanePole / (2 * fs);
zPlanePole = (T(1) + scalePole) / (T(1) - scalePole);
}
template <typename T>
void BilinearTransform<T>::SToZ(SubType fs, const std::vector<T>& sPlanePoles, std::vector<T>& zPlanePoles)
{
assert(sPlanePoles.size() == zPlanePoles.size());
for (size_t k = 0; k < sPlanePoles.size(); ++k)
SToZ(fs, sPlanePoles[k], zPlanePoles[k]);
}
template <typename T>
void BilinearTransform<T>::ZToS(SubType fs, const T& zPlanePole, T& sPlanePole)
{
T invPole = T(1) / zPlanePole;
sPlanePole = 2 * fs * (T(1) - invPole) / (T(1) + invPole);
}
template <typename T>
void BilinearTransform<T>::ZToS(SubType fs, const std::vector<T>& zPlanePoles, std::vector<T>& sPlanePoles)
{
assert(zPlanePoles.size() == sPlanePoles.size());
for (size_t k = 0; k < sPlanePoles.size(); ++k)
ZToS(fs, zPlanePoles[k], sPlanePoles[k]);
}
} // namespace fratio

Wyświetl plik

@ -11,7 +11,8 @@ template <typename T>
class Butterworth : public GenericFilter<T> { class Butterworth : public GenericFilter<T> {
public: public:
enum class Type { enum class Type {
LowPass LowPass,
HighPass
}; };
// public: // public:
@ -26,6 +27,7 @@ private:
void initialize(size_t order, T fc, T fs); void initialize(size_t order, T fc, T fs);
void computeDigitalRep(); void computeDigitalRep();
void updateCoeffSize(); void updateCoeffSize();
void transformFilter();
private: private:
Type m_type; Type m_type;

Wyświetl plik

@ -1,3 +1,4 @@
#include "BilinearTransform.h"
#include "polynome_functions.h" #include "polynome_functions.h"
#include <cmath> #include <cmath>
#include <sstream> #include <sstream>
@ -58,8 +59,7 @@ void Butterworth<T>::computeDigitalRep()
std::complex<T> scalePole; std::complex<T> scalePole;
for (size_t k = 1; k <= m_order; ++k) { for (size_t k = 1; k <= m_order; ++k) {
scalePole = scaleFactor * std::complex<T>(-std::sin(thetaK(k)), std::cos(thetaK(k))); scalePole = scaleFactor * std::complex<T>(-std::sin(thetaK(k)), std::cos(thetaK(k)));
scalePole /= 2 * m_fs; BilinearTransform<std::complex<T>>::SToZ(m_fs, scalePole, m_poles[k - 1]);
m_poles[k - 1] = (T(1) + scalePole) / (T(1) - scalePole);
} }
std::vector<std::complex<T>> numPoles(m_order, std::complex<T>(-1)); std::vector<std::complex<T>> numPoles(m_order, std::complex<T>(-1));
@ -89,4 +89,17 @@ void Butterworth<T>::updateCoeffSize()
resetFilter(); resetFilter();
} }
template <typename T>
void Butterworth<T>::transformFilter()
{
switch (m_type) {
case Type::HighPass:
break;
case Type::LowPass:
default:
break;
}
}
} // namespace fratio } // namespace fratio

Wyświetl plik

@ -6,11 +6,10 @@
namespace fratio { namespace fratio {
template <typename T, typename = std::enable_if_t<std::is_floating_point<T>::value && !std::is_const<T>::value>>
class GenericFilter;
template <typename T> template <typename T>
class GenericFilter<T> { class GenericFilter {
static_assert(std::is_floating_point<T>::value && !std::is_const<T>::value, "Only accept non-complex floating point types.");
public: public:
T stepFilter(T data); T stepFilter(T data);
std::vector<T> filter(const std::vector<T>& data); std::vector<T> filter(const std::vector<T>& data);

Wyświetl plik

@ -7,6 +7,7 @@
namespace fratio { namespace fratio {
// Filters
using DigitalFilterf = DigitalFilter<float>; using DigitalFilterf = DigitalFilter<float>;
using DigitalFilterd = DigitalFilter<double>; using DigitalFilterd = DigitalFilter<double>;
using MovingAveragef = MovingAverage<float>; using MovingAveragef = MovingAverage<float>;
@ -14,6 +15,7 @@ using MovingAveraged = MovingAverage<double>;
using Butterworthf = Butterworth<float>; using Butterworthf = Butterworth<float>;
using Butterworthd = Butterworth<double>; using Butterworthd = Butterworth<double>;
// Polynome helper functions
using VietaAlgof = VietaAlgo<float>; using VietaAlgof = VietaAlgo<float>;
using VietaAlgod = VietaAlgo<double>; using VietaAlgod = VietaAlgo<double>;
using VietaAlgoi = VietaAlgo<int>; using VietaAlgoi = VietaAlgo<int>;
@ -21,4 +23,10 @@ using VietaAlgocf = VietaAlgo<std::complex<float>>;
using VietaAlgocd = VietaAlgo<std::complex<double>>; using VietaAlgocd = VietaAlgo<std::complex<double>>;
using VietaAlgoci = VietaAlgo<std::complex<int>>; using VietaAlgoci = VietaAlgo<std::complex<int>>;
// Bilinear transformation functions
using BilinearTransformf = BilinearTransform<float>;
using BilinearTransformd = BilinearTransform<double>;
using BilinearTransformcf = BilinearTransform<std::complex<float>>;
using BilinearTransformcd = BilinearTransform<std::complex<double>>;
} // namespace fratio } // namespace fratio

Wyświetl plik

@ -6,11 +6,10 @@
namespace fratio { namespace fratio {
template <typename T, typename = std::enable_if_t<std::is_arithmetic<T>::value || is_complex_t<T>::value>>
struct VietaAlgo;
template <typename T> template <typename T>
struct VietaAlgo<T> { 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 // Vieta's computation: https://en.wikipedia.org/wiki/Vieta%27s_formulas
static std::vector<T> polyCoeffFromRoot(const std::vector<T>& poles); static std::vector<T> polyCoeffFromRoot(const std::vector<T>& poles);
}; };

Wyświetl plik

@ -4,12 +4,29 @@
namespace fratio { namespace fratio {
template <typename T> namespace internal {
struct is_complex_t : public std::false_type {
};
template <typename T> // Based on https://stackoverflow.com/a/41449096/9774052
struct is_complex_t<std::complex<T>> : public std::true_type { template <typename T>
}; std::true_type is_tt_impl(std::complex<T>);
std::false_type is_tt_impl(...);
template <typename T>
using is_complex = decltype(is_tt_impl(std::declval<T>()));
template <typename T, bool B>
struct sub_type {
using type = T;
};
template <typename T>
struct sub_type<T, true> {
using type = typename T::value_type;
};
template <typename T>
using complex_sub_type_t = typename sub_type<T, is_complex<T>::value>::type;
} // namespace internal
} // namespace fratio } // namespace fratio

Wyświetl plik

@ -8,7 +8,7 @@ DISABLE_CONVERSION_WARNING_BEGIN
template <typename T> template <typename T>
struct System { struct System {
std::vector<T> data = { 1., 2., 3., 4., 5., 6., 7., 8. }; std::vector<T> data = { 1, 2, 3, 4, 5, 6, 7, 8 };
size_t order = 5; size_t order = 5;
T fc = 10; T fc = 10;
T fs = 100; T fs = 100;
@ -88,7 +88,7 @@ BOOST_FIXTURE_TEST_CASE(BUTTERWORTH_FILTER_DOUBLE, System<double>)
bf2.setFilterParameters(order, fc, fs); bf2.setFilterParameters(order, fc, fs);
filteredData.resize(0); filteredData.resize(0);
for (float d : data) for (double d : data)
filteredData.push_back(bf2.stepFilter(d)); filteredData.push_back(bf2.stepFilter(d));
for (size_t i = 0; i < filteredData.size(); ++i) for (size_t i = 0; i < filteredData.size(); ++i)

Wyświetl plik

@ -8,8 +8,8 @@ DISABLE_CONVERSION_WARNING_BEGIN
template <typename T> template <typename T>
struct System { struct System {
std::vector<T> data = { 1., 2., 3., 4. }; std::vector<T> data = { 1, 2, 3, 4 };
std::vector<T> aCoeff = { 1., -0.99993717 }; std::vector<T> aCoeff = { 1, -0.99993717 };
std::vector<T> bCoeff = { 0.99996859, -0.99996859 }; std::vector<T> bCoeff = { 0.99996859, -0.99996859 };
std::vector<T> results = { 0.99996859, 1.999874351973491, 2.999717289867956, 3.999497407630634 }; std::vector<T> results = { 0.99996859, 1.999874351973491, 2.999717289867956, 3.999497407630634 };
}; };

Wyświetl plik

@ -5,12 +5,12 @@
BOOST_AUTO_TEST_CASE(FilterThrows) BOOST_AUTO_TEST_CASE(FilterThrows)
{ {
BOOST_REQUIRE_THROW(fratio::DigitalFilterd({}, { 1., 2. }), std::runtime_error); BOOST_REQUIRE_THROW(fratio::DigitalFilterd({}, { 1, 2 }), std::runtime_error);
BOOST_REQUIRE_THROW(fratio::DigitalFilterd({ 1., 2. }, {}), std::runtime_error); BOOST_REQUIRE_THROW(fratio::DigitalFilterd({ 1, 2 }, {}), std::runtime_error);
BOOST_REQUIRE_THROW(fratio::DigitalFilterd({ 0. }, { 1. }), std::invalid_argument); BOOST_REQUIRE_THROW(fratio::DigitalFilterd({ 0 }, { 1 }), std::invalid_argument);
auto df = fratio::DigitalFilterd(); auto df = fratio::DigitalFilterd();
BOOST_REQUIRE_THROW(df.setCoeff({}, { 1., 2. }), std::runtime_error); BOOST_REQUIRE_THROW(df.setCoeff({}, { 1, 2 }), std::runtime_error);
BOOST_REQUIRE_THROW(df.setCoeff({ 1., 2. }, {}), std::runtime_error); BOOST_REQUIRE_THROW(df.setCoeff({ 1, 2 }, {}), std::runtime_error);
BOOST_REQUIRE_THROW(df.setCoeff({ 0. }, { 1. }), std::invalid_argument); BOOST_REQUIRE_THROW(df.setCoeff({ 0 }, { 1 }), std::invalid_argument);
} }

Wyświetl plik

@ -5,7 +5,7 @@
template <typename T> template <typename T>
struct System { struct System {
std::vector<T> data = { 1., 2., 3., 4., 5., 6. }; std::vector<T> data = { 1, 2, 3, 4, 5, 6 };
size_t windowSize = 4; size_t windowSize = 4;
std::vector<T> results = { 0.25, 0.75, 1.5, 2.5, 3.5, 4.5 }; std::vector<T> results = { 0.25, 0.75, 1.5, 2.5, 3.5, 4.5 };
}; };

Wyświetl plik

@ -19,13 +19,13 @@ DISABLE_CONVERSION_WARNING_BEGIN
template <typename T> template <typename T>
struct SystemFloat { struct SystemFloat {
std::vector<T> data = { 0.32, -0.0518, 41.4, 0.89 }; std::vector<T> data = { 0.32, -0.0518, 41.4, 0.89 };
std::vector<T> results = { 1., -42.558199999999999, 48.171601999999993, -9.181098159999999, -0.610759296 }; std::vector<T> results = { 1, -42.558199999999999, 48.171601999999993, -9.181098159999999, -0.610759296 };
}; };
template <typename T> template <typename T>
struct SystemCFloat { struct SystemCFloat {
std::vector<std::complex<T>> data = { { 1.35, 0.2 }, { -1.5, 4.45 }, { 12.8, -3.36 }, { 5.156, 2.12 } }; std::vector<std::complex<T>> data = { { 1.35, 0.2 }, { -1.5, 4.45 }, { 12.8, -3.36 }, { 5.156, 2.12 } };
std::vector<std::complex<T>> results = { { 1., 0. }, { -17.806, -3.41 }, { 73.2776, 99.20074 }, { 101.857496, -444.634694 }, { -269.1458768, 388.7308864 } }; std::vector<std::complex<T>> results = { { 1, 0 }, { -17.806, -3.41 }, { 73.2776, 99.20074 }, { 101.857496, -444.634694 }, { -269.1458768, 388.7308864 } };
}; };
DISABLE_CONVERSION_WARNING_END DISABLE_CONVERSION_WARNING_END