----------------------------------------------------------------------------- -- | -- Module : DSP.Filter.IIR.IIR -- Copyright : (c) Matthew Donadio 2003 -- License : GPL -- -- Maintainer : m.p.donadio@ieee.org -- Stability : experimental -- Portability : portable -- -- IIR functions -- -- IMPORTANT NOTE: -- -- Except in integrator, we use the convention that -- -- @y[n] = sum(k=0..M) b_k*x[n-k] - sum(k=1..N) a_k*y[n-k]@ -- -- -- -- @ sum(k=0..M) b_k*z^-1@ -- -- @H(z) = ------------------------@ -- -- @ 1 + sum(k=1..N) a_k*z^-1@ -- ----------------------------------------------------------------------------- -- TODO: Should these use Arrays for a and b? Tuples? {- Reference: @Book{dsp, author = "Alan V. Oppenheim and Ronald W. Schafer", title = "Discrete-Time Signal Processing", publisher = "Prentice-Hall", year = 1989, address = "Englewood Cliffs", series = {Prentice-Hall Signal Processing Series} } However, we differ in the convention of the sign of the poles, as noted in the module header. -} module DSP.Filter.IIR.IIR (integrator, fos_df1, fos_df2, fos_df2t, biquad_df1, biquad_df2, biquad_df2t, iir_df1, iir_df2, -- for testing xt, yt, f1, f2, f3, f4, f5, ) where import Data.Array import DSP.Filter.FIR.FIR -- | This is an integrator when a==1, and a leaky integrator when @0 \< a \< 1@. -- -- @y[n] = a * y[n-1] + x[n]@ {-# specialize integrator :: Float -> [Float] -> [Float] #-} {-# specialize integrator :: Double -> [Double] -> [Double] #-} integrator :: Num a => a -- ^ a -> [a] -- ^ x[n] -> [a] -- ^ y[n] integrator a x = integrator' a 0 x integrator' :: Num a => a -> a-> [a] -> [a] integrator' _ _ [] = [] integrator' a y1 (x:xs) = y : integrator' a y xs where y = a * y1 + x -- | First order section, DF1 -- -- @v[n] = b0 * x[n] + b1 * x[n-1]@ -- -- @y[n] = v[n] - a1 * y[n-1]@ {-# specialize fos_df1 :: Float -> Float -> Float -> [Float] -> [Float] #-} {-# specialize fos_df1 :: Double -> Double -> Double -> [Double] -> [Double] #-} fos_df1 :: Num a => a -- ^ a_1 -> a -- ^ b_0 -> a -- ^ b_1 -> [a] -- ^ x[n] -> [a] -- ^ y[n] fos_df1 a1 b0 b1 x = fos_df1' a1 b0 b1 0 0 x fos_df1' :: Num a => a -> a -> a -> a -> a -> [a] -> [a] fos_df1' _ _ _ _ _ [] = [] fos_df1' a1 b0 b1 x1 y1 (x:xs) = y : fos_df1' a1 b0 b1 x y xs where v = b0 * x + b1 * x1 y = v - a1 * y1 -- | First order section, DF2 -- -- @w[n] = -a1 * w[n-1] + x[n]@ -- -- @y[n] = b0 * w[n] + b1 * w[n-1]@ {-# specialize fos_df2 :: Float -> Float -> Float -> [Float] -> [Float] #-} {-# specialize fos_df2 :: Double -> Double -> Double -> [Double] -> [Double] #-} fos_df2 :: Num a => a -- ^ a_1 -> a -- ^ b_0 -> a -- ^ b_1 -> [a] -- ^ x[n] -> [a] -- ^ y[n] fos_df2 a1 b0 b1 x = fos_df2' a1 b0 b1 0 x fos_df2' :: Num a => a -> a -> a -> a -> [a] -> [a] fos_df2' _ _ _ _ [] = [] fos_df2' a1 b0 b1 w1 (x:xs) = y : fos_df2' a1 b0 b1 w xs where w = x - a1 * w1 y = b0 * w + b1 * w1 -- | First order section, DF2T -- -- @v0[n] = b0 * x[n] + v1[n-1]@ -- -- @y[n] = v0[n]@ -- -- @v1[n] = -a1 * y[n] + b1 * x[n]@ {-# specialize fos_df2t :: Float -> Float -> Float -> [Float] -> [Float] #-} {-# specialize fos_df2t :: Double -> Double -> Double -> [Double] -> [Double] #-} fos_df2t :: Num a => a -- ^ a_1 -> a -- ^ b_0 -> a -- ^ b_1 -> [a] -- ^ x[n] -> [a] -- ^ y[n] fos_df2t a1 b0 b1 x = fos_df2t' a1 b0 b1 0 x fos_df2t' :: Num a => a -> a -> a -> a -> [a] -> [a] fos_df2t' _ _ _ _ [] = [] fos_df2t' a1 b0 b1 v11 (x:xs) = y : fos_df2t' a1 b0 b1 v1 xs where v0 = b0 * x + v11 y = v0 v1 = -a1 * y + b1 * x -- | Direct Form I for a second order section -- -- @v[n] = b0 * x[n] + b1 * x[n-1] + b2 * x[n-2]@ -- -- @y[n] = v[n] - a1 * y[n-1] - a2 * y[n-2]@ {-# specialize biquad_df1 :: Float -> Float -> Float -> Float -> Float -> [Float] -> [Float] #-} {-# specialize biquad_df1 :: Double -> Double -> Double -> Double -> Double -> [Double] -> [Double] #-} biquad_df1 :: Num a => a -- ^ a_1 -> a -- ^ a_2 -> a -- ^ b_0 -> a -- ^ b_1 -> a -- ^ b_2 -> [a] -- ^ x[n] -> [a] -- ^ y[n] biquad_df1 a1 a2 b0 b1 b2 x = df1 a1 a2 b0 b1 b2 0 0 0 0 x df1 :: Num a => a -> a -> a -> a -> a -> a -> a -> a -> a -> [a] -> [a] df1 _ _ _ _ _ _ _ _ _ [] = [] df1 a1 a2 b0 b1 b2 x1 x2 y1 y2 (x:xs) = y : df1 a1 a2 b0 b1 b2 x x1 y y1 xs where v = b0 * x + b1 * x1 + b2 * x2 y = v - a1 * y1 - a2 * y2 -- | Direct Form II for a second order section (biquad) -- -- @w[n] = -a1 * w[n-1] - a2 * w[n-2] + x[n]@ -- -- @y[n] = b0 * w[n] + b1 * w[n-1] + b2 * w[n-2]@ {-# specialize biquad_df2 :: Float -> Float -> Float -> Float -> Float -> [Float] -> [Float] #-} {-# specialize biquad_df2 :: Double -> Double -> Double -> Double -> Double -> [Double] -> [Double] #-} biquad_df2 :: Num a => a -- ^ a_1 -> a -- ^ a_2 -> a -- ^ b_0 -> a -- ^ b_1 -> a -- ^ b_2 -> [a] -- ^ x[n] -> [a] -- ^ y[n] biquad_df2 a1 a2 b0 b1 b2 x = df2 a1 a2 b0 b1 b2 0 0 x df2 :: Num a => a -> a -> a -> a -> a -> a -> a -> [a] -> [a] df2 _ _ _ _ _ _ _ [] = [] df2 a1 a2 b0 b1 b2 w1 w2 (x:xs) = y : df2 a1 a2 b0 b1 b2 w w1 xs where w = x - a1 * w1 - a2 * w2 y = b0 * w + b1 * w1 + b2 * w2 -- | Transposed Direct Form II for a second order section -- -- @v0[n] = b0 * x[n] + v1[n-1]@ -- -- @y[n] = v0[n]@ -- -- @v1[n] = -a1 * y[n] + b1 * x[n] + v2[n-1]@ -- -- @v2[n] = -a2 * y[n] + b2 * x[n]@ {-# specialize biquad_df2t :: Float -> Float -> Float -> Float -> Float -> [Float] -> [Float] #-} {-# specialize biquad_df2t :: Double -> Double -> Double -> Double -> Double -> [Double] -> [Double] #-} biquad_df2t :: Num a => a -- ^ a_1 -> a -- ^ a_2 -> a -- ^ b_0 -> a -- ^ b_1 -> a -- ^ b_2 -> [a] -- ^ x[n] -> [a] -- ^ y[n] biquad_df2t a1 a2 b0 b1 b2 x = df2t a1 a2 b0 b1 b2 0 0 x df2t :: Num a => a -> a -> a -> a -> a -> a -> a -> [a] -> [a] df2t _ _ _ _ _ _ _ [] = [] df2t a1 a2 b0 b1 b2 v11 v21 (x:xs) = y : df2t a1 a2 b0 b1 b2 v1 v2 xs where v0 = b0 * x + v11 y = v0 v1 = -a1 * y + b1 * x + v21 v2 = -a2 * y + b2 * x -- | Direct Form I IIR -- -- @v[n] = sum(k=0..M) b_k*x[n-k]@ -- -- @y[n] = v[n] - sum(k=1..N) a_k*y[n-k]@ -- -- @v[n]@ is calculated with 'fir' {- specialize iir_df1 :: (Array Int Float, Array Int Float) -> [Float] -> [Float] -} {- specialize iir_df1 :: (Array Int Double, Array Int Double) -> [Double] -> [Double] -} iir_df1 :: (Num a, Eq a) => (Array Int a, Array Int a) -- ^ (b,a) -> [a] -- ^ x[n] -> [a] -- ^ y[n] iir_df1 (b,a) x = y where v = fir b x y = iir'df1 a w v w = listArray (1,n) $ repeat 0 n = snd $ bounds a {- specialize iir'df1 :: Array Int Float -> Array Int Float -> [Float] -> [Float] -} {- specialize iir'df1 :: Array Int Double -> Array Int Double -> [Double] -> [Double] -} iir'df1 :: (Num a) => Array Int a -> Array Int a -> [a] -> [a] iir'df1 _ _ [] = [] iir'df1 a w (v:vs) = y : iir'df1 a w' vs where y = v - sum [ a!i * w!i | i <- [1..n] ] w' = listArray (1,n) $ y : elems w n = snd $ bounds a -- | Direct Form II IIR -- -- @w[n] = x[n] - sum(k=1..N) a_k*w[n-k]@ -- -- @y[n] = sum(k=0..M) b_k*w[n-k]@ {- specialize iir_df2 :: (Array Int Float, Array Int Float) -> [Float] -> [Float] -} {- specialize iir_df2 :: (Array Int Double, Array Int Double) -> [Double] -> [Double] -} iir_df2 :: (Num a) => (Array Int a, Array Int a) -- ^ (b,a) -> [a] -- ^ x[n] -> [a] -- ^ y[n] iir_df2 (b,a) x = y where y = iir'df2 (b,a) w x w = listArray (0,mn) $ repeat 0 m = snd $ bounds b n = snd $ bounds a mn = max m n {- specialize iir'df2 :: Array Int Float -> Array Int Float -> [Float] -> [Float] -} {- specialize iir'df2 :: Array Int Double -> Array Int Double -> [Double] -> [Double] -} iir'df2 :: (Num a) => (Array Int a,Array Int a) -> Array Int a -> [a] -> [a] iir'df2 _ _ [] = [] iir'df2 (b,a) w (x:xs) = y : iir'df2 (b,a) w' xs where y = sum [ b!i * w'!i | i <- [0..m] ] w0 = x - sum [ a!i * w'!i | i <- [1..m] ] w' = listArray (0,mn) $ w0 : elems w m = snd $ bounds b mn = snd $ bounds w --------- -- test xt :: [Double] xt = [ 1, 0, 0, 0, 0, 0, 0, 0 ] :: [Double] yt :: [Double] yt = integrator 0.5 xt f1 :: Fractional a => [a] -> [a] f1 x = biquad_df1 (-0.4) 0.3 0.5 0.4 (-0.3) x f2 :: Fractional a => [a] -> [a] f2 x = biquad_df2 (-0.4) 0.3 0.5 0.4 (-0.3) x f3 :: Fractional a => [a] -> [a] f3 x = biquad_df2t (-0.4) 0.3 0.5 0.4 (-0.3) x at :: Array Int Double at = listArray (1,2) [ -0.4, 0.3 ] bt :: Array Int Double bt = listArray (0,2) [ 0.5, 0.4, -0.3 ] f4 :: [Double] -> [Double] f4 x = iir_df1 (bt,at) x f5 :: [Double] -> [Double] f5 x = iir_df2 (bt,at) x