dsp-0.1: DSP/Filter/FIR/Kaiser.hs
-----------------------------------------------------------------------------
-- |
-- Module : DSP.Filter.FIR.Kaiser
-- Copyright : (c) Matthew Donadio 1998
-- License : GPL
--
-- Maintainer : m.p.donadio@ieee.org
-- Stability : experimental
-- Portability : portable
--
-- This module implements the Kaiser Window Method for designing FIR
-- filters.
--
-----------------------------------------------------------------------------
-- Reference:
--
-- @Book{dsp,
-- author = "Alan V. Oppenheim and Ronald W. Schafer",
-- title = "Discrete-Time Signal Processing",
-- publisher = "Pretice-Hall",
-- year = 1989,
-- address = "Englewood Cliffs",
-- series = {Pretice-Hall Signal Processing Series}
-- }
module DSP.Filter.FIR.Kaiser (kaiser_lpf, kaiser_hpf) where
import Data.Array
import DSP.Filter.FIR.Window
import DSP.Filter.FIR.Taps
-- Set the cutoff frequency to the middle of the transition band. This
-- equation isn't numbered.
calc_wc wp ws = (wp + ws) / 2
-- Equation 7.90
calc_dw wp ws = abs (ws - wp)
-- Equation 7.91
calc_A d1 d2 = -20 * logBase 10 (min d1 d2)
-- xEquation 7.92
calc_beta a | a > 50 = 0.1102 * (a - 8.7)
| a >= 21 = 0.5842 * ((a-21) ** 0.4) + 0.07886 * (a-21)
| otherwise = 0.0
-- Equation 7.93
calc_M a dw = ceiling ((a - 8) / (2.285 * dw))
-- Procedure on pg 455. We should really check the peak approximation
-- error and then increase M if necessary.
-- | Designs a lowpass Kaiser filter
kaiser_lpf :: Double -- ^ wp
-> Double -- ^ ws
-> Double -- ^ dp
-> Double -- ^ ds
-> Array Int Double -- ^ h[n]
kaiser_lpf wp ws d1 d2 = window (kaiser beta m) (lpf wc m)
where wc = calc_wc wp ws
dw = calc_dw wp ws
a = calc_A d1 d2
beta = calc_beta a
m = calc_M a dw
-- The weird case for m below is because highpass (or bandstop) filters
-- should only be Type I. Linear phase forces a null at w=pi for Type II
-- filters, which doesn't fit well with these kinds of filters. Again,
-- we should really check the peak approximation error and then increase
-- M (by two) if necessary.
-- | Designs a highpass Kaiser filter
kaiser_hpf :: Double -- ^ wp
-> Double -- ^ ws
-> Double -- ^ dp
-> Double -- ^ ds
-> Array Int Double -- ^ h[n]
kaiser_hpf wp ws d1 d2 = window (kaiser beta m) (hpf wc m)
where wc = calc_wc wp ws
dw = calc_dw wp ws
a = calc_A d1 d2
beta = calc_beta a
m | odd (calc_M a dw) = (calc_M a dw) + 1
| otherwise = (calc_M a dw)