示例#1
0
class _OsmoSDRTXDriver(ExportedState, gr.hier_block2):
    def __init__(self,
            osmo_device,
            rx,
            name,
            tuning,
            sample_rate):
        gr.hier_block2.__init__(
            self, b'TX ' + str(name),
            gr.io_signature(1, 1, gr.sizeof_gr_complex),
            gr.io_signature(0, 0, 0))
        
        self.__osmo_device = osmo_device
        self.__rx_driver = rx
        self.__tuning = tuning
        
        self.__signal_type = SignalType(
            kind='IQ',
            sample_rate=sample_rate)
        
        self.__sink = None
        self.__placeholder = blocks.null_sink(gr.sizeof_gr_complex)
        self.__state_while_inactive = {}
        
        self.connect(self, self.__placeholder)
    
    # implement ITXDriver
    def get_input_type(self):
        return self.__signal_type
    
    # implement ITXDriver
    def close(self):
        self.disconnect_all()
        self.__rx_driver = None
        self.__sink = None
        self.__tuning = None
    
    # implement ITXDriver
    def notify_reconnecting_or_restarting(self):
        pass
    
    # implement ITXDriver
    def set_transmitting(self, value, midpoint_hook):
        self.disconnect_all()
        if value:
            self.__rx_driver._stop_rx()
            midpoint_hook()
            self.__sink = osmosdr.sink(self.__osmo_device)
            self.__sink.set_sample_rate(self.__signal_type.get_sample_rate())
            self.__tuning.set_block(self.__sink)
            self.connect(self, self.__sink)
            self.state_from_json(self.__state_while_inactive)
        else:
            self.__state_while_inactive = self.state_to_json()
            self.__tuning.set_block(None)
            self.__sink = None
            self.connect(self, self.__placeholder)
            midpoint_hook()
            self.__rx_driver._start_rx()
