constfilt
Compile-time IIR digital filter design for C++17
Loading...
Searching...
No Matches
analog_filter.hpp
1#ifndef CONSTFILT_ANALOG_FILTER_HPP
2#define CONSTFILT_ANALOG_FILTER_HPP
3
4#include "discretize.hpp"
5#include "filter.hpp"
6#include "stability.hpp"
7
8namespace constfilt
9{
10
11// Discretize an analog (continuous-time, s-domain) transfer function into a
12// digital Filter.
13//
14// Coefficients are in descending power order:
15// coeff[0]*s^N + coeff[1]*s^{N-1} + ... + coeff[N]
16//
17// Template parameters:
18// T - numeric type (float, double, ...)
19// N - filter order (degree of denominator)
20// Method - Tustin (default), ZOH, or MatchedZ
21// CheckStab - reserved for future use; currently has no effect (see below).
22//
23// Constructors:
24// AnalogFilter(b_c, a_c, sample_rate_hz)
25// b_c - s-domain numerator array [N+1], descending order
26// a_c - s-domain denominator array [N+1], descending order
27// sample_rate_hz - sample rate in Hz
28//
29// AnalogFilter(continuous_tf, sample_rate_hz)
30// continuous_tf - s-domain TransferFunction (e.g. from a subclass)
31// sample_rate_hz - sample rate in Hz
32template <typename T, consteig::Size N, typename Method = Tustin,
33 bool CheckStab = true>
34class AnalogFilter : public Filter<T, N + 1u, N + 1u>
35{
36 static_assert(N >= 1u, "Filter order must be at least 1");
37
38 public:
39 constexpr AnalogFilter(const T (&b_c)[N + 1u], const T (&a_c)[N + 1u],
40 T sample_rate_hz)
41 : AnalogFilter(checked_discretize(b_c, a_c, sample_rate_hz))
42 {
43 }
44
45 constexpr AnalogFilter(TransferFunction<T, N + 1u, N + 1u> continuous_tf,
46 T sample_rate_hz)
47 : AnalogFilter(checked_discretize(continuous_tf.b, continuous_tf.a,
48 sample_rate_hz))
49 {
50 }
51
52 private:
53 constexpr explicit AnalogFilter(
54 TransferFunction<T, N + 1u, N + 1u> digital_tf)
55 : Filter<T, N + 1u, N + 1u>(digital_tf.b, digital_tf.a)
56 {
57 }
58
59 static constexpr TransferFunction<T, N + 1u, N + 1u> checked_discretize(
60 const T (&b_c)[N + 1u], const T (&a_c)[N + 1u], T sample_rate_hz)
61 {
62 // Stability check is currently disabled. See:
63 // https://github.com/MitchellThompkins/constfilt/issues/14
64 //
65 // The original implementation used:
66 // throw "constfilt: unstable analog filter";
67 // which serves dual purpose in C++17: a runtime exception and, when
68 // evaluated in a constexpr context, a compile-time error. This is
69 // incompatible with -fno-exceptions and freestanding (no-stdlib)
70 // builds.
71 //
72 // Candidate replacements, each with trade-offs:
73 // __builtin_trap() - preserves compile-time error via the
74 // non-constexpr call rule, but is
75 // GCC/Clang specific.
76 // [[noreturn]] customization point (declared, not defined) -
77 // portable,
78 // user supplies the handler; linker error
79 // if forgotten; compile-time error still
80 // works via non-constexpr call rule.
81 // Remove entirely - current state; no check at runtime or
82 // compile time; caller's responsibility.
83 //
84 // if (CheckStab &&
85 // check_stability(tf_to_ss<T, N>(b_c, a_c)) == Stability::Unstable)
86 // {
87 // throw "constfilt: unstable analog filter";
88 // }
89 return analog_to_digital<T, N>(
90 b_c, a_c, static_cast<T>(1) / sample_rate_hz, Method{});
91 }
92};
93
94} // namespace constfilt
95
96#endif // CONSTFILT_ANALOG_FILTER_HPP