I have been building an adaptive noise-cancellation toolkit in Julia and wanted to share it + get eyes on a couple of numerics questions.
What it is: five adaptive-filter families (NLMS, Leaky NLMS, VSS-NLMS, VSS Leaky NLMS, scalar RLS) plus a block-RLS contender with adaptive forgetting and Cholesky-based covariance updates.
The part I’m actually proud of: the NLMS-class inner loop is zero-allocation and SIMD-friendly. Preallocated process_audio! runs with no allocations in the hot path:
I had benchmarked against synthetic audio scenarios (generated in Python and will prolly shift the generation to julia also pardon me for that, filtered in Julia). Full results, mathematical derivations, and API reference are in the docs:
Feedback especially welcome on the RLS conditioning question above, and on the NLMS-vs-RLS tradeoff on continuous path drift (the one scenario where leaky NLMS beats Block RLS). And if y’all liked it do drop a follow, Highly Appreciated!!
Have a Great Day
-JB
i am not a big expert when it comes to sound processing, but if i understood it correctly, would it be possible to integrate it into game engines or other sound processing pipelines?
In principle, yes, particularly for the NLMS-family filters, but the repository is not currently a drop-in game-engine plugin.
The filter state is persistent and the preallocated processing path performs no allocations after warm-up, which are useful properties for an audio callback. An integration would still need engine-specific callback glue, channel and sample-format conversion, stable buffer sizing, thread-safety review, and deadline testing.
I would treat Block RLS more cautiously for real-time use. It has approximately O(L²) per-sample complexity and performs batched BLAS/LAPACK work, so update-time spikes need to be measured against the engine’s callback deadline. NLMS or VSS-NLMS would be the more conservative starting point.
Update: I completed a causal benchmark and numerical-diagnostics audit.
The old workflow reused too much state across passes and treated zero skipped Cholesky updates as sufficient evidence of stability. Correcting that methodology exposed a real Block RLS failure on reference dropouts, where the causal result fell to approximately -25 dB.
The underlying problem was variable-forgetting detector saturation during frozen low-excitation blocks. I have now fixed that behavior, added a regression test, regenerated all nine scenarios, and added covariance-health gates to the analyzer.
The corrected Block RLS result on ref_silence is +5.07 dB. All 186 tests and all nine scenario gates now pass.
The updated methodology and results are available in docs/BENCHMARKS.md and docs/RESULTS.md.
And thanks to a lot of users who had recommended me to use Workspaces you are a saviour for sure. I understood the topic and it helped me understand it properly