예제 #1
0
 def calc_usable_bandwidth(self, sample_rate):
     passband = sample_rate * (3 / 8)  # 3/4 of + and - halves
     if self.__profile.dc_offset:
         epsilon = 1.0  # TODO: Put width in the profile.
         return RangeT([(-passband, -epsilon), (epsilon, passband)])
     else:
         return RangeT([(-passband, passband)])
예제 #2
0
 def calc_usable_bandwidth(self, sample_rate):
     passband = sample_rate * (3 / 8)  # 3/4 of + and - halves
     if self.__profile.dc_offset:
         epsilon = 1.0  # RangeT has only inclusive bounds, so we need a nonzero value.
         return RangeT([(-passband, -epsilon), (epsilon, passband)])
     else:
         return RangeT([(-passband, passband)])
예제 #3
0
class SquelchMixin(ExportedState):
    def __init__(self, squelch_rate, squelch_threshold=-100):
        alpha = 80.0 / squelch_rate
        self.rf_squelch_block = analog.simple_squelch_cc(
            squelch_threshold, alpha)
        self.rf_probe_block = analog.probe_avg_mag_sqrd_c(0, alpha=alpha)

    @exported_value(type=RangeT([(-100, 0)], unit=units.dBFS, strict=False),
                    changes='continuous',
                    label='Channel power')
    def get_rf_power(self):
        return to_dB(max(1e-10, self.rf_probe_block.level()))

    @exported_value(type=RangeT([(-100, 0)],
                                unit=units.dBFS,
                                strict=False,
                                logarithmic=False),
                    changes='this_setter',
                    label='Squelch')
    def get_squelch_threshold(self):
        return self.rf_squelch_block.threshold()

    @setter
    def set_squelch_threshold(self, level):
        self.rf_squelch_block.set_threshold(level)
예제 #4
0
파일: devices.py 프로젝트: boubex/shinysdr
    def __init__(self, device_name, sample_rate, channel_mapping):
        self.__device_name = device_name
        self.__sample_rate = sample_rate

        if len(channel_mapping) == 2:
            self.__signal_type = SignalType(kind='IQ',
                                            sample_rate=self.__sample_rate)
            # TODO should be configurable
            self.__usable_bandwidth = RangeT([(-self.__sample_rate / 2,
                                               self.__sample_rate / 2)])
        else:
            self.__signal_type = SignalType(
                kind=
                'USB',  # TODO obtain correct type from config (or say hamlib)
                sample_rate=self.__sample_rate)
            self.__usable_bandwidth = RangeT([(500, 2500)])

        gr.hier_block2.__init__(
            self,
            type(self).__name__,
            gr.io_signature(0, 0, 0),
            gr.io_signature(1, 1, gr.sizeof_gr_complex * 1),
        )

        self.__source = audio.source(self.__sample_rate,
                                     device_name=self.__device_name,
                                     ok_to_block=True)

        channel_matrix = blocks.multiply_matrix_ff(channel_mapping)
        combine = blocks.float_to_complex(1)
        for i in xrange(0, len(channel_mapping[0])):
            self.connect((self.__source, i), (channel_matrix, i))
        for i in xrange(0, len(channel_mapping)):
            self.connect((channel_matrix, i), (combine, i))
        self.connect(combine, self)
예제 #5
0
class _HamlibRotator(_HamlibProxy):
    _server_name = 'rotctld'
    _dummy_command = 'get_pos'

    # TODO: support imperative commands:
    # move
    # stop
    # park
    # reset

    _info = {
        # TODO: Get ranges from dump_caps
        'Azimuth': (RangeT([(-180, 180)])),
        'Elevation': (RangeT([(0, 90)])),
    }

    _commands = {
        'pos': ['Azimuth', 'Elevation'],
    }

    def poll_fast(self, send):
        send('get_pos')

    def poll_slow(self, send):
        pass
