constfilt
Compile-time IIR digital filter design for C++17
Loading...
Searching...
No Matches
stability.hpp
1#ifndef CONSTFILT_STABILITY_HPP
2#define CONSTFILT_STABILITY_HPP
3
4#include "discretize.hpp"
5#include "vendor/consteig/consteig.hpp"
6
7namespace constfilt
8{
9
10enum class Stability
11{
12 Stable,
13 MarginallyStable,
14 Unstable
15};
16
17// Checks continuous-time stability via eigenvalues of the A matrix.
18//
19// Stable: all poles have Re(lambda) < 0
20// MarginallyStable: all poles have Re(lambda) <= 0, and any imaginary-axis
21// poles
22// are simple (no repeated imaginary-axis poles)
23// Unstable: any pole has Re(lambda) > 0, or repeated imaginary-axis
24// poles
25//
26// Tolerance used for "near imaginary axis" and "repeated" comparisons: 1e-8.
27template <typename T, consteig::Size N>
28constexpr Stability check_stability(const StateSpace<T, N> &sys)
29{
30 const auto evals = consteig::eigenvalues(sys.A);
31
32 // Classifies poles by real part:
33 // re > tol -> Unstable
34 // |re| <= tol -> MarginallyStable
35 // re < -tol -> Stable
36 // tol = 1e-8 is conservative. A pole that close to the imaginary axis is
37 // effectively marginal regardless.
38 constexpr T tol = static_cast<T>(1e-8);
39
40 bool has_imag_axis = false;
41
42 for (consteig::Size i = 0; i < N; ++i)
43 {
44 const T re = evals(i, 0).real;
45 if (re > tol)
46 {
47 return Stability::Unstable;
48 }
49 if (re > -tol)
50 {
51 has_imag_axis = true;
52 }
53 }
54
55 if (has_imag_axis)
56 {
57 // Check for repeated imaginary-axis poles (repeated = Unstable).
58 for (consteig::Size i = 0; i < N; ++i)
59 {
60 if (evals(i, 0).real > -tol)
61 {
62 const T im_i = evals(i, 0).imag;
63 for (consteig::Size j = i + 1u; j < N; ++j)
64 {
65 if (evals(j, 0).real > -tol)
66 {
67 const T diff = im_i - evals(j, 0).imag;
68 const T absdiff =
69 diff < static_cast<T>(0) ? -diff : diff;
70 if (absdiff < tol)
71 return Stability::Unstable;
72 }
73 }
74 }
75 }
76 return Stability::MarginallyStable;
77 }
78
79 return Stability::Stable;
80}
81
82} // namespace constfilt
83
84#endif // CONSTFILT_STABILITY_HPP