Pulp 1.88.0
Cross-platform audio plugin framework
Loading...
Searching...
No Matches
pulp::signal::detail::SaturatorShapeMath Struct Reference

The waveshaper family's three closed forms per member: the curve f, its derivative f' (needed for the bias normaliser), and its antiderivative F1 (needed for ADAA). More...

#include <saturator.hpp>

Static Public Member Functions

static double f (SaturatorShape shape, double u)
 f(u).
static double df (SaturatorShape shape, double u)
 f'(u).
static double antiderivative (SaturatorShape shape, double u)
 F1(u) = ∫f(u)du, with an arbitrary constant — ADAA only ever takes differences of it, so the constant cancels.
static double second_antiderivative (SaturatorShape shape, double u)
 F2(u) = ∫F1(u)du, the second antiderivative second-order ADAA takes divided differences of.
static double tanh_second_antiderivative (double u)
 ∫₀ᵘ ln cosh v dv.

Detailed Description

The waveshaper family's three closed forms per member: the curve f, its derivative f' (needed for the bias normaliser), and its antiderivative F1 (needed for ADAA).

F1 is EVEN for every member, because the antiderivative of an odd function is even. That is worth stating because it is easy to get wrong: writing the cubic's clipped branch as sign(u)·[(2/3)(|u|−1) + 5/12] makes it odd, and an odd F1 feeds ADAA a sign-flipped difference on every negative excursion — which does not look like a crash, it looks like distortion, and would be mistaken for the effect working.

Member Function Documentation

◆ antiderivative()

double pulp::signal::detail::SaturatorShapeMath::antiderivative ( SaturatorShape shape,
double u )
inlinestatic

F1(u) = ∫f(u)du, with an arbitrary constant — ADAA only ever takes differences of it, so the constant cancels.

◆ df()

double pulp::signal::detail::SaturatorShapeMath::df ( SaturatorShape shape,
double u )
inlinestatic

f'(u).

Unity at the origin for all four members, by construction — that identity is what makes one drive law work across the family.

◆ f()

double pulp::signal::detail::SaturatorShapeMath::f ( SaturatorShape shape,
double u )
inlinestatic

f(u).

◆ second_antiderivative()

double pulp::signal::detail::SaturatorShapeMath::second_antiderivative ( SaturatorShape shape,
double u )
inlinestatic

F2(u) = ∫F1(u)du, the second antiderivative second-order ADAA takes divided differences of.

Linear terms are arbitrary for the same reason F1's constant is, but every branch here is ODD (the integral of an even F1 from 0), so the asymptotic quadratic terms carry the right sign on both sides of the origin.

Second-order ADAA divides rounding error in F2 by the square of the sample spacing, so absolute accuracy near the origin matters as much as relative accuracy far from it: each branch is arranged to avoid subtracting two large terms when the result is small.

◆ tanh_second_antiderivative()

double pulp::signal::detail::SaturatorShapeMath::tanh_second_antiderivative ( double u)
inlinestatic

∫₀ᵘ ln cosh v dv.

With a = |u|, ln cosh v = v − ln 2 + ln(1 + e^(−2v)) integrates to

a²/2 − a·ln 2 + ½·Li₂(−e^(−2a)) + π²/24

and the dilogarithm on [−1, 0) maps through Landen's identity Li₂(z) = −Li₂(z/(z−1)) − ½ln²(1−z) onto Li₂(w) with w = 1/(1+e^(2a)) ∈ (0, ½]. For that argument −ln(1−w) is exactly s = ln(1 + e^(−2a)) ∈ (0, ln 2] — the same term F1 already needs — and Li₂(w) = Σ Bₙ sⁿ⁺¹/(n+1)! converges to double precision within ten Bernoulli terms there (Abramowitz & Stegun 27.7; Maximon, Proc. R. Soc. A 459, 2003). One exp, one log1p, one short odd polynomial.


The documentation for this struct was generated from the following file:
  • /home/runner/work/pulp/pulp/core/signal/include/pulp/signal/saturator.hpp