예제 #6
0
 def __init__(self, offset_radius):
     super(_RetuningTestRXDriver, self).__init__()
     rate = 200e3
     self.__signal_type = SignalType(kind='IQ', sample_rate=rate)
     halfrate = rate / 2
     if offset_radius > 0:
         self.__usable_bandwidth = RangeT([(-halfrate, -offset_radius), (offset_radius, halfrate)])
     else:
         self.__usable_bandwidth = RangeT([(-halfrate, halfrate)])
예제 #7
0
파일: simulate.py 프로젝트: tashby/shinysdr
class _SimulatedTransmitter(gr.hier_block2, ExportedState):
    """provides frequency parameters"""
    def __init__(self, modulator, audio_rate, rf_rate, freq):
        modulator = IModulator(modulator)
        
        gr.hier_block2.__init__(
            self, 'SimulatedChannel',
            gr.io_signature(1, 1, gr.sizeof_float * 1),
            gr.io_signature(1, 1, gr.sizeof_gr_complex * 1),
        )
        
        self.__freq = freq
        self.__rf_rate = rf_rate
        self.__modulator = modulator
        
        modulator_input_type = modulator.get_input_type()
        if modulator_input_type.get_kind() == 'MONO':
            audio_resampler = make_resampler(audio_rate, modulator_input_type.get_sample_rate())
            self.connect(self, audio_resampler, modulator)
        elif modulator_input_type.get_kind() == 'NONE':
            self.connect(self, blocks.null_sink(gr.sizeof_float))
        else:
            raise Exception('don\'t know how to supply input of type %s' % modulator_input_type)
        
        rf_resampler = rational_resampler.rational_resampler_ccf(
            interpolation=int(rf_rate),
            decimation=int(modulator.get_output_type().get_sample_rate()))
        self.__rotator = blocks.rotator_cc(rotator_inc(rate=rf_rate, shift=freq))
        self.__mult = blocks.multiply_const_cc(dB(-10))
        self.connect(modulator, rf_resampler, self.__rotator, self.__mult, self)
    
    @exported_value(type=ReferenceT(), changes='never')
    def get_modulator(self):
        return self.__modulator

    @exported_value(
        type_fn=lambda self: RangeT([(-self.__rf_rate / 2, self.__rf_rate / 2)], unit=units.Hz, strict=False),
        changes='this_setter',
        label='Frequency')
    def get_freq(self):
        return self.__freq
    
    @setter
    def set_freq(self, value):
        self.__freq = float(value)
        self.__rotator.set_phase_inc(rotator_inc(rate=self.__rf_rate, shift=self.__freq))
    
    @exported_value(
        type=RangeT([(-50.0, 0.0)], unit=units.dB, strict=False),
        changes='this_setter',
        label='Gain')
    def get_gain(self):
        return to_dB(self.__mult.k().real)
    
    @setter
    def set_gain(self, value):
        self.__mult.set_k(dB(value))
예제 #8
0
 def __init__(self,
         device_name,
         sample_rate,
         channel_mapping,
         usable_bandwidth,
         audio_module):
     self.__device_name = device_name
     self.__sample_rate = sample_rate
     
     if len(channel_mapping) == 2:
         self.__signal_type = SignalType(
             kind='IQ',
             sample_rate=self.__sample_rate)
         if usable_bandwidth is not None:
             ub_low, ub_high = usable_bandwidth
             assert ub_high > 0
             if ub_low <= 0:
                 self.__usable_bandwidth = RangeT([(-ub_high, ub_high)])
             else:
                 self.__usable_bandwidth = RangeT([(-ub_high, -ub_low), (ub_low, ub_high)])
         else:
             self.__usable_bandwidth = RangeT([(-self.__sample_rate / 2, self.__sample_rate / 2)])
     else:
         self.__signal_type = SignalType(
             kind='USB',  # TODO obtain correct type from config (or say hamlib)
             sample_rate=self.__sample_rate)
         self.__usable_bandwidth = RangeT([(500, 2500)])
     
     gr.hier_block2.__init__(
         self, type(self).__name__,
         gr.io_signature(0, 0, 0),
         gr.io_signature(1, 1, gr.sizeof_gr_complex * 1),
     )
 
     def init_source():
         self.__source = None
         self.disconnect_all()
     
         self.__source = audio_module.source(
             self.__sample_rate,
             device_name=self.__device_name,
             ok_to_block=True)
     
         channel_matrix = blocks.multiply_matrix_ff(channel_mapping)
         combine = blocks.float_to_complex(1)
         # TODO: min() is to support mono sources with default channel mapping. Handle this better, and give a warning if an explicit mapping is too big.
         for i in xrange(0, min(len(channel_mapping[0]),
                                self.__source.output_signature().max_streams())):
             self.connect((self.__source, i), (channel_matrix, i))
         for i in xrange(0, len(channel_mapping)):
             self.connect((channel_matrix, i), (combine, i))
         self.connect(combine, self)
     
     self.__init_source = init_source
     self.__init_source()
