-
-
Notifications
You must be signed in to change notification settings - Fork 37
Expand file tree
/
Copy pathfilters.py
More file actions
204 lines (150 loc) · 5.81 KB
/
filters.py
File metadata and controls
204 lines (150 loc) · 5.81 KB
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
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
#########################################################################################
##
## FILTERS (filters.py)
##
#########################################################################################
# IMPORTS ===============================================================================
import numpy as np
from scipy.signal import butter, tf2ss
from math import factorial
from .lti import StateSpace
from ..utils.register import Register
from ..utils.mutable import mutable
# FILTER BLOCKS =========================================================================
@mutable
class ButterworthLowpassFilter(StateSpace):
"""Direct implementation of a low pass butterworth filter block.
Follows the same structure as the 'StateSpace' block in the
'pathsim.blocks' module. The numerator and denominator of the
filter transfer function are generated and then the transfer
function is realized as a state space model.
Parameters
----------
Fc : float
corner frequency of the filter in [Hz]
n : int
filter order
"""
input_port_labels = {"in":0}
output_port_labels = {"out":0}
def __init__(self, Fc=100, n=2):
#filter parameters
self.Fc = Fc
self.n = n
#use scipy.signal for filter design for unit frequency
num, den = butter(n, 1.0, btype="low", analog=True, output="ba")
A, B, C, D = tf2ss(num, den)
#rescale to actual bandwidth and make statespace model
omega_c = 2*np.pi*self.Fc
super().__init__(omega_c*A, omega_c*B, C, D)
@mutable
class ButterworthHighpassFilter(StateSpace):
"""Direct implementation of a high pass butterworth filter block.
Follows the same structure as the 'StateSpace' block in the
'pathsim.blocks' module. The numerator and denominator of the
filter transfer function are generated and then the transfer
function is realized as a state space model.
Parameters
----------
Fc : float
corner frequency of the filter in [Hz]
n : int
filter order
"""
input_port_labels = {"in":0}
output_port_labels = {"out":0}
def __init__(self, Fc=100, n=2):
#filter parameters
self.Fc = Fc
self.n = n
#use scipy.signal for filter design for unit frequency
num, den = butter(n, 1.0, btype="high", analog=True, output="ba")
A, B, C, D = tf2ss(num, den)
#rescale to actual bandwidth and make statespace model
omega_c = 2*np.pi*self.Fc
super().__init__(omega_c*A, omega_c*B, C, D)
@mutable
class ButterworthBandpassFilter(StateSpace):
"""Direct implementation of a bandpass butterworth filter block.
Follows the same structure as the 'StateSpace' block in the
'pathsim.blocks' module. The numerator and denominator of the
filter transfer function are generated and then the transfer
function is realized as a state space model.
Parameters
----------
Fc : list[float]
corner frequencies (left, right) of the filter in [Hz]
n : int
filter order
"""
input_port_labels = {"in":0}
output_port_labels = {"out":0}
def __init__(self, Fc=[50, 100], n=2):
#filter parameters
self.Fc = np.asarray(Fc)
self.n = n
if len(Fc) != 2:
raise ValueError("'ButterworthBandpassFilter' requires two corner frequencies!")
#use scipy.signal for filter design
num, den = butter(n, 2*np.pi*self.Fc, btype="bandpass", analog=True, output="ba")
#initialize parent block
super().__init__(*tf2ss(num, den))
@mutable
class ButterworthBandstopFilter(StateSpace):
"""Direct implementation of a bandstop butterworth filter block.
Follows the same structure as the 'StateSpace' block in the
'pathsim.blocks' module. The numerator and denominator of the
filter transfer function are generated and then the transfer
function is realized as a state space model.
Parameters
----------
Fc : tuple[float], list[float]
corner frequencies (left, right) of the filter in [Hz]
n : int
filter order
"""
input_port_labels = {"in":0}
output_port_labels = {"out":0}
def __init__(self, Fc=[50, 100], n=2):
#filter parameters
self.Fc = np.asarray(Fc)
self.n = n
if len(Fc) != 2:
raise ValueError("'ButterworthBandstopFilter' requires two corner frequencies!")
#use scipy.signal for filter design
num, den = butter(n, 2*np.pi*self.Fc, btype="bandstop", analog=True, output="ba")
#initialize parent block
super().__init__(*tf2ss(num, den))
@mutable
class AllpassFilter(StateSpace):
"""Direct implementation of a first order allpass filter, or a cascade
of n 1st order allpass filters
.. math::
H(s) = \\frac{s - 2\\pi f_s}{s + 2\\pi f_s}
where f_s is the frequency, where the 1st order allpass has a 90 deg phase shift.
Parameters
----------
fs : float
frequency for 90 deg phase shift of 1st order allpass
n : int
number of cascades
"""
input_port_labels = {"in":0}
output_port_labels = {"out":0}
def __init__(self, fs=100, n=1):
#filter parameters
self.fs = fs
self.n = n
#1st order allpass for numerator and denominator (normalized frequency)
num = [-1, 1]
den = [1, 1]
#higher order by convolution
for _ in range(1, self.n):
num = np.convolve(num, [-1, 1])
den = np.convolve(den, [1, 1])
#create statespace model
A, B, C, D = tf2ss(num, den)
#rescale to actual frequency and make statespace model
omega_s = 2*np.pi*fs
#initialize parent block
super().__init__(omega_s*A, omega_s*B, C, D)