示例#2
0
class _OsmoSDRRXDriver(ExportedState, gr.hier_block2):
    
    # Note: Docs for gr-osmosdr are in comments at gr-osmosdr/lib/source_iface.h
    def __init__(self,
            osmo_device,
            source,
            profile,
            name,
            tuning):
        gr.hier_block2.__init__(
            self, b'RX ' + str(name),
            gr.io_signature(0, 0, 0),
            gr.io_signature(1, 1, gr.sizeof_gr_complex * 1),
        )
        
        self.__osmo_device = osmo_device
        self.__source = source
        self.__profile = profile
        self.__name = name
        self.__tuning = tuning
        self.__antenna_type = EnumT({unicode(name): unicode(name) for name in self.__source.get_antennas()}, strict=True)
        
        self.connect(self.__source, self)
        
        self.__gains = Gains(source, self)
        
        # State of the source that there are no getters for, so we must keep our own copy of
        self.__track_dc_offset_mode = DCOffsetOff
        self.__track_iq_balance_mode = IQBalanceOff
        source.set_dc_offset_mode(self.__track_dc_offset_mode, ch)
        source.set_iq_balance_mode(self.__track_iq_balance_mode, ch)
        
        # Blocks
        self.__state_while_inactive = {}
        self.__placeholder = blocks.vector_source_c([])
        
        sample_rate = float(source.get_sample_rate())
        self.__signal_type = SignalType(
            kind='IQ',
            sample_rate=sample_rate)
        self.__usable_bandwidth = tuning.calc_usable_bandwidth(sample_rate)
    
    @exported_value(type=SignalType, changes='never')
    def get_output_type(self):
        return self.__signal_type
    
    # implement IRXDriver
    def get_tune_delay(self):
        return self.__profile.tune_delay

    # implement IRXDriver
    def get_usable_bandwidth(self):
        return self.__usable_bandwidth
    
    # implement IRXDriver
    def close(self):
        self._stop_rx()
        self.__tuning = None
    
    @exported_value(
        type=QuantityT(unit=units.ppm),
        changes='this_setter',
        label='Freq.corr.')
    def get_correction_ppm(self):
        return self.__tuning.get_correction_ppm()
    
    @setter
    def set_correction_ppm(self, value):
        self.__tuning.set_correction_ppm(value)
    
    @exported_value(type=ReferenceT(), changes='never')
    def get_gains(self):
        return self.__gains
    
    @exported_value(
        type_fn=lambda self: convert_osmosdr_range(
            self.__source.get_gain_range(ch), unit=units.dB, strict=False),
        changes='this_setter',
        label='Gain')
    def get_gain(self):
        if self.__source is None: return 0.0
        return self.__source.get_gain(ch)
    
    @setter
    def set_gain(self, value):
        self.__source.set_gain(float(value), ch)
        # The single gain and individual-stage gain controls have an unspecified relationship to each other. Thus, changing one must poll the other.
        self.__gains.state_changed()
    
    @exported_value(
        type_fn=lambda self: bool if self.__profile.agc else ConstantT(False),
        changes='this_setter',
        label='AGC on')
    def get_agc(self):
        if self.__source is None: return False
        return bool(self.__source.get_gain_mode(ch))
    
    @setter
    def set_agc(self, value):
        self.__source.set_gain_mode(bool(value), ch)
    
    @exported_value(
        type_fn=lambda self: self.__antenna_type,
        changes='this_setter',
        label='Antenna')
    def get_antenna(self):
        if self.__source is None: return ''
        return unicode(self.__source.get_antenna(ch))
    
    @setter
    def set_antenna(self, value):
        # TODO we should have a provision for restricting antenna selection when transmit is possible to avoid hardware damage
        self.__source.set_antenna(str(self.__antenna_type(value)), ch)
    
    # Note: dc_offset_mode has a 'manual' mode we are not yet exposing, which is why the internal tracking is an enum integer but the exported value is a boolean
    @exported_value(
        type_fn=lambda self: bool if self.__profile.dc_cancel else ConstantT(False),
        changes='this_setter',
        label='Use DC cancellation')
    def get_dc_cancel(self):
        return bool(self.__track_dc_offset_mode)
    
    @setter
    def set_dc_cancel(self, value):
        if value:
            mode = DCOffsetAutomatic
        else:
            mode = DCOffsetOff
        self.__source.set_dc_offset_mode(mode, ch)
        self.__track_dc_offset_mode = mode
    
    # Note: iq_balance_mode has a 'manual' mode we are not yet exposing, which is why the internal tracking is an enum integer but the exported value is a boolean
    @exported_value(type=bool,    # TODO: detect gr-iqbal
        changes='this_setter',
        label='Use IQ balancer')
    def get_iq_balance(self):
        return bool(self.__track_iq_balance_mode)

    @setter
    def set_iq_balance(self, value):
        if value:
            mode = IQBalanceAutomatic
        else:
            mode = IQBalanceOff
        self.__source.set_iq_balance_mode(mode, ch)
        self.__track_iq_balance_mode = mode
    
    # add_zero because zero means automatic setting based on sample rate.
    # TODO: Display automaticness in the UI rather than having a zero value.
    @exported_value(
        type_fn=lambda self: convert_osmosdr_range(
            self.__source.get_bandwidth_range(ch), unit=units.Hz, add_zero=True),
        changes='this_setter',
        label='Analog bandwidth',
        description='Bandwidth of the analog antialiasing filter.')
    def get_bandwidth(self):
        if self.__source is None: return 0.0
        return self.__source.get_bandwidth(ch)
    
    @setter
    def set_bandwidth(self, value):
        self.__source.set_bandwidth(float(value), ch)
    
    def notify_reconnecting_or_restarting(self):
        pass

    # link to tx driver
    def _stop_rx(self):
        self.disconnect_all()
        self.__state_while_inactive = self.state_to_json()
        self.__tuning.set_block(None)
        self.__gains.close()
        self.__source = None
        self.connect(self.__placeholder, self)
    
    # link to tx driver
    def _start_rx(self):
        self.disconnect_all()
        self.__source = osmosdr.source('numchan=1 ' + self.__osmo_device)
        self.__source.set_sample_rate(self.__signal_type.get_sample_rate())
        self.__tuning.set_block(self.__source)
        self.__gains = Gains(self.__source, self)
        self.connect(self.__source, self)
        self.state_from_json(self.__state_while_inactive)
