gr-osmosdr/apps/osmocom_fft

842 lines
31 KiB
Python
Executable File

#!/usr/bin/env python
#
# Copyright 2012 Free Software Foundation, Inc.
#
# This file is part of GNU Radio
#
# GNU Radio is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3, or (at your option)
# any later version.
#
# GNU Radio is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with GNU Radio; see the file COPYING. If not, write to
# the Free Software Foundation, Inc., 51 Franklin Street,
# Boston, MA 02110-1301, USA.
#
SAMP_RANGE_KEY = 'samp_range'
SAMP_RATE_KEY = 'samp_rate'
GAIN_KEY = lambda x: 'gain:'+x
BWIDTH_KEY = 'bwidth'
CENTER_FREQ_KEY = 'center_freq'
FREQ_CORR_KEY = 'freq_corr'
FREQ_RANGE_KEY = 'freq_range'
GAIN_RANGE_KEY = lambda x: 'gain_range:'+x
BWIDTH_RANGE_KEY = 'bwidth_range'
import osmosdr
from gnuradio import blocks
from gnuradio import gr, gru
from gnuradio import eng_notation
from gnuradio.gr.pubsub import pubsub
from gnuradio.eng_option import eng_option
from optparse import OptionParser
import sys
import numpy
import time
import datetime
try:
from gnuradio.wxgui import stdgui2, form, slider
from gnuradio.wxgui import forms
from gnuradio.wxgui import fftsink2, waterfallsink2, scopesink2
import wx
except ImportError:
sys.stderr.write("Error importing GNU Radio's wxgui. Please make sure gr-wxgui is installed.\n")
sys.exit(1)
class app_top_block(stdgui2.std_top_block, pubsub):
def __init__(self, frame, panel, vbox, argv):
stdgui2.std_top_block.__init__(self, frame, panel, vbox, argv)
pubsub.__init__(self)
self.frame = frame
self.panel = panel
parser = OptionParser(option_class=eng_option)
parser.add_option("-a", "--args", type="string", default="",
help="Device args, [default=%default]")
parser.add_option("-A", "--antenna", type="string", default=None,
help="Select RX antenna where appropriate")
parser.add_option("-s", "--samp-rate", type="eng_float", default=None,
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=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("-G", "--gains", type="string", default=None,
help="Set named gain in dB, name:gain,name:gain,...")
parser.add_option("-r", "--record", type="string", default="/tmp/name-f%F-s%S-t%T.cfile",
help="Filename to record to, available wildcards: %S: sample rate, %F: center frequency, %T: timestamp, Example: /tmp/name-f%F-s%S-t%T.cfile")
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,
help="Enable fosphor display")
parser.add_option("-S", "--oscilloscope", action="store_true", default=False,
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,
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]")
parser.add_option("", "--fft-size", type="int", default=1024,
help="Set number of FFT bins [default=%default]")
parser.add_option("", "--fft-rate", type="int", default=30,
help="Set FFT update rate, [default=%default]")
parser.add_option("-v", "--verbose", action="store_true", default=False,
help="Use verbose console output [default=%default]")
(options, args) = parser.parse_args()
if len(args) != 0:
parser.print_help()
sys.exit(1)
self.options = options
self._verbose = options.verbose
self.src = osmosdr.source(options.args)
try:
self.src.get_sample_rates().start()
except RuntimeError:
print "Source has no sample rates (wrong device arguments?)."
sys.exit(1)
# Set the antenna
if(options.antenna):
self.src.set_antenna(options.antenna)
if options.samp_rate is None:
options.samp_rate = self.src.get_sample_rates().start()
if options.gain is None:
gain = self.src.get_gain()
if gain is None:
# if no gain was specified, use the mid-point in dB
r = self.src.get_gain_range()
try: # empty gain range returned in file= mode
options.gain = float(r.start()+r.stop())/2
except RuntimeError:
options.gain = 0
pass
else:
options.gain = gain
self.src.set_gain(options.gain)
if self._verbose:
gain_names = self.src.get_gain_names()
for name in gain_names:
range = self.src.get_gain_range(name)
print "%s gain range: start %d stop %d step %d" % (name, range.start(), range.stop(), range.step())
if options.gains:
for tuple in options.gains.split(","):
name, gain = tuple.split(":")
gain = int(gain)
print "Setting gain %s to %d." % (name, gain)
self.src.set_gain(gain, name)
if self._verbose:
rates = self.src.get_sample_rates()
print 'Supported sample rates %d-%d step %d.' % (rates.start(), rates.stop(), rates.step())
if options.center_freq is None:
freq = self.src.get_center_freq()
if freq != 0:
options.center_freq = freq
else:
# if no freq was specified, use the mid-point in Hz
r = self.src.get_freq_range()
options.center_freq = float(r.start()+r.stop())/2
input_rate = self.src.set_sample_rate(options.samp_rate)
self.src.set_bandwidth(input_rate)
self.publish(SAMP_RANGE_KEY, self.src.get_sample_rates)
self.publish(FREQ_RANGE_KEY, self.src.get_freq_range)
for name in self.get_gain_names():
self.publish(GAIN_RANGE_KEY(name), (lambda self=self,name=name: self.src.get_gain_range(name)))
self.publish(BWIDTH_RANGE_KEY, self.src.get_bandwidth_range)
for name in self.get_gain_names():
self.publish(GAIN_KEY(name), (lambda self=self,name=name: self.src.get_gain(name)))
self.publish(BWIDTH_KEY, self.src.get_bandwidth)
# initialize values from options
self[SAMP_RANGE_KEY] = self.src.get_sample_rates()
self[SAMP_RATE_KEY] = options.samp_rate
self[CENTER_FREQ_KEY] = options.center_freq
self[FREQ_CORR_KEY] = options.freq_corr
self['record'] = options.record
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)
for name in self.get_gain_names():
self.subscribe(GAIN_KEY(name), (lambda gain,self=self,name=name: self.set_named_gain(gain, name)))
self.subscribe(BWIDTH_KEY, self.set_bandwidth)
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]
#self[key] = self[key]
if options.fosphor:
from gnuradio import fosphor
self.scope = fosphor.wx_sink_c(panel, size=(800,300))
self.scope.set_sample_rate(input_rate)
self.frame.SetMinSize((800,600))
elif options.waterfall:
self.scope = waterfallsink2.waterfall_sink_c (panel,
fft_size=options.fft_size,
sample_rate=input_rate,
ref_scale=options.ref_scale,
ref_level=20.0,
y_divs = 12)
self.scope.set_callback(self.wxsink_callback)
self.frame.SetMinSize((800, 420))
elif options.oscilloscope:
self.scope = scopesink2.scope_sink_c(panel, sample_rate=input_rate)
self.frame.SetMinSize((800, 600))
else:
self.scope = fftsink2.fft_sink_c (panel,
fft_size=options.fft_size,
sample_rate=input_rate,
ref_scale=options.ref_scale,
ref_level=20.0,
y_divs = 12,
average=options.averaging,
avg_alpha=options.avg_alpha,
fft_rate=options.fft_rate)
self.scope.set_callback(self.wxsink_callback)
self.frame.SetMinSize((800, 420))
self.connect(self.src, self.scope)
self.file_sink = blocks.file_sink(gr.sizeof_gr_complex, "/dev/null", False)
self.file_sink.set_unbuffered(False)
self.file_sink.close() # close the sink immediately
# lock/connect/unlock at record button event did not work, so we leave it connected at all times
self.connect(self.src, self.file_sink)
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")
def record_to_filename(self):
s = self['record']
s = s.replace('%S', '%e' % self.src.get_sample_rate())
s = s.replace('%F', '%e' % self.src.get_center_freq())
s = s.replace('%T', datetime.datetime.now().strftime('%Y%m%d%H%M%S'))
return s
def wxsink_callback(self, x, y):
self.set_freq_from_callback(x)
def _set_status_msg(self, msg):
self.frame.GetStatusBar().SetStatusText(msg, 0)
def _build_gui(self, vbox):
if hasattr(self.scope, 'win'):
vbox.Add(self.scope.win, 1, wx.EXPAND)
vbox.AddSpacer(3)
# add control area at the bottom
self.myform = myform = form.form()
##################################################
# Frequency controls
##################################################
fc_vbox = forms.static_box_sizer(parent=self.panel,
label="Center Frequency",
orient=wx.VERTICAL,
bold=True)
fc_vbox.AddSpacer(3)
# First row of frequency controls (center frequency)
freq_hbox = wx.BoxSizer(wx.HORIZONTAL)
fc_vbox.Add(freq_hbox, 0, wx.EXPAND)
fc_vbox.AddSpacer(5)
# Second row of frequency controls (freq. correction)
corr_hbox = wx.BoxSizer(wx.HORIZONTAL)
fc_vbox.Add(corr_hbox, 0, wx.EXPAND)
fc_vbox.AddSpacer(3)
# Add frequency controls to top window sizer
vbox.Add(fc_vbox, 0, wx.EXPAND)
vbox.AddSpacer(5)
freq_hbox.AddSpacer(3)
forms.text_box(
parent=self.panel, sizer=freq_hbox,
label='Center Frequency (Hz)',
proportion=1,
converter=forms.float_converter(),
ps=self,
key=CENTER_FREQ_KEY,
)
freq_hbox.AddSpacer(5)
try: # range.start() == range.stop() in file= mode
forms.slider(
parent=self.panel, sizer=freq_hbox,
proportion=3,
ps=self,
key=CENTER_FREQ_KEY,
minimum=self[FREQ_RANGE_KEY].start(),
maximum=self[FREQ_RANGE_KEY].stop(),
num_steps=1000,
)
freq_hbox.AddSpacer(3)
except AssertionError:
pass
if self[FREQ_CORR_KEY] != None: # show frequency correction scrollbar
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
##################################################
gc_vbox = forms.static_box_sizer(parent=self.panel,
label="Gain Settings",
orient=wx.VERTICAL,
bold=True)
gc_vbox.AddSpacer(3)
# Add gain controls to top window sizer
vbox.Add(gc_vbox, 0, wx.EXPAND)
vbox.AddSpacer(5)
for gain_name in self.get_gain_names():
range = self[GAIN_RANGE_KEY(gain_name)]
gain = self[GAIN_KEY(gain_name)]
#print gain_name, gain, range.to_pp_string()
if range.start() < range.stop():
gain_hbox = wx.BoxSizer(wx.HORIZONTAL)
gc_vbox.Add(gain_hbox, 0, wx.EXPAND)
gc_vbox.AddSpacer(3)
gain_hbox.AddSpacer(3)
forms.text_box(
parent=self.panel, sizer=gain_hbox,
proportion=1,
converter=forms.float_converter(),
ps=self,
key=GAIN_KEY(gain_name),
label=gain_name + " Gain (dB)",
)
gain_hbox.AddSpacer(5)
forms.slider(
parent=self.panel, sizer=gain_hbox,
proportion=3,
ps=self,
key=GAIN_KEY(gain_name),
minimum=range.start(),
maximum=range.stop(),
step_size=range.step() or (range.stop() - range.start())/10,
)
gain_hbox.AddSpacer(3)
##################################################
# Bandwidth controls
##################################################
try:
bw_range = self[BWIDTH_RANGE_KEY]
#print bw_range.to_pp_string()
if bw_range.start() < bw_range.stop():
bwidth_vbox = forms.static_box_sizer(parent=self.panel,
label="Bandwidth",
orient=wx.VERTICAL,
bold=True)
bwidth_vbox.AddSpacer(3)
bwidth_hbox = wx.BoxSizer(wx.HORIZONTAL)
bwidth_vbox.Add(bwidth_hbox, 0, wx.EXPAND)
bwidth_vbox.AddSpacer(3)
vbox.Add(bwidth_vbox, 0, wx.EXPAND)
vbox.AddSpacer(5)
bwidth_hbox.AddSpacer(3)
forms.text_box(
parent=self.panel, sizer=bwidth_hbox,
proportion=1,
converter=forms.float_converter(),
ps=self,
key=BWIDTH_KEY,
label="Bandwidth (Hz)",
)
bwidth_hbox.AddSpacer(5)
forms.slider(
parent=self.panel, sizer=bwidth_hbox,
proportion=3,
ps=self,
key=BWIDTH_KEY,
minimum=bw_range.start(),
maximum=bw_range.stop(),
step_size=bw_range.step() or (bw_range.stop() - bw_range.start())/100,
)
bwidth_hbox.AddSpacer(3)
except RuntimeError:
pass
##################################################
# Sample rate controls
##################################################
sr_vbox = forms.static_box_sizer(parent=self.panel,
label="Sample Rate",
orient=wx.VERTICAL,
bold=True)
sr_vbox.AddSpacer(3)
# First row of sample rate controls
sr_hbox = wx.BoxSizer(wx.HORIZONTAL)
sr_vbox.Add(sr_hbox, 0, wx.EXPAND)
sr_vbox.AddSpacer(5)
# Add sample rate controls to top window sizer
vbox.Add(sr_vbox, 0, wx.EXPAND)
vbox.AddSpacer(5)
sr_hbox.AddSpacer(3)
self.sample_rate_text = forms.text_box(
parent=self.panel, sizer=sr_hbox,
label='Sample Rate (Hz)',
proportion=1,
converter=forms.float_converter(),
ps=self,
key=SAMP_RATE_KEY,
)
sr_hbox.AddSpacer(5)
#forms.slider(
# parent=self.panel, sizer=sr_hbox,
# proportion=3,
# ps=self,
# key=SAMP_RATE_KEY,
# minimum=self[SAMP_RANGE_KEY].start(),
# maximum=self[SAMP_RANGE_KEY].stop(),
# step_size=self[SAMP_RANGE_KEY].step(),
#)
#sr_hbox.AddSpacer(3)
##################################################
# File recording controls
##################################################
rec_vbox = forms.static_box_sizer(parent=self.panel,
label="File recording",
orient=wx.VERTICAL,
bold=True)
rec_vbox.AddSpacer(3)
# First row of sample rate controls
rec_hbox = wx.BoxSizer(wx.HORIZONTAL)
rec_vbox.Add(rec_hbox, 0, wx.EXPAND)
rec_vbox.AddSpacer(5)
# Add sample rate controls to top window sizer
vbox.Add(rec_vbox, 0, wx.EXPAND)
vbox.AddSpacer(5)
rec_hbox.AddSpacer(3)
self.record_text = forms.text_box(
parent=self.panel, sizer=rec_hbox,
label='File Name',
proportion=1,
ps=self,
key='record',
converter=forms.str_converter(),
)
rec_hbox.AddSpacer(5)
def record_callback(value):
if value:
self.sample_rate_text.Disable()
self.record_text.Disable()
self.rec_file_name = self.record_to_filename()
print "Recording samples to ", self.rec_file_name
self.file_sink.open(self.rec_file_name);
else:
self.sample_rate_text.Enable()
self.record_text.Enable()
self.file_sink.close()
print "Finished recording to", self.rec_file_name
forms.toggle_button(
sizer=rec_hbox,
parent=self.panel,
false_label='REC',
true_label='STOP',
value=False,
callback=record_callback,
)
##################################################
# 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'] )
try:
self.src.set_dc_offset( correction )
if self._verbose:
print "Set DC offset to", correction
except RuntimeError as ex:
print ex
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'] )
try:
self.src.set_iq_balance( correction )
if self._verbose:
print "Set IQ balance to", correction
except RuntimeError as ex:
print ex
def set_sample_rate(self, samp_rate):
samp_rate = self.src.set_sample_rate(samp_rate)
if hasattr(self.scope, 'set_sample_rate'):
self.scope.set_sample_rate(samp_rate)
if self._verbose:
print "Set sample rate to:", samp_rate
try:
self[BWIDTH_KEY] = self.set_bandwidth(samp_rate)
except RuntimeError:
pass
return samp_rate
def get_gain_names(self):
return self.src.get_gain_names()
def set_named_gain(self, gain, name):
if gain is None:
g = self[GAIN_RANGE_KEY(name)]
gain = float(g.start()+g.stop())/2
if self._verbose:
print "Using auto-calculated mid-point gain"
self[GAIN_KEY(name)] = gain
return
gain = self.src.set_gain(gain, name)
if self._verbose:
print "Set " + name + " gain to:", gain
def set_bandwidth(self, bw):
clipped_bw = self[BWIDTH_RANGE_KEY].clip(bw)
if self.src.get_bandwidth() != clipped_bw:
bw = self.src.set_bandwidth(clipped_bw)
if self._verbose:
print "Set bandwidth to:", bw
return bw
def set_freq_from_callback(self, freq):
freq = self.src.set_center_freq(freq)
self[CENTER_FREQ_KEY] = freq;
def set_freq(self, freq):
if freq is None:
f = self[FREQ_RANGE_KEY]
freq = float(f.start()+f.stop())/2.0
if self._verbose:
print "Using auto-calculated mid-point frequency"
self[CENTER_FREQ_KEY] = freq
return
freq = self.src.set_center_freq(freq)
if hasattr(self.scope, 'set_baseband_freq'):
self.scope.set_baseband_freq(freq)
if freq is not None:
if self._verbose:
print "Set center frequency to", freq
elif self._verbose:
print "Failed to set freq."
return freq
def set_freq_corr(self, ppm):
if ppm is None:
ppm = 0.0
if self._verbose:
print "Using frequency corrrection of", ppm
self[FREQ_CORR_KEY] = ppm
return
ppm = self.src.set_freq_corr(ppm)
if self._verbose:
print "Set frequency correction to:", ppm
def main ():
app = stdgui2.stdapp(app_top_block, "osmocom Spectrum Browser", nstatus=1)
app.MainLoop()
if __name__ == '__main__':
main ()