Skip to content

LadderFilter: bound the tail below Resonance 4 - #234

Merged
bdbarnett merged 2 commits into
mainfrom
fix/ladder-tail
Oct 28, 2026
Merged

bdbarnett merged 2 commits into
mainfrom
fix/ladder-tail

Conversation

@bdbarnett

@bdbarnett bdbarnett commented Oct 28, 2026 •

Copy link
Copy Markdown
Contributor

LadderFilter.tail_samples was None at every setting, so a host could not tell when a ringing filter falls silent. Below Resonance 4 it is now an upper bound on the frames to exact zero after your input stops, for the settings as they stand. From 4 up the filter sustains and the bound stays None. It is also None in a narrow band just below 4 where single precision cannot show the decay: from Resonance 3.988 at a 20 Hz cutoff, 48 kHz, Oversample on, and nearer 4 at higher cutoffs. At Mix 0 the output is the input, so the tail is 0 at any Resonance.

How the bound is reached (ring_frames). Each stage is a bilinear one-pole, so the loop's poles are the analog ladder's mapped through the prewarped bilinear transform. Half of 1 - |z|^2 gives a per-step decay no faster than the slowest pole's. The bound sizes the largest state the integrators can hold from the drive and the saturator's ceiling, then counts the frames for it to fall under half an output LSB. The free response is enveloped by a transient constant, 256, worked out over every cutoff, rate, tap and Oversample setting; the largest needed was 131. The saturator only lowers the loop gain. That it does not slow the ring is measured, not derived.

What the tests render. The slowest corners: a 20 Hz cutoff at the highest Resonance the bound covers, 48 and 22.05 kHz, Oversample on and off, one pole and four, full Drive and Passband Comp, full-scale DC and a square. They also render Resonance 0, where four coincident poles bring the ring to 0.96 of the bound, and every patch below 4. Near 4 the ring comes to about half the bound. Two faults go red: half the bound, and a bound that ignores Resonance. A sweep of 1,920 further cells (Resonance 0 to 1.5, Drive 0 to 24 dB, cutoffs 20 to 100 Hz, three rates) found none past the bound.

The lifecycle matrix now judges moved-and-back cells it skipped while the tail was None. In six of them, at patches 1 and 4, the filter's residue under material outlasts the bound by up to 13%. They join the known rows for #155 beside the other filters' rows. The rack's check that one pedal's None makes the rack's tail None now uses a self-oscillating ladder.

Plants. Three faults a real bug could make, each shown red by the test of the claim it breaks: the cutoff passed past half the sample rate unclamped, Resonance sent as a 0..1 knob rather than k, and Drive at half its decibels. They are declared as KIT_PLANTS, and the plant check finds none of them reproduced by a knob or a patch. The two tail plants change only the reported tail, so they stay out.

Fixes #146
Fixes #151

tail_samples was None at every setting. Below Resonance 4 it is now an
upper bound for the settings as they stand (ring_frames): the linear
ladder's slowest pole, mapped through the bilinear stages, decays the
largest state the integrators can hold to under half an output LSB, with a
transient constant worked out over every cutoff, rate, tap and Oversample
setting. From 4 up, and in the narrow band just below it where the decay
per step is under 2^-20 and single precision cannot show it, the bound
stays None. At Mix 0 the tail is 0 at any Resonance.

The tests render the slowest corners (20 Hz at the highest Resonance the
bound covers, 48 and 22.05 kHz, Oversample on and off, one pole and four,
full Drive and Passband Comp) and Resonance 0, where the ring comes to 0.96
of the bound; half the bound, and a bound blind to Resonance, are
outlived. The lifecycle matrix now judges the moved-and-back cells it
skipped while the tail was None; six of them carry a filter residue past
the bound under material and join the known rows for #155. The rack's
None-propagation check moves to a self-oscillating ladder.

Fixes #146
@bdbarnett
bdbarnett merged commit 824c853 into main Oct 28, 2026
7 checks passed
@bdbarnett
bdbarnett deleted the fix/ladder-tail branch October 28, 2026 02:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

1 participant