def __init__(self, context, mode, angle=0.0): gr.hier_block2.__init__( self, type(self).__name__, gr.io_signature(1, 1, gr.sizeof_float * 1), gr.io_signature(1, 1, gr.sizeof_gr_complex * 1), ) self.__angle = 0.0 # dummy statically visible value will be overwritten # TODO: My signal level parameters are probably wrong because this signal doesn't look like a real VOR signal vor_30 = analog.sig_source_f(self.__audio_rate, analog.GR_COS_WAVE, self.__vor_sig_freq, 1, 0) vor_add = blocks.add_cc(1) vor_audio = blocks.add_ff(1) # Audio/AM signal self.connect( vor_30, blocks.multiply_const_ff(0.3), # M_n (vor_audio, 0)) self.connect( self, blocks.multiply_const_ff(audio_modulation_index), # M_i (vor_audio, 1)) # Carrier component self.connect(analog.sig_source_c(0, analog.GR_CONST_WAVE, 0, 0, 1), (vor_add, 0)) # AM component self.__delay = blocks.delay(gr.sizeof_gr_complex, 0) # configured by set_angle self.connect( vor_audio, make_resampler(self.__audio_rate, self.__rf_rate ), # TODO make a complex version and do this last blocks.float_to_complex(1), self.__delay, (vor_add, 1)) # FM component vor_fm_mult = blocks.multiply_cc(1) self.connect( # carrier generation analog.sig_source_f(self.__rf_rate, analog.GR_COS_WAVE, fm_subcarrier, 1, 0), blocks.float_to_complex(1), (vor_fm_mult, 1)) self.connect( # modulation vor_30, make_resampler(self.__audio_rate, self.__rf_rate), analog.frequency_modulator_fc(2 * math.pi * fm_deviation / self.__rf_rate), blocks.multiply_const_cc(0.3), # M_d vor_fm_mult, (vor_add, 2)) self.connect(vor_add, self) # calculate and initialize delay self.set_angle(angle)
def __init__(self, mode, input_rate, output_rate, demod_class=None, freq=0.0, quiet=False): gr.hier_block2.__init__( self, type(self).__name__, gr.io_signature(1, 1, gr.sizeof_gr_complex), gr.io_signature(2, 2, gr.sizeof_float)) if demod_class is None: mode_def = lookup_mode(mode) if mode_def is None: raise Exception('{}: No demodulator registered for mode {!r}, only {!r}'.format( type(self).__name__, mode, [md.mode for md in get_modes()])) demod_class = mode_def.demod_class context = _DemodulatorAdapterContext(adapter=self, freq=freq) demod = self.__demodulator = IDemodulator(demod_class( mode=mode, input_rate=input_rate, context=context)) self.connect(self, demod) output_type = demod.get_output_type() demod_output_rate = output_type.get_sample_rate() same_rate = demod_output_rate == output_rate stereo = output_type.get_kind() == 'STEREO' # connect outputs, resampling and adapting mono/stereo as needed # TODO: Make the logic for this in receiver.py reusable? if output_type.get_kind() == 'NONE': # TODO: produce correct sample rate of zeroes and maybe a warning dummy = blocks.vector_source_f([]) self.connect(dummy, (self, 0)) self.connect(dummy, (self, 1)) else: if stereo: splitter = blocks.vector_to_streams(gr.sizeof_float, 2) self.connect(demod, splitter) if same_rate: if stereo: self.connect((splitter, 0), (self, 0)) self.connect((splitter, 1), (self, 1)) else: self.connect(demod, (self, 0)) self.connect(demod, (self, 1)) else: if not quiet: gr.log.info(b'{}: Native {} demodulated rate is {}; resampling to {}'.format( type(self).__name__, mode, demod_output_rate, output_rate)) if stereo: self.connect((splitter, 0), make_resampler(demod_output_rate, output_rate), (self, 0)) self.connect((splitter, 1), make_resampler(demod_output_rate, output_rate), (self, 1)) else: resampler = make_resampler(demod_output_rate, output_rate) self.connect(demod, resampler, (self, 0)) self.connect(resampler, (self, 1))
def __init__(self, mode, input_rate, output_rate, demod_class=None, freq=0.0, quiet=False): gr.hier_block2.__init__( self, type(self).__name__, gr.io_signature(1, 1, gr.sizeof_gr_complex), gr.io_signature(2, 2, gr.sizeof_float)) if demod_class is None: mode_def = lookup_mode(mode) if mode_def is None: raise Exception('{}: No demodulator registered for mode {!r}, only {!r}'.format( type(self).__name__, mode, [md.mode for md in get_modes()])) demod_class = mode_def.demod_class context = _DemodulatorAdapterContext(adapter=self, freq=freq) demod = self.__demodulator = IDemodulator(demod_class( mode=mode, input_rate=input_rate, context=context)) self.connect(self, demod) output_type = demod.get_output_type() demod_output_rate = output_type.get_sample_rate() same_rate = demod_output_rate == output_rate stereo = output_type.get_kind() == 'STEREO' # connect outputs, resampling and adapting mono/stereo as needed # TODO: Make the logic for this in receiver.py reusable? if output_type.get_kind() == 'NONE': # TODO: produce correct sample rate of zeroes and maybe a warning dummy = blocks.vector_source_f([]) self.connect(dummy, (self, 0)) self.connect(dummy, (self, 1)) else: if stereo: splitter = blocks.vector_to_streams(gr.sizeof_float, 2) self.connect(demod, splitter) if same_rate: if stereo: self.connect((splitter, 0), (self, 0)) self.connect((splitter, 1), (self, 1)) else: self.connect(demod, (self, 0)) self.connect(demod, (self, 1)) else: if not quiet: gr.log.info('{}: Native {} demodulated rate is {}; resampling to {}'.format( type(self).__name__, mode, demod_output_rate, output_rate)) if stereo: self.connect((splitter, 0), make_resampler(demod_output_rate, output_rate), (self, 0)) self.connect((splitter, 1), make_resampler(demod_output_rate, output_rate), (self, 1)) else: resampler = make_resampler(demod_output_rate, output_rate) self.connect(demod, resampler, (self, 0)) self.connect(resampler, (self, 1))
def __init__(self, context, mode, angle=0.0): gr.hier_block2.__init__( self, 'SimulatedDevice VOR modulator', gr.io_signature(1, 1, gr.sizeof_float * 1), gr.io_signature(1, 1, gr.sizeof_gr_complex * 1), ) self.__angle = 0.0 # dummy statically visible value will be overwritten # TODO: My signal level parameters are probably wrong because this signal doesn't look like a real VOR signal vor_30 = analog.sig_source_f(self.__audio_rate, analog.GR_COS_WAVE, self.__vor_sig_freq, 1, 0) vor_add = blocks.add_cc(1) vor_audio = blocks.add_ff(1) # Audio/AM signal self.connect( vor_30, blocks.multiply_const_ff(0.3), # M_n (vor_audio, 0)) self.connect( self, blocks.multiply_const_ff(audio_modulation_index), # M_i (vor_audio, 1)) # Carrier component self.connect( analog.sig_source_c(0, analog.GR_CONST_WAVE, 0, 0, 1), (vor_add, 0)) # AM component self.__delay = blocks.delay(gr.sizeof_gr_complex, 0) # configured by set_angle self.connect( vor_audio, make_resampler(self.__audio_rate, self.__rf_rate), # TODO make a complex version and do this last blocks.float_to_complex(1), self.__delay, (vor_add, 1)) # FM component vor_fm_mult = blocks.multiply_cc(1) self.connect( # carrier generation analog.sig_source_f(self.__rf_rate, analog.GR_COS_WAVE, fm_subcarrier, 1, 0), blocks.float_to_complex(1), (vor_fm_mult, 1)) self.connect( # modulation vor_30, make_resampler(self.__audio_rate, self.__rf_rate), analog.frequency_modulator_fc(2 * math.pi * fm_deviation / self.__rf_rate), blocks.multiply_const_cc(0.3), # M_d vor_fm_mult, (vor_add, 2)) self.connect( vor_add, self) # calculate and initialize delay self.set_angle(angle)
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)
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)
def __init__(self, mode, input_rate=0, context=None): assert input_rate > 0 assert context is not None gr.hier_block2.__init__( self, str(mode) + ' (FM + Multimon-NG) demodulator', gr.io_signature(1, 1, gr.sizeof_gr_complex * 1), gr.io_signature(1, 1, gr.sizeof_float * 1), ) self.mode = mode self.input_rate = input_rate # FM demod # TODO: Retry telling the NFMDemodulator to have its output rate be pipe_rate instead of using a resampler. Something went wrong when trying that before. Same thing is done in dsd.py self.fm_demod = NFMDemodulator( mode='NFM', input_rate=input_rate, no_audio_filter=True, # don't remove CTCSS tone tau=None) # no deemphasis assert self.fm_demod.get_output_type().get_kind() == 'MONO' fm_audio_rate = self.fm_demod.get_output_type().get_sample_rate() # Subprocess self.mm_demod = APRSDemodulator(context=context) mm_audio_rate = self.mm_demod.get_input_type().get_sample_rate() # Output self.connect(self, self.fm_demod, make_resampler(fm_audio_rate, mm_audio_rate), self.mm_demod, self)
def __init__(self, mode, input_rate=0, context=None): assert input_rate > 0 assert context is not None gr.hier_block2.__init__( self, str(mode) + ' (FM + Multimon-NG) demodulator', gr.io_signature(1, 1, gr.sizeof_gr_complex * 1), gr.io_signature(1, 1, gr.sizeof_float * 1), ) self.mode = mode self.input_rate = input_rate # FM demod # TODO: Retry telling the NFMDemodulator to have its output rate be pipe_rate instead of using a resampler. Something went wrong when trying that before. Same thing is done in dsd.py self.fm_demod = NFMDemodulator( mode='NFM', input_rate=input_rate, no_audio_filter=True, # don't remove CTCSS tone tau=None) # no deemphasis assert self.fm_demod.get_output_type().get_kind() == 'MONO' fm_audio_rate = self.fm_demod.get_output_type().get_sample_rate() # Subprocess self.mm_demod = APRSDemodulator(context=context) mm_audio_rate = self.mm_demod.get_input_type().get_sample_rate() # Output self.connect( self, self.fm_demod, make_resampler(fm_audio_rate, mm_audio_rate), self.mm_demod, self)
def __init__(self, mode, input_rate, output_rate, freq=0.0): gr.hier_block2.__init__(self, type(self).__name__, gr.io_signature(1, 1, gr.sizeof_gr_complex), gr.io_signature(2, 2, gr.sizeof_float)) mode_def = lookup_mode(mode) if mode_def is None: raise Exception( '{}: No demodulator registered for mode {!r}, only {!r}'. format( type(self).__name__, mode, [md.mode for md in get_modes()])) context = _DemodulatorAdapterContext(adapter=self, freq=freq) demod = self.__demodulator = IDemodulator( mode_def.demod_class(mode=mode, input_rate=input_rate, context=context)) self.connect(self, demod) output_type = demod.get_output_type() demod_output_rate = output_type.get_sample_rate() same_rate = demod_output_rate == output_rate stereo = output_type.get_kind() == 'STEREO' # connect outputs, resampling and adapting mono/stereo as needed if same_rate: self.connect((demod, 0), (self, 0)) self.connect((demod, 1 if stereo else 0), (self, 1)) else: gr.log.info( '{}: Native {} demodulated rate is {}; resampling to {}'. format( type(self).__name__, mode, demod_output_rate, output_rate)) if stereo: self.connect((demod, 0), make_resampler(demod_output_rate, output_rate), (self, 0)) self.connect((demod, 1), make_resampler(demod_output_rate, output_rate), (self, 1)) else: resampler = make_resampler(demod_output_rate, output_rate) self.connect((demod, 0), resampler, (self, 0)) self.connect(resampler, (self, 1))
def __connect_with_resampling(self, from_endpoint, from_rate, to_endpoint, to_rate, complex): if from_rate == to_rate: self.connect(from_endpoint, to_endpoint) else: gr.log.info('{}: Resampling {} to {}'.format( type(self).__name__, from_rate, to_rate)) resampler = make_resampler(from_rate, to_rate, complex=complex) self.connect(from_endpoint, resampler, to_endpoint)
def __connect_with_resampling(self, from_endpoint, from_rate, to_endpoint, to_rate, complex): # pylint: disable=redefined-builtin if from_rate == to_rate: self.connect(from_endpoint, to_endpoint) else: gr.log.info(b'{}: Resampling {} to {}'.format( type(self).__name__, from_rate, to_rate)) resampler = make_resampler(from_rate, to_rate, complex=complex) self.connect(from_endpoint, resampler, to_endpoint)
def __init__(self, in_rate, out_rate, vlen, complex=False): # pylint: disable=redefined-builtin vitemsize = gr.sizeof_gr_complex if complex else gr.sizeof_float itemsize = vitemsize * vlen gr.hier_block2.__init__( self, type(self).__name__, gr.io_signature(1, 1, itemsize), gr.io_signature(1, 1, itemsize)) if vlen == 1: self.connect(self, make_resampler(in_rate, out_rate, complex=complex), self) else: splitter = blocks.vector_to_streams(vitemsize, vlen) joiner = blocks.streams_to_vector(vitemsize, vlen) self.connect(self, splitter) for ch in xrange(vlen): self.connect( (splitter, ch), make_resampler(in_rate, out_rate, complex=complex), (joiner, ch)) self.connect(joiner, self)
def __connect_with_resampling(self, from_endpoint, from_rate, to_endpoint, to_rate, complex): # pylint: disable=redefined-builtin if from_rate == to_rate: self.connect(from_endpoint, to_endpoint) else: gr.log.info( defaultstr('{}: Resampling {} to {}'.format( type(self).__name__, from_rate, to_rate))) resampler = make_resampler(from_rate, to_rate, complex=complex) self.connect(from_endpoint, resampler, to_endpoint)
def __init__(self, in_rate, out_rate, vlen, complex=False): # pylint: disable=redefined-builtin vitemsize = gr.sizeof_gr_complex if complex else gr.sizeof_float itemsize = vitemsize * vlen gr.hier_block2.__init__(self, type(self).__name__, gr.io_signature(1, 1, itemsize), gr.io_signature(1, 1, itemsize)) if vlen == 1: self.connect(self, make_resampler(in_rate, out_rate, complex=complex), self) else: splitter = blocks.vector_to_streams(vitemsize, vlen) joiner = blocks.streams_to_vector(vitemsize, vlen) self.connect(self, splitter) for ch in six.moves.range(vlen): self.connect((splitter, ch), make_resampler(in_rate, out_rate, complex=complex), (joiner, ch)) self.connect(joiner, self)
def _make_resampler(self, input_port, input_rate): taps = design_lofi_audio_filter(input_rate, self.__no_audio_filter) if self.audio_rate == input_rate: filt = grfilter.fir_filter_fff(1, taps) self.connect(input_port, filt) return filt elif input_rate % self.audio_rate == 0: filt = grfilter.fir_filter_fff(input_rate // self.audio_rate, taps) self.connect(input_port, filt) return filt else: # TODO: use combined filter and resampler (need to move filter design) filt = grfilter.fir_filter_fff(1, taps) resampler = make_resampler(input_rate, self.audio_rate) self.connect(input_port, filt, resampler) return resampler
def __init__(self, mode, input_rate=0, context=None): assert input_rate > 0 gr.hier_block2.__init__(self, type(self).__name__, gr.io_signature(1, 1, gr.sizeof_gr_complex), gr.io_signature(1, 1, gr.sizeof_float)) # TODO: Retry telling the NFMDemodulator to have its output rate be pipe_rate instead of using a resampler. Something went wrong when trying that before. Same thing is done in multimon.py self.__fm_demod = NFMDemodulator( mode='NFM', input_rate=input_rate, no_audio_filter=True, # don't remove CTCSS tone tau=None) # no deemphasis assert self.__fm_demod.get_output_type().get_kind() == 'MONO' fm_audio_rate = self.__fm_demod.get_output_type().get_sample_rate() self.__output_type = SignalType(kind='MONO', sample_rate=8000) self.connect(self, self.__fm_demod, make_resampler(fm_audio_rate, _demod_rate), dsd_block_ff(), self)
def __init__(self, mode, input_rate=0, uvquality=3, context=None): assert input_rate > 0 gr.hier_block2.__init__( self, type(self).__name__, gr.io_signature(1, 1, gr.sizeof_gr_complex), gr.io_signature(1, 1, gr.sizeof_float)) self.__context = context self.__output_type = SignalType(kind='MONO', sample_rate=8000) self.__uvquality = uvquality # TODO: Retry telling the NFMDemodulator to have its output rate be _demod_rate instead of using a resampler. Something went wrong when trying that before. Same thing is done in multimon.py self.__fm_demod = NFMDemodulator( mode='NFM', input_rate=input_rate, no_audio_filter=True, # don't remove CTCSS tone tau=None) # no deemphasis assert self.__fm_demod.get_output_type().get_kind() == 'MONO' fm_audio_rate = self.__fm_demod.get_output_type().get_sample_rate() self.__resampler = make_resampler(fm_audio_rate, _demod_rate) self.__do_connect(False)
def __init__(self, name, add_transmitters): gr.hier_block2.__init__( self, type(self).__name__ + b' ' + str(name), gr.io_signature(0, 0, 0), gr.io_signature(1, 1, gr.sizeof_gr_complex * 1), ) rf_rate = self.rf_rate audio_rate = self.audio_rate self.__noise_level = -22 self.__transmitters = CellDict(dynamic=True) self.__transmitters_cs = CollectionState(self.__transmitters) self.__bus = blocks.add_vcc(1) self.__channel_model = channels.channel_model( noise_voltage=dB(self.__noise_level), frequency_offset=0, epsilon=1.01, # TODO: expose this parameter # taps=..., # TODO: apply something here? ) self.__rotator = blocks.rotator_cc() self.__throttle = blocks.throttle(gr.sizeof_gr_complex, rf_rate) self.connect(self.__bus, self.__throttle, self.__channel_model, self.__rotator, self) signals = [] def add_modulator(freq, key, mode_or_modulator_ctor, **kwargs): if isinstance(mode_or_modulator_ctor, type): mode = None ctor = mode_or_modulator_ctor else: mode = mode_or_modulator_ctor mode_def = lookup_mode(mode) if mode_def is None: # missing plugin, say return ctor = mode_def.mod_class context = None # TODO implement context modulator = ctor(context=context, mode=mode, **kwargs) tx = _SimulatedTransmitter(modulator, audio_rate, rf_rate, freq) self.connect(audio_signal, tx) signals.append(tx) self.__transmitters[key] = tx # Audio input signal pitch = analog.sig_source_f(audio_rate, analog.GR_SAW_WAVE, -1, 2000, 1000) audio_signal = vco = blocks.vco_f(audio_rate, 1, 1) self.connect(pitch, vco) # Channels if add_transmitters: add_modulator(0.0, 'usb', 'USB') add_modulator(10e3, 'am', 'AM') add_modulator(30e3, 'fm', 'NFM') add_modulator(-30e3, 'vor1', 'VOR', angle=0) add_modulator(-60e3, 'vor2', 'VOR', angle=math.pi / 2) add_modulator( 50e3, 'rtty', 'RTTY', message='The quick brown fox jumped over the lazy dog.\n') add_modulator(80e3, 'chirp', ChirpModulator) if signals: for bus_input, signal in enumerate(signals): self.connect(signal, (self.__bus, bus_input)) else: # kludge up a correct-sample-rate no-op self.connect(audio_signal, blocks.multiply_const_ff(0), make_resampler(audio_rate, rf_rate), blocks.float_to_complex(), self.__bus) self.__signal_type = SignalType(kind='IQ', sample_rate=rf_rate) self.__usable_bandwidth = RangeT([(-rf_rate / 2, rf_rate / 2)])
def connect(self, inputs, outputs): """ Make all new connections (graph.disconnect_all() must have been done) between inputs and outputs. inputs and outputs must be iterables of (sample_rate, block) tuples. """ inputs = list(inputs) outputs = list(outputs) # Determine bus rate. # The bus obviously does not need to be higher than the rate of any bus input, because that would be extraneous data. It also does not need to be higher than the rate of any bus output, because no output has use for the information. max_in_rate = max((rate for rate, _ in inputs)) if len(inputs) > 0 else 0.0 max_out_rate = max((rate for rate, _ in outputs)) if len(outputs) > 0 else 0.0 new_bus_rate = min(max_out_rate, max_in_rate) if new_bus_rate == 0.0: # There are either no inputs or no outputs. Use the other side's rate so we have a well-defined value. new_bus_rate = max(max_out_rate, max_in_rate) if new_bus_rate == 0.0: # There are both no inputs and no outputs. No point in not keeping the old rate (and its resampler cache). new_bus_rate = self.__bus_rate elif new_bus_rate != self.__bus_rate: self.__bus_rate = new_bus_rate self.__resampler_cache.clear() # recreated each time because reusing an add_ff w/ different # input counts fails; TODO: report/fix bug bus_sums = [blocks.add_ff() for _ in self.__channels] in_index = 0 for in_rate, in_block in inputs: if in_rate == self.__bus_rate: for ch in self.__channels: self.__graph.connect((in_block, ch), (bus_sums[ch], in_index)) else: for ch in self.__channels: self.__graph.connect( (in_block, ch), # TODO pool these resamplers make_resampler(in_rate, self.__bus_rate), (bus_sums[ch], in_index), ) in_index += 1 if in_index > 0: # connect output only if there is at least one input if len(outputs) > 0: used_resamplers = set() for out_rate, out_block in outputs: if out_rate == self.__bus_rate: for ch in self.__channels: self.__graph.connect(bus_sums[ch], (out_block, ch)) else: if out_rate not in self.__resampler_cache: # Moderately expensive due to the internals using optfir log.msg("Constructing resampler for audio rate %i" % out_rate) self.__resampler_cache[out_rate] = tuple( make_resampler(self.__bus_rate, out_rate) for _ in self.__channels ) resamplers = self.__resampler_cache[out_rate] used_resamplers.add(resamplers) for ch in self.__channels: self.__graph.connect(resamplers[ch], (out_block, ch)) for resamplers in used_resamplers: for ch in self.__channels: self.__graph.connect(bus_sums[ch], resamplers[ch]) else: # gnuradio requires at least one connected output for ch in self.__channels: self.__graph.connect(bus_sums[ch], blocks.null_sink(gr.sizeof_float))
def connect(self, inputs, outputs): """ Make all new connections (graph.disconnect_all() must have been done) between inputs and outputs. inputs and outputs must be iterables of (sample_rate, block) tuples. """ inputs = list(inputs) outputs = list(outputs) # Determine bus rate. # The bus obviously does not need to be higher than the rate of any bus input, because that would be extraneous data. It also does not need to be higher than the rate of any bus output, because no output has use for the information. max_in_rate = max( (rate for rate, _ in inputs)) if len(inputs) > 0 else 0.0 max_out_rate = max( (rate for rate, _ in outputs)) if len(outputs) > 0 else 0.0 new_bus_rate = min(max_out_rate, max_in_rate) if new_bus_rate == 0.0: # There are either no inputs or no outputs. Use the other side's rate so we have a well-defined value. new_bus_rate = max(max_out_rate, max_in_rate) if new_bus_rate == 0.0: # There are both no inputs and no outputs. No point in not keeping the old rate (and its resampler cache). new_bus_rate = self.__bus_rate elif new_bus_rate != self.__bus_rate: self.__bus_rate = new_bus_rate self.__resampler_cache.clear() # recreated each time because reusing an add_ff w/ different # input counts fails; TODO: report/fix bug bus_sums = [blocks.add_ff() for _ in self.__channels] in_index = 0 for in_rate, in_block in inputs: if in_rate == self.__bus_rate: for ch in self.__channels: self.__graph.connect((in_block, ch), (bus_sums[ch], in_index)) else: for ch in self.__channels: self.__graph.connect( (in_block, ch), # TODO pool these resamplers make_resampler(in_rate, self.__bus_rate), (bus_sums[ch], in_index)) in_index += 1 if in_index > 0: # connect output only if there is at least one input if len(outputs) > 0: used_resamplers = set() for out_rate, out_block in outputs: if out_rate == self.__bus_rate: for ch in self.__channels: self.__graph.connect(bus_sums[ch], (out_block, ch)) else: if out_rate not in self.__resampler_cache: # Moderately expensive due to the internals using optfir log.msg( 'Constructing resampler for audio rate %i' % out_rate) self.__resampler_cache[out_rate] = tuple( make_resampler(self.__bus_rate, out_rate) for _ in self.__channels) resamplers = self.__resampler_cache[out_rate] used_resamplers.add(resamplers) for ch in self.__channels: self.__graph.connect(resamplers[ch], (out_block, ch)) for resamplers in used_resamplers: for ch in self.__channels: self.__graph.connect(bus_sums[ch], resamplers[ch]) else: # gnuradio requires at least one connected output for ch in self.__channels: self.__graph.connect(bus_sums[ch], blocks.null_sink(gr.sizeof_float))
def __init__(self, name, add_transmitters): gr.hier_block2.__init__( self, defaultstr(type(self).__name__ + ' ' + name), gr.io_signature(0, 0, 0), gr.io_signature(1, 1, gr.sizeof_gr_complex * 1), ) rf_rate = self.rf_rate audio_rate = self.audio_rate self.__noise_level = -22 self.__transmitters = CellDict(dynamic=True) self.__transmitters_cs = CollectionState(self.__transmitters) self.__bus = blocks.add_vcc(1) self.__channel_model = channels.channel_model( noise_voltage=dB(self.__noise_level), frequency_offset=0, epsilon=1.01, # TODO: expose this parameter # taps=..., # TODO: apply something here? ) self.__rotator = blocks.rotator_cc() self.__throttle = blocks.throttle(gr.sizeof_gr_complex, rf_rate) self.connect( self.__bus, self.__throttle, self.__channel_model, self.__rotator, self) signals = [] def add_modulator(freq, key, mode_or_modulator_ctor, **kwargs): if isinstance(mode_or_modulator_ctor, type): mode = None ctor = mode_or_modulator_ctor else: mode = mode_or_modulator_ctor mode_def = lookup_mode(mode) if mode_def is None: # missing plugin, say return ctor = mode_def.mod_class context = None # TODO implement context modulator = ctor(context=context, mode=mode, **kwargs) tx = _SimulatedTransmitter(modulator, audio_rate, rf_rate, freq) self.connect(audio_signal, tx) signals.append(tx) self.__transmitters[key] = tx # Audio input signal pitch = analog.sig_source_f(audio_rate, analog.GR_SAW_WAVE, -1, 2000, 1000) audio_signal = vco = blocks.vco_f(audio_rate, 1, 1) self.connect(pitch, vco) # Channels if add_transmitters: add_modulator(0.0, 'usb', 'USB') add_modulator(10e3, 'am', 'AM') add_modulator(30e3, 'fm', 'NFM') add_modulator(50e3, 'rtty', 'RTTY', message='The quick brown fox jumped over the lazy dog.\n') add_modulator(80e3, 'chirp', ChirpModulator) if signals: for bus_input, signal in enumerate(signals): self.connect(signal, (self.__bus, bus_input)) else: # kludge up a correct-sample-rate no-op self.connect( audio_signal, blocks.multiply_const_ff(0), make_resampler(audio_rate, rf_rate), blocks.float_to_complex(), self.__bus) self.__signal_type = SignalType( kind='IQ', sample_rate=rf_rate) self.__usable_bandwidth = RangeT([(-rf_rate / 2, rf_rate / 2)])