To change the sampling rate of a signal, one needs to upsample , filter, then downsample. Doing this naively means inserting zeros into the input signal, correlating with a filter's impulse response, then discarding all but every n
th sample of the convolution.
The problem with the naive approach is that there is a lot of useless computation. When convolving with the filter, most of the filter taps are multiplied by zero, and computing the value of samples that will be discarded in the downsampling phase is useless. That's why efficient rational resampling uses polyphase filter banks, where only the computations that are needed are performed.
I wonder if it would be possible to use lazy computation to avoid the useless multiplications, while also avoiding explicitely constructing the polyphase filter banks. My ideal solution would be something that resembled the naive approach (upsample, then correlate, then downsample), but did the same computations as the explicit polyphase filter approach.
The downsampling is easy, since values that aren't needed won't be calculated. But I can't figure out how to avoid the multiplications-by-zero in the correlation part. The best I've come up with is to use the Maybe type and upsample with Nothings (instead of zeros):
upsample n xs = upsample2' n xs 0
where upsample' _ [] _ = []
upsample' _ (x:_) 0 = Just x : upsample' n xs n
upsample' n xs counter = Nothing : upsample' n xs (counter - 1)
correlate xs ys = sum $ catMaybes $ zipWith (fmap . (*)) xs ys
firFilter taps signal = map (correlate taps) (tails signal)
downsample _ [] = []
downsample n (x:xs) = x : downsample n (drop (n-1) xs)
upfirdn up down taps = (downsample down).(fir_filter taps).(upsample up)
The upfirdn
function indeed is just the straightforward approach, and laziness in the downsampling avoids computation, but I think the processor still needs to check if values are Nothing
in the correlation step.
Is there a way to use laziness to get the same computational savings as the polyphase filter approach? If not, is there a fundamental reason it can't be done?