-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathFilter.hs
120 lines (105 loc) · 4.35 KB
/
Filter.hs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE TypeOperators #-}
module Filter(
FIR(..)
, bode
, phasePlot
) where
import Signal
import Math.Polynomial
import Common
import Noise
import Fixed
import GHC.TypeLits
import SpecialInt
import Data.Bits
import Plot
import Data.Complex
import Text.Printf
import Debug.Trace
debug a = trace (show a) a
data FIR p i o where
FIR :: (SingI (nc + ni), SingI nc, SingI ni, SingI no, SingI s, SingI r, HasDoubleRepresentation (Fixed a nc s r), Num (Fixed ag (nc + ni) s r), Num (Fixed a nc s r), Eq a, Conversion ag ao, ConvertConstraint ag ao, AMulConstraint a ag)
=> Poly (Fixed a nc s r)
-> FIR ((Fixed ag (nc + ni) s r),(Fixed a nc s r)) (Fixed a ni s r) (Fixed ao no s r)
FIRD :: Poly Double
-> FIR Double Double Double
polyRepresentation :: FIR p i o -> Poly Double
polyRepresentation (FIRD p) = p
polyRepresentation (FIR f) = fmap toDouble f
instance Show p => Show (FIR p i o) where
show (FIR c) = show c
show (FIRD d) = show d
delay :: s -> Signal s -> Signal s
delay a s = consS a s
guardType :: FIR ((Fixed ag ng s r),(Fixed a nc s r)) i (Fixed ao no s r)
-> Fixed ag n s r
-> Fixed ag n s r
guardType _ = id
filterDWith :: [Double]
-> Signal Double
-> Signal Double
filterDWith (a:l) s | null l = mapS (a*) s
| otherwise = zipWithS (+) (mapS (a*) s) (filterDWith l (delay 0 s))
filterDWith [] s = s
_filterWith :: (AMulConstraint a ag, SingI (na + ni), SingI s, SingI r, SingI na, SingI ni, Num (Fixed a ni s r), Num (Fixed ag (na + ni) s r))
=> FIR ((Fixed ag ng s r),(Fixed a na s r)) (Fixed a ni s r) (Fixed ao no s r)
-> [Fixed a na s r]
-> Signal (Fixed a ni s r)
-> Signal (Fixed ag (na + ni) s r)
_filterWith f (a:l) s | null l = mapS (amul a) s
| otherwise = zipWithS (+) (mapS (amul a) s) (_filterWith f l (delay 0 s))
_filterWith _ [] s = error "Empty polynomial can't be used for filtering"
filterWith :: (Conversion ag ao, ConvertConstraint ag ao, Num (Fixed a ni s r), Num (Fixed ag (na + ni) s r), SingI r, SingI s, SingI (na + ni), SingI ni, SingI na, SingI no, AMulConstraint a ag)
=> FIR ((Fixed ag ng s r),(Fixed a na s r)) (Fixed a ni s r) (Fixed ao no s r)
-> [Fixed a na s r]
-> Signal (Fixed a ni s r)
-> Signal (Fixed ao no s r)
filterWith f l = mapS convert . _filterWith f l
instance Structure FIR where
doubleVersion (FIR p) = FIRD $ fmap toDouble p
transferFunction f@(FIR p) s =
let c = polyCoeffs LE $ p
in
filterWith f c s
transferFunction (FIRD p) s =
let c = polyCoeffs LE p
in
filterDWith c s
bode :: (Sample o,Sample i)
=> FIR p i o -> StyledSignal Double Double
bode f =
let fd = polyRepresentation f
log10 x = log x / log 10
polyF = evalPoly (fmap (:+ 0) fd)
transferFunction = \t -> 20 * log10 (magnitude . polyF . cis $ -t)
dw = 0.01
values = map transferFunction [0,dw..pi]
nb = length values
ticksWithPhase n = printf "%.2f pi" (n / fromIntegral nb :: Double)
in
(plotSpectrum nb [ AS $ fromListS 0 values])
`withNewStyle` (\s -> s { verticalLabel = Just "Filter Gain (dB)"
, title = Just "Bode Plot"
, horizontalTickRepresentation = ticksWithPhase
})
phasePlot :: (Sample o,Sample i)
=> FIR p i o -> StyledSignal Double Double
phasePlot f =
let fd = polyRepresentation f
log10 x = log x / log 10
polyF = evalPoly (fmap (:+ 0) fd)
transferFunction = \t -> phase . polyF . cis $ -t
dw = 0.01
values = map transferFunction [0,dw..pi]
nb = length values
ticksWithPhase n = printf "%.2f pi" (n / fromIntegral nb :: Double)
in
(plotSpectrum nb [ AS $ fromListS 0 values])
`withNewStyle` (\s -> s { verticalLabel = Just "Filter Phase"
, title = Just "Phase Plot"
, horizontalTickRepresentation = ticksWithPhase
})