Introduction
In this article we look at implementing fractional delays using Linear Interpolation and Resampling Techniques
A integral delay of $M$ is obtained by a delay line of length $M$.A factional delay is implemented cascading the integral part of delay with a block which can approximate a constant phase delay equal to fractional part of $m$
Fractional delay filters receive a sequential stream of input samples and produce a corresponding sequential stream of interpolated output values.
The most intuitive way of obtaining fractional delay is interpolation .
For an ideal fractional-delay filter, the frequency response should be equal to that of an ideal delay
$\displaystyle H^\ast(e^{j\omega}) = e^{-j\omega\Delta}$
where $ \Delta = N+ \eta$ denotes the total desired delay of the filter Thus, the ideal desired frequency response is a linear phase term corresponding to a delay of $ \Delta$ samples.
Linear Interpolation
Linear interpolation works by effectively drawing a straight line between two neighboring samples and returning the appropriate point along that line.
More specifically, let $ \eta$ be a number between 0 and 1 which represents how far we want to interpolate a signal $ y$ between time $ n$ and time $ n+1$ . Then we can define the linearly interpolated value $ \hat y(n+\eta)$ as follows:
$\displaystyle \hat y(n+\eta) = (1-\eta) \cdot y(n) + \eta \cdot y(n+1) $
$\displaystyle \hat y(n+\eta) = y(n) + \eta\cdot\left[y(n+1) - y(n)\right].$
Thus, the computational complexity of linear interpolation is one multiply and two additions per sample of output.
In case of delay filter $\eta$ is the fractional part of the delay.Thus we pass the sequence throught a filter
for example for a delay of 1/4 $\displaystyle {\hat y}\left(n-\frac{1}{4}\right) \;=\;\frac{3}{4} \cdot y(n) + \frac{1}{4}\cdot y(n-1) $
The python code for implementing fractional delay by interpolation can be found below
def convolution(signal,h): """ function that performs linear convolution """ output=scipy.convolve(signal,h,"same") return output def fdelay(signal,N): """ function introduces a fractional delay of N samples Parameters ----------- signal : numpy-array, The input signal N : factional delay Returns -------- out : numpy-array delayed signal """ f,i=math.modf(N) #perform integral delay signal=delay(signal,i) #perform linear interpolation for fractional delay output=convolution(signal,[f,i-f]) return output def delay(signal,N): """ function introduces a circular delay of N samples Parameters ----------- signal : numpy-array, The input signal N : integer delay Returns -------- out : numpy-array delayed signal """ if N==0: return signal; if N >= len(signal): N=N-len(signal) if N <0: N=N+len(signal) d=signal[len(signal)-N:len(signal)];#numpy.zeros((1,N+1)); signal1=numpy.append(d,signal[0:len(signal)-N]) return signal1;
Upsampling Technique
Let us assume we can express the fractional delay as rational number $\frac{M}{N}$
The steps to introduce fractional delay are
- upsample the sequence by a factor $N$ which simple inserts N zeros between adjacent samples.
- interpolate the zero values using low pass filter
- Delay the signal by $M$ samples
- downsample by a factor $N$
def fdelay(signal,N,mode="upsample"): """ function introduces a fractional delay of N samples Parameters ----------- signal : numpy-array, The input signal N : factional delay mode : "linear " - linear interpolation "upsample " - upsampling technique Returns -------- out : numpy-array delayed signal """ if mode=="linear": f,i=math.modf(N) #perform integral delay signal=delay(signal,i) #perform linear interpolation for fractional delay output=convolution(signal,[f,i-f]) if mode=="upsample": N=math.ceil(N*100)/100 #get rational approximation result=fractions.Fraction(N).limit_denominator(20) num=result.numerator; den=result.denominator #upsample the signal and interpolate out1=scipy.signal.resample(signal,den*len(signal)) #delay the signal out1=delay(out1,int(num)) #downsample the signal out1=scipy.signal.resample(out1,len(signal)) output=out1 return output
The Rational number has been chosse such that denominator is limited to 20 ,so that we are not upscaling by a large factor.
Code
The code for the same can be found in the pyVision github repository in files
The function fdelay
implements fractional delay while function delay
implements integer delay.
The mode
parameter of fdelay
function specified which method to use to perform fractional delay operations.
presently it support linear
- Linear Interpolation and upsample
- Upsamling technique