forked from sdr/gr-osmosdr
apps/osmocom_fft: gui to set DC offset / IQ imbalance correction mode
This commit is contained in:
parent
3f281d9705
commit
f42fe3d065
230
apps/osmocom_fft
230
apps/osmocom_fft
|
@ -66,17 +66,21 @@ class app_top_block(stdgui2.std_top_block, pubsub):
|
||||||
help="Set sample rate (bandwidth), minimum by default")
|
help="Set sample rate (bandwidth), minimum by default")
|
||||||
parser.add_option("-f", "--center-freq", type="eng_float", default=None,
|
parser.add_option("-f", "--center-freq", type="eng_float", default=None,
|
||||||
help="Set frequency to FREQ", metavar="FREQ")
|
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)")
|
help="Set frequency correction (ppm)")
|
||||||
parser.add_option("-g", "--gain", type="eng_float", default=None,
|
parser.add_option("-g", "--gain", type="eng_float", default=None,
|
||||||
help="Set gain in dB (default is midpoint)")
|
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,
|
parser.add_option("-W", "--waterfall", action="store_true", default=False,
|
||||||
help="Enable waterfall display")
|
help="Enable waterfall display")
|
||||||
parser.add_option("-S", "--oscilloscope", action="store_true", default=False,
|
parser.add_option("-S", "--oscilloscope", action="store_true", default=False,
|
||||||
help="Enable oscilloscope display")
|
help="Enable oscilloscope display")
|
||||||
parser.add_option("", "--avg-alpha", type="eng_float", default=1e-1,
|
parser.add_option("", "--avg-alpha", type="eng_float", default=1e-1,
|
||||||
help="Set fftsink averaging factor, default=[%default]")
|
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]")
|
help="Enable fftsink averaging, default=[%default]")
|
||||||
parser.add_option("", "--ref-scale", type="eng_float", default=1.0,
|
parser.add_option("", "--ref-scale", type="eng_float", default=1.0,
|
||||||
help="Set dBFS=0dB input value, default=[%default]")
|
help="Set dBFS=0dB input value, default=[%default]")
|
||||||
|
@ -156,6 +160,15 @@ class app_top_block(stdgui2.std_top_block, pubsub):
|
||||||
self[CENTER_FREQ_KEY] = options.center_freq
|
self[CENTER_FREQ_KEY] = options.center_freq
|
||||||
self[FREQ_CORR_KEY] = options.freq_corr
|
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
|
#subscribe set methods
|
||||||
self.subscribe(SAMP_RATE_KEY, self.set_sample_rate)
|
self.subscribe(SAMP_RATE_KEY, self.set_sample_rate)
|
||||||
|
|
||||||
|
@ -166,6 +179,11 @@ class app_top_block(stdgui2.std_top_block, pubsub):
|
||||||
self.subscribe(CENTER_FREQ_KEY, self.set_freq)
|
self.subscribe(CENTER_FREQ_KEY, self.set_freq)
|
||||||
self.subscribe(FREQ_CORR_KEY, self.set_freq_corr)
|
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
|
#force update on pubsub keys
|
||||||
#for key in (SAMP_RATE_KEY, BWIDTH_KEY, CENTER_FREQ_KEY, FREQ_CORR_KEY):
|
#for key in (SAMP_RATE_KEY, BWIDTH_KEY, CENTER_FREQ_KEY, FREQ_CORR_KEY):
|
||||||
#print key, "=", self[key]
|
#print key, "=", self[key]
|
||||||
|
@ -202,6 +220,12 @@ class app_top_block(stdgui2.std_top_block, pubsub):
|
||||||
|
|
||||||
self._build_gui(vbox)
|
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
|
# set initial values
|
||||||
if not(self.set_freq(options.center_freq)):
|
if not(self.set_freq(options.center_freq)):
|
||||||
self._set_status_msg("Failed to set initial frequency")
|
self._set_status_msg("Failed to set initial frequency")
|
||||||
|
@ -269,6 +293,8 @@ class app_top_block(stdgui2.std_top_block, pubsub):
|
||||||
except AssertionError:
|
except AssertionError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
if self[FREQ_CORR_KEY] != None: # show frequency correction scrollbar
|
||||||
|
|
||||||
corr_hbox.AddSpacer(3)
|
corr_hbox.AddSpacer(3)
|
||||||
forms.text_box(
|
forms.text_box(
|
||||||
parent=self.panel, sizer=corr_hbox,
|
parent=self.panel, sizer=corr_hbox,
|
||||||
|
@ -423,6 +449,206 @@ class app_top_block(stdgui2.std_top_block, pubsub):
|
||||||
#)
|
#)
|
||||||
#sr_hbox.AddSpacer(3)
|
#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):
|
def set_sample_rate(self, samp_rate):
|
||||||
samp_rate = self.src.set_sample_rate(samp_rate)
|
samp_rate = self.src.set_sample_rate(samp_rate)
|
||||||
self.scope.set_sample_rate(samp_rate)
|
self.scope.set_sample_rate(samp_rate)
|
||||||
|
|
Loading…
Reference in New Issue