Pulp 1.88.0
Cross-platform audio plugin framework
Loading...
Searching...
No Matches
poly_math.hpp
Go to the documentation of this file.
1#pragma once
2
5
6#include <vector>
7#include <complex>
8#include <cmath>
9#include <algorithm>
10#include <numeric>
11
12namespace pulp::signal {
13
27struct Polynomial {
28
31 template <typename SampleType = float>
32 static SampleType eval(const std::vector<SampleType>& coeffs, SampleType x) {
33 if (coeffs.empty()) return 0;
34 SampleType result = coeffs.back();
35 for (int i = static_cast<int>(coeffs.size()) - 2; i >= 0; --i) {
36 result = result * x + coeffs[static_cast<size_t>(i)];
37 }
38 return result;
39 }
40
42 template <typename SampleType = float>
43 static std::complex<SampleType> eval_complex(
44 const std::vector<SampleType>& coeffs,
45 std::complex<SampleType> z) {
46 if (coeffs.empty()) return {0, 0};
47 std::complex<SampleType> result = coeffs.back();
48 for (int i = static_cast<int>(coeffs.size()) - 2; i >= 0; --i) {
49 result = result * z + coeffs[static_cast<size_t>(i)];
50 }
51 return result;
52 }
53
56 template <typename SampleType = float>
57 static std::pair<std::complex<SampleType>, std::complex<SampleType>>
58 roots_quadratic(SampleType a, SampleType b, SampleType c) {
59 if (std::abs(a) < SampleType{1e-12f}) {
60 if (std::abs(b) < SampleType{1e-12f}) {
61 return {{SampleType{0.0f}, SampleType{0.0f}},
62 {SampleType{0.0f}, SampleType{0.0f}}};
63 }
64 const auto root = std::complex<SampleType>{-c / b, SampleType{0.0f}};
65 return {root, root};
66 }
67
68 SampleType disc = b * b - SampleType{4.0f} * a * c;
69 if (disc >= 0) {
70 SampleType sq = std::sqrt(disc);
71 return {(-b + sq) / (SampleType{2.0f} * a),
72 (-b - sq) / (SampleType{2.0f} * a)};
73 } else {
74 SampleType real = -b / (SampleType{2.0f} * a);
75 SampleType imag = std::sqrt(-disc) / (SampleType{2.0f} * a);
76 return {{real, imag}, {real, -imag}};
77 }
78 }
79
81 template <typename SampleType = float>
82 static std::vector<SampleType> multiply(const std::vector<SampleType>& a,
83 const std::vector<SampleType>& b) {
84 if (a.empty() || b.empty()) return {};
85 std::vector<SampleType> result(a.size() + b.size() - 1, SampleType{0.0f});
86 for (size_t i = 0; i < a.size(); ++i) {
87 for (size_t j = 0; j < b.size(); ++j) {
88 result[i + j] += a[i] * b[j];
89 }
90 }
91 return result;
92 }
93
95 template <typename SampleType = float>
96 static std::vector<SampleType> add(const std::vector<SampleType>& a,
97 const std::vector<SampleType>& b) {
98 auto& longer = (a.size() >= b.size()) ? a : b;
99 auto& shorter = (a.size() >= b.size()) ? b : a;
100 std::vector<SampleType> result = longer;
101 for (size_t i = 0; i < shorter.size(); ++i) {
102 result[i] += shorter[i];
103 }
104 return result;
105 }
106
108 template <typename SampleType = float>
109 static std::vector<SampleType> scale(const std::vector<SampleType>& p,
110 SampleType s) {
111 std::vector<SampleType> result(p.size());
112 for (size_t i = 0; i < p.size(); ++i) result[i] = p[i] * s;
113 return result;
114 }
115
117 template <typename SampleType = float>
118 static std::vector<SampleType> derivative(const std::vector<SampleType>& p) {
119 if (p.size() <= 1) return {0};
120 std::vector<SampleType> result(p.size() - 1);
121 for (size_t i = 1; i < p.size(); ++i) {
122 result[i - 1] = p[i] * static_cast<SampleType>(i);
123 }
124 return result;
125 }
126};
127
129template <typename SampleType = float>
130struct Mat2T {
131 SampleType m[2][2] = {{SampleType{1}, SampleType{0}},
132 {SampleType{0}, SampleType{1}}};
133
134 static Mat2T identity() {
135 return {{{SampleType{1}, SampleType{0}},
136 {SampleType{0}, SampleType{1}}}};
137 }
138
139 Mat2T operator*(const Mat2T& b) const {
140 Mat2T r;
141 r.m[0][0] = m[0][0] * b.m[0][0] + m[0][1] * b.m[1][0];
142 r.m[0][1] = m[0][0] * b.m[0][1] + m[0][1] * b.m[1][1];
143 r.m[1][0] = m[1][0] * b.m[0][0] + m[1][1] * b.m[1][0];
144 r.m[1][1] = m[1][0] * b.m[0][1] + m[1][1] * b.m[1][1];
145 return r;
146 }
147
148 SampleType determinant() const {
149 return m[0][0] * m[1][1] - m[0][1] * m[1][0];
150 }
151
152 Mat2T inverse() const {
153 SampleType d = determinant();
154 if (std::abs(d) < SampleType{1e-10f}) return identity();
155 SampleType inv_d = SampleType{1.0f} / d;
156 return {{{m[1][1] * inv_d, -m[0][1] * inv_d},
157 {-m[1][0] * inv_d, m[0][0] * inv_d}}};
158 }
159};
160
163
165template <typename SampleType = float>
166struct Mat3T {
167 SampleType m[3][3] = {{SampleType{1}, SampleType{0}, SampleType{0}},
168 {SampleType{0}, SampleType{1}, SampleType{0}},
169 {SampleType{0}, SampleType{0}, SampleType{1}}};
170
171 static Mat3T identity() {
172 return {{{SampleType{1}, SampleType{0}, SampleType{0}},
173 {SampleType{0}, SampleType{1}, SampleType{0}},
174 {SampleType{0}, SampleType{0}, SampleType{1}}}};
175 }
176
177 Mat3T operator*(const Mat3T& b) const {
178 Mat3T r{{{SampleType{0}, SampleType{0}, SampleType{0}},
179 {SampleType{0}, SampleType{0}, SampleType{0}},
180 {SampleType{0}, SampleType{0}, SampleType{0}}}};
181 for (int i = 0; i < 3; ++i)
182 for (int j = 0; j < 3; ++j)
183 for (int k = 0; k < 3; ++k)
184 r.m[i][j] += m[i][k] * b.m[k][j];
185 return r;
186 }
187
188 SampleType determinant() const {
189 return m[0][0] * (m[1][1] * m[2][2] - m[1][2] * m[2][1])
190 - m[0][1] * (m[1][0] * m[2][2] - m[1][2] * m[2][0])
191 + m[0][2] * (m[1][0] * m[2][1] - m[1][1] * m[2][0]);
192 }
193};
194
197
198} // namespace pulp::signal
Definition additive_bank.hpp:218
Mat3T< double > Mat3d
Definition poly_math.hpp:196
Mat2T< double > Mat2d
Definition poly_math.hpp:162
@ c
Definition spectrum_trace.hpp:35
Mat3T< float > Mat3
Definition poly_math.hpp:195
Mat2T< float > Mat2
Definition poly_math.hpp:161
@ a
Definition formant_filter_bank.hpp:20
@ i
Definition formant_filter_bank.hpp:20
Simple 2x2 matrix for biquad coefficient manipulation.
Definition poly_math.hpp:130
Mat2T operator*(const Mat2T &b) const
Definition poly_math.hpp:139
SampleType determinant() const
Definition poly_math.hpp:148
static Mat2T identity()
Definition poly_math.hpp:134
Mat2T inverse() const
Definition poly_math.hpp:152
float m[2][2]
Definition poly_math.hpp:131
Simple 3x3 matrix for state-space filter representations.
Definition poly_math.hpp:166
Mat3T operator*(const Mat3T &b) const
Definition poly_math.hpp:177
float m[3][3]
Definition poly_math.hpp:167
static Mat3T identity()
Definition poly_math.hpp:171
SampleType determinant() const
Definition poly_math.hpp:188
Polynomial evaluation and manipulation utilities.
Definition poly_math.hpp:27
static std::complex< SampleType > eval_complex(const std::vector< SampleType > &coeffs, std::complex< SampleType > z)
Evaluate complex polynomial (for frequency response).
Definition poly_math.hpp:43
static std::vector< SampleType > add(const std::vector< SampleType > &a, const std::vector< SampleType > &b)
Add two polynomials. Not RT-safe.
Definition poly_math.hpp:96
static std::vector< SampleType > multiply(const std::vector< SampleType > &a, const std::vector< SampleType > &b)
Multiply two polynomials (convolution of coefficients). Not RT-safe.
Definition poly_math.hpp:82
static SampleType eval(const std::vector< SampleType > &coeffs, SampleType x)
Evaluate polynomial using Horner's method.
Definition poly_math.hpp:32
static std::vector< SampleType > scale(const std::vector< SampleType > &p, SampleType s)
Scale all coefficients by a constant. Not RT-safe.
Definition poly_math.hpp:109
static std::vector< SampleType > derivative(const std::vector< SampleType > &p)
Derivative of a polynomial. Not RT-safe.
Definition poly_math.hpp:118
static std::pair< std::complex< SampleType >, std::complex< SampleType > > roots_quadratic(SampleType a, SampleType b, SampleType c)
Roots of quadratic ax^2 + bx + c.
Definition poly_math.hpp:58