예제 #9
0
 def test_repr(self):
     self.assertEqual('RangeT([(1, 2), (3, 4)], unit=, strict=True, logarithmic=False, integer=False)',
                      repr(RangeT([(1, 2), (3, 4)])))
     self.assertEqual('RangeT([(1, 2), (3, 4)], unit=dB, strict=True, logarithmic=False, integer=False)',
                      repr(RangeT([(1, 2), (3, 4)], unit=units.dB)))
     self.assertEqual('RangeT([(1, 2), (3, 4)], unit=, strict=False, logarithmic=False, integer=False)',
                      repr(RangeT([(1, 2), (3, 4)], strict=False)))
     self.assertEqual('RangeT([(1, 2), (3, 4)], unit=, strict=True, logarithmic=True, integer=False)',
                      repr(RangeT([(1, 2), (3, 4)], logarithmic=True)))
     self.assertEqual('RangeT([(1, 2), (3, 4)], unit=, strict=True, logarithmic=False, integer=True)',
                      repr(RangeT([(1, 2), (3, 4)], integer=True)))
예제 #10
0
def _install_cell(self, name, is_level, writable, caps):
    # this is a function for the sake of the closure variables
    
    if name == 'Frequency':
        cell_name = 'freq'  # consistency with our naming scheme elsewhere, also IHasFrequency
    else:
        cell_name = name
    
    if is_level:
        # TODO: Use range info from hamlib if available
        if name == 'STRENGTH level':
            vtype = RangeT([(-54, 50)], strict=False)
        elif name == 'SWR level':
            vtype = RangeT([(1, 30)], strict=False)
        elif name == 'RFPOWER level':
            vtype = RangeT([(0, 100)], strict=False)
        else:
            vtype = RangeT([(-10, 10)], strict=False)
    elif name == 'Mode' or name == 'TX Mode':
        # kludge
        vtype = EnumT({x: x for x in caps['Mode list'].strip().split(' ')})
    elif name == 'VFO' or name == 'TX VFO':
        vtype = EnumT({x: x for x in caps['VFO list'].strip().split(' ')})
    else:
        vtype = self._info[name]
    
    def updater(strval):
        try:
            if vtype is bool:
                value = bool(int(strval))
            else:
                value = vtype(strval)
        except ValueError:
            value = unicode(strval)
        cell.set_internal(value)
    
    def actually_write_value(value):
        if vtype is bool:
            self._ehs_set(name, str(int(value)))
        else:
            self._ehs_set(name, str(vtype(value)))
    
    cell = LooseCell(
        value='placeholder',
        type=vtype,
        writable=writable,
        persists=False,
        post_hook=actually_write_value,
        label=name)  # TODO: supply label values from _info table
    self._cell_updaters[name] = updater
    updater(self._ehs_get(name))
    return cell_name, cell
예제 #11
0
def SimulatedDevice(name='Simulated RF', freq=0.0, allow_tuning=False):
    rx_driver = _SimulatedRXDriver(name)
    return Device(
        name=name,
        vfo_cell=LooseCell(
            key='freq',
            value=freq,
            type=RangeT([(-1e9, 1e9)]) if allow_tuning else RangeT(
                [(freq, freq)]),  # TODO kludge magic numbers
            writable=True,
            persists=False,
            post_hook=rx_driver._set_sim_freq),
        rx_driver=rx_driver)
