I've been looking at the opus paper (https://arxiv.org/pdf/1602.04845.pdf); in particular, in section 4.1, they describe the predictor for the current band energy based on energy from both the current band from the previous frames, and the previous bands in the current frame. This makes sense; I would interpret this as "some linear combination of the previous values". Where I get a bit stuck (due to unfamiliarity) is that the predictor is described in the paper by its z-transform. To quote:
"The 2D $z$-transform of the predictor is
$A(z_\ell,z_b)=(1-\alpha{z_\ell^{-1}})\cdot\frac{1-{z_b^{-1}}}{1-\beta{z_b^{-1}}}$
where $\ell$ is the frame index and $b$ is the band."
My main questions are: how might I interpret this as a difference equation, and why is it presented as a $z$-transform in the first place?
Here's what I've got so far:
So, it appears to be describing some kind of filter $a(\ell,b)$. This filter seems to be made up of two separate filters (one based on the previous frame energy and one based on the previous band). The former appears to be a basic FIR filter with one tap and the coefficient $\alpha$; the latter appears to be an IIR filter with one input tap with coefficient $-1$ and one output tap with coefficient $\beta$. so, first questions:
- why $a$? Is it just arbitrary? I would have expected that this was a transfer function, in which case I would have expected $h$.
- is my interpretation of the two filters separately correct?
assuming I've interpreted them correctly separately, I would convert them to difference equations, eg. the first one might be:
$y[n]=\alpha{x[n-1]}$
and the second one might be:
$y[n]=x[n-1]+\beta{y[n-1]}$
next question:
- is this correct?
These filters are multiplied in the z-domain, which I would interpret as being applied in series somehow (as that should correspond to convolution in the time domain), but they have different subscripts for the z
values so I'm not totally sure.
To gain a better understanding, I took a look at the code for the filter (in unquant_coarse_energy
in quant_bands.c
in the latest libopus). I tried to simplify it as much as possible (removing multichannel/fixed point/etc) and came up with this:
// On input, bandEnergies represents the energies from previous frame (or zeros if first frame)
void decodeBandEnergies(float bandEnergies[], int numBands, bool intra)
{
float alpha = <something based on intra etc>f;
float beta = <something based on intra etc>f;
float prev = 0.0f;
for (int band = 0; band < numBands; band++)
{
float q = <decode from bitstream>;
bandEnergies[band] = alpha * bandEnergies[band] + prev + q;
prev = prev + q - beta * q;
}
}
I think I did this right but there may be mistakes. Anyway, q
in this case represents the residual energy for the current frame/band, so q[l,b]=a[l,b]-x[l,b]
if x
is the previous band energies.
From this simplified code it looks like my interpretation of the filter for the last frame energy is correct, but I'm very confused about how prev
and its usage matches both the previous band predictor, as well as why they're composed here with addition.
Any help/tips would be appreciated!