36# include <gtest/gtest.h>
54 using Complex = FFTD::Complex;
56 constexpr double eps = 1e-9;
59 const double tol = eps)
67 const double tol = eps)
70 for (
size_t i = 0; i <
lhs.size(); ++i)
76 const double tol = eps)
79 for (
size_t i = 0; i <
lhs.size(); ++i)
92 const size_t idx =
static_cast<size_t>(
rounded);
97 const double frequency,
102 response.response.size())]);
107 const double tol = eps)
110 for (
size_t i = 0; i <
lhs.size(); ++i)
116 const double tol = eps)
119 for (
size_t i = 0; i <
lhs.size(); ++i)
125 const double tol = eps)
128 for (
size_t i = 0; i <
lhs.size(); ++i)
134 const double tol = eps)
137 for (
size_t i = 0; i <
lhs.size(); ++i)
144 for (
size_t i = 0; i < src.size(); ++i)
151 for (
size_t i = 0; i < src.
size(); ++i)
157 const double tol = eps)
162 for (
size_t i = 0; i <
lhs.size(); ++i)
165 for (
size_t j = 0; j <
rhs.size(); ++j)
170 if (std::abs(
lhs[i] -
rhs[j]) <= tol)
185 coeffs(0) = Complex(1.0, 0.0);
187 for (
size_t i = 0; i < roots.
size(); ++i)
190 for (
size_t j = 0; j <
next.size(); ++j)
191 next(j) = Complex(0.0, 0.0);
193 for (
size_t j = 0; j < coeffs.
size(); ++j)
195 next(j) += coeffs[j];
196 next(j + 1) -= coeffs[j] * roots[i];
199 coeffs = std::move(
next);
203 for (
size_t i = 0; i < coeffs.
size(); ++i)
206 output(i) = coeffs[i].real();
215 for (
size_t i = 0; i <
input.size(); ++i)
227 for (
size_t k = 0;
k < n; ++
k)
229 Complex
sum(0.0, 0.0);
230 for (
size_t t = 0; t < n; ++t)
232 const double angle =
sign * 2.0 * std::numbers::pi *
233 static_cast<double>(
k * t) /
234 static_cast<double>(n);
239 sum /=
static_cast<double>(n);
254 for (
size_t i = 0; i <
output.size(); ++i)
255 output(i) = Complex(0.0, 0.0);
257 for (
size_t i = 0; i < a.
size(); ++i)
258 for (
size_t j = 0; j < b.
size(); ++j)
259 output(i + j) += a[i] * b[j];
271 for (
size_t i = 0; i <
output.size(); ++i)
274 for (
size_t i = 0; i < a.
size(); ++i)
275 for (
size_t j = 0; j < b.
size(); ++j)
276 output(i + j) += a[i] * b[j];
290 for (
size_t i = 0; i <
upsampled.size(); ++i)
292 for (
size_t i = 0; i < signal.
size(); ++i)
298 for (
size_t i = 0; i <
output.size(); ++i)
305 const double frequency,
307 const double phase = 0.0)
311 for (
size_t i = 0; i < n; ++i)
313 * std::sin(2.0 * std::numbers::pi * frequency
323 for (
size_t i = 1; i <
input.size(); ++i)
333 for (
size_t i =
input.size(); i > 0; --i)
345 for (
size_t i = 0; i < signal.
size(); ++i)
348 const size_t limit = std::min(i + 1, coeffs.
size());
350 sum += coeffs[
k] * signal[i -
k];
365 ? std::numeric_limits<size_t>::max()
379 for (
size_t i = 0; i <
pad_len; ++i)
381 for (
size_t i = 0; i < signal.
size(); ++i)
383 for (
size_t i = 0; i <
pad_len; ++i)
395 for (
size_t i = 0; i < length; ++i)
406 if (coeffs.
size() == 1)
409 const double gain = coeffs[0] * coeffs[0];
410 for (
size_t i = 0; i < signal.
size(); ++i)
411 output(i) = signal[i] * gain;
422 struct RefIIRCoefficients
431 for (
size_t i = 0; i <
input.size(); ++i)
432 max_value = std::max(max_value, std::abs(
input[i]));
438 if (
input.is_empty())
442 * std::numeric_limits<double>::epsilon();
443 size_t n =
input.size();
444 while (n > 1
and std::abs(
input[n - 1]) <= tol)
457 const double a0 = denominator[0];
459 * std::numeric_limits<double>::epsilon();
463 RefIIRCoefficients coeffs;
466 for (
size_t i = 0; i <= order; ++i)
468 coeffs.numerator(i) = 0.0;
469 coeffs.denominator(i) = 0.0;
473 coeffs.numerator(i) = numerator[i] / a0;
475 coeffs.denominator(i) = denominator[i] / a0;
476 coeffs.denominator(0) = 1.0;
487 auto coeff = [&
matrix, n](
const size_t row,
const size_t col) ->
double &
489 return matrix(row * n + col);
493 for (
size_t i = 0; i <
matrix.size(); ++i)
495 for (
size_t i = 0; i <
rhs.size(); ++i)
498 const double tol = (
max_entry + 1.0) * 128.0
499 * std::numeric_limits<double>::epsilon();
501 for (
size_t col = 0; col < n; ++col)
505 for (
size_t row = col + 1; row < n; ++row)
519 for (
size_t k = col;
k < n; ++
k)
525 for (
size_t row = col + 1; row < n; ++row)
527 const double factor =
coeff(row, col) /
pivot;
528 coeff(row, col) = 0.0;
529 for (
size_t k = col + 1;
k < n; ++
k)
531 rhs(row) -= factor *
rhs[col];
536 for (
size_t row = n; row > 0; --row)
538 const size_t i = row - 1;
540 for (
size_t col = i + 1; col < n; ++col)
541 sum -=
coeff(i, col) * solution[col];
551 const size_t order = denominator.
size() - 1;
556 for (
size_t i = 0; i <
system.size(); ++i)
559 auto coeff = [&
system, order](
const size_t row,
const size_t col) ->
double &
561 return system(row * order + col);
564 for (
size_t i = 0; i < order; ++i)
566 for (
size_t i = 0; i < order; ++i)
568 coeff(i, 0) += denominator[i + 1];
570 coeff(i, i + 1) -= 1.0;
574 for (
size_t i = 0; i < order; ++i)
575 rhs(i) = numerator[i + 1] - denominator[i + 1] * numerator[0];
582 for (
size_t i = 0; i <
input.size(); ++i)
595 const size_t order = denominator.
size() - 1;
599 for (
size_t i = 0; i < signal.
size(); ++i)
600 output(i) = numerator[0] * signal[i];
605 for (
size_t i = 0; i < order; ++i)
608 for (
size_t n = 0; n < signal.
size(); ++n)
610 const double x = signal[n];
611 const double y = numerator[0] * x + state[0];
613 for (
size_t i = 0; i + 1 < order; ++i)
614 state(i) = state[i + 1] + numerator[i + 1] * x
615 - denominator[i + 1] *
y;
616 state(order - 1) = numerator[order] * x - denominator[order] *
y;
630 const size_t order = coeffs.denominator.size() - 1;
635 const double gain = coeffs.numerator[0] * coeffs.numerator[0];
636 for (
size_t i = 0; i < signal.
size(); ++i)
637 output(i) = signal[i] * gain;
642 coeffs.denominator.size());
668 for (
size_t i = 0; i <
sections.size(); ++i)
706 template <std::
floating_po
int Real>
708 const Array<std::complex<Real>> &
rhs,
712 for (
size_t i = 0; i <
lhs.size(); ++i)
720 EXPECT_THROW(FFTD::transform(empty,
false), std::invalid_argument);
733 const std::string
backend = FFTD::simd_backend_name();
734 const std::string
batch_backend = FFTD::batched_plan_simd_backend_name();
735 const std::string
detected = FFTD::detected_simd_backend_name();
736 const std::string
preference = FFTD::simd_preference_name();
743 EXPECT_FALSE(FFTD::avx2_runtime_available()
and FFTD::neon_runtime_available());
764 FFTD::transform(work,
false);
765 FFTD::transform(work,
true);
772 std::mt19937_64
rng(20260305);
773 std::uniform_real_distribution<double> dist(-5.0, 5.0);
775 for (
const size_t n : {size_t(2), size_t(3), size_t(4), size_t(5),
776 size_t(6), size_t(8), size_t(10), size_t(15),
777 size_t(16), size_t(17)})
781 for (
size_t i = 0; i < n; ++i)
785 const auto obtained = FFTD::transformed(signal,
false);
792 Array<double> signal = {1.0, 2.0, -1.0, 0.5, 3.0, -2.0, 4.0, -0.75, 1.25};
795 const auto complex_spectrum = FFTD::transformed(lift_real_input(signal),
false);
802 std::mt19937_64
rng(20260306);
803 std::uniform_real_distribution<double> dist(-4.0, 4.0);
805 for (
const size_t n : {size_t(3), size_t(5), size_t(6), size_t(10),
806 size_t(12), size_t(15), size_t(17)})
810 for (
size_t i = 0; i < n; ++i)
814 FFTD::transform(work,
false);
815 FFTD::transform(work,
true);
822 std::vector<Complex> signal = {
846 std::vector<double> signal = {1.0, 2.0, -1.0, 0.5, 3.0, -2.0, 4.0, -0.75};
890 const auto magnitude = FFTD::magnitude_spectrum(
bins);
891 const auto power = FFTD::power_spectrum(
bins);
913 const auto phase = FFTD::phase_spectrum(
bins);
916 EXPECT_NEAR(phase[1], std::numbers::pi / 2.0, 1e-12);
918 EXPECT_NEAR(phase[3], -std::numbers::pi / 2.0, 1e-12);
926 std::vector<double> signal = {1.0, -0.5, 2.0, 0.25, -1.0, 3.0};
931 const auto obtained = FFTD::transform_padded(signal);
952 const auto expected = FFTD::transformed(signal,
false);
953 const auto obtained = FFTD::ptransformed(pool, signal,
false);
957 FFTD::ptransform(pool, work,
false);
972 Complex(-1.25, 0.75),
977 const auto expected = FFTD::transformed(signal,
false);
978 const auto obtained = FFTD::ptransformed(pool, signal,
false);
985 Array<double> signal = {2.0, -1.0, 0.5, 3.0, -2.5, 1.25, 4.0, -0.75};
987 const auto expected = FFTD::transform(signal);
988 const auto obtained = FFTD::ptransform(pool, signal);
994 Array<double> signal = {0.5, -1.25, 3.5, 2.0, -0.75, 4.25, 1.0, -2.0, 0.25};
996 const auto spectrum = FFTD::transform(signal);
997 const auto restored = FFTD::inverse_transform_real(spectrum);
1016 Array<double> signal = {2.0, -1.0, 0.5, 3.0, -2.5, 1.25, 4.0, -0.75};
1017 const auto spectrum = FFTD::transform(signal);
1023 for (
size_t k = 1;
k < 4; ++
k)
1067 Complex(1.0, 0.0), Complex(0.0, 0.0), Complex(0.0, 0.0), Complex(0.0, 0.0),
1068 Complex(0.0, 0.0), Complex(0.0, 0.0), Complex(0.0, 0.0), Complex(0.0, 0.0)
1096 const auto obtained = FFTD::multiply(a, b);
1113 const auto expected = FFTD::multiply(a, b);
1114 const auto obtained = FFTD::pmultiply(pool, a, b);
1120 std::vector<Complex> a = {
1132 const auto obtained = FFTD::multiply(a, b);
1142 const auto obtained = FFTD::multiply(a, b);
1152 const auto expected = FFTD::multiply(a, b);
1153 const auto obtained = FFTD::pmultiply(pool, a, b);
1159 std::vector<double> a = {1.0, 2.0, 3.0, -1.0};
1164 const auto obtained = FFTD::multiply(a, b);
1170 std::mt19937_64
rng(424242);
1171 std::uniform_real_distribution<double> dist(-3.0, 3.0);
1175 const size_t n =
static_cast<size_t>(
trial % 6 + 1);
1176 const size_t m =
static_cast<size_t>((
trial * 3) % 5 + 1);
1182 for (
size_t i = 0; i < n; ++i)
1183 ra.append(dist(
rng));
1184 for (
size_t i = 0; i <
m; ++i)
1185 rb.append(dist(
rng));
1195 for (
size_t i = 0; i < n; ++i)
1196 ca.append(Complex(dist(
rng), dist(
rng)));
1197 for (
size_t i = 0; i <
m; ++i)
1198 cb.append(Complex(dist(
rng), dist(
rng)));
1229 FFTF::transform(work,
false);
1230 FFTF::transform(work,
true);
1252 FFTL::transform(work,
false);
1253 FFTL::transform(work,
true);
1283 FFTD::Plan
p1024(1024);
1299 std::mt19937_64
rng(99887766);
1300 std::uniform_real_distribution<double> dist(-5.0, 5.0);
1302 for (
const size_t n : {size_t(1), size_t(2), size_t(3), size_t(4),
1303 size_t(5), size_t(6), size_t(8), size_t(10),
1304 size_t(15), size_t(16), size_t(17), size_t(64),
1305 size_t(256), size_t(1024)})
1310 for (
size_t i = 0; i < n; ++i)
1313 auto from_static = FFTD::transformed(signal,
false);
1321 std::mt19937_64
rng(55443322);
1322 std::uniform_real_distribution<double> dist(-10.0, 10.0);
1324 for (
const size_t n : {size_t(2), size_t(3), size_t(5), size_t(8),
1325 size_t(15), size_t(17), size_t(64), size_t(512)})
1330 for (
size_t i = 0; i < n; ++i)
1334 plan.transform(work,
false);
1335 plan.transform(work,
true);
1343 std::mt19937_64
rng(11223344);
1344 std::uniform_real_distribution<double> dist(-3.0, 3.0);
1346 FFTD::Plan
plan(256);
1352 for (
size_t i = 0; i < 256; ++i)
1356 plan.transform(work,
false);
1357 plan.transform(work,
true);
1365 Array<double> signal = {0.5, -1.25, 3.5, 2.0, -0.75, 4.25, 1.0, -2.0, 0.25};
1368 for (
size_t i = 0; i < signal.
size(); ++i)
1369 lifted.append(Complex(signal[i], 0.0));
1372 auto spectrum =
plan.transformed(
lifted,
false);
1381 std::mt19937_64
rng(31415926);
1382 std::uniform_real_distribution<double> dist(-4.0, 4.0);
1384 const size_t n = 256;
1387 for (
size_t i = 0; i < n; ++i)
1391 const auto spectrum = FFTD::transform(signal);
1392 const auto sequential =
plan.inverse_transform_real(spectrum);
1393 const auto parallel =
plan.pinverse_transform_real(pool, spectrum);
1401 std::mt19937_64
rng(77665544);
1402 std::uniform_real_distribution<double> dist(-5.0, 5.0);
1404 const size_t n = 64;
1408 for (
size_t i = 0; i < n; ++i)
1419 std::mt19937_64
rng(33221100);
1420 std::uniform_real_distribution<double> dist(-5.0, 5.0);
1422 for (
const size_t n : {size_t(8), size_t(10), size_t(15),
1423 size_t(17), size_t(64), size_t(256), size_t(1024)})
1428 for (
size_t i = 0; i < n; ++i)
1431 const auto sequential =
plan.transformed(signal,
false);
1432 const auto parallel =
plan.ptransformed(pool, signal,
false);
1435 const auto seq_inv =
plan.transformed(signal,
true);
1436 const auto par_inv =
plan.ptransformed(pool, signal,
true);
1444 std::mt19937_64
rng(76543210);
1445 std::uniform_real_distribution<double> dist(-3.0, 3.0);
1447 const size_t n = 17;
1451 for (
size_t item = 0; item < 6; ++item)
1455 for (
size_t i = 0; i < n; ++i)
1457 batch.append(signal);
1464 for (
size_t i = 0; i <
batch.size(); ++i)
1473 for (
size_t i = 0; i <
batch.size(); ++i)
1485 Array<Complex>({Complex(1.0, 0.0), Complex(0.0, 1.0), Complex(-1.0, 0.0),
1486 Complex(0.0, -1.0), Complex(0.5, 0.25), Complex(-0.5, 0.75),
1487 Complex(1.25, -0.5), Complex(-0.25, 0.5)}),
1494 EXPECT_THROW(FFTD::ptransformed_batch(pool,
batch,
false), std::invalid_argument);
1500 std::mt19937_64
rng(123456789);
1501 std::uniform_real_distribution<double> dist(-2.0, 2.0);
1503 const size_t n = 15;
1507 for (
size_t item = 0; item < 5; ++item)
1511 for (
size_t i = 0; i < n; ++i)
1513 batch.append(signal);
1516 const auto sequential =
plan.rfft_batch(
batch);
1517 const auto parallel =
plan.prfft_batch(pool,
batch);
1525 for (
size_t i = 0; i <
batch.size(); ++i)
1538 std::mt19937_64
rng(987654321);
1539 std::uniform_real_distribution<double> dist(-2.5, 2.5);
1541 const size_t n = 32;
1548 for (
size_t item = 0; item < 4; ++item)
1554 for (
size_t i = 0; i < n; ++i)
1556 const double sample = dist(
rng);
1558 lifted.append(Complex(sample, 0.0));
1564 const auto sequential =
plan.inverse_transform_real_batch(
spectra);
1565 const auto parallel =
plan.pinverse_transform_real_batch(pool,
spectra);
1568 for (
size_t i = 0; i <
expected.size(); ++i)
1578 Array<double> signal = {1.0, -2.0, 0.5, 3.5, -1.0, 4.0, 0.75};
1605 plan.transform(work,
false);
1606 plan.transform(work,
true);
1613 std::mt19937_64
rng(44556677);
1614 std::uniform_real_distribution<double> dist(-5.0, 5.0);
1616 for (
const size_t n : {size_t(8), size_t(64), size_t(256), size_t(1024)})
1621 for (
size_t i = 0; i < n; ++i)
1625 for (
size_t i = 0; i < n; ++i)
1628 const auto spectrum =
plan.transformed(signal,
false);
1631 for (
size_t i = 0; i < n; ++i)
1635 <<
"Parseval failed for N=" << n;
1641 std::mt19937_64
rng(66778899);
1642 std::uniform_real_distribution<double> dist(-3.0, 3.0);
1644 const size_t n = 128;
1650 for (
size_t i = 0; i < n; ++i)
1653 y.append(Complex(dist(
rng), dist(
rng)));
1656 const double alpha = 3.7;
1657 const double beta = -2.1;
1661 for (
size_t i = 0; i < n; ++i)
1662 z.
append(alpha * x[i] + beta *
y[i]);
1664 const auto fft_z =
plan.transformed(z,
false);
1665 const auto fft_x =
plan.transformed(x,
false);
1666 const auto fft_y =
plan.transformed(
y,
false);
1670 for (
size_t i = 0; i < n; ++i)
1682 std::mt19937_64
rng(10203040);
1683 std::uniform_real_distribution<double> dist(-5.0, 5.0);
1685 for (
const size_t n : {size_t(32), size_t(64), size_t(128), size_t(256)})
1689 for (
size_t i = 0; i < n; ++i)
1693 const auto obtained = FFTD::transformed(signal,
false);
1695 for (
size_t i = 0; i < n; ++i)
1698 <<
"N=" << n <<
" bin=" << i;
1700 <<
"N=" << n <<
" bin=" << i;
1707 std::mt19937_64
rng(50607080);
1708 std::uniform_real_distribution<double> dist(-10.0, 10.0);
1710 for (
const size_t n : {size_t(256), size_t(1024), size_t(4096), size_t(16384)})
1714 for (
size_t i = 0; i < n; ++i)
1718 FFTD::transform(work,
false);
1719 FFTD::transform(work,
true);
1721 for (
size_t i = 0; i < n; ++i)
1724 <<
"N=" << n <<
" i=" << i;
1726 <<
"N=" << n <<
" i=" << i;
1733 std::mt19937_64
rng(90807060);
1734 std::uniform_real_distribution<double> dist(-10.0, 10.0);
1736 for (
const size_t n : {size_t(256), size_t(1024), size_t(4096)})
1740 for (
size_t i = 0; i < n; ++i)
1743 const auto spectrum = FFTD::transform(signal);
1744 const auto restored = FFTD::inverse_transform_real(spectrum);
1747 for (
size_t i = 0; i < n; ++i)
1749 <<
"N=" << n <<
" i=" << i;
1755 std::mt19937_64
rng(12121212);
1756 std::uniform_real_distribution<double> dist(-5.0, 5.0);
1758 for (
const size_t n : {size_t(256), size_t(1024), size_t(4096), size_t(16384)})
1762 for (
size_t i = 0; i < n; ++i)
1766 for (
size_t i = 0; i < n; ++i)
1769 const auto spectrum = FFTD::transformed(signal,
false);
1772 for (
size_t i = 0; i < n; ++i)
1776 <<
"Parseval failed for N=" << n;
1782 std::mt19937_64
rng(34343434);
1783 std::uniform_real_distribution<double> dist(-3.0, 3.0);
1785 for (
const size_t n : {size_t(8), size_t(64), size_t(512), size_t(4096)})
1790 for (
size_t i = 0; i < n; ++i)
1792 Complex val(dist(
rng), dist(
rng));
1797 const auto spectrum = FFTD::transformed(signal,
false);
1804 std::mt19937_64
rng(56565656);
1805 std::uniform_real_distribution<double> dist(-5.0, 5.0);
1807 for (
const size_t n : {size_t(64), size_t(256), size_t(1024)})
1811 for (
size_t i = 0; i < n; ++i)
1814 const auto spectrum = FFTD::transform(signal);
1818 <<
"DC should be real, N=" << n;
1820 <<
"Nyquist should be real, N=" << n;
1822 for (
size_t k = 1;
k < n / 2; ++
k)
1825 <<
"Re symmetry failed at k=" <<
k <<
" N=" << n;
1827 <<
"Im symmetry failed at k=" <<
k <<
" N=" << n;
1834 std::mt19937_64
rng(78787878);
1835 std::uniform_real_distribution<double> dist(-5.0, 5.0);
1837 for (
const size_t n : {size_t(64), size_t(256), size_t(1024)})
1841 for (
size_t i = 0; i < n; ++i)
1845 const auto complex_spectrum = FFTD::transformed(lift_real_input(signal),
false);
1853 std::mt19937_64
rng(11111111);
1854 std::uniform_real_distribution<double> dist(-5.0, 5.0);
1856 for (
const size_t n : {size_t(256), size_t(1024), size_t(4096), size_t(8192)})
1860 for (
size_t i = 0; i < n; ++i)
1863 const auto sequential = FFTD::transformed(signal,
false);
1864 const auto parallel = FFTD::ptransformed(pool, signal,
false);
1866 for (
size_t i = 0; i < n; ++i)
1869 <<
"N=" << n <<
" i=" << i;
1871 <<
"N=" << n <<
" i=" << i;
1879 std::mt19937_64
rng(22222222);
1880 std::uniform_real_distribution<double> dist(-5.0, 5.0);
1882 for (
const size_t n : {size_t(256), size_t(1024), size_t(4096)})
1886 for (
size_t i = 0; i < n; ++i)
1889 const auto sequential = FFTD::transform(signal);
1890 const auto parallel = FFTD::ptransform(pool, signal);
1898 std::mt19937_64
rng(33333333);
1899 std::uniform_real_distribution<double> dist(-2.0, 2.0);
1901 for (
const size_t n : {size_t(128), size_t(512), size_t(2048)})
1906 for (
size_t i = 0; i < n; ++i)
1912 const auto sequential = FFTD::multiply(a, b);
1913 const auto parallel = FFTD::pmultiply(pool, a, b);
1920 std::mt19937_64
rng(44444444);
1921 std::uniform_real_distribution<double> dist(-2.0, 2.0);
1923 for (
const size_t n : {size_t(50), size_t(100), size_t(200)})
1925 const size_t m = n / 2 + 1;
1929 for (
size_t i = 0; i < n; ++i)
1931 for (
size_t i = 0; i <
m; ++i)
1935 const auto obtained = FFTD::multiply(a, b);
1947 const auto spectrum = FFTD::transform(signal);
1955 const auto spectrum = FFTD::transform(signal);
1960 const auto restored = FFTD::inverse_transform_real(spectrum);
1967 const auto spectrum = FFTD::transform(signal);
1984 std::mt19937_64
rng(55555555);
1985 std::uniform_real_distribution<float> dist(-5.0f, 5.0f);
1987 for (
const size_t n : {size_t(64), size_t(256), size_t(1024)})
1991 for (
size_t i = 0; i < n; ++i)
1995 FFTF::transform(work,
false);
1996 FFTF::transform(work,
true);
1998 const float tol = 5e-3f * std::log2(
static_cast<float>(n));
2008 std::mt19937_64
rng(66666666);
2009 std::uniform_real_distribution<float> dist(-3.0f, 3.0f);
2011 for (
const size_t n : {size_t(64), size_t(256), size_t(1024)})
2015 for (
size_t i = 0; i < n; ++i)
2019 for (
size_t i = 0; i < n; ++i)
2022 auto spectrum = FFTF::transformed(signal,
false);
2024 for (
size_t i = 0; i < n; ++i)
2029 <<
"Float Parseval failed for N=" << n;
2040 const auto result = FFTF::multiply(a, b);
2046 for (
size_t i = 0; i <
expected.size(); ++i)
2057 signal.
append(Complex(1e+12, 0.0));
2058 signal.
append(Complex(1e-12, 0.0));
2059 signal.
append(Complex(-1e+12, 0.0));
2060 signal.
append(Complex(1e-12, 0.0));
2061 signal.
append(Complex(1e+6, 0.0));
2062 signal.
append(Complex(-1e+6, 0.0));
2063 signal.
append(Complex(1e-6, 0.0));
2064 signal.
append(Complex(-1e-6, 0.0));
2067 for (
size_t i = 0; i < signal.
size(); ++i)
2071 FFTD::transform(work,
false);
2072 FFTD::transform(work,
true);
2079 for (
size_t i = 0; i < signal.
size(); ++i)
2088 for (
size_t i = 0; i < signal.
size(); ++i)
2098 std::mt19937_64
rng(77777777);
2100 const size_t n = 1024;
2103 for (
size_t i = 0; i < n; ++i)
2105 const double scale = (i % 3 == 0) ? 1e+10 : ((i % 3 == 1) ? 1e-10 : 1.0);
2106 std::uniform_real_distribution<double> dist(-
scale,
scale);
2111 for (
size_t i = 0; i < n; ++i)
2114 const auto spectrum = FFTD::transformed(signal,
false);
2117 for (
size_t i = 0; i < n; ++i)
2131 std::mt19937_64
rng(88888888);
2132 std::uniform_real_distribution<double> dist(-3.0, 3.0);
2136 const size_t na =
static_cast<size_t>(
trial + 3);
2137 const size_t nb =
static_cast<size_t>(
trial + 2);
2142 for (
size_t i = 0; i <
na; ++i)
2144 for (
size_t i = 0; i <
nb; ++i)
2147 const auto ab = FFTD::multiply(a, b);
2148 const auto ba = FFTD::multiply(b, a);
2158 const auto result = FFTD::multiply(a, identity);
2167 const auto result = FFTD::multiply(a,
delay2);
2179 const auto result = FFTD::multiply(a,
scale);
2182 for (
size_t i = 0; i < a.
size(); ++i)
2183 EXPECT_NEAR(result[i], a[i] * 3.5, 1e-10) <<
"i=" << i;
2188 std::mt19937_64
rng(99999999);
2189 std::uniform_real_distribution<double> dist(-3.0, 3.0);
2192 for (
size_t i = 0; i < 5; ++i)
2194 for (
size_t i = 0; i < 4; ++i)
2197 const auto ab = FFTD::multiply(a, b);
2198 const auto ba = FFTD::multiply(b, a);
2206 const auto result = FFTD::multiply(a, b);
2213 std::mt19937_64
rng(12345678);
2214 std::uniform_real_distribution<double> dist(-3.0, 3.0);
2216 const size_t na = 5;
2217 const size_t nb = 4;
2222 for (
size_t i = 0; i <
na; ++i)
2224 for (
size_t i = 0; i <
nb; ++i)
2232 for (
size_t i = 0; i <
na; ++i)
2234 for (
size_t i =
na; i < n; ++i)
2235 a_padded.append(Complex(0.0, 0.0));
2236 for (
size_t i = 0; i <
nb; ++i)
2238 for (
size_t i =
nb; i < n; ++i)
2239 b_padded.append(Complex(0.0, 0.0));
2241 auto fa = FFTD::transformed(
a_padded,
false);
2242 auto fb = FFTD::transformed(
b_padded,
false);
2246 for (
size_t i = 0; i < n; ++i)
2251 for (
size_t i = 0; i <
required; ++i)
2257 const auto hann = FFTD::hann_window(5);
2258 const auto hamming = FFTD::hamming_window(5);
2259 const auto blackman = FFTD::blackman_window(5);
2284 const auto beta = FFTD::kaiser_beta(60.0);
2287 const auto kaiser = FFTD::kaiser_window(9, beta);
2301 const auto fir_bp = FFTD::firwin_bandpass(65, 700.0, 1500.0,
sample_rate, 70.0);
2302 const auto fir_bs = FFTD::firwin_bandstop(65, 700.0, 1500.0,
sample_rate, 70.0);
2323 EXPECT_THROW(FFTD::kaiser_beta(-1.0), std::invalid_argument);
2324 EXPECT_THROW(FFTD::kaiser_window(9, -1.0), std::invalid_argument);
2326 std::invalid_argument);
2344 for (
size_t i = 0; i <
weighted.size(); ++i)
2373 std::invalid_argument);
2375 std::invalid_argument);
2377 std::invalid_argument);
2379 std::invalid_argument);
2397 for (
size_t i = 0; i <
equiripple.size(); ++i)
2417 std::invalid_argument);
2419 std::invalid_argument);
2421 std::invalid_argument);
2430 const auto windowed_real = FFTD::apply_window(signal, window);
2454 FFTD::apply_window(signal, FFTD::hann_window(signal.
size())),
2478 Array<double> signal = {1.0, -0.5, 2.0, 0.25, -1.0, 3.0, 0.5, -2.0};
2479 const auto window = FFTD::hann_window(signal.
size());
2481 const auto manual_real = FFTD::spectrum(FFTD::apply_window(signal, window));
2482 const auto helper_real = FFTD::windowed_spectrum(signal, window);
2491 std::vector<double>
window_vec(window.begin(), window.end());
2509 const auto exact_offsets = FFTD::frame_offsets(5, 4, 2,
false);
2514 const auto frames = FFTD::frame_signal(signal, 4, 2,
true);
2522 EXPECT_THROW(FFTD::frame_offsets(5, 0, 2,
true), std::invalid_argument);
2534 const auto window = FFTD::hann_window(64);
2547 std::invalid_argument);
2556 const auto actual = FFTD::upfirdn(signal, coeffs, 3, 2);
2560 const auto same = FFTD::resample_poly(signal, 1, 1, identity);
2565 for (
size_t i = 0; i < 64; ++i)
2568 FFTD::ResamplePolyOptions
options;
2572 for (
size_t i = 16; i < 112; ++i)
2575 EXPECT_THROW(FFTD::upfirdn(signal, coeffs, 0, 1), std::invalid_argument);
2577 std::invalid_argument);
2579 FFTD::ResamplePolyOptions{0, 80.0}),
2580 std::invalid_argument);
2587 const auto padded = FFTD::frame_signal(signal, 4, 2,
true);
2593 const auto exact = FFTD::frame_signal(signal, 4, 2,
false);
2600 Array<double> signal = {1.0, -0.5, 2.0, 0.25, -1.0, 3.0, 0.5};
2603 const auto frames = FFTD::frame_signal(signal, window.
size(), 2,
true);
2604 const auto spectrogram = FFTD::stft(signal, window, 2,
true);
2607 for (
size_t i = 0; i <
frames.size(); ++i)
2609 const auto expected = FFTD::transform_padded(FFTD::apply_window(
frames[i], window));
2613 const auto hann_stft = FFTD::stft(signal, 4, 2,
true);
2623 EXPECT_THROW(FFTD::frame_signal(signal, 0, 1,
true), std::invalid_argument);
2624 EXPECT_THROW(FFTD::frame_signal(signal, 2, 0,
true), std::invalid_argument);
2632 Array<double> signal = {1.0, -0.5, 2.0, 0.25, -1.0, 3.0, 0.5, -2.0, 1.25};
2641 const auto parallel =
2656 Complex(3.0, 0.0), Complex(4.0, 0.0)}),
2658 Complex(1.5, 0.0), Complex(2.0, 0.0)})
2662 std::invalid_argument);
2664 std::invalid_argument);
2666 std::invalid_argument);
2668 std::invalid_argument);
2673 std::invalid_argument);
2679 std::invalid_argument);
2684 std::mt19937_64
rng(20260305);
2685 std::uniform_real_distribution<double> dist(-1.0, 1.0);
2689 for (
size_t i = 0; i < 23; ++i)
2692 const auto window = FFTD::hann_window(8);
2731 0.0, 1.0, 0.5, -0.25, -1.0, -0.5, 0.75, 1.25, 0.0, -0.75, 0.5
2757 std::mt19937_64
rng(20260306);
2758 std::uniform_real_distribution<double> dist(-1.0, 1.0);
2762 for (
size_t i = 0; i < 29; ++i)
2765 const auto window = FFTD::hann_window(8);
2774 const auto parallel = FFTD::pstft(pool, signal, window,
options);
2781 const size_t length = std::min(
size_t(5 + (
offset % 4)),
2785 for (
size_t i = 0; i < length; ++i)
2805 const size_t length = std::min(
size_t(3 + (
offset % 5)),
2809 for (
size_t i = 0; i < length; ++i)
2827 Array<double>({1.0, -0.5, 0.25, 2.0, -1.0, 0.5, 1.5, -0.75, 0.25}),
2828 Array<double>({-1.0, 0.75, 0.5, -0.25, 1.25, -1.5, 0.0, 0.5, 1.0, -0.5,
2833 const auto window = FFTD::hann_window(8);
2845 for (
size_t i = 0; i <
signals.size(); ++i)
2859 for (
size_t i = 0; i <
signals.size(); ++i)
2869 for (
size_t i = 0; i <
signals.size(); ++i)
2879 std::invalid_argument);
2885 std::mt19937_64
rng(20260307);
2886 std::uniform_real_distribution<double> dist(-1.0, 1.0);
2890 for (
size_t i = 0; i < 27; ++i)
2893 const auto window = FFTD::hann_window(8);
2913 const size_t length = std::min(
size_t(2 + (
offset % 3)),
2916 for (
size_t i = 0; i < length; ++i)
2919 const auto partial =
processor.process_block(chunk);
2920 for (
size_t i = 0; i < partial.size(); ++i)
2926 for (
size_t i = 0; i < tail.size(); ++i)
2935 for (
size_t i = 0; i <
full_tail.size(); ++i)
2943 const size_t length = std::min(
size_t(1 + (
offset % 4)),
2946 for (
size_t i = 0; i < length; ++i)
2950 for (
size_t i = 0; i < partial.size(); ++i)
2968 Array<double>({1.0, -0.5, 0.25, 2.0, -1.0, 0.5, 1.5, -0.75, 0.25, 0.0}),
2969 Array<double>({-1.0, 0.75, 0.5, -0.25, 1.25, -1.5, 0.0, 0.5, 1.0}),
2970 Array<double>({0.25, -0.125, 0.75, 1.5, -0.5, 0.0, 0.5, -0.75})
2975 const auto window = FFTD::hann_window(8);
2990 for (
size_t i = 0; i <
signals.size(); ++i)
3006 for (
size_t channel = 0; channel <
signals.size(); ++channel)
3013 for (
size_t i = 0; i < length; ++i)
3025 for (
size_t channel = 0; channel <
signals.size(); ++channel)
3032 const auto tail =
analyzer.flush();
3034 for (
size_t channel = 0; channel <
signals.size(); ++channel)
3042 FFTD::BatchedISTFTProcessor inverse(
signals.size(),
3060 for (
size_t channel = 0; channel <
offline.size(); ++channel)
3062 const size_t remaining =
offline[channel].
size() - frame_offsets[channel];
3066 for (
size_t i = 0; i < length; ++i)
3068 frame_offsets(channel) += length;
3076 const auto emitted = inverse.process_block(block);
3078 for (
size_t channel = 0; channel <
signals.size(); ++channel)
3087 for (
size_t channel = 0; channel <
signals.size(); ++channel)
3100 FFTD::ISTFTProcessor inverse;
3109 std::runtime_error);
3117 Complex(0.25, -0.75), Complex(3.0, 0.0)}),
3119 Complex(0.5, 0.5), Complex(-0.75, 1.25)})
3123 for (
size_t row = 0; row <
matrix.size(); ++row)
3124 for (
size_t col = 0; col <
matrix[row].size(); ++col)
3128 auto transformed =
flat;
3129 FFTD::transform_axis(transformed,
row_major, 1,
false);
3131 for (
size_t row = 0; row <
matrix.size(); ++row)
3134 for (
size_t col = 0; col <
expected.size(); ++col)
3139 for (
size_t col = 0; col < 4; ++col)
3152 for (
size_t row = 0; row <
matrix.size(); ++row)
3155 for (
size_t col = 0; col <
expected.size(); ++col)
3165 Complex(-1.0, 0.25), Complex(0.5, 1.0)}),
3167 Complex(0.0, 0.5), Complex(-2.0, 0.0)}),
3169 Complex(2.5, 0.0), Complex(1.0, -1.5)})
3173 for (
size_t row = 0; row <
expected.size(); ++row)
3176 for (
size_t col = 0; col <
expected[0].size(); ++col)
3179 for (
size_t row = 0; row <
expected.size(); ++row)
3181 column = FFTD::transformed(column);
3182 for (
size_t row = 0; row <
expected.size(); ++row)
3196 Array<Complex>({Complex(1.0, 0.0), Complex(0.5, -0.25), Complex(-1.0, 0.5)}),
3197 Array<Complex>({Complex(2.0, 1.0), Complex(-0.75, 0.0), Complex(1.5, -0.5)})
3200 Array<Complex>({Complex(-0.5, 1.25), Complex(1.0, 0.0), Complex(0.25, -0.75)}),
3201 Array<Complex>({Complex(0.0, 0.5), Complex(-1.5, 0.25), Complex(2.0, 0.0)})
3211 for (
size_t i = 0; i <
tensor.size(); ++i)
3217 for (
size_t i = 0; i <
tensor.size(); ++i)
3218 for (
size_t j = 0; j <
tensor[i].size(); ++j)
3219 for (
size_t k = 0;
k <
tensor[i][j].size(); ++
k)
3223 FFTD::transformed_axes(
flat,
3228 for (
size_t i = 0; i <
expected2d.size(); ++i)
3229 for (
size_t j = 0; j <
expected2d[i].size(); ++j)
3230 for (
size_t k = 0;
k <
expected2d[i][j].size(); ++
k, ++index)
3238 Array<double>({1.0, -0.5, 0.25, 2.0, -1.0, 0.5, 1.5, -0.75, 0.25}),
3239 Array<double>({-1.0, 0.75, 0.5, -0.25, 1.25, -1.5, 0.0, 0.5, 1.0})
3241 const auto window = FFTD::hann_window(8);
3258 FFTD::multichannel_stft(
signals,
3261 FFTD::SpectrogramLayout::channel_frame_bin);
3263 FFTD::multichannel_stft(
signals,
3266 FFTD::SpectrogramLayout::frame_channel_bin);
3268 FFTD::pmultichannel_stft(pool,
3272 FFTD::SpectrogramLayout::frame_channel_bin);
3276 FFTD::SpectrogramLayout::frame_channel_bin,
3277 FFTD::SpectrogramLayout::channel_frame_bin);
3280 FFTD::SpectrogramLayout::frame_channel_bin,
3281 FFTD::SpectrogramLayout::channel_frame_bin);
3291 FFTD::SpectrogramLayout::frame_channel_bin);
3293 FFTD::pmultichannel_istft(pool,
3299 FFTD::SpectrogramLayout::frame_channel_bin);
3316 std::mt19937_64
rng(56473829);
3317 std::uniform_real_distribution<double> dist(-2.0, 2.0);
3321 for (
size_t i = 0; i < 41; ++i)
3327 const auto obtained = FFTD::filtfilt(signal, coeffs, 16);
3334 Array<double> signal = {1.0, -1.0, 2.0, -2.0, 0.5, 3.0, -0.5, 1.5};
3337 const auto sequential = FFTD::filtfilt(signal, coeffs, 8);
3338 const auto parallel = FFTD::pfiltfilt(pool, signal, coeffs, 8);
3352 EXPECT_TRUE(FFTD::filtfilt(empty, coeffs).is_empty());
3353 EXPECT_TRUE(FFTD::filtfilt(signal, empty).is_empty());
3372 std::mt19937_64
rng(11235813);
3373 std::uniform_real_distribution<double> dist(-2.0, 2.0);
3377 for (
size_t i = 0; i < 57; ++i)
3382 FFTD::BiquadSection
section{0.075, 0.15, 0.075, 1.0, -0.9, 0.2};
3385 const auto obtained = FFTD::filtfilt(signal, numerator, denominator);
3400 std::mt19937_64
rng(42424242);
3401 std::uniform_real_distribution<double> dist(-1.5, 1.5);
3405 for (
size_t i = 0; i < 64; ++i)
3409 FFTD::BiquadSection{0.075, 0.15, 0.075, 1.0, -0.9, 0.2},
3410 FFTD::BiquadSection{0.14, 0.28, 0.14, 1.0, -0.5, 0.06}
3423 std::mt19937_64
rng(17171717);
3424 std::uniform_real_distribution<double> dist(-1.0, 1.0);
3428 for (
size_t i = 0; i < 48; ++i)
3434 const auto expected = FFTD::lfilter(signal, numerator, denominator);
3436 FFTD::LFilter
filter(numerator, denominator);
3442 const size_t length = std::min(
size_t(11), signal.
size() -
offset);
3445 for (
size_t i = 0; i < length; ++i)
3448 const auto partial =
filter.filter(chunk);
3449 for (
size_t i = 0; i < partial.size(); ++i)
3461 std::mt19937_64
rng(31313131);
3462 std::uniform_real_distribution<double> dist(-1.0, 1.0);
3466 for (
size_t i = 0; i < 52; ++i)
3470 FFTD::BiquadSection{0.075, 0.15, 0.075, 1.0, -0.9, 0.2},
3471 FFTD::BiquadSection{0.14, 0.28, 0.14, 1.0, -0.5, 0.06}
3481 const size_t length = std::min(
size_t(9), signal.
size() -
offset);
3484 for (
size_t i = 0; i < length; ++i)
3487 const auto partial =
filter.filter(chunk);
3488 for (
size_t i = 0; i < partial.size(); ++i)
3502 Array<double>({1.0, -0.5, 0.25, 2.0, -1.0, 0.5, 1.5, -0.75, 0.25}),
3503 Array<double>({-1.0, 0.75, 0.5, -0.25, 1.25, -1.5, 0.0, 0.5}),
3511 for (
size_t i = 0; i <
signals.size(); ++i)
3514 const auto batch = FFTD::batched_lfilter(
signals, numerator, denominator);
3516 FFTD::pbatched_lfilter(pool,
signals, numerator, denominator);
3517 for (
size_t i = 0; i <
signals.size(); ++i)
3523 FFTD::LFilterBank
bank(
signals.size(), numerator, denominator);
3533 for (
size_t channel = 0; channel <
signals.size(); ++channel)
3540 for (
size_t i = 0; i < length; ++i)
3552 for (
size_t channel = 0; channel <
signals.size(); ++channel)
3559 for (
size_t i = 0; i <
signals.size(); ++i)
3567 for (
size_t i = 0; i <
signals.size(); ++i)
3575 Array<double>({1.0, -0.5, 0.25, 2.0, -1.0, 0.5, 1.5, -0.75, 0.25}),
3576 Array<double>({-1.0, 0.75, 0.5, -0.25, 1.25, -1.5, 0.0, 0.5}),
3580 FFTD::BiquadSection{0.075, 0.15, 0.075, 1.0, -0.9, 0.2},
3581 FFTD::BiquadSection{0.14, 0.28, 0.14, 1.0, -0.5, 0.06}
3586 for (
size_t i = 0; i <
signals.size(); ++i)
3591 for (
size_t i = 0; i <
signals.size(); ++i)
3607 for (
size_t channel = 0; channel <
signals.size(); ++channel)
3614 for (
size_t i = 0; i < length; ++i)
3626 for (
size_t channel = 0; channel <
signals.size(); ++channel)
3633 for (
size_t i = 0; i <
signals.size(); ++i)
3641 for (
size_t i = 0; i <
signals.size(); ++i)
3654 FFTD::BiquadSection
s1{0.075, 0.15, 0.075, 1.0, -0.9, 0.2};
3655 FFTD::BiquadSection
s2{0.14, 0.28, 0.14, 1.0, -0.5, 0.06};
3658 const auto r1 = FFTD::freqz(
s1, 9,
false);
3659 const auto r2 = FFTD::freqz(
s2, 9,
false);
3660 const auto rs = FFTD::freqz(
sections, 9,
false);
3661 for (
size_t i = 0; i <
rs.response.size(); ++i)
3669 FFTD::IIRCoefficients coeffs{numerator, denominator};
3670 FFTD::BiquadSection
section{0.5, 0.5, 0.0, 1.0, -0.9, 0.2};
3677 Complex(0.4, 0.0)}),
3690 const auto response = FFTD::freqz(
delay_line, 65,
false);
3691 const auto group = FFTD::group_delay(response);
3692 const auto phase = FFTD::phase_delay(response);
3699 for (
size_t i = 1; i + 1 <
group.size(); ++i)
3711 const auto pairs = FFTD::pair_poles_and_zeros(numerator, denominator);
3715 EXPECT_NEAR(FFTD::minimum_pole_zero_distance(numerator, denominator), 0.01, 1e-8);
3716 EXPECT_NEAR(FFTD::stability_margin(denominator), 0.5, 1e-8);
3718 EXPECT_TRUE(FFTD::has_near_pole_zero_cancellation(numerator, denominator, 0.02));
3719 EXPECT_FALSE(FFTD::has_near_pole_zero_cancellation(numerator, denominator, 0.005));
3720 EXPECT_THROW(FFTD::validate_no_near_pole_zero_cancellation(numerator,
3724 EXPECT_NO_THROW(FFTD::validate_no_near_pole_zero_cancellation(numerator,
3729 EXPECT_THROW(FFTD::validate_stable(denominator, 0.6), std::domain_error);
3735 Complex(0.985, 0.0),
3736 Complex(0.972, 0.0),
3737 Complex(0.91, 0.12),
3738 Complex(0.91, -0.12),
3739 Complex(0.84, 0.21),
3740 Complex(0.84, -0.21),
3744 const auto polynomial = real_polynomial_from_roots(roots);
3748 for (
size_t i = 0; i <
polynomial.size(); ++i)
3755 std::mt19937_64
rng(20260306);
3756 std::uniform_real_distribution<double>
real_dist(-0.92, 0.92);
3757 std::uniform_real_distribution<double>
radius_dist(0.55, 0.95);
3758 std::uniform_real_distribution<double>
angle_dist(0.12, 1.0);
3775 const auto denominator = real_polynomial_from_roots(roots);
3776 const auto recovered = FFTD::poles(denominator);
3784 FFTD::BiquadSection
s1{0.075, 0.15, 0.075, 1.0, -0.9, 0.2};
3785 FFTD::BiquadSection
s2{0.14, 0.28, 0.14, 1.0, -0.5, 0.06};
3790 const auto group_1 = FFTD::group_delay(
s1, 257,
false);
3791 const auto group_2 = FFTD::group_delay(
s2, 257,
false);
3792 const auto phase_1 = FFTD::phase_delay(
s1, 257,
false);
3793 const auto phase_2 = FFTD::phase_delay(
s2, 257,
false);
3812 FFTD::BiquadSection{0.3, 0.6, 0.3, 1.0, -0.9, 0.2},
3813 FFTD::BiquadSection{0.14, 0.28, 0.14, 1.0, -0.5, 0.06}
3818 FFTD::phase_margin(FFTD::freqz(
sections, 32769,
true));
3826 FFTD::gain_margin(FFTD::freqz(
sections, 32769,
true));
3835 FFTD::BiquadSection
s1{0.075, 0.15, 0.075, 1.0, -0.9, 0.2};
3836 FFTD::BiquadSection
s2{0.2, 0.1, 0.05, 1.0, -1.7, 0.72};
3839 const double margin_1 = FFTD::stability_margin(
s1);
3840 const double margin_2 = FFTD::stability_margin(
s2);
3851 std::polar(2.0, 0.0),
3852 std::polar(1.0, -std::numbers::pi / 2.0),
3853 std::polar(0.5, -3.0 * std::numbers::pi / 4.0)
3858 EXPECT_NEAR(phase_margin.crossover_omega, 1.0, 1e-12);
3859 EXPECT_NEAR(phase_margin.radians, std::numbers::pi / 2.0, 1e-12);
3865 std::polar(2.0, -std::numbers::pi / 2.0),
3866 std::polar(0.5, -std::numbers::pi),
3867 std::polar(0.25, -3.0 * std::numbers::pi / 2.0)
3872 EXPECT_NEAR(gain_margin.crossover_omega, 1.0, 1e-12);
3874 EXPECT_NEAR(gain_margin.decibels, 20.0 * std::log10(2.0), 1e-12);
3880 FFTD::SOSFilter
sos;
3903 const auto butter_lp = FFTD::butterworth_lowpass(4, 800.0, 8000.0);
3904 const auto butter_hp = FFTD::butterworth_highpass(4, 800.0, 8000.0);
3905 const auto cheby_lp = FFTD::chebyshev1_lowpass(4, 1.0, 800.0, 8000.0);
3906 const auto cheby_hp = FFTD::chebyshev1_highpass(5, 1.0, 800.0, 8000.0);
3924 std::pow(10.0, -1.0 / 20.0),
3934 EXPECT_THROW(FFTD::butterworth_lowpass(0, 800.0, 8000.0), std::invalid_argument);
3935 EXPECT_THROW(FFTD::butterworth_lowpass(4, 4000.0, 8000.0), std::invalid_argument);
3936 EXPECT_THROW(FFTD::chebyshev1_lowpass(4, 0.0, 800.0, 8000.0),
3937 std::invalid_argument);
3948 FFTD::chebyshev1_bandpass(4, 1.0, 700.0, 1500.0,
sample_rate);
3950 FFTD::chebyshev1_bandstop(4, 1.0, 700.0, 1500.0,
sample_rate);
3952 FFTD::chebyshev2_lowpass(4, 40.0, 900.0,
sample_rate);
3954 FFTD::chebyshev2_highpass(4, 40.0, 900.0,
sample_rate);
3956 FFTD::chebyshev2_bandpass(4, 40.0, 700.0, 1500.0,
sample_rate);
3958 FFTD::chebyshev2_bandstop(4, 40.0, 700.0, 1500.0,
sample_rate);
4028 std::invalid_argument);
4030 std::invalid_argument);
4032 std::invalid_argument);
4041 FFTD::elliptic_lowpass(4, 1.0, 40.0, 900.0,
sample_rate);
4043 FFTD::elliptic_highpass(4, 1.0, 40.0, 900.0,
sample_rate);
4045 FFTD::elliptic_bandpass(4, 1.0, 40.0, 700.0, 1500.0,
sample_rate);
4047 FFTD::elliptic_bandstop(4, 1.0, 40.0, 700.0, 1500.0,
sample_rate);
4075 std::invalid_argument);
4077 std::invalid_argument);
4079 std::invalid_argument);
4084 std::mt19937_64
rng(24681357);
4085 std::uniform_real_distribution<double> dist(-2.0, 2.0);
4089 for (
size_t i = 0; i < 257; ++i)
4094 for (
size_t i = 0; i < 37; ++i)
4097 const auto expected = FFTD::multiply(signal, kernel);
4099 for (
const size_t block_size : {size_t(0), size_t(8), size_t(31), size_t(64)})
4101 const auto obtained = FFTD::overlap_add_convolution(signal, kernel, block_size);
4109 std::mt19937_64
rng(97531864);
4110 std::uniform_real_distribution<double> dist(-3.0, 3.0);
4114 for (
size_t i = 0; i < 513; ++i)
4119 for (
size_t i = 0; i < 29; ++i)
4126 const auto sequential =
convolver.convolve(signal);
4127 const auto parallel =
convolver.pconvolve(pool, signal);
4128 const auto expected = FFTD::multiply(signal, kernel);
4147 EXPECT_TRUE(FFTD::overlap_add_convolution(empty, kernel).is_empty());
4148 EXPECT_TRUE(FFTD::overlap_add_convolution(signal, empty).is_empty());
4150 std::invalid_argument);
4155 std::mt19937_64
rng(12344321);
4156 std::uniform_real_distribution<double> dist(-2.0, 2.0);
4160 for (
size_t i = 0; i < 150; ++i)
4165 for (
size_t i = 0; i < 17; ++i)
4171 const size_t chunks[] = {13, 7, 64, 5, 61};
4173 for (
const size_t chunk_size :
chunks)
4177 for (
size_t i = 0; i < chunk_size; ++i)
4182 for (
size_t i = 0; i <
emitted.size(); ++i)
4187 for (
size_t i = 0; i < tail.size(); ++i)
4190 const auto expected = FFTD::multiply(signal, kernel);
4197 std::mt19937_64
rng(99884411);
4198 std::uniform_real_distribution<double> dist(-1.5, 1.5);
4202 for (
size_t i = 0; i < 96; ++i)
4207 for (
size_t i = 0; i < 11; ++i)
4215 const size_t length = std::min(
size_t(19), signal.
size() -
offset);
4218 for (
size_t i = 0; i < length; ++i)
4222 for (
size_t i = 0; i <
emitted.size(); ++i)
4226 for (
size_t i = 0; i <
first_tail.size(); ++i)
4229 const auto expected = FFTD::multiply(signal, kernel);
4235 for (
size_t i = 0; i <
full_block.size(); ++i)
4247 std::mt19937_64
rng(11235813);
4248 std::uniform_real_distribution<double> dist(-1.5, 1.5);
4252 for (
size_t i = 0; i < 193; ++i)
4257 for (
size_t i = 0; i < 29; ++i)
4260 const auto expected = FFTD::multiply(signal, kernel);
4262 for (
const size_t block_size : {size_t(0), size_t(8), size_t(32)})
4265 FFTD::overlap_save_convolution(signal, kernel, block_size);
4268 FFTD::OverlapSave
processor(kernel, block_size);
4283 std::mt19937_64
rng(424242);
4284 std::uniform_real_distribution<double> dist(-1.0, 1.0);
4288 for (
size_t i = 0; i < 257; ++i)
4293 for (
size_t i = 0; i < 73; ++i)
4296 const auto expected = FFTD::multiply(signal, kernel);
4298 for (
const size_t partition_size : {size_t(0), size_t(8), size_t(16)})
4301 FFTD::partitioned_convolution(signal, kernel, partition_size);
4304 FFTD::PartitionedConvolver
processor(kernel, partition_size);
4320 std::mt19937_64
rng(123987456);
4321 std::uniform_real_distribution<double> dist(-2.0, 2.0);
4325 for (
const size_t size : {size_t(193), size_t(257), size_t(141)})
4329 for (
size_t i = 0; i <
size; ++i)
4336 for (
size_t i = 0; i < 23; ++i)
4339 FFTD::OverlapAddBank
bank(
signals.size(), kernel, 48);
4341 const auto parallel =
bank.pconvolve(pool,
signals);
4343 FFTD::poverlap_add_convolution_batch(pool,
signals, kernel, 48);
4348 for (
size_t channel = 0; channel <
signals.size(); ++channel)
4360 std::mt19937_64
rng(555666777);
4361 std::uniform_real_distribution<double> dist(-1.5, 1.5);
4365 for (
const size_t size : {size_t(96), size_t(141), size_t(87)})
4369 for (
size_t i = 0; i <
size; ++i)
4376 for (
size_t i = 0; i < 13; ++i)
4379 FFTD::OverlapAddBank
bank(
signals.size(), kernel, 24);
4388 for (
size_t channel = 0; channel <
signals.size(); ++channel)
4395 for (
size_t i = 0; i < length; ++i)
4405 const auto emitted =
bank.pprocess_block(pool, block);
4406 for (
size_t channel = 0; channel <
signals.size(); ++channel)
4410 const auto tail =
bank.pflush(pool);
4411 for (
size_t channel = 0; channel <
signals.size(); ++channel)
4414 for (
size_t channel = 0; channel <
signals.size(); ++channel)
4423 for (
size_t channel = 0; channel <
signals.size(); ++channel)
4442 FFTD::OverlapAddBank
bank(
signals.size(), kernel, 4);
4444 const auto parallel =
bank.pconvolve(pool,
signals);
4470 const auto tail =
bank.pflush(pool);
4471 for (
size_t channel = 0; channel <
signals.size(); ++channel)
Simple dynamic array with automatic resizing and functional operations.
static Array create(size_t n)
Create an array with n logical elements.
constexpr size_t size() const noexcept
Return the number of elements stored in the stack.
constexpr bool is_empty() const noexcept
Checks if the container is empty.
T & append(const T &data)
Append a copy of data
void reserve(size_t cap)
Reserves cap cells into the array.
Fast Fourier Transform (FFT) and DSP Toolkit.
A reusable thread pool for efficient parallel task execution.
iterator end() noexcept
Return an STL-compatible end iterator.
iterator begin() noexcept
Return an STL-compatible iterator to the first element.
Fast Fourier Transform (FFT) and Digital Signal Processing (DSP) toolkit.
const long double offset[]
Offset values indexed by symbol string length (bounded by MAX_OFFSET_INDEX)
Main namespace for Aleph-w library functions.
and
Check uniqueness with explicit hash + equality functors.
size_t size(Node *root) noexcept
Container2< typename Container1::Item_Type > filter(Container1 &container, Operation &operation)
Filter elements that satisfy operation.
Divide_Conquer_DP_Result< Cost > divide_and_conquer_partition_dp(const size_t groups, const size_t n, Transition_Cost_Fn transition_cost, const Cost inf=dp_optimization_detail::default_inf< Cost >())
Optimize partition DP using divide-and-conquer optimization.
T product(const Container &container, const T &init=T{1})
Compute product of all elements.
std::pair< First, Second > pair
Alias to std::pair kept for backwards compatibility.
void next()
Advance all underlying iterators (bounds-checked).
auto max_value(const Container &data) -> std::decay_t< decltype(*std::begin(data))>
Compute maximum value.
T sum(const Container &container, const T &init=T{})
Compute sum of all elements.
static struct argp_option options[]
static void section(const string &title)
FooMap m(5, fst_unit_pair_hash, snd_unit_pair_hash)
Dynamic array container with automatic resizing.