68 std::complex<double> variance = std::complex<double>(0.0, 0.0);
69 for (
const std::complex<double> &pole : poles) {
70 const double magnitude = std::pow(std::abs(pole), 1.0 / scale_factor);
71 const double phase = std::arg(pole) / scale_factor;
72 const std::complex<double> multiplier1 = std::polar(magnitude, phase);
73 const std::complex<double> multiplier2 = std::pow(magnitude - std::polar(1.0, phase), -2.0);
74 variance += 2.0 * multiplier1 * multiplier2;
79 return variance.real();
98 const std::array<std::complex<double>, 4> &poles,
double scale_factor)
100 std::complex<double> variance_derivative = std::complex<double>(0.0, 0.0);
101 for (
const std::complex<double> &pole : poles) {
102 const double magnitude = std::pow(std::abs(pole), 1.0 / scale_factor);
103 const double phase = std::arg(pole) / scale_factor;
105 const std::complex<double> multiplier1 = std::polar(magnitude, phase);
106 const std::complex<double> multiplier2 = magnitude + std::polar(1.0, phase);
107 const std::complex<double> multiplier3 = std::log(std::abs(pole)) -
108 std::complex<double>(0.0, std::arg(pole));
110 const std::complex<double> divisor1 = std::pow(magnitude - std::polar(1.0, phase), 3.0);
111 const std::complex<double> divisor2 =
math::square(scale_factor);
113 variance_derivative += 2.0 * multiplier1 * multiplier2 * multiplier3 / (divisor1 * divisor2);
118 return variance_derivative.real();
127 float reference_sigma)
129 const double reference_variance =
math::square(reference_sigma);
134 double scale_factor = reference_sigma / 2.0;
136 const int maximum_interations = 10;
137 for (
int i = 0; i < maximum_interations; i++) {
141 if (
math::abs(reference_variance - variance) < 1.0e-8) {
150 scale_factor -= (variance - reference_variance) / derivative;
164 const std::array<std::complex<double>, 4> &poles,
float sigma)
168 std::array<std::complex<double>, 4> scaled_poles;
169 for (
int i = 0; i < poles.size(); i++) {
170 const std::complex<double> &pole = poles[i];
171 const double magnitude = std::pow(std::abs(pole), 1.0 / scale_factor);
172 const double phase = std::arg(pole) / scale_factor;
173 scaled_poles[i] = std::polar(magnitude, phase);
183 const std::array<std::complex<double>, 4> &non_causal_poles)
185 std::array<std::complex<double>, 4> causal_poles;
186 for (
int i = 0; i < non_causal_poles.size(); i++) {
187 causal_poles[i] = 1.0 / non_causal_poles[i];
198 std::complex<double> gain = std::complex<double>(1.0, 0.0);
199 for (
const std::complex<double> &pole : poles) {
226 const std::complex<double> b4 = gain;
227 const std::complex<double> b3 = -gain * (poles[0] + poles[1] + poles[2] + poles[3]);
228 const std::complex<double> b2 = gain * (poles[1] * poles[0] + poles[2] * poles[0] +
229 poles[2] * poles[1] + poles[3] * poles[0] +
230 poles[3] * poles[1] + poles[3] * poles[2]);
231 const std::complex<double>
b1 = -gain * (poles[2] * poles[1] * poles[0] +
232 poles[3] * poles[1] * poles[0] +
233 poles[3] * poles[2] * poles[0] +
234 poles[3] * poles[2] * poles[1]);
238 const double4 coefficients =
double4(
b1.real(), b2.real(), b3.real(), b4.real());
279 const std::array<std::complex<double>, 4> &poles,
280 const std::complex<double> &target_pole,
287 std::complex<double> target_pole_inverse = 1.0 / target_pole;
288 std::complex<double> residue = std::complex<double>(1.0, 0.0);
289 for (
const std::complex<double> &pole : poles) {
290 if (pole != target_pole && pole != std::conj(target_pole)) {
291 residue *= 1.0 - pole * target_pole_inverse;
296 return gain / residue;
305 const std::array<std::complex<double>, 4> &poles,
306 const std::complex<double> &target_pole,
309 std::complex<double> result = std::complex<double>(1.0, 0.0);
310 for (
const std::complex<double> &pole : poles) {
311 result *= 1.0 - pole * target_pole;
323 const std::complex<double> &residue,
324 const std::complex<double> &transfer_value,
325 double2 &r_feedback_coefficients,
326 double2 &r_causal_feedforward_coefficients,
327 double2 &r_non_causal_feedforward_coefficients)
329 const std::complex<double> parallel_residue = residue * transfer_value;
330 const std::complex<double> pole_inverse = 1.0 / pole;
332 r_feedback_coefficients =
double2(-2.0 * pole.real(), std::norm(pole));
334 const double causal_feedforward_1 = parallel_residue.imag() / pole_inverse.imag();
335 const double causal_feedforward_0 = parallel_residue.real() -
336 causal_feedforward_1 * pole_inverse.real();
337 r_causal_feedforward_coefficients =
double2(causal_feedforward_0, causal_feedforward_1);
339 const double non_causal_feedforward_1 = causal_feedforward_1 -
340 causal_feedforward_0 * r_feedback_coefficients[0];
341 const double non_causal_feedforward_2 = -causal_feedforward_0 * r_feedback_coefficients[1];
342 r_non_causal_feedforward_coefficients =
double2(non_causal_feedforward_1,
343 non_causal_feedforward_2);
392 const std::array<std::complex<double>, 4> poles = {
393 std::complex<double>(1.12075, 1.27788),
394 std::complex<double>(1.12075, -1.27788),
395 std::complex<double>(1.76952, 0.46611),
396 std::complex<double>(1.76952, -0.46611),
404 const std::array<std::complex<double>, 4> non_causal_poles = scaled_poles;
405 const std::array<std::complex<double>, 4> causal_poles =
compute_causal_poles(non_causal_poles);
417 causal_poles, causal_poles[0], feedforward_coefficient);
419 causal_poles, causal_poles[2], feedforward_coefficient);
425 const std::complex<double> first_transfer_value =
427 causal_poles, causal_poles[0], feedforward_coefficient);
428 const std::complex<double> second_transfer_value =
430 causal_poles, causal_poles[2], feedforward_coefficient);
436 first_transfer_value,
437 first_feedback_coefficients_,
438 first_causal_feedforward_coefficients_,
439 first_non_causal_feedforward_coefficients_);
442 second_transfer_value,
443 second_feedback_coefficients_,
444 second_causal_feedforward_coefficients_,
445 second_non_causal_feedforward_coefficients_);
449 first_feedback_coefficients_, first_causal_feedforward_coefficients_);
451 first_feedback_coefficients_, first_non_causal_feedforward_coefficients_);
453 second_feedback_coefficients_, second_causal_feedforward_coefficients_);
455 second_feedback_coefficients_, second_non_causal_feedforward_coefficients_);
static void compute_second_order_section(const std::complex< double > &pole, const std::complex< double > &residue, const std::complex< double > &transfer_value, double2 &r_feedback_coefficients, double2 &r_causal_feedforward_coefficients, double2 &r_non_causal_feedforward_coefficients)