[opus] Coarse energy predictor confusion

Jake Taylor yupferris at gmail.com
Sat Jul 3 11:51:57 UTC 2021

Hi again all,

I've solved it (in fact the clues showed up in earlier notes, but I didn't
put it together entirely until now)! I was making a crucial conceptual
mistake. I assumed the output of the predictor was the *prediction*,
however, this is incorrect - instead it outputs the *residual* directly.
Under that interpretation, everything falls into place. So I no longer need
help with this, and sorry for the noise while I figured it out!

For the curious, once again, notes in pdf/lyx format are attached, as well
as on my dropbox:
and plaintext below.

Thanks again,


Opus Coarse Energy Predictor Notes (Round 5)

Jake Taylor (yupferris at gmail.com), 3 July 2021

I've solved it - I was simply mistaken about what the output of
the filters should be. Instead of the filters outputting the
prediction, they output the residual directly. Under this
interpretation, everything falls into place.

According to the paper[0]/RFC[1], the 2D z-transform should be:

A(z_{\ell},z_{b})=(1-\alpha z_{\ell}^{-1})\cdot\frac{1-z_{b}^{-1}}{1-\beta

I've simplified the source code (in unquant_coarse_energy in
quant_bands.c in libopus 1.3.1[2]) to the following C (pseudo)code:

void unquant_coarse_energy(float *e, int bands) {
  float alpha = /* ... */;
  float beta = /* ... */;
  float prev = 0.0f;
  for (int b = 0; b < bands; b++) {
    float r = /* read from bitstream */;
    e[i] = alpha * e[i] + prev + r;
    prev = prev + (1 - beta) * r;

The goal is simple: extract difference equations from the code,
derive the corresponding z-transforms, and then solve the final z
-transform which should hopefully match what the paper/RFC list.

The code is governed by the following difference equations:

e[\ell,b]=\alpha e[\ell-1,b]+prev[\ell,b-1]+r[\ell,b]


The corresponding z-transforms are:



We expect the domain of the predictor to be e (the 2D “energy
plane”) and the range of the predictor to be r (the final coded
residual). So, these two z-transforms should be all we need to
reach the z-transform from the paper/RFC.

First, let's simplify the latter equation by isolating Prev:


Now, we can substitute this definition in the first equation,
which leaves only E and R signals (our expected domain and range,


Simplifying this yields:

R(z_{\ell},z_{b})=(1-\alpha z_{\ell}^{-1})\cdot\frac{1-z_{b}^{-1}}{1-\beta

Or, equivalently:

A(z_{\ell},z_{b})=(1-\alpha z_{\ell}^{-1})\cdot\frac{1-z_{b}^{-1}}{1-\beta

Just as expected!

[0] https://arxiv.org/abs/1602.04845
[1] https://datatracker.ietf.org/doc/html/rfc6716#section-4.3.2
[2] https://opus-codec.org/release/stable/2019/04/12/libopus-1_3_1.html
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.xiph.org/pipermail/opus/attachments/20210703/95d5f41a/attachment-0001.htm>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: predictor-confusion-5.lyx
Type: application/lyx
Size: 7306 bytes
Desc: not available
URL: <http://lists.xiph.org/pipermail/opus/attachments/20210703/95d5f41a/attachment-0001.bin>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: predictor-confusion-5.pdf
Type: application/pdf
Size: 84298 bytes
Desc: not available
URL: <http://lists.xiph.org/pipermail/opus/attachments/20210703/95d5f41a/attachment-0001.pdf>

More information about the opus mailing list