]> git.gag.com Git - debian/gnuradio/blobdiff - gr-qtgui/src/python/qt_digital.py
Improving digital GUI analysis tool. Adding receiver carrier and timing recovery...
[debian/gnuradio] / gr-qtgui / src / python / qt_digital.py
index ead540c514d5763283dc888828baec68d0671eec..33c3794ed13cfc0a2c3a5639aabec2086d8fc2eb 100755 (executable)
@@ -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();