dsp-0.2: DSP/Filter/IIR/Prony.hs
-----------------------------------------------------------------------------
-- |
-- Module : DSP.Filter.IIR.Prony
-- Copyright : (c) Matthew Donadio 2003
-- License : GPL
--
-- Maintainer : m.p.donadio@ieee.org
-- Stability : experimental
-- Portability : portable
--
-- General case of Prony's Method where K > p+q
--
-- References: L&I, Sect 8.1; P&B, Sect 7.5; P&M, Sect 8.5.2
--
-- Notation follows L&I
--
-----------------------------------------------------------------------------
-- TODO: Handle rank deficiencies of G3 gracefully. Can/should we
-- generate a (K/2+1) by (K/2+1) G2, and set p=q=rank(G2)? Need SVD to
-- compute rank, though.
module DSP.Filter.IIR.Prony (prony) where
import Data.Array
import Matrix.Matrix
import Matrix.LU
{------------------------------------------------------------------------------
Case 1: K=p+q
a = array (0,p)
b = array (0,q)
g1 : q+1 by p+1
g2 : p by p+1
g3 : p by p
We do not define G1 and G2, but
mg2 = array ((1,1),(p,p+1)) [ ((i,j), g!(p+i+1-j)) | j <- [1..p+1], i <- [1..p] ]
prony p q g = (a,b)
where mg3 = array ((1,1),(p,p)) [ ((i,j), g!(p+i-j)) | j <- [1..p], i <- [1..p] ]
g1 = array (1,p) [ (i, g!(p+i)) | i <- [1..p] ]
a' = solve mg3 (fmap negate g1)
a = array (0,p) $ (0,1) : [ (i,a'!i) | i <- [1..p] ]
b = listArray (0,q) [ sum [ a!j * g!(i-j) | j <- [0..(min i p)] ] | i <- [0..q] ]
Test case, pg 422
g = listArray (0,6) [ 1, 18, 9, 2, 1, 2/9, 1/9 ] :: Array Int Double
------------------------------------------------------------------------------}
-- Case 2: K>p+q
-- a = array (0,p)
-- b = array (0,q)
-- g1 : q+1 by p+1
-- g2 : K-q by p+1
-- g3 : K-q by p
-- We need gi for the q<p cases because these generate zero elements in
-- G3, and this is the easiest way to take care of that.
-- mg1 = array ((1,1),(q+1,p+1)) [ ((i,j), gi (i-j)) | j <- [1..p+1], i <- [1..q+1] ]
-- mg2 = array ((1,1),(k-q,p+1)) [ ((i,j), gi (q+i-j+1)) | j <- [1..p+1], i <- [1..k-q] ]
-- | Implementation of Prony's method
prony :: Int -- ^ p
-> Int -- ^ q
-> Array Int Double -- ^ g[n]
-> (Array Int Double, Array Int Double) -- ^ (b,a)
prony p q g = (b,a)
where k = snd $ bounds g
gi i | i < 0 = 0
| i > k = 0
| otherwise = g!i
mg3 = array ((1,1),(k-q,p)) [ ((i,j), gi (q+i-j)) | j <- [1..p], i <- [1..k-q] ]
g1 = array (1,k-q) [ (i, gi (q+i)) | i <- [1..k-q] ]
a' = solve (mm_mult (m_trans mg3) mg3) (fmap negate (mv_mult (m_trans mg3) g1))
a = array (0,p) $ (0,1) : [ (i,a'!i) | i <- [1..p] ]
b = listArray (0,q) [ sum [ a!j * gi (i-j) | j <- [0..(min i p)] ] | i <- [0..q] ]