예제 #12
0
def SimulatedDevice(name='Simulated RF', freq=0.0, allow_tuning=False):
    """
    See documentation in shinysdr/i/webstatic/manual/configuration.html.
    """
    rx_driver = _SimulatedRXDriver(name)
    return Device(
        name=name,
        vfo_cell=LooseCell(
            value=freq,
            type=RangeT([(-1e9, 1e9)]) if allow_tuning else RangeT(
                [(freq, freq)]),  # TODO kludge magic numbers
            writable=True,
            persists=False,
            post_hook=rx_driver._set_sim_freq),
        rx_driver=rx_driver)
예제 #13
0
 def test_bandwidth_discontiguous(self):
     self.assertEqual(
         RangeT([(-30000.0, -1.0), (1.0, 30000.0)]),
         OsmoSDRDevice(
             'file=/dev/null,rate=80000',
             profile=OsmoSDRProfile(
                 dc_offset=True)).get_rx_driver().get_usable_bandwidth())
예제 #14
0
 def test_vfos(self):
     d = merge_devices([
         Device(vfo_cell=_ConstantVFOCell(1)),
         Device(vfo_cell=LooseCell(
             value=0, type=RangeT([(10, 20)]), writable=True))
     ])
     self.assertTrue(d.get_vfo_cell().isWritable())
예제 #15
0
 def test_log_integer(self):
     _testType(
         self, RangeT([(1, 32)],
                      strict=True,
                      logarithmic=True,
                      integer=True), [(0, 1), 1, 2, 4, 32, (2.0, 2),
                                      (2.5, 2), (3.5, 4), (33, 32)], [])
예제 #16
0
def SimulatedDeviceForTest(name='Simulated RF',
                           freq=0.0,
                           allow_tuning=False,
                           add_transmitters=False):
    """Identical to SimulatedDevice except that the defaults are arranged to be minimal for fast testing rather than to provide a rich simulation."""
    rx_driver = _SimulatedRXDriver(name, add_transmitters=add_transmitters)
    return Device(
        name=name,
        vfo_cell=LooseCell(
            value=freq,
            type=RangeT([(-1e9, 1e9)]) if allow_tuning else RangeT(
                [(freq, freq)]),  # TODO kludge magic numbers
            writable=True,
            persists=False,
            post_hook=rx_driver._set_sim_freq),
        rx_driver=rx_driver)
예제 #17
0
class RTTYFSKDemodulator(gr.hier_block2, ExportedState):
    """
    Demodulate FSK with parameters suitable for gr-rtty.
    
    TODO: Make this into something more reusable once we have other examples of FSK.
    Note this differs from the GFSK demod in gnuradio.digital by having a DC blocker.
    """
    def __init__(self, input_rate, baud):
        gr.hier_block2.__init__(
            self, 'RTTY FSK demodulator',
            gr.io_signature(1, 1, gr.sizeof_gr_complex * 1),
            gr.io_signature(1, 1, gr.sizeof_float * 1),
        )
        
        self.bit_time = bit_time = input_rate / baud
        
        fsk_deviation_hz = 85  # TODO param or just don't care
        
        self.__dc_blocker = grfilter.dc_blocker_ff(int(bit_time * _HALF_BITS_PER_CODE * 10), False)
        self.__quadrature_demod = analog.quadrature_demod_cf(-input_rate / (2 * math.pi * fsk_deviation_hz))
        self.__freq_probe = blocks.probe_signal_f()
        
        self.connect(
            self,
            self.__quadrature_demod,
            self.__dc_blocker,
            digital.binary_slicer_fb(),
            blocks.char_to_float(scale=1),
            self)
        self.connect(self.__dc_blocker, self.__freq_probe)

    @exported_value(type=RangeT([(-2, 2)]), changes='continuous')
    def get_probe(self):
        return abs(self.__freq_probe.level())
예제 #18
0
def _ConstantVFOCell(value):
    value = float(value)
    return LooseCell(
        value=value,
        type=RangeT([(value, value)]),
        writable=False,
        persists=False)