示例#3
0
class _OsmoSDRRXDriver(ExportedState, gr.hier_block2):
    implements(IRXDriver)
    
    # Note: Docs for gr-osmosdr are in comments at gr-osmosdr/lib/source_iface.h
    def __init__(self,
            osmo_device,
            source,
            profile,
            name,
            tuning):
        gr.hier_block2.__init__(
            self, 'RX ' + name,
            gr.io_signature(0, 0, 0),
            gr.io_signature(1, 1, gr.sizeof_gr_complex * 1),
        )
        
        self.__osmo_device = osmo_device
        self.__source = source
        self.__profile = profile
        self.__name = name
        self.__tuning = tuning
        
        self.connect(self.__source, self)
        
        self.__gains = Gains(source)
        
        # Misc state
        self.dc_state = DCOffsetOff
        self.iq_state = IQBalanceOff
        source.set_dc_offset_mode(self.dc_state, ch)  # no getter, set to known state
        source.set_iq_balance_mode(self.iq_state, ch)  # no getter, set to known state
        
        # Blocks
        self.__state_while_inactive = {}
        self.__placeholder = blocks.vector_source_c([])
        
        sample_rate = float(source.get_sample_rate())
        self.__signal_type = SignalType(
            kind='IQ',
            sample_rate=sample_rate)
        self.__usable_bandwidth = tuning.calc_usable_bandwidth(sample_rate)
    
    @exported_value(type=SignalType)
    def get_output_type(self):
        return self.__signal_type
    
    # implement IRXDriver
    def get_tune_delay(self):
        return 0.25  # TODO: make configurable and/or account for as many factors as we can

    # implement IRXDriver
    def get_usable_bandwidth(self):
        return self.__usable_bandwidth
    
    # implement IRXDriver
    def close(self):
        self._stop_rx()
        self.__tuning = None
    
    @exported_value(type=float)
    def get_correction_ppm(self):
        return self.__tuning.get_correction_ppm()
    
    @setter
    def set_correction_ppm(self, value):
        self.__tuning.set_correction_ppm(value)
    
    @exported_block()
    def get_gains(self):
        return self.__gains
    
    @exported_value(type_fn=lambda self: convert_osmosdr_range(
            self.__source.get_gain_range(ch), strict=False))
    def get_gain(self):
        if self.__source is None: return 0.0
        return self.__source.get_gain(ch)
    
    @setter
    def set_gain(self, value):
        self.__source.set_gain(float(value), ch)
    
    @exported_value(type_fn=lambda self: bool if self.__profile.agc else Constant(False))
    def get_agc(self):
        if self.__source is None: return False
        return bool(self.__source.get_gain_mode(ch))
    
    @setter
    def set_agc(self, value):
        self.__source.set_gain_mode(bool(value), ch)
    
    @exported_value(type_fn=lambda self: Enum(
        {unicode(name): unicode(name) for name in self.__source.get_antennas()}))
    def get_antenna(self):
        if self.__source is None: return ''
        return unicode(self.__source.get_antenna(ch))
        # TODO review whether set_antenna is safe to expose
    
    # Note: dc_cancel has a 'manual' mode we are not yet exposing
    @exported_value(type_fn=lambda self: bool if self.__profile.dc_cancel else Constant(False))
    def get_dc_cancel(self):
        return bool(self.dc_state)
    
    @setter
    def set_dc_cancel(self, value):
        if value:
            mode = DCOffsetAutomatic
        else:
            mode = DCOffsetOff
        self.dc_state = self.__source.set_dc_offset_mode(mode, ch)
    
    # Note: iq_balance has a 'manual' mode we are not yet exposing
    @exported_value(type=bool)  # TODO: detect gr-iqbal
    def get_iq_balance(self):
        return bool(self.iq_state)

    @setter
    def set_iq_balance(self, value):
        if value:
            mode = IQBalanceAutomatic
        else:
            mode = IQBalanceOff
        self.iq_state = self.__source.set_iq_balance_mode(mode, ch)
    
    # add_zero because zero means automatic setting based on sample rate.
    # TODO: Display automaticness in the UI rather than having a zero value.
    @exported_value(type_fn=lambda self: convert_osmosdr_range(
        self.__source.get_bandwidth_range(ch), add_zero=True))
    def get_bandwidth(self):
        if self.__source is None: return 0.0
        return self.__source.get_bandwidth(ch)
    
    @setter
    def set_bandwidth(self, value):
        self.__source.set_bandwidth(float(value), ch)
    
    def notify_reconnecting_or_restarting(self):
        pass

    # link to tx driver
    def _stop_rx(self):
        self.disconnect_all()
        self.__state_while_inactive = self.state_to_json()
        self.__tuning.set_block(None)
        self.__gains.close()
        self.__source = None
        self.connect(self.__placeholder, self)
    
    # link to tx driver
    def _start_rx(self):
        self.disconnect_all()
        self.__source = osmosdr.source('numchan=1 ' + self.__osmo_device)
        self.__source.set_sample_rate(self.__signal_type.get_sample_rate())
        self.__tuning.set_block(self.__source)
        self.__gains = Gains(self.__source)
        self.connect(self.__source, self)
        self.state_from_json(self.__state_while_inactive)
