----------------------------------------------------------------------------- -- | -- Module : DSP.Multirate.CIC -- Copyright : (c) Matthew Donadio 1998 -- License : GPL -- -- Maintainer : m.p.donadio@ieee.org -- Stability : experimental -- Portability : portable -- -- CIC filters -- -- R = rate change -- -- M = differential delay in combs -- -- N = number of stages -- ----------------------------------------------------------------------------- {- An implementation in Haskell of the description of CIC decimator and interpolators as described in: @Article{Hogenauer_AnEcon_ASSP81, journal = "{IEEE} Trans. Acoustics, Speech and Signal Processing", author = "E. B. Hogenauer", title = "An Economical Class of Digital Filters for Decimation and Interpolation", year = "1981", volume = "{ASSP-29}", number = "2", pages = "155", } Note that this implementation does not account for the overflow handling, bit growth, etc., described in the paper, but this does not matter for real or complex data. -} module DSP.Multirate.CIC (cic_interpolate, cic_decimate) where import DSP.Basic (delay1, delay, upsample, downsample) -- apply returns a function of n applications of a function, eg, -- apply f 3 = f . f . f -- We will use this to create a cascade of integrators and combs apply :: (a -> a) -> Int -> (a -> a) apply f 1 = f apply f n = f . apply f (n - 1) -- integrate implements a discrte integrator, ie, the output is the sum -- of all previous samples and the current one, eg -- integrate [ 1, 1, 1, 1 ] = [ 1, 2, 3, 4 ] integrate :: (Num a) => [a] -> [a] integrate a = zipWith (+) a (delay1 (integrate a)) -- comb implements the comb function described in the paper above. The m -- parameter is the length of the delay in the feed-forward element. comb :: (Num a) => Int -> [a] -> [a] comb m a = zipWith (-) a (delay m a) {- It is now simple to create a CIC imterpolator or decimator. In the functions below r is the rate change m is the length of the delay in the feed-forward element of the combs n is the number of stages (the number of integrators and combs) integrate_chain and comb_chain are the cascade of integrator and combs (hence the name CIC filter). We then just slap the functions together with the application operator. There is a non unity gain that I should probably account for, but that cound be swallowed up in another function. -} -- | CIC interpolator cic_interpolate :: (Num a) => Int -- ^ R -> Int -- ^ M -> Int -- ^ N -> [a] -- ^ x[n] -> [a] -- ^ y[n] cic_interpolate r m n = integrate_chain . (upsample r) . comb_chain where integrate_chain = apply integrate n comb_chain = apply (comb m) n -- | CIC interpolator cic_decimate :: (Num a) => Int -- ^ R -> Int -- ^ M -> Int -- ^ N -> [a] -- ^ x[n] -> [a] -- ^ y[n] cic_decimate r m n = comb_chain . (downsample r) . integrate_chain where integrate_chain = apply integrate n comb_chain = apply (comb m) n