예제 #19
0
 def setUp(self):
     self.lc = LooseCell(value=0, type=RangeT([(-100, 100)]))
     self.delta = 1
     self.vc = ViewCell(base=self.lc,
                        get_transform=lambda x: x + self.delta,
                        set_transform=lambda x: x - self.delta,
                        type=int)
예제 #20
0
class StubRXDriver(gr.hier_block2, ExportedState):
    """Minimal implementation of IRXDriver."""
    __signal_type = SignalType(kind='IQ', sample_rate=10000)
    __usable_bandwidth = RangeT([(-1e9, 1e9)])  # TODO magic numbers

    def __init__(self):
        gr.hier_block2.__init__(self,
                                type(self).__name__, gr.io_signature(0, 0, 0),
                                gr.io_signature(1, 1, gr.sizeof_gr_complex))
        self.connect(blocks.vector_source_c([]), self)

    def get_output_type(self):
        return self.__signal_type

    def get_tune_delay(self):
        return 0.0

    def get_usable_bandwidth(self):
        return self.__usable_bandwidth

    def close(self):
        pass

    def notify_reconnecting_or_restarting(self):
        pass
예제 #21
0
class ChirpModulator(gr.hier_block2, ExportedState):
    def __init__(self, context, mode, chirp_rate=0.1, output_rate=10000):
        gr.hier_block2.__init__(self,
                                type(self).__name__, gr.io_signature(0, 0, 0),
                                gr.io_signature(1, 1, gr.sizeof_gr_complex))

        self.__output_rate = output_rate
        self.__chirp_rate = chirp_rate

        self.__control = analog.sig_source_f(output_rate, analog.GR_SAW_WAVE,
                                             chirp_rate,
                                             output_rate * 2 * math.pi, 0)
        chirp_vco = blocks.vco_c(output_rate, 1, 1)

        self.connect(self.__control, chirp_vco, self)

    def get_input_type(self):
        return no_signal

    def get_output_type(self):
        return SignalType(kind='IQ', sample_rate=self.__output_rate)

    @exported_value(parameter='chirp_rate',
                    type=RangeT([(-10.0, 10.0)], unit=units.Hz, strict=False),
                    changes='this_setter',
                    label='Chirp rate')
    def get_chirp_rate(self):
        return self.__chirp_rate

    @setter
    def set_chirp_rate(self, value):
        self.__chirp_rate = value
        self.__control.set_frequency(value)
예제 #22
0
def _RetuningTestDevice(freq, has_dc_offset):
    return Device(
        rx_driver=_RetuningTestRXDriver(has_dc_offset),
        vfo_cell=LooseCell(
            value=freq,
            type=RangeT([(-1e9, 1e9)]),  # TODO kludge magic numbers
            writable=True,
            persists=False))
예제 #23
0
def convert_osmosdr_range(meta_range, add_zero=False, transform=lambda f: f, **kwargs):
    # TODO: Recognize step values from osmosdr
    subranges = []
    for i in xrange(0, meta_range.size()):
        single_range = meta_range[i]
        subranges.append((transform(single_range.start()), transform(single_range.stop())))
    if add_zero or not subranges:  # don't generate an invalid empty RangeT
        subranges[0:0] = [(0, 0)]
    return RangeT(subranges, **kwargs)
예제 #24
0
 def __init__(self, lime_block):
     self.__lime_block = lime_block
     self.__vfo_cell = LooseCell(value=0.0,
                                 type=RangeT([(10e6, 3500e6)],
                                             strict=False,
                                             unit=units.Hz),
                                 writable=True,
                                 persists=True,
                                 post_hook=self.__set_freq)
예제 #25
0
 def setUp(self):
     self.lc = LooseCell(value=0, type=RangeT([(-100, 100)]), writable=True)
     self.delta = 1
     self.vc = ViewCell(base=self.lc,
                        get_transform=lambda x: x + self.delta,
                        set_transform=lambda x: x - self.delta,
                        type=int,
                        writable=True,
                        interest_tracker=LoopbackInterestTracker())
