-----------------------------------------------------------------------------
-- |
-- Module      :  DSP.Filter.IIR.Bilinear
-- Copyright   :  (c) Matthew Donadio 2003
-- License     :  GPL
--
-- Maintainer  :  m.p.donadio@ieee.org
-- Stability   :  experimental
-- Portability :  portable
--
-- The module contains a function for performing the bilinear transform.
--
-- The input is a rational polynomial representation of the s-domain
-- function to be transformed.
--
-- In the bilinear transform, we substitute
--
-- @       2    1 - z^-1@
--
-- @s \<--  -- * --------@
--
-- @       ts   1 + z^-1@
--
-- into the rational polynomial, where ts is the sampling period.  To get
-- a rational polynomial back, we use the following method:
--
-- (1) Substitute s^n with (2\/ts * (1-z^-1))^n == [ -2\/ts, 2\/ts ]^n
--
-- 2.  Multiply the results by (1+z^-1)^n == [ 1, 1 ]^n
--
-- 3.  Add up all of the common terms
--
-- 4.  Normalize all of the coeficients by a0
--
-- where n is the maximum order of the numerator and denominator
--
-----------------------------------------------------------------------------

-- TODO: Rework to replace roots2poly using the fact that most poles
-- and\/or zeros are either complex conjugate pairs, or real only.

-- TODO: Do we want to include prewarping?

module DSP.Filter.IIR.Bilinear {- (bilinear, prewarp) -} where

import Polynomial.Basic

-- Computes (2\/ts * (1-z^-1))^n == [ -2\/ts, 2\/ts ]^n

zm :: (Integral b, Fractional a) => a -> b -> [a]
zm ts n = polypow [ -2/ts, 2/ts ] n

-- Computes (1+z^-1)^n == [ 1, 1 ]^n

zp :: (Integral b, Num a) => b -> [a]
zp n = polypow [ 1, 1 ] n

-- Step 1: Substitute s^n with (2\/ts * (1-z^-1))^n == [ -2\/ts, 2\/ts ]^n
-- in num and den

step1 :: Fractional a => a -> [a] -> [[a]]
step1 ts = step1' (0::Int)
    where step1' _ []     = []
          step1' n (x:xs) = polyscale x (zm ts n) : step1' (n+1) xs

-- Step 2: Multiply the num and den by (1+z^-1)^n == [ 1, 1 ]^n

step2 :: (Num a, Integral b) => b -> [[a]] -> [[a]]
step2 _ []     = []
step2 n (x:xs) = polymult (zp n) x : step2 (n-1) xs

-- Step 3: Add up all of the common terms

step3 :: Num a => [[a]] -> [a]
step3 x = foldr polyadd [0] x

-- Step 4: Normalize all of the coeficients by a0

step4 :: Fractional a => a -> [a] -> [a]
step4 a0 x = map (/a0) x

-- Glue it all together

-- | Performs the bilinear transform

bilinear :: Double -- ^ T_s
         -> ([Double],[Double]) -- ^ (b,a)
         -> ([Double],[Double]) -- ^ (b',a')

bilinear ts (num,den) = (num'', den'')
    where n = max (length num - 1) (length den - 1)
          num' = step3 $ step2 n $ step1 ts $ num
          den' = step3 $ step2 n $ step1 ts $ den
          a0 = last den'
          num'' = step4 a0 num'
          den'' = step4 a0 den'

-- | Function for frequency prewarping

prewarp :: Double -- ^ w_c
        -> Double -- ^ T_s
        -> Double -- ^ W_c

prewarp wc ts = 2/ts * tan (wc / 2)

{-

-- Test, section 6.5.1 from Lyon's book

num1 = [ 17410.145 ]
den1 = [ 17410.145, 137.94536, 1 ]

(num1',den1') = bilinear 0.01 (num1,den1)

-- Test, from O&S, p 421

num2 = [ 0.202238 ]
den2 = polymult (polymult [ 0.5871, 0.3996, 1 ] [ 0.5871, 1.0836, 1 ] ) [ 0.5871, 1.4802, 1 ]

(num2',den2') = bilinear 1 (num2,den2)

bilinear ([0, 0, 0, 0, 1], reverse [ 1, 158881.5000000000000000000000, 6734684542.320000000000000000, 33433292062222.63200000000000, 26749649944094120.95199999999, 5301498365227355432.219999999, 308666240537082938598.7999999 ]) 48000

> num3 = [ 0, 0, 0, 0, 72687672654.5 ]
> den3 = reverse [ 1, 158881.5000000000000000000000, 6734684542.320000000000000000, 33433292062222.63200000000000, 26749649944094120.95199999999, 5301498365227355432.219999999, 308666240537082938598.7999999 ]

num31 = [ 0.0, 519.2365 ]
den31 = polypow [ 129.4, 1.0 ] 2

num32 = [ 0.0, 519.2365 ]
den32 = [ 676.7, 1.0 ]

num33 = [ 0.0, 519.2365 ]
den33 = [ 4636.0, 1.0 ]

num34 = [ 0.0, 519.2365 ]
den34 = polypow [ 76655.0, 1.0 ] 2

-}