|
|
|
@ -66,10 +66,14 @@ class app_top_block(stdgui2.std_top_block, pubsub): |
|
|
|
|
help="Set sample rate (bandwidth), minimum by default") |
|
|
|
|
parser.add_option("-f", "--center-freq", type="eng_float", default=None, |
|
|
|
|
help="Set frequency to FREQ", metavar="FREQ") |
|
|
|
|
parser.add_option("-c", "--freq-corr", type="eng_float", default=0, |
|
|
|
|
parser.add_option("-c", "--freq-corr", type="eng_float", default=None, |
|
|
|
|
help="Set frequency correction (ppm)") |
|
|
|
|
parser.add_option("-g", "--gain", type="eng_float", default=None, |
|
|
|
|
help="Set gain in dB (default is midpoint)") |
|
|
|
|
parser.add_option("", "--dc-offset-mode", type="int", default=None, |
|
|
|
|
help="Set the RX frontend DC offset correction mode") |
|
|
|
|
parser.add_option("", "--iq-balance-mode", type="int", default=None, |
|
|
|
|
help="Set the RX frontend IQ imbalance correction mode") |
|
|
|
|
parser.add_option("-W", "--waterfall", action="store_true", default=False, |
|
|
|
|
help="Enable waterfall display") |
|
|
|
|
parser.add_option("-F", "--fosphor", action="store_true", default=False, |
|
|
|
@ -78,7 +82,7 @@ class app_top_block(stdgui2.std_top_block, pubsub): |
|
|
|
|
help="Enable oscilloscope display") |
|
|
|
|
parser.add_option("", "--avg-alpha", type="eng_float", default=1e-1, |
|
|
|
|
help="Set fftsink averaging factor, default=[%default]") |
|
|
|
|
parser.add_option ("", "--averaging", action="store_true", default=False, |
|
|
|
|
parser.add_option("", "--averaging", action="store_true", default=False, |
|
|
|
|
help="Enable fftsink averaging, default=[%default]") |
|
|
|
|
parser.add_option("", "--ref-scale", type="eng_float", default=1.0, |
|
|
|
|
help="Set dBFS=0dB input value, default=[%default]") |
|
|
|
@ -158,6 +162,15 @@ class app_top_block(stdgui2.std_top_block, pubsub): |
|
|
|
|
self[CENTER_FREQ_KEY] = options.center_freq |
|
|
|
|
self[FREQ_CORR_KEY] = options.freq_corr |
|
|
|
|
|
|
|
|
|
self.dc_offset_mode = options.dc_offset_mode |
|
|
|
|
self.iq_balance_mode = options.iq_balance_mode |
|
|
|
|
|
|
|
|
|
# initialize reasonable defaults for DC / IQ correction |
|
|
|
|
self['dc_offset_real'] = 0 |
|
|
|
|
self['dc_offset_imag'] = 0 |
|
|
|
|
self['iq_balance_mag'] = 0 |
|
|
|
|
self['iq_balance_pha'] = 0 |
|
|
|
|
|
|
|
|
|
#subscribe set methods |
|
|
|
|
self.subscribe(SAMP_RATE_KEY, self.set_sample_rate) |
|
|
|
|
|
|
|
|
@ -168,6 +181,11 @@ class app_top_block(stdgui2.std_top_block, pubsub): |
|
|
|
|
self.subscribe(CENTER_FREQ_KEY, self.set_freq) |
|
|
|
|
self.subscribe(FREQ_CORR_KEY, self.set_freq_corr) |
|
|
|
|
|
|
|
|
|
self.subscribe('dc_offset_real', self.set_dc_offset) |
|
|
|
|
self.subscribe('dc_offset_imag', self.set_dc_offset) |
|
|
|
|
self.subscribe('iq_balance_mag', self.set_iq_balance) |
|
|
|
|
self.subscribe('iq_balance_pha', self.set_iq_balance) |
|
|
|
|
|
|
|
|
|
#force update on pubsub keys |
|
|
|
|
#for key in (SAMP_RATE_KEY, BWIDTH_KEY, CENTER_FREQ_KEY, FREQ_CORR_KEY): |
|
|
|
|
#print key, "=", self[key] |
|
|
|
@ -209,6 +227,12 @@ class app_top_block(stdgui2.std_top_block, pubsub): |
|
|
|
|
|
|
|
|
|
self._build_gui(vbox) |
|
|
|
|
|
|
|
|
|
if self.dc_offset_mode != None: |
|
|
|
|
self.set_dc_offset_mode(self.dc_offset_mode) |
|
|
|
|
|
|
|
|
|
if self.iq_balance_mode != None: |
|
|
|
|
self.set_iq_balance_mode(self.iq_balance_mode) |
|
|
|
|
|
|
|
|
|
# set initial values |
|
|
|
|
if not(self.set_freq(options.center_freq)): |
|
|
|
|
self._set_status_msg("Failed to set initial frequency") |
|
|
|
@ -276,28 +300,30 @@ class app_top_block(stdgui2.std_top_block, pubsub): |
|
|
|
|
except AssertionError: |
|
|
|
|
pass |
|
|
|
|
|
|
|
|
|
corr_hbox.AddSpacer(3) |
|
|
|
|
forms.text_box( |
|
|
|
|
parent=self.panel, sizer=corr_hbox, |
|
|
|
|
label='Freq. Correction (ppm)', |
|
|
|
|
proportion=1, |
|
|
|
|
converter=forms.float_converter(), |
|
|
|
|
ps=self, |
|
|
|
|
key=FREQ_CORR_KEY, |
|
|
|
|
) |
|
|
|
|
corr_hbox.AddSpacer(5) |
|
|
|
|
if self[FREQ_CORR_KEY] != None: # show frequency correction scrollbar |
|
|
|
|
|
|
|
|
|
forms.slider( |
|
|
|
|
parent=self.panel, sizer=corr_hbox, |
|
|
|
|
proportion=3, |
|
|
|
|
ps=self, |
|
|
|
|
key=FREQ_CORR_KEY, |
|
|
|
|
minimum=-100, |
|
|
|
|
maximum=+100, |
|
|
|
|
num_steps=2010, |
|
|
|
|
step_size=0.1, |
|
|
|
|
) |
|
|
|
|
corr_hbox.AddSpacer(3) |
|
|
|
|
corr_hbox.AddSpacer(3) |
|
|
|
|
forms.text_box( |
|
|
|
|
parent=self.panel, sizer=corr_hbox, |
|
|
|
|
label='Freq. Correction (ppm)', |
|
|
|
|
proportion=1, |
|
|
|
|
converter=forms.float_converter(), |
|
|
|
|
ps=self, |
|
|
|
|
key=FREQ_CORR_KEY, |
|
|
|
|
) |
|
|
|
|
corr_hbox.AddSpacer(5) |
|
|
|
|
|
|
|
|
|
forms.slider( |
|
|
|
|
parent=self.panel, sizer=corr_hbox, |
|
|
|
|
proportion=3, |
|
|
|
|
ps=self, |
|
|
|
|
key=FREQ_CORR_KEY, |
|
|
|
|
minimum=-100, |
|
|
|
|
maximum=+100, |
|
|
|
|
num_steps=2010, |
|
|
|
|
step_size=0.1, |
|
|
|
|
) |
|
|
|
|
corr_hbox.AddSpacer(3) |
|
|
|
|
|
|
|
|
|
################################################## |
|
|
|
|
# Gain controls |
|
|
|
@ -427,6 +453,206 @@ class app_top_block(stdgui2.std_top_block, pubsub): |
|
|
|
|
#) |
|
|
|
|
#sr_hbox.AddSpacer(3) |
|
|
|
|
|
|
|
|
|
################################################## |
|
|
|
|
# DC Offset controls |
|
|
|
|
################################################## |
|
|
|
|
|
|
|
|
|
if self.dc_offset_mode != None: |
|
|
|
|
|
|
|
|
|
dc_offset_vbox = forms.static_box_sizer(parent=self.panel, |
|
|
|
|
label="DC Offset Correction", |
|
|
|
|
orient=wx.VERTICAL, |
|
|
|
|
bold=True) |
|
|
|
|
dc_offset_vbox.AddSpacer(3) |
|
|
|
|
# First row of sample rate controls |
|
|
|
|
dc_offset_hbox = wx.BoxSizer(wx.HORIZONTAL) |
|
|
|
|
dc_offset_vbox.Add(dc_offset_hbox, 0, wx.EXPAND) |
|
|
|
|
dc_offset_vbox.AddSpacer(3) |
|
|
|
|
|
|
|
|
|
# Add frequency controls to top window sizer |
|
|
|
|
vbox.Add(dc_offset_vbox, 0, wx.EXPAND) |
|
|
|
|
vbox.AddSpacer(3) |
|
|
|
|
|
|
|
|
|
self.dc_offset_mode_chooser = forms.radio_buttons( |
|
|
|
|
parent=self.panel, |
|
|
|
|
value=self.dc_offset_mode, |
|
|
|
|
callback=self.set_dc_offset_mode, |
|
|
|
|
label='', |
|
|
|
|
choices=[0, 1, 2], |
|
|
|
|
labels=["Off", "Manual", "Auto"], |
|
|
|
|
style=wx.RA_HORIZONTAL, |
|
|
|
|
) |
|
|
|
|
dc_offset_hbox.Add(self.dc_offset_mode_chooser) |
|
|
|
|
dc_offset_hbox.AddSpacer(3) |
|
|
|
|
|
|
|
|
|
dc_offset_hbox.AddSpacer(3) |
|
|
|
|
self.dc_offset_real_text = forms.text_box( |
|
|
|
|
parent=self.panel, sizer=dc_offset_hbox, |
|
|
|
|
label='Real', |
|
|
|
|
proportion=1, |
|
|
|
|
converter=forms.float_converter(), |
|
|
|
|
ps=self, |
|
|
|
|
key='dc_offset_real', |
|
|
|
|
) |
|
|
|
|
dc_offset_hbox.AddSpacer(3) |
|
|
|
|
|
|
|
|
|
self.dc_offset_real_slider = forms.slider( |
|
|
|
|
parent=self.panel, sizer=dc_offset_hbox, |
|
|
|
|
proportion=3, |
|
|
|
|
minimum=-1, |
|
|
|
|
maximum=+1, |
|
|
|
|
step_size=0.001, |
|
|
|
|
ps=self, |
|
|
|
|
key='dc_offset_real', |
|
|
|
|
) |
|
|
|
|
dc_offset_hbox.AddSpacer(3) |
|
|
|
|
|
|
|
|
|
dc_offset_hbox.AddSpacer(3) |
|
|
|
|
self.dc_offset_imag_text = forms.text_box( |
|
|
|
|
parent=self.panel, sizer=dc_offset_hbox, |
|
|
|
|
label='Imag', |
|
|
|
|
proportion=1, |
|
|
|
|
converter=forms.float_converter(), |
|
|
|
|
ps=self, |
|
|
|
|
key='dc_offset_imag', |
|
|
|
|
) |
|
|
|
|
dc_offset_hbox.AddSpacer(3) |
|
|
|
|
|
|
|
|
|
self.dc_offset_imag_slider = forms.slider( |
|
|
|
|
parent=self.panel, sizer=dc_offset_hbox, |
|
|
|
|
proportion=3, |
|
|
|
|
minimum=-1, |
|
|
|
|
maximum=+1, |
|
|
|
|
step_size=0.001, |
|
|
|
|
ps=self, |
|
|
|
|
key='dc_offset_imag', |
|
|
|
|
) |
|
|
|
|
dc_offset_hbox.AddSpacer(3) |
|
|
|
|
|
|
|
|
|
################################################## |
|
|
|
|
# IQ Imbalance controls |
|
|
|
|
################################################## |
|
|
|
|
|
|
|
|
|
if self.iq_balance_mode != None: |
|
|
|
|
|
|
|
|
|
iq_balance_vbox = forms.static_box_sizer(parent=self.panel, |
|
|
|
|
label="IQ Imbalance Correction", |
|
|
|
|
orient=wx.VERTICAL, |
|
|
|
|
bold=True) |
|
|
|
|
iq_balance_vbox.AddSpacer(3) |
|
|
|
|
# First row of sample rate controls |
|
|
|
|
iq_balance_hbox = wx.BoxSizer(wx.HORIZONTAL) |
|
|
|
|
iq_balance_vbox.Add(iq_balance_hbox, 0, wx.EXPAND) |
|
|
|
|
iq_balance_vbox.AddSpacer(3) |
|
|
|
|
|
|
|
|
|
# Add frequency controls to top window sizer |
|
|
|
|
vbox.Add(iq_balance_vbox, 0, wx.EXPAND) |
|
|
|
|
vbox.AddSpacer(3) |
|
|
|
|
|
|
|
|
|
self.iq_balance_mode_chooser = forms.radio_buttons( |
|
|
|
|
parent=self.panel, |
|
|
|
|
value=self.iq_balance_mode, |
|
|
|
|
callback=self.set_iq_balance_mode, |
|
|
|
|
label='', |
|
|
|
|
choices=[0, 1, 2], |
|
|
|
|
labels=["Off", "Manual", "Auto"], |
|
|
|
|
style=wx.RA_HORIZONTAL, |
|
|
|
|
) |
|
|
|
|
iq_balance_hbox.Add(self.iq_balance_mode_chooser) |
|
|
|
|
iq_balance_hbox.AddSpacer(3) |
|
|
|
|
|
|
|
|
|
iq_balance_hbox.AddSpacer(3) |
|
|
|
|
self.iq_balance_mag_text = forms.text_box( |
|
|
|
|
parent=self.panel, sizer=iq_balance_hbox, |
|
|
|
|
label='Mag', |
|
|
|
|
proportion=1, |
|
|
|
|
converter=forms.float_converter(), |
|
|
|
|
ps=self, |
|
|
|
|
key='iq_balance_mag', |
|
|
|
|
) |
|
|
|
|
iq_balance_hbox.AddSpacer(3) |
|
|
|
|
|
|
|
|
|
self.iq_balance_mag_slider = forms.slider( |
|
|
|
|
parent=self.panel, sizer=iq_balance_hbox, |
|
|
|
|
proportion=3, |
|
|
|
|
minimum=-1, |
|
|
|
|
maximum=+1, |
|
|
|
|
step_size=0.001, |
|
|
|
|
ps=self, |
|
|
|
|
key='iq_balance_mag', |
|
|
|
|
) |
|
|
|
|
iq_balance_hbox.AddSpacer(3) |
|
|
|
|
|
|
|
|
|
iq_balance_hbox.AddSpacer(3) |
|
|
|
|
self.iq_balance_pha_text = forms.text_box( |
|
|
|
|
parent=self.panel, sizer=iq_balance_hbox, |
|
|
|
|
label='Phase', |
|
|
|
|
proportion=1, |
|
|
|
|
converter=forms.float_converter(), |
|
|
|
|
ps=self, |
|
|
|
|
key='iq_balance_pha', |
|
|
|
|
) |
|
|
|
|
iq_balance_hbox.AddSpacer(3) |
|
|
|
|
|
|
|
|
|
self.iq_balance_pha_slider = forms.slider( |
|
|
|
|
parent=self.panel, sizer=iq_balance_hbox, |
|
|
|
|
proportion=3, |
|
|
|
|
minimum=-1, |
|
|
|
|
maximum=+1, |
|
|
|
|
step_size=0.001, |
|
|
|
|
ps=self, |
|
|
|
|
key='iq_balance_pha', |
|
|
|
|
) |
|
|
|
|
iq_balance_hbox.AddSpacer(3) |
|
|
|
|
|
|
|
|
|
def set_dc_offset_mode(self, dc_offset_mode): |
|
|
|
|
if dc_offset_mode == 1: |
|
|
|
|
self.dc_offset_real_text.Enable() |
|
|
|
|
self.dc_offset_real_slider.Enable() |
|
|
|
|
self.dc_offset_imag_text.Enable() |
|
|
|
|
self.dc_offset_imag_slider.Enable() |
|
|
|
|
|
|
|
|
|
self.set_dc_offset(0) |
|
|
|
|
else: |
|
|
|
|
self.dc_offset_real_text.Disable() |
|
|
|
|
self.dc_offset_real_slider.Disable() |
|
|
|
|
self.dc_offset_imag_text.Disable() |
|
|
|
|
self.dc_offset_imag_slider.Disable() |
|
|
|
|
|
|
|
|
|
self.dc_offset_mode = dc_offset_mode |
|
|
|
|
self.src.set_dc_offset_mode(dc_offset_mode) |
|
|
|
|
self.dc_offset_mode_chooser.set_value(self.dc_offset_mode) |
|
|
|
|
|
|
|
|
|
def set_dc_offset(self, value): |
|
|
|
|
correction = complex( self['dc_offset_real'], self['dc_offset_imag'] ) |
|
|
|
|
if self._verbose: |
|
|
|
|
print "Set DC offset to", correction |
|
|
|
|
self.src.set_dc_offset( correction ) |
|
|
|
|
|
|
|
|
|
def set_iq_balance_mode(self, iq_balance_mode): |
|
|
|
|
if iq_balance_mode == 1: |
|
|
|
|
self.iq_balance_mag_text.Enable() |
|
|
|
|
self.iq_balance_mag_slider.Enable() |
|
|
|
|
self.iq_balance_pha_text.Enable() |
|
|
|
|
self.iq_balance_pha_slider.Enable() |
|
|
|
|
|
|
|
|
|
self.set_iq_balance(0) |
|
|
|
|
else: |
|
|
|
|
self.iq_balance_mag_text.Disable() |
|
|
|
|
self.iq_balance_mag_slider.Disable() |
|
|
|
|
self.iq_balance_pha_text.Disable() |
|
|
|
|
self.iq_balance_pha_slider.Disable() |
|
|
|
|
|
|
|
|
|
self.iq_balance_mode = iq_balance_mode |
|
|
|
|
self.src.set_iq_balance_mode(iq_balance_mode) |
|
|
|
|
self.iq_balance_mode_chooser.set_value(self.iq_balance_mode) |
|
|
|
|
|
|
|
|
|
def set_iq_balance(self, value): |
|
|
|
|
correction = complex( self['iq_balance_mag'], self['iq_balance_pha'] ) |
|
|
|
|
if self._verbose: |
|
|
|
|
print "Set IQ balance to", correction |
|
|
|
|
self.src.set_iq_balance( correction ) |
|
|
|
|
|
|
|
|
|
def set_sample_rate(self, samp_rate): |
|
|
|
|
samp_rate = self.src.set_sample_rate(samp_rate) |
|
|
|
|
if hasattr(self.scope, 'set_sample_rate'): |
|
|
|
|