예제 #26
0
class DecoratorInheritanceSpecimen(DecoratorInheritanceSpecimenSuper):
    """Helper for TestDecorator"""
    def __init__(self):
        self.rw = 0.0

    @exported_value(type=RangeT([(0.0, 10.0)]), changes='this_setter')
    def get_rw(self):
        return self.rw

    @setter
    def set_rw(self, value):
        self.rw = value
예제 #27
0
 def test_rounding_at_ends_split(self):
     self.assertEqual(RangeT([[1, 2], [3, 4]])(0, range_round_direction=0), 1)
     self.assertEqual(RangeT([[1, 2], [3, 4]])(0, range_round_direction=-1), 1)
     self.assertEqual(RangeT([[1, 2], [3, 4]])(0, range_round_direction=+1), 1)
     self.assertEqual(RangeT([[1, 2], [3, 4]])(5, range_round_direction=0), 4)
     self.assertEqual(RangeT([[1, 2], [3, 4]])(5, range_round_direction=-1), 4)
     self.assertEqual(RangeT([[1, 2], [3, 4]])(5, range_round_direction=+1), 4)
예제 #28
0
 def test_rounding_in_gap(self):
     self.assertEqual(RangeT([[1, 2], [3, 4]])(2.4, range_round_direction=0), 2)
     self.assertEqual(RangeT([[1, 2], [3, 4]])(2.4, range_round_direction=-1), 2)
     self.assertEqual(RangeT([[1, 2], [3, 4]])(2.4, range_round_direction=+1), 3)
     self.assertEqual(RangeT([[1, 2], [3, 4]])(2.6, range_round_direction=-1), 2)
     self.assertEqual(RangeT([[1, 2], [3, 4]])(2.6, range_round_direction=+1), 3)
     self.assertEqual(RangeT([[1, 2], [3, 4]])(2.6, range_round_direction=0), 3)
예제 #29
0
 def test_rounding_at_ends_single(self):
     self.assertEqual(RangeT([[1, 3]])(0, range_round_direction=-1), 1)
     self.assertEqual(RangeT([[1, 3]])(2, range_round_direction=-1), 2)
     self.assertEqual(RangeT([[1, 3]])(4, range_round_direction=-1), 3)
     self.assertEqual(RangeT([[1, 3]])(0, range_round_direction=+1), 1)
     self.assertEqual(RangeT([[1, 3]])(2, range_round_direction=+1), 2)
     self.assertEqual(RangeT([[1, 3]])(4, range_round_direction=+1), 3)
예제 #30
0
class SquelchMixin(ExportedState):
    """Provides simple RF-power squelch and a level meter.
    
    To use, connect self.squelch_block in the pre-demodulation signal path.
    """
    def __init__(self, squelch_rate, squelch_threshold=-100):
        alpha = 80.0 / squelch_rate

        self.__squelch = analog.simple_squelch_cc(squelch_threshold, alpha)
        self.__probe = analog.probe_avg_mag_sqrd_c(0, alpha=alpha)

        self.squelch_block = gr.hier_block2(
            defaultstr('SquelchMixin bundle'),
            gr.io_signature(1, 1, gr.sizeof_gr_complex),
            gr.io_signature(1, 1, gr.sizeof_gr_complex))
        self.squelch_block.connect(self.squelch_block, self.__squelch,
                                   self.squelch_block)
        self.squelch_block.connect(self.squelch_block, self.__probe)

    @exported_value(type=RangeT([(-100, 0)], unit=units.dBFS, strict=False),
                    changes='continuous',
                    label='Channel power')
    def get_rf_power(self):
        return to_dB(max(1e-10, self.__probe.level()))

    @exported_value(type=RangeT([(-100, 0)],
                                unit=units.dBFS,
                                strict=False,
                                logarithmic=False),
                    changes='this_setter',
                    label='Squelch')
    def get_squelch_threshold(self):
        return self.__squelch.threshold()

    @setter
    def set_squelch_threshold(self, level):
        self.__squelch.set_threshold(level)