-----------------------------------------------------------------------------
-- |
-- 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 :: forall a. (a -> a) -> Int -> a -> a
apply a -> a
f Int
1 = a -> a
f
apply a -> a
f Int
n = a -> a
f forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. (a -> a) -> Int -> a -> a
apply a -> a
f (Int
n forall a. Num a => a -> a -> a
- Int
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 :: forall a. Num a => [a] -> [a]
integrate [a]
a = forall a b c. (a -> b -> c) -> [a] -> [b] -> [c]
zipWith forall a. Num a => a -> a -> a
(+) [a]
a (forall a. Num a => [a] -> [a]
delay1 (forall a. Num a => [a] -> [a]
integrate [a]
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 :: forall a. Num a => Int -> [a] -> [a]
comb Int
m [a]
a = forall a b c. (a -> b -> c) -> [a] -> [b] -> [c]
zipWith (-) [a]
a (forall a. Num a => Int -> [a] -> [a]
delay Int
m [a]
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 :: forall a. Num a => Int -> Int -> Int -> [a] -> [a]
cic_interpolate Int
r Int
m Int
n = [a] -> [a]
integrate_chain forall b c a. (b -> c) -> (a -> b) -> a -> c
. (forall a. Num a => Int -> [a] -> [a]
upsample Int
r) forall b c a. (b -> c) -> (a -> b) -> a -> c
. [a] -> [a]
comb_chain
    where integrate_chain :: [a] -> [a]
integrate_chain = forall a. (a -> a) -> Int -> a -> a
apply forall a. Num a => [a] -> [a]
integrate Int
n
          comb_chain :: [a] -> [a]
comb_chain = forall a. (a -> a) -> Int -> a -> a
apply (forall a. Num a => Int -> [a] -> [a]
comb Int
m) Int
n

-- | CIC interpolator

cic_decimate :: (Num a) => Int -- ^ R
	     -> Int -- ^ M
	     -> Int -- ^ N
	     -> [a] -- ^ x[n]
	     -> [a] -- ^ y[n]

cic_decimate :: forall a. Num a => Int -> Int -> Int -> [a] -> [a]
cic_decimate Int
r Int
m Int
n = [a] -> [a]
comb_chain forall b c a. (b -> c) -> (a -> b) -> a -> c
. (forall a. Int -> [a] -> [a]
downsample Int
r) forall b c a. (b -> c) -> (a -> b) -> a -> c
. [a] -> [a]
integrate_chain
    where integrate_chain :: [a] -> [a]
integrate_chain = forall a. (a -> a) -> Int -> a -> a
apply forall a. Num a => [a] -> [a]
integrate Int
n
          comb_chain :: [a] -> [a]
comb_chain = forall a. (a -> a) -> Int -> a -> a
apply (forall a. Num a => Int -> [a] -> [a]
comb Int
m) Int
n