RLPF vs BLowPass: BLowPass seems better (?!)

As long as I’ve been doing this, there are still things I don’t get about filters…

I had thought that a resonant filter with a relatively low Q would have a frequency response more or less similar to LPF.

Not so (with RLPF anyway).

s.boot;
s.freqscope;

(
a = {
	var src = PinkNoise.ar(0.1);
	var sigs = [src, RLPF.ar(src, 18000, 1), RLPF.ar(src, 18000, 0.5), LPF.ar(src, 18000)];
	var x = MouseX.kr(0, sigs.size - 0.01);
	// amusing slanted-stairstep interpolation function here
	var xFrac = x.frac;
	xFrac = clip(wrap(xFrac, -0.5, 0.5) * 10, -0.5, 0.5);
	SelectX.ar(
		clip(xFrac + (x + 0.5).trunc - 0.5, 0, sigs.size - 0.01),
		sigs
	).dup
}.play;
)

a.release;
  • MouseX band 1 = source (pink noise)
  • Band 2 = RLPF at 18000 Hz, Q = 1 (rq = 1): Attenuates quite heavily above 5000 Hz
  • Band 3 = RLPF at 18000 Hz, Q = 2 (rq = 0.5): Almost flat response up to 10 kHz
  • Band 4 = LPF at 18000 Hz: Similar to 3, but a little less attenuation below 10 kHz

That led me to compare the frequency responses of RLPF and BLowPass.

b = Buffer.alloc(s, 2048, 2);

// record filters' impulse responses
(
a = {
	var sig = Impulse.ar(0);
	RecordBuf.ar([RLPF.ar(sig, 18000, 1), BLowPass.ar(sig, 18000, 1)],
		bufnum: b, loop: 0, doneAction: 2);
	Silent.ar(1)
}.play;
)

// get time-domain IRs
b.getToFloatArray(wait: -1, timeout: 5, action: { |data| d = data });

// rejigger into 2 signals
d = d.as(Array).clump(2).flop.collectAs(_.as(Signal), Array);

// get frequency responses
f = d.collect { |ir|
	var fft = ir.fft(Signal.newClear(ir.size), Signal.fftCosTable(ir.size)).asPolar;
	fft.rho[0 .. ir.size div: 2]
};

// plot FRs
f.lace(f[0].size * 2).plot(numChannels: 2)

rlpf-vs-blowpass

The RLPF frequency response (at the top) is… well… shocking to me. BLowPass is what I would expect for a resonant filter with a high cutoff and low resonance. RLPF… I don’t even know what the [bleep] that is but it was wiping out my drums.

TL;DR is… RLPF might not be doing what you think, while the B*** filters probably are.

hjh

Checking the source it looks to me like RLPF and BLowPass are both discretized versions of the standard two-pole analog lowpass filter, but the key difference is that RLPF uses a warped bilinear transform while BLowPass uses the standard bilinear transform. That’s the root cause of any differences observed between them. Consequences of this:

  • RLPF’s cutoff argument really is the exact -3 dB cutoff of the digital filter.
  • BLowPass’s cutoff argument is the -3 dB cutoff of the original analog filter prior to BLT discretization. BLT maps the analog frequencies [0, infinity) to digital frequencies [0, Nyquist), so the cutoff argument becomes gradually more inaccurate as it increases.
  • It’s possible to set BLowPass’s cutoff higher than Nyquist, but the actual cutoff of the digital filter will be warped so it asymptotically approaches Nyquist. There may be floating point issues if you set it too high though.
  • It’s not possible to set RLPF’s cutoff to Nyquist or higher. It may run into issues below Nyquist because of floating-point precision.
  • Due to the close relationship between warped and unwarped BLT, hypothetically there is a 1:1 mapping from settings of RLPF and BLowPass that will yield identical results. Too lazy to derive what it is right now, you may be able to figure it out from the source code.

I haven’t tested all of these so take them w a grain of salt.

I don’t have a full explanation for your results right now but here’s my guess: RLPF is telling you that cutoff = 18 kHz and Q = 1 are problematic settings. BLowPass gets around it because it naturally lowers the cutoff as a consequence of BLT warping.

Also LPF is just RLPF with Q = 1/sqrt(2). RLPF is a general two-pole analog lowpass, while LPF is a specific setting of RLPF that satisfies the Butterworth criteria. Both use the same discretization method I believe.

2 Likes

Sure, and I’ve seen that RLPF is sensitive to high cutoffs with Q < 1 (rq > 1), and I have some intuitive understanding why that would be.

From the musician’s perspective, there’s a concrete need to be able to slide smoothly between a nearly transparent filter and strong resonant coloration. It’s worth it for SC users to be aware that RLPF may make this harder than you’d think (though the answer might be as simple as limiting the cutoff frequency a bit lower than I did, or using a higher sampling rate) – in that my attempt to make RLPF transparent ended up wiping out the entire upper midrange.

hjh