apps/osmocom_fft: gui to set DC offset / IQ imbalance correction mode

This commit is contained in:
Dimitri Stolnikov 2013-12-28 00:56:11 +01:00
parent 18e11438a0
commit 15d3699d72
1 changed files with 249 additions and 23 deletions

View File

@ -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'):