From 0055921e21259ea96b05e7456304731ea05c6a45 Mon Sep 17 00:00:00 2001 From: trondeau Date: Sun, 26 Apr 2009 21:09:20 +0000 Subject: Improving digital GUI analysis tool. Adding receiver carrier and timing recovery loop and ability to control the some of the receiver's parameters. git-svn-id: http://gnuradio.org/svn/gnuradio/trunk@10919 221aa14e-8319-0410-a670-987f0aec2ac5 --- gr-qtgui/src/python/qt_digital.py | 218 +++++++++++++++++----- gr-qtgui/src/python/qt_digital_window.ui | 307 +++++++++++++++++++++---------- 2 files changed, 384 insertions(+), 141 deletions(-) (limited to 'gr-qtgui/src/python') diff --git a/gr-qtgui/src/python/qt_digital.py b/gr-qtgui/src/python/qt_digital.py index ead540c51..33c3794ed 100755 --- a/gr-qtgui/src/python/qt_digital.py +++ b/gr-qtgui/src/python/qt_digital.py @@ -2,6 +2,7 @@ from gnuradio import gr, blks2 from gnuradio.qtgui import qtgui +from gnuradio import eng_notation from PyQt4 import QtGui, QtCore import sys, sip import scipy @@ -14,61 +15,107 @@ except ImportError: sys.exit(1) class dialog_box(QtGui.QMainWindow): - def __init__(self, snkTx, snkRx, channel, parent=None): + def __init__(self, snkTx, snkRx, fg, parent=None): QtGui.QWidget.__init__(self, parent) self.gui = Ui_DigitalWindow() self.gui.setupUi(self) - self.channel = channel + self.fg = fg + + self.set_sample_rate(self.fg.sample_rate()) + + self.set_snr(self.fg.snr()) + self.set_frequency(self.fg.frequency_offset()) + self.set_time_offset(self.fg.timing_offset()) + + self.set_gain_mu(self.fg.rx_gain_mu()) + self.set_alpha(self.fg.rx_alpha()) # Add the qtsnk widgets to the hlayout box self.gui.sinkLayout.addWidget(snkTx) self.gui.sinkLayout.addWidget(snkRx) # Connect up some signals - self.connect(self.gui.noiseEdit, QtCore.SIGNAL("editingFinished()"), - self.noiseEditText) + self.connect(self.gui.sampleRateEdit, QtCore.SIGNAL("editingFinished()"), + self.sampleRateEditText) + + self.connect(self.gui.snrEdit, QtCore.SIGNAL("editingFinished()"), + self.snrEditText) self.connect(self.gui.freqEdit, QtCore.SIGNAL("editingFinished()"), self.freqEditText) self.connect(self.gui.timeEdit, QtCore.SIGNAL("editingFinished()"), self.timeEditText) - - def set_noise(self, noise): - self.noise = noise - self.gui.noiseEdit.setText(QtCore.QString("%1").arg(self.noise)) - def set_frequency(self, freq): - self.freq = freq - self.gui.freqEdit.setText(QtCore.QString("%1").arg(self.freq)) + self.connect(self.gui.gainMuEdit, QtCore.SIGNAL("editingFinished()"), + self.gainMuEditText) + self.connect(self.gui.alphaEdit, QtCore.SIGNAL("editingFinished()"), + self.alphaEditText) - def set_time_offset(self, to): - self.timing_offset = to - self.gui.timeEdit.setText(QtCore.QString("%1").arg(self.timing_offset)) - def noiseEditText(self): + # Accessor functions for Gui to manipulate system parameters + def set_sample_rate(self, sr): + ssr = eng_notation.num_to_str(sr) + self.gui.sampleRateEdit.setText(QtCore.QString("%1").arg(ssr)) + + def sampleRateEditText(self): try: - noise = self.gui.noiseEdit.text().toDouble()[0] - self.channel.set_noise_voltage(noise) + rate = self.gui.sampleRateEdit.text().toAscii() + srate = eng_notation.str_to_num(rate) + self.fg.set_sample_rate(srate) + except RuntimeError: + pass + - self.noise = noise + # Accessor functions for Gui to manipulate channel model + def set_snr(self, snr): + self.gui.snrEdit.setText(QtCore.QString("%1").arg(snr)) + + def set_frequency(self, fo): + self.gui.freqEdit.setText(QtCore.QString("%1").arg(fo)) + + def set_time_offset(self, to): + self.gui.timeEdit.setText(QtCore.QString("%1").arg(to)) + + def snrEditText(self): + try: + snr = self.gui.snrEdit.text().toDouble()[0] + self.fg.set_snr(snr) except RuntimeError: pass def freqEditText(self): try: freq = self.gui.freqEdit.text().toDouble()[0] - self.channel.set_frequency_offset(freq) - - self.freq = freq + self.fg.set_frequency_offset(freq) except RuntimeError: pass def timeEditText(self): try: to = self.gui.timeEdit.text().toDouble()[0] - self.channel.set_timing_offset(to) + self.fg.set_timing_offset(to) + except RuntimeError: + pass + + + # Accessor functions for Gui to manipulate receiver parameters + def set_gain_mu(self, gain): + self.gui.gainMuEdit.setText(QtCore.QString("%1").arg(gain)) + + def set_alpha(self, alpha): + self.gui.alphaEdit.setText(QtCore.QString("%1").arg(alpha)) + + def alphaEditText(self): + try: + alpha = self.gui.alphaEdit.text().toDouble()[0] + self.fg.set_rx_alpha(alpha) + except RuntimeError: + pass - self.timing_offset = to + def gainMuEditText(self): + try: + gain = self.gui.gainMuEdit.text().toDouble()[0] + self.fg.set_rx_gain_mu(gain) except RuntimeError: pass @@ -79,33 +126,58 @@ class my_top_block(gr.top_block): self.qapp = QtGui.QApplication(sys.argv) - sps = 2 - excess_bw = 0.35 - gray_code = True + self._sample_rate = 200e3 + + self.sps = 2 + self.excess_bw = 0.35 + self.gray_code = True fftsize = 2048 - data = scipy.random.randint(0, 255, 1000) - src = gr.vector_source_b(data, True) - mod = blks2.dqpsk_mod(sps, excess_bw, gray_code, False, False) + self.data = scipy.random.randint(0, 255, 1000) + self.src = gr.vector_source_b(self.data, True) + self.mod = blks2.dqpsk_mod(self.sps, self.excess_bw, self.gray_code, False, False) - rrctaps = gr.firdes.root_raised_cosine(1, sps, 1, excess_bw, 21) - rx_rrc = gr.fir_filter_ccf(sps, rrctaps) + self.rrctaps = gr.firdes.root_raised_cosine(1, self.sps, 1, self.excess_bw, 21) + self.rx_rrc = gr.fir_filter_ccf(1, self.rrctaps) - noise = 1e-7 - fo = 1e-6 - to = 1.0 - channel = gr.channel_model(noise, fo, to) - thr = gr.throttle(gr.sizeof_gr_complex, 10*fftsize) + # Set up the carrier & clock recovery parameters + self.arity = 4 + self.mu = 0.5 + self.gain_mu = 0.05 + self.omega = self.sps + self.gain_omega = .25 * self.gain_mu * self.gain_mu + self.omega_rel_lim = 0.05 + + self.alpha = 0.15 + self.beta = 0.25 * self.alpha * self.alpha + self.fmin = -1000/self.sample_rate() + self.fmax = 1000/self.sample_rate() + + self.receiver = gr.mpsk_receiver_cc(self.arity, 0, + self.alpha, self.beta, + self.fmin, self.fmax, + self.mu, self.gain_mu, + self.omega, self.gain_omega, + self.omega_rel_lim) + + + self.snr_dB = 15 + noise = self.get_noise_voltage(self.snr_dB) + self.fo = 100/self.sample_rate() + self.to = 1.0 + self.channel = gr.channel_model(noise, self.fo, self.to) + + self.thr = gr.throttle(gr.sizeof_char, 10*fftsize) self.snk_tx = qtgui.sink_c(fftsize, gr.firdes.WIN_BLACKMAN_hARRIS, -1/2, 1/2, "Tx", True, True, False, True, True) self.snk_rx = qtgui.sink_c(fftsize, gr.firdes.WIN_BLACKMAN_hARRIS, -1/2, 1/2, "Rx", True, True, False, True, True) - self.connect(src, mod, channel, self.snk_tx) - self.connect(channel, rx_rrc, thr, self.snk_rx) + self.connect(self.src, self.thr, self.mod, self.channel, self.snk_tx) + self.connect(self.channel, self.rx_rrc, self.receiver, self.snk_rx) pyTxQt = self.snk_tx.pyqwidget() pyTx = sip.wrapinstance(pyTxQt, QtGui.QWidget) @@ -113,13 +185,75 @@ class my_top_block(gr.top_block): pyRxQt = self.snk_rx.pyqwidget() pyRx = sip.wrapinstance(pyRxQt, QtGui.QWidget) - self.main_box = dialog_box(pyTx, pyRx, channel); - self.main_box.set_noise(noise) - self.main_box.set_frequency(fo) - self.main_box.set_time_offset(to) + self.main_box = dialog_box(pyTx, pyRx, self); self.main_box.show() + def get_noise_voltage(self, SNR): + S = 0 # dBm, assuming signal power normalized + N = S - SNR # dBm + npwr = pow(10.0, N/10.0) # ratio + nv = scipy.sqrt(npwr * self.sps) # convert the noise voltage + return nv + + + # System Parameters + def sample_rate(self): + return self._sample_rate + + def set_sample_rate(self, sr): + self._sample_rate = sr + + + # Channel Model Parameters + def snr(self): + return self.snr_dB + + def set_snr(self, snr): + self.snr_dB = snr + noise = self.get_noise_voltage(self.snr_dB) + self.channel.set_noise_voltage(noise) + + def frequency_offset(self): + return self.fo * self.sample_rate() + + def set_frequency_offset(self, fo): + self.fo = fo / self.sample_rate() + self.channel.set_frequency_offset(self.fo) + + def timing_offset(self): + return self.to + + def set_timing_offset(self, to): + self.to = to + self.channel.set_timing_offset(self.to) + + + # Receiver Parameters + def rx_gain_mu(self): + return self.gain_mu + + def rx_gain_omega(self): + return self.gain_omega + + def set_rx_gain_mu(self, gain): + self.gain_mu = gain + self.gain_omega = .25 * self.gain_mu * self.gain_mu + self.receiver.set_gain_mu(self.gain_mu) + self.receiver.set_gain_omega(self.gain_omega) + + def rx_alpha(self): + return self.alpha + + def rx_beta(self): + return self.beta + + def set_rx_alpha(self, alpha): + self.alpha = alpha + self.beta = .25 * self.alpha * self.alpha + self.receiver.set_alpha(self.alpha) + self.receiver.set_beta(self.beta) + if __name__ == "__main__": tb = my_top_block(); diff --git a/gr-qtgui/src/python/qt_digital_window.ui b/gr-qtgui/src/python/qt_digital_window.ui index 67b7bbe92..27764e5f2 100644 --- a/gr-qtgui/src/python/qt_digital_window.ui +++ b/gr-qtgui/src/python/qt_digital_window.ui @@ -1,155 +1,264 @@ - + + DigitalWindow - - + + 0 0 1236 - 655 + 739 - + MainWindow - - - + + + - 120 - 520 - 113 - 23 - - - - - - - 10 - 520 - 111 - 20 - - - - Noise Amplitude - - - - - - 260 - 580 - 80 - 27 + 1120 + 650 + 101 + 31 - + Close - - + + - 120 - 550 - 113 - 23 + 10 + 10 + 1221 + 501 - - - - - 120 - 580 - 113 - 23 - + + QFrame::StyledPanel + + + QFrame::Raised + + + + 10 + 10 + 1201 + 481 + + + + - - + + - 10 - 550 - 101 - 17 + 290 + 520 + 291 + 161 - - Frequency Offset + + Channel Model Parameters + + + + 10 + 90 + 101 + 17 + + + + Timing Offset + + + + + + 160 + 90 + 113 + 23 + + + + + + + 160 + 30 + 113 + 23 + + + + + + + 10 + 30 + 111 + 20 + + + + SNR (dB) + + + + + + 160 + 60 + 113 + 23 + + + + + + + 10 + 60 + 141 + 17 + + + + Frequency Offset (Hz) + + - - + + - 10 - 580 - 101 - 17 + 590 + 520 + 251 + 161 - - Timing Offset + + Receiver Parameters + + + + 120 + 30 + 113 + 23 + + + + + + + 10 + 30 + 111 + 20 + + + + Gain mu + + + + + + 120 + 60 + 113 + 23 + + + + + + + 10 + 60 + 111 + 20 + + + + Alpha + + - - + + - 10 - 10 - 1221 - 501 + 20 + 520 + 261 + 161 - - QFrame::StyledPanel - - - QFrame::Raised + + System Parameters - - + + + + 140 + 30 + 113 + 23 + + + + + 10 - 10 - 1201 - 481 + 30 + 121 + 20 - + + Sample Rate (sps) + - - + + 0 0 1236 - 22 + 25 - - + + &File - + - + - - - + + + E&xit closeButton - noiseEdit + snrEdit freqEdit timeEdit @@ -161,11 +270,11 @@ DigitalWindow close() - + 322 623 - + 66 561 @@ -177,11 +286,11 @@ DigitalWindow close() - + -1 -1 - + 617 327 -- cgit