[music-dsp] who else needs a fractional delay.
Ross Bencina
rossb-lists at audiomulch.com
Sun Nov 21 06:10:22 EST 2010
robert bristow-johnson wrote:
> On Nov 20, 2010, at 4:46 PM, Ross Bencina wrote:
>> I'm implementing a low-latency audio-over-wi-fi system with UDP
>> transport. The packet period is somewhere between 5 and 30ms. I'm doing
>> clock-recovery on the client to keep the buffering in sync. Since it's a
>> low latency system I can't afford to have more than the minimum required
>> buffering - so getting the playout rate correct is important.
>>
>> I've already implemented a prototype/simulation of most of the
>> mechanisms. I'm using a PI controller for the servo mechanism with a
>> feedforward path for (smoothed) playback rate (so the servo only really
>> needs to deal with correcting offset errors). I havn't tuned it yet, but
>> the simulation results look OK. I found the wikipedia article on PID
>> controllers pretty helpful: http://en.wikipedia.org/wiki/PID_controller
>> Would you recommend something other than a PI controller for this?
>
> i don't think you want any D, but you probably want some P and I.
Yeah, that's why I said "I'm using a PI controller"
> one thing to remember, because this becomes the rate input to an NCO
> (essentially the output pointer address, which has a fractional
> component), there is an inherent integrator in your "plant" (using
> control systems lingo :). the plant and the controller are essentially
> in series, so the integrator in the plant teams up with the PI making it
> I and I^2, instead. maybe you *do* want a D. i dunno. but i'm pretty
> sure you don't need an I, because your controller P already is your I.
Interesting, I hadn't thought of that, thanks. So if P is already my I,
what's my P? or is that why you're saying I might want D...
>>> From my point of view the more difficult thing is recovering a stable
>> wordclock from a jittery packet stream -- and getting this to start up
>> quickly enough to be useful. In the past I've used an Ordinary Least
>> Squares regression on packet timestamps to estimate the incoming sample
>> rate and intercept (time offset).
>
> whoa! i wonder how that is incorporated in this?
>
> i'm only thinking about how a difference signal between two pointers in a
> buffer.
Yep.
The problem is that there can be a huge amount of jitter on the audio
packets. Let's say the packets have a 29ms period -- the jitter caused by
the network (especially with Multicast traffic over WiFi) can be up to
50ms... so asking the servo mechanism to smooth out all of that jitter is
asking quite a lot... especially since a P(I)(D) mechanism has no inherent
model of system or measurement error. you could heavily damp the system and
I suppose it might stabilise eventually but I need more stability and faster
convergence than that.
So I have two phases:
1. The network packets come in and I timestamp them and run some kind of
robust clock recovery procedure (OLS, Kalman, whatever) to determine the
incoming sample rate and phase/offset.
2. Take this stabilised rate and offset information and feed it to the PI
controller to adjust the playout rate.
I might be able to do it all in one step with some kind of fancy controller
that I have no idea about right now, but I my intuition is that it's best to
recover a stable incoming sample clock first and feed this into a PI
controller (ie a mostly feedforward structure) rather than having a feedback
system act on such massively jittery phase information.
I have read quite a few papers on approaches to this (mostly in clock
recovery for IP TV, but also some audio streaming applications) and everyone
seems to have their own favourite method -- with little consensus. I found
people proposing new methods in the literature as late as 2009.
> there is an input pointer that increments each time you get an input
> sample (you might be getting them in asynchronous bursts of samples).
> and there is an output pointer that advances by a given stride that has
> both integer and fractional components. the value of that stride is the
> reciprocal of the output/input sample rate ratio, r. at least it is,
> when it settles down to a reasonably constant value.
Yep. Arrival of input samples in this system have a jitter of ~50ms.
> so imagine this circular buffer with samples popping in with a pointer
> whose increment stride is 1. and an output pointer that increments by
> something that settles down to 1/r. that is the signal that comes out of
> your controller.
>
> what goes into your controller is the difference between the output
> pointer (the pointer that has an integer and fractional value) and a set
> point for that pointer. the set point is at some fixed delay behind the
> input pointer, which might be at the opposite side of the circular buffer
> (if you want an equal amount of elbow room, but you might not if you want
> low latency).
That's what I'm doing. I feed samples into the structure using the incoming
sample rate i derive at step (1) above.
> do you get time-stamps for the samples going out? does it come from an
> asynchronous interrupt source or can you increment some number for it?
I timestamp a UDP packet when it arrives. The packet contains ~29ms of audio
data @44.1k in the current implementation... but the packet size might
change.
> when the input and output sample rates are *almost* the same, there can
> be a problem of delay slippage of a single sample when the controller
> knows it's off. so you have to compute a signal from the difference of
> timestamp of the sample (or packet) now going out and the computed
> timestamp of effectively where the input pointer is. even thought it
> always increments by 1, you need a fractional signal that represents a
> smoothly incrementing pointer value that happens to cross an integer
> sample boundary every time an input sample comes in. this is estimated
> from the N most recent input samples (or packets). this might be the
> regression problem you mention. i dunno.
Yes, I think that's the regression problem I mention. I need to continuously
compute the relative word-clock phase of the incoming signal.
>> This time I have a mechanism for time offset based on the assumption
>> that the "most on time" packets represent the best time offset, but the
>> rate estimator is still a bit of a mystery... I have a Kalman filter
>> version that works about as well as the OLS rate detector and is a
>> little cheaper -- lately I've been reading up on "robust regression"
>> methods (LMS and TLS) -- they're pretty costly but I'm hoping they'll
>> allow me to lock on to the word clock more quickly.
>
> i haven't done a Kalman filter problem since grad school. i dunno how to
> do it or use it anymore. i've been comparing this problem to a more
> hardware-like ASRC where, from reading the DSP chip's clock register
> (that increments at the machine instruction rate) when an input sample
> arrives (and putting it into a buffer) and when the output samples goes
> out. that, and the difference of the output pointer and the set point
> (that increments with the input pointer and that fractional portion that
> is computed). there is a simple way to anticipate what the fractional
> portion is from the difference of the most recent two input timestamps
> and the difference of the output timestamp and the most recent input
> timestamp. but i can see that with more of the input timestamps (than
> just two), you can get a better guess.
The difference between what you describe, and the problem I have is that I
have only one timestamp every 29ms, not one timestamp per sample. And my
timestamp can be wrong by up to 50ms. So I need to do the regression (or
similar) accross a larger number of timestamps to try to recover something
remotely approximating a word clock (constant time increment per incoming
sample)
> but i haven't tried it because i was thinking that the simple method
> would be good enough if the two asynced sample streams settled down. if
> they settle down, then your increment rate on the output pointer should
> become constant and about 1/r. that's what your controller has to do.
once I've done the wordclock recovery, then i can do that bit. That's my
step 2 above.
thanks.. it's a big help to have the opportunity to try to explain it. and
although I'm still hunting for the idea robust regression/state estimation
method to do the clock recovery with I think I understand what I want the
result to look like a bit better than the (P)(I)(D) controller bit.
Ross.
More information about the music-dsp
mailing list