5 from scipy import fftpack
7 print "Please install SciPy to run this script (http://www.scipy.org/)"
11 from PyQt4 import Qt, QtCore, QtGui
12 import PyQt4.Qwt5 as Qwt
13 from optparse import OptionParser
14 from gnuradio import gr, blks2, eng_notation
15 from scipy import fftpack
17 from pyqt_filter import Ui_MainWindow
18 from pyqt_filter_firlpf import Ui_firlpfForm
19 from pyqt_filter_firhpf import Ui_firhpfForm
21 class gr_plot_filter(QtGui.QMainWindow):
22 def __init__(self, qapp, options):
23 QtGui.QWidget.__init__(self, None)
24 self.gui = Ui_MainWindow()
25 self.gui.setupUi(self)
27 self.connect(self.gui.filterTypeComboBox,
28 Qt.SIGNAL("currentIndexChanged(const QString&)"),
29 self.changed_filter_type)
30 self.connect(self.gui.filterDesignTypeComboBox,
31 Qt.SIGNAL("currentIndexChanged(const QString&)"),
32 self.changed_filter_design_type)
34 self.connect(self.gui.designButton,
35 Qt.SIGNAL("released()"),
38 self.connect(self.gui.tabGroup,
39 Qt.SIGNAL("currentChanged(int)"),
42 self.connect(self.gui.nfftEdit,
43 Qt.SIGNAL("textEdited(QString)"),
44 self.nfft_edit_changed)
46 self.gui.designButton.setShortcut("Return")
49 self.nfftpts = int(10000)
50 self.gui.nfftEdit.setText(Qt.QString("%1").arg(self.nfftpts))
52 self.gui.lpfPassBandRippleLabel.setVisible(False)
53 self.gui.lpfPassBandRippleEdit.setVisible(False)
54 self.gui.bpfPassBandRippleLabel.setVisible(False)
55 self.gui.bpfPassBandRippleEdit.setVisible(False)
56 self.gui.hpfPassBandRippleLabel.setVisible(False)
57 self.gui.hpfPassBandRippleEdit.setVisible(False)
60 self.gui.filterTypeWidget.setCurrentWidget(self.gui.firlpfPage)
63 self.gui.freqPlot.setAxisTitle(self.gui.freqPlot.xBottom,
65 self.gui.freqPlot.setAxisTitle(self.gui.freqPlot.yLeft,
67 self.gui.timePlot.setAxisTitle(self.gui.timePlot.xBottom,
69 self.gui.timePlot.setAxisTitle(self.gui.timePlot.yLeft,
71 self.gui.phasePlot.setAxisTitle(self.gui.phasePlot.xBottom,
73 self.gui.phasePlot.setAxisTitle(self.gui.phasePlot.yLeft,
75 self.gui.groupPlot.setAxisTitle(self.gui.groupPlot.xBottom,
77 self.gui.groupPlot.setAxisTitle(self.gui.groupPlot.yLeft,
81 self.rcurve = Qwt.QwtPlotCurve("Real")
82 self.rcurve.attach(self.gui.timePlot)
84 self.freqcurve = Qwt.QwtPlotCurve("PSD")
85 self.freqcurve.attach(self.gui.freqPlot)
87 self.phasecurve = Qwt.QwtPlotCurve("Phase")
88 self.phasecurve.attach(self.gui.phasePlot)
90 self.groupcurve = Qwt.QwtPlotCurve("Group Delay")
91 self.groupcurve.attach(self.gui.groupPlot)
93 # Create zoom functionality for the plots
94 self.timeZoomer = Qwt.QwtPlotZoomer(self.gui.timePlot.xBottom,
95 self.gui.timePlot.yLeft,
96 Qwt.QwtPicker.PointSelection,
97 Qwt.QwtPicker.AlwaysOn,
98 self.gui.timePlot.canvas())
100 self.freqZoomer = Qwt.QwtPlotZoomer(self.gui.freqPlot.xBottom,
101 self.gui.freqPlot.yLeft,
102 Qwt.QwtPicker.PointSelection,
103 Qwt.QwtPicker.AlwaysOn,
104 self.gui.freqPlot.canvas())
106 self.phaseZoomer = Qwt.QwtPlotZoomer(self.gui.phasePlot.xBottom,
107 self.gui.phasePlot.yLeft,
108 Qwt.QwtPicker.PointSelection,
109 Qwt.QwtPicker.AlwaysOn,
110 self.gui.phasePlot.canvas())
112 self.groupZoomer = Qwt.QwtPlotZoomer(self.gui.groupPlot.xBottom,
113 self.gui.groupPlot.yLeft,
114 Qwt.QwtPicker.PointSelection,
115 Qwt.QwtPicker.AlwaysOn,
116 self.gui.groupPlot.canvas())
118 # Set up pen for colors and line width
119 blue = QtGui.qRgb(0x00, 0x00, 0xFF)
120 blueBrush = Qt.QBrush(Qt.QColor(blue))
121 self.freqcurve.setPen(Qt.QPen(blueBrush, 2))
122 self.rcurve.setPen(Qt.QPen(blueBrush, 2))
123 self.phasecurve.setPen(Qt.QPen(blueBrush, 2))
124 self.groupcurve.setPen(Qt.QPen(blueBrush, 2))
126 self.filterWindows = {"Hamming Window" : gr.firdes.WIN_HAMMING,
127 "Hann Window" : gr.firdes.WIN_HANN,
128 "Blackman Window" : gr.firdes.WIN_BLACKMAN,
129 "Rectangular Window" : gr.firdes.WIN_RECTANGULAR,
130 "Kaiser Window" : gr.firdes.WIN_KAISER,
131 "Blackman-harris Window" : gr.firdes.WIN_BLACKMAN_hARRIS}
135 def changed_filter_type(self, ftype):
136 strftype = str(ftype.toAscii())
137 if(ftype == "Low Pass"):
138 self.gui.filterTypeWidget.setCurrentWidget(self.gui.firlpfPage)
139 elif(ftype == "Band Pass"):
140 self.gui.filterTypeWidget.setCurrentWidget(self.gui.firbpfPage)
141 elif(ftype == "High Pass"):
142 self.gui.filterTypeWidget.setCurrentWidget(self.gui.firhpfPage)
146 def changed_filter_design_type(self, design):
147 if(design == "Equiripple"):
148 self.set_equiripple()
154 def set_equiripple(self):
155 self.equiripple = True
156 self.gui.lpfPassBandRippleLabel.setVisible(True)
157 self.gui.lpfPassBandRippleEdit.setVisible(True)
158 self.gui.bpfPassBandRippleLabel.setVisible(True)
159 self.gui.bpfPassBandRippleEdit.setVisible(True)
160 self.gui.hpfPassBandRippleLabel.setVisible(True)
161 self.gui.hpfPassBandRippleEdit.setVisible(True)
163 def set_windowed(self):
164 self.equiripple = False
165 self.gui.lpfPassBandRippleLabel.setVisible(False)
166 self.gui.lpfPassBandRippleEdit.setVisible(False)
167 self.gui.bpfPassBandRippleLabel.setVisible(False)
168 self.gui.bpfPassBandRippleEdit.setVisible(False)
169 self.gui.hpfPassBandRippleLabel.setVisible(False)
170 self.gui.hpfPassBandRippleEdit.setVisible(False)
174 fs,r = self.gui.sampleRateEdit.text().toDouble()
176 gain,r = self.gui.filterGainEdit.text().toDouble()
180 winstr = str(self.gui.filterDesignTypeComboBox.currentText().toAscii())
181 ftype = str(self.gui.filterTypeComboBox.currentText().toAscii())
183 if(winstr == "Equiripple"):
184 designer = {"Low Pass" : self.design_opt_lpf,
185 "Band Pass" : self.design_opt_bpf,
186 "High Pass" : self.design_opt_hpf}
187 taps,r = designer[ftype](fs, gain)
190 designer = {"Low Pass" : self.design_win_lpf,
191 "Band Pass" : self.design_win_bpf,
192 "High Pass" : self.design_win_hpf}
193 wintype = self.filterWindows[winstr]
194 self.taps,r = designer[ftype](fs, gain, wintype)
197 self.get_fft(self.taps, self.nfftpts)
198 self.update_time_curves()
199 self.update_freq_curves()
200 self.update_phase_curves()
203 # Filter design functions using a window
204 def design_win_lpf(self, fs, gain, wintype):
206 pb,r = self.gui.endofLpfPassBandEdit.text().toDouble()
208 sb,r = self.gui.startofLpfStopBandEdit.text().toDouble()
210 atten,r = self.gui.lpfStopBandAttenEdit.text().toDouble()
216 taps = gr.firdes.low_pass_2(gain, fs, pb, tb,
222 def design_win_bpf(self, fs, gain, wintype):
224 pb1,r = self.gui.startofBpfPassBandEdit.text().toDouble()
226 pb2,r = self.gui.endofBpfPassBandEdit.text().toDouble()
228 tb,r = self.gui.bpfTransitionEdit.text().toDouble()
230 atten,r = self.gui.bpfStopBandAttenEdit.text().toDouble()
234 taps = gr.firdes.band_pass_2(gain, fs, pb1, pb2, tb,
240 def design_win_hpf(self, fs, gain, wintype):
242 sb,r = self.gui.endofHpfStopBandEdit.text().toDouble()
244 pb,r = self.gui.startofHpfPassBandEdit.text().toDouble()
246 atten,r = self.gui.hpfStopBandAttenEdit.text().toDouble()
251 taps = gr.firdes.high_pass_2(gain, fs, pb, tb,
259 # Design Functions for Equiripple Filters
260 def design_opt_lpf(self, fs, gain, wintype=None):
262 pb,r = self.gui.endofLpfPassBandEdit.text().toDouble()
264 sb,r = self.gui.startofLpfStopBandEdit.text().toDouble()
266 atten,r = self.gui.lpfStopBandAttenEdit.text().toDouble()
268 ripple,r = self.gui.lpfPassBandRippleEdit.text().toDouble()
272 taps = blks2.optfir.low_pass(gain, fs, pb, sb,
278 def design_opt_bpf(self, fs, gain, wintype=None):
280 pb1,r = self.gui.startofBpfPassBandEdit.text().toDouble()
282 pb2,r = self.gui.endofBpfPassBandEdit.text().toDouble()
284 tb,r = self.gui.bpfTransitionEdit.text().toDouble()
286 atten,r = self.gui.bpfStopBandAttenEdit.text().toDouble()
288 ripple,r = self.gui.bpfPassBandRippleEdit.text().toDouble()
294 taps = blks2.optfir.band_pass(gain, fs, sb1, pb1, pb2, sb2,
300 def design_opt_hpf(self, fs, gain, wintype=None):
302 sb,r = self.gui.endofHpfStopBandEdit.text().toDouble()
304 pb,r = self.gui.startofHpfPassBandEdit.text().toDouble()
306 atten,r = self.gui.hpfStopBandAttenEdit.text().toDouble()
308 ripple,r = self.gui.hpfPassBandRippleEdit.text().toDouble()
312 taps = blks2.optfir.high_pass(gain, fs, sb, pb,
318 def nfft_edit_changed(self, nfft):
319 infft,r = nfft.toInt()
320 if(r and (infft != self.nfftpts)):
322 self.update_freq_curves()
324 def tab_changed(self, tab):
326 self.update_freq_curves()
328 self.update_time_curves()
330 self.update_phase_curves()
332 def get_fft(self, taps, Npts):
333 fftpts = fftpack.fft(taps, Npts)
334 self.freq = scipy.arange(0, Npts)
336 self.fftdB = 20.0*scipy.log10(abs(fftpts))
337 self.fftDeg = scipy.unwrap(scipy.angle(fftpts))
339 def update_time_curves(self):
340 ntaps = len(self.taps)
342 self.rcurve.setData(scipy.arange(ntaps), self.taps)
344 # Reset the x-axis to the new time scale
345 ymax = 1.5 * max(self.taps)
346 ymin = 1.5 * min(self.taps)
347 self.gui.timePlot.setAxisScale(self.gui.timePlot.xBottom,
349 self.gui.timePlot.setAxisScale(self.gui.timePlot.yLeft,
352 # Set the zoomer base to unzoom to the new axis
353 self.timeZoomer.setZoomBase()
355 self.gui.timePlot.replot()
357 def update_freq_curves(self):
358 npts = len(self.fftdB)
360 self.freqcurve.setData(self.freq, self.fftdB)
362 # Reset the x-axis to the new time scale
363 ymax = 1.5 * max(self.fftdB[0:npts/2])
364 ymin = 1.1 * min(self.fftdB[0:npts/2])
365 self.gui.freqPlot.setAxisScale(self.gui.freqPlot.xBottom,
367 self.gui.freqPlot.setAxisScale(self.gui.freqPlot.yLeft,
370 # Set the zoomer base to unzoom to the new axis
371 self.freqZoomer.setZoomBase()
373 self.gui.freqPlot.replot()
376 def update_phase_curves(self):
377 npts = len(self.fftDeg)
379 self.phasecurve.setData(self.freq, self.fftDeg)
381 # Reset the x-axis to the new time scale
382 ymax = 1.5 * max(self.fftDeg[0:npts/2])
383 ymin = 1.1 * min(self.fftDeg[0:npts/2])
384 self.gui.phasePlot.setAxisScale(self.gui.phasePlot.xBottom,
386 self.gui.phasePlot.setAxisScale(self.gui.phasePlot.yLeft,
389 # Set the zoomer base to unzoom to the new axis
390 self.phaseZoomer.setZoomBase()
392 self.gui.phasePlot.replot()
396 usage="%prog: [options] (input_filename)"
399 parser = OptionParser(conflict_handler="resolve",
400 usage=usage, description=description)
404 parser = setup_options()
405 (options, args) = parser.parse_args ()
407 app = Qt.QApplication(args)
408 gplt = gr_plot_filter(app, options)
411 if __name__ == '__main__':