root / gr-qtgui / apps / qt_digital.py @ abb70ac7
History | View | Annotate | Download (9.5 kB)
| 1 | #!/usr/bin/env python
|
|---|---|
| 2 | #
|
| 3 | # Copyright 2011 Free Software Foundation, Inc.
|
| 4 | #
|
| 5 | # This file is part of GNU Radio
|
| 6 | #
|
| 7 | # GNU Radio is free software; you can redistribute it and/or modify
|
| 8 | # it under the terms of the GNU General Public License as published by
|
| 9 | # the Free Software Foundation; either version 3, or (at your option)
|
| 10 | # any later version.
|
| 11 | #
|
| 12 | # GNU Radio is distributed in the hope that it will be useful,
|
| 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| 15 | # GNU General Public License for more details.
|
| 16 | #
|
| 17 | # You should have received a copy of the GNU General Public License
|
| 18 | # along with GNU Radio; see the file COPYING. If not, write to
|
| 19 | # the Free Software Foundation, Inc., 51 Franklin Street,
|
| 20 | # Boston, MA 02110-1301, USA.
|
| 21 | #
|
| 22 | |
| 23 | from gnuradio import gr, blks2 |
| 24 | from gnuradio import eng_notation |
| 25 | import sys |
| 26 | |
| 27 | try:
|
| 28 | from gnuradio import qtgui |
| 29 | from PyQt4 import QtGui, QtCore |
| 30 | import sip |
| 31 | except ImportError: |
| 32 | print "Error: Program requires PyQt4 and gr-qtgui." |
| 33 | sys.exit(1)
|
| 34 | |
| 35 | try:
|
| 36 | import scipy |
| 37 | except ImportError: |
| 38 | print "Error: Program requires scipy (see: www.scipy.org)." |
| 39 | sys.exit(1)
|
| 40 | |
| 41 | try:
|
| 42 | from qt_digital_window import Ui_DigitalWindow |
| 43 | except ImportError: |
| 44 | print "Error: could not find qt_digital_window.py:" |
| 45 | print "\t\"Please run: pyuic4 qt_digital_window.ui -o qt_digital_window.py\"" |
| 46 | sys.exit(1)
|
| 47 | |
| 48 | class dialog_box(QtGui.QMainWindow): |
| 49 | def __init__(self, snkTx, snkRx, fg, parent=None): |
| 50 | QtGui.QWidget.__init__(self, parent)
|
| 51 | self.gui = Ui_DigitalWindow()
|
| 52 | self.gui.setupUi(self) |
| 53 | |
| 54 | self.fg = fg
|
| 55 | |
| 56 | self.set_sample_rate(self.fg.sample_rate()) |
| 57 | |
| 58 | self.set_snr(self.fg.snr()) |
| 59 | self.set_frequency(self.fg.frequency_offset()) |
| 60 | self.set_time_offset(self.fg.timing_offset()) |
| 61 | |
| 62 | self.set_gain_mu(self.fg.rx_gain_mu()) |
| 63 | self.set_alpha(self.fg.rx_alpha()) |
| 64 | |
| 65 | # Add the qtsnk widgets to the hlayout box
|
| 66 | self.gui.sinkLayout.addWidget(snkTx)
|
| 67 | self.gui.sinkLayout.addWidget(snkRx)
|
| 68 | |
| 69 | |
| 70 | # Connect up some signals
|
| 71 | self.connect(self.gui.pauseButton, QtCore.SIGNAL("clicked()"), |
| 72 | self.pauseFg)
|
| 73 | |
| 74 | self.connect(self.gui.sampleRateEdit, QtCore.SIGNAL("editingFinished()"), |
| 75 | self.sampleRateEditText)
|
| 76 | |
| 77 | self.connect(self.gui.snrEdit, QtCore.SIGNAL("editingFinished()"), |
| 78 | self.snrEditText)
|
| 79 | self.connect(self.gui.freqEdit, QtCore.SIGNAL("editingFinished()"), |
| 80 | self.freqEditText)
|
| 81 | self.connect(self.gui.timeEdit, QtCore.SIGNAL("editingFinished()"), |
| 82 | self.timeEditText)
|
| 83 | |
| 84 | self.connect(self.gui.gainMuEdit, QtCore.SIGNAL("editingFinished()"), |
| 85 | self.gainMuEditText)
|
| 86 | self.connect(self.gui.alphaEdit, QtCore.SIGNAL("editingFinished()"), |
| 87 | self.alphaEditText)
|
| 88 | |
| 89 | |
| 90 | def pauseFg(self): |
| 91 | if(self.gui.pauseButton.text() == "Pause"): |
| 92 | self.fg.stop()
|
| 93 | self.fg.wait()
|
| 94 | self.gui.pauseButton.setText("Unpause") |
| 95 | else:
|
| 96 | self.fg.start()
|
| 97 | self.gui.pauseButton.setText("Pause") |
| 98 | |
| 99 | # Accessor functions for Gui to manipulate system parameters
|
| 100 | def set_sample_rate(self, sr): |
| 101 | ssr = eng_notation.num_to_str(sr) |
| 102 | self.gui.sampleRateEdit.setText(QtCore.QString("%1").arg(ssr)) |
| 103 | |
| 104 | def sampleRateEditText(self): |
| 105 | try:
|
| 106 | rate = self.gui.sampleRateEdit.text().toAscii()
|
| 107 | srate = eng_notation.str_to_num(rate) |
| 108 | self.fg.set_sample_rate(srate)
|
| 109 | except RuntimeError: |
| 110 | pass
|
| 111 | |
| 112 | |
| 113 | # Accessor functions for Gui to manipulate channel model
|
| 114 | def set_snr(self, snr): |
| 115 | self.gui.snrEdit.setText(QtCore.QString("%1").arg(snr)) |
| 116 | |
| 117 | def set_frequency(self, fo): |
| 118 | self.gui.freqEdit.setText(QtCore.QString("%1").arg(fo)) |
| 119 | |
| 120 | def set_time_offset(self, to): |
| 121 | self.gui.timeEdit.setText(QtCore.QString("%1").arg(to)) |
| 122 | |
| 123 | def snrEditText(self): |
| 124 | try:
|
| 125 | snr = self.gui.snrEdit.text().toDouble()[0] |
| 126 | self.fg.set_snr(snr)
|
| 127 | except RuntimeError: |
| 128 | pass
|
| 129 | |
| 130 | def freqEditText(self): |
| 131 | try:
|
| 132 | freq = self.gui.freqEdit.text().toDouble()[0] |
| 133 | self.fg.set_frequency_offset(freq)
|
| 134 | except RuntimeError: |
| 135 | pass
|
| 136 | |
| 137 | def timeEditText(self): |
| 138 | try:
|
| 139 | to = self.gui.timeEdit.text().toDouble()[0] |
| 140 | self.fg.set_timing_offset(to)
|
| 141 | except RuntimeError: |
| 142 | pass
|
| 143 | |
| 144 | |
| 145 | # Accessor functions for Gui to manipulate receiver parameters
|
| 146 | def set_gain_mu(self, gain): |
| 147 | self.gui.gainMuEdit.setText(QtCore.QString("%1").arg(gain)) |
| 148 | |
| 149 | def set_alpha(self, alpha): |
| 150 | self.gui.alphaEdit.setText(QtCore.QString("%1").arg(alpha)) |
| 151 | |
| 152 | def alphaEditText(self): |
| 153 | try:
|
| 154 | alpha = self.gui.alphaEdit.text().toDouble()[0] |
| 155 | self.fg.set_rx_alpha(alpha)
|
| 156 | except RuntimeError: |
| 157 | pass
|
| 158 | |
| 159 | def gainMuEditText(self): |
| 160 | try:
|
| 161 | gain = self.gui.gainMuEdit.text().toDouble()[0] |
| 162 | self.fg.set_rx_gain_mu(gain)
|
| 163 | except RuntimeError: |
| 164 | pass
|
| 165 | |
| 166 | |
| 167 | class my_top_block(gr.top_block): |
| 168 | def __init__(self): |
| 169 | gr.top_block.__init__(self)
|
| 170 | |
| 171 | self.qapp = QtGui.QApplication(sys.argv)
|
| 172 | |
| 173 | self._sample_rate = 2000e3 |
| 174 | |
| 175 | self.sps = 2 |
| 176 | self.excess_bw = 0.35 |
| 177 | self.gray_code = True |
| 178 | |
| 179 | fftsize = 2048
|
| 180 | |
| 181 | self.data = scipy.random.randint(0, 255, 1000) |
| 182 | self.src = gr.vector_source_b(self.data.tolist(), True) |
| 183 | self.mod = blks2.dqpsk_mod(self.sps, self.excess_bw, self.gray_code, False, False) |
| 184 | |
| 185 | self.rrctaps = gr.firdes.root_raised_cosine(1, self.sps, 1, self.excess_bw, 21) |
| 186 | self.rx_rrc = gr.fir_filter_ccf(1, self.rrctaps) |
| 187 | |
| 188 | |
| 189 | # Set up the carrier & clock recovery parameters
|
| 190 | self.arity = 4 |
| 191 | self.mu = 0.5 |
| 192 | self.gain_mu = 0.05 |
| 193 | self.omega = self.sps |
| 194 | self.gain_omega = .25 * self.gain_mu * self.gain_mu |
| 195 | self.omega_rel_lim = 0.05 |
| 196 | |
| 197 | self.alpha = 0.15 |
| 198 | self.beta = 0.25 * self.alpha * self.alpha |
| 199 | self.fmin = -1000/self.sample_rate() |
| 200 | self.fmax = 1000/self.sample_rate() |
| 201 | |
| 202 | self.receiver = gr.mpsk_receiver_cc(self.arity, 0, |
| 203 | self.alpha, self.beta, |
| 204 | self.fmin, self.fmax, |
| 205 | self.mu, self.gain_mu, |
| 206 | self.omega, self.gain_omega, |
| 207 | self.omega_rel_lim)
|
| 208 | |
| 209 | |
| 210 | self.snr_dB = 15 |
| 211 | noise = self.get_noise_voltage(self.snr_dB) |
| 212 | self.fo = 100/self.sample_rate() |
| 213 | self.to = 1.0 |
| 214 | self.channel = gr.channel_model(noise, self.fo, self.to) |
| 215 | |
| 216 | self.thr = gr.throttle(gr.sizeof_char, self._sample_rate) |
| 217 | self.snk_tx = qtgui.sink_c(fftsize, gr.firdes.WIN_BLACKMAN_hARRIS,
|
| 218 | 0, self._sample_rate*self.sps, |
| 219 | "Tx", True, True, True, True) |
| 220 | |
| 221 | self.snk_rx = qtgui.sink_c(fftsize, gr.firdes.WIN_BLACKMAN_hARRIS,
|
| 222 | 0, self._sample_rate, |
| 223 | "Rx", True, True, True, True) |
| 224 | |
| 225 | self.connect(self.src, self.thr, self.mod, self.channel, self.snk_tx) |
| 226 | self.connect(self.channel, self.rx_rrc, self.receiver, self.snk_rx) |
| 227 | |
| 228 | pyTxQt = self.snk_tx.pyqwidget()
|
| 229 | pyTx = sip.wrapinstance(pyTxQt, QtGui.QWidget) |
| 230 | |
| 231 | pyRxQt = self.snk_rx.pyqwidget()
|
| 232 | pyRx = sip.wrapinstance(pyRxQt, QtGui.QWidget) |
| 233 | |
| 234 | self.main_box = dialog_box(pyTx, pyRx, self); |
| 235 | self.main_box.show()
|
| 236 | |
| 237 | |
| 238 | def get_noise_voltage(self, SNR): |
| 239 | S = 0 # dBm, assuming signal power normalized |
| 240 | N = S - SNR # dBm
|
| 241 | npwr = pow(10.0, N/10.0) # ratio |
| 242 | nv = scipy.sqrt(npwr * self.sps) # convert the noise voltage |
| 243 | return nv
|
| 244 | |
| 245 | |
| 246 | # System Parameters
|
| 247 | def sample_rate(self): |
| 248 | return self._sample_rate |
| 249 | |
| 250 | def set_sample_rate(self, sr): |
| 251 | self._sample_rate = sr
|
| 252 | |
| 253 | |
| 254 | # Channel Model Parameters
|
| 255 | def snr(self): |
| 256 | return self.snr_dB |
| 257 | |
| 258 | def set_snr(self, snr): |
| 259 | self.snr_dB = snr
|
| 260 | noise = self.get_noise_voltage(self.snr_dB) |
| 261 | self.channel.set_noise_voltage(noise)
|
| 262 | |
| 263 | def frequency_offset(self): |
| 264 | return self.fo * self.sample_rate() |
| 265 | |
| 266 | def set_frequency_offset(self, fo): |
| 267 | self.fo = fo / self.sample_rate() |
| 268 | self.channel.set_frequency_offset(self.fo) |
| 269 | |
| 270 | def timing_offset(self): |
| 271 | return self.to |
| 272 | |
| 273 | def set_timing_offset(self, to): |
| 274 | self.to = to
|
| 275 | self.channel.set_timing_offset(self.to) |
| 276 | |
| 277 | |
| 278 | # Receiver Parameters
|
| 279 | def rx_gain_mu(self): |
| 280 | return self.gain_mu |
| 281 | |
| 282 | def rx_gain_omega(self): |
| 283 | return self.gain_omega |
| 284 | |
| 285 | def set_rx_gain_mu(self, gain): |
| 286 | self.gain_mu = gain
|
| 287 | self.gain_omega = .25 * self.gain_mu * self.gain_mu |
| 288 | self.receiver.set_gain_mu(self.gain_mu) |
| 289 | self.receiver.set_gain_omega(self.gain_omega) |
| 290 | |
| 291 | def rx_alpha(self): |
| 292 | return self.alpha |
| 293 | |
| 294 | def rx_beta(self): |
| 295 | return self.beta |
| 296 | |
| 297 | def set_rx_alpha(self, alpha): |
| 298 | self.alpha = alpha
|
| 299 | self.beta = .25 * self.alpha * self.alpha |
| 300 | self.receiver.set_alpha(self.alpha) |
| 301 | self.receiver.set_beta(self.beta) |
| 302 | |
| 303 | |
| 304 | if __name__ == "__main__": |
| 305 | tb = my_top_block(); |
| 306 | tb.start() |
| 307 | tb.qapp.exec_() |
| 308 | tb.stop() |