module DSP.Filter.IIR.Design (
poly2iir,
butterworthLowpass, butterworthHighpass, butterworthBandpass,
chebyshev1Lowpass, chebyshev2Lowpass,
mkButterworth, mkChebyshev1, mkChebyshev2,
) where
import qualified DSP.Filter.Analog.Prototype as Analog
import DSP.Filter.Analog.Transform (a_lp2lp, a_lp2hp, a_lp2bp)
import DSP.Filter.IIR.Bilinear (bilinear, prewarp)
import DSP.Basic ((^!))
import Data.Array (Array, listArray)
poly2iir :: ([a], [b]) -> (Array Int a, Array Int b)
poly2iir (a,b) =
let toArray x = listArray (0, length x - 1) $ reverse x
in (toArray a, toArray b)
butterworthLowpass, mkButterworth ::
(Double, Double)
-> (Double, Double)
-> (Array Int Double, Array Int Double)
butterworthLowpass p s =
let (n, s') = butterworthParams p s
in butterworth (a_lp2lp $ wc n s') n
butterworthHighpass, butterworthBandpass ::
(Double, Double) ->
(Double, Double) ->
(Array Int Double, Array Int Double)
butterworthHighpass p s =
let (n, s') = butterworthParams p s
in butterworth (a_lp2hp $ wc n s') n
butterworthBandpass p@(wp, _dp) s@(ws, _ds) =
let (n, _s') = butterworthParams p s
in butterworth (a_lp2bp wp ws) n
butterworth ::
(([Double], [Double]) -> ([Double], [Double])) ->
Int -> (Array Int Double, Array Int Double)
butterworth analogToAnalog n =
poly2iir $ bilinear 1 $ analogToAnalog $ Analog.butterworth n
butterworthParams ::
(Double, Double) ->
(Double, Double) ->
(Int, (Double, Double))
butterworthParams (wp, dp) (ws, ds) =
let n = ceiling $ log (((1/ds)^!2-1) / ((1/(1-dp))^!2-1)) / 2 / log (ws' / wp')
wp' = prewarp wp 1
ws' = prewarp ws 1
in (n, (ws', ds))
wc :: Floating a => Int -> (a, a) -> a
wc n (ws', ds) = ws' / ((1/ds)^!2 - 1) ** (1/2/fromIntegral n)
{-# DEPRECATED mkButterworth "Use butterworthLowpass instead" #-}
mkButterworth = butterworthLowpass
chebyshev1Lowpass, mkChebyshev1 ::
(Double, Double)
-> (Double, Double)
-> (Array Int Double, Array Int Double)
chebyshev1Lowpass (wp,dp) (ws,ds) = poly2iir $
bilinear 1 $
a_lp2lp wp' $
Analog.chebyshev1 eps n
where wp' = prewarp wp 1
ws' = prewarp ws 1
eps = sqrt ((2 - dp)*dp) / (1 - dp)
a = 1 / ds
k1 = eps / sqrt (a^!2 - 1)
k = wp' / ws'
n = ceiling $ acosh (1/k1) / log ((1 + sqrt (1 - k^!2)) / k)
{-# DEPRECATED mkChebyshev1 "Use chebyshev1Lowpass instead" #-}
mkChebyshev1 = chebyshev1Lowpass
chebyshev2Lowpass, mkChebyshev2 ::
(Double, Double)
-> (Double, Double)
-> (Array Int Double, Array Int Double)
chebyshev2Lowpass (wp,dp) (ws,ds) = poly2iir $
bilinear 1 $
a_lp2lp ws' $
Analog.chebyshev2 eps n
where wp' = prewarp wp 1
ws' = prewarp ws 1
eps = ds / sqrt (1 - ds^!2)
g = 1 - dp
n = ceiling $ acosh (g / eps / sqrt (1 - g^!2)) / acosh (ws' / wp')
{-# DEPRECATED mkChebyshev2 "Use chebyshev2Lowpass instead" #-}
mkChebyshev2 = chebyshev2Lowpass