Adding a graphical tool to design and analyze filters.
[debian/gnuradio] / gr-utils / src / python / gr_filter_design.py
1 #!/usr/bin/env python
2
3 try:
4     import scipy
5     from scipy import fftpack
6 except ImportError:
7     print "Please install SciPy to run this script (http://www.scipy.org/)"
8     raise SystemExit, 1
9
10 import sys, os
11 from PyQt4 import Qt, QtCore, QtGui
12 import PyQt4.Qwt5 as Qwt
13 from optparse import OptionParser
14 from gnuradio import gr, eng_notation
15 from scipy import fftpack
16
17 from pyqt_filter import Ui_MainWindow
18 from pyqt_filter_firlpf import Ui_firlpfForm
19 from pyqt_filter_firhpf import Ui_firhpfForm
20
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)
26
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)
33
34         self.connect(self.gui.designButton,
35                      Qt.SIGNAL("released()"),
36                      self.design)
37         
38         self.fltdeslpf = Ui_firlpfForm()
39         self.fltdeshpf = Ui_firhpfForm()
40
41         self.fltdeslpf.setupUi(self.gui.firlpfPage)
42         self.fltdeshpf.setupUi(self.gui.firhpfPage)
43
44         # Initialize to LPF
45         self.gui.filterTypeWidget.setCurrentWidget(self.gui.firlpfPage)
46
47         # Set up plot curves
48         self.rcurve = Qwt.QwtPlotCurve("Real")
49         self.rcurve.attach(self.gui.timePlot)
50
51         self.freqcurve = Qwt.QwtPlotCurve("PSD")
52         self.freqcurve.attach(self.gui.freqPlot)
53
54         # Create zoom functionality for the plots
55         self.timeZoomer = Qwt.QwtPlotZoomer(self.gui.timePlot.xBottom,
56                                             self.gui.timePlot.yLeft,
57                                             Qwt.QwtPicker.PointSelection,
58                                             Qwt.QwtPicker.AlwaysOn,
59                                             self.gui.timePlot.canvas())
60
61         self.freqZoomer = Qwt.QwtPlotZoomer(self.gui.freqPlot.xBottom,
62                                             self.gui.freqPlot.yLeft,
63                                             Qwt.QwtPicker.PointSelection,
64                                             Qwt.QwtPicker.AlwaysOn,
65                                             self.gui.freqPlot.canvas())
66
67         # Set up pen for colors and line width
68         blue = QtGui.qRgb(0x00, 0x00, 0xFF)
69         blueBrush = Qt.QBrush(Qt.QColor(blue))
70         self.freqcurve.setPen(Qt.QPen(blueBrush, 2))
71         self.rcurve.setPen(Qt.QPen(blueBrush, 2))
72
73         self.show()
74
75     def changed_filter_type(self, ftype):
76         strftype = str(ftype.toAscii())
77         if(ftype == "Low Pass"):
78             self.gui.filterTypeWidget.setCurrentWidget(self.gui.firlpfPage)
79         elif(ftype == "High Pass"):
80             self.gui.filterTypeWidget.setCurrentWidget(self.gui.firhpfPage)
81         
82     def changed_filter_design_type(self, design):
83         print design
84
85     def design(self):
86         fs = self.gui.sampleRateEdit.text().toDouble()[0]
87         gain = self.gui.filterGainEdit.text().toDouble()[0]
88         
89         ftype = self.gui.filterTypeComboBox.currentText()
90         if(ftype == "Low Pass"):
91             taps = self.design_win_lpf(fs, gain)
92         elif(ftype == "High Pass"):
93             taps = self.design_win_hpf(fs, gain)
94
95         self.update_time_curves(taps)
96         self.update_freq_curves(taps)
97         
98     def design_win_lpf(self, fs, gain):
99         pb = self.fltdeslpf.endofPassBandEdit.text().toDouble()[0]
100         sb = self.fltdeslpf.startofStopBandEdit.text().toDouble()[0]
101         atten = self.fltdeslpf.stopBandAttenEdit.text().toDouble()[0]
102         tb = sb - pb
103
104         taps = gr.firdes.low_pass_2(gain, fs, pb, tb, atten,
105                                     gr.firdes.WIN_BLACKMAN_hARRIS)
106         return taps
107     
108     def design_win_hpf(self, fs, gain):
109         print fs
110         print widget
111
112     def update_time_curves(self, taps):
113         ntaps = len(taps)
114         self.rcurve.setData(scipy.arange(ntaps), taps)
115
116         # Reset the x-axis to the new time scale
117         ymax = 1.5 * max(taps)
118         ymin = 1.5 * min(taps)
119         self.gui.timePlot.setAxisScale(self.gui.timePlot.xBottom,
120                                        0, ntaps)
121         self.gui.timePlot.setAxisScale(self.gui.timePlot.yLeft,
122                                        ymin, ymax)
123
124         # Set the zoomer base to unzoom to the new axis
125         self.timeZoomer.setZoomBase()
126     
127         self.gui.timePlot.replot()
128         
129     def update_freq_curves(self, taps, Npts=1000):
130         fftpts = fftpack.fft(taps, Npts)
131         freq = scipy.arange(0, Npts)
132
133         fftdB = 20.0*scipy.log10(abs(fftpts))
134         
135         self.freqcurve.setData(freq, fftdB)
136
137         self.gui.freqPlot.setAxisScale(self.gui.freqPlot.xBottom,
138                                        0, Npts/2)
139
140         # Set the zoomer base to unzoom to the new axis
141         self.freqZoomer.setZoomBase()
142
143         self.gui.freqPlot.replot()
144
145
146 def setup_options():
147     usage="%prog: [options] (input_filename)"
148     description = ""
149
150     parser = OptionParser(conflict_handler="resolve",
151                           usage=usage, description=description)
152     return parser
153
154 def main(args):
155     parser = setup_options()
156     (options, args) = parser.parse_args ()
157
158     app = Qt.QApplication(args)
159     gplt = gr_plot_filter(app, options)
160     app.exec_()
161
162 if __name__ == '__main__':
163     main(sys.argv)
164