aboutsummaryrefslogtreecommitdiffstats
path: root/apps
diff options
context:
space:
mode:
authorDimitri Stolnikov <horiz0n@gmx.net>2013-12-28 00:56:11 +0100
committerDimitri Stolnikov <horiz0n@gmx.net>2013-12-28 00:56:11 +0100
commit15d3699d72df6a473ee0b4dc23fc1920a055e3fa (patch)
tree163d4dbb6e6d80ac09421e3a2173d4ad993bbfea /apps
parent18e11438a0918a602dbec5a2fc6b33f89698db5c (diff)
apps/osmocom_fft: gui to set DC offset / IQ imbalance correction mode
Diffstat (limited to 'apps')
-rwxr-xr-xapps/osmocom_fft272
1 files changed, 249 insertions, 23 deletions
diff --git a/apps/osmocom_fft b/apps/osmocom_fft
index 7a7168d..3847d1c 100755
--- a/apps/osmocom_fft
+++ b/apps/osmocom_fft
@@ -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'):