81 explicit operator bool() const noexcept {
134 explicit operator bool() const noexcept {
157 explicit operator bool() const noexcept {
164inline constexpr double pi = 3.141592653589793238462643383279502884;
167 const bool at_dc = omega == 0.0;
168 const bool at_nyquist = omega ==
pi;
171 (at_dc || at_nyquist)) ||
177inline std::complex<double>
fir_response(std::span<const double> coefficients,
178 double omega)
noexcept {
179 std::complex<double> response{};
180 const std::complex<double> step = std::polar(1.0, -omega);
181 std::complex<double> phase{1.0, 0.0};
182 for (
double coefficient : coefficients) {
183 response += coefficient * phase;
194 if (coefficients.empty())
198 const double delay = 0.5 *
static_cast<double>(coefficients.size() - 1u);
199 const auto zero_phase =
fir_response(coefficients, omega) * std::polar(1.0,
delay * omega);
202 return antisymmetric ? zero_phase.imag() : zero_phase.real();
205namespace fir_design_detail {
212 return (count & 1u) != 0
u;
214 return (count & 1u) == 0
u;
216 return count >= 3u && (count & 1u) != 0
u;
218 return (count & 1u) == 0
u;
224 std::size_t count)
noexcept {
233 return column == 0
u ? 1.0 : 2.0 * std::cos(
static_cast<double>(column) * omega);
235 return 2.0 * std::cos((
static_cast<double>(column) + 0.5) * omega);
237 return 2.0 * std::sin((
static_cast<double>(column) + 1.0) * omega);
239 return 2.0 * std::sin((
static_cast<double>(column) + 0.5) * omega);
245 result.coefficients.clear();
246 result.measured_amplitudes.clear();
247 result.errors.clear();
248 result.weighted_rms_error = 0.0;
249 result.maximum_absolute_error = 0.0;
253 result.fft_size = 0
u;
254 result.coefficients.clear();
255 result.measured_magnitudes.clear();
256 result.errors.clear();
257 result.rms_error = 0.0;
258 result.maximum_absolute_error = 0.0;
262 return value >= 2u && (value & (value - 1u)) == 0
u;
266 std::size_t coefficients, std::uint64_t limit)
noexcept {
272 if (!charge.
add<std::complex<double>>(fft_size) ||
273 !charge.
add<std::complex<double>>(fft_size / 2u) || !charge.
add<
double>(coefficients) ||
274 !charge.
add<
double>(bins) || !charge.
add<
double>(bins))
276 return charge.
total() <= limit;
280 std::uint64_t limit)
noexcept {
281 std::uint64_t matrix_elements = 0;
284 rows, columns,
static_cast<std::uint64_t
>(std::numeric_limits<std::size_t>::max()),
288 if (!charge.
add<
double>(matrix_elements) || !charge.
add<
double>(rows) ||
289 !charge.
add<std::size_t>(columns) || !charge.
add<
double>(columns) ||
290 !charge.
add<
double>(columns) || !charge.
add<
double>(columns) ||
291 !charge.
add<
double>(columns) || !charge.
add<
double>(taps) || !charge.
add<
double>(rows) ||
292 !charge.
add<
double>(rows))
294 return charge.
total() <= limit;
298 std::span<double> coefficients)
noexcept {
299 const std::size_t count = coefficients.size();
300 const std::size_t half = count / 2u;
303 for (std::size_t k = 1u; k <
independent.size(); ++k)
304 coefficients[half - k] = coefficients[half + k] =
independent[k];
310 coefficients[half] = 0.0;
312 const std::size_t offset =
314 const std::size_t
left = half - 1u - k;
315 const std::size_t
right =
341 if (!valid_type_length(options.
type, options.
tap_count) || points.empty() ||
348 const std::size_t rows = points.size();
349 const std::size_t columns = independent_coefficient_count(options.
type, options.
tap_count);
350 double maximum_weight = 0.0;
351 for (
const auto& point : points) {
352 if (!std::isfinite(point.omega) || point.omega < 0.0 || point.omega > pi ||
353 !std::isfinite(point.amplitude) || !(point.weight > 0.0) ||
354 !std::isfinite(point.weight))
356 maximum_weight = std::max(maximum_weight, point.weight);
358 if (rows < columns) {
362 const double maximum_weight_sqrt = std::sqrt(maximum_weight);
363 if (!admit_least_squares_workspace(rows, columns, options.
tap_count,
369#if defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND)
372 std::vector<double> matrix(rows * columns);
373 std::vector<double> rhs(rows);
374 std::vector<std::size_t> permutation(columns);
375 std::vector<double> solution(columns);
376 for (std::size_t row = 0
u; row < rows; ++row) {
380 const double scale = std::sqrt(points[row].weight) / maximum_weight_sqrt;
381 rhs[row] = scale * points[row].amplitude;
382 if (!std::isfinite(rhs[row])) {
386 for (std::size_t column = 0
u; column < columns; ++column) {
387 matrix[row * columns + column] =
388 scale * basis_value(options.
type, column, points[row].omega);
389 if (!std::isfinite(matrix[row * columns + column])) {
395 std::iota(permutation.begin(), permutation.end(), std::size_t{0});
397 double leading_norm = 0.0;
398 for (std::size_t column = 0
u; column < columns; ++column) {
400 for (std::size_t row = 0
u; row < rows; ++row)
401 norm = std::hypot(norm, matrix[row * columns + column]);
402 leading_norm = std::max(leading_norm, norm);
404 if (!std::isfinite(leading_norm)) {
408 if (!(leading_norm > 0.0)) {
413 const double rank_threshold = options.
rank_tolerance * leading_norm;
414 double minimum_diagonal = std::numeric_limits<double>::infinity();
415 double maximum_diagonal = 0.0;
416 for (std::size_t step = 0
u; step < columns; ++step) {
417 std::size_t pivot = step;
418 double pivot_norm = -1.0;
419 for (std::size_t column = step; column < columns; ++column) {
421 for (std::size_t row = step; row < rows; ++row)
422 norm = std::hypot(norm, matrix[row * columns + column]);
423 if (norm > pivot_norm) {
428 if (!std::isfinite(pivot_norm)) {
433 if (!(pivot_norm > rank_threshold)) {
439 for (std::size_t row = 0
u; row < rows; ++row)
440 std::swap(matrix[row * columns + step], matrix[row * columns + pivot]);
441 std::swap(permutation[step], permutation[pivot]);
444 const double x0 = matrix[step * columns + step];
445 const double alpha = x0 >= 0.0 ? -pivot_norm : pivot_norm;
446 matrix[step * columns + step] = x0 - alpha;
447 double vector_norm_squared = 0.0;
448 for (std::size_t row = step; row < rows; ++row) {
449 const double value = matrix[row * columns + step];
450 vector_norm_squared += value * value;
452 if (!(vector_norm_squared > 0.0) || !std::isfinite(vector_norm_squared)) {
454 clear_payload(result);
457 const double beta = 2.0 / vector_norm_squared;
458 for (std::size_t column = step + 1u; column < columns; ++column) {
460 for (std::size_t row = step; row < rows; ++row)
461 dot += matrix[row * columns + step] * matrix[row * columns + column];
462 const double factor = beta * dot;
463 for (std::size_t row = step; row < rows; ++row)
464 matrix[row * columns + column] -= factor * matrix[row * columns + step];
466 double rhs_dot = 0.0;
467 for (std::size_t row = step; row < rows; ++row)
468 rhs_dot += matrix[row * columns + step] * rhs[row];
469 const double rhs_factor = beta * rhs_dot;
470 for (std::size_t row = step; row < rows; ++row)
471 rhs[row] -= rhs_factor * matrix[row * columns + step];
472 matrix[step * columns + step] = alpha;
473 for (std::size_t row = step + 1u; row < rows; ++row)
474 matrix[row * columns + step] = 0.0;
476 const double diagonal = std::abs(alpha);
477 minimum_diagonal = std::min(minimum_diagonal, diagonal);
478 maximum_diagonal = std::max(maximum_diagonal, diagonal);
494 for (std::size_t column =
reverse + 1u; column < columns; ++column)
495 value -= matrix[
reverse * columns + column] * solution[column];
497 if (!std::isfinite(solution[
reverse])) {
499 clear_payload(result);
508 const double refinement_condition_limit =
509 1.0 / std::sqrt(std::sqrt(std::numeric_limits<double>::epsilon()));
511 std::vector<double> correction(columns, 0.0);
512 std::vector<double> gradient(columns, 0.0);
513 for (std::size_t row = 0
u; row < rows; ++row) {
514 const double scale = std::sqrt(points[row].weight) / maximum_weight_sqrt;
515 double predicted = 0.0;
516 for (std::size_t column = 0
u; column < columns; ++column) {
518 scale * basis_value(options.
type, permutation[column], points[row].omega);
519 predicted = std::fma(value, solution[column], predicted);
521 const double residual = scale * points[row].amplitude - predicted;
522 if (!std::isfinite(residual)) {
524 clear_payload(result);
527 for (std::size_t column = 0
u; column < columns; ++column) {
529 scale * basis_value(options.
type, permutation[column], points[row].omega);
530 gradient[column] = std::fma(value, residual, gradient[column]);
533 for (std::size_t column = 0
u; column < columns; ++column) {
534 double value = gradient[column];
535 if (!std::isfinite(value)) {
537 clear_payload(result);
540 for (std::size_t row = 0
u; row < column; ++row)
541 value -= matrix[row * columns + column] * correction[row];
542 correction[column] = value / matrix[column * columns + column];
543 if (!std::isfinite(correction[column])) {
545 clear_payload(result);
550 double value = correction[
reverse];
551 for (std::size_t column =
reverse + 1u; column < columns; ++column)
552 value -= matrix[
reverse * columns + column] * correction[column];
554 if (!std::isfinite(correction[
reverse])) {
556 clear_payload(result);
560 double linear_gain = 0.0;
561 double correction_energy = 0.0;
562 for (std::size_t row = 0
u; row < columns; ++row) {
563 linear_gain = std::fma(correction[row], gradient[row], linear_gain);
564 double transformed = 0.0;
565 for (std::size_t column = row; column < columns; ++column)
567 std::fma(matrix[row * columns + column], correction[column], transformed);
568 correction_energy = std::fma(transformed, transformed, correction_energy);
570 const double predicted_reduction = 2.0 * linear_gain - correction_energy;
571 if (std::isfinite(predicted_reduction) && predicted_reduction > 0.0) {
572 bool finite_candidate =
true;
573 for (std::size_t column = 0
u; column < columns; ++column) {
574 gradient[column] = solution[column] + correction[column];
575 finite_candidate = finite_candidate && std::isfinite(gradient[column]);
577 if (finite_candidate)
581 std::vector<double> unpermuted(columns);
582 for (std::size_t column = 0
u; column < columns; ++column)
583 unpermuted[permutation[column]] = solution[column];
588 result.
errors.resize(rows);
589 double weighted_squared_error = 0.0;
590 double weight_sum = 0.0;
591 for (std::size_t row = 0
u; row < rows; ++row) {
592 const double measured =
594 const double error = measured - points[row].amplitude;
595 if (!std::isfinite(measured) || !std::isfinite(error)) {
597 clear_payload(result);
601 result.
errors[row] = error;
604 const double scale = std::sqrt(points[row].weight) / maximum_weight_sqrt;
605 const double scaled_error = scale * error;
606 if (!std::isfinite(scaled_error)) {
608 clear_payload(result);
611 weighted_squared_error += scaled_error * scaled_error;
612 weight_sum += scale * scale;
617 clear_payload(result);
622#if defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND)
623 }
catch (
const std::bad_alloc&) {
624 clear_payload(result);
627 }
catch (
const std::length_error&) {
628 clear_payload(result);
635namespace fir_design_detail {
641 std::size_t n)
noexcept {
642 for (std::size_t column = 0
u; column < n; ++column) {
643 std::size_t pivot = column;
644 double best = std::abs(matrix[column * n + column]);
645 for (std::size_t row = column + 1u; row < n; ++row) {
646 const double candidate = std::abs(matrix[row * n + column]);
647 if (candidate > best) {
652 if (!(best > 0.0) || !std::isfinite(best))
654 if (pivot != column) {
655 for (std::size_t k = column; k < n; ++k)
656 std::swap(matrix[pivot * n + k], matrix[column * n + k]);
657 std::swap(rhs[pivot], rhs[column]);
659 const double diagonal = matrix[column * n + column];
660 for (std::size_t row = column + 1u; row < n; ++row) {
661 const double factor = matrix[row * n + column] / diagonal;
662 if (!std::isfinite(factor))
666 for (std::size_t k = column; k < n; ++k)
667 matrix[row * n + k] = std::fma(-factor, matrix[column * n + k], matrix[row * n + k]);
668 rhs[row] = std::fma(-factor, rhs[column], rhs[row]);
673 for (std::size_t k =
reverse + 1u; k < n; ++k)
674 value = std::fma(-matrix[
reverse * n + k], rhs[k], value);
676 if (!std::isfinite(solved))
684 result.coefficients.clear();
685 result.extremal_frequencies.clear();
686 result.band_ripples.clear();
687 result.minimax_error = 0.0;
688 result.measured_weighted_error = 0.0;
735 double previous_upper = -1.0;
736 for (
const auto& band : bands) {
737 if (!std::isfinite(band.lower_omega) || !std::isfinite(band.upper_omega) ||
738 !std::isfinite(band.amplitude) || !std::isfinite(band.weight))
740 if (!(band.weight > 0.0))
742 if (band.lower_omega < 0.0 || band.upper_omega > pi)
744 if (!(band.lower_omega < band.upper_omega))
746 if (band.lower_omega <= previous_upper)
748 previous_upper = band.upper_omega;
751 const std::size_t coefficients = independent_coefficient_count(options.
type, options.
tap_count);
752 if (coefficients == 0
u)
754 const std::size_t unknowns = coefficients + 1u;
758#if defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND)
763 double total_width = 0.0;
764 for (
const auto& band : bands)
765 total_width += band.upper_omega - band.lower_omega;
766 if (!(total_width > 0.0))
769 const std::size_t requested_points = options.
grid_density * unknowns;
774 const auto grid_elements =
static_cast<std::uint64_t
>(requested_points) + bands.size();
775 const auto square =
static_cast<std::uint64_t
>(unknowns) * unknowns;
776 if (!charge.
add<
double>(grid_elements) || !charge.
add<
double>(grid_elements) ||
777 !charge.
add<
double>(grid_elements) || !charge.
add<std::size_t>(grid_elements) ||
778 !charge.
add<
double>(
square) || !charge.
add<
double>(unknowns) ||
779 !charge.
add<
double>(coefficients) || !charge.
add<
double>(grid_elements)) {
784 std::vector<double> grid_omega;
785 std::vector<double> grid_desired;
786 std::vector<double> grid_weight;
787 std::vector<std::size_t> grid_band;
788 grid_omega.reserve(requested_points + bands.size());
789 for (std::size_t b = 0
u; b < bands.size(); ++b) {
790 const auto& band = bands[b];
791 const double width = band.upper_omega - band.lower_omega;
792 std::size_t count =
static_cast<std::size_t
>(
793 std::llround(
static_cast<double>(requested_points) * (width / total_width)));
794 count = std::max<std::size_t>(count, 2u);
795 for (std::size_t
i = 0
u;
i < count; ++
i) {
796 const double t =
static_cast<double>(
i) /
static_cast<double>(count - 1u);
797 const double omega = band.lower_omega + t * width;
801 if (is_forced_zero_endpoint(options.
type, omega))
803 grid_omega.push_back(omega);
804 grid_desired.push_back(band.amplitude);
805 grid_weight.push_back(band.weight);
806 grid_band.push_back(b);
809 const std::size_t grid_size = grid_omega.size();
810 if (grid_size < unknowns)
814 std::vector<std::size_t> extremal(unknowns);
815 for (std::size_t
i = 0
u;
i < unknowns; ++
i)
816 extremal[
i] =
static_cast<std::size_t
>(
817 std::llround(
static_cast<double>(
i) *
static_cast<double>(grid_size - 1u) /
818 static_cast<double>(unknowns - 1u)));
820 std::vector<double> matrix(unknowns * unknowns);
821 std::vector<double> rhs(unknowns);
822 std::vector<double> solution(coefficients);
823 std::vector<double> error(grid_size);
825 bool converged =
false;
826 std::size_t iteration = 0
u;
829 for (std::size_t
i = 0
u;
i < unknowns; ++
i) {
830 const double omega = grid_omega[extremal[
i]];
831 for (std::size_t k = 0
u; k < coefficients; ++k)
832 matrix[
i * unknowns + k] = basis_value(options.
type, k, omega);
833 const double sign = (
i % 2u == 0
u) ? 1.0 : -1.0;
834 matrix[
i * unknowns + coefficients] = -sign / grid_weight[extremal[
i]];
835 rhs[
i] = grid_desired[extremal[
i]];
837 if (!solve_dense_in_place(matrix, rhs, unknowns)) {
839 clear_payload(result);
843 for (std::size_t k = 0
u; k < coefficients; ++k)
844 solution[k] = rhs[k];
845 delta = rhs[coefficients];
846 if (!std::isfinite(delta)) {
848 clear_payload(result);
854 for (std::size_t g = 0
u; g < grid_size; ++g) {
855 double amplitude = 0.0;
856 for (std::size_t k = 0
u; k < coefficients; ++k)
857 amplitude = std::fma(solution[k],
858 basis_value(options.
type, k, grid_omega[g]), amplitude);
859 const double weighted = grid_weight[g] * (amplitude - grid_desired[g]);
860 if (!std::isfinite(weighted)) {
862 clear_payload(result);
866 peak = std::max(
peak, std::abs(weighted));
869 const double reference = std::max(std::abs(delta), 1.0e-300);
878 std::vector<std::size_t> candidates;
879 candidates.reserve(grid_size);
880 for (std::size_t g = 0
u; g < grid_size; ++g) {
888 const bool starts_band = g == 0
u || grid_band[g] != grid_band[g - 1u];
889 const bool ends_band = g + 1u == grid_size || grid_band[g] != grid_band[g + 1u];
890 const bool interior_peak =
891 (g == 0
u || std::abs(error[g]) >= std::abs(error[g - 1u])) &&
892 (g + 1u == grid_size || std::abs(error[g]) >= std::abs(error[g + 1u]));
893 if ((starts_band || ends_band || interior_peak) && std::abs(error[g]) > 0.0)
894 candidates.push_back(g);
897 std::vector<std::size_t> alternating;
898 alternating.reserve(candidates.size());
899 for (std::size_t index : candidates) {
900 if (!alternating.empty()) {
901 const double previous = error[alternating.back()];
902 if ((previous > 0.0) == (error[index] > 0.0)) {
903 if (std::abs(error[index]) > std::abs(previous))
904 alternating.back() = index;
908 alternating.push_back(index);
910 if (alternating.size() < unknowns) {
912 clear_payload(result);
918 while (alternating.size() > unknowns) {
919 if (std::abs(error[alternating.front()]) < std::abs(error[alternating.back()]))
920 alternating.erase(alternating.begin());
922 alternating.pop_back();
924 extremal = alternating;
929 clear_payload(result);
941 double measured_peak = 0.0;
942 for (std::size_t g = 0
u; g < grid_size; ++g) {
943 const double amplitude =
945 if (!std::isfinite(amplitude)) {
947 clear_payload(result);
950 const double deviation = std::abs(amplitude - grid_desired[g]);
953 measured_peak = std::max(measured_peak, grid_weight[g] * deviation);
958 for (std::size_t index : extremal)
966 clear_payload(result);
974#if defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND)
975 }
catch (
const std::bad_alloc&) {
976 clear_payload(result);
979 }
catch (
const std::length_error&) {
980 clear_payload(result);
996inline MinimumPhaseFirResult
999 using namespace fir_design_detail;
1000 MinimumPhaseFirResult result;
1001 if (one_sided_magnitudes.size() < 2u ||
1002 one_sided_magnitudes.size() - 1u > std::numeric_limits<std::size_t>::max() / 2u ||
1003 !(options.log_magnitude_floor > 0.0) || !std::isfinite(options.log_magnitude_floor))
1005 const std::size_t fft_size = 2u * (one_sided_magnitudes.size() - 1u);
1006 const std::size_t coefficient_count =
1007 options.coefficient_count == 0
u ? fft_size : options.coefficient_count;
1009 fft_size >
static_cast<std::size_t
>(std::numeric_limits<int>::max())) {
1013 if (!is_power_of_two(fft_size) || coefficient_count == 0
u || coefficient_count > fft_size)
1015 for (
double magnitude : one_sided_magnitudes) {
1016 if (!(magnitude >= 0.0) || !std::isfinite(magnitude))
1020 options.maximum_workspace_bytes)) {
1025#if defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND)
1028 std::vector<std::complex<double>>
spectrum(fft_size);
1029 for (std::size_t bin = 0
u; bin < one_sided_magnitudes.size(); ++bin) {
1030 const double log_magnitude =
1031 std::log(std::max(one_sided_magnitudes[bin], options.log_magnitude_floor));
1032 if (!std::isfinite(log_magnitude)) {
1037 spectrum[bin] = {log_magnitude, 0.0};
1039 for (std::size_t bin = one_sided_magnitudes.size(); bin < fft_size; ++bin)
1044 for (
const auto value : spectrum) {
1045 if (!std::isfinite(
value.real()) || !std::isfinite(
value.imag())) {
1051 for (std::size_t quefrency = 1u; quefrency < fft_size / 2u; ++quefrency)
1052 spectrum[quefrency] *= 2.0;
1053 for (std::size_t quefrency = fft_size / 2u + 1u; quefrency < fft_size; ++quefrency)
1054 spectrum[quefrency] = {};
1056 for (
auto& value : spectrum) {
1057 value = std::exp(value);
1058 if (!std::isfinite(
value.real()) || !std::isfinite(
value.imag())) {
1066 result.fft_size = fft_size;
1067 result.coefficients.resize(coefficient_count);
1068 for (std::size_t index = 0
u;
index < coefficient_count; ++
index) {
1070 if (!std::isfinite(value)) {
1079 for (std::size_t index = 0
u;
index < coefficient_count; ++
index)
1080 spectrum[index] = {result.coefficients[
index], 0.0};
1082 result.measured_magnitudes.resize(one_sided_magnitudes.size());
1083 result.errors.resize(one_sided_magnitudes.size());
1084 double squared_error = 0.0;
1085 for (std::size_t bin = 0
u; bin < one_sided_magnitudes.size(); ++bin) {
1086 const double measured = std::abs(spectrum[bin]);
1087 const double target = std::max(one_sided_magnitudes[bin], options.log_magnitude_floor);
1088 const double error = measured - target;
1089 if (!std::isfinite(measured) || !std::isfinite(error)) {
1094 result.measured_magnitudes[bin] = measured;
1095 result.errors[bin] =
error;
1096 result.maximum_absolute_error =
1097 std::max(result.maximum_absolute_error, std::abs(error));
1101 std::sqrt(squared_error /
static_cast<double>(one_sided_magnitudes.size()));
1102 if (!std::isfinite(result.rms_error)) {
1109#if defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND)
1110 }
catch (
const std::bad_alloc&) {
1114 }
catch (
const std::length_error&) {
Definition checked_allocation.hpp:57
bool add(std::uint64_t elements) noexcept
Definition checked_allocation.hpp:63
std::uint64_t total() const noexcept
Definition checked_allocation.hpp:83
@ index
Definition gpu_pass.hpp:140
Definition fir_design.hpp:162
constexpr double pi
Definition fir_design.hpp:164
void reconstruct_coefficients(LinearPhaseFirType type, std::span< const double > independent, std::span< double > coefficients) noexcept
Definition fir_design.hpp:297
std::size_t independent_coefficient_count(LinearPhaseFirType type, std::size_t count) noexcept
Definition fir_design.hpp:223
bool valid_type_length(LinearPhaseFirType type, std::size_t count) noexcept
Definition fir_design.hpp:207
double basis_value(LinearPhaseFirType type, std::size_t column, double omega) noexcept
Definition fir_design.hpp:228
void clear_payload(FirLeastSquaresResult &result) noexcept
Definition fir_design.hpp:244
bool is_forced_zero_endpoint(LinearPhaseFirType type, double omega) noexcept
Definition fir_design.hpp:166
bool is_power_of_two(std::size_t value) noexcept
Definition fir_design.hpp:261
bool admit_minimum_phase_workspace(std::size_t fft_size, std::size_t bins, std::size_t coefficients, std::uint64_t limit) noexcept
Definition fir_design.hpp:265
bool admit_least_squares_workspace(std::size_t rows, std::size_t columns, std::size_t taps, std::uint64_t limit) noexcept
Definition fir_design.hpp:279
bool solve_dense_in_place(std::vector< double > &matrix, std::vector< double > &rhs, std::size_t n) noexcept
Solve a small dense square system in place by Gaussian elimination with partial pivoting.
Definition fir_design.hpp:640
Definition additive_bank.hpp:218
constexpr std::uint64_t kDefaultFirDesignWorkspaceBytes
Definition fir_design.hpp:23
constexpr std::size_t kMaximumFirDesignTapCount
Definition fir_design.hpp:24
@ right
Definition multi_channel_meter.hpp:67
@ left
Definition multi_channel_meter.hpp:66
@ peak
Sample peak. Literal, fastest-responding.
Definition feedforward_compressor.hpp:119
FirLeastSquaresResult design_fir_least_squares(std::span< const FirDesignPoint > points, const FirLeastSquaresOptions &options)
Weighted least-squares design of a real Type I, II, III, or IV linear-phase FIR.
Definition fir_design.hpp:332
FirEquirippleResult design_fir_equiripple(std::span< const FirEquirippleBand > bands, const FirEquirippleOptions &options)
Equiripple (weighted minimax) design of a real Type I-IV linear-phase FIR by the Remez exchange,...
Definition fir_design.hpp:714
LinearPhaseFirType
Definition fir_design.hpp:44
@ type_iv_antisymmetric_even
Definition fir_design.hpp:48
@ type_i_symmetric_odd
Definition fir_design.hpp:45
@ type_ii_symmetric_even
Definition fir_design.hpp:46
@ type_iii_antisymmetric_odd
Definition fir_design.hpp:47
constexpr std::size_t kMaximumFirDesignPointCount
Definition fir_design.hpp:25
@ delay
Definition envelope.hpp:57
@ independent
X and Y advance only on their own clocks and never on each other's.
Definition cartesian_walk.hpp:20
@ invalid_argument
Definition comb_filter.hpp:35
std::complex< double > fir_response(std::span< const double > coefficients, double omega) noexcept
Definition fir_design.hpp:177
bool checked_capacity_product(std::uint64_t lhs, std::uint64_t rhs, std::uint64_t maximum, std::uint64_t &product) noexcept
Definition checked_allocation.hpp:12
@ reference
Platform sine; the compatibility default.
Definition fast_math.hpp:40
double linear_phase_fir_amplitude(std::span< const double > coefficients, LinearPhaseFirType type, double omega) noexcept
Signed amplitude after removing the exact linear delay of a Type I-IV FIR.
Definition fir_design.hpp:192
FirDesignStatus
Definition fir_design.hpp:30
@ not_converged
The exchange hit its iteration cap without meeting the convergence tolerance, or the achieved minimax...
Definition fir_design.hpp:41
@ success
Definition fir_design.hpp:31
@ unsupported_size
Definition fir_design.hpp:33
@ ill_conditioned
Definition fir_design.hpp:37
@ numerical_failure
Definition fir_design.hpp:38
@ workspace_limit_exceeded
Definition fir_design.hpp:34
@ rank_deficient
Definition fir_design.hpp:36
@ allocation_failure
Definition fir_design.hpp:35
@ invalid_argument
Definition fir_design.hpp:32
@ u
Definition formant_filter_bank.hpp:20
@ i
Definition formant_filter_bank.hpp:20
MinimumPhaseFirResult reconstruct_minimum_phase_fir(std::span< const double > one_sided_magnitudes, const MinimumPhaseFirOptions &options={})
Reconstruct a causal minimum-phase FIR from N/2+1 nonnegative magnitude bins.
Definition fir_design.hpp:997
@ square
Definition lfo_sampling.hpp:58
@ reverse
Rise to a peak, then cut.
Definition nonlin_ambience_design.hpp:246
constexpr std::size_t kMaximumMinimumPhaseFirSize
Largest admitted radix-2 FFT size for minimum-phase reconstruction.
Definition fir_design.hpp:28
@ spectrum
Definition design_ir.hpp:265
@ value
the widget's primary value (Knob, Fader, RangeSlider, Toggle, ProgressBar)
Definition binding_diagnostics.hpp:19
Definition fir_design.hpp:51
double amplitude
Signed zero-phase amplitude.
Definition fir_design.hpp:56
double omega
Angular frequency in radians/sample, in the closed interval [0, pi].
Definition fir_design.hpp:53
double weight
Positive least-squares weight. The objective is sum(weight * error^2).
Definition fir_design.hpp:58
One contiguous approximation band for an equiripple design.
Definition fir_design.hpp:91
double amplitude
Desired signed zero-phase amplitude across the band.
Definition fir_design.hpp:95
double weight
Positive weight.
Definition fir_design.hpp:98
double lower_omega
Definition fir_design.hpp:92
double upper_omega
Definition fir_design.hpp:93
Definition fir_design.hpp:101
LinearPhaseFirType type
Definition fir_design.hpp:103
std::size_t grid_density
Dense-grid points per independent coefficient.
Definition fir_design.hpp:106
std::uint64_t maximum_workspace_bytes
Definition fir_design.hpp:116
std::size_t tap_count
Definition fir_design.hpp:102
double convergence_tolerance
Relative gap between the grid's peak error and the interpolated ripple below which the exchange is co...
Definition fir_design.hpp:111
std::size_t maximum_iterations
Bounded exchange budget. Reaching it is reported, never ignored.
Definition fir_design.hpp:108
double maximum_minimax_error
Optional requirement.
Definition fir_design.hpp:115
Definition fir_design.hpp:119
FirDesignStatus status
Definition fir_design.hpp:120
std::size_t iterations
Definition fir_design.hpp:132
std::vector< double > extremal_frequencies
The final alternation set, ascending.
Definition fir_design.hpp:124
std::vector< double > coefficients
Definition fir_design.hpp:121
std::vector< double > band_ripples
Achieved max |A(w) - amplitude| per input band, unweighted.
Definition fir_design.hpp:126
double minimax_error
The equalized weighted ripple, |delta|.
Definition fir_design.hpp:128
double measured_weighted_error
Largest weighted error measured on the dense grid at the returned design.
Definition fir_design.hpp:131
Definition fir_design.hpp:61
LinearPhaseFirType type
Definition fir_design.hpp:63
double maximum_diagonal_condition_estimate
Definition fir_design.hpp:65
std::uint64_t maximum_workspace_bytes
Definition fir_design.hpp:66
std::size_t tap_count
Definition fir_design.hpp:62
double rank_tolerance
Definition fir_design.hpp:64
Definition fir_design.hpp:69
double qr_diagonal_condition_estimate
Ratio of largest to smallest accepted diagonal of pivoted R.
Definition fir_design.hpp:79
double maximum_absolute_error
Definition fir_design.hpp:75
std::vector< double > coefficients
Definition fir_design.hpp:71
double weighted_rms_error
Definition fir_design.hpp:74
std::vector< double > measured_amplitudes
Definition fir_design.hpp:72
std::vector< double > errors
Definition fir_design.hpp:73
FirDesignStatus status
Definition fir_design.hpp:70
std::size_t numerical_rank
Definition fir_design.hpp:76
Definition fir_design.hpp:139
double log_magnitude_floor
Every magnitude below this positive floor, including zero, is replaced before log().
Definition fir_design.hpp:144
std::uint64_t maximum_workspace_bytes
Definition fir_design.hpp:145
std::size_t coefficient_count
Zero means retain the complete circular impulse of fft_size samples.
Definition fir_design.hpp:141
Definition fir_design.hpp:148
std::size_t fft_size
Definition fir_design.hpp:150
double maximum_absolute_error
Definition fir_design.hpp:155
std::vector< double > coefficients
Definition fir_design.hpp:151
FirDesignStatus status
Definition fir_design.hpp:149
std::vector< double > errors
Definition fir_design.hpp:153
std::vector< double > measured_magnitudes
Definition fir_design.hpp:152
double rms_error
Definition fir_design.hpp:154