IIR filter coefficients for LUFS calculation

Hi, I am trying to implement LUFS meter and I am around 3 LUFS off from correct value (on both, momentary and integrated LUFS).

My primary suspects are filters, given that coefficients from ITU-R BS.1770-5 go as follows:


But IIRCoefficients class and IIRFilter base take coefficients from c1 to c6. I couldn’t find any documentation on what’s the relation of 5 ‘a’ and ‘b’ coefficients to 6 ‘c’ coefficients. For now I assumed:

c1 = b0
c2 = b1
c3 = b2
c4 = 0 or 1 (both versions doesn't work)
c5 = a1
c6 = a2

But it doesn’t work - something is being calculated and is in proper range, but the values are just a bit (~3 LUFS) off.

If you could help me implement this k-weighting curve filtering using juce IIRFilter, I’d greatly appreciate it.

Project GitHub page - project goal is to do something similar to Youlean Loudness Meter and learn both juce and some DSP

c4 should be 1.0. The relationship between 5 coefficients and 6 is that b0-b2 and a1-a2 are divided by a0 (which here corresponds to c4).

Since you say that doesn’t work, try c5 = -a1 and c6 = -a2. It depends on how the filter is implemented whether these should be added or subtracted.

1 Like

For context, my sense of what happened here is that the standards authors sent an obscene gesture to the developer community by specifying the LUFS K-weighting filters only in terms of coefficients for a 48kHz implementation, to the exclusion of traditionally helpful metrics such as -3dB or -6dB cutoff frequencies, Q-factors or dB/octave filter slopes. The developer community then returned this gesture by implementing every new LUFS meter with a unique K-filter design. If you haven’t already, open up your favorite LUFS plugins at the same time and see how much diversity of measurement they all report from the same source material.

This presents us with a philosophical question as to whether it is actually important to match the official standard for calculating LUFS; or whether is it indeed more practical merely to agree with whatever other flawed LUFS meter that your user has open alongside yours.

As you struggle through this, here are a couple of resources you may find helpful:

I have heard of people converting everything to 48kHz just to make the K-math easier. Please don’t do this.

Personally, I use K-weighting filters of type

dsp::ProcessorDuplicator<dsp::IIR::Filter, dsp::IIR::Coefficients>

and configure them with

*Klowcut .state = dsp::IIR::ArrayCoefficients::makeFirstOrderHighPass(SampleRate, 60.0f);
*Khighshelf.state = dsp::IIR::ArrayCoefficients::makeHighShelf(SampleRate, 1500.0f, 0.707f, 1.585f); // 1.585 = +4dB

This doesn’t quite match the frequency response of Klangfreund’s K-weighting, but it’s close enough for government work, especially if you add 0.07dB to your final result.

I will leave a couple of questions that presently weigh on my mind:

  1. Does anybody have insight they can share into how the major streaming services calculate LUFS, specifically the K-weighting filters?
  2. Would it make sense for JUCE to include a module for LUFS, so that every new learner doesn’t have to wrestle in futility with ITU-R BS.1770?

The broadcasters’ QC departments must use some sort of loudness meter like the rest of us (varying across broadcasters) but the spec always has a few dB wiggle room and I don’t hear about QC fails due to inconsistencies in measurements.

I don’t think they let the QC people meet the audio post people so I don’t think I’ll get a better answer than that for you…

this might help. ITU-R BS.1770 Loudness Measurement IIR filter coefficients