示例#4
0
class _LimeSDRRXDriver(ExportedState, gr.hier_block2):
    
    # Note: Docs for gr-limesdr are in comments at gr-limesdr/include/limesdr/source.h
    def __init__(self,
                 source,
                 device_type,
                 lna_path,
                 name,
                 tuning,
                 sample_rate):
        gr.hier_block2.__init__(
            self, defaultstr('RX ' + name),
            gr.io_signature(0, 0, 0),
            gr.io_signature(1, 1, gr.sizeof_gr_complex * 1),
        )
        
        self.__source = source
        self.__name = name
        self.__tuning = tuning
        
        self.connect(self.__source, self)
        
        # State of the source that there are no getters for, so we must keep our own copy of
        self.__track_gain = 50.
        source.set_gain(int(self.__track_gain), ch)

        self.__track_bandwidth = max(sample_rate / 2, 1.5e6)
        source.set_analog_filter(True, self.__track_bandwidth, ch)

        self.__lna_path_type = EnumT({
            LNANONE: 'None',
            LNAH: 'LNAH',
            LNAL: 'LNAL',
            LNAW: 'LNAW',
        })
        if device_type == LimeSDRMini:
            self.__lna_path_type = EnumT({
                LNAH: 'LNAH',
                LNAW: 'LNAW',
            })
        self.__track_lna_path = lna_path
        
        self.__signal_type = SignalType(
            kind='IQ',
            sample_rate=sample_rate)
        self.__usable_bandwidth = tuning.calc_usable_bandwidth(sample_rate)
    
    @exported_value(type=SignalType, changes='never')
    def get_output_type(self):
        return self.__signal_type
    
    # implement IRXDriver
    def get_tune_delay(self):
        # TODO: Measure this.
        return 0.07

    # implement IRXDriver
    def get_usable_bandwidth(self):
        if self.__track_bandwidth:
            return self.__tuning.calc_usable_bandwidth(self.__track_bandwidth)
        return self.__usable_bandwidth
    
    # implement IRXDriver
    def close(self):
        self.disconnect_all()
        self.__source = None
        self.__tuning = None

    @exported_value(
        type_fn=lambda self: self.__lna_path_type,
        changes='this_setter',
        label='LNA Path')
    def get_lna_path(self):
        return self.__track_lna_path

    @setter
    def set_lna_path(self, lna_path):
        self.__track_lna_path = int(lna_path)
        self.__source.set_lna_path(int(lna_path), ch)
    
    @exported_value(
        type_fn=lambda self: RangeT([(0, 70)], unit=units.dB, strict=False),
        changes='this_setter',
        label='Gain')
    def get_gain(self):
        if self.__source is None: return 0.0
        return self.__track_gain
    
    @setter
    def set_gain(self, value):
        self.__track_gain = int(value)
        self.__source.set_gain(int(value), ch)

    # zero means no filter
    @exported_value(
        type_fn=lambda self: RangeT([(1e3, min(130e6, self.__signal_type.get_sample_rate()))], unit=units.Hz),
        changes='this_setter',
        label='Hardware filter',
        description='Bandwidth of the analog and digital filters.')
    def get_bandwidth(self):
        if self.__source is None: return 0.0
        return self.__track_bandwidth
    
    @setter
    def set_bandwidth(self, value):
        self.__track_bandwidth = float(value)
        if value == self.__signal_type.get_sample_rate():
            self.__source.set_analog_filter(False, 0, ch)
            self.__source.set_digital_filter(False, 0, ch)
            return
        # Analog filter goes down to 1.5e6, digital filter goes arbitrarily low.
        analog = max(value, 1.5e6)
        self.__source.set_analog_filter(True, float(analog), ch)
        self.__source.set_digital_filter(True, float(value), ch)
    
    def notify_reconnecting_or_restarting(self):
        pass
