dsp-0.1: DSP/Filter/FIR/Smooth.hs
-----------------------------------------------------------------------------
-- |
-- Module : DSP.Filter.FIR.Smooth
-- Copyright : (c) Matthew Donadio 2003
-- License : GPL
--
-- Maintainer : m.p.donadio@ieee.org
-- Stability : experimental
-- Portability : portable
--
-- Herrmann type smooth FIR filters, from Hamming, Chapter 7, also
-- known as maximally flat FIR filters
--
-- If x is the -3 dB point, then p\/q = -(x+1)\/(x-1)
--
-----------------------------------------------------------------------------
-- TODO: function for rational fraction approximation
-- TODO: input parameters in the style of sect53.f
module DSP.Filter.FIR.Smooth (smoothfir) where
import Data.Array
import Polynomial.Basic
-- Normalize is the step to set g(1) = 1 (pg 123)
normalize x = map (/ a) x
where a = sum x
-- Expand performs the algorithm in Sect 7.3
expand (x1:x2:[]) = [ x1, x2 ]
expand (x:xs) = expand' x $ expand xs
expand' x ys = zipWith (+) (m1 x ys) (p1 ys)
where m1 x (y:ys) = x : y : map (0.5*) ys
p1 (y:ys) = map (0.5*) ys ++ [ 0, 0 ]
-- Reflect makes the filter symetric (not sure where this is stated)
reflect (x:xs) = (map (0.5*) $ reverse xs) ++ x : (map (0.5*) xs)
-- The actual function. Note that we use (1+t)^p * (1-t)^q directly
-- since we have a polynomial library.
-- | designs smooth FIR filters
smoothfir :: (Ix a, Integral a, Fractional b) => a -- ^ p
-> a -- ^ q
-> Array a b -- ^ h[n]
smoothfir p q = listArray (0,n-1) $ reflect $ expand $ b
where b' = polymult (polypow [ 1, 1 ] p) (polypow [ 1, -1 ] q)
b1 = polyinteg b' 0
c = -polyeval b1 (-1)
b = normalize $ c : tail b1
n = 2 * (p+1 + q+1) - 1
-- Test
-- map (256*) $ elems $ smoothfir 3 1 == [ -1, -5, -5, 20, 70, 98, 70, 20, -5, -5, -1 ]