Getting Started¶
Requirements¶
- A C++17 compiler
- CMake 3.14 or newer if consuming via CMake.
constfilt is header-only. consteig and gcem are vendored under
include/constfilt/vendor/ and are pulled in automatically by constfilt's
own headers; no separate installation is needed.
Consuming the library¶
add_subdirectory¶
add_subdirectory(third_party/constfilt)
target_link_libraries(your_target PRIVATE constfilt::constfilt)
FetchContent¶
include(FetchContent)
FetchContent_Declare(
constfilt
GIT_REPOSITORY https://github.com/MitchellThompkins/constfilt
GIT_TAG main
)
FetchContent_MakeAvailable(constfilt)
target_link_libraries(your_target PRIVATE constfilt::constfilt)
constfilt::constfilt is an INTERFACE target that propagates the include path
and the consteig / gcem dependencies transitively.
Header-only, no CMake¶
Add the constfilt, consteig, and gcem include directories to your compiler's
include path, then #include <constfilt/constfilt.hpp>.
Hello, filter¶
#include <constfilt/constfilt.hpp>
int main()
{
// 4th-order Butterworth lowpass, 100 Hz cutoff at 1 kHz sample rate.
// All coefficient math happens at compile time.
static constexpr constfilt::Butterworth<double, 4> bw(100.0, 1000.0);
// Batch filtering.
double input[8]{1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0};
double output[8]{};
bw(input, output);
// Real-time sample-by-sample filtering (mutates internal state).
constfilt::Butterworth<double, 4> rt(100.0, 1000.0);
double y = rt(0.5);
}
Supported filters¶
- Butterworth: lowpass, highpass
- Elliptic: lowpass, highpass
All filter types support four discretization methods: TustinPW (prewarped
bilinear, default), TustinNW (standard bilinear), ZOH, and MatchedZ.
The library imposes no upper bound on the filter order. The practical upper
bound is set by double precision: as N grows, the magnitudes of polynomial
coefficients and pole separations stretch over many orders of magnitude and
round-off begins to dominate. The committed regression tests cover orders 1 through 8
because that is the range that is comfortably verifiable against Octave's
reference implementations.
Selecting variants¶
// Lowpass / highpass (template parameter 4):
constfilt::Butterworth<double, 4> lp(100.0, 1000.0);
constfilt::Butterworth<double, 4, constfilt::TustinPW, constfilt::HighPass> hp(100.0, 1000.0);
// Discretization method (template parameter 3):
constfilt::Butterworth<double, 4, constfilt::TustinPW> tupw(100.0, 1000.0); // default
constfilt::Butterworth<double, 4, constfilt::TustinNW> tunw(100.0, 1000.0);
constfilt::Butterworth<double, 4, constfilt::ZOH> zoh(100.0, 1000.0);
constfilt::Butterworth<double, 4, constfilt::MatchedZ> mz(100.0, 1000.0);
// Elliptic takes (cutoff_hz, passband_ripple_dB, stopband_atten_dB, sample_rate_hz):
constfilt::Elliptic<double, 4> el(100.0, 0.5, 60.0, 1000.0);
constfilt::Elliptic<double, 4, constfilt::TustinNW, constfilt::HighPass> el_hp(100.0, 0.5, 60.0, 1000.0);
// AnalogFilter defaults to TustinNW; TustinPW requires an explicit warp frequency:
constfilt::AnalogFilter<double, 2> af(b, a, 1000.0);
constfilt::AnalogFilter<double, 2, constfilt::TustinPW> af_pw(b, a, 1000.0,
constfilt::prewarp(100.0));
// Convenience aliases for first-order RC equivalents:
constfilt::FirstOrderLowPass<double> first_lp(100.0, 1000.0);
constfilt::FirstOrderHighPass<double> first_hp(100.0, 1000.0);
Accessing coefficients¶
The discretized transfer function is exposed as coeffs_b() and coeffs_a()
on the underlying Filter, both constexpr:
static constexpr auto bw = constfilt::Butterworth<double, 2>(100.0, 1000.0);
// coeffs_b() and coeffs_a() return const T* that can be indexed:
constexpr double b0 = bw.coeffs_b()[0];
constexpr double a1 = bw.coeffs_a()[1];
Stability checking¶
AnalogFilter (the base of Butterworth and Elliptic) exposes a CheckStab
template parameter (fourth parameter, default true) for stability checking
(not yet implemented). To skip the check, pass CheckStab = false.