示例#5
0
class _OsmoSDRRXDriver(ExportedState, gr.hier_block2):
    implements(IRXDriver)
    
    # Note: Docs for gr-osmosdr are in comments at gr-osmosdr/lib/source_iface.h
    def __init__(self,
            osmo_device,
            source,
            profile,
            name,
            tuning):
        gr.hier_block2.__init__(
            self, 'RX ' + name,
            gr.io_signature(0, 0, 0),
            gr.io_signature(1, 1, gr.sizeof_gr_complex * 1),
        )
        
        self.__osmo_device = osmo_device
        self.__source = source
        self.__profile = profile
        self.__name = name
        self.__tuning = tuning
        self.__antenna_type = Enum({unicode(name): unicode(name) for name in self.__source.get_antennas()}, strict=True)
        
        self.connect(self.__source, self)
        
        self.__gains = Gains(source)
        
        # Misc state
        self.dc_state = DCOffsetOff
        self.iq_state = IQBalanceOff
        source.set_dc_offset_mode(self.dc_state, ch)  # no getter, set to known state
        source.set_iq_balance_mode(self.iq_state, ch)  # no getter, set to known state
        
        # Blocks
        self.__state_while_inactive = {}
        self.__placeholder = blocks.vector_source_c([])
        
        sample_rate = float(source.get_sample_rate())
        self.__signal_type = SignalType(
            kind='IQ',
            sample_rate=sample_rate)
        self.__usable_bandwidth = tuning.calc_usable_bandwidth(sample_rate)
    
    @exported_value(type=SignalType)
    def get_output_type(self):
        return self.__signal_type
    
    # implement IRXDriver
    def get_tune_delay(self):
        return self.__profile.tune_delay

    # implement IRXDriver
    def get_usable_bandwidth(self):
        return self.__usable_bandwidth
    
    # implement IRXDriver
    def close(self):
        self._stop_rx()
        self.__tuning = None
    
    @exported_value(type=float)
    def get_correction_ppm(self):
        return self.__tuning.get_correction_ppm()
    
    @setter
    def set_correction_ppm(self, value):
        self.__tuning.set_correction_ppm(value)
    
    @exported_block()
    def get_gains(self):
        return self.__gains
    
    @exported_value(type_fn=lambda self: convert_osmosdr_range(
            self.__source.get_gain_range(ch), strict=False))
    def get_gain(self):
        if self.__source is None: return 0.0
        return self.__source.get_gain(ch)
    
    @setter
    def set_gain(self, value):
        self.__source.set_gain(float(value), ch)
    
    @exported_value(type_fn=lambda self: bool if self.__profile.agc else Constant(False))
    def get_agc(self):
        if self.__source is None: return False
        return bool(self.__source.get_gain_mode(ch))
    
    @setter
    def set_agc(self, value):
        self.__source.set_gain_mode(bool(value), ch)
    
    @exported_value(type_fn=lambda self: self.__antenna_type)
    def get_antenna(self):
        if self.__source is None: return ''
        return unicode(self.__source.get_antenna(ch))
    
    @setter
    def set_antenna(self, value):
        # TODO we should have a provision for restricting antenna selection when transmit is possible to avoid hardware damage
        self.__source.set_antenna(str(self.__antenna_type(value)), ch)
    
    # Note: dc_cancel has a 'manual' mode we are not yet exposing
    @exported_value(type_fn=lambda self: bool if self.__profile.dc_cancel else Constant(False))
    def get_dc_cancel(self):
        return bool(self.dc_state)
    
    @setter
    def set_dc_cancel(self, value):
        if value:
            mode = DCOffsetAutomatic
        else:
            mode = DCOffsetOff
        self.dc_state = self.__source.set_dc_offset_mode(mode, ch)
    
    # Note: iq_balance has a 'manual' mode we are not yet exposing
    @exported_value(type=bool)  # TODO: detect gr-iqbal
    def get_iq_balance(self):
        return bool(self.iq_state)

    @setter
    def set_iq_balance(self, value):
        if value:
            mode = IQBalanceAutomatic
        else:
            mode = IQBalanceOff
        self.iq_state = self.__source.set_iq_balance_mode(mode, ch)
    
    # add_zero because zero means automatic setting based on sample rate.
    # TODO: Display automaticness in the UI rather than having a zero value.
    @exported_value(type_fn=lambda self: convert_osmosdr_range(
        self.__source.get_bandwidth_range(ch), add_zero=True))
    def get_bandwidth(self):
        if self.__source is None: return 0.0
        return self.__source.get_bandwidth(ch)
    
    @setter
    def set_bandwidth(self, value):
        self.__source.set_bandwidth(float(value), ch)
    
    def notify_reconnecting_or_restarting(self):
        pass

    # link to tx driver
    def _stop_rx(self):
        self.disconnect_all()
        self.__state_while_inactive = self.state_to_json()
        self.__tuning.set_block(None)
        self.__gains.close()
        self.__source = None
        self.connect(self.__placeholder, self)
    
    # link to tx driver
    def _start_rx(self):
        self.disconnect_all()
        self.__source = osmosdr.source('numchan=1 ' + self.__osmo_device)
        self.__source.set_sample_rate(self.__signal_type.get_sample_rate())
        self.__tuning.set_block(self.__source)
        self.__gains = Gains(self.__source)
        self.connect(self.__source, self)
        self.state_from_json(self.__state_while_inactive)
