def test_012_disconnect_input(self): hblock = gr.hier_block2("test_block", gr.io_signature(1,1,gr.sizeof_int), gr.io_signature(1,1,gr.sizeof_int)) nop1 = blocks.nop(gr.sizeof_int) hblock.connect(hblock, nop1) hblock.disconnect(hblock, nop1)
def __init__(self): gr.hier_block2.__init__( self, "NBFM Chain", gr.io_signature(1, 1, gr.sizeof_gr_complex*1), gr.io_signature(1, 1, gr.sizeof_float*1), ) ################################################## # Blocks ################################################## self.rational_resampler_xxx_0 = filter.rational_resampler_ccc( interpolation=192000, decimation=2400000, taps=None, fractional_bw=None, ) self.low_pass_filter_1 = filter.fir_filter_ccf(1, firdes.low_pass( 1, 192000, 5e3, 5e3, firdes.WIN_HAMMING, 6.76)) self.blocks_multiply_const_vxx_0 = blocks.multiply_const_vff((5, )) self.analog_nbfm_rx_0 = analog.nbfm_rx( audio_rate=48000, quad_rate=192000, tau=75e-6, max_dev=2.5e3, ) ################################################## # Connections ################################################## self.connect((self.analog_nbfm_rx_0, 0), (self.blocks_multiply_const_vxx_0, 0)) self.connect((self.blocks_multiply_const_vxx_0, 0), (self, 0)) self.connect((self.low_pass_filter_1, 0), (self.analog_nbfm_rx_0, 0)) self.connect((self, 0), (self.rational_resampler_xxx_0, 0)) self.connect((self.rational_resampler_xxx_0, 0), (self.low_pass_filter_1, 0))
def __init__(self, size, factor, itemsize=gr.sizeof_gr_complex): """ size: (int) vector size (FFT size) of next block factor: (int) output will have this many more samples than input If size is not divisible by factor, then the output will necessarily have jitter. """ size = int(size) factor = int(factor) # assert size % factor == 0 offset = size // factor gr.hier_block2.__init__( self, type(self).__name__, gr.io_signature(1, 1, itemsize), gr.io_signature(1, 1, itemsize), ) if factor == 1: # No duplication needed; simplify flowgraph # GR refused to connect self to self, so insert a dummy block self.connect(self, blocks.copy(itemsize), self) else: interleave = blocks.interleave(itemsize * size) self.connect( interleave, blocks.vector_to_stream(itemsize, size), self) for i in xrange(0, factor): self.connect( self, blocks.delay(itemsize, (factor - 1 - i) * offset), blocks.stream_to_vector(itemsize, size), (interleave, i))
def test_016_disconnect_output(self): hblock = gr.hier_block2("test_block", gr.io_signature(1,1,gr.sizeof_int), gr.io_signature(1,1,gr.sizeof_int)) nop1 = blocks.nop(gr.sizeof_int) hblock.connect(nop1, hblock) hblock.disconnect(nop1, hblock)
def __init__(self, fft_length, occupied_tones, carrier_map_bin): """ Hierarchical block for receiving OFDM symbols. """ gr.hier_block2.__init__(self, "ncofdm_filt", gr.io_signature(1, 1, gr.sizeof_gr_complex), gr.io_signature(1, 1, gr.sizeof_gr_complex)) # Input signature # fft length, e.g. 256 self._fft_length = fft_length # the number of used subcarriers, e.g. 240 self._occupied_tones = occupied_tones # a binary array indicates the used subcarriers self._carrier_map_bin = carrier_map_bin # setup filter banks self.chan_filt_low = filter.fft_filter_ccc(1,[1]) self.chan_filt_high1 = filter.fft_filter_ccc(1,[1]) self.chan_filt_high2 = filter.fft_filter_ccc(1,[1]) self.chan_filt_high3 = filter.fft_filter_ccc(1,[1]) self.chan_filt_high4 = filter.fft_filter_ccc(1,[1]) self.chan_filt_high5 = filter.fft_filter_ccc(1,[1]) # calculate the filter taps filt_num = self.calc_filter_taps(2, 0) # signals run into a serial of filters, one lowpass filter and 5 highpass filters self.connect(self, self.chan_filt_high1, self.chan_filt_high2, self.chan_filt_high3, self.chan_filt_high4, self.chan_filt_high5, self.chan_filt_low, self)
def __init__(self, access_code='', threshold=-1, callback=None, verbose=0): """ packet_demod constructor. @param access_code AKA sync vector @param threshold detect access_code with up to threshold bits wrong (0 -> use default) @param callback a function of args: ok, payload """ #access code if not access_code: #get access code access_code = packet_utils.default_access_code if not packet_utils.is_1_0_string(access_code): raise ValueError, "Invalid access_code %r. Must be string of 1's and 0's" % (access_code,) self._access_code = access_code #threshold if threshold < 0: threshold = DEFAULT_THRESHOLD self._threshold = threshold #blocks msgq = gr.msg_queue(DEFAULT_MSGQ_LIMIT) #holds packets from the PHY correlator = digital.correlate_access_code_bb(self._access_code, self._threshold) framer_sink = logitech_27mhz_transceiver.framer_sink(msgq) #initialize hier2 gr.hier_block2.__init__( self, "packet_decoder", gr.io_signature(1, 1, gr.sizeof_char), # Input signature gr.io_signature(0, 0, 0) # Output signature ) #connect self.connect(self, correlator, framer_sink) #start thread _packet_decoder_thread(msgq, callback,verbose)
def __init__(self, samples_per_symbol, bits_per_symbol, access_code='', pad_for_usrp=True, kbid='', verbose=0): """ packet_mod constructor. @param samples_per_symbol number of samples per symbol @param bits_per_symbol number of bits per symbol @param access_code AKA sync vector @param pad_for_usrp If true, packets are padded such that they end up a multiple of 128 samples @param payload_length number of bytes in a data-stream slice """ #setup parameters self._samples_per_symbol = samples_per_symbol self._bits_per_symbol = bits_per_symbol self._kbid = kbid self._verbose = verbose if not access_code: #get access code access_code = packet_utils.default_access_code if not packet_utils.is_1_0_string(access_code): raise ValueError, "Invalid access_code %r. Must be string of 1's and 0's" % (access_code,) self._access_code = access_code self._pad_for_usrp = pad_for_usrp #create blocks msg_source = gr.message_source(gr.sizeof_char, DEFAULT_MSGQ_LIMIT) self._msgq_out = msg_source.msgq() #initialize hier2 gr.hier_block2.__init__( self, "packet_encoder", gr.io_signature(0, 0, 0), # Input signature gr.io_signature(1, 1, gr.sizeof_char) # Output signature ) #connect self.connect(msg_source, self)
def __init__(self, sample_rate, symbol_rate): gr.hier_block2.__init__(self, "dvb_s_demodulator_cc", gr.io_signature(1, 1, gr.sizeof_gr_complex), # Input signature gr.io_signature(1, 1, gr.sizeof_gr_complex)) # Output signature omega = sample_rate / symbol_rate gain_omega = omega * omega / 4.0 freq_beta = freq_alpha * freq_alpha / 4.0 mu = 0.0 gain_mu = 0.05 omega_relative_limit = 0.005 # Automatic gain control self.agc = gr.agc2_cc( 0.06, # Attack rate 0.001, # Decay rate 1, # Reference 1, # Initial gain 100) # Max gain # Frequency correction with band-edge filters FLL freq_beta = freq_alpha * freq_alpha / 4 self.freq_recov = digital.fll_band_edge_cc(omega, dvb_swig.RRC_ROLLOFF_FACTOR, 11 * int(omega), freq_bw) self.freq_recov.set_alpha(freq_alpha) self.freq_recov.set_beta(freq_beta) self.receiver = digital.mpsk_receiver_cc(M, 0, freq_bw, fmin, fmax, mu, gain_mu, omega, gain_omega, omega_relative_limit) self.receiver.set_alpha(freq_alpha) self.receiver.set_beta(freq_beta) self.rotate = gr.multiply_const_cc(0.707 + 0.707j) self.connect(self, self.agc, self.freq_recov, self.receiver, self.rotate, self)
def __init__(self, bitrate, constellation, samples_per_symbol, differential, excess_bw, gray_coded, freq_bw, timing_bw, phase_bw, verbose, log): gr.hier_block2.__init__(self, "bert_receive", gr.io_signature(1, 1, gr.sizeof_gr_complex), # Input signature gr.io_signature(0, 0, 0)) # Output signature self._bitrate = bitrate self._demod = digital.generic_demod(constellation, differential, samples_per_symbol, gray_coded, excess_bw, freq_bw, timing_bw, phase_bw, verbose, log) self._symbol_rate = self._bitrate / self._demod.bits_per_symbol() self._sample_rate = self._symbol_rate * samples_per_symbol # Add an SNR probe on the demodulated constellation self._snr_probe = digital.probe_mpsk_snr_est_c(digital.SNR_EST_M2M4, 1000, alpha=10.0/self._symbol_rate) self.connect(self._demod.time_recov, self._snr_probe) # Descramble BERT sequence. A channel error will create 3 incorrect bits self._descrambler = digital.descrambler_bb(0x8A, 0x7F, 7) # CCSDS 7-bit descrambler # Measure BER by the density of 0s in the stream self._ber = digital.probe_density_b(1.0/self._symbol_rate) self.connect(self, self._demod, self._descrambler, self._ber)
def __init__(self, input_is_real=False, baseband_freq=0, y_per_div=10, ref_level=50, sample_rate=1, fac_size=512, fac_rate=default_fac_rate, average=False, avg_alpha=None, title='', peak_hold=False): self._item_size = gr.sizeof_gr_complex if input_is_real: self._item_size = gr.sizeof_float gr.hier_block2.__init__( self, "Fast AutoCorrelation", gr.io_signature(1, 1, self._item_size), gr.io_signature(0, 0, 0), ) # initialize common attributes self.baseband_freq = baseband_freq self.y_divs = 8 self.y_per_div=y_per_div self.ref_level = ref_level self.sample_rate = sample_rate self.fac_size = fac_size self.fac_rate = fac_rate self.average = average if (avg_alpha is None) or (avg_alpha <= 0): self.avg_alpha = 0.20 / fac_rate # averaging needed to be slowed down for very slow rates else: self.avg_alpha = avg_alpha self.title = title self.peak_hold = peak_hold self.input_is_real = input_is_real self.msgq = gr.msg_queue(2) # queue that holds a maximum of 2 messages
def __init__(self, device_name, sample_rate, channel_mapping, audio_module): self.__device_name = device_name self.__sample_rate = sample_rate self.__signal_type = SignalType( # TODO: type should be able to be LSB kind='IQ' if len(channel_mapping) == 2 else 'USB', sample_rate=self.__sample_rate) gr.hier_block2.__init__( self, type(self).__name__, gr.io_signature(1, 1, gr.sizeof_gr_complex * 1), gr.io_signature(0, 0, 0), ) sink = audio_module.sink( self.__sample_rate, device_name=self.__device_name, ok_to_block=True) # TODO: ignoring channel_mapping parameter, shouldn't be split = blocks.complex_to_float(1) self.connect(self, split, (sink, 0)) self.connect((split, 1), (sink, 1))
def __init__(self, interp, taps=None, atten=100): gr.hier_block2.__init__(self, "pfb_interpolator_ccf", gr.io_signature(1, 1, gr.sizeof_gr_complex), gr.io_signature(1, 1, gr.sizeof_gr_complex)) self._interp = interp self._taps = taps if (taps is not None) and (len(taps) > 0): self._taps = taps else: # Create a filter that covers the full bandwidth of the input signal bw = 0.4 tb = 0.2 ripple = 0.99 made = False while not made: try: self._taps = optfir.low_pass(self._interp, self._interp, bw, bw+tb, ripple, atten) made = True except RuntimeError: ripple += 0.01 made = False print("Warning: set ripple to %.4f dB. If this is a problem, adjust the attenuation or create your own filter taps." % (ripple)) # Build in an exit strategy; if we've come this far, it ain't working. if(ripple >= 1.0): raise RuntimeError("optfir could not generate an appropriate filter.") self.pfb = filter.pfb_interpolator_ccf(self._interp, self._taps) self.connect(self, self.pfb) self.connect(self.pfb, self)
def __init__(self, mode, input_rate=0, context=None): assert input_rate > 0 self.__input_rate = input_rate gr.hier_block2.__init__( self, 'RTTY demodulator', gr.io_signature(1, 1, gr.sizeof_gr_complex * 1), gr.io_signature(1, 1, gr.sizeof_float * 1)) channel_filter = self.__make_channel_filter() self.__text = u'' self.__char_queue = gr.msg_queue(limit=100) self.__char_sink = blocks.message_sink(gr.sizeof_char, self.__char_queue, True) self.connect( self, channel_filter, self.__make_demodulator(), self.__char_sink) self.connect( channel_filter, self.__make_audio_filter(), blocks.rotator_cc(rotator_inc(self.__demod_rate, 2000 + self.__spacing / 2)), blocks.complex_to_real(vlen=1), analog.agc2_ff( reference=dB(-10), attack_rate=8e-1, decay_rate=8e-1), self)
def __init__(self, rate, taps=None, flt_size=32, atten=100): gr.hier_block2.__init__(self, "pfb_arb_resampler_ccc", gr.io_signature(1, 1, gr.sizeof_gr_complex), # Input signature gr.io_signature(1, 1, gr.sizeof_gr_complex)) # Output signature self._rate = rate self._size = flt_size if (taps is not None) and (len(taps) > 0): self._taps = taps else: # Create a filter that covers the full bandwidth of the input signal bw = 0.4 tb = 0.2 ripple = 0.1 #self._taps = filter.firdes.low_pass_2(self._size, self._size, bw, tb, atten) made = False while not made: try: self._taps = optfir.low_pass(self._size, self._size, bw, bw+tb, ripple, atten) made = True except RuntimeError: ripple += 0.01 made = False print("Warning: set ripple to %.4f dB. If this is a problem, adjust the attenuation or create your own filter taps." % (ripple)) # Build in an exit strategy; if we've come this far, it ain't working. if(ripple >= 1.0): raise RuntimeError("optfir could not generate an appropriate filter.") self.pfb = filter.pfb_arb_resampler_ccc(self._rate, self._taps, self._size) #print "PFB has %d taps\n" % (len(self._taps),) self.connect(self, self.pfb) self.connect(self.pfb, self)
def __init__(self, n_chans, n_filterbanks=1, taps=None, outchans=None, atten=100, bw=1.0, tb=0.2, ripple=0.1): if n_filterbanks > n_chans: n_filterbanks = n_chans if outchans is None: outchans = range(n_chans) gr.hier_block2.__init__( self, "pfb_channelizer_hier_ccf", gr.io_signature(1, 1, gr.sizeof_gr_complex), gr.io_signature(len(outchans), len(outchans), gr.sizeof_gr_complex)) if taps is None: taps = optfir.low_pass(1, n_chans, bw, bw+tb, ripple, atten) taps = list(taps) extra_taps = int(math.ceil(1.0*len(taps)/n_chans)*n_chans - len(taps)) taps = taps + [0] * extra_taps # Make taps for each channel chantaps = [list(reversed(taps[i: len(taps): n_chans])) for i in range(0, n_chans)] # Convert the input stream into a stream of vectors. self.s2v = blocks.stream_to_vector(gr.sizeof_gr_complex, n_chans) # Create a mapping to separate out each filterbank (a group of channels to be processed together) # And a list of sets of taps for each filterbank. low_cpp = int(n_chans/n_filterbanks) extra = n_chans - low_cpp*n_filterbanks cpps = [low_cpp+1]*extra + [low_cpp]*(n_filterbanks-extra) splitter_mapping = [] filterbanktaps = [] total = 0 for cpp in cpps: splitter_mapping.append([(0, i) for i in range(total, total+cpp)]) filterbanktaps.append(chantaps[total: total+cpp]) total += cpp assert(total == n_chans) # Split the stream of vectors in n_filterbanks streams of vectors. self.splitter = blocks.vector_map(gr.sizeof_gr_complex, [n_chans], splitter_mapping) # Create the filterbanks self.fbs = [filter.filterbank_vcvcf(taps) for taps in filterbanktaps] # Combine the streams of vectors back into a single stream of vectors. combiner_mapping = [[]] for i, cpp in enumerate(cpps): for j in range(cpp): combiner_mapping[0].append((i, j)) self.combiner = blocks.vector_map(gr.sizeof_gr_complex, cpps, combiner_mapping) # Add the final FFT to the channelizer. self.fft = fft.fft_vcc(n_chans, forward=True, window=[1.0]*n_chans) # Select the desired channels if outchans != range(n_chans): selector_mapping = [[(0, i) for i in outchans]] self.selector = blocks.vector_map(gr.sizeof_gr_complex, [n_chans], selector_mapping) # Convert stream of vectors to a normal stream. self.v2ss = blocks.vector_to_streams(gr.sizeof_gr_complex, len(outchans)) self.connect(self, self.s2v, self.splitter) for i in range(0, n_filterbanks): self.connect((self.splitter, i), self.fbs[i], (self.combiner, i)) self.connect(self.combiner, self.fft) if outchans != range(n_chans): self.connect(self.fft, self.selector, self.v2ss) else: self.connect(self.fft, self.v2ss) for i in range(0, len(outchans)): self.connect((self.v2ss, i), (self, i))
def __init__(self, sps, channel_decim, channel_taps, options, usrp_rate, channel_rate, lo_freq): gr.hier_block2.__init__(self, "rx_channel_cqpsk", gr.io_signature(1, 1, gr.sizeof_gr_complex), gr.io_signature(1, 1, gr.sizeof_float)) chan = gr.freq_xlating_fir_filter_ccf(int(channel_decim), channel_taps, lo_freq, usrp_rate) agc = gr.feedforward_agc_cc(16, 1.0) gain_omega = 0.125 * options.gain_mu * options.gain_mu alpha = options.costas_alpha beta = 0.125 * alpha * alpha fmin = -0.025 fmax = 0.025 clock = repeater.gardner_costas_cc(sps, options.gain_mu, gain_omega, alpha, beta, fmax, fmin) # Perform Differential decoding on the constellation diffdec = gr.diff_phasor_cc() # take angle of the difference (in radians) to_float = gr.complex_to_arg() # convert from radians such that signal is in -3/-1/+1/+3 rescale = gr.multiply_const_ff( (1 / (pi / 4)) ) self.connect (self, chan, agc, clock, diffdec, to_float, rescale, self)
def __init__(self, sps, channel_decim, channel_taps, options, usrp_rate, channel_rate, lo_freq, max_dev, ctcss): gr.hier_block2.__init__(self, "rx_channel_nfm", gr.io_signature(1, 1, gr.sizeof_gr_complex), # gr.io_signature(0, 0, 0)) gr.io_signature(1, 1, gr.sizeof_float)) output_sample_rate = 8000 chan = gr.freq_xlating_fir_filter_ccf(int(channel_decim), channel_taps, lo_freq, usrp_rate) nphases = 32 frac_bw = 0.45 rs_taps = gr.firdes.low_pass(nphases, nphases, frac_bw, 0.5-frac_bw) resampler = blks2.pfb_arb_resampler_ccf( float(output_sample_rate)/channel_rate, (rs_taps), nphases ) # FM Demodulator input: complex; output: float k = output_sample_rate/(2*math.pi*max_dev) fm_demod = gr.quadrature_demod_cf(k) self.connect (self, chan, resampler, fm_demod) if ctcss > 0: level = 5.0 len = 0 ramp = 0 gate = True ctcss = repeater.ctcss_squelch_ff(output_sample_rate, ctcss, level, len, ramp, gate) self.connect (fm_demod, ctcss, self) else: self.connect (fm_demod, 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, sps, channel_decim, channel_taps, options, usrp_rate, channel_rate, lo_freq): gr.hier_block2.__init__(self, "rx_channel_fm", gr.io_signature(1, 1, gr.sizeof_gr_complex), gr.io_signature(1, 1, gr.sizeof_float)) chan = gr.freq_xlating_fir_filter_ccf(int(channel_decim), channel_taps, lo_freq, usrp_rate) symbol_decim = 1 symbol_rate = 4800 self.symbol_deviation = 600.0 fm_demod_gain = channel_rate / (2.0 * pi * self.symbol_deviation) fm_demod = gr.quadrature_demod_cf(fm_demod_gain) symbol_coeffs = gr.firdes_root_raised_cosine(1.0, channel_rate, symbol_rate, 1.0, 51) symbol_filter = gr.fir_filter_fff(symbol_decim, symbol_coeffs) # C4FM demodulator autotuneq = gr.msg_queue(2) demod_fsk4 = fsk4.demod_ff(autotuneq, channel_rate, symbol_rate) self.connect (self, chan, fm_demod, symbol_filter, demod_fsk4, self)
def __init__(self, options): gr.hier_block2.__init__(self, "ais_demod", gr.io_signature(1, 1, gr.sizeof_gr_complex), # Input signature gr.io_signature(1, 1, gr.sizeof_char)) # Output signature self._samples_per_symbol = options[ "samples_per_symbol" ] self._bits_per_sec = options[ "bits_per_sec" ] self._samplerate = self._samples_per_symbol * self._bits_per_sec self._clockrec_gain = options[ "clockrec_gain" ] self._omega_relative_limit = options[ "omega_relative_limit" ] self.fftlen = options[ "fftlen" ] self.freq_sync = gmsk_sync.square_and_fft_sync_cc(self._samplerate, self._bits_per_sec, self.fftlen) self.agc = analog.feedforward_agc_cc(512, 2) self.preamble = [1,1,0,0]*7 self.mod = digital.gmsk_mod(self._samples_per_symbol, 0.4) self.mod_vector = ais.modulate_vector_bc(self.mod.to_basic_block(), self.preamble, [1]) self.preamble_detect = ais.corr_est_cc(self.mod_vector, self._samples_per_symbol, 1, #mark delay 0.9) #threshold self.clockrec = ais.msk_timing_recovery_cc(self._samples_per_symbol, self._clockrec_gain, #gain self._omega_relative_limit, #error lim 1) #output sps sensitivity = (math.pi / 2) self.demod = analog.quadrature_demod_cf(sensitivity) #param is gain self.slicer = digital.binary_slicer_fb() self.diff = digital.diff_decoder_bb(2) self.invert = ais.invert() #NRZI signal diff decoded and inverted should give original signal # self.connect(self, self.gmsk_sync) self.connect(self, self.freq_sync, self.agc, (self.preamble_detect, 0), self.clockrec, self.demod, self.slicer, self.diff, self.invert, self)
def __init__(self, mode, input_rate, output_rate, mod_class=None): gr.hier_block2.__init__( self, type(self).__name__, gr.io_signature(1, 1, gr.sizeof_float), gr.io_signature(1, 1, gr.sizeof_gr_complex)) if mod_class is None: mode_def = lookup_mode(mode) if mode_def is None: raise Exception('{}: No modulator registered for mode {!r}, only {!r}'.format( type(self).__name__, mode, [md.mode for md in get_modes() if md.mod_class])) mod_class = mode_def.mod_class context = _ModulatorAdapterContext(adapter=self) modulator = self.__modulator = IModulator(mod_class( mode=mode, context=context)) self.__connect_with_resampling( self, input_rate, modulator, modulator.get_input_type().get_sample_rate(), False) self.__connect_with_resampling( modulator, modulator.get_output_type().get_sample_rate(), self, output_rate, True)
def __init__(self, device_name, sample_rate, quadrature_as_stereo): self.__device_name = device_name self.__sample_rate = sample_rate self.__quadrature_as_stereo = quadrature_as_stereo if self.__quadrature_as_stereo: self.__signal_type = SignalType( kind='IQ', sample_rate=self.__sample_rate) else: self.__signal_type = SignalType( kind='USB', # TODO obtain correct type from config (or say hamlib) sample_rate=self.__sample_rate) 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) combine = blocks.float_to_complex(1) self.connect(self.__source, combine, self) if self.__quadrature_as_stereo: # if we don't do this, the imaginary component is 0 and the spectrum is symmetric self.connect((self.__source, 1), (combine, 1))
def __init__(self, sps, # Samples per symbol excess_bw, # RRC filter excess bandwidth (typically 0.35-0.5) amplitude, # DAC output level, 0-32767, typically 2000-8000 vector_source, # Indicate if it's the infinite sequence of 1, or by use the code to change the amplitude ): gr.hier_block2.__init__(self, "bpsk_modulator", gr.io_signature(0, 0, 0), # Input signature gr.io_signature(1, 1, gr.sizeof_gr_complex)) # Output signature # Create BERT data bit stream self.vector_source = vector_source self._scrambler = gr.scrambler_bb(0x8A, 0x7F, 31) # CCSDS 7-bit scrambler # Map to constellation self._constellation = [-1+0j, 1+0j] self._mapper = gr.chunks_to_symbols_bc(self._constellation) # Create RRC with specified excess bandwidth taps = gr.firdes.root_raised_cosine(sps, # Gain sps, # Sampling rate 1.0, # Symbol rate excess_bw, # Roll-off factor 11*sps) # Number of taps self._rrc = gr.interp_fir_filter_ccf(sps, # Interpolation rate taps) # FIR taps self.amp = gr.multiply_const_cc(amplitude) # Wire block inputs and outputs self.connect(self.vector_source, self._scrambler, self._mapper, self._rrc, self.amp, self)
def test_005_connect_invalid_src_port_exceeds(self): hblock = gr.hier_block2("test_block", gr.io_signature(1,1,gr.sizeof_int), gr.io_signature(1,1,gr.sizeof_int)) nop1 = blocks.nop(gr.sizeof_int) self.assertRaises(RuntimeError, lambda: hblock.connect((hblock, 1), nop1))
def __init__(self, queue, freq=0.0, verbose=False, log=False): gr.hier_block2.__init__(self, "flex_demod", gr.io_signature(1, 1, gr.sizeof_gr_complex), gr.io_signature(0,0,0)) k = 25000/(2*pi*1600) # 4800 Hz max deviation quad = gr.quadrature_demod_cf(k) self.connect(self, quad) rsamp = blks2.rational_resampler_fff(16, 25) self.slicer = pager_swig.slicer_fb(5e-6) # DC removal averaging filter constant self.sync = pager_swig.flex_sync() self.connect(quad, rsamp, self.slicer, self.sync) for i in range(4): self.connect((self.sync, i), pager_swig.flex_deinterleave(), pager_swig.flex_parse(queue, freq)) if log: suffix = '_'+ "%3.3f" % (freq/1e6,) + '.dat' quad_sink = gr.file_sink(gr.sizeof_float, 'quad'+suffix) rsamp_sink = gr.file_sink(gr.sizeof_float, 'rsamp'+suffix) slicer_sink = gr.file_sink(gr.sizeof_char, 'slicer'+suffix) self.connect(rsamp, rsamp_sink) self.connect(quad, quad_sink) self.connect(self.slicer, slicer_sink)
def test_024_disconnect_single(self): hblock = gr.top_block("test_block") blk = gr.hier_block2("block", gr.io_signature(0, 0, 0), gr.io_signature(0, 0, 0)) hblock.connect(blk) hblock.disconnect(blk)
def test_025_disconnect_single_not_connected(self): hblock = gr.top_block("test_block") blk = gr.hier_block2("block", gr.io_signature(0, 0, 0), gr.io_signature(0, 0, 0)) self.assertRaises(RuntimeError, lambda: hblock.disconnect(blk))
def __init__(self, dest, key): gr.hier_block2.__init__( self, self.__class__.__name__, gr.io_signature(1, 1, gr.sizeof_gr_complex * 1), gr.io_signature(1, 1, gr.sizeof_gr_complex * 1)) self.__dest = dest self.__key = key
def test_022_connect_single_with_ports(self): hblock = gr.top_block("test_block") blk = gr.hier_block2("block", gr.io_signature(1, 1, 1), gr.io_signature(1, 1, 1)) self.assertRaises(RuntimeError, lambda: hblock.connect(blk))
def __init__(self, device_name, sample_rate, quadrature_as_stereo): self.__device_name = device_name self.__sample_rate = sample_rate self.__quadrature_as_stereo = quadrature_as_stereo self.__signal_type = SignalType( # TODO: type should be able to be LSB kind='IQ' if quadrature_as_stereo else 'USB', sample_rate=self.__sample_rate) gr.hier_block2.__init__( self, type(self).__name__, gr.io_signature(1, 1, gr.sizeof_gr_complex * 1), gr.io_signature(0, 0, 0), ) sink = audio.sink( self.__sample_rate, device_name=self.__device_name, ok_to_block=True) split = blocks.complex_to_float(1) self.connect(self, split, (sink, 0)) self.connect((split, 1), (sink, 1))
def __init__(self, samples_per_symbol=_def_samples_per_symbol, excess_bw=_def_excess_bw, gray_code=_def_gray_code, verbose=_def_verbose, log=_def_log): """ Hierarchical block for RRC-filtered QPSK modulation. The input is a byte stream (unsigned char) and the output is the complex modulated signal at baseband. @param samples_per_symbol: samples per symbol >= 2 @type samples_per_symbol: integer @param excess_bw: Root-raised cosine filter excess bandwidth @type excess_bw: float @param gray_code: Tell modulator to Gray code the bits @type gray_code: bool @param verbose: Print information about modulator? @type verbose: bool @param debug: Print modualtion data to files? @type debug: bool """ gr.hier_block2.__init__( self, "qam64_mod", gr.io_signature(1, 1, gr.sizeof_char), # Input signature gr.io_signature(1, 1, gr.sizeof_gr_complex)) # Output signature self._samples_per_symbol = samples_per_symbol self._excess_bw = excess_bw self._gray_code = gray_code if not isinstance(samples_per_symbol, int) or samples_per_symbol < 2: raise TypeError, ("sbp must be an integer >= 2, is %d" % samples_per_symbol) ntaps = 11 * samples_per_symbol arity = pow(2, self.bits_per_symbol()) # turn bytes into k-bit vectors self.bytes2chunks = \ gr.packed_to_unpacked_bb(self.bits_per_symbol(), gr.GR_MSB_FIRST) if self._gray_code: self.symbol_mapper = gr.map_bb(qam.binary_to_gray[arity]) else: self.symbol_mapper = gr.map_bb(qam.binary_to_ungray[arity]) self.diffenc = gr.diff_encoder_bb(arity) rot = 1.0 print "constellation with %d arity" % arity rotated_const = map(lambda pt: pt * rot, qam.constellation[arity]) self.chunks2symbols = gr.chunks_to_symbols_bc(rotated_const) # pulse shaping filter self.rrc_taps = gr.firdes.root_raised_cosine( self. _samples_per_symbol, # gain (sps since we're interpolating by sps) self._samples_per_symbol, # sampling rate 1.0, # symbol rate self._excess_bw, # excess bandwidth (roll-off factor) ntaps) self.rrc_filter = gr.interp_fir_filter_ccf(self._samples_per_symbol, self.rrc_taps) if verbose: self._print_verbage() if log: self._setup_logging() # Connect self.connect(self, self.bytes2chunks, self.symbol_mapper, self.diffenc, self.chunks2symbols, self.rrc_filter, self)
def __init__(self, options, msgq_limit=2, pad_for_usrp=True): """ Hierarchical block for sending packets Packets to be sent are enqueued by calling send_pkt. The output is the complex modulated signal at baseband. Args: options: pass modulation options from higher layers (fft length, occupied tones, etc.) msgq_limit: maximum number of messages in message queue (int) pad_for_usrp: If true, packets are padded such that they end up a multiple of 128 samples """ gr.hier_block2.__init__( self, "ofdm_mod", gr.io_signature(0, 0, 0), # Input signature gr.io_signature(1, 1, gr.sizeof_gr_complex)) # Output signature self._pad_for_usrp = pad_for_usrp self._modulation = options.modulation self._fft_length = options.fft_length self._occupied_tones = options.occupied_tones self._cp_length = options.cp_length win = [] #[1 for i in range(self._fft_length)] # Use freq domain to get doubled-up known symbol for correlation in time domain zeros_on_left = int( math.ceil((self._fft_length - self._occupied_tones) / 2.0)) ksfreq = known_symbols_4512_3[0:self._occupied_tones] for i in range(len(ksfreq)): if ((zeros_on_left + i) & 1): ksfreq[i] = 0 # hard-coded known symbols preambles = (ksfreq, ) padded_preambles = list() for pre in preambles: padded = self._fft_length * [ 0, ] padded[zeros_on_left:zeros_on_left + self._occupied_tones] = pre padded_preambles.append(padded) symbol_length = options.fft_length + options.cp_length mods = { "bpsk": 2, "qpsk": 4, "8psk": 8, "qam8": 8, "qam16": 16, "qam64": 64, "qam256": 256 } arity = mods[self._modulation] rot = 1 if self._modulation == "qpsk": rot = (0.707 + 0.707j) # FIXME: pass the constellation objects instead of just the points if (self._modulation.find("psk") >= 0): constel = psk.psk_constellation(arity) rotated_const = map(lambda pt: pt * rot, constel.points()) elif (self._modulation.find("qam") >= 0): constel = qam.qam_constellation(arity) rotated_const = map(lambda pt: pt * rot, constel.points()) #print rotated_const self._pkt_input = digital.ofdm_mapper_bcv(rotated_const, msgq_limit, options.occupied_tones, options.fft_length) self.preambles = digital.ofdm_insert_preamble(self._fft_length, padded_preambles) self.ifft = fft.fft_vcc(self._fft_length, False, win, True) self.cp_adder = digital.ofdm_cyclic_prefixer(self._fft_length, symbol_length) self.scale = blocks.multiply_const_cc(1.0 / math.sqrt(self._fft_length)) self.connect((self._pkt_input, 0), (self.preambles, 0)) self.connect((self._pkt_input, 1), (self.preambles, 1)) self.connect(self.preambles, self.ifft, self.cp_adder, self.scale, self)
class receiver(gr.hier_block2): def __init__(self): gr.hier_block2.__init__(self, "ofdm_tx", gr.io_signature(1, 1, gr.sizeof_gr_complex), gr.io_signature(1, 1, gr.sizeof_char))
def __init__(self, mode='433', input_rate=0, context=None): assert input_rate > 0 assert context is not None gr.hier_block2.__init__(self, type(self).__name__, gr.io_signature(1, 1, gr.sizeof_gr_complex), gr.io_signature(0, 0, 0)) # The input bandwidth chosen is not primarily determined by the bandwidth of the input signals, but by the frequency error of the transmitters. Therefore it is not too critical, and we can choose the exact rate to make the filtering easy. if input_rate <= upper_preferred_demod_rate: # Skip having a filter at all. self.__band_filter = None demod_rate = input_rate else: # TODO: This gunk is very similar to the stuff that MultistageChannelFilter does. See if we can share some code. lower_rate = input_rate lower_rate_prev = None while lower_rate > upper_preferred_demod_rate and lower_rate != lower_rate_prev: lower_rate_prev = lower_rate if lower_rate % 5 == 0 and lower_rate > upper_preferred_demod_rate * 3: lower_rate /= 5 elif lower_rate % 2 == 0: lower_rate /= 2 else: # non-integer ratio lower_rate = upper_preferred_demod_rate break demod_rate = lower_rate self.__band_filter = MultistageChannelFilter( input_rate=input_rate, output_rate=demod_rate, cutoff_freq=demod_rate * 0.4, transition_width=demod_rate * 0.2) # Subprocess # using /usr/bin/env because twisted spawnProcess doesn't support path search # pylint: disable=no-member self.__process = the_reactor.spawnProcess( RTL433ProcessProtocol(context.output_message, self.__log), '/usr/bin/env', env=None, # inherit environment args=[ b'env', b'rtl_433', b'-F', b'json', b'-r', b'-', # read from stdin b'-m', b'3', # complex float input b'-s', str(demod_rate), b'-q' # quiet mode, suppress "Registering protocol..." stderr flood ], childFDs={ 0: 'w', 1: 'r', 2: 2 }) sink = make_sink_to_process_stdin(self.__process, itemsize=gr.sizeof_gr_complex) agc = analog.agc2_cc(reference=dB(-4)) agc.set_attack_rate(200 / demod_rate) agc.set_decay_rate(200 / demod_rate) if self.__band_filter: self.connect(self, self.__band_filter, agc) else: self.connect(self, agc) self.connect(agc, sink)
def __init__(self, input_rate=None, demod_type='cqpsk', filter_type=None, excess_bw=_def_excess_bw, relative_freq=0, offset=0, if_rate=_def_if_rate, gain_mu=_def_gain_mu, costas_alpha=_def_costas_alpha, symbol_rate=_def_symbol_rate): """ Hierarchical block for P25 demodulation. The complex input is tuned, decimated and demodulated @param input_rate: sample rate of complex input channel @type input_rate: int """ gr.hier_block2.__init__( self, "p25_demod_cb", gr.io_signature(1, 1, gr.sizeof_gr_complex), # Input signature gr.io_signature(1, 1, gr.sizeof_char)) # Output signature # gr.io_signature(0, 0, 0)) # Output signature p25_demod_base.__init__(self, if_rate=if_rate, symbol_rate=symbol_rate, filter_type=filter_type) self.input_rate = input_rate self.if_rate = if_rate self.symbol_rate = symbol_rate self.connect_state = None self.offset = 0 self.sps = 0.0 self.lo_freq = 0 self.float_sink = None self.complex_sink = None self.if1 = 0 self.if2 = 0 self.t_cache = {} if filter_type == 'rrc': self.set_baseband_gain(0.61) self.mixer = blocks.multiply_cc() decimator_values = get_decim(input_rate) if decimator_values: self.decim, self.decim2 = decimator_values self.if1 = input_rate / self.decim self.if2 = self.if1 / self.decim2 sys.stderr.write( 'Using two-stage decimator for speed=%d, decim=%d/%d if1=%d if2=%d\n' % (input_rate, self.decim, self.decim2, self.if1, self.if2)) bpf_coeffs = filter.firdes.complex_band_pass( 1.0, input_rate, -self.if1 / 2, self.if1 / 2, self.if1 / 2, filter.firdes.WIN_HAMMING) self.t_cache[0] = bpf_coeffs fa = 6250 fb = self.if2 / 2 if filter_type == 'nxdn' and self.symbol_rate == 2400: # nxdn48 6.25 KHz fa = 3125 lpf_coeffs = filter.firdes.low_pass(1.0, self.if1, (fb + fa) / 2, fb - fa, filter.firdes.WIN_HAMMING) self.bpf = filter.fir_filter_ccc(self.decim, bpf_coeffs) self.lpf = filter.fir_filter_ccf(self.decim2, lpf_coeffs) resampled_rate = self.if2 self.relative_limit = (input_rate // 2) - (self.if1 // 2) self.bfo = analog.sig_source_c(self.if1, analog.GR_SIN_WAVE, 0, 1.0, 0) self.connect(self, self.bpf, (self.mixer, 0)) self.connect(self.bfo, (self.mixer, 1)) else: sys.stderr.write( 'Unable to use two-stage decimator for speed=%d\n' % (input_rate)) # local osc self.lo = analog.sig_source_c(input_rate, analog.GR_SIN_WAVE, 0, 1.0, 0) f1 = 7250 f2 = 1450 if filter_type == 'nxdn' and self.symbol_rate == 2400: # nxdn48 6.25 KHz f1 = 3125 f2 = 625 lpf_coeffs = filter.firdes.low_pass(1.0, input_rate, f1, f2, filter.firdes.WIN_HANN) decimation = int(input_rate / if_rate) self.lpf = filter.fir_filter_ccf(decimation, lpf_coeffs) resampled_rate = float(input_rate) / float( decimation) # rate at output of self.lpf self.relative_limit = (input_rate // 2) - f1 self.connect(self, (self.mixer, 0)) self.connect(self.lo, (self.mixer, 1)) self.connect(self.mixer, self.lpf) if self.if_rate != resampled_rate: self.if_out = filter.pfb.arb_resampler_ccf( float(self.if_rate) / resampled_rate) self.connect(self.lpf, self.if_out) else: self.if_out = self.lpf fa = 6250 fb = fa + 625 cutoff_coeffs = filter.firdes.low_pass(1.0, self.if_rate, (fb + fa) / 2, fb - fa, filter.firdes.WIN_HANN) self.cutoff = filter.fir_filter_ccf(1, cutoff_coeffs) omega = float(self.if_rate) / float(self.symbol_rate) gain_omega = 0.1 * gain_mu * gain_mu alpha = costas_alpha beta = 0.125 * alpha * alpha fmax = 2400 # Hz fmax = 2 * pi * fmax / float(self.if_rate) self.clock = op25_repeater.gardner_costas_cc(omega, gain_mu, gain_omega, alpha, beta, fmax, -fmax) self.agc = analog.feedforward_agc_cc(16, 1.0) # Perform Differential decoding on the constellation self.diffdec = digital.diff_phasor_cc() # take angle of the difference (in radians) self.to_float = blocks.complex_to_arg() # convert from radians such that signal is in -3/-1/+1/+3 self.rescale = blocks.multiply_const_ff((1 / (pi / 4))) # fm demodulator (needed in fsk4 case) fm_demod_gain = if_rate / (2.0 * pi * _def_symbol_deviation) self.fm_demod = analog.quadrature_demod_cf(fm_demod_gain) self.connect_chain(demod_type) self.connect(self.slicer, self) self.set_relative_frequency(relative_freq)
def __init__( self, verbose_mode=True, radio_device_name="/dev/ndr47x", radio_baud_rate=921600, gig_iface_to_use="eth0", num_tuners=1, tuner1_param_list=[False, 900e6, 0], tuner2_param_list=[False, 900e6, 0], num_wbddcs=1, wbddc1_param_list=[40001, 0, 0, False, 0e6], wbddc2_param_list=[40002, 0, 0, False, 0e6], tagged=False, ): gr.hier_block2.__init__( self, "[CyberRadio] NDR472 Source", gr.io_signature(0, 0, 0), gr.io_signaturev(num_wbddcs + 1, num_wbddcs + 1, [gr.sizeof_char * 1] + num_wbddcs * [gr.sizeof_gr_complex * 1]), ) self.verbose_mode = verbose_mode self.radio_device_name = radio_device_name self.radio_baud_rate = radio_baud_rate self.gig_iface_to_use = gig_iface_to_use self.udp_host_name = CyberRadioDriver.getInterfaceAddresses( self.gig_iface_to_use)[1] self.num_tuners = num_tuners self.tuner1_param_list = tuner1_param_list self.tuner2_param_list = tuner2_param_list self.num_wbddcs = num_wbddcs self.wbddc1_param_list = wbddc1_param_list self.wbddc2_param_list = wbddc2_param_list self.tagged = tagged self.CyberRadio_file_like_object_source_0 = CyberRadio.file_like_object_source( ) self.connect((self.CyberRadio_file_like_object_source_0, 0), (self, 0)) self.CyberRadio_NDR_driver_interface_0 = CyberRadio.NDR_driver_interface( radio_type="ndr472", verbose=verbose_mode, log_file=self.CyberRadio_file_like_object_source_0, connect_mode="tty", dev_name=radio_device_name, baud_rate=radio_baud_rate, ) self.vita_tail_size = self.CyberRadio_NDR_driver_interface_0.getVitaTailSize( ) self.vita_payload_size = self.CyberRadio_NDR_driver_interface_0.getVitaPayloadSize( ) self.vita_header_size = self.CyberRadio_NDR_driver_interface_0.getVitaHeaderSize( ) self.iq_swapped = self.CyberRadio_NDR_driver_interface_0.isIqSwapped() self.byte_swapped = self.CyberRadio_NDR_driver_interface_0.isByteswapped( ) self._set_udp_dest_info() if self.num_tuners >= 1: self._set_tuner_param_list(1, tuner1_param_list) if self.num_tuners >= 2: self._set_tuner_param_list(2, tuner2_param_list) self.wbddc_sources = {} if self.num_wbddcs >= 1: self.CyberRadio_vita_iq_source_wbddc_1 = self._get_configured_wbddc( 1, wbddc1_param_list) self.connect((self.CyberRadio_vita_iq_source_wbddc_1, 0), (self, 1)) self.wbddc_sources[1] = self.CyberRadio_vita_iq_source_wbddc_1 if self.num_wbddcs >= 2: self.CyberRadio_vita_iq_source_wbddc_2 = self._get_configured_wbddc( 2, wbddc2_param_list) self.connect((self.CyberRadio_vita_iq_source_wbddc_2, 0), (self, 2)) self.wbddc_sources[2] = self.CyberRadio_vita_iq_source_wbddc_2
def __init__(self, options, log=False): ## Read configuration config = station_configuration() fft_length = config.fft_length #cp_length = config.cp_length block_header = config.training_data data_subc = config.data_subcarriers virtual_subc = config.virtual_subcarriers total_subc = config.subcarriers block_length = config.block_length frame_length = config.frame_length L = block_header.mm_periodic_parts cp_length = config.cp_length print "data_subc: ", config.data_subcarriers print "total_subc: ", config.subcarriers print "frame_lengthframe_length: ", frame_length ## Set Input/Output signature gr.hier_block2.__init__( self, "fbmc_inner_receiver", gr.io_signature(1, 1, gr.sizeof_gr_complex), gr.io_signaturev( 4, 4, [ gr.sizeof_float * total_subc, # Normalized |CTF|^2 gr.sizeof_char, # Frame start gr.sizeof_gr_complex * total_subc, # OFDM blocks, SNR est gr.sizeof_float ])) # CFO ## Input and output ports self.input = rx_input = self out_ofdm_blocks = (self, 2) out_frame_start = (self, 1) out_disp_ctf = (self, 0) out_disp_cfo = (self, 3) #out_snr_pream = ( self, 3 ) ## pre-FFT processing ''' ## Compute autocorrelations for S&C preamble ## and cyclic prefix self._sc_metric = sc_metric = autocorrelator( fft_length/2, fft_length/2 ) self._gi_metric = gi_metric = autocorrelator( fft_length, cp_length ) self.connect( rx_input, sc_metric ) self.connect( rx_input, gi_metric ) terminate_stream(self, gi_metric) ## Sync. Output contains OFDM blocks sync = ofdm.time_sync( fft_length/2, 1) self.connect( rx_input, ( sync, 0 ) ) self.connect( sc_metric, ( sync, 1 ) ) self.connect( sc_metric, ( sync, 2 ) ) ofdm_blocks = ( sync, 0 ) frame_start = ( sync, 1 ) log_to_file( self, ( sync, 1 ), "data/fbmc_peak_detector.char" ) ''' if options.ideal is False and options.ideal2 is False: #Testing old/new metric self.tm = schmidl.recursive_timing_metric(2 * fft_length) self.connect(self.input, self.tm) #log_to_file( self, self.tm, "data/fbmc_rec_sc_metric_ofdm.float" ) timingmetric_shift = 0 #-2 #int(-cp_length * 0.8) tmfilter = filter.fft_filter_fff( 1, [2. / fft_length] * (fft_length / 2) ) # ofdm.lms_fir_ff( fft_length, 1e-3 ) #; filter.fir_filter_fff(1, [1./fft_length]*fft_length) self.connect(self.tm, tmfilter) self.tm = tmfilter #log_to_file( self, self.tm, "data/fbmc_rec_sc_metric_ofdm2.float" ) self._pd_thres = 0.6 self._pd_lookahead = fft_length # empirically chosen peak_detector = ofdm.peak_detector_02_fb(self._pd_lookahead, self._pd_thres) self.connect(self.tm, peak_detector) #log_to_file( self, peak_detector, "data/fbmc_rec_peak_detector.char" ) #frame_start = [0]*frame_length #frame_start[0] = 1 #frame_start = blocks.vector_source_b(frame_start,True) #OLD #delayed_timesync = blocks.delay(gr.sizeof_char, # (frame_length-10)*fft_length/2 - fft_length/4 -1 + timingmetric_shift) delayed_timesync = blocks.delay( gr.sizeof_char, (frame_length - 10) * fft_length / 2 - fft_length / 4 + int(2.5 * fft_length) + timingmetric_shift - 1) #delayed_timesync = blocks.delay(gr.sizeof_char, #(frame_length-10)*fft_length/2 - fft_length/4 + int(3.5*fft_length) + timingmetric_shift-1) self.connect(peak_detector, delayed_timesync) self.block_sampler = ofdm.vector_sampler( gr.sizeof_gr_complex, fft_length / 2 * frame_length) self.connect(self.input, self.block_sampler) self.connect(delayed_timesync, (self.block_sampler, 1)) #log_to_file( self, self.block_sampler, "data/fbmc_block_sampler.compl" ) vt2s = blocks.vector_to_stream(gr.sizeof_gr_complex * fft_length, frame_length / 2) self.connect(self.block_sampler, vt2s) #terminate_stream(self,ofdm_blocks) ofdm_blocks = vt2s ''' # TODO: dynamic solution vt2s = blocks.vector_to_stream(gr.sizeof_gr_complex*block_length/2, frame_length) self.connect(self.block_sampler,vt2s) terminate_stream(self,( sync, 0 )) ofdm_blocks = vt2s ''' ##stv_help = blocks.stream_to_vector(gr.sizeof_gr_complex*config.fft_length/2, 1) #stv_help = blocks.vector_to_stream(gr.sizeof_gr_complex*config.fft_length/2, 2) ##self.connect(ofdm_blocks, stv_help) ##ofdm_blocks = stv_help #ofdm_blocks = ( sync, 0 ) #frame_start = ( sync, 1 ) #log_to_file(self, frame_start, "data/frame_start.compl") #log_to_file( self, sc_metric, "data/sc_metric.float" ) #log_to_file( self, gi_metric, "data/gi_metric.float" ) #log_to_file( self, (sync,1), "data/sync.float" ) # log_to_file(self,ofdm_blocks,"data/ofdm_blocks_original.compl") frame_start = [0] * int(frame_length / 2) frame_start[0] = 1 frame_start = blocks.vector_source_b(frame_start, True) #frame_start2 = [0]*int(frame_length/2) #frame_start2[0] = 1 #frame_start2 = blocks.vector_source_b(frame_start2,True) if options.disable_time_sync or options.ideal or options.ideal2: if options.ideal is False and options.ideal2 is False: terminate_stream(self, ofdm_blocks) terminate_stream(self, frame_start) serial_to_parallel = blocks.stream_to_vector( gr.sizeof_gr_complex, fft_length) #discard_cp = ofdm.vector_mask(block_length,cp_length,fft_length,[]) #serial_to_parallel = blocks.stream_to_vector(gr.sizeof_gr_complex,block_length) #discard_cp = ofdm.vector_mask(block_length,cp_length,fft_length,[]) #self.connect( rx_input,serial_to_parallel) #self.connect( rx_input, blocks.delay(gr.sizeof_gr_complex,0),serial_to_parallel) initial_skip = blocks.skiphead(gr.sizeof_gr_complex, 2 * fft_length) self.connect(rx_input, initial_skip) if options.ideal is False and options.ideal2 is False: self.connect(initial_skip, serial_to_parallel) ofdm_blocks = serial_to_parallel else: ofdm_blocks = initial_skip #self.connect( rx_input, serial_to_parallel, discard_cp ) frame_start = [0] * int(frame_length / 2) frame_start[0] = 1 frame_start = blocks.vector_source_b(frame_start, True) #frame_start2 = [0]*int(frame_length/2) #frame_start2[0] = 1 #frame_start2 = blocks.vector_source_b(frame_start2,True) print "Disabled time synchronization stage" print "\t\t\t\t\tframe_length = ", frame_length if options.ideal is False and options.ideal2 is False: ## Extract preamble, feed to Morelli & Mengali frequency offset estimator assert (block_header.mm_preamble_pos == 0) morelli_foe = ofdm.mm_frequency_estimator(fft_length, 2, 1, config.fbmc) sampler_preamble = ofdm.vector_sampler( gr.sizeof_gr_complex * fft_length, 1) self.connect(ofdm_blocks, (sampler_preamble, 0)) self.connect(frame_start, blocks.delay(gr.sizeof_char, 1), (sampler_preamble, 1)) self.connect(sampler_preamble, morelli_foe) freq_offset = morelli_foe print "FRAME_LENGTH: ", frame_length #log_to_file( self, sampler_preamble, "data/sampler_preamble.compl" ) #log_to_file( self, rx_input, "data/rx_input.compl" ) #log_to_file( self, ofdm_blocks, "data/rx_input.compl" ) #Extracting preamble for SNR estimation #fft_snr_est = fft_blocks.fft_vcc( fft_length, True, [], True ) #self.connect( sampler_preamble, blocks.stream_to_vector(gr.sizeof_gr_complex*fft_length/2, 2), fft_snr_est ) ## Remove virtual subcarriers #if fft_length > data_subc: #subcarrier_mask_snr_est = ofdm.vector_mask( fft_length, virtual_subc/2, # total_subc, [] ) #self.connect( fft_snr_est, subcarrier_mask_snr_est ) #fft_snr_est = subcarrier_mask_snr_est #log_to_file(self, ofdm_blocks, "data/vec_mask.compl") ## Least Squares estimator for channel transfer function (CTF) #self.connect( fft_snr_est, out_snr_pream ) # Connecting to output ## Adaptive LMS FIR filtering of frequency offset lms_fir = ofdm.lms_fir_ff(20, 1e-3) # TODO: verify parameter choice self.connect(freq_offset, lms_fir) freq_offset = lms_fir self.connect(freq_offset, blocks.keep_one_in_n(gr.sizeof_float, 20), out_disp_cfo) else: self.connect(blocks.vector_source_f([1]), out_disp_cfo) #log_to_file(self, lms_fir, "data/lms_fir.float") if options.disable_freq_sync or options.ideal or options.ideal2: if options.ideal is False and options.ideal2 is False: terminate_stream(self, freq_offset) freq_offset = blocks.vector_source_f([0.0], True) print "Disabled frequency synchronization stage" if options.ideal is False and options.ideal2 is False: ## Correct frequency shift, feed-forward structure frequency_shift = ofdm.frequency_shift_vcc(fft_length, -1.0 / fft_length, 0) #freq_shift = blocks.multiply_cc() #norm_freq = -0.1 / config.fft_length #freq_off = self.freq_off_src = analog.sig_source_c(1.0, analog.GR_SIN_WAVE, norm_freq, 1.0, 0.0 ) self.connect(ofdm_blocks, (frequency_shift, 0)) self.connect(freq_offset, (frequency_shift, 1)) self.connect(frame_start, blocks.delay(gr.sizeof_char, 0), (frequency_shift, 2)) #self.connect(frequency_shift,s2help) #ofdm_blocks = s2help ofdm_blocks = frequency_shift #terminate_stream(self, frequency_shift) #inner_pb_filt = self._inner_pilot_block_filter = fbmc_inner_pilot_block_filter() #self.connect(ofdm_blocks,inner_pb_filt) #self.connect(frame_start,(inner_pb_filt,1)) #self.connect((inner_pb_filt,1),blocks.null_sink(gr.sizeof_char)) #ofdm_blocks = (inner_pb_filt,0) overlap_ser_to_par = ofdm.fbmc_overlapping_serial_to_parallel_cvc( fft_length) self.separate_vcvc = ofdm.fbmc_separate_vcvc(fft_length, 2) self.polyphase_network_vcvc_1 = ofdm.fbmc_polyphase_network_vcvc( fft_length, 4, 4 * fft_length - 1, True) self.polyphase_network_vcvc_2 = ofdm.fbmc_polyphase_network_vcvc( fft_length, 4, 4 * fft_length - 1, True) self.junction_vcvc = ofdm.fbmc_junction_vcvc(fft_length, 2) self.fft_fbmc = fft_blocks.fft_vcc(fft_length, True, [], True) print "config.training_data.fbmc_no_preambles: ", config.training_data.fbmc_no_preambles #center_preamble = [1, -1j, -1, 1j] #self.preamble = preamble = [0]*total_subc + center_preamble*((int)(total_subc/len(center_preamble)))+[0]*total_subc self.preamble = preamble = config.training_data.fbmc_pilotsym_fd_list #inv_preamble = 1. / numpy.array(self.preamble) #print "self.preamble: ", len(self.preamble #print "inv_preamble: ", list(inv_preamble) #print "self.preamble", self.preamble #print "self.preamble2", self.preamble2 self.multiply_const = ofdm.multiply_const_vcc( ([1.0 / (math.sqrt(fft_length * 0.6863))] * total_subc)) self.beta_multiplier_vcvc = ofdm.fbmc_beta_multiplier_vcvc( total_subc, 4, 4 * fft_length - 1, 0) #self.skiphead = blocks.skiphead(gr.sizeof_gr_complex*total_subc, 2*4-1-1) self.skiphead = blocks.skiphead(gr.sizeof_gr_complex * total_subc, 2) self.skiphead_1 = blocks.skiphead(gr.sizeof_gr_complex * total_subc, 0) #self.remove_preamble_vcvc = ofdm.fbmc_remove_preamble_vcvc(total_subc, config.frame_data_part/2, config.training_data.fbmc_no_preambles*total_subc/2) #self.subchannel_processing_vcvc = ofdm.fbmc_subchannel_processing_vcvc(total_subc, config.frame_data_part, 1, 2, 1, 0) self.oqam_postprocessing_vcvc = ofdm.fbmc_oqam_postprocessing_vcvc( total_subc, 0, 0) #log_to_file( self, ofdm_blocks, "data/PRE_FBMC.compl" ) #log_to_file( self, self.fft_fbmc, "data/FFT_FBMC.compl" ) if options.ideal is False and options.ideal2 is False: self.subchannel_processing_vcvc = ofdm.fbmc_subchannel_processing_vcvc( total_subc, config.frame_data_part, 3, 2, 1, 0) help2 = blocks.keep_one_in_n(gr.sizeof_gr_complex * total_subc, frame_length) self.connect((self.subchannel_processing_vcvc, 1), help2) #log_to_file( self, self.subchannel_processing_vcvc, "data/fbmc_subc.compl" ) #terminate_stream(self, help2) if options.ideal is False and options.ideal2 is False: self.connect( ofdm_blocks, blocks.vector_to_stream(gr.sizeof_gr_complex, fft_length), overlap_ser_to_par) else: self.connect(ofdm_blocks, overlap_ser_to_par) self.connect(overlap_ser_to_par, self.separate_vcvc) self.connect((self.separate_vcvc, 1), (self.polyphase_network_vcvc_2, 0)) self.connect((self.separate_vcvc, 0), (self.polyphase_network_vcvc_1, 0)) self.connect((self.polyphase_network_vcvc_1, 0), (self.junction_vcvc, 0)) self.connect((self.polyphase_network_vcvc_2, 0), (self.junction_vcvc, 1)) self.connect(self.junction_vcvc, self.fft_fbmc) ofdm_blocks = self.fft_fbmc print "config.dc_null: ", config.dc_null if fft_length > data_subc: subcarrier_mask_fbmc = ofdm.vector_mask_dc_null( fft_length, virtual_subc / 2, total_subc, config.dc_null, []) self.connect(ofdm_blocks, subcarrier_mask_fbmc) ofdm_blocks = subcarrier_mask_fbmc #log_to_file(self, ofdm_blocks, "data/vec_mask.compl") ## Least Squares estimator for channel transfer function (CTF) #log_to_file( self, subcarrier_mask, "data/OFDM_Blocks.compl" ) self.connect(ofdm_blocks, self.beta_multiplier_vcvc) ofdm_blocks = self.beta_multiplier_vcvc #self.connect(ofdm_blocks,self.multiply_const) #self.connect(self.multiply_const, (self.skiphead, 0)) self.connect(ofdm_blocks, (self.skiphead, 0)) #log_to_file( self, self.skiphead, "data/fbmc_skiphead_4.compl" ) #self.connect(ofdm_blocks, self.multiply_const) #self.connect(self.multiply_const, self.beta_multiplier_vcvc) #self.connect((self.beta_multiplier_vcvc, 0), (self.skiphead, 0)) if options.ideal or options.ideal2: self.connect((self.skiphead, 0), (self.skiphead_1, 0)) else: self.connect((self.skiphead, 0), (self.subchannel_processing_vcvc, 0)) self.connect((self.subchannel_processing_vcvc, 0), (self.skiphead_1, 0)) #log_to_file( self, self.skiphead, "data/fbmc_subc.compl" ) #self.connect((self.skiphead_1, 0),(self.remove_preamble_vcvc, 0)) #self.connect((self.remove_preamble_vcvc, 0), (self.oqam_postprocessing_vcvc, 0)) #ofdm_blocks = self.oqam_postprocessing_vcvc #log_to_file( self, self.subchannel_processing_vcvc, "data/subc_0.compl" ) #log_to_file( self, (self.subchannel_processing_vcvc,1), "data/subc_1.compl" ) self.connect((self.skiphead_1, 0), (self.oqam_postprocessing_vcvc, 0)) #self.connect((self.oqam_postprocessing_vcvc, 0), (self.remove_preamble_vcvc, 0) ) ofdm_blocks = (self.oqam_postprocessing_vcvc, 0 ) #(self.remove_preamble_vcvc, 0) #log_to_file( self, (self.oqam_postprocessing_vcvc, 0), "data/fbmc_before_remove.compl" ) #log_to_file( self, self.skiphead, "data/SKIP_HEAD_FBMC.compl" ) #log_to_file( self, self.beta_multiplier_vcvc, "data/BETA_REC_FBMC.compl" ) #log_to_file( self, self.oqam_postprocessing_vcvc, "data/REC_OUT_FBMC.compl" ) """ DISABLED OFDM CHANNEL ESTIMATION PREMBLE -> CORRECT LATER to compare FBMC and OFDM channel estimation #TAKING THE CHANNEL ESTIMATION PREAMBLE chest_pre_trigger = blocks.delay( gr.sizeof_char, 3 ) sampled_chest_preamble = ofdm.vector_sampler( gr.sizeof_gr_complex * fft_length/2, 2 ) self.connect( frame_start, chest_pre_trigger ) self.connect( chest_pre_trigger, ( sampled_chest_preamble, 1 ) ) self.connect( frequency_shift, ( sampled_chest_preamble, 0 ) ) #ofdm_blocks = sampled_chest_preamble ## FFT fft = fft_blocks.fft_vcc( fft_length, True, [], True ) self.connect( sampled_chest_preamble, fft ) ofdm_blocks_est = fft log_to_file( self, sampled_chest_preamble, "data/SAMPLED_EST_PREAMBLE.compl" ) log_to_file( self, ofdm_blocks_est, "data/FFT.compl" ) ## Remove virtual subcarriers if fft_length > data_subc: subcarrier_mask = ofdm.vector_mask( fft_length, virtual_subc/2, total_subc, [] ) self.connect( ofdm_blocks_est, subcarrier_mask ) ofdm_blocks_est = subcarrier_mask #log_to_file(self, ofdm_blocks, "data/vec_mask.compl") ## Least Squares estimator for channel transfer function (CTF) log_to_file( self, subcarrier_mask, "data/OFDM_Blocks.compl" ) ## post-FFT processing ## extract channel estimation preamble from frame ##chest_pre_trigger = blocks.delay( gr.sizeof_char, ##1 ) ##sampled_chest_preamble = \ ## ofdm.vector_sampler( gr.sizeof_gr_complex * total_subc, 1 ) ##self.connect( frame_start, chest_pre_trigger ) ##self.connect( chest_pre_trigger, ( sampled_chest_preamble, 1 ) ) ##self.connect( ofdm_blocks, ( sampled_chest_preamble, 0 ) ) ## Least Squares estimator for channel transfer function (CTF) inv_preamble_fd = numpy.array( block_header.pilotsym_fd[ block_header.channel_estimation_pilot[0] ] ) #print "Channel estimation pilot: ", inv_preamble_fd inv_preamble_fd = 1. / inv_preamble_fd LS_channel_estimator = ofdm.multiply_const_vcc( list( inv_preamble_fd ) ) self.connect( ofdm_blocks_est, LS_channel_estimator ) estimated_CTF = LS_channel_estimator terminate_stream(self,estimated_CTF) """ if options.ideal is False and options.ideal2 is False: if options.logcir: log_to_file(self, sampled_chest_preamble, "data/PREAM.compl") if not options.disable_ctf_enhancer: if options.logcir: ifft1 = fft_blocks.fft_vcc(total_subc, False, [], True) self.connect( estimated_CTF, ifft1, gr.null_sink(gr.sizeof_gr_complex * total_subc)) summ1 = ofdm.vector_sum_vcc(total_subc) c2m = gr.complex_to_mag(total_subc) self.connect(estimated_CTF, summ1, gr.null_sink(gr.sizeof_gr_complex)) self.connect(estimated_CTF, c2m, gr.null_sink(gr.sizeof_float * total_subc)) log_to_file(self, ifft1, "data/CIR1.compl") log_to_file(self, summ1, "data/CTFsumm1.compl") log_to_file(self, estimated_CTF, "data/CTF1.compl") log_to_file(self, c2m, "data/CTFmag1.float") ## MSE enhancer ctf_mse_enhancer = ofdm.CTF_MSE_enhancer( total_subc, cp_length + cp_length) self.connect(estimated_CTF, ctf_mse_enhancer) # log_to_file( self, ctf_mse_enhancer, "data/ctf_mse_enhancer_original.compl") #ifft3 = fft_blocks.fft_vcc(total_subc,False,[],True) #null_noise = ofdm.noise_nulling(total_subc, cp_length + cp_length) #ctf_mse_enhancer = fft_blocks.fft_vcc(total_subc,True,[],True) #ctf_mse_enhancer = ofdm.vector_mask( fft_length, virtual_subc/2, # total_subc, [] ) #self.connect( estimated_CTF, ifft3,null_noise,ctf_mse_enhancer ) estimated_CTF = ctf_mse_enhancer print "Disabled CTF MSE enhancer" if options.logcir: ifft2 = fft_blocks.fft_vcc(total_subc, False, [], True) self.connect(estimated_CTF, ifft2, gr.null_sink(gr.sizeof_gr_complex * total_subc)) summ2 = ofdm.vector_sum_vcc(total_subc) c2m2 = gr.complex_to_mag(total_subc) self.connect(estimated_CTF, summ2, gr.null_sink(gr.sizeof_gr_complex)) self.connect(estimated_CTF, c2m2, gr.null_sink(gr.sizeof_float * total_subc)) log_to_file(self, ifft2, "data/CIR2.compl") log_to_file(self, summ2, "data/CTFsumm2.compl") log_to_file(self, estimated_CTF, "data/CTF2.compl") log_to_file(self, c2m2, "data/CTFmag2.float") ## Postprocess the CTF estimate ## CTF -> inverse CTF (for equalizer) ## CTF -> norm |.|^2 (for CTF display) ctf_postprocess = ofdm.fbmc_postprocess_CTF_estimate(total_subc) self.connect(help2, ctf_postprocess) #estimated_SNR = ( ctf_postprocess, 0 ) disp_CTF = (ctf_postprocess, 0) #self.connect(estimated_SNR,out_snr_pream) #log_to_file( self, estimated_SNR, "data/fbmc_SNR.float" ) #Disable measured SNR output #terminate_stream(self, estimated_SNR) #self.connect(blocks.vector_source_f([10.0],True) ,out_snr_pream) # if options.disable_equalization or options.ideal: # terminate_stream(self, inv_estimated_CTF) # inv_estimated_CTF_vec = blocks.vector_source_c([1.0/fft_length*math.sqrt(total_subc)]*total_subc,True,total_subc) # inv_estimated_CTF_str = blocks.vector_to_stream(gr.sizeof_gr_complex, total_subc) # self.inv_estimated_CTF_mul = ofdm.multiply_const_ccf( 1.0/config.rms_amplitude ) # #inv_estimated_CTF_mul.set_k(1.0/config.rms_amplitude) # inv_estimated_CTF = blocks.stream_to_vector(gr.sizeof_gr_complex, total_subc) # self.connect( inv_estimated_CTF_vec, inv_estimated_CTF_str, self.inv_estimated_CTF_mul, inv_estimated_CTF) # print "Disabled equalization stage" ''' ## LMS Phase tracking ## Track residual frequency offset and sampling clock frequency offset nondata_blocks = [] for i in range(config.frame_length): if i in config.training_data.pilotsym_pos: nondata_blocks.append(i) print"\t\t\t\t\tnondata_blocks=",nondata_blocks pilot_subc = block_header.pilot_tones pilot_subcarriers = block_header.pilot_subc_sym print "PILOT SUBCARRIERS: ", pilot_subcarriers phase_tracking = ofdm.lms_phase_tracking_03( total_subc, pilot_subc, nondata_blocks, pilot_subcarriers,0 ) self.connect( ofdm_blocks, ( phase_tracking, 0 ) ) self.connect( inv_estimated_CTF, ( phase_tracking, 1 ) ) self.connect( frame_start, ( phase_tracking, 2 ) ) ## if options.scatter_plot_before_phase_tracking: self.before_phase_tracking = equalizer if options.disable_phase_tracking or options.ideal: terminate_stream(self, phase_tracking) print "Disabled phase tracking stage" else: ofdm_blocks = phase_tracking ''' ## Channel Equalizer ##equalizer = ofdm.channel_equalizer( total_subc ) ##self.connect( ofdm_blocks, ( equalizer, 0 ) ) ##self.connect( inv_estimated_CTF, ( equalizer, 1 ) ) ##self.connect( frame_start, ( equalizer, 2 ) ) ##ofdm_blocks = equalizer #log_to_file(self, equalizer,"data/equalizer_siso.compl") #log_to_file(self, ofdm_blocks, "data/equalizer.compl") ## LMS Phase tracking ## Track residual frequency offset and sampling clock frequency offset nondata_blocks = [] for i in range(config.frame_length): if i in config.training_data.pilotsym_pos: nondata_blocks.append(i) print "\t\t\t\t\tnondata_blocks=", nondata_blocks pilot_subc = block_header.pilot_tones pilot_subcarriers = block_header.pilot_subc_sym print "PILOT SUBCARRIERS: ", pilot_subcarriers if options.scatter_plot_before_phase_tracking: self.before_phase_tracking = equalizer ## Output connections self.connect(ofdm_blocks, out_ofdm_blocks) self.connect(frame_start, out_frame_start) if options.ideal is False and options.ideal2 is False: self.connect(disp_CTF, out_disp_ctf) else: self.connect(blocks.vector_source_f([1.0] * total_subc), blocks.stream_to_vector(gr.sizeof_float, total_subc), out_disp_ctf) if log: log_to_file(self, sc_metric, "data/sc_metric.float") log_to_file(self, gi_metric, "data/gi_metric.float") log_to_file(self, morelli_foe, "data/morelli_foe.float") log_to_file(self, lms_fir, "data/lms_fir.float") log_to_file(self, sampler_preamble, "data/preamble.compl") log_to_file(self, sync, "data/sync.compl") log_to_file(self, frequency_shift, "data/frequency_shift.compl") log_to_file(self, fft, "data/fft.compl") log_to_file(self, fft, "data/fft.float", mag=True) if vars().has_key('subcarrier_mask'): log_to_file(self, subcarrier_mask, "data/subcarrier_mask.compl") log_to_file(self, ofdm_blocks, "data/ofdm_blocks_out.compl") log_to_file(self, frame_start, "data/frame_start.float", char_to_float=True) log_to_file(self, sampled_chest_preamble, "data/sampled_chest_preamble.compl") log_to_file(self, LS_channel_estimator, "data/ls_channel_estimator.compl") log_to_file(self, LS_channel_estimator, "data/ls_channel_estimator.float", mag=True) if "ctf_mse_enhancer" in locals(): log_to_file(self, ctf_mse_enhancer, "data/ctf_mse_enhancer.compl") log_to_file(self, ctf_mse_enhancer, "data/ctf_mse_enhancer.float", mag=True) log_to_file(self, (ctf_postprocess, 0), "data/inc_estimated_ctf.compl") log_to_file(self, (ctf_postprocess, 1), "data/disp_ctf.float") log_to_file(self, equalizer, "data/equalizer.compl") log_to_file(self, equalizer, "data/equalizer.float", mag=True) log_to_file(self, phase_tracking, "data/phase_tracking.compl")
def __init__(self, vlen): gr.hier_block2.__init__( self, "snr_estimator", gr.io_signature2(2, 2, gr.sizeof_gr_complex, gr.sizeof_char), gr.io_signature(1, 1, gr.sizeof_float)) data_in = (self, 0) trig_in = (self, 1) snr_out = (self, 0) ## Preamble Extraction sampler = vector_sampler(gr.sizeof_gr_complex, vlen) self.connect(data_in, sampler) self.connect(trig_in, (sampler, 1)) ## Algorithm implementation estim = sc_snr_estimator(vlen) self.connect(sampler, estim) self.connect(estim, snr_out) return ## Split block into two parts splitter = gr.vector_to_streams(gr.sizeof_gr_complex * vlen / 2, 2) self.connect(sampler, splitter) ## Conjugate first half block conj = gr.conjugate_cc(vlen / 2) self.connect(splitter, conj) ## Vector multiplication of both half blocks vmult = gr.multiply_vcc(vlen / 2) self.connect(conj, vmult) self.connect((splitter, 1), (vmult, 1)) ## Sum of Products psum = vector_sum_vcc(vlen / 2) self.connect(vmult, psum) ## Magnitude of P(d) p_mag = gr.complex_to_mag() self.connect(psum, p_mag) ## Squared Magnitude of block r_magsqrd = gr.complex_to_mag_squared(vlen) self.connect(sampler, r_magsqrd) ## Sum of squared second half block r_sum = vector_sum_vff(vlen) self.connect(r_magsqrd, r_sum) ## Square Root of Metric m_sqrt = gr.divide_ff() self.connect(p_mag, (m_sqrt, 0)) self.connect(r_sum, gr.multiply_const_ff(0.5), (m_sqrt, 1)) ## Denominator of SNR estimate denom = gr.add_const_ff(1) neg_m_sqrt = gr.multiply_const_ff(-1.0) self.connect(m_sqrt, limit_vff(1, 1 - 2e-5, -1000), neg_m_sqrt, denom) ## SNR estimate snr_est = gr.divide_ff() self.connect(m_sqrt, (snr_est, 0)) self.connect(denom, (snr_est, 1)) ## Setup Output Connections self.connect(snr_est, self)
def __init__(self, options, callback=None): """ Hierarchical block for demodulating and deframing packets. The input is the complex modulated signal at baseband. Demodulated packets are sent to the handler. Args: options: pass modulation options from higher layers (fft length, occupied tones, etc.) callback: function of two args: ok, payload (ok: bool; payload: string) """ gr.hier_block2.__init__(self, "ofdm_demod", gr.io_signature(1, 1, gr.sizeof_gr_complex), # Input signature gr.io_signature(1, 1, gr.sizeof_gr_complex)) # Output signature self._rcvd_pktq = gr.msg_queue() # holds packets from the PHY self._modulation = options.modulation self._fft_length = options.fft_length self._occupied_tones = options.occupied_tones self._cp_length = options.cp_length self._snr = options.snr # Use freq domain to get doubled-up known symbol for correlation in time domain zeros_on_left = int(math.ceil((self._fft_length - self._occupied_tones)/2.0)) ksfreq = known_symbols_4512_3[0:self._occupied_tones] for i in range(len(ksfreq)): if((zeros_on_left + i) & 1): ksfreq[i] = 0 # hard-coded known symbols preambles = (ksfreq,) symbol_length = self._fft_length + self._cp_length self.ofdm_recv = ofdm_receiver(self._fft_length, self._cp_length, self._occupied_tones, self._snr, preambles, options.log) mods = {"bpsk": 2, "qpsk": 4, "8psk": 8, "qam8": 8, "qam16": 16, "qam64": 64, "qam256": 256} arity = mods[self._modulation] rot = 1 if self._modulation == "qpsk": rot = (0.707+0.707j) # FIXME: pass the constellation objects instead of just the points if(self._modulation.find("psk") >= 0): constel = psk.psk_constellation(arity) rotated_const = map(lambda pt: pt * rot, constel.points()) elif(self._modulation.find("qam") >= 0): constel = qam.qam_constellation(arity) rotated_const = map(lambda pt: pt * rot, constel.points()) #print rotated_const phgain = 0.25 frgain = phgain*phgain / 4.0 self.ofdm_demod = digital.ofdm_frame_sink(rotated_const, range(arity), self._rcvd_pktq, self._occupied_tones, phgain, frgain) self.connect(self, self.ofdm_recv) self.connect((self.ofdm_recv, 0), (self.ofdm_demod, 0)) self.connect((self.ofdm_recv, 1), (self.ofdm_demod, 1)) # added output signature to work around bug, though it might not be a bad # thing to export, anyway self.connect(self.ofdm_recv.chan_filt, self) if options.log: self.connect(self.ofdm_demod, blocks.file_sink(gr.sizeof_gr_complex*self._occupied_tones, "ofdm_frame_sink_c.dat")) else: self.connect(self.ofdm_demod, blocks.null_sink(gr.sizeof_gr_complex*self._occupied_tones)) if options.verbose: self._print_verbage() self._watcher = _queue_watcher_thread(self._rcvd_pktq, callback)
def __init__( self, n_bursts, n_channels, freq_delta, base_freq, burst_length, base_time, hop_time, post_tuning=True, tx_gain=30, verbose=False ): gr.hier_block2.__init__(self, "FrequencyHopperSrc", gr.io_signature(1, 1, gr.sizeof_gr_complex), gr.io_signature(1, 1, gr.sizeof_gr_complex), ) n_samples_total = n_bursts * burst_length self.hop_sequence = numpy.arange(base_freq, base_freq + n_channels * freq_delta, freq_delta) # self.hop_sequence = 2410000000, 2415000000, 2425000000, 2430000000, 2435000000, 2440000000, 2455000000 # numpy.random.shuffle(self.hop_sequence) #this randomly shuffels frequencies in the specified range # self.hop_sequence = [self.hop_sequence[x % n_channels] for x in xrange(n_bursts)] self.hop_sequence = [self.hop_sequence[x % 7]for x in xrange(n_bursts)] if verbose: print "Hop Frequencies | Hop Pattern" print "=================|================================" for f in self.hop_sequence: print "{:6.3f} MHz | ".format(f/1e6), if n_channels < 50: print " " * int((f - base_freq) / freq_delta) + "#" else: print "\n" print "=================|================================" gain_tag = gr.tag_t() gain_tag.offset = 0 gain_tag.key = pmt.string_to_symbol('tx_command') gain_tag.value = pmt.cons( pmt.intern("gain"), # These are both valid: #pmt.from_double(tx_gain) pmt.cons(pmt.to_pmt(0), pmt.to_pmt(tx_gain)) ) tag_list = [gain_tag,] for i in xrange(n_bursts): tune_tag = gr.tag_t() tune_tag.offset = i * burst_length if i > 0 and post_tuning: tune_tag.offset -= 1 # Move it to last sample of previous burst tune_tag.key = pmt.string_to_symbol('tx_freq') tune_tag.value = pmt.to_pmt(self.hop_sequence[i]) tag_list.append(tune_tag) length_tag = gr.tag_t() length_tag.offset = i * burst_length length_tag.key = pmt.string_to_symbol('packet_len') length_tag.value = pmt.from_long(burst_length) tag_list.append(length_tag) time_tag = gr.tag_t() time_tag.offset = i * burst_length time_tag.key = pmt.string_to_symbol('tx_time') time_tag.value = pmt.make_tuple( pmt.from_uint64(int(base_time + i * hop_time)), pmt.from_double((base_time + i * hop_time) % 1), ) tag_list.append(time_tag) tag_source = blocks.vector_source_c((1.0,) * n_samples_total, repeat=False, tags=tag_list) mult = blocks.multiply_cc() self.connect(self, mult, self) self.connect(tag_source, (mult, 1))
def __init__(self, sign_freq, audio_freq, signal_low_pass_cutoff=10000, signal_low_pass_trans=1000, audio_low_pass_cutoff=3000, audio_low_pass_trans=20, use_dc_blocker=True, audio_gain=1): ################################################## # Variables ################################################## self.sign_freq = sign_freq self.audio_freq = audio_freq self.signal_low_pass_cutoff = signal_low_pass_cutoff self.signal_low_pass_trans = signal_low_pass_trans self.audio_low_pass_cutoff = audio_low_pass_cutoff self.audio_low_pass_trans = audio_low_pass_trans self.use_dc_blocker = use_dc_blocker self.audio_gain = audio_gain # hyper parameter self.low_pass_ampl_bound = 0.1 self.low_pass_window = firdes.WIN_HAMMING self.low_pass_beta = 6.76 ################################################## # Submodule ################################################## self.input_resample = filter.rational_resampler_ccf( interpolation=2000000, decimation=sign_freq, taps=None, fractional_bw=None) self.signal_low_pass_filter = eewls.auto_gain_low_pass_filter( filter.fir_filter_ccf, 8, self.low_pass_ampl_bound, 2000000, self.signal_low_pass_cutoff, self.signal_low_pass_trans, self.low_pass_window, self.low_pass_beta, str(complex)) self.am_demod = analog.am_demod_cf(channel_rate=50000, audio_decim=5, audio_pass=5000, audio_stop=5500) self.resampler = filter.rational_resampler_fff( interpolation=48 * self.audio_freq * 2 / 96000, decimation=50, taps=None, fractional_bw=None) self.audio_filter = filter.interp_fir_filter_fff( 1, firdes.low_pass(self.audio_gain, self.audio_freq * 2, self.audio_low_pass_cutoff, self.audio_low_pass_trans, self.low_pass_window, self.low_pass_beta)) gr.hier_block2.__init__( self, "fm_audio_decoder", gr.io_signature( 1, 1, self.input_resample.input_signature().sizeof_stream_item(0)), gr.io_signature( 1, 1, self.audio_filter.output_signature().sizeof_stream_item(0))) if self.use_dc_blocker: self.dc_blocker = filter.dc_blocker_cc(256, True) ################################################## # Connections ################################################## self.connect((self, 0), (self.input_resample, 0)) self.connect((self.input_resample, 0), (self.signal_low_pass_filter, 0)) if self.use_dc_blocker: self.connect((self.signal_low_pass_filter, 0), (self.dc_blocker, 0)) self.connect((self.dc_blocker, 0), (self.am_demod, 0)) else: self.connect((self.signal_low_pass_filter, 0), (self.am_demod, 0)) self.connect((self.am_demod, 0), (self.resampler, 0)) self.connect((self.resampler, 0), (self.audio_filter, 0)) self.connect((self.audio_filter, 0), (self, 0))
def __init__(self, magnitude=0, phase=0, mode=0): ''' This block implements the single branch IQ imbalance transmitter and receiver models. Developed from source (2014): "In-Phase and Quadrature Imbalance: Modeling, Estimation, and Compensation" TX Impairment: {R}--|Multiply: 10**(mag/20)|--+--|Multiply: cos(pi*degree/180)|--X1 Input ---|Complex2Float|---| +--|Multiply: sin(pi*degree/180)|--X2 {I}--| Adder | X2--| (+) |--X3 X1--{R}--| Float 2 |--- Output X3--{I}--| Complex | RX Impairment: {R}--|Multiply: cos(pi*degree/180)|-------| | Input ---|Complex2Float|---| | Adder |--X1 {I}--+--|Multiply: sin(pi*degree/180)|----| (+) | | +--X2 X1--|Multiply: 10**(mag/20)|--{R}--| Float 2 |--- Output X2---------------------------{I}--| Complex | (ASCII ART monospace viewing) ''' gr.hier_block2.__init__( self, "IQ Imbalance Generator", gr.io_signature(1, 1, gr.sizeof_gr_complex * 1), gr.io_signature(1, 1, gr.sizeof_gr_complex * 1), ) ################################################## # Parameters ################################################## self.magnitude = magnitude self.phase = phase self.mode = mode ################################################## # Blocks ################################################## # Same blocks for Transmitter and Receiver self.mag = blocks.multiply_const_vff((math.pow(10, magnitude / 20.0), )) self.sin_phase = blocks.multiply_const_vff( (math.sin(phase * math.pi / 180.0), )) self.cos_phase = blocks.multiply_const_vff( (math.cos(phase * math.pi / 180.0), )) self.f2c = blocks.float_to_complex(1) self.c2f = blocks.complex_to_float(1) self.adder = blocks.add_vff(1) ################################################## # Connections ################################################## if (self.mode): # Receiver Mode self.connect((self, 0), (self.c2f, 0)) self.connect((self.c2f, 0), (self.cos_phase, 0)) self.connect((self.cos_phase, 0), (self.adder, 0)) self.connect((self.c2f, 1), (self.sin_phase, 0)) self.connect((self.sin_phase, 0), (self.adder, 1)) self.connect((self.adder, 0), (self.mag, 0)) self.connect((self.mag, 0), (self.f2c, 0)) self.connect((self.c2f, 1), (self.f2c, 1)) self.connect((self.f2c, 0), (self, 0)) else: # Transmitter Mode self.connect((self, 0), (self.c2f, 0)) self.connect((self.c2f, 0), (self.mag, 0)) self.connect((self.mag, 0), (self.cos_phase, 0)) self.connect((self.cos_phase, 0), (self.f2c, 0)) self.connect((self.mag, 0), (self.sin_phase, 0)) self.connect((self.sin_phase, 0), (self.adder, 0)) self.connect((self.c2f, 1), (self.adder, 1)) self.connect((self.adder, 0), (self.f2c, 1)) self.connect((self.f2c, 0), (self, 0))
def __init__(self, samples_per_symbol=_def_samples_per_symbol, excess_bw=_def_excess_bw, verbose=_def_verbose, log=_def_log): """ Hierarchical block for RRC-filtered QPSK modulation. The input is a byte stream (unsigned char) and the output is the complex modulated signal at baseband. @param samples_per_symbol: samples per symbol >= 2 @type samples_per_symbol: integer @param excess_bw: Root-raised cosine filter excess bandwidth @type excess_bw: float @param verbose: Print information about modulator? @type verbose: bool @param debug: Print modualtion data to files? @type debug: bool """ gr.hier_block2.__init__( self, "cqpsk_mod", gr.io_signature(1, 1, gr.sizeof_char), # Input signature gr.io_signature(1, 1, gr.sizeof_gr_complex)) # Output signature self._samples_per_symbol = samples_per_symbol self._excess_bw = excess_bw if not isinstance(samples_per_symbol, int) or samples_per_symbol < 2: raise TypeError, ("sbp must be an integer >= 2, is %d" % samples_per_symbol) ntaps = 11 * samples_per_symbol arity = 8 # turn bytes into k-bit vectors self.bytes2chunks = \ blocks.packed_to_unpacked_bb(self.bits_per_symbol(), gr.GR_MSB_FIRST) # 0 +45 1 [+1] # 1 +135 3 [+3] # 2 -45 7 [-1] # 3 -135 5 [-3] self.pi4map = [1, 3, 7, 5] self.symbol_mapper = digital.map_bb(self.pi4map) self.diffenc = digital.diff_encoder_bb(arity) self.chunks2symbols = digital.chunks_to_symbols_bc( psk.constellation[arity]) # pulse shaping filter self.rrc_taps = filter.firdes.root_raised_cosine( self. _samples_per_symbol, # gain (sps since we're interpolating by sps) self._samples_per_symbol, # sampling rate 1.0, # symbol rate self._excess_bw, # excess bandwidth (roll-off factor) ntaps) self.rrc_filter = filter.interp_fir_filter_ccf( self._samples_per_symbol, self.rrc_taps) if verbose: self._print_verbage() if log: self._setup_logging() # Connect & Initialize base class self.connect(self, self.bytes2chunks, self.symbol_mapper, self.diffenc, self.chunks2symbols, self.rrc_filter, self)
def __init__(self): gr.hier_block2.__init__( self, "bch_viterbi_vfvb", gr.io_signature(1, 1, gr.sizeof_float * 120), # Input signature gr.io_signature(1, 1, gr.sizeof_char * 40)) # Output signature # Define blocks and connect them # Repeat input vector one time to get viterbi decoder state right (tail-biting stuff) #self.rpt = blocks.repeat(gr.sizeof_float * 120, 2) # viterbi decoder requires stream as input #self.vtos = blocks.vector_to_stream(1 * gr.sizeof_float, 120) # self.vtss = blocks.vector_to_streams(1* gr.sizeof_float, 120, "bch_viterbi_vector_to_streams_0") self.vtss = blocks.vector_to_streams(1 * gr.sizeof_float, 120) #self.app = blocks.streams_to_stream(1* gr.sizeof_float, 138, "bch_viterbi_streams_to_stream_0") self.app = blocks.streams_to_stream(1 * gr.sizeof_float, 138) self.connect(self, self.vtss) for i in range(18): self.connect((self.vtss, 120 - 18 + i), (self.app, i)) for i in range(120): self.connect((self.vtss, i), (self.app, i + 18)) # Correct FSM instantiation: k=num_input_bits, n=num_output_bits, Tuple[dim(k*n)] (decimal notation) self.fsm = trellis.fsm(1, 3, [91, 121, 117]) # Values for viterbi decoder K = 46 # steps for one coding block SO = 0 # initial state SK = -1 # final state (in this case unknown, therefore -1) D = 3 # dimensionality # D = 3 follows from the fact that 1 {0,1} input symbol of the encoder produces 3 {0,1} output symbols. # (packed into one byte {0,1,...,7} ) # with NRZ coding follows: # 0 --> 1 # 1 --> -1 # This leads to the following constellation input # | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | constellation = [ 1, 1, 1, 1, 1, -1, 1, -1, 1, 1, -1, -1, -1, 1, 1, -1, 1, -1, -1, -1, 1, -1, -1, -1 ] # print "len(constellation)/D = " + str(len(constellation)/D) + "\tfsm.O = " + str(self.fsm.O()) # Viterbi_combined input: FSM, K, SO, SK, D, TABLE, TYPE # FSM = Finite State Machine # K = number of output symbols produced by the FSM # SO = initial state of the FSM # SK = final state of the FSM (unknown in this example) # D = dimensionality # TABLE = constellation of the input symbols # self.vit = trellis.viterbi_combined_fb(self.fsm, K, SO, SK, D, constellation, 200, "bch_viterbi_combined_fb_0") self.vit = trellis.viterbi_combined_fb(self.fsm, K, SO, SK, D, constellation, 200) self.connect(self.app, self.vit) # connect all streams which are crated yet #self.connect(self,self.rpt,self.vtos,self.vit) # self.keep = blocks.keep_m_in_n(gr.sizeof_char, 40, 46, 6, "bch_viterbi_keep_m_in_n_0") self.keep = blocks.keep_m_in_n(gr.sizeof_char, 40, 46, 6) # self.tovec = blocks.stream_to_vector(1, 40, "bch_viterbi_stream_to_vector_0") self.tovec = blocks.stream_to_vector(1, 40) self.connect(self.vit, self.keep, self.tovec, self)
def __init__(self, baudrate, samp_rate, iq, deviation=None, subaudio=False, dc_block=True, dump_path=None, options=None): gr.hier_block2.__init__( self, "fsk_demodulator", gr.io_signature(1, 1, gr.sizeof_gr_complex if iq else gr.sizeof_float), gr.io_signature(1, 1, gr.sizeof_float)) options_block.__init__(self, options) use_agc = self.options.use_agc or not iq if dump_path is not None: dump_path = pathlib.Path(dump_path) if deviation is not None: _deviation = deviation else: _deviation = self.options.deviation if iq: self.demod = analog.quadrature_demod_cf(samp_rate / (2 * pi * _deviation)) self.connect(self, self.demod) else: self.demod = self sps = samp_rate / baudrate max_sps = 10 if sps > max_sps: decimation = ceil(sps / max_sps) else: decimation = 1 sps /= decimation if subaudio: # some not-so-bad filter parameters for subaudio processing subaudio_cutoff = 2.0 / 3.0 * baudrate subaudio_transition = subaudio_cutoff / 4.0 subaudio_taps = firdes.low_pass(1, samp_rate, subaudio_cutoff, subaudio_transition) self.subaudio_lowpass = filter.fir_filter_fff(1, subaudio_taps) # square pulse filter sqfilter_len = int(samp_rate / baudrate) taps = np.ones(sqfilter_len) / sqfilter_len self.lowpass = filter.fir_filter_fff(decimation, taps) if dc_block: self.dcblock = filter.dc_blocker_ff(ceil(sps * 32), True) else: self.dcblock = self.lowpass # to simplify connections below if use_agc: agc_constant = 2e-2 / sps # This gives a time constant of 50 symbols self.agc = rms_agc_f(agc_constant, 1) if dump_path is not None: self.waveform = blocks.file_sink(gr.sizeof_float, str(dump_path / 'waveform.f32')) ted_gain = 1.47 # "empiric" formula for TED gain of Gardner detector 1.47 symbol^{-1} damping = 1.0 self.clock_recovery = digital.symbol_sync_ff( digital.TED_GARDNER, sps, self.options.clk_bw, damping, ted_gain, self.options.clk_limit * sps, 1, digital.constellation_bpsk().base(), digital.IR_PFB_NO_MF) if dump_path is not None: self.clock_recovery_out = blocks.file_sink( gr.sizeof_float, str(dump_path / 'clock_recovery_out.f32'), False) self.clock_recovery_err = blocks.file_sink( gr.sizeof_float, str(dump_path / 'clock_recovery_err.f32'), False) self.clock_recovery_T_inst = blocks.file_sink( gr.sizeof_float, str(dump_path / 'clock_recovery_T_inst.f32'), False) self.clock_recovery_T_avg = blocks.file_sink( gr.sizeof_float, str(dump_path / 'clock_recovery_T_avg.f32'), False) self.connect(self.clock_recovery, self.clock_recovery_out) self.connect((self.clock_recovery, 1), self.clock_recovery_err) self.connect((self.clock_recovery, 2), self.clock_recovery_T_inst) self.connect((self.clock_recovery, 3), self.clock_recovery_T_avg) conns = [self.demod] if subaudio: conns.append(self.subaudio_lowpass) conns.append(self.lowpass) if dc_block: conns.append(self.dcblock) self.connect(*conns) if use_agc: self.connect(self.dcblock, self.agc, self.clock_recovery) if dump_path is not None: self.connect(self.agc, self.waveform) else: self.connect(self.dcblock, self.clock_recovery) if dump_path is not None: self.connect(self.dcblock, self.waveform) self.connect(self.clock_recovery, self)
def __init__(self, fft_length, cp_length, carrier_num, logging=False): """ OFDM synchronization using PN Correlation: T. M. Schmidl and D. C. Cox, "Robust Frequency and Timing Synchonization for OFDM," IEEE Trans. Communications, vol. 45, no. 12, 1997. """ gr.hier_block2.__init__(self, "ofdm_sync_pn", gr.io_signature(1, 1, gr.sizeof_gr_complex), # Input signature gr.io_signature2(2, 2, gr.sizeof_float, gr.sizeof_char)) # Output signature self.input = blocks.add_const_cc(0) # PN Sync # Create a delay line self.delay = blocks.delay(gr.sizeof_gr_complex, fft_length/2) # Correlation from ML Sync self.conjg = blocks.conjugate_cc(); self.corr = blocks.multiply_cc(); # Create a moving sum filter for the corr output if 1: moving_sum_taps = [1.0 for i in range(fft_length//2)] self.moving_sum_filter = filter.fir_filter_ccf(1,moving_sum_taps) else: moving_sum_taps = [complex(1.0,0.0) for i in range(fft_length//2)] self.moving_sum_filter = filter.fft_filter_ccc(1,moving_sum_taps) # Create a moving sum filter for the input self.inputmag2 = blocks.complex_to_mag_squared() movingsum2_taps = [1.0 for i in range(fft_length//2)] if 1: self.inputmovingsum = filter.fir_filter_fff(1,movingsum2_taps) else: self.inputmovingsum = filter.fft_filter_fff(1,movingsum2_taps) self.square = blocks.multiply_ff() self.normalize = blocks.divide_ff() # Get magnitude (peaks) and angle (phase/freq error) self.c2mag = blocks.complex_to_mag_squared() self.angle = blocks.complex_to_arg() self.sample_and_hold = gr_papyrus.sample_and_hold_ff() #ML measurements input to sampler block and detect self.sub1 = blocks.add_const_ff(-1) # linklab, change peak detector parameters: use higher threshold to detect rise/fall of peak #self.pk_detect = gr.peak_detector_fb(0.20, 0.20, 30, 0.001) self.pk_detect = gr_papyrus.peak_detector_fb(0.50, 0.60, 30, 0.001, carrier_num) # linklab #self.pk_detect = gr.peak_detector2_fb(9) self.connect(self, self.input) # Calculate the frequency offset from the correlation of the preamble self.connect(self.input, self.delay) self.connect(self.input, (self.corr,0)) self.connect(self.delay, self.conjg) self.connect(self.conjg, (self.corr,1)) self.connect(self.corr, self.moving_sum_filter) self.connect(self.moving_sum_filter, self.c2mag) self.connect(self.moving_sum_filter, self.angle) self.connect(self.angle, (self.sample_and_hold,0)) # Get the power of the input signal to normalize the output of the correlation self.connect(self.input, self.inputmag2, self.inputmovingsum) self.connect(self.inputmovingsum, (self.square,0)) self.connect(self.inputmovingsum, (self.square,1)) self.connect(self.square, (self.normalize,1)) self.connect(self.c2mag, (self.normalize,0)) # Create a moving sum filter for the corr output matched_filter_taps = [1.0/cp_length for i in range(cp_length)] self.matched_filter = filter.fir_filter_fff(1,matched_filter_taps) self.connect(self.normalize, self.matched_filter) # linklab, provide the signal power into peak detector, linklab self.connect(self.square, (self.pk_detect,1)) #self.connect(self.matched_filter, self.sub1, self.pk_detect) self.connect(self.matched_filter, self.sub1, (self.pk_detect, 0)) #self.connect(self.matched_filter, self.pk_detect) self.connect(self.pk_detect, (self.sample_and_hold,1)) # Set output signals # Output 0: fine frequency correction value # Output 1: timing signal self.connect(self.sample_and_hold, (self,0)) self.connect(self.pk_detect, (self,1)) if logging: self.connect(self.matched_filter, gr.file_sink(gr.sizeof_float, "ofdm_sync_pn-mf_f.dat")) self.connect(self.normalize, gr.file_sink(gr.sizeof_float, "ofdm_sync_pn-theta_f.dat")) self.connect(self.angle, gr.file_sink(gr.sizeof_float, "ofdm_sync_pn-epsilon_f.dat")) self.connect(self.pk_detect, gr.file_sink(gr.sizeof_char, "ofdm_sync_pn-peaks_b.dat")) self.connect(self.sample_and_hold, gr.file_sink(gr.sizeof_float, "ofdm_sync_pn-sample_and_hold_f.dat")) self.connect(self.input, gr.file_sink(gr.sizeof_gr_complex, "ofdm_sync_pn-input_c.dat"))
def __init__(self, k, cl_loop_bandwidth, cl_order, cl_freq_sub, ss_sps, ss_loop_bandwidth, ss_ted_gain, ss_damping, ss_max_dev, ss_out_ss, ss_interpolation, ss_ted_type, ss_constellation, ss_nfilter, ss_pfb_mf_taps, sel_costas, sel_spl, samp_rate): gr.hier_block2.__init__( self, "demodulator", gr.io_signature(1, 1, gr.sizeof_float), # Input signature gr.io_signature(1, 1, gr.sizeof_char)) # Output signature ################################################## # Variables ################################################## self.k = k self.cl_loop_bandwidth = cl_loop_bandwidth self.cl_order = cl_order self.cl_freq_sub = cl_freq_sub self.ss_sps = ss_sps self.ss_loop_bandwidth = ss_loop_bandwidth self.ss_ted_gain = ss_ted_gain self.ss_damping = ss_damping self.ss_max_dev = ss_max_dev self.ss_out_ss = ss_out_ss self.ss_interpolation = ss_interpolation self.ss_ted_type = ss_ted_type self.ss_constellation = ss_constellation self.ss_nfilter = ss_nfilter self.ss_pfb_mf_taps = ss_pfb_mf_taps self.sel_costas = sel_costas self.sel_spl = sel_spl self.samp_rate = samp_rate ################################################## # Blocks ################################################## self.digital_sync = digital.symbol_sync_ff( self.ss_ted_type, self.ss_sps, self.ss_loop_bandwidth, self.ss_damping, self.ss_ted_gain, self.ss_max_dev, self.ss_out_ss, self.ss_constellation, self.ss_interpolation, self.ss_nfilter, (self.ss_pfb_mf_taps)) self.spl_decoder = ecss.spl_decoder() self.costas_loop_cc = digital.costas_loop_cc(self.cl_loop_bandwidth, self.cl_order, False) self.signal_gen = analog.sig_source_c(samp_rate, analog.GR_SIN_WAVE, self.cl_freq_sub, 1, 0) self.multiply = blocks.multiply_vcc(1) self.hilbert = filter.hilbert_fc(65, firdes.WIN_HAMMING, 6.76) self.null_complex = blocks.null_sink(gr.sizeof_gr_complex * 1) self.null_float = blocks.null_sink(gr.sizeof_float * 1) self.to_char = blocks.float_to_uchar() self.unpack = blocks.unpack_k_bits_bb(k) ################################################## # Connections ################################################## if (sel_costas == 0): # if (type == 0): # self.connect(self, (self.multiply, 0)) # else: self.connect(self, self.hilbert, (self.multiply, 0)) self.connect(self.signal_gen, (self.multiply, 1)) self.connect(self.multiply, self.costas_loop_cc) self.connect((self.costas_loop_cc, 0), self.null_complex) self.connect((self.costas_loop_cc, 1), self.null_float) self.connect((self.costas_loop_cc, 2), self.digital_sync) else: self.connect(self, self.digital_sync) if (sel_spl == 0): self.connect(self.digital_sync, self.spl_decoder, self.unpack, self) else: self.connect(self.digital_sync, self.to_char, self.unpack, self)
def __init__(self, samples_per_symbol=_def_samples_per_symbol, excess_bw=_def_excess_bw, costas_alpha=_def_costas_alpha, gain_mu=_def_gain_mu, mu=_def_mu, omega_relative_limit=_def_omega_relative_limit, gray_code=_def_gray_code, verbose=_def_verbose, log=_def_log): """ Hierarchical block for RRC-filtered CQPSK demodulation The input is the complex modulated signal at baseband. The output is a stream of floats in [ -3 / -1 / +1 / +3 ] @param samples_per_symbol: samples per symbol >= 2 @type samples_per_symbol: float @param excess_bw: Root-raised cosine filter excess bandwidth @type excess_bw: float @param costas_alpha: loop filter gain @type costas_alphas: float @param gain_mu: for M&M block @type gain_mu: float @param mu: for M&M block @type mu: float @param omega_relative_limit: for M&M block @type omega_relative_limit: float @param gray_code: Tell modulator to Gray code the bits @type gray_code: bool @param verbose: Print information about modulator? @type verbose: bool @param debug: Print modualtion data to files? @type debug: bool """ gr.hier_block2.__init__( self, "cqpsk_demod", gr.io_signature(1, 1, gr.sizeof_gr_complex), # Input signature gr.io_signature(1, 1, gr.sizeof_float)) # Output signature self._samples_per_symbol = samples_per_symbol self._excess_bw = excess_bw self._costas_alpha = costas_alpha self._mm_gain_mu = gain_mu self._mm_mu = mu self._mm_omega_relative_limit = omega_relative_limit self._gray_code = gray_code if samples_per_symbol < 2: raise TypeError, "sbp must be >= 2, is %d" % samples_per_symbol arity = pow(2, self.bits_per_symbol()) # Automatic gain control scale = (1.0 / 16384.0) self.pre_scaler = blocks.multiply_const_cc( scale) # scale the signal from full-range to +-1 #self.agc = gr.agc2_cc(0.6e-1, 1e-3, 1, 1, 100) self.agc = analog.feedforward_agc_cc(16, 2.0) # RRC data filter ntaps = 11 * samples_per_symbol self.rrc_taps = filter.firdes.root_raised_cosine( 1.0, # gain self._samples_per_symbol, # sampling rate 1.0, # symbol rate self._excess_bw, # excess bandwidth (roll-off factor) ntaps) self.rrc_filter = filter.interp_fir_filter_ccf(1, self.rrc_taps) if not self._mm_gain_mu: sbs_to_mm = { 2: 0.050, 3: 0.075, 4: 0.11, 5: 0.125, 6: 0.15, 7: 0.15 } self._mm_gain_mu = sbs_to_mm[samples_per_symbol] self._mm_omega = self._samples_per_symbol self._mm_gain_omega = .25 * self._mm_gain_mu * self._mm_gain_mu self._costas_beta = 0.25 * self._costas_alpha * self._costas_alpha fmin = -0.025 fmax = 0.025 self.receiver = digital.mpsk_receiver_cc(arity, pi / 4.0, 2 * pi / 150, fmin, fmax, self._mm_mu, self._mm_gain_mu, self._mm_omega, self._mm_gain_omega, self._mm_omega_relative_limit) self.receiver.set_alpha(self._costas_alpha) self.receiver.set_beta(self._costas_beta) # Perform Differential decoding on the constellation self.diffdec = digital.diff_phasor_cc() # take angle of the difference (in radians) self.to_float = blocks.complex_to_arg() # convert from radians such that signal is in -3/-1/+1/+3 self.rescale = blocks.multiply_const_ff(1 / (pi / 4)) if verbose: self._print_verbage() if log: self._setup_logging() # Connect & Initialize base class self.connect(self, self.pre_scaler, self.agc, self.rrc_filter, self.receiver, self.diffdec, self.to_float, self.rescale, self)
def __init__(self, dab_params, bit_rate, address, subch_size, protection, output_float, verbose=False, debug=False): if output_float: # map short samples to the range [-1,1] in floats gr.hier_block2.__init__( self, "dabplus_audio_decoder_ff", # Input signature gr.io_signature(1, 1, gr.sizeof_float * dab_params.num_carriers * 2), # Output signature gr.io_signature2(2, 2, gr.sizeof_float, gr.sizeof_float)) else: # output signed 16 bit integers (directly from decoder) gr.hier_block2.__init__( self, "dabplus_audio_decoder_ff", # Input signature gr.io_signature(1, 1, gr.sizeof_float * dab_params.num_carriers * 2), # Output signature gr.io_signature2(2, 2, gr.sizeof_short, gr.sizeof_short)) self.dp = dab_params self.bit_rate_n = bit_rate / 8 self.address = address self.size = subch_size self.protection = protection self.output_float = output_float self.verbose = verbose self.debug = debug # sanity check # if self.bit_rate_n*6 != self.size: # log = gr.logger("log") # log.debug("bit rate and subchannel size are not fitting") # log.set_level("ERROR") # raise ValueError # MSC decoder extracts logical frames out of transmission frame and decodes it self.msc_decoder = grdab.msc_decode(self.dp, self.address, self.size, self.protection, self.verbose, self.debug) # firecode synchronizes to superframes and checks self.firecode = grdab.firecode_check_bb_make(self.bit_rate_n) # Reed-Solomon error repair self.rs = grdab.reed_solomon_decode_bb_make(self.bit_rate_n) # mp4 decoder self.mp4 = grdab.mp4_decode_bs_make(self.bit_rate_n) self.connect((self, 0), self.msc_decoder, self.firecode, self.rs, self.mp4) if self.output_float: # map short samples to the range [-1,1] in floats self.s2f_left = blocks.short_to_float_make(1, 32767) self.s2f_right = blocks.short_to_float_make(1, 32767) self.gain_left = blocks.multiply_const_ff(1, 1) self.gain_right = blocks.multiply_const_ff(1, 1) self.connect((self.mp4, 0), self.s2f_left, self.gain_left, (self, 0)) self.connect((self.mp4, 1), self.s2f_right, self.gain_right, (self, 1)) else: # output signed 16 bit integers (directly from decoder) self.connect((self.mp4, 0), (self, 0)) self.connect((self.mp4, 1), (self, 1))
def __init__(self, options, payload='', msgq_limit=2, pad_for_usrp=False): """ Hierarchical block for sending packets Packets to be sent are enqueued by calling send_pkt. The output is the complex modulated signal at baseband. @param options: pass modulation options from higher layers (fft length, occupied tones, etc.) @param msgq_limit: maximum number of messages in message queue @type msgq_limit: int @param pad_for_usrp: If true, packets are padded such that they end up a multiple of 128 samples """ gr.hier_block2.__init__( self, "ofdm_mod", gr.io_signature(0, 0, 0), # Input signature gr.io_signature(1, 1, gr.sizeof_gr_complex)) # Output signature self._fft_length = 64 self._total_sub_carriers = 53 self._data_subcarriers = 48 self._cp_length = 16 self._regime = options.regime self._symbol_length = self._fft_length + self._cp_length self._role = options.role # assuming we have 100Ms/s going to the USRP2 and 80 samples per symbol # we can calculate the OFDM symboltime (in microseconds) # depending on the interpolation factor self._symbol_time = options.interp * (self._fft_length + self._cp_length) / 100 win = [] if (self._regime == "1" or self._regime == "2"): rotated_const = ofdm_packet_utils.bpsk(self) elif (self._regime == "3" or self._regime == "4"): rotated_const = ofdm_packet_utils.qpsk(self) elif (self._regime == "5" or self._regime == "6"): rotated_const = ofdm_packet_utils.qam16(self) elif (self._regime == "7" or self._regime == "8"): rotated_const = ofdm_packet_utils.qam64(self) # map groups of bits to complex symbols self._pkt_input = ftw.ofdm_mapper(rotated_const, msgq_limit, self._data_subcarriers, self._fft_length) # insert pilot symbols (use pnc block * by lzyou) if self._role == 'A': print " >>> [FPNC]: *A* Insert Pilot" self.pilot = ftw.pnc_ofdm_pilot_cc(self._data_subcarriers, 1) elif self._role == 'B': print " >>> [FPNC]: *B* Insert Pilot" self.pilot = ftw.pnc_ofdm_pilot_cc(self._data_subcarriers, 2) else: print " >>> [FTW ]: Insert Pilot" self.pilot = ftw.ofdm_pilot_cc(self._data_subcarriers) # just for test #self.pilot = ftw.pnc_ofdm_pilot_cc(self._data_subcarriers, 1) #self.pilot = ftw.pnc_ofdm_pilot_cc(self._data_subcarriers, 2) # move subcarriers to their designated place and insert DC self.cmap = ftw.ofdm_cmap_cc(self._fft_length, self._total_sub_carriers) # inverse fast fourier transform self.ifft = gr.fft_vcc(self._fft_length, False, win, False) # add cyclic prefix from gnuradio import digital self.cp_adder = digital.ofdm_cyclic_prefixer(self._fft_length, self._symbol_length) self.connect( gr.null_source(gr.sizeof_char), (self.cp_adder, 1)) # Note: dirty modification to accomdate the API change # scale accordingly self.scale = gr.multiply_const_cc(1.0 / math.sqrt(self._fft_length)) # we need to know the number of OFDM data symbols for preamble and zerogap info = ofdm_packet_utils.get_info(payload, options.regime, self._symbol_time) N_sym = info["N_sym"] # add training sequence (modify by lzyou) if self._role == 'A': print " >>> [FPNC]: *A* Insert Preamble" self.preamble = ofdm_packet_utils.insert_preamble( self._symbol_length, N_sym, 'A') elif self._role == 'B': print " >>> [FPNC]: *B* Insert Preamble" self.preamble = ofdm_packet_utils.insert_preamble( self._symbol_length, N_sym, 'B') else: print " >>> [FTW ]: Insert Preamble" self.preamble = ofdm_packet_utils.insert_preamble( self._symbol_length, N_sym) # append zero samples at the end (receiver needs that to decode) if self._role == None: print " >>> [FTW ]: Insert Zerogap" self.zerogap = ofdm_packet_utils.insert_zerogap( self._symbol_length, N_sym) else: print " >>> [FPNC]: Insert Zerogap" self.zerogap = ofdm_packet_utils.insert_zerogap( self._symbol_length, N_sym, 'FPNC') self.s2v = gr.stream_to_vector(gr.sizeof_gr_complex, self._symbol_length) self.v2s = gr.vector_to_stream(gr.sizeof_gr_complex, self._symbol_length) # swap real and immaginary component before sending (GNURadio/USRP2 bug!) if options.swapIQ == True: self.gr_complex_to_imag_0 = gr.complex_to_imag(1) self.gr_complex_to_real_0 = gr.complex_to_real(1) self.gr_float_to_complex_0 = gr.float_to_complex(1) self.connect((self.v2s, 0), (self.gr_complex_to_imag_0, 0)) self.connect((self.v2s, 0), (self.gr_complex_to_real_0, 0)) self.connect((self.gr_complex_to_real_0, 0), (self.gr_float_to_complex_0, 1)) self.connect((self.gr_complex_to_imag_0, 0), (self.gr_float_to_complex_0, 0)) self.connect((self.gr_float_to_complex_0, 0), (self)) elif options.swapIQ == False: self.gr_complex_to_imag_0 = gr.complex_to_imag(1) self.gr_complex_to_real_0 = gr.complex_to_real(1) self.gr_float_to_complex_0 = gr.float_to_complex(1) self.connect((self.v2s, 0), (self.gr_complex_to_imag_0, 0)) self.connect((self.v2s, 0), (self.gr_complex_to_real_0, 0)) self.connect((self.gr_complex_to_imag_0, 0), (self.gr_float_to_complex_0, 1)) self.connect((self.gr_complex_to_real_0, 0), (self.gr_float_to_complex_0, 0)) self.connect((self.gr_float_to_complex_0, 0), (self)) # connect the blocks self.connect((self._pkt_input, 0), (self.pilot, 0)) self.connect((self._pkt_input, 1), (self.preamble, 1)) self.connect((self.preamble, 1), (self.zerogap, 1)) self.connect(self.pilot, self.cmap, self.ifft, self.cp_adder, self.scale, self.s2v, self.preamble, self.zerogap, self.v2s) if options.log: self.connect( (self._pkt_input), gr.file_sink(gr.sizeof_gr_complex * self._data_subcarriers, "ofdm_mapper.dat")) self.connect( self.pilot, gr.file_sink( gr.sizeof_gr_complex * (5 + self._data_subcarriers), "ofdm_pilot.dat")) self.connect( self.cmap, gr.file_sink(gr.sizeof_gr_complex * self._fft_length, "ofdm_cmap.dat")) self.connect( self.ifft, gr.file_sink(gr.sizeof_gr_complex * self._fft_length, "ofdm_ifft.dat")) self.connect( self.cp_adder, gr.file_sink(gr.sizeof_gr_complex, "ofdm_cp_adder.dat")) self.connect(self.scale, gr.file_sink(gr.sizeof_gr_complex, "ofdm_scale.dat")) self.connect( self.preamble, gr.file_sink(gr.sizeof_gr_complex * self._symbol_length, "ofdm_preamble.dat")) self.connect( self.zerogap, gr.file_sink(gr.sizeof_gr_complex * self._symbol_length, "ofdm_zerogap.dat"))
def __init__( self, parent, x_offset=0, ref_level=50, #sample_rate=1, data_len=512 * 2, #fft_rate=waterfall_window.DEFAULT_FRAME_RATE, #average=False, #avg_alpha=None, title='', size=waterfall_window.DEFAULT_WIN_SIZE, ref_scale=2.0, dynamic_range=80, num_lines=256, win=None, always_run=False, **kwargs #do not end with a comma ): #ensure avg alpha #if avg_alpha is None: avg_alpha = 2.0/fft_rate #init gr.hier_block2.__init__( self, "waterfall_sink", gr.io_signature(1, 1, gr.sizeof_float * data_len), gr.io_signature(0, 0, 0), ) #blocks msgq = gr.msg_queue(2) sink = blocks.message_sink(gr.sizeof_float * data_len, msgq, True) #controller self.controller = pubsub() #start input watcher common.input_watcher(msgq, self.controller, MSG_KEY) #create window self.win = waterfall_window.waterfall_window( parent=parent, controller=self.controller, size=size, title=title, data_len=data_len, num_lines=num_lines, x_offset=x_offset, #decimation_key=DECIMATION_KEY, #sample_rate_key=SAMPLE_RATE_KEY, #frame_rate_key=FRAME_RATE_KEY, dynamic_range=dynamic_range, ref_level=ref_level, #average_key=AVERAGE_KEY, #avg_alpha_key=AVG_ALPHA_KEY, msg_key=MSG_KEY, ) common.register_access_methods(self, self.win) setattr(self.win, 'set_baseband_freq', getattr(self, 'set_baseband_freq')) #BACKWARDS # FIXME #connect if always_run: connect_fn = self.connect else: connect_fn = self.wxgui_connect connect_fn(self, sink)
def __init__(self, demod_rate, audio_decimation): """ Hierarchical block for demodulating a broadcast FM signal. The input is the downconverted complex baseband signal (gr_complex). The output is two streams of the demodulated audio (float) 0=Left, 1=Right. Args: demod_rate: input sample rate of complex baseband input. (float) audio_decimation: how much to decimate demod_rate to get to audio. (integer) """ gr.hier_block2.__init__( self, "wfm_rcv_fmdet", gr.io_signature(1, 1, gr.sizeof_gr_complex), # Input signature gr.io_signature(2, 2, gr.sizeof_float)) # Output signature lowfreq = -125e3 / demod_rate highfreq = 125e3 / demod_rate audio_rate = demod_rate / audio_decimation # We assign to self so that outsiders can grab the demodulator # if they need to. E.g., to plot its output. # # input: complex; output: float self.fm_demod = analog.fmdet_cf(demod_rate, lowfreq, highfreq, 0.05) # input: float; output: float self.deemph_Left = fm_deemph(audio_rate) self.deemph_Right = fm_deemph(audio_rate) # compute FIR filter taps for audio filter width_of_transition_band = audio_rate / 32 audio_coeffs = filter.firdes.low_pass( 1.0, # gain demod_rate, # sampling rate 15000, width_of_transition_band, filter.firdes.WIN_HAMMING) # input: float; output: float self.audio_filter = filter.fir_filter_fff(audio_decimation, audio_coeffs) if 1: # Pick off the stereo carrier/2 with this filter. It # attenuated 10 dB so apply 10 dB gain We pick off the # negative frequency half because we want to base band by # it! ## NOTE THIS WAS HACKED TO OFFSET INSERTION LOSS DUE TO ## DEEMPHASIS stereo_carrier_filter_coeffs = \ filter.firdes.complex_band_pass(10.0, demod_rate, -19020, -18980, width_of_transition_band, filter.firdes.WIN_HAMMING) #print "len stereo carrier filter = ",len(stereo_carrier_filter_coeffs) #print "stereo carrier filter ", stereo_carrier_filter_coeffs #print "width of transition band = ",width_of_transition_band, " audio rate = ", audio_rate # Pick off the double side band suppressed carrier # Left-Right audio. It is attenuated 10 dB so apply 10 dB # gain stereo_dsbsc_filter_coeffs = \ filter.firdes.complex_band_pass(20.0, demod_rate, 38000-15000 / 2, 38000+15000 / 2, width_of_transition_band, filter.firdes.WIN_HAMMING) #print "len stereo dsbsc filter = ",len(stereo_dsbsc_filter_coeffs) #print "stereo dsbsc filter ", stereo_dsbsc_filter_coeffs # construct overlap add filter system from coefficients # for stereo carrier self.stereo_carrier_filter = \ filter.fir_filter_fcc(audio_decimation, stereo_carrier_filter_coeffs) # carrier is twice the picked off carrier so arrange to do # a complex multiply self.stereo_carrier_generator = blocks.multiply_cc() # Pick off the rds signal stereo_rds_filter_coeffs = \ filter.firdes.complex_band_pass(30.0, demod_rate, 57000 - 1500, 57000 + 1500, width_of_transition_band, filter.firdes.WIN_HAMMING) #print "len stereo dsbsc filter = ",len(stereo_dsbsc_filter_coeffs) #print "stereo dsbsc filter ", stereo_dsbsc_filter_coeffs # construct overlap add filter system from coefficients for stereo carrier self.rds_signal_filter = \ filter.fir_filter_fcc(audio_decimation, stereo_rds_filter_coeffs) self.rds_carrier_generator = blocks.multiply_cc() self.rds_signal_generator = blocks.multiply_cc() self_rds_signal_processor = blocks.null_sink(gr.sizeof_gr_complex) loop_bw = 2 * math.pi / 100.0 max_freq = -2.0 * math.pi * 18990 / audio_rate min_freq = -2.0 * math.pi * 19010 / audio_rate self.stereo_carrier_pll_recovery = analog.pll_refout_cc( loop_bw, max_freq, min_freq) #self.stereo_carrier_pll_recovery.squelch_enable(False) ##pll_refout does not have squelch yet, so disabled for #now # set up mixer (multiplier) to get the L-R signal at # baseband self.stereo_basebander = blocks.multiply_cc() # pick off the real component of the basebanded L-R # signal. The imaginary SHOULD be zero self.LmR_real = blocks.complex_to_real() self.Make_Left = blocks.add_ff() self.Make_Right = blocks.sub_ff() self.stereo_dsbsc_filter = \ filter.fir_filter_fcc(audio_decimation, stereo_dsbsc_filter_coeffs) if 1: # send the real signal to complex filter to pick off the # carrier and then to one side of a multiplier self.connect(self, self.fm_demod, self.stereo_carrier_filter, self.stereo_carrier_pll_recovery, (self.stereo_carrier_generator, 0)) # send the already filtered carrier to the otherside of the carrier # the resulting signal from this multiplier is the carrier # with correct phase but at -38000 Hz. self.connect(self.stereo_carrier_pll_recovery, (self.stereo_carrier_generator, 1)) # send the new carrier to one side of the mixer (multiplier) self.connect(self.stereo_carrier_generator, (self.stereo_basebander, 0)) # send the demphasized audio to the DSBSC pick off filter, the complex # DSBSC signal at +38000 Hz is sent to the other side of the mixer/multiplier # the result is BASEBANDED DSBSC with phase zero! self.connect(self.fm_demod, self.stereo_dsbsc_filter, (self.stereo_basebander, 1)) # Pick off the real part since the imaginary is # theoretically zero and then to one side of a summer self.connect(self.stereo_basebander, self.LmR_real, (self.Make_Left, 0)) #take the same real part of the DSBSC baseband signal and #send it to negative side of a subtracter self.connect(self.LmR_real, (self.Make_Right, 1)) # Make rds carrier by taking the squared pilot tone and # multiplying by pilot tone self.connect(self.stereo_basebander, (self.rds_carrier_generator, 0)) self.connect(self.stereo_carrier_pll_recovery, (self.rds_carrier_generator, 1)) # take signal, filter off rds, send into mixer 0 channel self.connect(self.fm_demod, self.rds_signal_filter, (self.rds_signal_generator, 0)) # take rds_carrier_generator output and send into mixer 1 # channel self.connect(self.rds_carrier_generator, (self.rds_signal_generator, 1)) # send basebanded rds signal and send into "processor" # which for now is a null sink self.connect(self.rds_signal_generator, self_rds_signal_processor) if 1: # pick off the audio, L+R that is what we used to have and # send it to the summer self.connect(self.fm_demod, self.audio_filter, (self.Make_Left, 1)) # take the picked off L+R audio and send it to the PLUS # side of the subtractor self.connect(self.audio_filter, (self.Make_Right, 0)) # The result of Make_Left gets (L+R) + (L-R) and results in 2*L # The result of Make_Right gets (L+R) - (L-R) and results in 2*R self.connect(self.Make_Left, self.deemph_Left, (self, 0)) self.connect(self.Make_Right, self.deemph_Right, (self, 1))
def __init__(self, samples_per_symbol=_def_samples_per_symbol, sensitivity=_def_sensitivity, gain_mu=_def_gain_mu, mu=_def_mu, omega_relative_limit=_def_omega_relative_limit, freq_error=_def_freq_error, verbose=_def_verbose, log=_def_log): """ Hierarchical block for Gaussian Minimum Shift Key (GFSK) demodulation. The input is the complex modulated signal at baseband. The output is a stream of bits packed 1 bit per byte (the LSB) Args: samples_per_symbol: samples per baud (integer) verbose: Print information about modulator? (bool) log: Print modualtion data to files? (bool) Clock recovery parameters. These all have reasonable defaults. Args: gain_mu: controls rate of mu adjustment (float) mu: fractional delay [0.0, 1.0] (float) omega_relative_limit: sets max variation in omega (float, typically 0.000200 (200 ppm)) freq_error: bit rate error as a fraction float: """ gr.hier_block2.__init__( self, "gfsk_demod", gr.io_signature(1, 1, gr.sizeof_gr_complex), # Input signature gr.io_signature(1, 1, gr.sizeof_char)) # Output signature self._samples_per_symbol = samples_per_symbol self._gain_mu = gain_mu self._mu = mu self._omega_relative_limit = omega_relative_limit self._freq_error = freq_error self._differential = False if samples_per_symbol < 2: raise TypeError("samples_per_symbol >= 2, is %f" % samples_per_symbol) self._omega = samples_per_symbol * (1 + self._freq_error) if not self._gain_mu: self._gain_mu = 0.175 self._gain_omega = .25 * self._gain_mu * self._gain_mu # critically damped # Demodulate FM #sensitivity = (pi / 2) / samples_per_symbol self.fmdemod = analog.quadrature_demod_cf(1.0 / sensitivity) # the clock recovery block tracks the symbol clock and resamples as needed. # the output of the block is a stream of soft symbols (float) self.clock_recovery = digital.clock_recovery_mm_ff( self._omega, self._gain_omega, self._mu, self._gain_mu, self._omega_relative_limit) # slice the floats at 0, outputting 1 bit (the LSB of the output byte) per sample self.slicer = digital.binary_slicer_fb() if verbose: self._print_verbage() if log: self._setup_logging() # Connect & Initialize base class self.connect(self, self.fmdemod, self.clock_recovery, self.slicer, self)
def __init__(self, dest=_def_dest, do_imbe=_def_do_imbe, num_ambe=_def_num_ambe, wireshark_host=_def_wireshark_host, udp_port=_def_udp_port, do_msgq=False, msgq=None, audio_output=_def_audio_output, debug=_def_debug): """ Hierarchical block for P25 decoding. @param debug: debug level @type debug: int """ gr.hier_block2.__init__( self, "p25_demod_c", gr.io_signature(1, 1, gr.sizeof_char), # Input signature gr.io_signature(0, 0, 0)) # Output signature assert 0 <= num_ambe <= _def_max_tdma_timeslots assert not (num_ambe > 1 and dest != 'wav') self.debug = debug self.dest = dest do_output = 1 do_audio_output = True if msgq is None: msgq = gr.msg_queue(1) self.p25_decoders = [] self.audio_s2f = [] self.scaler = [] self.audio_sink = [] self.xorhash = [] num_decoders = 1 if num_ambe > 1: num_decoders += num_ambe - 1 for slot in xrange(num_decoders): self.p25_decoders.append( op25_repeater.p25_frame_assembler(wireshark_host, udp_port, debug, do_imbe, do_output, do_msgq, msgq, do_audio_output, True)) self.p25_decoders[slot].set_slotid(slot) self.audio_s2f.append( blocks.short_to_float()) # another ridiculous conversion self.scaler.append(blocks.multiply_const_ff(1 / 32768.0)) self.xorhash.append('') if dest == 'wav': filename = 'default-%f-%d.wav' % (time.time(), slot) n_channels = 1 sample_rate = 8000 bits_per_sample = 16 self.audio_sink.append( blocks.wavfile_sink(filename, n_channels, sample_rate, bits_per_sample)) elif dest == 'audio': self.audio_sink.append( audio.sink(_def_audio_rate, audio_output, True)) self.connect(self, self.p25_decoders[slot], self.audio_s2f[slot], self.scaler[slot], self.audio_sink[slot])
def __init__( self, parent, baseband_freq=0, ref_scale=2.0, y_per_div=10, y_divs=8, ref_level=50, sample_rate=1, pspectrum_len=512, specest_rate=specest_window.DEFAULT_FRAME_RATE, average=False, avg_alpha=None, title='', size=specest_window.DEFAULT_WIN_SIZE, peak_hold=False, use_persistence=False, persist_alpha=None, n=1, m=150, nsamples=256, estimator='esprit', **kwargs #do not end with a comma ): #ensure avg alpha if avg_alpha is None: avg_alpha = 2.0 / specest_rate #ensure analog alpha if persist_alpha is None: actual_specest_rate = float(sample_rate / pspectrum_len) / float( max(1, int(float( (sample_rate / pspectrum_len) / specest_rate)))) #print "requested_specest_rate ",specest_rate #print "actual_specest_rate ",actual_specest_rate analog_cutoff_freq = 0.5 # Hertz #calculate alpha from wanted cutoff freq persist_alpha = 1.0 - math.exp( -2.0 * math.pi * analog_cutoff_freq / actual_specest_rate) #init gr.hier_block2.__init__( self, "spectrum_sink", gr.io_signature(1, 1, self._item_size), gr.io_signature(0, 0, 0), ) #blocks fft = self._specest_chain(sample_rate=sample_rate, pspectrum_len=pspectrum_len, frame_rate=specest_rate, ref_scale=ref_scale, avg_alpha=avg_alpha, average=average, n=n, m=m, nsamples=nsamples, estimator=estimator) msgq = gr.msg_queue(2) sink = blocks.message_sink(gr.sizeof_float * pspectrum_len, msgq, True) #controller self.controller = pubsub() self.controller.subscribe(AVERAGE_KEY, fft.set_average) self.controller.publish(AVERAGE_KEY, fft.average) self.controller.subscribe(AVG_ALPHA_KEY, fft.set_avg_alpha) self.controller.publish(AVG_ALPHA_KEY, fft.avg_alpha) self.controller.subscribe(SAMPLE_RATE_KEY, fft.set_sample_rate) self.controller.publish(SAMPLE_RATE_KEY, fft.sample_rate) #start input watcher common.input_watcher(msgq, self.controller, MSG_KEY) #create window self.win = specest_window.specest_window( parent=parent, controller=self.controller, size=size, title=title, real=self._real, spectrum_len=pspectrum_len, baseband_freq=baseband_freq, sample_rate_key=SAMPLE_RATE_KEY, y_per_div=y_per_div, y_divs=y_divs, ref_level=ref_level, average_key=AVERAGE_KEY, avg_alpha_key=AVG_ALPHA_KEY, peak_hold=peak_hold, msg_key=MSG_KEY, use_persistence=use_persistence, persist_alpha=persist_alpha, ) common.register_access_methods(self, self.win) setattr(self.win, 'set_baseband_freq', getattr(self, 'set_baseband_freq')) #BACKWARDS setattr(self.win, 'set_peak_hold', getattr(self, 'set_peak_hold')) #BACKWARDS #connect self.wxgui_connect(self, fft, sink)
def __init__(self, samples_per_symbol=_def_samples_per_symbol, sensitivity=_def_sensitivity, bt=_def_bt, verbose=_def_verbose, log=_def_log): """ Hierarchical block for Gaussian Frequency Shift Key (GFSK) modulation. The input is a byte stream (unsigned char) and the output is the complex modulated signal at baseband. Args: samples_per_symbol: samples per baud >= 2 (integer) bt: Gaussian filter bandwidth * symbol time (float) verbose: Print information about modulator? (bool) debug: Print modualtion data to files? (bool) """ gr.hier_block2.__init__( self, "gfsk_mod", gr.io_signature(1, 1, gr.sizeof_char), # Input signature gr.io_signature(1, 1, gr.sizeof_gr_complex)) # Output signature samples_per_symbol = int(samples_per_symbol) self._samples_per_symbol = samples_per_symbol self._bt = bt self._differential = False if not isinstance(samples_per_symbol, int) or samples_per_symbol < 2: raise TypeError( "samples_per_symbol must be an integer >= 2, is %r" % (samples_per_symbol, )) ntaps = 4 * samples_per_symbol # up to 3 bits in filter at once #sensitivity = (pi / 2) / samples_per_symbol # phase change per bit = pi / 2 # Turn it into NRZ data. #self.nrz = digital.bytes_to_syms() self.unpack = blocks.packed_to_unpacked_bb(1, gr.GR_MSB_FIRST) self.nrz = digital.chunks_to_symbols_bf([-1, 1]) # Form Gaussian filter # Generate Gaussian response (Needs to be convolved with window below). self.gaussian_taps = filter.firdes.gaussian( 1.0, # gain samples_per_symbol, # symbol_rate bt, # bandwidth * symbol time ntaps # number of taps ) self.sqwave = (1, ) * samples_per_symbol # rectangular window self.taps = numpy.convolve(numpy.array(self.gaussian_taps), numpy.array(self.sqwave)) self.gaussian_filter = filter.interp_fir_filter_fff( samples_per_symbol, self.taps) # FM modulation self.fmmod = analog.frequency_modulator_fc(sensitivity) # small amount of output attenuation to prevent clipping USRP sink self.amp = blocks.multiply_const_cc(0.999) if verbose: self._print_verbage() if log: self._setup_logging() # Connect & Initialize base class self.connect(self, self.unpack, self.nrz, self.gaussian_filter, self.fmmod, self.amp, self)
def __init__(self, *args, **kwds): gr.hier_block2.__init__(self, "horizons", gr.io_signature(0, 0, 0), gr.io_signature(0, 0, 0)) self.thread = h.horizons_thread(*args, auto_start=False, **kwds)
def __init__(self, phase_noise_mag=0, magbal=0, phasebal=0, q_ofs=0, i_ofs=0, freq_offset=0, gamma=0, beta=0): gr.hier_block2.__init__( self, "Radio Impairments Model", gr.io_signature(1, 1, gr.sizeof_gr_complex * 1), gr.io_signature(1, 1, gr.sizeof_gr_complex * 1), ) ################################################## # Parameters ################################################## self.phase_noise_mag = phase_noise_mag self.magbal = magbal self.phasebal = phasebal self.q_ofs = q_ofs self.i_ofs = i_ofs self.freq_offset = freq_offset self.gamma = gamma self.beta = beta ################################################## # Blocks ################################################## self.phase_noise = phase_noise_gen(10.0**(phase_noise_mag / 20.0), .01) self.iq_imbalance = iqbal_gen(magbal, phasebal) self.channels_distortion_3_gen_0 = distortion_3_gen(beta) self.channels_distortion_2_gen_0 = distortion_2_gen(gamma) self.freq_modulator = blocks.multiply_cc() self.freq_offset_gen = analog.sig_source_c(1.0, analog.GR_COS_WAVE, freq_offset, 1, 0) self.freq_modulator_dcoffs = blocks.multiply_cc() self.freq_offset_conj = blocks.conjugate_cc() self.dc_offset = blocks.add_const_vcc((i_ofs + q_ofs * 1j, )) ################################################## # Frequency offset self.connect((self, 0), (self.freq_modulator, 1)) self.connect((self.freq_offset_gen, 0), (self.freq_offset_conj, 0)) self.connect((self.freq_offset_conj, 0), (self.freq_modulator, 0)) # Most distortions can be strung in a row self.connect( (self.freq_modulator, 0), (self.phase_noise, 0), (self.channels_distortion_3_gen_0, 0), (self.channels_distortion_2_gen_0, 0), (self.iq_imbalance, 0), (self.dc_offset, 0), ) # Frequency offset again self.connect((self.freq_offset_gen, 0), (self.freq_modulator_dcoffs, 0)) self.connect((self.dc_offset, 0), (self.freq_modulator_dcoffs, 1)) self.connect((self.freq_modulator_dcoffs, 0), (self, 0))
def __init__(self): gr.hier_block2.__init__(self, type(self).__name__, gr.io_signature(1, 1, gr.sizeof_gr_complex), gr.io_signature(0, 0, 0)) self.connect(self, blocks.null_sink(gr.sizeof_gr_complex))
def __init__( self, top_level_dir, channels=None, start=None, end=None, repeat=False, throttle=False, ): """Initialize source to directory containing Digital RF channels. Parameters ---------- top_level_dir : string Either a single top level directory containing Digital RF channel directories, or a list of such. A directory can be a file system path or a url, where the url points to a top level directory. Each must be a local path, or start with 'http://'', 'file://'', or 'ftp://''. Other Parameters ---------------- channels : None | string | int | iterable of previous If None, use all available channels in alphabetical order. Otherwise, use the channels in the order specified in the given iterable (a string or int is taken as a single-element iterable). A string is used to specify the channel name, while an int is used to specify the channel index in the sorted list of available channel names. start : None | string | long | iterable of previous Can be a single value or an iterable of values corresponding to `channels` giving the start of the channel's playback. If None or '', the start of the channel's available data is used. If an integer, it is interpreted as a sample index given in the number of samples since the epoch (time_since_epoch*sample_rate). If a float, it is interpreted as a timestamp (seconds since epoch). If a string, three forms are permitted: 1) a string which can be evaluated to an integer/float and interpreted as above, 2) a string beginning with '+' and followed by an integer (float) expression, interpreted as samples (seconds) from the start of the data, and 3) a time in ISO8601 format, e.g. '2016-01-01T16:24:00Z' end : None | string | long | iterable of previous Can be a single value or an iterable of values corresponding to `channels` giving the end of the channel's playback. If None or '', the end of the channel's available data is used. See `start` for a description of how this value is interpreted. repeat : bool If True, loop the data continuously from the start after the end is reached. If False, stop after the data is read once. throttle : bool If True, playback the samples at their recorded sample rate. If False, read samples as quickly as possible. Notes ----- A top level directory must contain files in the format: <channel>/<YYYY-MM-DDTHH-MM-SS/rf@<seconds>.<%03i milliseconds>.h5 If more than one top level directory contains the same channel_name subdirectory, this is considered the same channel. An error is raised if their sample rates differ, or if their time periods overlap. """ Reader = DigitalRFReader(top_level_dir) available_channel_names = Reader.get_channels() self._channel_names = self._get_channel_names( channels, available_channel_names, ) if start is None: start = [None]*len(self._channel_names) try: s_iter = iter(start) except TypeError: s_iter = iter([start]) if end is None: end = [None]*len(self._channel_names) try: e_iter = iter(end) except TypeError: e_iter = iter([end]) # make sources for each channel self._channels = [] for ch, s, e in zip(self._channel_names, s_iter, e_iter): chsrc = digital_rf_channel_source( os.path.join(top_level_dir, ch), start=s, end=e, repeat=repeat, ) self._channels.append(chsrc) out_sig_dtypes = [src.out_sig()[0] for src in self._channels] out_sig = gr.io_signaturev( len(out_sig_dtypes), len(out_sig_dtypes), [s.itemsize for s in out_sig_dtypes], ) in_sig = gr.io_signature(0, 0, 0) gr.hier_block2.__init__( self, name="digital_rf_source", input_signature=in_sig, output_signature=out_sig, ) msg_port_name = pmt.intern('metadata') self.message_port_register_hier_out('metadata') for k, src in enumerate(self._channels): if throttle: throt = gnuradio.blocks.throttle( src.out_sig()[0].itemsize, src._sample_rate, ignore_tags=True, ) self.connect(src, throt, (self, k)) else: self.connect(src, (self, k)) self.msg_connect(src, msg_port_name, self, msg_port_name)