TB-303: numerical accuracy, convergence and realtime cost
Why solving the discrete circuit equations is only one gate, and what the retained integration experiments actually show.
Technical research · edition 2 · reviewed 2026-10-24

Roland TB-303 service notes: oscillator detail inspected during the circuit investigation. Image source. View full-size image
What we found
A circuit solver can satisfy Kirchhoff's laws at every accepted step and still produce the wrong timing. Our complete-voice experiments exposed that problem around oscillator resets and gate edges. A tiny residual verifies the discrete equations that were solved; it does not show that the timestep was small enough or that two rates converge to the same sound.
We compared trajectories from a shared physical state, investigated step doubling and charge-domain SDIRK integration, and measured optimizations against both electrical references and processing deadlines. These are numerical experiments, not new hardware measurements. The failed candidates are useful results: smaller matrices, higher order and reused Jacobians did not automatically produce a realtime engine.
Make the comparison physically meaningful
complete_voice_rate_probe.cpp renders 240 ms at 48, 96, 192, 384, 768 and
1,536 kHz. Every run uses the same powered-on initial state, fixed original
controls, saw waveform, electrical volume fraction 0.7, gate on at 10 ms and
gate off at 210 ms. Gate timing uses integer sample boundaries common to all
rates. The oscillator is not reset by the gate.
The probe records time-zero state and each interval endpoint. An internal-step observer locates each rising 8-V saw crossing, with linear interpolation within an accepted interval. Frequency uses those crossings between 80 and 200 ms; it is not estimated from coarse audio-rate crossings or fitted waveform phase.
compare_complete_voice_rates.py checks finite data, source times and equal
reset counts. Each line output is decimated to a common 48-kHz grid with a
Kaiser polyphase filter, then passed through the same 513-tap, 20-kHz FIR.
Adjacent rates are compared over 80–200 ms and 5–235 ms. No fitted gain,
pitch, phase or delay removes differences. The common zero-phase filtering is
an offline analysis operation, not a proposed causal plugin reconstruction.
No production rate is approved by this exploratory report.
The line-output comparison includes each rate's endpoint-sampling and reconstruction error. Ultrasonic content already aliased by a coarse endpoint grid cannot be removed by its subsequent FIR, even with perfect internal integration. Thus a line-error floor alone cannot identify integration error. The separately reported internally observed reset timings avoid this particular ambiguity when investigating oscillator cycle timing.
The report contains executable, probe and circuit-source hashes and NumPy/SciPy
versions. Isolated experiments must pass --circuit-header and, if changed,
--probe-source so the report hashes the actual compiled sources rather than
mislabeling the canonical header. These options label an experiment; they do
not validate the executable's build provenance by themselves.
Evidence: research/tb303/VOICE-RATE-CONVERGENCE.md.
Integrate charge rather than an unrelated envelope approximation
The two-stage, second-order L-stable scheme is documented by
INL's MOOSE project,
which cites R. Alexander, SIAM Journal on Numerical Analysis 14(6), 1006–1021
(1977). Its coefficient is gamma = 1 - 1/sqrt(2). The circuit implementation
below is independently derived in charge variables; no MOOSE implementation
code is incorporated.
For physical nodal charge q(v), static outward current F(v) and held sources,
the two stage equations over a requested interval h are:
Stage times are t + gamma*h and t + h. Both equations retain the full
physical Kirchhoff solve, including all 36 passive capacitors and nonlinear
oscillator junction charges. Stage two stores a constant charge bias from
stage one; it is independent of the stage-two Newton iterate. Each diagonal
Jacobian is therefore G + C/(gamma*h) with the actual nonlinear differential
capacitance. Charge increments use the stable branchwise laws rather than
subtracting nearly equal absolute charges.
Passive capacitor endpoint currents remain available for electrical diagnostics and error estimation. They are no longer inter-step derivative memory. Source changes consequently do not average a previous gate's derivative into the next interval, and no special BE gate restart is used. Each stage retains the existing 2-pA KCL, 20-nV correction and voltage-increment limits.
The outer controller compares one complete SDIRK step with two half-steps and
keeps the fine path only. It checks all 118 voltages and the passive endpoint
current discrepancy expressed in volts as h*abs(deltaCurrent)/C. The scale is
atol + rtol*max(abs(coarse),abs(fine)). It uses the unscaled full/fine
discrepancy, with no Richardson state extrapolation. The next interval hint is
h*clamp(0.8/cbrt(error), 0.5, 2). Physical state, compensation, currents, gate
history and the scheduling hint roll back on a rejected trial. Stage biases
and observer metadata clear on every exit.
Accepted fine paths produce four observer records, with stages 1,2,1,2.
Each record includes its actual elapsed time and implicit equation interval.
Discarded trial states never reach the caller's observer. During replay,
observers must use the supplied state instead of querying the circuit's current
endpoint. Intermediate SDIRK stages are not second-order dense output; reset
crossings interpolated from them remain a convergence diagnostic.
Evidence: research/tb303/SDIRK.md.
Why stage order matters
The abscissas are 1/4, 3/4, 11/20, 1/2, 1. They are not chronological.
Intermediate algebraic stage states therefore cannot be sent unchanged through
the existing chronological reset-crossing observer or used as dense output.
Keep chronological accepted method endpoints separate from diagnostic stage records. The latter need the method origin, full interval, stage index and abscissa, implicit interval, source values and reconstructible charge history. Discarded trials must not publish either endpoint or stage records. The rate fixture should use accepted chronological endpoints for reset timing. Its timestamp and crossing checks must verify that contract explicitly.
The independent electrical auditor must reconstruct this tableau's charge
biases, not apply --integration sdirk2 to five-stage data. Validate startup,
immediate MIDI/legato, source/control jumps, all internal current/charge balances,
selected independent roots, tolerance comparisons and complete processing cost.
Account for fixed scratch storage and stack depth when retaining more stage
records. Coefficient checks alone do not complete the circuit gates below.
Evidence: research/tb303/SDIRK4-DESIGN.md.
Measured optimization results
| Experiment | Retained result | Interpretation |
|---|---|---|
| Packed full-voice storage | Median 9.32393 → 8.87911 s; 4.77% less processing | Still 104.05 times audio duration in that fixture |
| Wider SDIRK4 stage guards | Median 3.56874 → 3.09443 s; 13.29% less processing | Still 36.26 times audio duration; one short convergence comparison, separate electrical audit open |
| Modified Newton factor reuse | Baseline 3.07002/3.07658/3.16094 s; candidate 3.56346/3.59714/3.61772 s | The attempted optimization was slower |
| Accepted residual reuse | One observation: 2.94199 s for 85.333 ms audio | 34.48 times realtime; no stable paired speedup claim |
These rows concern different isolated candidates and cannot be treated as one cumulative speedup. The packed experiment retained the compared trace; modified Newton had sample-state and comparison evidence, with its own full electrical audit still open. AB/BA/AB measurements with competing research workers stopped made ordering and workload explicit.
Applying the findings
For a nonlinear DSP engine, keep four independent gates: physical residuals, timestep convergence, reconstructed audio error, and callback cost. Start convergence runs from the same complete snapshot, apply control events at the same physical time, and avoid arbitrary gain or phase alignment that could conceal an error. Record event-time error alongside waveform error.
Benchmark the actual processing schedule, including automation and difficult retriggers. Compare the slowest block with its deadline: 64 frames at 48 kHz allow only 1.333 ms. Fixed iteration limits and zero allocations are necessary contracts, but a bounded algorithm can still be far too slow. Accept a speedup only with matched evidence that it preserved the intended trajectory.
Limits and open questions
The numerical tolerances are properties of declared fixtures, not universal audible thresholds. Intermediate SDIRK states are not automatically accurate dense output. Reusing a factorization needs invalidation and convergence checks against the current equations. No candidate in the table is approved merely because its average timing improved.
Research illustrations

Prismal Labs native editor capture, illustrating the corresponding software project. View full-size image
Primary references
Research provenance
The methods and results above are drawn from these retained research records. Dates and product versions inside the article identify the scope of each experiment; publication review does not mean the hardware or numerical tests were rerun.
research/tb303/VOICE-RATE-CONVERGENCE.md— SHA-25688e9c8a485724add158a2faf92f0b7d207752e718edf2066e2bbbebead6b5dddresearch/tb303/SDIRK.md— SHA-2561b33a1e71949c114ea4b0393d4d16a8824b1baf883bb36b331886d39e061facdresearch/tb303/SDIRK4-DESIGN.md— SHA-256e41c7a95cdbb31846dda63c62bd6610fc6c64fd17f69fb38a2790dabcb30c4f8research/tb303/PACKED-SOLVE.md— SHA-256cd8321e72273062b3dd263d41073085c066d2177c1c9c812e74d7020ada0dd3cresearch/tb303/FACTOR-REUSE.md— SHA-256e8444040d4ed70cfe79da8b247c5419ecadb0a49c44ff904bc496c3f4736157a