示例#6
0
class _LimeSDRRXDriver(ExportedState, gr.hier_block2):

    # Note: Docs for gr-limesdr are in comments at gr-limesdr/include/limesdr/source.h
    def __init__(self, source, device_type, lna_path, name, tuning,
                 sample_rate):
        gr.hier_block2.__init__(
            self,
            defaultstr('RX ' + name),
            gr.io_signature(0, 0, 0),
            gr.io_signature(1, 1, gr.sizeof_gr_complex * 1),
        )

        self.__source = source
        self.__name = name
        self.__tuning = tuning

        self.connect(self.__source, self)

        # State of the source that there are no getters for, so we must keep our own copy of
        self.__track_gain = 50.
        source.set_gain(int(self.__track_gain), ch)

        self.__track_bandwidth = max(sample_rate / 2, 1.5e6)
        source.set_analog_filter(True, self.__track_bandwidth, ch)

        self.__lna_path_type = EnumT({
            LNANONE: 'None',
            LNAH: 'LNAH',
            LNAL: 'LNAL',
            LNAW: 'LNAW',
        })
        if device_type == LimeSDRMini:
            self.__lna_path_type = EnumT({
                LNAH: 'LNAH',
                LNAW: 'LNAW',
            })
        self.__track_lna_path = lna_path

        self.__signal_type = SignalType(kind='IQ', sample_rate=sample_rate)
        self.__usable_bandwidth = tuning.calc_usable_bandwidth(sample_rate)

    @exported_value(type=SignalType, changes='never')
    def get_output_type(self):
        return self.__signal_type

    # implement IRXDriver
    def get_tune_delay(self):
        # TODO: Measure this.
        return 0.07

    # implement IRXDriver
    def get_usable_bandwidth(self):
        if self.__track_bandwidth:
            return self.__tuning.calc_usable_bandwidth(self.__track_bandwidth)
        return self.__usable_bandwidth

    # implement IRXDriver
    def close(self):
        self.disconnect_all()
        self.__source = None
        self.__tuning = None

    @exported_value(type_fn=lambda self: self.__lna_path_type,
                    changes='this_setter',
                    label='LNA Path')
    def get_lna_path(self):
        return self.__track_lna_path

    @setter
    def set_lna_path(self, lna_path):
        self.__track_lna_path = int(lna_path)
        self.__source.set_lna_path(int(lna_path), ch)

    @exported_value(
        type_fn=lambda self: RangeT([(0, 70)], unit=units.dB, strict=False),
        changes='this_setter',
        label='Gain')
    def get_gain(self):
        if self.__source is None: return 0.0
        return self.__track_gain

    @setter
    def set_gain(self, value):
        self.__track_gain = int(value)
        self.__source.set_gain(int(value), ch)

    # zero means no filter
    @exported_value(type_fn=lambda self: RangeT([(
        1e3, min(130e6, self.__signal_type.get_sample_rate()))],
                                                unit=units.Hz),
                    changes='this_setter',
                    label='Hardware filter',
                    description='Bandwidth of the analog and digital filters.')
    def get_bandwidth(self):
        if self.__source is None: return 0.0
        return self.__track_bandwidth

    @setter
    def set_bandwidth(self, value):
        self.__track_bandwidth = float(value)
        if value == self.__signal_type.get_sample_rate():
            self.__source.set_analog_filter(False, 0, ch)
            self.__source.set_digital_filter(False, 0, ch)
            return
        # Analog filter goes down to 1.5e6, digital filter goes arbitrarily low.
        analog = max(value, 1.5e6)
        self.__source.set_analog_filter(True, float(analog), ch)
        self.__source.set_digital_filter(True, float(value), ch)

    def notify_reconnecting_or_restarting(self):
        pass