def __init__(self, samplerate, bits_per_sec, fftlen): gr.hier_block2.__init__( self, "gmsk_sync", gr.io_signature(1, 1, gr.sizeof_gr_complex), # Input signature gr.io_signature(1, 1, gr.sizeof_gr_complex)) # Output signature #this is just the old square-and-fft method #ais.freqest is simply looking for peaks spaced bits-per-sec apart self.square = gr.multiply_cc(1) self.fftvect = gr.stream_to_vector(gr.sizeof_gr_complex, fftlen) self.fft = gr.fft_vcc(fftlen, True, window.rectangular(fftlen), True) self.freqest = ais.freqest(int(samplerate), int(bits_per_sec), fftlen) self.repeat = gr.repeat(gr.sizeof_float, fftlen) self.fm = gr.frequency_modulator_fc(-1.0 / (float(samplerate) / (2 * pi))) self.mix = gr.multiply_cc(1) self.connect(self, (self.square, 0)) self.connect(self, (self.square, 1)) #this is the feedforward branch self.connect(self, (self.mix, 0)) #this is the feedback branch self.connect(self.square, self.fftvect, self.fft, self.freqest, self.repeat, self.fm, (self.mix, 1)) #and this is the output self.connect(self.mix, self)
def __init__(self, bt=0.3, samples_per_symbol=2): gr.hier_block2.__init__( self, "msk_demod", gr.io_signature(1, 1, gr.sizeof_char), gr.io_signature(1, 1, gr.sizeof_gr_complex) ) 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.unpack = gr.packed_to_unpacked_bb(1, gr.GR_MSB_FIRST) self.nrz = digital.chunks_to_symbols_bf([-1, 1], 1) # note could also invert bits here # Form Gaussian filter # Generate Gaussian response (Needs to be convolved with window below). self.gaussian_taps = gr.firdes.gaussian(1, samples_per_symbol, bt, ntaps) 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 = gr.frequency_modulator_fc(sensitivity) # TODO: this is hardcoded, how to figure out this value? self.offset = gr.add_const_vff((-0.5,)) # CC430 RF core is inverted with respect to USRP for some reason self.invert = gr.multiply_const_vff((-1,)) # Connect & Initialize base class self.connect(self, self.unpack, self.nrz, self.invert, self.offset, self.gaussian_filter, self.fmmod, self)
def set_waveform(self, type): self.lock() self.disconnect_all() if type == gr.GR_SIN_WAVE or type == gr.GR_CONST_WAVE: self._src = gr.sig_source_c( self[SAMP_RATE_KEY], # Sample rate type, # Waveform type self[WAVEFORM_FREQ_KEY], # Waveform frequency self[AMPLITUDE_KEY], # Waveform amplitude self[WAVEFORM_OFFSET_KEY]) # Waveform offset elif type == gr.GR_GAUSSIAN or type == gr.GR_UNIFORM: self._src = gr.noise_source_c(type, self[AMPLITUDE_KEY]) elif type == "2tone": self._src1 = gr.sig_source_c(self[SAMP_RATE_KEY], gr.GR_SIN_WAVE, self[WAVEFORM_FREQ_KEY], self[AMPLITUDE_KEY] / 2.0, 0) if (self[WAVEFORM2_FREQ_KEY] is None): self[WAVEFORM2_FREQ_KEY] = -self[WAVEFORM_FREQ_KEY] self._src2 = gr.sig_source_c(self[SAMP_RATE_KEY], gr.GR_SIN_WAVE, self[WAVEFORM2_FREQ_KEY], self[AMPLITUDE_KEY] / 2.0, 0) self._src = gr.add_cc() self.connect(self._src1, (self._src, 0)) self.connect(self._src2, (self._src, 1)) elif type == "sweep": # rf freq is center frequency # waveform_freq is total swept width # waveform2_freq is sweep rate # will sweep from (rf_freq-waveform_freq/2) to (rf_freq+waveform_freq/2) if self[WAVEFORM2_FREQ_KEY] is None: self[WAVEFORM2_FREQ_KEY] = 0.1 self._src1 = gr.sig_source_f(self[SAMP_RATE_KEY], gr.GR_TRI_WAVE, self[WAVEFORM2_FREQ_KEY], 1.0, -0.5) self._src2 = gr.frequency_modulator_fc( self[WAVEFORM_FREQ_KEY] * 2 * math.pi / self[SAMP_RATE_KEY]) self._src = gr.multiply_const_cc(self[AMPLITUDE_KEY]) self.connect(self._src1, self._src2, self._src) else: raise RuntimeError("Unknown waveform type") self.connect(self._src, self._u) self.unlock() if self._verbose: print "Set baseband modulation to:", waveforms[type] if type == gr.GR_SIN_WAVE: print "Modulation frequency: %sHz" % (n2s( self[WAVEFORM_FREQ_KEY]), ) print "Initial phase:", self[WAVEFORM_OFFSET_KEY] elif type == "2tone": print "Tone 1: %sHz" % (n2s(self[WAVEFORM_FREQ_KEY]), ) print "Tone 2: %sHz" % (n2s(self[WAVEFORM2_FREQ_KEY]), ) elif type == "sweep": print "Sweeping across %sHz to %sHz" % (n2s( -self[WAVEFORM_FREQ_KEY] / 2.0), n2s(self[WAVEFORM_FREQ_KEY] / 2.0)) print "Sweep rate: %sHz" % (n2s(self[WAVEFORM2_FREQ_KEY]), ) print "TX amplitude:", self[AMPLITUDE_KEY]
def __init__(self, vocoder, lo_freq, audio_rate, if_rate): gr.hier_block2.__init__(self, "pipeline", gr.io_signature(0, 0, 0), # Input signature gr.io_signature(1, 1, gr.sizeof_gr_complex)) # Output signature c4fm = op25_c4fm_mod.p25_mod_bf(output_sample_rate=audio_rate, log=False, verbose=True) interp_factor = if_rate / audio_rate low_pass = 2.88e3 interp_taps = gr.firdes.low_pass(1.0, if_rate, low_pass, low_pass * 0.1, gr.firdes.WIN_HANN) interpolator = gr.interp_fir_filter_fff (int(interp_factor), interp_taps) max_dev = 12.5e3 k = 2 * math.pi * max_dev / if_rate adjustment = 1.5 # adjust for proper c4fm deviation level modulator = gr.frequency_modulator_fc (k * adjustment) # Local oscillator lo = gr.sig_source_c (if_rate, # sample rate gr.GR_SIN_WAVE, # waveform type lo_freq, #frequency 1.0, # amplitude 0) # DC Offset mixer = gr.multiply_cc () self.connect (vocoder, c4fm, interpolator, modulator, (mixer, 0)) self.connect (lo, (mixer, 1)) self.connect (mixer, self)
def __init__(self, audio_rate, quad_rate, tau=75e-6, max_dev=5e3): """ Narrow Band FM Transmitter. Takes a single float input stream of audio samples in the range [-1,+1] and produces a single FM modulated complex baseband output. @param audio_rate: sample rate of audio stream, >= 16k @type audio_rate: integer @param quad_rate: sample rate of output stream @type quad_rate: integer @param tau: preemphasis time constant (default 75e-6) @type tau: float @param max_dev: maximum deviation in Hz (default 5e3) @type max_dev: float quad_rate must be an integer multiple of audio_rate. """ gr.hier_block2.__init__( self, "nbfm_tx", gr.io_signature(1, 1, gr.sizeof_float), # Input signature gr.io_signature(1, 1, gr.sizeof_gr_complex)) # Output signature # FIXME audio_rate and quad_rate ought to be exact rationals audio_rate = int(audio_rate) quad_rate = int(quad_rate) if quad_rate % audio_rate != 0: raise ValueError, "quad_rate is not an integer multiple of audio_rate" do_interp = audio_rate != quad_rate if do_interp: interp_factor = quad_rate / audio_rate interp_taps = optfir.low_pass( interp_factor, # gain quad_rate, # Fs 4500, # passband cutoff 7000, # stopband cutoff 0.1, # passband ripple dB 40) # stopband atten dB #print "len(interp_taps) =", len(interp_taps) self.interpolator = gr.interp_fir_filter_fff( interp_factor, interp_taps) self.preemph = fm_preemph(quad_rate, tau=tau) k = 2 * math.pi * max_dev / quad_rate self.modulator = gr.frequency_modulator_fc(k) if do_interp: self.connect(self, self.interpolator, self.preemph, self.modulator, self) else: self.connect(self, self.preemph, self.modulator, self)
def __init__(self, subdev_spec, freq, subdev_gain, filename, delay): gr.top_block.__init__(self) # data sink and sink rate u = usrp.sink_c() # important vars (to be calculated from USRP when available dac_rate = u.dac_rate() usrp_rate = 320e3 usrp_interp = int(dac_rate // usrp_rate) channel_rate = 32e3 interp_factor = int(usrp_rate // channel_rate) # open the pcap source pcap = op25.pcap_source_b(filename, delay) # pcap = gr.glfsr_source_b(16) # convert octets into dibits bits_per_symbol = 2 unpack = gr.packed_to_unpacked_bb(bits_per_symbol, gr.GR_MSB_FIRST) # modulator c4fm = p25_mod_bf(output_rate=channel_rate) # setup low pass filter + interpolator low_pass = 2.88e3 interp_taps = gr.firdes.low_pass(1.0, channel_rate, low_pass, low_pass * 0.1, gr.firdes.WIN_HANN) interpolator = gr.interp_fir_filter_fff(int(interp_factor), interp_taps) # frequency modulator max_dev = 12.5e3 k = 2 * math.pi * max_dev / usrp_rate adjustment = 1.5 # adjust for proper c4fm deviation level fm = gr.frequency_modulator_fc(k * adjustment) # signal gain gain = gr.multiply_const_cc(4000) # configure USRP if subdev_spec is None: subdev_spec = usrp.pick_tx_subdevice(u) u.set_mux(usrp.determine_tx_mux_value(u, subdev_spec)) self.db = usrp.selected_subdev(u, subdev_spec) print "Using TX d'board %s" % (self.db.side_and_name(), ) u.set_interp_rate(usrp_interp) if gain is None: g = self.db.gain_range() gain = float(g[0] + g[1]) / 2 self.db.set_gain(self.db.gain_range()[0]) u.tune(self.db.which(), self.db, freq) self.db.set_enable(True) self.connect(pcap, unpack, c4fm, interpolator, fm, gain, u)
def __init__(self, audio_rate, quad_rate, tau=75e-6, max_dev=75e3): """ Wide Band FM Transmitter. Takes a single float input stream of audio samples in the range [-1,+1] and produces a single FM modulated complex baseband output. @param audio_rate: sample rate of audio stream, >= 16k @type audio_rate: integer @param quad_rate: sample rate of output stream @type quad_rate: integer @param tau: preemphasis time constant (default 75e-6) @type tau: float @param max_dev: maximum deviation in Hz (default 75e3) @type max_dev: float quad_rate must be an integer multiple of audio_rate. """ gr.hier_block2.__init__( self, "wfm_tx", gr.io_signature(1, 1, gr.sizeof_float), # Input signature gr.io_signature(1, 1, gr.sizeof_gr_complex)) # Output signature # FIXME audio_rate and quad_rate ought to be exact rationals audio_rate = int(audio_rate) quad_rate = int(quad_rate) if quad_rate % audio_rate != 0: raise ValueError, "quad_rate is not an integer multiple of audio_rate" do_interp = audio_rate != quad_rate if do_interp: interp_factor = quad_rate / audio_rate interp_taps = optfir.low_pass( interp_factor, # gain quad_rate, # Fs 16000, # passband cutoff 18000, # stopband cutoff 0.1, # passband ripple dB 40) # stopband atten dB print "len(interp_taps) =", len(interp_taps) self.interpolator = gr.interp_fir_filter_fff( interp_factor, interp_taps) self.preemph = fm_preemph(quad_rate, tau=tau) k = 2 * math.pi * max_dev / quad_rate self.modulator = gr.frequency_modulator_fc(k) if do_interp: self.connect(self, self.interpolator, self.preemph, self.modulator, self) else: self.connect(self, self.preemph, self.modulator, self)
def test_freqmod() : from cmath import phase, pi, rect tb = gr.top_block() src = gr.vector_source_f((1,)*1000) mod = gr.frequency_modulator_fc(pi) sink = gr.vector_sink_c() tb.connect(src, mod, sink) tb.run() d = sink.data() print "\n".join(["% 1.3f % 1.3f"%((i*1j).real, (i*1j).imag) for i in d])
def __init__(self, subdev_spec, freq, subdev_gain, filename, delay): gr.top_block.__init__ (self) # data sink and sink rate u = usrp.sink_c() # important vars (to be calculated from USRP when available dac_rate = u.dac_rate() usrp_rate = 320e3 usrp_interp = int(dac_rate // usrp_rate) channel_rate = 32e3 interp_factor = int(usrp_rate // channel_rate) # open the pcap source pcap = op25.pcap_source_b(filename, delay) # pcap = gr.glfsr_source_b(16) # convert octets into dibits bits_per_symbol = 2 unpack = gr.packed_to_unpacked_bb(bits_per_symbol, gr.GR_MSB_FIRST) # modulator c4fm = p25_mod_bf(output_rate=channel_rate) # setup low pass filter + interpolator low_pass = 2.88e3 interp_taps = gr.firdes.low_pass(1.0, channel_rate, low_pass, low_pass * 0.1, gr.firdes.WIN_HANN) interpolator = gr.interp_fir_filter_fff (int(interp_factor), interp_taps) # frequency modulator max_dev = 12.5e3 k = 2 * math.pi * max_dev / usrp_rate adjustment = 1.5 # adjust for proper c4fm deviation level fm = gr.frequency_modulator_fc(k * adjustment) # signal gain gain = gr.multiply_const_cc(4000) # configure USRP if subdev_spec is None: subdev_spec = usrp.pick_tx_subdevice(u) u.set_mux(usrp.determine_tx_mux_value(u, subdev_spec)) self.db = usrp.selected_subdev(u, subdev_spec) print "Using TX d'board %s" % (self.db.side_and_name(),) u.set_interp_rate(usrp_interp) if gain is None: g = self.db.gain_range() gain = float(g[0] + g[1]) / 2 self.db.set_gain(self.db.gain_range()[0]) u.tune(self.db.which(), self.db, freq) self.db.set_enable(True) self.connect(pcap, unpack, c4fm, interpolator, fm, gain, u)
def test_freqmod(): from cmath import phase, pi, rect tb = gr.top_block() src = gr.vector_source_f((1, ) * 1000) mod = gr.frequency_modulator_fc(pi) sink = gr.vector_sink_c() tb.connect(src, mod, sink) tb.run() d = sink.data() print "\n".join( ["% 1.3f % 1.3f" % ((i * 1j).real, (i * 1j).imag) for i in d])
def test_fm_001 (self): pi = math.pi sensitivity = pi/4 src_data = (1.0/4, 1.0/2, 1.0/4, -1.0/4, -1.0/2, -1/4.0) running_sum = (pi/16, 3*pi/16, pi/4, 3*pi/16, pi/16, 0) expected_result = tuple ([sincos (x) for x in running_sum]) src = gr.vector_source_f (src_data) op = gr.frequency_modulator_fc (sensitivity) dst = gr.vector_sink_c () self.tb.connect (src, op) self.tb.connect (op, dst) self.tb.run () result_data = dst.data () self.assertComplexTuplesAlmostEqual (expected_result, result_data, 5)
def __init__(self, bt = 0.3, samples_per_symbol = 2, ti_adj=False): gr.hier_block2.__init__(self, "msk_demod", gr.io_signature(1, 1, gr.sizeof_char), gr.io_signature(1, 1, gr.sizeof_gr_complex)) self.sps = 2 self.bt = 0.35 self.mu = 0.5 self.gain_mu = 0.175 self.freq_error = 0.0 self.omega_relative_limit = 0.005 self.omega = self.sps * (1 + self.freq_error) self.gain_omega = .25 * self.gain_mu * self.gain_mu # critically damped 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.unpack = gr.packed_to_unpacked_bb(1, gr.GR_MSB_FIRST) self.nrz = digital.chunks_to_symbols_bf([-1, 1], 1) # note could also invert bits here # Form Gaussian filter # Generate Gaussian response (Needs to be convolved with window below). self.gaussian_taps = gr.firdes.gaussian(1, samples_per_symbol, bt, ntaps) 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) # 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) # FM modulation self.fmmod = gr.frequency_modulator_fc(sensitivity) # TODO: this is hardcoded, how to figure out this value? self.offset = gr.add_const_vff((-.5, )) # CC430 RF core is inverted with respect to USRP for some reason self.invert = gr.multiply_const_vff((-1, )) # Connect & Initialize base class if ti_adj: self.connect(self, self.unpack, self.nrz, self.invert, self.offset, self.gaussian_filter, self.fmmod, self) else: self.connect(self, self.unpack, self.nrz, self.gaussian_filter, self.fmmod, self)
def __init__(self, samples_per_symbol=_def_samples_per_symbol, bt=_def_bt, verbose=_def_verbose, log=_def_log): gr.hier_block2.__init__(self, "gmsk_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 = gr.packed_to_unpacked_bb(1, gr.GR_MSB_FIRST) self.nrz = digital.chunks_to_symbols_bf([-1, 1], 1) # Form Gaussian filter # Generate Gaussian response (Needs to be convolved with window below). self.gaussian_taps = gr.firdes.gaussian( 1, # 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 = gr.frequency_modulator_fc(sensitivity) 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)
def test_fm_001 (self): pi = math.pi sensitivity = pi/4 src_data = (1.0/4, 1.0/2, 1.0/4, -1.0/4, -1.0/2, -1/4.0) running_sum = (pi/16, 3*pi/16, pi/4, 3*pi/16, pi/16, 0) expected_result = tuple ([sincos (x) for x in running_sum]) src = gr.vector_source_f (src_data) op = gr.frequency_modulator_fc (sensitivity) dst = gr.vector_sink_c () self.tb.connect (src, op) self.tb.connect (op, dst) self.tb.run () result_data = dst.data () self.assertComplexTuplesAlmostEqual (expected_result, result_data)
def __init__(self, fg, spb=8, bt=0.3): """ Hierarchical block for cc1k FSK modulation. The input is a byte stream (unsigned char) and the output is the complex modulated signal at baseband. @param fg: flow graph @type fg: flow graph @param spb: samples per baud >= 2 @type spb: integer @param bt: Gaussian filter bandwidth * symbol time @type bt: float """ if not isinstance(spb, int) or spb < 2: raise TypeError, "sbp must be an integer >= 2" self.spb = spb #sensitivity = (pi / 2) / spb # phase change per bit = pi / 2 sensitivity = 3.5 * pi / spb # Turn it into NRZ data. self.nrz = gr.bytes_to_syms() # Manchester Encode the whole thing and upsample by 8 self.manchester = ucla.manchester_ff() # FM modulation self.fmmod = gr.frequency_modulator_fc(sensitivity) # Connect fg.connect(self.nrz, self.manchester) fg.connect(self.manchester, self.fmmod) #filesink1 = gr.file_sink(gr.sizeof_float, 'nrz.dat') #fg.connect(self.nrz, filesink1) #filesink = gr.file_sink(gr.sizeof_float, 'manchester.dat') #fg.connect(self.manchester, filesink) # Initialize base class gr.hier_block.__init__(self, fg, self.nrz, self.fmmod)
def __init__(self, fg, spb = 8, bt = 0.3): """ Hierarchical block for cc1k FSK modulation. The input is a byte stream (unsigned char) and the output is the complex modulated signal at baseband. @param fg: flow graph @type fg: flow graph @param spb: samples per baud >= 2 @type spb: integer @param bt: Gaussian filter bandwidth * symbol time @type bt: float """ if not isinstance(spb, int) or spb < 2: raise TypeError, "sbp must be an integer >= 2" self.spb = spb #sensitivity = (pi / 2) / spb # phase change per bit = pi / 2 sensitivity = 3.5*pi / spb # Turn it into NRZ data. self.nrz = gr.bytes_to_syms() # Manchester Encode the whole thing and upsample by 8 self.manchester = ucla.manchester_ff() # FM modulation self.fmmod = gr.frequency_modulator_fc(sensitivity) # Connect fg.connect(self.nrz, self.manchester) fg.connect(self.manchester, self.fmmod) #filesink1 = gr.file_sink(gr.sizeof_float, 'nrz.dat') #fg.connect(self.nrz, filesink1) #filesink = gr.file_sink(gr.sizeof_float, 'manchester.dat') #fg.connect(self.manchester, filesink) # Initialize base class gr.hier_block.__init__(self, fg, self.nrz, self.fmmod)
def __init__(self, vocoder, lo_freq, audio_rate, if_rate): gr.hier_block2.__init__( self, "pipeline", gr.io_signature(0, 0, 0), # Input signature gr.io_signature(1, 1, gr.sizeof_gr_complex)) # Output signature c4fm = op25_c4fm_mod.p25_mod_bf(output_sample_rate=audio_rate, log=False, verbose=True) interp_factor = if_rate / audio_rate low_pass = 2.88e3 interp_taps = gr.firdes.low_pass(1.0, if_rate, low_pass, low_pass * 0.1, gr.firdes.WIN_HANN) interpolator = gr.interp_fir_filter_fff(int(interp_factor), interp_taps) max_dev = 12.5e3 k = 2 * math.pi * max_dev / if_rate adjustment = 1.5 # adjust for proper c4fm deviation level modulator = gr.frequency_modulator_fc(k * adjustment) # Local oscillator lo = gr.sig_source_c( if_rate, # sample rate gr.GR_SIN_WAVE, # waveform type lo_freq, #frequency 1.0, # amplitude 0) # DC Offset mixer = gr.multiply_cc() self.connect(vocoder, c4fm, interpolator, modulator, (mixer, 0)) self.connect(lo, (mixer, 1)) self.connect(mixer, self)
def __init__(self, samplerate, bits_per_sec, fftlen): gr.hier_block2.__init__(self, "gmsk_sync", gr.io_signature(1, 1, gr.sizeof_gr_complex), # Input signature gr.io_signature(1, 1, gr.sizeof_gr_complex)) # Output signature #this is just the old square-and-fft method #ais.freqest is simply looking for peaks spaced bits-per-sec apart self.square = gr.multiply_cc(1) self.fftvect = gr.stream_to_vector(gr.sizeof_gr_complex, fftlen) self.fft = gr.fft_vcc(fftlen, True, window.rectangular(fftlen), True) self.freqest = ais.freqest(int(samplerate), int(bits_per_sec), fftlen) self.repeat = gr.repeat(gr.sizeof_float, fftlen) self.fm = gr.frequency_modulator_fc(-1.0/(float(samplerate)/(2*pi))) self.mix = gr.multiply_cc(1) self.connect(self, (self.square, 0)) self.connect(self, (self.square, 1)) #this is the feedforward branch self.connect(self, (self.mix, 0)) #this is the feedback branch self.connect(self.square, self.fftvect, self.fft, self.freqest, self.repeat, self.fm, (self.mix, 1)) #and this is the output self.connect(self.mix, self)
def __init__(self, noise_voltage, sensitivity): gr.hier_block2.__init__(self, "variable_awgn_channel", gr.io_signature(1,1,gr.sizeof_gr_complex), gr.io_signature(1,1,gr.sizeof_gr_complex)) self.noise_adder = gr.add_cc() self.noise = gr.noise_source_c(gr.GR_GAUSSIAN,noise_voltage) self.noise_amp = gr.multiply_cc() self.offset = gr.frequency_modulator_fc(sensitivity) self.mixer_offset = gr.multiply_cc() self.connect(self, (self.mixer_offset,0)) self.connect(self.offset,(self.mixer_offset,1)) self.connect(self.mixer_offset, (self.noise_adder,1)) self.connect(self.noise, (self.noise_amp,0)) self.connect(self.noise_amp, (self.noise_adder,0)) self.connect(self.noise_adder, self) try: gr.hier_block.update_var_names(self, "var_awgn_channel", vars()) gr.hier_block.update_var_names(self, "var_awgn_channel", vars(self)) except: pass
def __init__(self, bt=0.3, samples_per_symbol=2): gr.hier_block2.__init__(self, "msk_demod", gr.io_signature(1, 1, gr.sizeof_char), gr.io_signature(1, 1, gr.sizeof_gr_complex)) 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.unpack = gr.packed_to_unpacked_bb(1, gr.GR_MSB_FIRST) self.nrz = digital.chunks_to_symbols_bf( [-1, 1], 1) # note could also invert bits here # Form Gaussian filter # Generate Gaussian response (Needs to be convolved with window below). self.gaussian_taps = gr.firdes.gaussian(1, samples_per_symbol, bt, ntaps) 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 = gr.frequency_modulator_fc(sensitivity) # TODO: this is hardcoded, how to figure out this value? self.offset = gr.add_const_vff((-.5, )) # CC430 RF core is inverted with respect to USRP for some reason self.invert = gr.multiply_const_vff((-1, )) # Connect & Initialize base class self.connect(self, self.unpack, self.nrz, self.invert, self.offset, self.gaussian_filter, self.fmmod, self)
def __init__(self, noise_voltage, sensitivity): gr.hier_block2.__init__(self, "variable_awgn_channel", gr.io_signature(1, 1, gr.sizeof_gr_complex), gr.io_signature(1, 1, gr.sizeof_gr_complex)) self.noise_adder = gr.add_cc() self.noise = gr.noise_source_c(gr.GR_GAUSSIAN, noise_voltage) self.noise_amp = gr.multiply_cc() self.offset = gr.frequency_modulator_fc(sensitivity) self.mixer_offset = gr.multiply_cc() self.connect(self, (self.mixer_offset, 0)) self.connect(self.offset, (self.mixer_offset, 1)) self.connect(self.mixer_offset, (self.noise_adder, 1)) self.connect(self.noise, (self.noise_amp, 0)) self.connect(self.noise_amp, (self.noise_adder, 0)) self.connect(self.noise_adder, self) try: gr.hier_block.update_var_names(self, "var_awgn_channel", vars()) gr.hier_block.update_var_names(self, "var_awgn_channel", vars(self)) except: pass
def __init__(self, dab_params, rx_params, debug=False): """ OFDM time and coarse frequency synchronisation for DAB @param mode DAB mode (1-4) @param debug if True: write data streams out to files """ dp = dab_params rp = rx_params gr.hier_block2.__init__(self,"ofdm_sync_dab", gr.io_signature(1, 1, gr.sizeof_gr_complex), # input signature gr.io_signature2(2, 2, gr.sizeof_gr_complex, gr.sizeof_char)) # output signature # workaround for a problem that prevents connecting more than one block directly (see trac ticket #161) self.input = gr.kludge_copy(gr.sizeof_gr_complex) self.connect(self, self.input) # # null-symbol detection # # (outsourced to detect_zero.py) self.ns_detect = detect_null.detect_null(dp.ns_length, debug) self.connect(self.input, self.ns_detect) # # fine frequency synchronisation # # the code for fine frequency synchronisation is adapted from # ofdm_sync_ml.py; it abuses the cyclic prefix to find the fine # frequency error, as suggested in "ML Estimation of Timing and # Frequency Offset in OFDM Systems", by Jan-Jaap van de Beek, # Magnus Sandell, Per Ola Börjesson, see # http://www.sm.luth.se/csee/sp/research/report/bsb96r.html self.ffs_delay = gr.delay(gr.sizeof_gr_complex, dp.fft_length) self.ffs_conj = gr.conjugate_cc() self.ffs_mult = gr.multiply_cc() self.ffs_moving_sum = dab_swig.moving_sum_cc(dp.cp_length) self.ffs_arg = gr.complex_to_arg() self.ffs_sample_and_average = dab_swig.ofdm_ffs_sample(dp.symbol_length, dp.fft_length, rp.symbols_for_ffs_estimation, rp.ffs_alpha, dp.sample_rate) if rp.correct_ffe: self.ffs_delay_input_for_correction = gr.delay(gr.sizeof_gr_complex, dp.symbol_length*rp.symbols_for_ffs_estimation) # by delaying the input, we can use the ff offset estimation from the first symbol to correct the first symbol itself self.ffs_delay_frame_start = gr.delay(gr.sizeof_char, dp.symbol_length*rp.symbols_for_ffs_estimation) # sample the value at the end of the symbol .. self.ffs_nco = gr.frequency_modulator_fc(1) # ffs_sample_and_hold directly outputs phase error per sample self.ffs_mixer = gr.multiply_cc() # calculate fine frequency error self.connect(self.input, self.ffs_conj, self.ffs_mult) self.connect(self.input, self.ffs_delay, (self.ffs_mult, 1)) self.connect(self.ffs_mult, self.ffs_moving_sum, self.ffs_arg, (self.ffs_sample_and_average, 0)) self.connect(self.ns_detect, (self.ffs_sample_and_average, 1)) if rp.correct_ffe: # do the correction self.connect(self.ffs_sample_and_average, self.ffs_nco, (self.ffs_mixer, 0)) self.connect(self.input, self.ffs_delay_input_for_correction, (self.ffs_mixer, 1)) # output - corrected signal and start of DAB frames self.connect(self.ffs_mixer, (self, 0)) self.connect(self.ns_detect, self.ffs_delay_frame_start, (self, 1)) else: # just patch the signal through self.connect(self.ffs_sample_and_average, gr.null_sink(gr.sizeof_float)) self.connect(self.input, (self,0)) # frame start still needed .. self.connect(self.ns_detect, (self,1)) if debug: self.connect(self.ffs_sample_and_average, gr.multiply_const_ff(1./(dp.T*2*pi)), gr.file_sink(gr.sizeof_float, "debug/ofdm_sync_dab_fine_freq_err_f.dat")) self.connect(self.ffs_mixer, gr.file_sink(gr.sizeof_gr_complex, "debug/ofdm_sync_dab_fine_freq_corrected_c.dat"))
def __init__(self, fft_length, cp_length, occupied_tones, snr, ks, carrier_map_bin, nc_filter, logging=False): gr.hier_block2.__init__(self, "ofdm_receiver", gr.io_signature(1, 1, gr.sizeof_gr_complex), # Input signature gr.io_signature4(4, 4, gr.sizeof_gr_complex*occupied_tones, gr.sizeof_char, gr.sizeof_char, gr.sizeof_float)) # Output signature self._fft_length = fft_length self._occupied_tones = occupied_tones self._cp_length = cp_length self._nc_filter = nc_filter self._carrier_map_bin = carrier_map_bin win = [1 for i in range(self._fft_length)] self.initialize(ks, self._carrier_map_bin) SYNC = "pn" if SYNC == "ml": nco_sensitivity = -1.0/fft_length # correct for fine frequency self.ofdm_sync = ofdm_sync_ml(fft_length, cp_length, snr, self._ks0time, logging) elif SYNC == "pn": nco_sensitivity = -2.0/fft_length # correct for fine frequency self.ofdm_sync = ofdm_sync_pn.ofdm_sync_pn(fft_length, cp_length, logging) elif SYNC == "pnac": nco_sensitivity = -2.0/fft_length # correct for fine frequency self.ofdm_sync = ofdm_sync_pnac(fft_length, cp_length, self._ks0time, logging) elif SYNC == "fixed": # for testing only; do not user over the air self.chan_filt = gr.multiply_const_cc(1.0) # remove filter and filter delay for this nsymbols = 18 # enter the number of symbols per packet freq_offset = 0.0 # if you use a frequency offset, enter it here nco_sensitivity = -2.0/fft_length # correct for fine frequency self.ofdm_sync = ofdm_sync_fixed(fft_length, cp_length, nsymbols, freq_offset, logging) self.reset_filter() # TODO: why? Create a delay line, linklab self.delay = gr.delay(gr.sizeof_gr_complex, fft_length) self.nco = gr.frequency_modulator_fc(nco_sensitivity) # generate a signal proportional to frequency error of sync block self.sigmix = gr.multiply_cc() self.sampler = flex.ofdm_sampler(fft_length, fft_length+cp_length) self.fft_demod = gr.fft_vcc(fft_length, True, win, True) self.ofdm_frame_acq = flex.ofdm_frame_acquisition(self._occupied_tones, self._fft_length, self._cp_length, self._ks[0], 1) if self._nc_filter: print '\nMulti-band Filter Turned ON!' self.ncofdm_filt = ncofdm_filt(self._fft_length, self._occupied_tones, self._carrier_map_bin) self.connect(self, self.chan_filt, self.ncofdm_filt) self.connect(self.ncofdm_filt, self.ofdm_sync) # into the synchronization alg. self.connect((self.ofdm_sync,0), self.nco, (self.sigmix,1)) # use sync freq. offset output to derotate input signal self.connect(self.ncofdm_filt, self.delay, (self.sigmix,0)) # signal to be derotated else : print '\nMulti-band Filter Turned OFF!' self.connect(self, self.chan_filt) self.connect(self.chan_filt, self.ofdm_sync) # into the synchronization alg. self.connect((self.ofdm_sync,0), self.nco, (self.sigmix,1)) # use sync freq. offset output to derotate input signal self.connect(self.chan_filt, self.delay, (self.sigmix,0)) # signal to be derotated self.connect(self.sigmix, (self.sampler,0)) # sample off timing signal detected in sync alg self.connect((self.ofdm_sync,1), (self.sampler,1)) # timing signal to sample at self.connect((self.sampler,0), self.fft_demod) # send derotated sampled signal to FFT self.connect(self.fft_demod, (self.ofdm_frame_acq,0)) # find frame start and equalize signal # TODO: do we need a char delay for the timing signal? self.connect((self.sampler,1), (self.ofdm_frame_acq,1)) # send timing signal to signal frame start # TODO: reconnect properly self.connect((self.ofdm_frame_acq,0), (self,0)) # finished with fine/coarse freq correction, self.connect((self.ofdm_sync,1), gr.delay(gr.sizeof_char,1), (self,1)) self.connect((self.ofdm_frame_acq,1), (self,2)) # frame and symbol timing, and equalization self.connect((self.ofdm_frame_acq,2), (self,3)) # snr estimates if logging: self.connect(self.chan_filt, gr.file_sink(gr.sizeof_gr_complex, "flex_ofdm_recv-chan_filt_c.dat")) self.connect(self.ncofdm_filt, gr.file_sink(gr.sizeof_gr_complex, "flex_ofdm_recv-ncofdm_filt_c.dat")) self.connect(self.nco, gr.file_sink(gr.sizeof_gr_complex, "flex_ofdm_recv-nco_c.dat")) self.connect(self.fft_demod, gr.file_sink(gr.sizeof_gr_complex*fft_length, "flex_ofdm_recv-fft_out_c.dat")) self.connect(self.ofdm_frame_acq, gr.file_sink(gr.sizeof_gr_complex*occupied_tones, "flex_ofdm_recv-frame_acq_data_c.dat")) self.connect((self.ofdm_frame_acq,3), gr.keep_one_in_n(gr.sizeof_float*occupied_tones, 32), gr.file_sink(gr.sizeof_float*occupied_tones, "flex_ofdm_recv-frame_acq_gain_f.dat")) self.connect((self.ofdm_frame_acq,1), gr.file_sink(1, "flex_ofdm_recv-frame_acq_signal_b.dat")) self.connect((self.ofdm_frame_acq,2), gr.file_sink(gr.sizeof_float, "flex_ofdm_recv-frame_acq_snr_f.dat")) self.connect(self.sampler, gr.file_sink(gr.sizeof_gr_complex*fft_length, "flex_ofdm_recv-sampler_data_c.dat")) self.connect(self.sampler, gr.file_sink(gr.sizeof_gr_complex*fft_length, "flex_ofdm_recv-sampler_data_c.dat")) self.connect((self.sampler, 1), gr.file_sink(1*fft_length, "flex_ofdm_recv-sampler_signal_b.dat")) self.connect((self.ofdm_sync, 1), gr.file_sink(1, "flex_ofdm_recv-sync_b.dat")) self.connect(self.sigmix, gr.file_sink(gr.sizeof_gr_complex, "flex_ofdm_recv-sigmix_c.dat")) else: self.connect((self.ofdm_frame_acq,3), gr.null_sink(gr.sizeof_float*self._occupied_tones))
def __init__(self, p, logging=False): """ Hierarchical block for receiving OFDM symbols. The input is the complex modulated signal at baseband. Synchronized packets are sent back to the demodulator. @param params: Raw OFDM parameters @type params: ofdm_params @param logging: turn file logging on or off @type logging: bool """ from numpy import fft gr.hier_block2.__init__(self, "ofdm_receiver", gr.io_signature(1, 1, gr.sizeof_gr_complex), # Input signature gr.io_signature2(2, 2, gr.sizeof_gr_complex*p.occupied_tones, gr.sizeof_char)) # Output signature # low-pass filter the input channel bw = (float(p.occupied_tones) / float(p.fft_length)) / 2.0 tb = bw*0.08 lpf_coeffs = gr.firdes.low_pass (1.0, # gain 1.0, # sampling rate bw+tb, # midpoint of trans. band tb, # width of trans. band gr.firdes.WIN_HAMMING) # filter type lpf = gr.fft_filter_ccc(1, lpf_coeffs) #lpf = gr.add_const_cc(0.0) ## no-op low-pass-filter self.connect(self, lpf) # to the synchronization algorithm #from gnuradio import blks2impl #from gnuradio.blks2impl.ofdm_sync_pn import ofdm_sync_pn sync = ofdm_sync(p.fft_length, p.cp_length, p.half_sync, logging) self.connect(lpf, sync) # correct for fine frequency offset computed in sync (up to +-pi/fft_length) # NOTE: frame_acquisition can correct coarse freq offset (i.e. kpi/fft_length) if p.half_sync: nco_sensitivity = 2.0/p.fft_length else: nco_sensitivity = 1.0/(p.fft_length + p.cp_length) #nco_sensitivity = 0 nco = gr.frequency_modulator_fc(nco_sensitivity) sigmix = gr.multiply_cc() self.connect((sync,0), (sigmix,0)) self.connect((sync,1), nco, (sigmix,1)) # sample at symbol boundaries # NOTE: (sync,2) indicates the first sample of the symbol! sampler = raw.ofdm_sampler(p.fft_length, p.fft_length+p.cp_length, timeout=100) self.connect(sigmix, (sampler,0)) self.connect((sync,2), (sampler,1)) # timing signal to sample at # fft on the symbols win = [1 for i in range(p.fft_length)] # see gr_fft_vcc_fftw that it works differently if win = [] fft = gr.fft_vcc(p.fft_length, True, win, True) self.connect((sampler,0), fft) # use the preamble to correct the coarse frequency offset and initial equalizer frame_acq = raw.ofdm_frame_acquisition(p.fft_length, p.cp_length, p.preambles) self.frame_acq = frame_acq self.connect(fft, (frame_acq,0)) self.connect((sampler,1), (frame_acq,1)) self.connect((frame_acq,0), (self,0)) # finished with fine/coarse freq correction self.connect((frame_acq,1), (self,1)) # frame and symbol timing if logging: self.connect(lpf, gr.file_sink(gr.sizeof_gr_complex, "rx-filt.dat")) self.connect(fft, gr.file_sink(gr.sizeof_gr_complex*p.fft_length, "rx-fft.dat")) self.connect((frame_acq,0), gr.file_sink(gr.sizeof_gr_complex*p.occupied_tones, "rx-acq.dat")) self.connect((frame_acq,1), gr.file_sink(1, "rx-detect.datb")) self.connect(sampler, gr.file_sink(gr.sizeof_gr_complex*p.fft_length, "rx-sampler.dat")) self.connect(sigmix, gr.file_sink(gr.sizeof_gr_complex, "rx-sigmix.dat")) self.connect(nco, gr.file_sink(gr.sizeof_gr_complex, "rx-nco.dat"))
def __init__(self, fg, samples_per_symbol=_def_samples_per_symbol, bt=_def_bt, verbose=_def_verbose, log=_def_log): """ Hierarchical block for Gaussian Minimum Shift Key (GMSK) modulation. The input is a byte stream (unsigned char) and the output is the complex modulated signal at baseband. @param fg: flow graph @type fg: flow graph @param samples_per_symbol: samples per baud >= 2 @type samples_per_symbol: integer @param bt: Gaussian filter bandwidth * symbol time @type bt: float @param verbose: Print information about modulator? @type verbose: bool @param debug: Print modualtion data to files? @type debug: bool """ self._fg = fg self._samples_per_symbol = samples_per_symbol self._bt = bt 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 = gr.bytes_to_syms() # Form Gaussian filter # Generate Gaussian response (Needs to be convolved with window below). self.gaussian_taps = gr.firdes.gaussian( 1, # 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 = gr.interp_fir_filter_fff(samples_per_symbol, self.taps) # FM modulation self.fmmod = gr.frequency_modulator_fc(sensitivity) if verbose: self._print_verbage() if log: self._setup_logging() # Connect & Initialize base class self._fg.connect(self.nrz, self.gaussian_filter, self.fmmod) gr.hier_block.__init__(self, self._fg, self.nrz, self.fmmod)
def __init__(self, frame, panel, vbox, argv): stdgui2.std_top_block.__init__(self, frame, panel, vbox, argv) parser = OptionParser(option_class=eng_option) parser.add_option("-T", "--tx-subdev-spec", type="subdev", default=None, help="select USRP Tx side A or B") parser.add_option( "-f", "--freq", type="eng_float", default=107.2e6, help="set Tx frequency to FREQ [required]", metavar="FREQ", ) parser.add_option("--wavfile", type="string", default=None, help="open .wav audio file FILE") parser.add_option("--xml", type="string", default="rds_data.xml", help="open .xml RDS data FILE") (options, args) = parser.parse_args() if len(args) != 0: parser.print_help() sys.exit(1) usrp_interp = 500 self.u = usrp.sink_c(0, usrp_interp) print "USRP Serial: ", self.u.serial_number() usrp_rate = self.u.dac_rate() / usrp_interp # 256 kS/s # determine the daughterboard subdevice we're using if options.tx_subdev_spec is None: options.tx_subdev_spec = usrp.pick_tx_subdevice(self.u) self.u.set_mux(usrp.determine_tx_mux_value(self.u, options.tx_subdev_spec)) self.subdev = usrp.selected_subdev(self.u, options.tx_subdev_spec) print "Using d'board", self.subdev.side_and_name() # set max Tx gain, tune frequency and enable transmitter gain = self.subdev.gain_range()[1] self.subdev.set_gain(gain) print "Gain set to", gain if self.u.tune(self.subdev.which(), self.subdev, options.freq): print "Tuned to", options.freq / 1e6, "MHz" else: sys.exit(1) self.subdev.set_enable(True) # open wav file containing floats in the [-1, 1] range, repeat if options.wavfile is None: print "Please provide a wavfile to transmit! Exiting\n" sys.exit(1) self.src = gr.wavfile_source(options.wavfile, True) nchans = self.src.channels() sample_rate = self.src.sample_rate() bits_per_sample = self.src.bits_per_sample() print nchans, "channels,", sample_rate, "samples/sec,", bits_per_sample, "bits/sample" # resample to usrp rate self.resample_left = blks2.rational_resampler_fff(usrp_rate, sample_rate) self.resample_right = blks2.rational_resampler_fff(usrp_rate, sample_rate) self.connect((self.src, 0), self.resample_left) self.connect((self.src, 1), self.resample_right) # create L+R (mono) and L-R (stereo) self.audio_lpr = gr.add_ff() self.audio_lmr = gr.sub_ff() self.connect(self.resample_left, (self.audio_lpr, 0)) self.connect(self.resample_left, (self.audio_lmr, 0)) self.connect(self.resample_right, (self.audio_lpr, 1)) self.connect(self.resample_right, (self.audio_lmr, 1)) # low-pass filter for L+R audio_lpr_taps = gr.firdes.low_pass( 0.5, # gain usrp_rate, # sampling rate 15e3, # passband cutoff 1e3, # transition width gr.firdes.WIN_HAMMING, ) self.audio_lpr_filter = gr.fir_filter_fff(1, audio_lpr_taps) self.connect(self.audio_lpr, self.audio_lpr_filter) # create pilot tone at 19 kHz self.pilot = gr.sig_source_f( usrp_rate, gr.GR_SIN_WAVE, 19e3, 5e-2 # sampling rate # waveform # frequency ) # amplitude # upconvert L-R to 38 kHz and band-pass self.mix_stereo = gr.multiply_ff() audio_lmr_taps = gr.firdes.band_pass( 80, # gain usrp_rate, # sampling rate 38e3 - 15e3, # low cutoff 38e3 + 15e3, # high cutoff 1e3, # transition width gr.firdes.WIN_HAMMING, ) self.audio_lmr_filter = gr.fir_filter_fff(1, audio_lmr_taps) self.connect(self.audio_lmr, (self.mix_stereo, 0)) self.connect(self.pilot, (self.mix_stereo, 1)) self.connect(self.pilot, (self.mix_stereo, 2)) self.connect(self.mix_stereo, self.audio_lmr_filter) # create RDS bitstream # diff-encode, manchester-emcode, NRZ # enforce the 1187.5bps rate # pulse shaping filter (matched with receiver) # mix with 57kHz carrier (equivalent to BPSK) self.rds_enc = rds.data_encoder("rds_data.xml") self.diff_enc = gr.diff_encoder_bb(2) self.manchester1 = gr.map_bb([1, 2]) self.manchester2 = gr.unpack_k_bits_bb(2) self.nrz = gr.map_bb([-1, 1]) self.c2f = gr.char_to_float() self.rate_enforcer = rds.rate_enforcer(usrp_rate) pulse_shaping_taps = gr.firdes.low_pass( 1, # gain usrp_rate, # sampling rate 1.5e3, # passband cutoff 2e3, # transition width gr.firdes.WIN_HAMMING, ) self.pulse_shaping = gr.fir_filter_fff(1, pulse_shaping_taps) self.bpsk_mod = gr.multiply_ff() self.connect(self.rds_enc, self.diff_enc, self.manchester1, self.manchester2, self.nrz, self.c2f) self.connect(self.c2f, (self.rate_enforcer, 0)) self.connect(self.pilot, (self.rate_enforcer, 1)) self.connect(self.rate_enforcer, (self.bpsk_mod, 0)) self.connect(self.pilot, (self.bpsk_mod, 1)) self.connect(self.pilot, (self.bpsk_mod, 2)) self.connect(self.pilot, (self.bpsk_mod, 3)) # RDS band-pass filter rds_filter_taps = gr.firdes.band_pass( 50, # gain usrp_rate, # sampling rate 57e3 - 3e3, # low cutoff 57e3 + 3e3, # high cutoff 1e3, # transition width gr.firdes.WIN_HAMMING, ) self.rds_filter = gr.fir_filter_fff(1, rds_filter_taps) self.connect(self.bpsk_mod, self.rds_filter) # mix L+R, pilot, L-R and RDS self.mixer = gr.add_ff() self.connect(self.audio_lpr_filter, (self.mixer, 0)) self.connect(self.pilot, (self.mixer, 1)) self.connect(self.audio_lmr_filter, (self.mixer, 2)) self.connect(self.rds_filter, (self.mixer, 3)) # fm modulation, gain & TX max_dev = 75e3 k = 2 * math.pi * max_dev / usrp_rate # modulator sensitivity self.modulator = gr.frequency_modulator_fc(k) self.gain = gr.multiply_const_cc(5e3) self.connect(self.mixer, self.modulator, self.gain, self.u) # plot an FFT to verify we are sending what we want if 1: self.fft = fftsink2.fft_sink_f( panel, title="Pre FM modulation", fft_size=512 * 4, sample_rate=usrp_rate, y_per_div=20, ref_level=-20 ) self.connect(self.mixer, self.fft) vbox.Add(self.fft.win, 1, wx.EXPAND) if 0: self.scope = scopesink2.scope_sink_f(panel, title="RDS encoder output", sample_rate=usrp_rate) self.connect(self.rds_enc, self.scope) vbox.Add(self.scope.win, 1, wx.EXPAND)
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. @param samples_per_symbol: samples per baud >= 2 @type samples_per_symbol: integer @param bt: Gaussian filter bandwidth * symbol time @type bt: 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, "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 = gr.bytes_to_syms() # Form Gaussian filter # Generate Gaussian response (Needs to be convolved with window below). self.gaussian_taps = gr.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 = gr.interp_fir_filter_fff(samples_per_symbol, self.taps) # FM modulation self.fmmod = gr.frequency_modulator_fc(sensitivity) # small amount of output attenuation to prevent clipping USRP sink self.amp = gr.multiply_const_cc(0.999) if verbose: self._print_verbage() if log: self._setup_logging() # Connect & Initialize base class self.connect(self, self.nrz, self.gaussian_filter, self.fmmod, self.amp, self)
def run_test(seed,blocksize): tb = gr.top_block() ################################################## # Variables ################################################## M = 2 K = 1 P = 2 h = (1.0*K)/P L = 3 Q = 4 frac = 0.99 f = trellis.fsm(P,M,L) # CPFSK signals #p = numpy.ones(Q)/(2.0) #q = numpy.cumsum(p)/(1.0*Q) # GMSK signals BT=0.3; tt=numpy.arange(0,L*Q)/(1.0*Q)-L/2.0; #print tt p=(0.5*scipy.stats.erfc(2*math.pi*BT*(tt-0.5)/math.sqrt(math.log(2.0))/math.sqrt(2.0))-0.5*scipy.stats.erfc(2*math.pi*BT*(tt+0.5)/math.sqrt(math.log(2.0))/math.sqrt(2.0)))/2.0; p=p/sum(p)*Q/2.0; #print p q=numpy.cumsum(p)/Q; q=q/q[-1]/2.0; #print q (f0T,SS,S,F,Sf,Ff,N) = fsm_utils.make_cpm_signals(K,P,M,L,q,frac) #print N #print Ff Ffa = numpy.insert(Ff,Q,numpy.zeros(N),axis=0) #print Ffa MF = numpy.fliplr(numpy.transpose(Ffa)) #print MF E = numpy.sum(numpy.abs(Sf)**2,axis=0) Es = numpy.sum(E)/f.O() #print Es constellation = numpy.reshape(numpy.transpose(Sf),N*f.O()) #print Ff #print Sf #print constellation #print numpy.max(numpy.abs(SS - numpy.dot(Ff , Sf))) EsN0_db = 10.0 N0 = Es * 10.0**(-(1.0*EsN0_db)/10.0) #N0 = 0.0 #print N0 head = 4 tail = 4 numpy.random.seed(seed*666) data = numpy.random.randint(0, M, head+blocksize+tail+1) #data = numpy.zeros(blocksize+1+head+tail,'int') for i in range(head): data[i]=0 for i in range(tail+1): data[-i]=0 ################################################## # Blocks ################################################## random_source_x_0 = gr.vector_source_b(data, False) gr_chunks_to_symbols_xx_0 = gr.chunks_to_symbols_bf((-1, 1), 1) gr_interp_fir_filter_xxx_0 = gr.interp_fir_filter_fff(Q, p) gr_frequency_modulator_fc_0 = gr.frequency_modulator_fc(2*math.pi*h*(1.0/Q)) gr_add_vxx_0 = gr.add_vcc(1) gr_noise_source_x_0 = gr.noise_source_c(gr.GR_GAUSSIAN, (N0/2.0)**0.5, -long(seed)) gr_multiply_vxx_0 = gr.multiply_vcc(1) gr_sig_source_x_0 = gr.sig_source_c(Q, gr.GR_COS_WAVE, -f0T, 1, 0) # only works for N=2, do it manually for N>2... gr_fir_filter_xxx_0_0 = gr.fir_filter_ccc(Q, MF[0].conjugate()) gr_fir_filter_xxx_0_0_0 = gr.fir_filter_ccc(Q, MF[1].conjugate()) gr_streams_to_stream_0 = gr.streams_to_stream(gr.sizeof_gr_complex*1, N) gr_skiphead_0 = gr.skiphead(gr.sizeof_gr_complex*1, N*(1+0)) viterbi = trellis.viterbi_combined_cb(f, head+blocksize+tail, 0, -1, N, constellation, trellis.TRELLIS_EUCLIDEAN) gr_vector_sink_x_0 = gr.vector_sink_b() ################################################## # Connections ################################################## tb.connect((random_source_x_0, 0), (gr_chunks_to_symbols_xx_0, 0)) tb.connect((gr_chunks_to_symbols_xx_0, 0), (gr_interp_fir_filter_xxx_0, 0)) tb.connect((gr_interp_fir_filter_xxx_0, 0), (gr_frequency_modulator_fc_0, 0)) tb.connect((gr_frequency_modulator_fc_0, 0), (gr_add_vxx_0, 0)) tb.connect((gr_noise_source_x_0, 0), (gr_add_vxx_0, 1)) tb.connect((gr_add_vxx_0, 0), (gr_multiply_vxx_0, 0)) tb.connect((gr_sig_source_x_0, 0), (gr_multiply_vxx_0, 1)) tb.connect((gr_multiply_vxx_0, 0), (gr_fir_filter_xxx_0_0, 0)) tb.connect((gr_multiply_vxx_0, 0), (gr_fir_filter_xxx_0_0_0, 0)) tb.connect((gr_fir_filter_xxx_0_0, 0), (gr_streams_to_stream_0, 0)) tb.connect((gr_fir_filter_xxx_0_0_0, 0), (gr_streams_to_stream_0, 1)) tb.connect((gr_streams_to_stream_0, 0), (gr_skiphead_0, 0)) tb.connect((gr_skiphead_0, 0), (viterbi, 0)) tb.connect((viterbi, 0), (gr_vector_sink_x_0, 0)) tb.run() dataest = gr_vector_sink_x_0.data() #print data #print numpy.array(dataest) perr = 0 err = 0 for i in range(blocksize): if data[head+i] != dataest[head+i]: #print i err += 1 if err != 0 : perr = 1 return (err,perr)
def __init__(self, samples_per_symbol=_def_samples_per_symbol, bits_per_symbol=_def_bits_per_symbol, h_numerator=_def_h_numerator, h_denominator=_def_h_denominator, cpm_type=_def_cpm_type, bt=_def_bt, symbols_per_pulse=_def_symbols_per_pulse, generic_taps=_def_generic_taps, verbose=_def_verbose, log=_def_log): """ Hierarchical block for Continuous Phase modulation. The input is a byte stream (unsigned char) representing packed bits and the output is the complex modulated signal at baseband. See Proakis for definition of generic CPM signals: s(t)=exp(j phi(t)) phi(t)= 2 pi h int_0^t f(t') dt' f(t)=sum_k a_k g(t-kT) (normalizing assumption: int_0^infty g(t) dt = 1/2) @param samples_per_symbol: samples per baud >= 2 @type samples_per_symbol: integer @param bits_per_symbol: bits per symbol @type bits_per_symbol: integer @param h_numerator: numerator of modulation index @type h_numerator: integer @param h_denominator: denominator of modulation index (numerator and denominator must be relative primes) @type h_denominator: integer @param cpm_type: supported types are: 0=CPFSK, 1=GMSK, 2=RC, 3=GENERAL @type cpm_type: integer @param bt: bandwidth symbol time product for GMSK @type bt: float @param symbols_per_pulse: shaping pulse duration in symbols @type symbols_per_pulse: integer @param generic_taps: define a generic CPM pulse shape (sum = samples_per_symbol/2) @type generic_taps: array of floats @param verbose: Print information about modulator? @type verbose: bool @param debug: Print modulation data to files? @type debug: bool """ gr.hier_block2.__init__("cpm_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._bits_per_symbol = bits_per_symbol self._h_numerator = h_numerator self._h_denominator = h_denominator self._cpm_type = cpm_type self._bt=bt if cpm_type == 0 or cpm_type == 2 or cpm_type == 3: # CPFSK, RC, Generic self._symbols_per_pulse = symbols_per_pulse elif cpm_type == 1: # GMSK self._symbols_per_pulse = 4 else: raise TypeError, ("cpm_type must be an integer in {0,1,2,3}, is %r" % (cpm_type,)) self._generic_taps=numpy.array(generic_taps) 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,)) self.nsymbols = 2**bits_per_symbol self.sym_alphabet=numpy.arange(-(self.nsymbols-1),self.nsymbols,2) self.ntaps = self._symbols_per_pulse * samples_per_symbol sensitivity = 2 * pi * h_numerator / h_denominator / samples_per_symbol # Unpack Bytes into bits_per_symbol groups self.B2s = gr.packed_to_unpacked_bb(bits_per_symbol,gr.GR_MSB_FIRST) # Turn it into symmetric PAM data. self.pam = gr.chunks_to_symbols_bf(self.sym_alphabet,1) # Generate pulse (sum of taps = samples_per_symbol/2) if cpm_type == 0: # CPFSK self.taps= (1.0/self._symbols_per_pulse/2,) * self.ntaps elif cpm_type == 1: # GMSK gaussian_taps = gr.firdes.gaussian( 1.0/2, # gain samples_per_symbol, # symbol_rate bt, # bandwidth * symbol time self.ntaps # number of taps ) sqwave = (1,) * samples_per_symbol # rectangular window self.taps = numpy.convolve(numpy.array(gaussian_taps),numpy.array(sqwave)) elif cpm_type == 2: # Raised Cosine # generalize it for arbitrary roll-off factor self.taps = (1-numpy.cos(2*pi*numpy.arange(0,self.ntaps)/samples_per_symbol/self._symbols_per_pulse))/(2*self._symbols_per_pulse) elif cpm_type == 3: # Generic CPM self.taps = generic_taps else: raise TypeError, ("cpm_type must be an integer in {0,1,2,3}, is %r" % (cpm_type,)) self.filter = gr.interp_fir_filter_fff(samples_per_symbol, self.taps) # FM modulation self.fmmod = gr.frequency_modulator_fc(sensitivity) if verbose: self._print_verbage() if log: self._setup_logging() # Connect self.connect(self, self.B2s, self.pam, self.filter, self.fmmod, self)
def __init__(self, mode, debug=False): """ OFDM time and coarse frequency synchronisation for DAB @param mode DAB mode (1-4) @param debug if True: write data streams out to files """ if mode<1 or mode>4: raise ValueError, "Invalid DAB mode: "+str(mode)+" (modes 1-4 exist)" # get the correct DAB parameters dp = parameters.dab_parameters(mode) rp = parameters.receiver_parameters(mode) gr.hier_block2.__init__(self,"ofdm_sync_dab", gr.io_signature(1, 1, gr.sizeof_gr_complex), # input signature gr.io_signature2(2, 2, gr.sizeof_gr_complex, gr.sizeof_char)) # output signature # workaround for a problem that prevents connecting more than one block directly (see trac ticket #161) self.input = gr.kludge_copy(gr.sizeof_gr_complex) self.connect(self, self.input) # # null-symbol detection # # (outsourced to detect_zero.py) self.ns_detect = detect_null.detect_null(dp.ns_length, debug) self.connect(self.input, self.ns_detect) # # fine frequency synchronisation # # the code for fine frequency synchronisation is adapted from # ofdm_sync_ml.py; it abuses the cyclic prefix to find the fine # frequency error, as suggested in "ML Estimation of Timing and # Frequency Offset in OFDM Systems", by Jan-Jaap van de Beek, # Magnus Sandell, Per Ola Börjesson, see # http://www.sm.luth.se/csee/sp/research/report/bsb96r.html self.ffs_delay = gr.delay(gr.sizeof_gr_complex, dp.fft_length) self.ffs_conj = gr.conjugate_cc() self.ffs_mult = gr.multiply_cc() # self.ffs_moving_sum = gr.fir_filter_ccf(1, [1]*dp.cp_length) self.ffs_moving_sum = dab_swig.moving_sum_cc(dp.cp_length) self.ffs_angle = gr.complex_to_arg() self.ffs_angle_scale = gr.multiply_const_ff(1./dp.fft_length) self.ffs_delay_sample_and_hold = gr.delay(gr.sizeof_char, dp.symbol_length) # sample the value at the end of the symbol .. self.ffs_sample_and_hold = gr.sample_and_hold_ff() self.ffs_delay_input_for_correction = gr.delay(gr.sizeof_gr_complex, dp.symbol_length) # by delaying the input, we can use the ff offset estimation from the first symbol to correct the first symbol itself self.ffs_nco = gr.frequency_modulator_fc(1) # ffs_sample_and_hold directly outputs phase error per sample self.ffs_mixer = gr.multiply_cc() # calculate fine frequency error self.connect(self.input, self.ffs_conj, self.ffs_mult) self.connect(self.input, self.ffs_delay, (self.ffs_mult, 1)) self.connect(self.ffs_mult, self.ffs_moving_sum, self.ffs_angle) # only use the value from the first half of the first symbol self.connect(self.ffs_angle, self.ffs_angle_scale, (self.ffs_sample_and_hold, 0)) self.connect(self.ns_detect, self.ffs_delay_sample_and_hold, (self.ffs_sample_and_hold, 1)) # do the correction self.connect(self.ffs_sample_and_hold, self.ffs_nco, (self.ffs_mixer, 0)) self.connect(self.input, self.ffs_delay_input_for_correction, (self.ffs_mixer, 1)) # output - corrected signal and start of DAB frames self.connect(self.ffs_mixer, (self, 0)) self.connect(self.ffs_delay_sample_and_hold, (self, 1)) if debug: self.connect(self.ffs_angle, gr.file_sink(gr.sizeof_float, "debug/ofdm_sync_dab_ffs_angle.dat")) self.connect(self.ffs_sample_and_hold, gr.multiply_const_ff(1./(dp.T*2*pi)), gr.file_sink(gr.sizeof_float, "debug/ofdm_sync_dab_fine_freq_err_f.dat")) self.connect(self.ffs_mixer, gr.file_sink(gr.sizeof_gr_complex, "debug/ofdm_sync_dab_fine_freq_corrected_c.dat"))
def __init__(self, samples_per_symbol=_def_samples_per_symbol, bits_per_symbol=_def_bits_per_symbol, h_numerator=_def_h_numerator, h_denominator=_def_h_denominator, cpm_type=_def_cpm_type, bt=_def_bt, symbols_per_pulse=_def_symbols_per_pulse, generic_taps=_def_generic_taps, verbose=_def_verbose, log=_def_log): """ Hierarchical block for Continuous Phase modulation. The input is a byte stream (unsigned char) representing packed bits and the output is the complex modulated signal at baseband. See Proakis for definition of generic CPM signals: s(t)=exp(j phi(t)) phi(t)= 2 pi h int_0^t f(t') dt' f(t)=sum_k a_k g(t-kT) (normalizing assumption: int_0^infty g(t) dt = 1/2) @param samples_per_symbol: samples per baud >= 2 @type samples_per_symbol: integer @param bits_per_symbol: bits per symbol @type bits_per_symbol: integer @param h_numerator: numerator of modulation index @type h_numerator: integer @param h_denominator: denominator of modulation index (numerator and denominator must be relative primes) @type h_denominator: integer @param cpm_type: supported types are: 0=CPFSK, 1=GMSK, 2=RC, 3=GENERAL @type cpm_type: integer @param bt: bandwidth symbol time product for GMSK @type bt: float @param symbols_per_pulse: shaping pulse duration in symbols @type symbols_per_pulse: integer @param generic_taps: define a generic CPM pulse shape (sum = samples_per_symbol/2) @type generic_taps: array of floats @param verbose: Print information about modulator? @type verbose: bool @param debug: Print modulation data to files? @type debug: bool """ gr.hier_block2.__init__( self, "cpm_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._bits_per_symbol = bits_per_symbol self._h_numerator = h_numerator self._h_denominator = h_denominator self._cpm_type = cpm_type self._bt = bt if cpm_type == 0 or cpm_type == 2 or cpm_type == 3: # CPFSK, RC, Generic self._symbols_per_pulse = symbols_per_pulse elif cpm_type == 1: # GMSK self._symbols_per_pulse = 4 else: raise TypeError, ( "cpm_type must be an integer in {0,1,2,3}, is %r" % (cpm_type, )) self._generic_taps = numpy.array(generic_taps) if samples_per_symbol < 2: raise TypeError, ("samples_per_symbol must be >= 2, is %r" % (samples_per_symbol, )) self.nsymbols = 2**bits_per_symbol self.sym_alphabet = numpy.arange(-(self.nsymbols - 1), self.nsymbols, 2).tolist() self.ntaps = int(self._symbols_per_pulse * samples_per_symbol) sensitivity = 2 * pi * h_numerator / h_denominator / samples_per_symbol # Unpack Bytes into bits_per_symbol groups self.B2s = gr.packed_to_unpacked_bb(bits_per_symbol, gr.GR_MSB_FIRST) # Turn it into symmetric PAM data. self.pam = gr.chunks_to_symbols_bf(self.sym_alphabet, 1) # Generate pulse (sum of taps = samples_per_symbol/2) if cpm_type == 0: # CPFSK self.taps = (1.0 / self._symbols_per_pulse / 2, ) * self.ntaps elif cpm_type == 1: # GMSK gaussian_taps = gr.firdes.gaussian( 1.0 / 2, # gain samples_per_symbol, # symbol_rate bt, # bandwidth * symbol time self.ntaps # number of taps ) sqwave = (1, ) * samples_per_symbol # rectangular window self.taps = numpy.convolve(numpy.array(gaussian_taps), numpy.array(sqwave)) elif cpm_type == 2: # Raised Cosine # generalize it for arbitrary roll-off factor self.taps = (1 - numpy.cos( 2 * pi * numpy.arange(0, self.ntaps) / samples_per_symbol / self._symbols_per_pulse)) / (2 * self._symbols_per_pulse) elif cpm_type == 3: # Generic CPM self.taps = generic_taps else: raise TypeError, ( "cpm_type must be an integer in {0,1,2,3}, is %r" % (cpm_type, )) self.filter = blks2.pfb_arb_resampler_fff(samples_per_symbol, self.taps) # FM modulation self.fmmod = gr.frequency_modulator_fc(sensitivity) if verbose: self._print_verbage() if log: self._setup_logging() # Connect self.connect(self, self.B2s, self.pam, self.filter, self.fmmod, self)
def __init__(self, freq, subdev_spec, which_USRP, audio_input, debug): #gr.hier_block2.__init__(self, "analog_transmit_path", # gr.io_signature(0, 0, 0), #input signature # gr.io_signature(0, 0, 0)) #output signature gr.top_block.__init__(self) self.DEBUG = debug self.freq = freq #self.freq = 462562500 # audio_input="hw:0" #Formerly from XML self.tx_usrp_pga_gain_scaling = 1.0 self.tx_power = 1 self.tx_mod_type = 'fm' self.tx_freq_deviation = 2.5e3 self.tx_base_band_bw = 5e3 ################## USRP settings ################### r = gr.enable_realtime_scheduling () # acquire USRP via USB 2.0 #self.u = usrp.sink_c(fusb_block_size=1024, # fusb_nblocks=4, # which=which_USRP) self.u = uhd.single_usrp_sink( device_addr="", io_type=uhd.io_type_t.COMPLEX_FLOAT32, num_channels=1, ) # get D/A converter sampling rate #self.dac_rate = self.u.dac_rate() #128 MS/s self.dac_rate = 128e6 #128 MS/s if self.DEBUG: print " Tx Path DAC rate: %d" %(self.dac_rate) #System digital sample rate setting self.audio_rate = 16e3 self._gr_interp = 16 self.max_gr_interp_rate = 40 self._usrp_interp = 500 self.gr_rate = self.dac_rate / self._usrp_interp self._gr_decim = 1 if self.DEBUG: print " usrp interp: ", self._usrp_interp print " gr interp: ", self._gr_interp print " gr rate1: ", self.gr_rate print " gr decim: ", self._gr_decim print " audio rate: ", self.audio_rate # set USRP interplation ratio #self.u.set_interp_rate(self._usrp_interp) self.u.set_samp_rate(self.gr_rate) # set USRP daughterboard subdevice #if subdev_spec is None: # subdev_spec = usrp.pick_tx_subdevice(self.u) #self.u.set_mux(usrp.determine_tx_mux_value(self.u, subdev_spec)) #self.subdev = usrp.selected_subdev(self.u, subdev_spec) self.u.set_antenna("TX/RX") #if self.DEBUG: # print " TX Path use daughterboard: %s" % (self.subdev.side_and_name()) # Set center frequency of USRP """ Set the center frequency we're interested in. Tuning is a two step process. First we ask the front-end to tune as close to the desired frequency as it can. Then we use the result of that operation and our target_frequency to determine the value for the digital up converter. """ assert(self.freq != None) #r = self.u.tune(self.subdev.which(), self.subdev, self.freq) r = self.u.set_center_freq(self.freq, 0) if self.DEBUG: if r: print " Tx Frequency: %s" %(eng_notation.num_to_str(self.freq)) else: print "----Failed to set Tx frequency to %s" % (eng_notation.num_to_str(self.freq),) raise ValueError # Set the USRP Tx PGA gain, (Note that on the RFX cards this is a nop.) # subdev.set_gain(subdev.gain_range()[1]) # set max Tx gain #g = self.subdev.gain_range() g = self.u.get_gain_range(0) #_tx_usrp_gain_range = g[1]-g[0] _tx_usrp_gain_range = g #_tx_usrp_gain = g[0] + _tx_usrp_gain_range * self.tx_usrp_pga_gain_scaling #_tx_usrp_gain = g + _tx_usrp_gain_range * self.tx_usrp_pga_gain_scaling #self.subdev.set_gain(_tx_usrp_gain) #self.u.set_gain(_tx_usrp_gain, 0) self.u.set_gain(10, 0) #if self.DEBUG: # print " USRP Tx PGA Gain Range: min = %g, max = %g, step size = %g" \ # %(g[0], g[1], g[2]) # print " USRP Tx PGA gain set to: %g" %(_tx_usrp_gain) # Set the transmit amplitude sent to the USRP (param: ampl 0 <= ampl < 16384.) """ Convert tx_power(mW) in waveform.xml to amplitude in gnu radio """ ampl= 1638.3*pow(self.tx_power, 0.5) self.tx_amplitude = max(0.0, min(ampl, 16383.0)) if self.DEBUG: print "tx amplitude:", self.tx_amplitude #gr digital amplifier self.tx_amplitude = 1.0 self.gr_amp = gr.multiply_const_cc (int(self.tx_amplitude)) # software amplifier (scaler) print "GR amp= ", int(self.tx_amplitude) if self.DEBUG: print " Tx power acquired from waveform configuration XML file is: %f between (0, 100.0mW)" %(self.tx_power) print " Tx Path initial software signal amplitude to USRP: %f / 16383.0" %(ampl) print " Tx Path actual software signal amplitude to USRP: %f / 16383.0" %(self.tx_amplitude) ################## Choose the corresponding analog modem ################### if self.DEBUG: print "----Tx path modulation: %s" % (self.tx_mod_type) chan_filter_coeffs_fixed = ( 0.000457763671875, 0.000946044921875, 0.00067138671875, 0.001068115234375, 0.00091552734375, 0.0008544921875, 0.000518798828125, 0.0001220703125, -0.000396728515625, -0.0008544921875, -0.00128173828125, -0.00146484375, -0.001434326171875, -0.0010986328125, -0.000518798828125, 0.000274658203125, 0.001129150390625, 0.00189208984375, 0.00238037109375, 0.00250244140625, 0.002166748046875, 0.0013427734375, 0.000152587890625, -0.001220703125, -0.002532958984375, -0.0035400390625, -0.003997802734375, -0.003753662109375, -0.002777099609375, -0.0010986328125, 0.000946044921875, 0.00311279296875, 0.00494384765625, 0.00604248046875, 0.006103515625, 0.005035400390625, 0.00286865234375, -0.0001220703125, -0.00347900390625, -0.006561279296875, -0.008758544921875, -0.00958251953125, -0.008636474609375, -0.005950927734375, -0.001739501953125, 0.00335693359375, 0.00848388671875, 0.0126953125, 0.01507568359375, 0.014862060546875, 0.01171875, 0.00579833984375, -0.002227783203125, -0.01123046875, -0.0196533203125, -0.02587890625, -0.028228759765625, -0.025421142578125, -0.016754150390625, -0.002166748046875, 0.017608642578125, 0.041015625, 0.0660400390625, 0.090240478515625, 0.111083984375, 0.12640380859375, 0.134490966796875, 0.134490966796875, 0.12640380859375, 0.111083984375, 0.090240478515625, 0.0660400390625, 0.041015625, 0.017608642578125, -0.002166748046875, -0.016754150390625, -0.025421142578125, -0.028228759765625, -0.02587890625, -0.0196533203125, -0.01123046875, -0.002227783203125, 0.00579833984375, 0.01171875, 0.014862060546875, 0.01507568359375, 0.0126953125, 0.00848388671875, 0.00335693359375, -0.001739501953125, -0.005950927734375, -0.008636474609375, -0.00958251953125, -0.008758544921875, -0.006561279296875, -0.00347900390625, -0.0001220703125, 0.00286865234375, 0.005035400390625, 0.006103515625, 0.00604248046875, 0.00494384765625, 0.00311279296875, 0.000946044921875, -0.0010986328125, -0.002777099609375, -0.003753662109375, -0.003997802734375, -0.0035400390625, -0.002532958984375, -0.001220703125, 0.000152587890625, 0.0013427734375, 0.002166748046875, 0.00250244140625, 0.00238037109375, 0.00189208984375, 0.001129150390625, 0.000274658203125, -0.000518798828125, -0.0010986328125, -0.001434326171875, -0.00146484375, -0.00128173828125, -0.0008544921875, -0.000396728515625, 0.0001220703125, 0.000518798828125, 0.0008544921875, 0.00091552734375, 0.001068115234375, 0.00067138671875, 0.000946044921875, 0.000457763671875) #chan_filter = gr.interp_fir_filter_ccf(self._gr_interp, chan_filter_coeffs_fixed) #chan_filter_dsp = gr.dsp_fir_ccf (chan_filter_coeffs_fixed, 14, self._gr_interp, 0, 0, 0, 1) #r = gr.enable_realtime_scheduling () if self.DEBUG: print "interpolation rate = ", self._gr_interp # FM modulator k = 2 * math.pi * self.tx_freq_deviation / self.gr_rate modulator = gr.frequency_modulator_fc(k) # Pre-emphasis for FM modulation """ tau is preemphasis time constant, inverse proportional to channel bandwidth """ chan_bw = 2.0*(self.tx_base_band_bw + \ self.tx_freq_deviation)# Carson's rule of FM channel bandwidth tau = 1/(chan_bw * 0.5) if self.DEBUG: print " channel bandwidth: ", chan_bw print " tau: ", tau preemph = fm_preemph (self.gr_rate, tau) # audio_coeffs = ( # 0.00058729130373770002, # 0.0016584444738215582, # 0.0015819269921330031, # 0.0014607862142637573, # 0.00020681278261230754, #-0.0013001097961560814, #-0.00249802658603143, #-0.0024276134129972843, #-0.00083069749014258953, # 0.0017562878158492619, # 0.003963761120687582, # 0.0043075911442784871, # 0.0020710872871114866, #-0.0020172640629268932, #-0.005882026963765212, #-0.0070692053073845166, #-0.0041954626649490937, # 0.0019311082705710714, # 0.0082980827342646387, # 0.011045923787287403, # 0.0076530405054369872, #-0.0012102332109476402, #-0.011372099802214802, #-0.016910189774436514, #-0.013347352799620162, #-0.00068013535845177706, # 0.015578754320259895, # 0.026379517186832846, # 0.023618496101893545, # 0.0051085800414948012, #-0.022608534445133374, #-0.045529642916534545, #-0.047580556152787695, #-0.018048092177406189, # 0.042354392363985506, # 0.11988807809069109, # 0.19189052073753335, # 0.2351677633079737, # 0.2351677633079737, # 0.19189052073753335, # 0.11988807809069109, # 0.042354392363985506, #-0.018048092177406189, #-0.047580556152787695, #-0.045529642916534545, #-0.022608534445133374, # 0.0051085800414948012, # 0.023618496101893545, # 0.026379517186832846, # 0.015578754320259895, #-0.00068013535845177706, #-0.013347352799620162, #-0.016910189774436514, #-0.011372099802214802, #-0.0012102332109476402, # 0.0076530405054369872, # 0.011045923787287403, # 0.0082980827342646387, # 0.0019311082705710714, #-0.0041954626649490937, #-0.0070692053073845166, #-0.005882026963765212, #-0.0020172640629268932, # 0.0020710872871114866, # 0.0043075911442784871, # 0.003963761120687582, # 0.0017562878158492619, #-0.00083069749014258953, #-0.0024276134129972843, #-0.00249802658603143, #-0.0013001097961560814, # 0.00020681278261230754, # 0.0014607862142637573, # 0.0015819269921330031, # 0.0016584444738215582, # 0.00058729130373770002) audio_coeffs = ( -0.021392822265625, -0.0194091796875, 0.02972412109375, -0.018341064453125, -0.025299072265625, 0.07745361328125, -0.08251953125, -0.033905029296875, 0.56634521484375, 0.56634521484375, -0.033905029296875, -0.08251953125, 0.07745361328125, -0.025299072265625, -0.018341064453125, 0.02972412109375, -0.0194091796875, -0.021392822265625) #audio_coeffs = ( # -0.21392822265625, # -0.194091796875, # 0.2972412109375, # -0.18341064453125, # -0.25299072265625, # 0.7745361328125, # -0.8251953125, # -0.33905029296875, # 5.6634521484375, # 5.6634521484375, # -0.33905029296875, # -0.8251953125, # 0.7745361328125, # -0.25299072265625, # -0.18341064453125, # 0.2972412109375, # -0.194091796875, # -0.21392822265625) self.audio_filter = gr.interp_fir_filter_fff(self._gr_interp, audio_coeffs) #Source audio Low-pass Filter #self.audio_throt = gr.multiply_const_ff(50) self.audio_throt = gr.multiply_const_ff(5) if self.DEBUG: print "audio decim FIR filter tap length:", len(audio_coeffs) # Setup audio source src = audio.source(int(self.audio_rate), audio_input) # Wiring up #self.connect(src, self.audio_throt, interpolator, preemph, modulator, chan_filter_dsp, self.gr_amp, self.u) self.connect(src, self.audio_throt, self.audio_filter, modulator, self.gr_amp, self.u)
def __init__(self, frame, panel, vbox, argv): stdgui2.std_top_block.__init__(self, frame, panel, vbox, argv) parser = OptionParser(option_class=eng_option) parser.add_option("-T", "--tx-subdev-spec", type="subdev", default=None, help="select USRP Tx side A or B") parser.add_option("-f", "--freq", type="eng_float", default=107.2e6, help="set Tx frequency to FREQ [required]", metavar="FREQ") parser.add_option("--wavfile", type="string", default="", help="read input from FILE") (options, args) = parser.parse_args() if len(args) != 0: parser.print_help() sys.exit(1) self.usrp_interp = 200 self.u = usrp.sink_c(0, self.usrp_interp) print "USRP Serial: ", self.u.serial_number() self.dac_rate = self.u.dac_rate() # 128 MS/s self.usrp_rate = self.dac_rate / self.usrp_interp # 640 kS/s self.sw_interp = 5 self.audio_rate = self.usrp_rate / self.sw_interp # 128 kS/s # determine the daughterboard subdevice we're using if options.tx_subdev_spec is None: options.tx_subdev_spec = usrp.pick_tx_subdevice(self.u) self.u.set_mux( usrp.determine_tx_mux_value(self.u, options.tx_subdev_spec)) self.subdev = usrp.selected_subdev(self.u, options.tx_subdev_spec) print "Using d'board: ", self.subdev.side_and_name() # set max Tx gain, tune frequency and enable transmitter self.subdev.set_gain(self.subdev.gain_range()[1]) if self.u.tune(self.subdev.which(), self.subdev, options.freq): print "Tuned to", options.freq / 1e6, "MHz" else: sys.exit(1) self.subdev.set_enable(True) # open wav file containing floats in the [-1, 1] range, repeat if options.wavfile is None: print "Please provide a wavfile to transmit! Exiting\n" sys.exit(1) self.src = gr.wavfile_source(options.wavfile, True) nchans = self.src.channels() sample_rate = self.src.sample_rate() bits_per_sample = self.src.bits_per_sample() print nchans, "channels,", sample_rate, "kS/s,", bits_per_sample, "bits/sample" # resample to 128kS/s if sample_rate == 44100: self.resample_left = blks2.rational_resampler_fff(32, 11) self.resample_right = blks2.rational_resampler_fff(32, 11) elif sample_rate == 48000: self.resample_left == blks2.rational_resampler_fff(8, 3) self.resample_right == blks2.rational_resampler_fff(8, 3) elif sample_rate == 8000: self.resample_left == blks2.rational_resampler_fff(16, 1) self.resample_right == blks2.rational_resampler_fff(16, 1) else: print sample_rate, "is an unsupported sample rate" sys.exit(1) self.connect((self.src, 0), self.resample_left) self.connect((self.src, 1), self.resample_right) # create L+R (mono) and L-R (stereo) self.audio_lpr = gr.add_ff() self.audio_lmr = gr.sub_ff() self.connect(self.resample_left, (self.audio_lpr, 0)) self.connect(self.resample_left, (self.audio_lmr, 0)) self.connect(self.resample_right, (self.audio_lpr, 1)) self.connect(self.resample_right, (self.audio_lmr, 1)) # low-pass filter for L+R audio_lpr_taps = gr.firdes.low_pass( 0.3, # gain self.audio_rate, # sampling rate 15e3, # passband cutoff 2e3, # transition width gr.firdes.WIN_HANN) self.audio_lpr_filter = gr.fir_filter_fff(1, audio_lpr_taps) self.connect(self.audio_lpr, self.audio_lpr_filter) # create pilot tone at 19 kHz self.pilot = gr.sig_source_f( self.audio_rate, # sampling freq gr.GR_SIN_WAVE, # waveform 19e3, # frequency 3e-2) # amplitude # create the L-R signal carrier at 38 kHz, high-pass to remove 0Hz tone self.stereo_carrier = gr.multiply_ff() self.connect(self.pilot, (self.stereo_carrier, 0)) self.connect(self.pilot, (self.stereo_carrier, 1)) stereo_carrier_taps = gr.firdes.high_pass( 1, # gain self.audio_rate, # sampling rate 1e4, # cutoff freq 2e3, # transition width gr.firdes.WIN_HANN) self.stereo_carrier_filter = gr.fir_filter_fff(1, stereo_carrier_taps) self.connect(self.stereo_carrier, self.stereo_carrier_filter) # upconvert L-R to 23-53 kHz and band-pass self.mix_stereo = gr.multiply_ff() audio_lmr_taps = gr.firdes.band_pass( 3e3, # gain self.audio_rate, # sampling rate 23e3, # low cutoff 53e3, # high cuttof 2e3, # transition width gr.firdes.WIN_HANN) self.audio_lmr_filter = gr.fir_filter_fff(1, audio_lmr_taps) self.connect(self.audio_lmr, (self.mix_stereo, 0)) self.connect(self.stereo_carrier_filter, (self.mix_stereo, 1)) self.connect(self.mix_stereo, self.audio_lmr_filter) # mix L+R, pilot and L-R self.mixer = gr.add_ff() self.connect(self.audio_lpr_filter, (self.mixer, 0)) self.connect(self.pilot, (self.mixer, 1)) self.connect(self.audio_lmr_filter, (self.mixer, 2)) # interpolation & pre-emphasis interp_taps = gr.firdes.low_pass( self.sw_interp, # gain self.audio_rate, # Fs 60e3, # cutoff freq 5e3, # transition width gr.firdes.WIN_HAMMING) self.interpolator = gr.interp_fir_filter_fff(self.sw_interp, interp_taps) self.pre_emph = blks2.fm_preemph(self.usrp_rate, tau=50e-6) self.connect(self.mixer, self.interpolator, self.pre_emph) # fm modulation, gain & TX max_dev = 100e3 k = 2 * math.pi * max_dev / self.usrp_rate # modulator sensitivity self.modulator = gr.frequency_modulator_fc(k) self.gain = gr.multiply_const_cc(1e3) self.connect(self.pre_emph, self.modulator, self.gain, self.u) # plot an FFT to verify we are sending what we want pre_mod = fftsink2.fft_sink_f(panel, title="Before Interpolation", fft_size=512, sample_rate=self.audio_rate, y_per_div=20, ref_level=20) self.connect(self.mixer, pre_mod) vbox.Add(pre_mod.win, 1, wx.EXPAND)
def main(): parser = OptionParser(option_class=eng_option) parser.add_option("-f", "--freq", type="eng_float", default=144.800e6, help="set frequency to FREQ", metavar="FREQ") parser.add_option("-m", "--message", type="string", default=":ALL :this is a test", help="message to send", metavar="MESSAGE") parser.add_option("-c", "--mycall", type="string", default="MYCALL", help="source callsign", metavar="CALL") parser.add_option("-t", "--tocall", type="string", default="CQ", help="recipient callsign", metavar="CALL") parser.add_option("-v", "--via", type="string", default="RELAY", help="digipeater callsign", metavar="CALL") parser.add_option("-d", "--do-logging", action="store_true", default=False, help="enable logging on datafiles") parser.add_option("-s", "--use-datafile", action="store_true", default=False, help="use usrp.dat (256kbps) as output") (options, args) = parser.parse_args() if len(args) != 0: parser.print_help() sys.exit(1) bitrate = 9600 dac_rate = 128e6 usrp_interp = 500 cordic_freq = options.freq - dac_rate sf = 153600 syminterp = sf / bitrate #16 nbfmdev = 3e3 fmsens = 2 * pi * nbfmdev / (sf * 5 / 3) bit_oversampling = 8 sw_interp = int(sf / bitrate / bit_oversampling) #2 fg = gr.flow_graph() p = buildpacket(options.mycall, 0, options.tocall, 0, options.via, 0, 0x03, 0xf0, options.message) if options.do_logging: dumppackettofile(p, "packet.dat") v = bits2syms(nrziencode(scrambler(hdlcpacket(p, 100, 1000)))) src = gr.vector_source_f(v) gaussian_taps = gr.firdes.gaussian( 1, # gain bit_oversampling, # symbol_rate 0.3, # bandwidth * symbol time 4 * bit_oversampling # number of taps ) sqwave = (1, ) * syminterp #rectangular window taps = Numeric.convolve(Numeric.array(gaussian_taps), Numeric.array(sqwave)) gaussian = gr.interp_fir_filter_fff(syminterp, taps) #9600*16=153600 res_taps = blks.design_filter(5, 3, 0.4) res = blks.rational_resampler_fff(fg, 5, 3, res_taps) #153600*5/3=256000 fmmod = gr.frequency_modulator_fc(fmsens) amp = gr.multiply_const_cc(32000) if options.use_datafile: dst = gr.file_sink(gr.sizeof_gr_complex, "usrp.dat") else: u = usrp.sink_c(0, usrp_interp) #256000*500=128000000 tx_subdev_spec = usrp.pick_tx_subdevice(u) m = usrp.determine_tx_mux_value(u, tx_subdev_spec) print "mux = %#04x" % (m, ) u.set_mux(m) subdev = usrp.selected_subdev(u, tx_subdev_spec) print "Using TX d'board %s" % (subdev.side_and_name(), ) u.set_tx_freq(0, cordic_freq) u.set_pga(0, 0) print "Actual frequency: ", u.tx_freq(0) dst = u fg.connect(src, gaussian, res, fmmod, amp, dst) fg.start() fg.wait()
def __init__(self, frame, panel, vbox, argv): stdgui2.std_top_block.__init__(self, frame, panel, vbox, argv) parser = OptionParser(option_class=eng_option) parser.add_option("-T", "--tx-subdev-spec", type="subdev", default=None, help="select USRP Tx side A or B") parser.add_option("-f", "--freq", type="eng_float", default=107.2e6, help="set Tx frequency to FREQ [required]", metavar="FREQ") parser.add_option("--wavfile", type="string", default=None, help="open .wav audio file FILE") parser.add_option("--xml", type="string", default="rds_data.xml", help="open .xml RDS data FILE") (options, args) = parser.parse_args() if len(args) != 0: parser.print_help() sys.exit(1) usrp_interp = 500 self.u = usrp.sink_c(0, usrp_interp) print "USRP Serial: ", self.u.serial_number() usrp_rate = self.u.dac_rate() / usrp_interp # 256 kS/s # determine the daughterboard subdevice we're using if options.tx_subdev_spec is None: options.tx_subdev_spec = usrp.pick_tx_subdevice(self.u) self.u.set_mux( usrp.determine_tx_mux_value(self.u, options.tx_subdev_spec)) self.subdev = usrp.selected_subdev(self.u, options.tx_subdev_spec) print "Using d'board", self.subdev.side_and_name() # set max Tx gain, tune frequency and enable transmitter gain = self.subdev.gain_range()[1] self.subdev.set_gain(gain) print "Gain set to", gain if self.u.tune(self.subdev.which(), self.subdev, options.freq): print "Tuned to", options.freq / 1e6, "MHz" else: sys.exit(1) self.subdev.set_enable(True) # open wav file containing floats in the [-1, 1] range, repeat if options.wavfile is None: print "Please provide a wavfile to transmit! Exiting\n" sys.exit(1) self.src = gr.wavfile_source(options.wavfile, True) nchans = self.src.channels() sample_rate = self.src.sample_rate() bits_per_sample = self.src.bits_per_sample() print nchans, "channels,", sample_rate, "samples/sec,", \ bits_per_sample, "bits/sample" # resample to usrp rate self.resample_left = blks2.rational_resampler_fff( usrp_rate, sample_rate) self.resample_right = blks2.rational_resampler_fff( usrp_rate, sample_rate) self.connect((self.src, 0), self.resample_left) self.connect((self.src, 1), self.resample_right) # create L+R (mono) and L-R (stereo) self.audio_lpr = gr.add_ff() self.audio_lmr = gr.sub_ff() self.connect(self.resample_left, (self.audio_lpr, 0)) self.connect(self.resample_left, (self.audio_lmr, 0)) self.connect(self.resample_right, (self.audio_lpr, 1)) self.connect(self.resample_right, (self.audio_lmr, 1)) # low-pass filter for L+R audio_lpr_taps = gr.firdes.low_pass( 0.5, # gain usrp_rate, # sampling rate 15e3, # passband cutoff 1e3, # transition width gr.firdes.WIN_HAMMING) self.audio_lpr_filter = gr.fir_filter_fff(1, audio_lpr_taps) self.connect(self.audio_lpr, self.audio_lpr_filter) # create pilot tone at 19 kHz self.pilot = gr.sig_source_f( usrp_rate, # sampling rate gr.GR_SIN_WAVE, # waveform 19e3, # frequency 5e-2) # amplitude # upconvert L-R to 38 kHz and band-pass self.mix_stereo = gr.multiply_ff() audio_lmr_taps = gr.firdes.band_pass( 80, # gain usrp_rate, # sampling rate 38e3 - 15e3, # low cutoff 38e3 + 15e3, # high cutoff 1e3, # transition width gr.firdes.WIN_HAMMING) self.audio_lmr_filter = gr.fir_filter_fff(1, audio_lmr_taps) self.connect(self.audio_lmr, (self.mix_stereo, 0)) self.connect(self.pilot, (self.mix_stereo, 1)) self.connect(self.pilot, (self.mix_stereo, 2)) self.connect(self.mix_stereo, self.audio_lmr_filter) # create RDS bitstream # diff-encode, manchester-emcode, NRZ # enforce the 1187.5bps rate # pulse shaping filter (matched with receiver) # mix with 57kHz carrier (equivalent to BPSK) self.rds_enc = rds.data_encoder('rds_data.xml') self.diff_enc = gr.diff_encoder_bb(2) self.manchester1 = gr.map_bb([1, 2]) self.manchester2 = gr.unpack_k_bits_bb(2) self.nrz = gr.map_bb([-1, 1]) self.c2f = gr.char_to_float() self.rate_enforcer = rds.rate_enforcer(usrp_rate) pulse_shaping_taps = gr.firdes.low_pass( 1, # gain usrp_rate, # sampling rate 1.5e3, # passband cutoff 2e3, # transition width gr.firdes.WIN_HAMMING) self.pulse_shaping = gr.fir_filter_fff(1, pulse_shaping_taps) self.bpsk_mod = gr.multiply_ff() self.connect (self.rds_enc, self.diff_enc, self.manchester1, \ self.manchester2, self.nrz, self.c2f) self.connect(self.c2f, (self.rate_enforcer, 0)) self.connect(self.pilot, (self.rate_enforcer, 1)) self.connect(self.rate_enforcer, (self.bpsk_mod, 0)) self.connect(self.pilot, (self.bpsk_mod, 1)) self.connect(self.pilot, (self.bpsk_mod, 2)) self.connect(self.pilot, (self.bpsk_mod, 3)) # RDS band-pass filter rds_filter_taps = gr.firdes.band_pass( 50, # gain usrp_rate, # sampling rate 57e3 - 3e3, # low cutoff 57e3 + 3e3, # high cutoff 1e3, # transition width gr.firdes.WIN_HAMMING) self.rds_filter = gr.fir_filter_fff(1, rds_filter_taps) self.connect(self.bpsk_mod, self.rds_filter) # mix L+R, pilot, L-R and RDS self.mixer = gr.add_ff() self.connect(self.audio_lpr_filter, (self.mixer, 0)) self.connect(self.pilot, (self.mixer, 1)) self.connect(self.audio_lmr_filter, (self.mixer, 2)) self.connect(self.rds_filter, (self.mixer, 3)) # fm modulation, gain & TX max_dev = 75e3 k = 2 * math.pi * max_dev / usrp_rate # modulator sensitivity self.modulator = gr.frequency_modulator_fc(k) self.gain = gr.multiply_const_cc(5e3) self.connect(self.mixer, self.modulator, self.gain, self.u) # plot an FFT to verify we are sending what we want if 1: self.fft = fftsink2.fft_sink_f(panel, title="Pre FM modulation", fft_size=512 * 4, sample_rate=usrp_rate, y_per_div=20, ref_level=-20) self.connect(self.mixer, self.fft) vbox.Add(self.fft.win, 1, wx.EXPAND) if 0: self.scope = scopesink2.scope_sink_f(panel, title="RDS encoder output", sample_rate=usrp_rate) self.connect(self.rds_enc, self.scope) vbox.Add(self.scope.win, 1, wx.EXPAND)
def __init__(self, fft_length, cp_length, occupied_tones, snr, ks, threshold, options, logging=False): """ Hierarchical block for receiving OFDM symbols. The input is the complex modulated signal at baseband. Synchronized packets are sent back to the demodulator. @param fft_length: total number of subcarriers @type fft_length: int @param cp_length: length of cyclic prefix as specified in subcarriers (<= fft_length) @type cp_length: int @param occupied_tones: number of subcarriers used for data @type occupied_tones: int @param snr: estimated signal to noise ratio used to guide cyclic prefix synchronizer @type snr: float @param ks: known symbols used as preambles to each packet @type ks: list of lists @param logging: turn file logging on or off @type logging: bool """ gr.hier_block2.__init__( self, "ofdm_receiver", gr.io_signature(1, 1, gr.sizeof_gr_complex), # Input signature #gr.io_signature2(2, 2, gr.sizeof_gr_complex*occupied_tones, gr.sizeof_char)) # Output signature apurv-- gr.io_signature3(3, 3, gr.sizeof_gr_complex * occupied_tones, gr.sizeof_char, gr.sizeof_gr_complex * occupied_tones )) # apurv++, goes into frame sink for hestimates #gr.io_signature4(4, 4, gr.sizeof_gr_complex*occupied_tones, gr.sizeof_char, gr.sizeof_gr_complex*occupied_tones, gr.sizeof_gr_complex*fft_length)) # apurv++, goes into frame sink for hestimates bw = (float(occupied_tones) / float(fft_length)) / 2.0 tb = bw * 0.08 chan_coeffs = gr.firdes.low_pass( 1.0, # gain 1.0, # sampling rate bw + tb, # midpoint of trans. band tb, # width of trans. band gr.firdes.WIN_HAMMING) # filter type self.chan_filt = gr.fft_filter_ccc(1, chan_coeffs) win = [1 for i in range(fft_length)] zeros_on_left = int(math.ceil((fft_length - occupied_tones) / 2.0)) ks0 = fft_length * [ 0, ] ks0[zeros_on_left:zeros_on_left + occupied_tones] = ks[0] ks0 = fft.ifftshift(ks0) ks0time = fft.ifft(ks0) # ADD SCALING FACTOR ks0time = ks0time.tolist() nco_sensitivity = -2.0 / fft_length # correct for fine frequency self.ofdm_sync = ofdm_sync_pn(fft_length, cp_length, ks0time, threshold, options.threshold_type, options.threshold_gap, logging) # apurv++ # Set up blocks self.nco = gr.frequency_modulator_fc( nco_sensitivity ) # generate a signal proportional to frequency error of sync block self.sigmix = gr.multiply_cc() self.sampler = digital_swig.ofdm_sampler( fft_length, fft_length + cp_length, len(ks) + 1, 100 ) # 1 for the extra preamble which ofdm_rx doesn't know about (check frame_sink) self.fft_demod = gr.fft_vcc(fft_length, True, win, True) self.ofdm_frame_acq = digital_swig.ofdm_frame_acquisition( occupied_tones, fft_length, cp_length, ks) if options.verbose: self._print_verbage(options) # apurv++ modified to allow collected time domain data to artifically pass through the rx chain # # to replay the input manually, use this # #self.connect(self, gr.null_sink(gr.sizeof_gr_complex)) #self.connect(gr.file_source(gr.sizeof_gr_complex, "input.dat"), self.chan_filt) ############# input -> chan_filt ############## self.connect(self, self.chan_filt) use_chan_filt = options.use_chan_filt correct_freq_offset = 0 if use_chan_filt == 1: ##### chan_filt -> SYNC, chan_filt -> SIGMIX #### self.connect(self.chan_filt, self.ofdm_sync) if correct_freq_offset == 1: # enable if frequency offset correction is required # self.connect(self.chan_filt, gr.delay(gr.sizeof_gr_complex, (fft_length)), (self.sigmix, 0)) # apurv++ follow freq offset else: self.connect(self.chan_filt, (self.sampler, 0)) ###self.connect(self.chan_filt, gr.delay(gr.sizeof_gr_complex, (fft_length)), (self.sampler, 0)) ## extra delay #self.connect(self.chan_filt, gr.file_sink(gr.sizeof_gr_complex, "ofdm_receiver-chan_filt_c.dat")) elif use_chan_filt == 2: #### alternative: chan_filt-> NULL, file_source -> SYNC, file_source -> SIGMIX #### self.connect(self.chan_filt, gr.null_sink(gr.sizeof_gr_complex)) if correct_freq_offset == 1: self.connect( gr.file_source(gr.sizeof_gr_complex, "chan_filt.dat"), self.ofdm_sync) self.connect( gr.file_source(gr.sizeof_gr_complex, "chan_filt.dat"), gr.delay(gr.sizeof_gr_complex, (fft_length)), (self.sigmix, 0)) else: self.connect( gr.file_source(gr.sizeof_gr_complex, "chan_filt.dat"), self.ofdm_sync) self.connect( gr.file_source(gr.sizeof_gr_complex, "chan_filt.dat"), (self.sampler, 0)) else: # chan_filt->NULL # self.connect(self.chan_filt, gr.null_sink(gr.sizeof_gr_complex)) method = options.method if method == -1: ################## for offline analysis, dump sampler input till the frame_sink, using io_signature4 ################# if correct_freq_offset == 1: # enable if frequency offset correction is required # self.connect((self.ofdm_sync, 0), self.nco, (self.sigmix, 1)) # freq offset (0'ed :/) self.connect(self.sigmix, (self.sampler, 0)) # corrected output (0'ed FF) self.connect((self.ofdm_sync, 1), gr.delay(gr.sizeof_char, fft_length), (self.sampler, 1)) # timing signal else: # disable frequency offset correction completely # self.connect((self.ofdm_sync, 0), gr.null_sink(gr.sizeof_float)) self.connect((self.ofdm_sync, 1), (self.sampler, 1)) # timing signal, #self.connect((self.ofdm_sync,0), (self.sampler, 2)) ##added ##self.connect((self.ofdm_sync,1), gr.delay(gr.sizeof_char, fft_length+cp_length), (self.sampler, 1)) # timing signal, ##extra delay # route received time domain to sink (all-the-way) for offline analysis # self.connect((self.sampler, 0), (self.ofdm_frame_acq, 2)) #self.connect((self.sampler, 1), gr.file_sink(gr.sizeof_char*fft_length, "sampler_timing.dat")) elif method == 0: # NORMAL functioning # if correct_freq_offset == 1: self.connect( (self.ofdm_sync, 0), self.nco, (self.sigmix, 1) ) # use sync freq. offset output to derotate input signal self.connect( self.sigmix, (self.sampler, 0)) # sample off timing signal detected in sync alg self.connect((self.ofdm_sync, 1), gr.delay(gr.sizeof_char, fft_length), (self.sampler, 1)) # delay? else: self.connect((self.ofdm_sync, 1), (self.sampler, 1)) #self.connect((self.sampler, 2), (self.ofdm_frame_acq, 2)) ####################################################################### use_default = options.use_default if use_default == 0: #(set method == 0) # sampler-> NULL, replay trace->fft_demod, ofdm_frame_acq (time domain) # #self.connect((self.sampler, 0), gr.null_sink(gr.sizeof_gr_complex*fft_length)) #self.connect((self.sampler, 1), gr.null_sink(gr.sizeof_char*fft_length)) self.connect( gr.file_source(gr.sizeof_gr_complex * fft_length, "symbols_src.dat"), self.fft_demod) self.connect( gr.file_source(gr.sizeof_char * fft_length, "timing_src.dat"), (self.ofdm_frame_acq, 1)) self.connect(self.fft_demod, (self.ofdm_frame_acq, 0)) elif use_default == 1: #(set method == -1) # normal functioning # self.connect( (self.sampler, 0), self.fft_demod) # send derotated sampled signal to FFT self.connect((self.sampler, 1), (self.ofdm_frame_acq, 1)) # send timing signal to signal frame start self.connect(self.fft_demod, (self.ofdm_frame_acq, 0)) elif use_default == 2: # replay directly to ofdm_frame_acq (frequency domain) # self.connect( gr.file_source(gr.sizeof_gr_complex * fft_length, "symbols_src.dat"), (self.ofdm_frame_acq, 0)) self.connect( gr.file_source(gr.sizeof_char * fft_length, "timing_src.dat"), (self.ofdm_frame_acq, 1)) ########################### some logging start ############################## #self.connect((self.ofdm_sync,1), gr.delay(gr.sizeof_char, fft_length), gr.file_sink(gr.sizeof_char, "ofdm_sync_pn-peaks_b.dat")) #self.connect((self.sampler, 0), gr.file_sink(gr.sizeof_gr_complex*fft_length, "ofdm_receiver-sampler_c.dat")) #self.connect((self.sampler, 1), gr.file_sink(gr.sizeof_char*fft_length, "ofdm_timing_sampler_c.dat")) ############################ some logging end ############################### self.connect((self.ofdm_frame_acq, 0), (self, 0)) # finished with fine/coarse freq correction, self.connect((self.ofdm_frame_acq, 1), (self, 1)) # frame and symbol timing, and equalization self.connect((self.ofdm_frame_acq, 2), (self, 2)) # equalizer: hestimates #self.connect((self.ofdm_frame_acq,3), (self,3)) # ref sampler above # apurv++ ends # #self.connect(self.ofdm_frame_acq, gr.file_sink(gr.sizeof_gr_complex*occupied_tones, "ofdm_receiver-frame_acq_c.dat")) #self.connect((self.ofdm_frame_acq,1), gr.file_sink(1, "ofdm_receiver-found_corr_b.dat")) # apurv++ log the fine frequency offset corrected symbols # #self.connect((self.ofdm_frame_acq, 1), gr.file_sink(gr.sizeof_char, "ofdm_timing_frame_acq_c.dat")) #self.connect((self.ofdm_frame_acq, 2), gr.file_sink(gr.sizeof_gr_complex*occupied_tones, "ofdm_hestimates_c.dat")) #self.connect(self.fft_demod, gr.file_sink(gr.sizeof_gr_complex*fft_length, "ofdm_receiver-fft_out_c.dat")) #self.connect(self.chan_filt, gr.file_sink(gr.sizeof_gr_complex, "ofdm_receiver-chan_filt_c.dat")) #self.connect(self, gr.file_sink(gr.sizeof_gr_complex, "ofdm_input_c.dat")) # apurv++ end # if logging: self.connect( self.chan_filt, gr.file_sink(gr.sizeof_gr_complex, "ofdm_receiver-chan_filt_c.dat")) self.connect( self.fft_demod, gr.file_sink(gr.sizeof_gr_complex * fft_length, "ofdm_receiver-fft_out_c.dat")) self.connect( self.ofdm_frame_acq, gr.file_sink(gr.sizeof_gr_complex * occupied_tones, "ofdm_receiver-frame_acq_c.dat")) self.connect((self.ofdm_frame_acq, 1), gr.file_sink(1, "ofdm_receiver-found_corr_b.dat")) self.connect( self.sampler, gr.file_sink(gr.sizeof_gr_complex * fft_length, "ofdm_receiver-sampler_c.dat")) #self.connect(self.sigmix, gr.file_sink(gr.sizeof_gr_complex, "ofdm_receiver-sigmix_c.dat")) self.connect( self.nco, gr.file_sink(gr.sizeof_gr_complex, "ofdm_receiver-nco_c.dat"))
def __init__(self): grc_wxgui.top_block_gui.__init__(self, title="Fm Stereo Tx") ################################################## # Variables ################################################## self.st_gain = st_gain = 10 self.samp_rate = samp_rate = 195.312e3 self.pilot_gain = pilot_gain = 80e-3 self.mpx_rate = mpx_rate = 160e3 self.Mono_gain = Mono_gain = 300e-3 self.FM_freq = FM_freq = 96.5e6 ################################################## # Blocks ################################################## _st_gain_sizer = wx.BoxSizer(wx.VERTICAL) self._st_gain_text_box = forms.text_box( parent=self.GetWin(), sizer=_st_gain_sizer, value=self.st_gain, callback=self.set_st_gain, label='st_gain', converter=forms.float_converter(), proportion=0, ) self._st_gain_slider = forms.slider( parent=self.GetWin(), sizer=_st_gain_sizer, value=self.st_gain, callback=self.set_st_gain, minimum=0, maximum=100, num_steps=100, style=wx.SL_HORIZONTAL, cast=float, proportion=1, ) self.Add(_st_gain_sizer) _pilot_gain_sizer = wx.BoxSizer(wx.VERTICAL) self._pilot_gain_text_box = forms.text_box( parent=self.GetWin(), sizer=_pilot_gain_sizer, value=self.pilot_gain, callback=self.set_pilot_gain, label='pilot_gain', converter=forms.float_converter(), proportion=0, ) self._pilot_gain_slider = forms.slider( parent=self.GetWin(), sizer=_pilot_gain_sizer, value=self.pilot_gain, callback=self.set_pilot_gain, minimum=0, maximum=1, num_steps=100, style=wx.SL_HORIZONTAL, cast=float, proportion=1, ) self.Add(_pilot_gain_sizer) self.notebook_0 = self.notebook_0 = wx.Notebook(self.GetWin(), style=wx.NB_TOP) self.notebook_0.AddPage(grc_wxgui.Panel(self.notebook_0), "FM") self.notebook_0.AddPage(grc_wxgui.Panel(self.notebook_0), "audio") self.Add(self.notebook_0) _Mono_gain_sizer = wx.BoxSizer(wx.VERTICAL) self._Mono_gain_text_box = forms.text_box( parent=self.GetWin(), sizer=_Mono_gain_sizer, value=self.Mono_gain, callback=self.set_Mono_gain, label='Mono_gain', converter=forms.float_converter(), proportion=0, ) self._Mono_gain_slider = forms.slider( parent=self.GetWin(), sizer=_Mono_gain_sizer, value=self.Mono_gain, callback=self.set_Mono_gain, minimum=0, maximum=1, num_steps=100, style=wx.SL_HORIZONTAL, cast=float, proportion=1, ) self.Add(_Mono_gain_sizer) _FM_freq_sizer = wx.BoxSizer(wx.VERTICAL) self._FM_freq_text_box = forms.text_box( parent=self.GetWin(), sizer=_FM_freq_sizer, value=self.FM_freq, callback=self.set_FM_freq, label='FM_freq', converter=forms.float_converter(), proportion=0, ) self._FM_freq_slider = forms.slider( parent=self.GetWin(), sizer=_FM_freq_sizer, value=self.FM_freq, callback=self.set_FM_freq, minimum=88e6, maximum=108e6, num_steps=100, style=wx.SL_HORIZONTAL, cast=float, proportion=1, ) self.Add(_FM_freq_sizer) self.wxgui_fftsink2_1 = fftsink2.fft_sink_f( self.notebook_0.GetPage(1).GetWin(), baseband_freq=0, y_per_div=10, y_divs=10, ref_level=0, ref_scale=2.0, sample_rate=samp_rate, fft_size=1024, fft_rate=15, average=False, avg_alpha=None, title="FFT Plot", peak_hold=False, ) self.notebook_0.GetPage(1).Add(self.wxgui_fftsink2_1.win) self.wxgui_fftsink2_0 = fftsink2.fft_sink_c( self.notebook_0.GetPage(0).GetWin(), baseband_freq=FM_freq, y_per_div=10, y_divs=10, ref_level=0, ref_scale=2.0, sample_rate=samp_rate, fft_size=1024, fft_rate=15, average=False, avg_alpha=None, title="FFT Plot", peak_hold=False, ) self.notebook_0.GetPage(0).Add(self.wxgui_fftsink2_0.win) self.uhd_usrp_sink_0 = uhd.usrp_sink( device_addr="addr=192.168.10.2", stream_args=uhd.stream_args( cpu_format="fc32", channels=range(1), ), ) self.uhd_usrp_sink_0.set_samp_rate(samp_rate) self.uhd_usrp_sink_0.set_center_freq(FM_freq, 0) self.uhd_usrp_sink_0.set_gain(0, 0) self.uhd_usrp_sink_0.set_antenna("TX/RX", 0) self.low_pass_filter_0 = gr.fir_filter_fff( 1, firdes.low_pass(Mono_gain, mpx_rate, 15000, 2000, firdes.WIN_HAMMING, 6.76)) self.gr_vector_to_streams_0 = gr.vector_to_streams( gr.sizeof_short * 1, 2) self.gr_sub_xx_0 = gr.sub_ff(1) self.gr_sig_source_x_1 = gr.sig_source_f(160000, gr.GR_SIN_WAVE, 19000, pilot_gain, 0) self.gr_sig_source_x_0 = gr.sig_source_f(160000, gr.GR_SIN_WAVE, 38000, 30e-3, 0) self.gr_short_to_float_1 = gr.short_to_float(1, 1) self.gr_short_to_float_0 = gr.short_to_float(1, 1) self.gr_multiply_xx_0 = gr.multiply_vff(1) self.gr_multiply_const_vxx_2 = gr.multiply_const_vcc((32.768e3, )) self.gr_multiply_const_vxx_1 = gr.multiply_const_vff((30e-6, )) self.gr_multiply_const_vxx_0 = gr.multiply_const_vff((30e-6, )) self.gr_frequency_modulator_fc_0 = gr.frequency_modulator_fc(980e-3) self.gr_file_source_0 = gr.file_source( gr.sizeof_short * 2, "/home/kranthi/Documents/project/FM Transceiver/FM Transmitter/test.raw", True) self.gr_add_xx_1 = gr.add_vff(1) self.gr_add_xx_0 = gr.add_vff(1) self.blks2_rational_resampler_xxx_2 = blks2.rational_resampler_fff( interpolation=4, decimation=1, taps=None, fractional_bw=None, ) self.blks2_rational_resampler_xxx_1 = blks2.rational_resampler_fff( interpolation=5, decimation=1, taps=None, fractional_bw=None, ) self.blks2_rational_resampler_xxx_0 = blks2.rational_resampler_fff( interpolation=5, decimation=1, taps=None, fractional_bw=None, ) self.blks2_fm_preemph_0 = blks2.fm_preemph(fs=mpx_rate, tau=50e-6) self.band_pass_filter_0 = gr.fir_filter_fff( 1, firdes.band_pass(st_gain, mpx_rate, 23000, 53000, 2000, firdes.WIN_HAMMING, 6.76)) ################################################## # Connections ################################################## self.connect((self.gr_file_source_0, 0), (self.gr_vector_to_streams_0, 0)) self.connect((self.gr_vector_to_streams_0, 0), (self.gr_short_to_float_0, 0)) self.connect((self.gr_vector_to_streams_0, 1), (self.gr_short_to_float_1, 0)) self.connect((self.gr_short_to_float_0, 0), (self.gr_multiply_const_vxx_0, 0)) self.connect((self.gr_short_to_float_1, 0), (self.gr_multiply_const_vxx_1, 0)) self.connect((self.gr_multiply_const_vxx_0, 0), (self.blks2_rational_resampler_xxx_0, 0)) self.connect((self.gr_multiply_const_vxx_1, 0), (self.blks2_rational_resampler_xxx_1, 0)) self.connect((self.blks2_rational_resampler_xxx_0, 0), (self.gr_add_xx_0, 1)) self.connect((self.blks2_rational_resampler_xxx_0, 0), (self.gr_sub_xx_0, 1)) self.connect((self.blks2_rational_resampler_xxx_1, 0), (self.gr_sub_xx_0, 0)) self.connect((self.blks2_rational_resampler_xxx_1, 0), (self.gr_add_xx_0, 0)) self.connect((self.gr_add_xx_0, 0), (self.low_pass_filter_0, 0)) self.connect((self.gr_sig_source_x_0, 0), (self.gr_multiply_xx_0, 0)) self.connect((self.gr_sub_xx_0, 0), (self.gr_multiply_xx_0, 1)) self.connect((self.gr_multiply_xx_0, 0), (self.band_pass_filter_0, 0)) self.connect((self.gr_sig_source_x_1, 0), (self.gr_add_xx_1, 0)) self.connect((self.band_pass_filter_0, 0), (self.gr_add_xx_1, 1)) self.connect((self.low_pass_filter_0, 0), (self.gr_add_xx_1, 2)) self.connect((self.gr_add_xx_1, 0), (self.blks2_fm_preemph_0, 0)) self.connect((self.blks2_fm_preemph_0, 0), (self.blks2_rational_resampler_xxx_2, 0)) self.connect((self.blks2_rational_resampler_xxx_2, 0), (self.gr_frequency_modulator_fc_0, 0)) self.connect((self.gr_frequency_modulator_fc_0, 0), (self.gr_multiply_const_vxx_2, 0)) self.connect((self.gr_multiply_const_vxx_2, 0), (self.uhd_usrp_sink_0, 0)) self.connect((self.gr_multiply_const_vxx_2, 0), (self.wxgui_fftsink2_0, 0)) self.connect((self.gr_multiply_const_vxx_1, 0), (self.wxgui_fftsink2_1, 0))
def __init__(self, freq, subdev_spec, which_USRP, audio_input, debug): #gr.hier_block2.__init__(self, "analog_transmit_path", # gr.io_signature(0, 0, 0), #input signature # gr.io_signature(0, 0, 0)) #output signature gr.top_block.__init__(self) self.DEBUG = debug self.freq = freq #self.freq = 462562500 # audio_input="hw:0" #Formerly from XML self.tx_usrp_pga_gain_scaling = 1.0 self.tx_power = 1 self.tx_mod_type = 'fm' self.tx_freq_deviation = 2.5e3 self.tx_base_band_bw = 5e3 ################## USRP settings ################### r = gr.enable_realtime_scheduling() # acquire USRP via USB 2.0 #self.u = usrp.sink_c(fusb_block_size=1024, # fusb_nblocks=4, # which=which_USRP) self.u = uhd.single_usrp_sink( device_addr="", io_type=uhd.io_type_t.COMPLEX_FLOAT32, num_channels=1, ) # get D/A converter sampling rate #self.dac_rate = self.u.dac_rate() #128 MS/s self.dac_rate = 128e6 #128 MS/s if self.DEBUG: print " Tx Path DAC rate: %d" % (self.dac_rate) #System digital sample rate setting self.audio_rate = 16e3 self._gr_interp = 16 self.max_gr_interp_rate = 40 self._usrp_interp = 500 self.gr_rate = self.dac_rate / self._usrp_interp self._gr_decim = 1 if self.DEBUG: print " usrp interp: ", self._usrp_interp print " gr interp: ", self._gr_interp print " gr rate1: ", self.gr_rate print " gr decim: ", self._gr_decim print " audio rate: ", self.audio_rate # set USRP interplation ratio #self.u.set_interp_rate(self._usrp_interp) self.u.set_samp_rate(self.gr_rate) # set USRP daughterboard subdevice #if subdev_spec is None: # subdev_spec = usrp.pick_tx_subdevice(self.u) #self.u.set_mux(usrp.determine_tx_mux_value(self.u, subdev_spec)) #self.subdev = usrp.selected_subdev(self.u, subdev_spec) self.u.set_antenna("TX/RX") #if self.DEBUG: # print " TX Path use daughterboard: %s" % (self.subdev.side_and_name()) # Set center frequency of USRP """ Set the center frequency we're interested in. Tuning is a two step process. First we ask the front-end to tune as close to the desired frequency as it can. Then we use the result of that operation and our target_frequency to determine the value for the digital up converter. """ assert (self.freq != None) #r = self.u.tune(self.subdev.which(), self.subdev, self.freq) r = self.u.set_center_freq(self.freq, 0) if self.DEBUG: if r: print " Tx Frequency: %s" % (eng_notation.num_to_str( self.freq)) else: print "----Failed to set Tx frequency to %s" % ( eng_notation.num_to_str(self.freq), ) raise ValueError # Set the USRP Tx PGA gain, (Note that on the RFX cards this is a nop.) # subdev.set_gain(subdev.gain_range()[1]) # set max Tx gain #g = self.subdev.gain_range() g = self.u.get_gain_range(0) #_tx_usrp_gain_range = g[1]-g[0] _tx_usrp_gain_range = g #_tx_usrp_gain = g[0] + _tx_usrp_gain_range * self.tx_usrp_pga_gain_scaling #_tx_usrp_gain = g + _tx_usrp_gain_range * self.tx_usrp_pga_gain_scaling #self.subdev.set_gain(_tx_usrp_gain) #self.u.set_gain(_tx_usrp_gain, 0) self.u.set_gain(10, 0) #if self.DEBUG: # print " USRP Tx PGA Gain Range: min = %g, max = %g, step size = %g" \ # %(g[0], g[1], g[2]) # print " USRP Tx PGA gain set to: %g" %(_tx_usrp_gain) # Set the transmit amplitude sent to the USRP (param: ampl 0 <= ampl < 16384.) """ Convert tx_power(mW) in waveform.xml to amplitude in gnu radio """ ampl = 1638.3 * pow(self.tx_power, 0.5) self.tx_amplitude = max(0.0, min(ampl, 16383.0)) if self.DEBUG: print "tx amplitude:", self.tx_amplitude #gr digital amplifier self.tx_amplitude = 1.0 self.gr_amp = gr.multiply_const_cc(int( self.tx_amplitude)) # software amplifier (scaler) print "GR amp= ", int(self.tx_amplitude) if self.DEBUG: print " Tx power acquired from waveform configuration XML file is: %f between (0, 100.0mW)" % ( self.tx_power) print " Tx Path initial software signal amplitude to USRP: %f / 16383.0" % ( ampl) print " Tx Path actual software signal amplitude to USRP: %f / 16383.0" % ( self.tx_amplitude) ################## Choose the corresponding analog modem ################### if self.DEBUG: print "----Tx path modulation: %s" % (self.tx_mod_type) chan_filter_coeffs_fixed = ( 0.000457763671875, 0.000946044921875, 0.00067138671875, 0.001068115234375, 0.00091552734375, 0.0008544921875, 0.000518798828125, 0.0001220703125, -0.000396728515625, -0.0008544921875, -0.00128173828125, -0.00146484375, -0.001434326171875, -0.0010986328125, -0.000518798828125, 0.000274658203125, 0.001129150390625, 0.00189208984375, 0.00238037109375, 0.00250244140625, 0.002166748046875, 0.0013427734375, 0.000152587890625, -0.001220703125, -0.002532958984375, -0.0035400390625, -0.003997802734375, -0.003753662109375, -0.002777099609375, -0.0010986328125, 0.000946044921875, 0.00311279296875, 0.00494384765625, 0.00604248046875, 0.006103515625, 0.005035400390625, 0.00286865234375, -0.0001220703125, -0.00347900390625, -0.006561279296875, -0.008758544921875, -0.00958251953125, -0.008636474609375, -0.005950927734375, -0.001739501953125, 0.00335693359375, 0.00848388671875, 0.0126953125, 0.01507568359375, 0.014862060546875, 0.01171875, 0.00579833984375, -0.002227783203125, -0.01123046875, -0.0196533203125, -0.02587890625, -0.028228759765625, -0.025421142578125, -0.016754150390625, -0.002166748046875, 0.017608642578125, 0.041015625, 0.0660400390625, 0.090240478515625, 0.111083984375, 0.12640380859375, 0.134490966796875, 0.134490966796875, 0.12640380859375, 0.111083984375, 0.090240478515625, 0.0660400390625, 0.041015625, 0.017608642578125, -0.002166748046875, -0.016754150390625, -0.025421142578125, -0.028228759765625, -0.02587890625, -0.0196533203125, -0.01123046875, -0.002227783203125, 0.00579833984375, 0.01171875, 0.014862060546875, 0.01507568359375, 0.0126953125, 0.00848388671875, 0.00335693359375, -0.001739501953125, -0.005950927734375, -0.008636474609375, -0.00958251953125, -0.008758544921875, -0.006561279296875, -0.00347900390625, -0.0001220703125, 0.00286865234375, 0.005035400390625, 0.006103515625, 0.00604248046875, 0.00494384765625, 0.00311279296875, 0.000946044921875, -0.0010986328125, -0.002777099609375, -0.003753662109375, -0.003997802734375, -0.0035400390625, -0.002532958984375, -0.001220703125, 0.000152587890625, 0.0013427734375, 0.002166748046875, 0.00250244140625, 0.00238037109375, 0.00189208984375, 0.001129150390625, 0.000274658203125, -0.000518798828125, -0.0010986328125, -0.001434326171875, -0.00146484375, -0.00128173828125, -0.0008544921875, -0.000396728515625, 0.0001220703125, 0.000518798828125, 0.0008544921875, 0.00091552734375, 0.001068115234375, 0.00067138671875, 0.000946044921875, 0.000457763671875) #chan_filter = gr.interp_fir_filter_ccf(self._gr_interp, chan_filter_coeffs_fixed) #chan_filter_dsp = gr.dsp_fir_ccf (chan_filter_coeffs_fixed, 14, self._gr_interp, 0, 0, 0, 1) #r = gr.enable_realtime_scheduling () if self.DEBUG: print "interpolation rate = ", self._gr_interp # FM modulator k = 2 * math.pi * self.tx_freq_deviation / self.gr_rate modulator = gr.frequency_modulator_fc(k) # Pre-emphasis for FM modulation """ tau is preemphasis time constant, inverse proportional to channel bandwidth """ chan_bw = 2.0*(self.tx_base_band_bw + \ self.tx_freq_deviation)# Carson's rule of FM channel bandwidth tau = 1 / (chan_bw * 0.5) if self.DEBUG: print " channel bandwidth: ", chan_bw print " tau: ", tau preemph = fm_preemph(self.gr_rate, tau) # audio_coeffs = ( # 0.00058729130373770002, # 0.0016584444738215582, # 0.0015819269921330031, # 0.0014607862142637573, # 0.00020681278261230754, #-0.0013001097961560814, #-0.00249802658603143, #-0.0024276134129972843, #-0.00083069749014258953, # 0.0017562878158492619, # 0.003963761120687582, # 0.0043075911442784871, # 0.0020710872871114866, #-0.0020172640629268932, #-0.005882026963765212, #-0.0070692053073845166, #-0.0041954626649490937, # 0.0019311082705710714, # 0.0082980827342646387, # 0.011045923787287403, # 0.0076530405054369872, #-0.0012102332109476402, #-0.011372099802214802, #-0.016910189774436514, #-0.013347352799620162, #-0.00068013535845177706, # 0.015578754320259895, # 0.026379517186832846, # 0.023618496101893545, # 0.0051085800414948012, #-0.022608534445133374, #-0.045529642916534545, #-0.047580556152787695, #-0.018048092177406189, # 0.042354392363985506, # 0.11988807809069109, # 0.19189052073753335, # 0.2351677633079737, # 0.2351677633079737, # 0.19189052073753335, # 0.11988807809069109, # 0.042354392363985506, #-0.018048092177406189, #-0.047580556152787695, #-0.045529642916534545, #-0.022608534445133374, # 0.0051085800414948012, # 0.023618496101893545, # 0.026379517186832846, # 0.015578754320259895, #-0.00068013535845177706, #-0.013347352799620162, #-0.016910189774436514, #-0.011372099802214802, #-0.0012102332109476402, # 0.0076530405054369872, # 0.011045923787287403, # 0.0082980827342646387, # 0.0019311082705710714, #-0.0041954626649490937, #-0.0070692053073845166, #-0.005882026963765212, #-0.0020172640629268932, # 0.0020710872871114866, # 0.0043075911442784871, # 0.003963761120687582, # 0.0017562878158492619, #-0.00083069749014258953, #-0.0024276134129972843, #-0.00249802658603143, #-0.0013001097961560814, # 0.00020681278261230754, # 0.0014607862142637573, # 0.0015819269921330031, # 0.0016584444738215582, # 0.00058729130373770002) audio_coeffs = (-0.021392822265625, -0.0194091796875, 0.02972412109375, -0.018341064453125, -0.025299072265625, 0.07745361328125, -0.08251953125, -0.033905029296875, 0.56634521484375, 0.56634521484375, -0.033905029296875, -0.08251953125, 0.07745361328125, -0.025299072265625, -0.018341064453125, 0.02972412109375, -0.0194091796875, -0.021392822265625) #audio_coeffs = ( # -0.21392822265625, # -0.194091796875, # 0.2972412109375, # -0.18341064453125, # -0.25299072265625, # 0.7745361328125, # -0.8251953125, # -0.33905029296875, # 5.6634521484375, # 5.6634521484375, # -0.33905029296875, # -0.8251953125, # 0.7745361328125, # -0.25299072265625, # -0.18341064453125, # 0.2972412109375, # -0.194091796875, # -0.21392822265625) self.audio_filter = gr.interp_fir_filter_fff(self._gr_interp, audio_coeffs) #Source audio Low-pass Filter #self.audio_throt = gr.multiply_const_ff(50) self.audio_throt = gr.multiply_const_ff(5) if self.DEBUG: print "audio decim FIR filter tap length:", len(audio_coeffs) # Setup audio source src = audio.source(int(self.audio_rate), audio_input) # Wiring up #self.connect(src, self.audio_throt, interpolator, preemph, modulator, chan_filter_dsp, self.gr_amp, self.u) self.connect(src, self.audio_throt, self.audio_filter, modulator, self.gr_amp, self.u)
def __init__(self, fft_length, cp_length, occupied_tones, snr, ks, threshold, options, logging=False): """ Hierarchical block for receiving OFDM symbols. The input is the complex modulated signal at baseband. Synchronized packets are sent back to the demodulator. @param fft_length: total number of subcarriers @type fft_length: int @param cp_length: length of cyclic prefix as specified in subcarriers (<= fft_length) @type cp_length: int @param occupied_tones: number of subcarriers used for data @type occupied_tones: int @param snr: estimated signal to noise ratio used to guide cyclic prefix synchronizer @type snr: float @param ks: known symbols used as preambles to each packet @type ks: list of lists @param logging: turn file logging on or off @type logging: bool """ gr.hier_block2.__init__( self, "ofdm_receiver", gr.io_signature(1, 1, gr.sizeof_gr_complex), # Input signature # gr.io_signature2(2, 2, gr.sizeof_gr_complex*occupied_tones, gr.sizeof_char)) # Output signature apurv-- gr.io_signature3( 3, 3, gr.sizeof_gr_complex * occupied_tones, gr.sizeof_char, gr.sizeof_gr_complex * occupied_tones ), ) # apurv++, goes into frame sink for hestimates # gr.io_signature4(4, 4, gr.sizeof_gr_complex*occupied_tones, gr.sizeof_char, gr.sizeof_gr_complex*occupied_tones, gr.sizeof_gr_complex*fft_length)) # apurv++, goes into frame sink for hestimates bw = (float(occupied_tones) / float(fft_length)) / 2.0 tb = bw * 0.08 chan_coeffs = gr.firdes.low_pass( 1.0, # gain 1.0, # sampling rate bw + tb, # midpoint of trans. band tb, # width of trans. band gr.firdes.WIN_HAMMING, ) # filter type self.chan_filt = gr.fft_filter_ccc(1, chan_coeffs) win = [1 for i in range(fft_length)] zeros_on_left = int(math.ceil((fft_length - occupied_tones) / 2.0)) ks0 = fft_length * [0] ks0[zeros_on_left : zeros_on_left + occupied_tones] = ks[0] ks0 = fft.ifftshift(ks0) ks0time = fft.ifft(ks0) # ADD SCALING FACTOR ks0time = ks0time.tolist() nco_sensitivity = -2.0 / fft_length # correct for fine frequency self.ofdm_sync = ofdm_sync_pn( fft_length, cp_length, ks0time, threshold, options.threshold_type, options.threshold_gap, logging ) # apurv++ # Set up blocks self.nco = gr.frequency_modulator_fc( nco_sensitivity ) # generate a signal proportional to frequency error of sync block self.sigmix = gr.multiply_cc() self.sampler = digital_swig.ofdm_sampler( fft_length, fft_length + cp_length, len(ks) + 1, 100 ) # 1 for the extra preamble which ofdm_rx doesn't know about (check frame_sink) self.fft_demod = gr.fft_vcc(fft_length, True, win, True) self.ofdm_frame_acq = digital_swig.ofdm_frame_acquisition(occupied_tones, fft_length, cp_length, ks) if options.verbose: self._print_verbage(options) # apurv++ modified to allow collected time domain data to artifically pass through the rx chain # # to replay the input manually, use this # # self.connect(self, gr.null_sink(gr.sizeof_gr_complex)) # self.connect(gr.file_source(gr.sizeof_gr_complex, "input.dat"), self.chan_filt) ############# input -> chan_filt ############## self.connect(self, self.chan_filt) use_chan_filt = options.use_chan_filt correct_freq_offset = 0 if use_chan_filt == 1: ##### chan_filt -> SYNC, chan_filt -> SIGMIX #### self.connect(self.chan_filt, self.ofdm_sync) if correct_freq_offset == 1: # enable if frequency offset correction is required # self.connect( self.chan_filt, gr.delay(gr.sizeof_gr_complex, (fft_length)), (self.sigmix, 0) ) # apurv++ follow freq offset else: self.connect(self.chan_filt, (self.sampler, 0)) ###self.connect(self.chan_filt, gr.delay(gr.sizeof_gr_complex, (fft_length)), (self.sampler, 0)) ## extra delay # self.connect(self.chan_filt, gr.file_sink(gr.sizeof_gr_complex, "ofdm_receiver-chan_filt_c.dat")) elif use_chan_filt == 2: #### alternative: chan_filt-> NULL, file_source -> SYNC, file_source -> SIGMIX #### self.connect(self.chan_filt, gr.null_sink(gr.sizeof_gr_complex)) if correct_freq_offset == 1: self.connect(gr.file_source(gr.sizeof_gr_complex, "chan_filt.dat"), self.ofdm_sync) self.connect( gr.file_source(gr.sizeof_gr_complex, "chan_filt.dat"), gr.delay(gr.sizeof_gr_complex, (fft_length)), (self.sigmix, 0), ) else: self.connect(gr.file_source(gr.sizeof_gr_complex, "chan_filt.dat"), self.ofdm_sync) self.connect(gr.file_source(gr.sizeof_gr_complex, "chan_filt.dat"), (self.sampler, 0)) else: # chan_filt->NULL # self.connect(self.chan_filt, gr.null_sink(gr.sizeof_gr_complex)) method = options.method if method == -1: ################## for offline analysis, dump sampler input till the frame_sink, using io_signature4 ################# if correct_freq_offset == 1: # enable if frequency offset correction is required # self.connect((self.ofdm_sync, 0), self.nco, (self.sigmix, 1)) # freq offset (0'ed :/) self.connect(self.sigmix, (self.sampler, 0)) # corrected output (0'ed FF) self.connect( (self.ofdm_sync, 1), gr.delay(gr.sizeof_char, fft_length), (self.sampler, 1) ) # timing signal else: # disable frequency offset correction completely # self.connect((self.ofdm_sync, 0), gr.null_sink(gr.sizeof_float)) self.connect((self.ofdm_sync, 1), (self.sampler, 1)) # timing signal, # self.connect((self.ofdm_sync,0), (self.sampler, 2)) ##added ##self.connect((self.ofdm_sync,1), gr.delay(gr.sizeof_char, fft_length+cp_length), (self.sampler, 1)) # timing signal, ##extra delay # route received time domain to sink (all-the-way) for offline analysis # self.connect((self.sampler, 0), (self.ofdm_frame_acq, 2)) # self.connect((self.sampler, 1), gr.file_sink(gr.sizeof_char*fft_length, "sampler_timing.dat")) elif method == 0: # NORMAL functioning # if correct_freq_offset == 1: self.connect( (self.ofdm_sync, 0), self.nco, (self.sigmix, 1) ) # use sync freq. offset output to derotate input signal self.connect(self.sigmix, (self.sampler, 0)) # sample off timing signal detected in sync alg self.connect((self.ofdm_sync, 1), gr.delay(gr.sizeof_char, fft_length), (self.sampler, 1)) # delay? else: self.connect((self.ofdm_sync, 1), (self.sampler, 1)) # self.connect((self.sampler, 2), (self.ofdm_frame_acq, 2)) ####################################################################### use_default = options.use_default if use_default == 0: # (set method == 0) # sampler-> NULL, replay trace->fft_demod, ofdm_frame_acq (time domain) # # self.connect((self.sampler, 0), gr.null_sink(gr.sizeof_gr_complex*fft_length)) # self.connect((self.sampler, 1), gr.null_sink(gr.sizeof_char*fft_length)) self.connect(gr.file_source(gr.sizeof_gr_complex * fft_length, "symbols_src.dat"), self.fft_demod) self.connect(gr.file_source(gr.sizeof_char * fft_length, "timing_src.dat"), (self.ofdm_frame_acq, 1)) self.connect(self.fft_demod, (self.ofdm_frame_acq, 0)) elif use_default == 1: # (set method == -1) # normal functioning # self.connect((self.sampler, 0), self.fft_demod) # send derotated sampled signal to FFT self.connect((self.sampler, 1), (self.ofdm_frame_acq, 1)) # send timing signal to signal frame start self.connect(self.fft_demod, (self.ofdm_frame_acq, 0)) elif use_default == 2: # replay directly to ofdm_frame_acq (frequency domain) # self.connect(gr.file_source(gr.sizeof_gr_complex * fft_length, "symbols_src.dat"), (self.ofdm_frame_acq, 0)) self.connect(gr.file_source(gr.sizeof_char * fft_length, "timing_src.dat"), (self.ofdm_frame_acq, 1)) ########################### some logging start ############################## # self.connect((self.ofdm_sync,1), gr.delay(gr.sizeof_char, fft_length), gr.file_sink(gr.sizeof_char, "ofdm_sync_pn-peaks_b.dat")) # self.connect((self.sampler, 0), gr.file_sink(gr.sizeof_gr_complex*fft_length, "ofdm_receiver-sampler_c.dat")) # self.connect((self.sampler, 1), gr.file_sink(gr.sizeof_char*fft_length, "ofdm_timing_sampler_c.dat")) ############################ some logging end ############################### self.connect((self.ofdm_frame_acq, 0), (self, 0)) # finished with fine/coarse freq correction, self.connect((self.ofdm_frame_acq, 1), (self, 1)) # frame and symbol timing, and equalization self.connect((self.ofdm_frame_acq, 2), (self, 2)) # equalizer: hestimates # self.connect((self.ofdm_frame_acq,3), (self,3)) # ref sampler above # apurv++ ends # # self.connect(self.ofdm_frame_acq, gr.file_sink(gr.sizeof_gr_complex*occupied_tones, "ofdm_receiver-frame_acq_c.dat")) # self.connect((self.ofdm_frame_acq,1), gr.file_sink(1, "ofdm_receiver-found_corr_b.dat")) # apurv++ log the fine frequency offset corrected symbols # # self.connect((self.ofdm_frame_acq, 1), gr.file_sink(gr.sizeof_char, "ofdm_timing_frame_acq_c.dat")) # self.connect((self.ofdm_frame_acq, 2), gr.file_sink(gr.sizeof_gr_complex*occupied_tones, "ofdm_hestimates_c.dat")) # self.connect(self.fft_demod, gr.file_sink(gr.sizeof_gr_complex*fft_length, "ofdm_receiver-fft_out_c.dat")) # self.connect(self.chan_filt, gr.file_sink(gr.sizeof_gr_complex, "ofdm_receiver-chan_filt_c.dat")) # self.connect(self, gr.file_sink(gr.sizeof_gr_complex, "ofdm_input_c.dat")) # apurv++ end # if logging: self.connect(self.chan_filt, gr.file_sink(gr.sizeof_gr_complex, "ofdm_receiver-chan_filt_c.dat")) self.connect(self.fft_demod, gr.file_sink(gr.sizeof_gr_complex * fft_length, "ofdm_receiver-fft_out_c.dat")) self.connect( self.ofdm_frame_acq, gr.file_sink(gr.sizeof_gr_complex * occupied_tones, "ofdm_receiver-frame_acq_c.dat"), ) self.connect((self.ofdm_frame_acq, 1), gr.file_sink(1, "ofdm_receiver-found_corr_b.dat")) self.connect(self.sampler, gr.file_sink(gr.sizeof_gr_complex * fft_length, "ofdm_receiver-sampler_c.dat")) # self.connect(self.sigmix, gr.file_sink(gr.sizeof_gr_complex, "ofdm_receiver-sigmix_c.dat")) self.connect(self.nco, gr.file_sink(gr.sizeof_gr_complex, "ofdm_receiver-nco_c.dat"))
def run_test(seed, blocksize): tb = gr.top_block() ################################################## # Variables ################################################## M = 2 K = 1 P = 2 h = (1.0 * K) / P L = 3 Q = 4 frac = 0.99 f = trellis.fsm(P, M, L) # CPFSK signals #p = numpy.ones(Q)/(2.0) #q = numpy.cumsum(p)/(1.0*Q) # GMSK signals BT = 0.3 tt = numpy.arange(0, L * Q) / (1.0 * Q) - L / 2.0 #print tt p = (0.5 * scipy.stats.erfc(2 * math.pi * BT * (tt - 0.5) / math.sqrt( math.log(2.0)) / math.sqrt(2.0)) - 0.5 * scipy.stats.erfc( 2 * math.pi * BT * (tt + 0.5) / math.sqrt(math.log(2.0)) / math.sqrt(2.0))) / 2.0 p = p / sum(p) * Q / 2.0 #print p q = numpy.cumsum(p) / Q q = q / q[-1] / 2.0 #print q (f0T, SS, S, F, Sf, Ff, N) = fsm_utils.make_cpm_signals(K, P, M, L, q, frac) #print N #print Ff Ffa = numpy.insert(Ff, Q, numpy.zeros(N), axis=0) #print Ffa MF = numpy.fliplr(numpy.transpose(Ffa)) #print MF E = numpy.sum(numpy.abs(Sf)**2, axis=0) Es = numpy.sum(E) / f.O() #print Es constellation = numpy.reshape(numpy.transpose(Sf), N * f.O()) #print Ff #print Sf #print constellation #print numpy.max(numpy.abs(SS - numpy.dot(Ff , Sf))) EsN0_db = 10.0 N0 = Es * 10.0**(-(1.0 * EsN0_db) / 10.0) #N0 = 0.0 #print N0 head = 4 tail = 4 numpy.random.seed(seed * 666) data = numpy.random.randint(0, M, head + blocksize + tail + 1) #data = numpy.zeros(blocksize+1+head+tail,'int') for i in range(head): data[i] = 0 for i in range(tail + 1): data[-i] = 0 ################################################## # Blocks ################################################## random_source_x_0 = gr.vector_source_b(data.tolist(), False) gr_chunks_to_symbols_xx_0 = gr.chunks_to_symbols_bf((-1, 1), 1) gr_interp_fir_filter_xxx_0 = gr.interp_fir_filter_fff(Q, p) gr_frequency_modulator_fc_0 = gr.frequency_modulator_fc(2 * math.pi * h * (1.0 / Q)) gr_add_vxx_0 = gr.add_vcc(1) gr_noise_source_x_0 = gr.noise_source_c(gr.GR_GAUSSIAN, (N0 / 2.0)**0.5, -long(seed)) gr_multiply_vxx_0 = gr.multiply_vcc(1) gr_sig_source_x_0 = gr.sig_source_c(Q, gr.GR_COS_WAVE, -f0T, 1, 0) # only works for N=2, do it manually for N>2... gr_fir_filter_xxx_0_0 = gr.fir_filter_ccc(Q, MF[0].conjugate()) gr_fir_filter_xxx_0_0_0 = gr.fir_filter_ccc(Q, MF[1].conjugate()) gr_streams_to_stream_0 = gr.streams_to_stream(gr.sizeof_gr_complex * 1, int(N)) gr_skiphead_0 = gr.skiphead(gr.sizeof_gr_complex * 1, int(N * (1 + 0))) viterbi = trellis.viterbi_combined_cb(f, head + blocksize + tail, 0, -1, int(N), constellation, digital.TRELLIS_EUCLIDEAN) gr_vector_sink_x_0 = gr.vector_sink_b() ################################################## # Connections ################################################## tb.connect((random_source_x_0, 0), (gr_chunks_to_symbols_xx_0, 0)) tb.connect((gr_chunks_to_symbols_xx_0, 0), (gr_interp_fir_filter_xxx_0, 0)) tb.connect((gr_interp_fir_filter_xxx_0, 0), (gr_frequency_modulator_fc_0, 0)) tb.connect((gr_frequency_modulator_fc_0, 0), (gr_add_vxx_0, 0)) tb.connect((gr_noise_source_x_0, 0), (gr_add_vxx_0, 1)) tb.connect((gr_add_vxx_0, 0), (gr_multiply_vxx_0, 0)) tb.connect((gr_sig_source_x_0, 0), (gr_multiply_vxx_0, 1)) tb.connect((gr_multiply_vxx_0, 0), (gr_fir_filter_xxx_0_0, 0)) tb.connect((gr_multiply_vxx_0, 0), (gr_fir_filter_xxx_0_0_0, 0)) tb.connect((gr_fir_filter_xxx_0_0, 0), (gr_streams_to_stream_0, 0)) tb.connect((gr_fir_filter_xxx_0_0_0, 0), (gr_streams_to_stream_0, 1)) tb.connect((gr_streams_to_stream_0, 0), (gr_skiphead_0, 0)) tb.connect((gr_skiphead_0, 0), (viterbi, 0)) tb.connect((viterbi, 0), (gr_vector_sink_x_0, 0)) tb.run() dataest = gr_vector_sink_x_0.data() #print data #print numpy.array(dataest) perr = 0 err = 0 for i in range(blocksize): if data[head + i] != dataest[head + i]: #print i err += 1 if err != 0: perr = 1 return (err, perr)
def __init__(self, frame, panel, vbox, argv): stdgui2.std_top_block.__init__ (self, frame, panel, vbox, argv) parser = OptionParser (option_class=eng_option) parser.add_option("-T", "--tx-subdev-spec", type="subdev", default=None, help="select USRP Tx side A or B") parser.add_option("-f", "--freq", type="eng_float", default=107.2e6, help="set Tx frequency to FREQ [required]", metavar="FREQ") parser.add_option("--wavfile", type="string", default="", help="read input from FILE") (options, args) = parser.parse_args() if len(args) != 0: parser.print_help() sys.exit(1) self.usrp_interp = 200 self.u = usrp.sink_c (0, self.usrp_interp) print "USRP Serial: ", self.u.serial_number() self.dac_rate = self.u.dac_rate() # 128 MS/s self.usrp_rate = self.dac_rate / self.usrp_interp # 640 kS/s self.sw_interp = 5 self.audio_rate = self.usrp_rate / self.sw_interp # 128 kS/s # determine the daughterboard subdevice we're using if options.tx_subdev_spec is None: options.tx_subdev_spec = usrp.pick_tx_subdevice(self.u) self.u.set_mux(usrp.determine_tx_mux_value(self.u, options.tx_subdev_spec)) self.subdev = usrp.selected_subdev(self.u, options.tx_subdev_spec) print "Using d'board: ", self.subdev.side_and_name() # set max Tx gain, tune frequency and enable transmitter self.subdev.set_gain(self.subdev.gain_range()[1]) if self.u.tune(self.subdev.which(), self.subdev, options.freq): print "Tuned to", options.freq/1e6, "MHz" else: sys.exit(1) self.subdev.set_enable(True) # open wav file containing floats in the [-1, 1] range, repeat if options.wavfile is None: print "Please provide a wavfile to transmit! Exiting\n" sys.exit(1) self.src = gr.wavfile_source (options.wavfile, True) nchans = self.src.channels() sample_rate = self.src.sample_rate() bits_per_sample = self.src.bits_per_sample() print nchans, "channels,", sample_rate, "kS/s,", bits_per_sample, "bits/sample" # resample to 128kS/s if sample_rate == 44100: self.resample_left = blks2.rational_resampler_fff(32,11) self.resample_right = blks2.rational_resampler_fff(32,11) elif sample_rate == 48000: self.resample_left == blks2.rational_resampler_fff(8,3) self.resample_right == blks2.rational_resampler_fff(8,3) elif sample_rate == 8000: self.resample_left == blks2.rational_resampler_fff(16,1) self.resample_right == blks2.rational_resampler_fff(16,1) else: print sample_rate, "is an unsupported sample rate" sys.exit(1) self.connect ((self.src, 0), self.resample_left) self.connect ((self.src, 1), self.resample_right) # create L+R (mono) and L-R (stereo) self.audio_lpr = gr.add_ff() self.audio_lmr = gr.sub_ff() self.connect (self.resample_left, (self.audio_lpr, 0)) self.connect (self.resample_left, (self.audio_lmr, 0)) self.connect (self.resample_right, (self.audio_lpr, 1)) self.connect (self.resample_right, (self.audio_lmr, 1)) # low-pass filter for L+R audio_lpr_taps = gr.firdes.low_pass (0.3, # gain self.audio_rate, # sampling rate 15e3, # passband cutoff 2e3, # transition width gr.firdes.WIN_HANN) self.audio_lpr_filter = gr.fir_filter_fff (1, audio_lpr_taps) self.connect (self.audio_lpr, self.audio_lpr_filter) # create pilot tone at 19 kHz self.pilot = gr.sig_source_f(self.audio_rate, # sampling freq gr.GR_SIN_WAVE, # waveform 19e3, # frequency 3e-2) # amplitude # create the L-R signal carrier at 38 kHz, high-pass to remove 0Hz tone self.stereo_carrier = gr.multiply_ff() self.connect (self.pilot, (self.stereo_carrier, 0)) self.connect (self.pilot, (self.stereo_carrier, 1)) stereo_carrier_taps = gr.firdes.high_pass (1, # gain self.audio_rate, # sampling rate 1e4, # cutoff freq 2e3, # transition width gr.firdes.WIN_HANN) self.stereo_carrier_filter = gr.fir_filter_fff(1, stereo_carrier_taps) self.connect (self.stereo_carrier, self.stereo_carrier_filter) # upconvert L-R to 23-53 kHz and band-pass self.mix_stereo = gr.multiply_ff() audio_lmr_taps = gr.firdes.band_pass (3e3, # gain self.audio_rate, # sampling rate 23e3, # low cutoff 53e3, # high cuttof 2e3, # transition width gr.firdes.WIN_HANN) self.audio_lmr_filter = gr.fir_filter_fff (1, audio_lmr_taps) self.connect (self.audio_lmr, (self.mix_stereo, 0)) self.connect (self.stereo_carrier_filter, (self.mix_stereo, 1)) self.connect (self.mix_stereo, self.audio_lmr_filter) # mix L+R, pilot and L-R self.mixer = gr.add_ff() self.connect (self.audio_lpr_filter, (self.mixer, 0)) self.connect (self.pilot, (self.mixer, 1)) self.connect (self.audio_lmr_filter, (self.mixer, 2)) # interpolation & pre-emphasis interp_taps = gr.firdes.low_pass (self.sw_interp, # gain self.audio_rate, # Fs 60e3, # cutoff freq 5e3, # transition width gr.firdes.WIN_HAMMING) self.interpolator = gr.interp_fir_filter_fff (self.sw_interp, interp_taps) self.pre_emph = blks2.fm_preemph(self.usrp_rate, tau=50e-6) self.connect (self.mixer, self.interpolator, self.pre_emph) # fm modulation, gain & TX max_dev = 100e3 k = 2 * math.pi * max_dev / self.usrp_rate # modulator sensitivity self.modulator = gr.frequency_modulator_fc (k) self.gain = gr.multiply_const_cc (1e3) self.connect (self.pre_emph, self.modulator, self.gain, self.u) # plot an FFT to verify we are sending what we want pre_mod = fftsink2.fft_sink_f(panel, title="Before Interpolation", fft_size=512, sample_rate=self.audio_rate, y_per_div=20, ref_level=20) self.connect (self.mixer, pre_mod) vbox.Add (pre_mod.win, 1, wx.EXPAND)
def set_waveform(self, type): self.lock() self.disconnect_all() if type == gr.GR_SIN_WAVE or type == gr.GR_CONST_WAVE: self._src = gr.sig_source_c(self[SAMP_RATE_KEY], # Sample rate type, # Waveform type self[WAVEFORM_FREQ_KEY], # Waveform frequency self[AMPLITUDE_KEY], # Waveform amplitude self[WAVEFORM_OFFSET_KEY]) # Waveform offset elif type == gr.GR_GAUSSIAN or type == gr.GR_UNIFORM: self._src = gr.noise_source_c(type, self[AMPLITUDE_KEY]) elif type == "2tone": self._src1 = gr.sig_source_c(self[SAMP_RATE_KEY], gr.GR_SIN_WAVE, self[WAVEFORM_FREQ_KEY], self[AMPLITUDE_KEY]/2.0, 0) if(self[WAVEFORM2_FREQ_KEY] is None): self[WAVEFORM2_FREQ_KEY] = -self[WAVEFORM_FREQ_KEY] self._src2 = gr.sig_source_c(self[SAMP_RATE_KEY], gr.GR_SIN_WAVE, self[WAVEFORM2_FREQ_KEY], self[AMPLITUDE_KEY]/2.0, 0) self._src = gr.add_cc() self.connect(self._src1,(self._src,0)) self.connect(self._src2,(self._src,1)) elif type == "sweep": # rf freq is center frequency # waveform_freq is total swept width # waveform2_freq is sweep rate # will sweep from (rf_freq-waveform_freq/2) to (rf_freq+waveform_freq/2) if self[WAVEFORM2_FREQ_KEY] is None: self[WAVEFORM2_FREQ_KEY] = 0.1 self._src1 = gr.sig_source_f(self[SAMP_RATE_KEY], gr.GR_TRI_WAVE, self[WAVEFORM2_FREQ_KEY], 1.0, -0.5) self._src2 = gr.frequency_modulator_fc(self[WAVEFORM_FREQ_KEY]*2*math.pi/self[SAMP_RATE_KEY]) self._src = gr.multiply_const_cc(self[AMPLITUDE_KEY]) self.connect(self._src1,self._src2,self._src) else: raise RuntimeError("Unknown waveform type") self.connect(self._src, self._u) self.unlock() if self._verbose: print "Set baseband modulation to:", waveforms[type] if type == gr.GR_SIN_WAVE: print "Modulation frequency: %sHz" % (n2s(self[WAVEFORM_FREQ_KEY]),) print "Initial phase:", self[WAVEFORM_OFFSET_KEY] elif type == "2tone": print "Tone 1: %sHz" % (n2s(self[WAVEFORM_FREQ_KEY]),) print "Tone 2: %sHz" % (n2s(self[WAVEFORM2_FREQ_KEY]),) elif type == "sweep": print "Sweeping across %sHz to %sHz" % (n2s(-self[WAVEFORM_FREQ_KEY]/2.0),n2s(self[WAVEFORM_FREQ_KEY]/2.0)) print "Sweep rate: %sHz" % (n2s(self[WAVEFORM2_FREQ_KEY]),) print "TX amplitude:", self[AMPLITUDE_KEY]
def __init__(self, samples_per_symbol=_def_samples_per_symbol, bits_per_symbol=_def_bits_per_symbol, h_numerator=_def_h_numerator, h_denominator=_def_h_denominator, cpm_type=_def_cpm_type, bt=_def_bt, symbols_per_pulse=_def_symbols_per_pulse, generic_taps=_def_generic_taps, verbose=_def_verbose, log=_def_log): gr.hier_block2.__init__(self, "cpm_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._bits_per_symbol = bits_per_symbol self._h_numerator = h_numerator self._h_denominator = h_denominator self._cpm_type = cpm_type self._bt=bt if cpm_type == 0 or cpm_type == 2 or cpm_type == 3: # CPFSK, RC, Generic self._symbols_per_pulse = symbols_per_pulse elif cpm_type == 1: # GMSK self._symbols_per_pulse = 4 else: raise TypeError, ("cpm_type must be an integer in {0,1,2,3}, is %r" % (cpm_type,)) self._generic_taps=numpy.array(generic_taps) if samples_per_symbol < 2: raise TypeError, ("samples_per_symbol must be >= 2, is %r" % (samples_per_symbol,)) self.nsymbols = 2**bits_per_symbol self.sym_alphabet = numpy.arange(-(self.nsymbols-1),self.nsymbols,2).tolist() self.ntaps = int(self._symbols_per_pulse * samples_per_symbol) sensitivity = 2 * pi * h_numerator / h_denominator / samples_per_symbol # Unpack Bytes into bits_per_symbol groups self.B2s = gr.packed_to_unpacked_bb(bits_per_symbol,gr.GR_MSB_FIRST) # Turn it into symmetric PAM data. self.pam = digital_swig.chunks_to_symbols_bf(self.sym_alphabet,1) # Generate pulse (sum of taps = samples_per_symbol/2) if cpm_type == 0: # CPFSK self.taps= (1.0/self._symbols_per_pulse/2,) * self.ntaps elif cpm_type == 1: # GMSK gaussian_taps = gr.firdes.gaussian( 1.0/2, # gain samples_per_symbol, # symbol_rate bt, # bandwidth * symbol time self.ntaps # number of taps ) sqwave = (1,) * samples_per_symbol # rectangular window self.taps = numpy.convolve(numpy.array(gaussian_taps),numpy.array(sqwave)) elif cpm_type == 2: # Raised Cosine # generalize it for arbitrary roll-off factor self.taps = (1-numpy.cos(2*pi*numpy.arange(0,self.ntaps)/samples_per_symbol/self._symbols_per_pulse))/(2*self._symbols_per_pulse) elif cpm_type == 3: # Generic CPM self.taps = generic_taps else: raise TypeError, ("cpm_type must be an integer in {0,1,2,3}, is %r" % (cpm_type,)) self.filter = filter.pfb.arb_resampler_fff(samples_per_symbol, self.taps) # FM modulation self.fmmod = gr.frequency_modulator_fc(sensitivity) if verbose: self._print_verbage() if log: self._setup_logging() # Connect self.connect(self, self.B2s, self.pam, self.filter, self.fmmod, self)
def __init__(self): grc_wxgui.top_block_gui.__init__(self, title="Fm Stereo Tx") ################################################## # Variables ################################################## self.st_gain = st_gain = 10 self.samp_rate = samp_rate = 195.312e3 self.pilot_gain = pilot_gain = 80e-3 self.mpx_rate = mpx_rate = 160e3 self.Mono_gain = Mono_gain = 300e-3 self.FM_freq = FM_freq = 96.5e6 ################################################## # Blocks ################################################## _st_gain_sizer = wx.BoxSizer(wx.VERTICAL) self._st_gain_text_box = forms.text_box( parent=self.GetWin(), sizer=_st_gain_sizer, value=self.st_gain, callback=self.set_st_gain, label='st_gain', converter=forms.float_converter(), proportion=0, ) self._st_gain_slider = forms.slider( parent=self.GetWin(), sizer=_st_gain_sizer, value=self.st_gain, callback=self.set_st_gain, minimum=0, maximum=100, num_steps=100, style=wx.SL_HORIZONTAL, cast=float, proportion=1, ) self.Add(_st_gain_sizer) _pilot_gain_sizer = wx.BoxSizer(wx.VERTICAL) self._pilot_gain_text_box = forms.text_box( parent=self.GetWin(), sizer=_pilot_gain_sizer, value=self.pilot_gain, callback=self.set_pilot_gain, label='pilot_gain', converter=forms.float_converter(), proportion=0, ) self._pilot_gain_slider = forms.slider( parent=self.GetWin(), sizer=_pilot_gain_sizer, value=self.pilot_gain, callback=self.set_pilot_gain, minimum=0, maximum=1, num_steps=100, style=wx.SL_HORIZONTAL, cast=float, proportion=1, ) self.Add(_pilot_gain_sizer) self.notebook_0 = self.notebook_0 = wx.Notebook(self.GetWin(), style=wx.NB_TOP) self.notebook_0.AddPage(grc_wxgui.Panel(self.notebook_0), "FM") self.notebook_0.AddPage(grc_wxgui.Panel(self.notebook_0), "audio") self.Add(self.notebook_0) _Mono_gain_sizer = wx.BoxSizer(wx.VERTICAL) self._Mono_gain_text_box = forms.text_box( parent=self.GetWin(), sizer=_Mono_gain_sizer, value=self.Mono_gain, callback=self.set_Mono_gain, label='Mono_gain', converter=forms.float_converter(), proportion=0, ) self._Mono_gain_slider = forms.slider( parent=self.GetWin(), sizer=_Mono_gain_sizer, value=self.Mono_gain, callback=self.set_Mono_gain, minimum=0, maximum=1, num_steps=100, style=wx.SL_HORIZONTAL, cast=float, proportion=1, ) self.Add(_Mono_gain_sizer) _FM_freq_sizer = wx.BoxSizer(wx.VERTICAL) self._FM_freq_text_box = forms.text_box( parent=self.GetWin(), sizer=_FM_freq_sizer, value=self.FM_freq, callback=self.set_FM_freq, label='FM_freq', converter=forms.float_converter(), proportion=0, ) self._FM_freq_slider = forms.slider( parent=self.GetWin(), sizer=_FM_freq_sizer, value=self.FM_freq, callback=self.set_FM_freq, minimum=88e6, maximum=108e6, num_steps=100, style=wx.SL_HORIZONTAL, cast=float, proportion=1, ) self.Add(_FM_freq_sizer) self.wxgui_fftsink2_1 = fftsink2.fft_sink_f( self.notebook_0.GetPage(1).GetWin(), baseband_freq=0, y_per_div=10, y_divs=10, ref_level=0, ref_scale=2.0, sample_rate=samp_rate, fft_size=1024, fft_rate=15, average=False, avg_alpha=None, title="FFT Plot", peak_hold=False, ) self.notebook_0.GetPage(1).Add(self.wxgui_fftsink2_1.win) self.wxgui_fftsink2_0 = fftsink2.fft_sink_c( self.notebook_0.GetPage(0).GetWin(), baseband_freq=FM_freq, y_per_div=10, y_divs=10, ref_level=0, ref_scale=2.0, sample_rate=samp_rate, fft_size=1024, fft_rate=15, average=False, avg_alpha=None, title="FFT Plot", peak_hold=False, ) self.notebook_0.GetPage(0).Add(self.wxgui_fftsink2_0.win) self.uhd_usrp_sink_0 = uhd.usrp_sink( device_addr="addr=192.168.10.2", stream_args=uhd.stream_args( cpu_format="fc32", channels=range(1), ), ) self.uhd_usrp_sink_0.set_samp_rate(samp_rate) self.uhd_usrp_sink_0.set_center_freq(FM_freq, 0) self.uhd_usrp_sink_0.set_gain(0, 0) self.uhd_usrp_sink_0.set_antenna("TX/RX", 0) self.low_pass_filter_0 = gr.fir_filter_fff(1, firdes.low_pass( Mono_gain, mpx_rate, 15000, 2000, firdes.WIN_HAMMING, 6.76)) self.gr_vector_to_streams_0 = gr.vector_to_streams(gr.sizeof_short*1, 2) self.gr_sub_xx_0 = gr.sub_ff(1) self.gr_sig_source_x_1 = gr.sig_source_f(160000, gr.GR_SIN_WAVE, 19000, pilot_gain, 0) self.gr_sig_source_x_0 = gr.sig_source_f(160000, gr.GR_SIN_WAVE, 38000, 30e-3, 0) self.gr_short_to_float_1 = gr.short_to_float(1, 1) self.gr_short_to_float_0 = gr.short_to_float(1, 1) self.gr_multiply_xx_0 = gr.multiply_vff(1) self.gr_multiply_const_vxx_2 = gr.multiply_const_vcc((32.768e3, )) self.gr_multiply_const_vxx_1 = gr.multiply_const_vff((30e-6, )) self.gr_multiply_const_vxx_0 = gr.multiply_const_vff((30e-6, )) self.gr_frequency_modulator_fc_0 = gr.frequency_modulator_fc(980e-3) self.gr_file_source_0 = gr.file_source(gr.sizeof_short*2, "/home/kranthi/Documents/project/FM Transceiver/FM Transmitter/test.raw", True) self.gr_add_xx_1 = gr.add_vff(1) self.gr_add_xx_0 = gr.add_vff(1) self.blks2_rational_resampler_xxx_2 = blks2.rational_resampler_fff( interpolation=4, decimation=1, taps=None, fractional_bw=None, ) self.blks2_rational_resampler_xxx_1 = blks2.rational_resampler_fff( interpolation=5, decimation=1, taps=None, fractional_bw=None, ) self.blks2_rational_resampler_xxx_0 = blks2.rational_resampler_fff( interpolation=5, decimation=1, taps=None, fractional_bw=None, ) self.blks2_fm_preemph_0 = blks2.fm_preemph(fs=mpx_rate, tau=50e-6) self.band_pass_filter_0 = gr.fir_filter_fff(1, firdes.band_pass( st_gain, mpx_rate, 23000, 53000, 2000, firdes.WIN_HAMMING, 6.76)) ################################################## # Connections ################################################## self.connect((self.gr_file_source_0, 0), (self.gr_vector_to_streams_0, 0)) self.connect((self.gr_vector_to_streams_0, 0), (self.gr_short_to_float_0, 0)) self.connect((self.gr_vector_to_streams_0, 1), (self.gr_short_to_float_1, 0)) self.connect((self.gr_short_to_float_0, 0), (self.gr_multiply_const_vxx_0, 0)) self.connect((self.gr_short_to_float_1, 0), (self.gr_multiply_const_vxx_1, 0)) self.connect((self.gr_multiply_const_vxx_0, 0), (self.blks2_rational_resampler_xxx_0, 0)) self.connect((self.gr_multiply_const_vxx_1, 0), (self.blks2_rational_resampler_xxx_1, 0)) self.connect((self.blks2_rational_resampler_xxx_0, 0), (self.gr_add_xx_0, 1)) self.connect((self.blks2_rational_resampler_xxx_0, 0), (self.gr_sub_xx_0, 1)) self.connect((self.blks2_rational_resampler_xxx_1, 0), (self.gr_sub_xx_0, 0)) self.connect((self.blks2_rational_resampler_xxx_1, 0), (self.gr_add_xx_0, 0)) self.connect((self.gr_add_xx_0, 0), (self.low_pass_filter_0, 0)) self.connect((self.gr_sig_source_x_0, 0), (self.gr_multiply_xx_0, 0)) self.connect((self.gr_sub_xx_0, 0), (self.gr_multiply_xx_0, 1)) self.connect((self.gr_multiply_xx_0, 0), (self.band_pass_filter_0, 0)) self.connect((self.gr_sig_source_x_1, 0), (self.gr_add_xx_1, 0)) self.connect((self.band_pass_filter_0, 0), (self.gr_add_xx_1, 1)) self.connect((self.low_pass_filter_0, 0), (self.gr_add_xx_1, 2)) self.connect((self.gr_add_xx_1, 0), (self.blks2_fm_preemph_0, 0)) self.connect((self.blks2_fm_preemph_0, 0), (self.blks2_rational_resampler_xxx_2, 0)) self.connect((self.blks2_rational_resampler_xxx_2, 0), (self.gr_frequency_modulator_fc_0, 0)) self.connect((self.gr_frequency_modulator_fc_0, 0), (self.gr_multiply_const_vxx_2, 0)) self.connect((self.gr_multiply_const_vxx_2, 0), (self.uhd_usrp_sink_0, 0)) self.connect((self.gr_multiply_const_vxx_2, 0), (self.wxgui_fftsink2_0, 0)) self.connect((self.gr_multiply_const_vxx_1, 0), (self.wxgui_fftsink2_1, 0))
def __init__(self, mode, debug=False): """ OFDM time and coarse frequency synchronisation for DAB @param mode DAB mode (1-4) @param debug if True: write data streams out to files """ if mode < 1 or mode > 4: raise ValueError, "Invalid DAB mode: " + str( mode) + " (modes 1-4 exist)" # get the correct DAB parameters dp = parameters.dab_parameters(mode) rp = parameters.receiver_parameters(mode) gr.hier_block2.__init__( self, "ofdm_sync_dab", gr.io_signature(1, 1, gr.sizeof_gr_complex), # input signature gr.io_signature2(2, 2, gr.sizeof_gr_complex, gr.sizeof_char)) # output signature # workaround for a problem that prevents connecting more than one block directly (see trac ticket #161) self.input = gr.kludge_copy(gr.sizeof_gr_complex) self.connect(self, self.input) # # null-symbol detection # # (outsourced to detect_zero.py) self.ns_detect = detect_null.detect_null(dp.ns_length, debug) self.connect(self.input, self.ns_detect) # # fine frequency synchronisation # # the code for fine frequency synchronisation is adapted from # ofdm_sync_ml.py; it abuses the cyclic prefix to find the fine # frequency error, as suggested in "ML Estimation of Timing and # Frequency Offset in OFDM Systems", by Jan-Jaap van de Beek, # Magnus Sandell, Per Ola Börjesson, see # http://www.sm.luth.se/csee/sp/research/report/bsb96r.html self.ffs_delay = gr.delay(gr.sizeof_gr_complex, dp.fft_length) self.ffs_conj = gr.conjugate_cc() self.ffs_mult = gr.multiply_cc() # self.ffs_moving_sum = gr.fir_filter_ccf(1, [1]*dp.cp_length) self.ffs_moving_sum = dab_swig.moving_sum_cc(dp.cp_length) self.ffs_angle = gr.complex_to_arg() self.ffs_angle_scale = gr.multiply_const_ff(1. / dp.fft_length) self.ffs_delay_sample_and_hold = gr.delay( gr.sizeof_char, dp.symbol_length) # sample the value at the end of the symbol .. self.ffs_sample_and_hold = gr.sample_and_hold_ff() self.ffs_delay_input_for_correction = gr.delay( gr.sizeof_gr_complex, dp.symbol_length ) # by delaying the input, we can use the ff offset estimation from the first symbol to correct the first symbol itself self.ffs_nco = gr.frequency_modulator_fc( 1) # ffs_sample_and_hold directly outputs phase error per sample self.ffs_mixer = gr.multiply_cc() # calculate fine frequency error self.connect(self.input, self.ffs_conj, self.ffs_mult) self.connect(self.input, self.ffs_delay, (self.ffs_mult, 1)) self.connect(self.ffs_mult, self.ffs_moving_sum, self.ffs_angle) # only use the value from the first half of the first symbol self.connect(self.ffs_angle, self.ffs_angle_scale, (self.ffs_sample_and_hold, 0)) self.connect(self.ns_detect, self.ffs_delay_sample_and_hold, (self.ffs_sample_and_hold, 1)) # do the correction self.connect(self.ffs_sample_and_hold, self.ffs_nco, (self.ffs_mixer, 0)) self.connect(self.input, self.ffs_delay_input_for_correction, (self.ffs_mixer, 1)) # output - corrected signal and start of DAB frames self.connect(self.ffs_mixer, (self, 0)) self.connect(self.ffs_delay_sample_and_hold, (self, 1)) if debug: self.connect( self.ffs_angle, gr.file_sink(gr.sizeof_float, "debug/ofdm_sync_dab_ffs_angle.dat")) self.connect( self.ffs_sample_and_hold, gr.multiply_const_ff(1. / (dp.T * 2 * pi)), gr.file_sink(gr.sizeof_float, "debug/ofdm_sync_dab_fine_freq_err_f.dat")) self.connect( self.ffs_mixer, gr.file_sink(gr.sizeof_gr_complex, "debug/ofdm_sync_dab_fine_freq_corrected_c.dat"))
def __init__( self, fft_length, cp_length, occupied_tones, snr, ks, threshold, options, logging=False ): # apurv++: added num_symbols, use_chan_filt """ Hierarchical block for receiving OFDM symbols. The input is the complex modulated signal at baseband. Synchronized packets are sent back to the demodulator. @param params: Raw OFDM parameters @type params: ofdm_params @param logging: turn file logging on or off @type logging: bool """ gr.hier_block2.__init__( self, "ofdm_receiver", gr.io_signature(1, 1, gr.sizeof_gr_complex), # Input signature gr.io_signature3( 3, 3, gr.sizeof_gr_complex * occupied_tones, gr.sizeof_char, gr.sizeof_gr_complex * occupied_tones ), ) # Output signature # low-pass filter the input channel bw = (float(occupied_tones) / float(fft_length)) / 2.0 tb = bw * 0.08 lpf_coeffs = gr.firdes.low_pass( 1.0, # gain 1.0, # sampling rate bw + tb, # midpoint of trans. band tb, # width of trans. band gr.firdes.WIN_HAMMING, ) # filter type self.chan_filt = gr.fft_filter_ccc(1, lpf_coeffs) self.connect(self, self.chan_filt) self.connect(self.chan_filt, gr.file_sink(gr.sizeof_gr_complex, "rx-filt.dat")) zeros_on_left = int(math.ceil((fft_length - occupied_tones) / 2.0)) ks0 = fft_length * [0] ks0[zeros_on_left : zeros_on_left + occupied_tones] = ks[0] ks0 = fft.ifftshift(ks0) ks0time = fft.ifft(ks0) ks0time = ks0time.tolist() ks1 = fft_length * [0] ks1[zeros_on_left : zeros_on_left + occupied_tones] = ks[1] ks1 = fft.ifftshift(ks1) ks1time = fft.ifft(ks1) ks1time = ks1time.tolist() # sync = ofdm_sync_pn(fft_length, cp_length, True, logging) # raw sync = ofdm_sync_pn(fft_length, cp_length, True, ks0time, ks1time, threshold, logging) # crosscorr version use_chan_filt = 1 if use_chan_filt == 0: self.connect(gr.file_source(gr.sizeof_gr_complex, "chan-filt.dat"), sync) else: self.connect(self.chan_filt, sync) # correct for fine frequency offset computed in sync (up to +-pi/fft_length) nco_sensitivity = 2.0 / fft_length nco = gr.frequency_modulator_fc(nco_sensitivity) sigmix = gr.multiply_cc() # sample at symbol boundaries # NOTE: (sync,2) indicates the first sample of the symbol! sampler = digital_swig.ofdm_sampler(fft_length, fft_length + cp_length, len(ks) + 1, timeout=100) # apurv-- # frequency offset correction # self.connect((sync, 0), (sigmix, 0)) self.connect((sync, 1), nco, (sigmix, 1)) self.connect(sigmix, (sampler, 0)) self.connect((sync, 2), (sampler, 1)) """ self.connect((sync,0), (sampler,0)) self.connect((sync,2), (sampler,1)) # timing signal to sample at self.connect((sync,1), gr.file_sink(gr.sizeof_float, "offset.dat")) """ self.connect((sampler, 1), gr.file_sink(gr.sizeof_char, "sampler_timing.dat")) # self.connect((sampler, 2), gr.file_sink(gr.sizeof_char*fft_length, "sampler_timing_fft.dat")) # fft on the symbols win = [1 for i in range(fft_length)] # see gr_fft_vcc_fftw that it works differently if win = [] fft1 = gr.fft_vcc(fft_length, True, win, True) self.connect((sampler, 0), fft1) # use the preamble to correct the coarse frequency offset and initial equalizer ###frame_acq = raw.ofdm_frame_acquisition(fft_length, cp_length, preambles_raw, carriers) frame_acq = digital_swig.ofdm_frame_acquisition(occupied_tones, fft_length, cp_length, ks) self.frame_acq = frame_acq # normal operation # self.connect((fft1, 0), gr.file_sink(gr.sizeof_gr_complex * options.fft_length, "fft-out.dat")) self.connect((sampler, 1), gr.file_sink(gr.sizeof_char, "sampler_timing.dat")) self.connect(fft1, (frame_acq, 0)) self.connect((sampler, 1), (frame_acq, 1)) """ # enable to have manual input to frame_acq # self.connect(fft1, gr.null_sink(gr.sizeof_gr_complex*options.fft_length)) self.connect(gr.file_source(gr.sizeof_gr_complex*options.fft_length, "combined.dat"), (frame_acq,0)) self.connect(gr.file_source(gr.sizeof_char, "combined_t.dat"), (frame_acq,1)) """ # self.connect(fft, gr.null_sink(gr.sizeof_gr_complex*options.fft_length)) # self.connect((sampler, 1), gr.null_sink(gr.sizeof_char)) # self.connect(gr.file_source(gr.sizeof_gr_complex*options.fft_length, "symbols_src.dat"), (frame_acq, 0)) # self.connect(gr.file_source(gr.sizeof_char, "timing.dat"), (frame_acq, 1)) self.connect((frame_acq, 0), (self, 0)) # finished with fine/coarse freq correction self.connect((frame_acq, 1), (self, 1)) # frame and symbol timing self.connect((frame_acq, 2), (self, 2)) # hestimates self.connect((frame_acq, 0), gr.file_sink(gr.sizeof_gr_complex * occupied_tones, "rx-acq.dat")) self.connect((frame_acq, 1), gr.file_sink(gr.sizeof_char, "timing-acq.dat")) if logging: self.connect(self.chan_filt, gr.file_sink(gr.sizeof_gr_complex, "rx-filt.dat")) self.connect(fft1, gr.file_sink(gr.sizeof_gr_complex * fft_length, "rx-fft.dat")) self.connect((frame_acq, 0), gr.file_sink(gr.sizeof_gr_complex * occupied_tones, "rx-acq.dat")) self.connect((frame_acq, 1), gr.file_sink(1, "rx-detect.datb")) self.connect(sampler, gr.file_sink(gr.sizeof_gr_complex * fft_length, "rx-sampler.dat")) self.connect(sigmix, gr.file_sink(gr.sizeof_gr_complex, "rx-sigmix.dat")) self.connect(nco, gr.file_sink(gr.sizeof_gr_complex, "rx-nco.dat"))
def __init__(self): grc_wxgui.top_block_gui.__init__(self, title="Rds Tx") _icon_path = "/home/azimout/.local/share/icons/hicolor/32x32/apps/gnuradio-grc.png" self.SetIcon(wx.Icon(_icon_path, wx.BITMAP_TYPE_ANY)) ################################################## # Variables ################################################## self.usrp_interp = usrp_interp = 500 self.dac_rate = dac_rate = 128e6 self.wav_rate = wav_rate = 44100 self.usrp_rate = usrp_rate = int(dac_rate/usrp_interp) self.fm_max_dev = fm_max_dev = 120e3 ################################################## # Blocks ################################################## self.band_pass_filter_0 = gr.interp_fir_filter_fff(1, firdes.band_pass( 1, usrp_rate, 54e3, 60e3, 3e3, firdes.WIN_HAMMING, 6.76)) self.band_pass_filter_1 = gr.interp_fir_filter_fff(1, firdes.band_pass( 1, usrp_rate, 23e3, 53e3, 2e3, firdes.WIN_HAMMING, 6.76)) self.blks2_rational_resampler_xxx_1 = blks2.rational_resampler_fff( interpolation=usrp_rate, decimation=wav_rate, taps=None, fractional_bw=None, ) self.blks2_rational_resampler_xxx_1_0 = blks2.rational_resampler_fff( interpolation=usrp_rate, decimation=wav_rate, taps=None, fractional_bw=None, ) self.gr_add_xx_0 = gr.add_vff(1) self.gr_add_xx_1 = gr.add_vff(1) self.gr_char_to_float_0 = gr.char_to_float() self.gr_diff_encoder_bb_0 = gr.diff_encoder_bb(2) self.gr_frequency_modulator_fc_0 = gr.frequency_modulator_fc(2*math.pi*fm_max_dev/usrp_rate) self.gr_map_bb_0 = gr.map_bb(([-1,1])) self.gr_map_bb_1 = gr.map_bb(([1,2])) self.gr_multiply_xx_0 = gr.multiply_vff(1) self.gr_multiply_xx_1 = gr.multiply_vff(1) self.gr_rds_data_encoder_0 = rds.data_encoder("/media/dimitris/mywork/gr/dimitris/rds/trunk/src/test/rds_data.xml") self.gr_rds_rate_enforcer_0 = rds.rate_enforcer(256000) self.gr_sig_source_x_0 = gr.sig_source_f(usrp_rate, gr.GR_COS_WAVE, 19e3, 0.3, 0) self.gr_sub_xx_0 = gr.sub_ff(1) self.gr_unpack_k_bits_bb_0 = gr.unpack_k_bits_bb(2) self.gr_wavfile_source_0 = gr.wavfile_source("/media/dimitris/mywork/gr/dimitris/rds/trunk/src/python/limmenso_stereo.wav", True) self.low_pass_filter_0 = gr.interp_fir_filter_fff(1, firdes.low_pass( 1, usrp_rate, 1.5e3, 2e3, firdes.WIN_HAMMING, 6.76)) self.low_pass_filter_0_0 = gr.interp_fir_filter_fff(1, firdes.low_pass( 1, usrp_rate, 15e3, 2e3, firdes.WIN_HAMMING, 6.76)) self.usrp_simple_sink_x_0 = grc_usrp.simple_sink_c(which=0, side="A") self.usrp_simple_sink_x_0.set_interp_rate(500) self.usrp_simple_sink_x_0.set_frequency(107.2e6, verbose=True) self.usrp_simple_sink_x_0.set_gain(0) self.usrp_simple_sink_x_0.set_enable(True) self.usrp_simple_sink_x_0.set_auto_tr(True) self.wxgui_fftsink2_0 = fftsink2.fft_sink_f( self.GetWin(), baseband_freq=0, y_per_div=20, y_divs=10, ref_level=0, ref_scale=2.0, sample_rate=usrp_rate, fft_size=1024, fft_rate=30, average=False, avg_alpha=None, title="FFT Plot", peak_hold=False, ) self.Add(self.wxgui_fftsink2_0.win) ################################################## # Connections ################################################## self.connect((self.gr_sig_source_x_0, 0), (self.gr_rds_rate_enforcer_0, 1)) self.connect((self.gr_char_to_float_0, 0), (self.gr_rds_rate_enforcer_0, 0)) self.connect((self.gr_map_bb_0, 0), (self.gr_char_to_float_0, 0)) self.connect((self.gr_frequency_modulator_fc_0, 0), (self.usrp_simple_sink_x_0, 0)) self.connect((self.gr_add_xx_1, 0), (self.gr_frequency_modulator_fc_0, 0)) self.connect((self.gr_sig_source_x_0, 0), (self.gr_add_xx_1, 1)) self.connect((self.gr_sub_xx_0, 0), (self.gr_multiply_xx_1, 2)) self.connect((self.gr_sig_source_x_0, 0), (self.gr_multiply_xx_1, 1)) self.connect((self.gr_sig_source_x_0, 0), (self.gr_multiply_xx_1, 0)) self.connect((self.gr_sig_source_x_0, 0), (self.gr_multiply_xx_0, 3)) self.connect((self.gr_sig_source_x_0, 0), (self.gr_multiply_xx_0, 2)) self.connect((self.blks2_rational_resampler_xxx_1_0, 0), (self.gr_add_xx_0, 1)) self.connect((self.blks2_rational_resampler_xxx_1, 0), (self.gr_add_xx_0, 0)) self.connect((self.blks2_rational_resampler_xxx_1_0, 0), (self.gr_sub_xx_0, 1)) self.connect((self.blks2_rational_resampler_xxx_1, 0), (self.gr_sub_xx_0, 0)) self.connect((self.gr_wavfile_source_0, 1), (self.blks2_rational_resampler_xxx_1_0, 0)) self.connect((self.gr_wavfile_source_0, 0), (self.blks2_rational_resampler_xxx_1, 0)) self.connect((self.gr_rds_data_encoder_0, 0), (self.gr_diff_encoder_bb_0, 0)) self.connect((self.gr_diff_encoder_bb_0, 0), (self.gr_map_bb_1, 0)) self.connect((self.gr_map_bb_1, 0), (self.gr_unpack_k_bits_bb_0, 0)) self.connect((self.gr_unpack_k_bits_bb_0, 0), (self.gr_map_bb_0, 0)) self.connect((self.gr_rds_rate_enforcer_0, 0), (self.low_pass_filter_0, 0)) self.connect((self.low_pass_filter_0, 0), (self.gr_multiply_xx_0, 0)) self.connect((self.gr_multiply_xx_0, 0), (self.band_pass_filter_0, 0)) self.connect((self.band_pass_filter_0, 0), (self.gr_add_xx_1, 0)) self.connect((self.gr_multiply_xx_1, 0), (self.band_pass_filter_1, 0)) self.connect((self.band_pass_filter_1, 0), (self.gr_add_xx_1, 3)) self.connect((self.gr_add_xx_1, 0), (self.wxgui_fftsink2_0, 0)) self.connect((self.gr_sig_source_x_0, 0), (self.gr_multiply_xx_0, 1)) self.connect((self.gr_add_xx_0, 0), (self.low_pass_filter_0_0, 0)) self.connect((self.low_pass_filter_0_0, 0), (self.gr_add_xx_1, 2))
def __init__(self, p, logging=False): """ Hierarchical block for receiving OFDM symbols. The input is the complex modulated signal at baseband. Synchronized packets are sent back to the demodulator. @param params: Raw OFDM parameters @type params: ofdm_params @param logging: turn file logging on or off @type logging: bool """ from numpy import fft gr.hier_block2.__init__( self, "ofdm_receiver", gr.io_signature(1, 1, gr.sizeof_gr_complex), # Input signature gr.io_signature2(2, 2, gr.sizeof_gr_complex * p.occupied_tones, gr.sizeof_char)) # Output signature # low-pass filter the input channel bw = (float(p.occupied_tones) / float(p.fft_length)) / 2.0 tb = bw * 0.08 lpf_coeffs = gr.firdes.low_pass( 1.0, # gain 1.0, # sampling rate bw + tb, # midpoint of trans. band tb, # width of trans. band gr.firdes.WIN_HAMMING) # filter type lpf = gr.fft_filter_ccc(1, lpf_coeffs) #lpf = gr.add_const_cc(0.0) ## no-op low-pass-filter self.connect(self, lpf) # to the synchronization algorithm #from gnuradio import blks2impl #from gnuradio.blks2impl.ofdm_sync_pn import ofdm_sync_pn sync = ofdm_sync(p.fft_length, p.cp_length, p.half_sync, logging) self.connect(lpf, sync) # correct for fine frequency offset computed in sync (up to +-pi/fft_length) # NOTE: frame_acquisition can correct coarse freq offset (i.e. kpi/fft_length) if p.half_sync: nco_sensitivity = 2.0 / p.fft_length else: nco_sensitivity = 1.0 / (p.fft_length + p.cp_length) #nco_sensitivity = 0 nco = gr.frequency_modulator_fc(nco_sensitivity) sigmix = gr.multiply_cc() self.connect((sync, 0), (sigmix, 0)) self.connect((sync, 1), nco, (sigmix, 1)) # sample at symbol boundaries # NOTE: (sync,2) indicates the first sample of the symbol! sampler = raw.ofdm_sampler(p.fft_length, p.fft_length + p.cp_length, timeout=100) self.connect(sigmix, (sampler, 0)) self.connect((sync, 2), (sampler, 1)) # timing signal to sample at # fft on the symbols win = [1 for i in range(p.fft_length)] # see gr_fft_vcc_fftw that it works differently if win = [] fft = gr.fft_vcc(p.fft_length, True, win, True) self.connect((sampler, 0), fft) # use the preamble to correct the coarse frequency offset and initial equalizer frame_acq = raw.ofdm_frame_acquisition(p.fft_length, p.cp_length, p.preambles) self.frame_acq = frame_acq self.connect(fft, (frame_acq, 0)) self.connect((sampler, 1), (frame_acq, 1)) self.connect((frame_acq, 0), (self, 0)) # finished with fine/coarse freq correction self.connect((frame_acq, 1), (self, 1)) # frame and symbol timing if logging: self.connect(lpf, gr.file_sink(gr.sizeof_gr_complex, "rx-filt.dat")) self.connect( fft, gr.file_sink(gr.sizeof_gr_complex * p.fft_length, "rx-fft.dat")) self.connect((frame_acq, 0), gr.file_sink(gr.sizeof_gr_complex * p.occupied_tones, "rx-acq.dat")) self.connect((frame_acq, 1), gr.file_sink(1, "rx-detect.datb")) self.connect( sampler, gr.file_sink(gr.sizeof_gr_complex * p.fft_length, "rx-sampler.dat")) self.connect(sigmix, gr.file_sink(gr.sizeof_gr_complex, "rx-sigmix.dat")) self.connect(nco, gr.file_sink(gr.sizeof_gr_complex, "rx-nco.dat"))
def __init__(self, bandwidth, fft_length, cp_length, occupied_tones, snr, ks, logging=False, mode='benchmark'): """ Hierarchical block for receiving OFDM symbols. The input is the complex modulated signal at baseband. Synchronized packets are sent back to the demodulator. @param fft_length: total number of subcarriers @type fft_length: int @param cp_length: length of cyclic prefix as specified in subcarriers (<= fft_length) @type cp_length: int @param occupied_tones: number of subcarriers used for data @type occupied_tones: int @param snr: estimated signal to noise ratio used to guide cyclic prefix synchronizer @type snr: float @param ks: known symbols used as preambles to each packet @type ks: list of lists @param logging: turn file logging on or off @type logging: bool """ gr.hier_block2.__init__(self, "ofdm_receiver", gr.io_signature(1, 1, gr.sizeof_gr_complex), # Input signature gr.io_signature2(2, 2, gr.sizeof_gr_complex*occupied_tones, gr.sizeof_char)) # Output signature bw = (float(occupied_tones) / float(fft_length)) / 2.0 tb = bw*0.08 chan_coeffs = gr.firdes.low_pass (1.0, # gain 1.0, # sampling rate bw+tb, # midpoint of trans. band tb, # width of trans. band gr.firdes.WIN_HAMMING) # filter type self.chan_filt = gr.fft_filter_ccc(1, chan_coeffs) win = [1 for i in range(fft_length)] zeros_on_left = int(math.ceil((fft_length - occupied_tones)/2.0)) ks0 = fft_length*[0,] ks0[zeros_on_left : zeros_on_left + occupied_tones] = ks[0] ks0 = fft.ifftshift(ks0) ks0time = fft.ifft(ks0) # ADD SCALING FACTOR ks0time = ks0time.tolist() SYNC = "pn" if SYNC == "ml": nco_sensitivity = -1.0/fft_length # correct for fine frequency self.ofdm_sync = ofdm_sync_ml(fft_length, cp_length, snr, ks0time, logging) elif SYNC == "pn": nco_sensitivity = -2.0/fft_length # correct for fine frequency self.ofdm_sync = ofdm_sync_pn(fft_length, cp_length, logging, mode) elif SYNC == "pnac": nco_sensitivity = -2.0/fft_length # correct for fine frequency self.ofdm_sync = ofdm_sync_pnac(fft_length, cp_length, ks0time, logging) # for testing only; do not user over the air # remove filter and filter delay for this elif SYNC == "fixed": self.chan_filt = gr.multiply_const_cc(1.0) nsymbols = 18 # enter the number of symbols per packet freq_offset = 0.0 # if you use a frequency offset, enter it here nco_sensitivity = -2.0/fft_length # correct for fine frequency self.ofdm_sync = ofdm_sync_fixed(fft_length, cp_length, nsymbols, freq_offset, logging) # Set up blocks self.nco = gr.frequency_modulator_fc(nco_sensitivity) # generate a signal proportional to frequency error of sync block self.sigmix = gr.multiply_cc() self.sampler = digital_swig.ofdm_sampler(fft_length, fft_length+cp_length, long(bandwidth)) self.fft_demod = gr.fft_vcc(fft_length, True, win, True) self.ofdm_frame_acq = digital_swig.ofdm_frame_acquisition(occupied_tones, fft_length, cp_length, ks[0]) self.connect(self, self.chan_filt) # filter the input channel self.connect(self.chan_filt, self.ofdm_sync) # into the synchronization alg. self.connect((self.ofdm_sync,0), self.nco, (self.sigmix,1)) # use sync freq. offset output to derotate input signal self.connect(self.chan_filt, (self.sigmix,0)) # signal to be derotated self.connect(self.sigmix, (self.sampler,0)) # sample off timing signal detected in sync alg self.connect((self.ofdm_sync,1), (self.sampler,1)) # timing signal to sample at self.connect((self.sampler,0), self.fft_demod) # send derotated sampled signal to FFT self.connect(self.fft_demod, (self.ofdm_frame_acq,0)) # find frame start and equalize signal self.connect((self.sampler,1), (self.ofdm_frame_acq,1)) # send timing signal to signal frame start self.connect((self.ofdm_frame_acq,0), (self,0)) # finished with fine/coarse freq correction, self.connect((self.ofdm_frame_acq,1), (self,1)) # frame and symbol timing, and equalization # for debugging self.connect(self.chan_filt, gr.file_sink(gr.sizeof_gr_complex, "ofdm_receiver-chan_filt_c.dat")) if logging: self.connect(self.chan_filt, gr.file_sink(gr.sizeof_gr_complex, "ofdm_receiver-chan_filt_c.dat")) self.connect(self.fft_demod, gr.file_sink(gr.sizeof_gr_complex*fft_length, "ofdm_receiver-fft_out_c.dat")) self.connect(self.ofdm_frame_acq, gr.file_sink(gr.sizeof_gr_complex*occupied_tones, "ofdm_receiver-frame_acq_c.dat")) self.connect((self.ofdm_frame_acq,1), gr.file_sink(1, "ofdm_receiver-found_corr_b.dat")) self.connect(self.sampler, gr.file_sink(gr.sizeof_gr_complex*fft_length, "ofdm_receiver-sampler_c.dat")) self.connect(self.sigmix, gr.file_sink(gr.sizeof_gr_complex, "ofdm_receiver-sigmix_c.dat")) self.connect(self.nco, gr.file_sink(gr.sizeof_gr_complex, "ofdm_receiver-nco_c.dat"))
def __init__(self, ntxchans, nrxchans, fft_length, cp_length, occupied_tones, snr, ks, logging=False): """ Hierarchical block for receiving OFDM symbols. The input is the complex modulated signal at baseband. Synchronized packets are sent back to the demodulator. @param ntxchans: Number of transmitter MIMO channels (antennas) @type ntxchans: int @param nrxchans: Number of reciever MIMO channels (antennas) @type nrxchans: int @param fft_length: total number of subcarriers @type fft_length: int @param cp_length: length of cyclic prefix as specified in subcarriers (<= fft_length) @type cp_length: int @param occupied_tones: number of subcarriers used for data @type occupied_tones: int @param snr: estimated signal to noise ratio used to guide cyclic prefix synchronizer @type snr: float @param ks: known symbols used as preambles to each packet @type ks: list of lists @param logging: turn file logging on or off @type logging: bool """ gr.hier_block2.__init__(self, "ofdm_mimo_receiver", gr.io_signature(1, 1, gr.sizeof_gr_complex), # Input signature gr.io_signature2(2, 2, gr.sizeof_gr_complex*occupied_tones, gr.sizeof_char)) # Output signature bw = (float(occupied_tones) / float(fft_length)) / 2.0 tb = bw*0.08 chan_coeffs = gr.firdes.low_pass (1.0, # gain 1.0, # sampling rate bw+tb, # midpoint of trans. band tb, # width of trans. band gr.firdes.WIN_HAMMING) # filter type # For starters, run Sync on channel 0 and use it to clock and retime all channels win = [1 for i in range(fft_length)] zeros_on_left = int(math.ceil((fft_length - occupied_tones)/2.0)) ks0 = fft_length*[0,] ks0[zeros_on_left : zeros_on_left + occupied_tones] = ks[0][0:] ks0 = fft.ifftshift(ks0) ks0time = fft.ifft(ks0) # ADD SCALING FACTOR ks0time = ks0time.tolist() SYNC = "pn" if SYNC == "ml": nco_sensitivity = -1.0/fft_length # correct for fine frequency self.ofdm_sync = ofdm_sync_ml(fft_length, cp_length, snr, ks0time, logging) elif SYNC == "pn": nco_sensitivity = -2.0/fft_length # correct for fine frequency self.ofdm_sync = ofdm_sync_pn(fft_length, cp_length, logging) elif SYNC == "pnac": nco_sensitivity = -2.0/fft_length # correct for fine frequency self.ofdm_sync = ofdm_sync_pnac(fft_length, cp_length, ks0time, logging) elif SYNC == "fixed": # for testing only; do not user over the air self.chan_filt = gr.multiply_const_cc(1.0) # remove filter and filter delay for this nsymbols = 18 # enter the number of symbols per packet freq_offset = 0.0 # if you use a frequency offset, enter it here nco_sensitivity = -2.0/fft_length # correct for fine frequency self.ofdm_sync = ofdm_sync_fixed(fft_length, cp_length, nsymbols, freq_offset, logging) # Set up blocks self.chan_filt = list() self.sigmix = list() self.sampler = list() self.fft_demod = list() # Deinterleave the incoming stream into separate channels self.deint = gr.deinterleave(gr.sizeof_gr_complex) # generate a signal proportional to frequency error of sync block self.nco = gr.frequency_modulator_fc(nco_sensitivity) # Manage and combine all channels if 0: self.ofdm_frame_acq = gr.ofdm_mrc_frame_acquisition(nrxchans, occupied_tones, fft_length, cp_length, ks[0]) else: print "Transmitter using ", ntxchans print "Receiver using ", nrxchans if(ntxchans == 1): self.ofdm_frame_acq = gr.ofdm_alamouti_frame_acquisition(ntxchans, occupied_tones, fft_length, cp_length, ks[0], occupied_tones*[0,]) else: self.ofdm_frame_acq = gr.ofdm_alamouti_frame_acquisition(ntxchans, occupied_tones, fft_length, cp_length, ks[0], ks[1]) self.connect(self, self.deint) # deinterleave channels self.connect((self.ofdm_sync,0), self.nco) # use sync freq. offset to derotate signal for i in xrange(nrxchans): self.chan_filt.append(gr.fft_filter_ccc(1, chan_coeffs)) self.sigmix.append(gr.multiply_cc()) self.sampler.append(gr.ofdm_sampler(fft_length, fft_length+cp_length)) self.fft_demod.append(gr.fft_vcc(fft_length, True, win, True)) self.connect((self.deint, i), self.chan_filt[i]) # filter the input channel self.connect(self.nco, (self.sigmix[i],1)) # use sync freq. offset to derotate signal self.connect(self.chan_filt[i], (self.sigmix[i],0)) # signal to be derotated self.connect(self.sigmix[i], (self.sampler[i],0)) # sample off timing signal detected in sync alg self.connect((self.ofdm_sync,1), (self.sampler[i],1)) # timing signal to sample at self.connect((self.sampler[i],0), self.fft_demod[i]) # send derotated sampled signal to FFT self.connect(self.fft_demod[i], (self.ofdm_frame_acq,1+i)) # find frame start and equalize signal if logging: self.connect(self.chan_filt[i], gr.file_sink(gr.sizeof_gr_complex, ("ofdm_mimo-receiver-chan%02d-chan_filt_c.dat" % i))) self.connect(self.fft_demod[i], gr.file_sink(gr.sizeof_gr_complex*fft_length, ("ofdm_mimo-receiver-chan%02d-fft_out_c.dat" % i))) self.connect(self.sampler[i], gr.file_sink(gr.sizeof_gr_complex*fft_length, ("ofdm_mimo-receiver-chan%02d-sampler_c.dat" % i))) self.connect(self.sigmix[i], gr.file_sink(gr.sizeof_gr_complex, ("ofdm_mimo-receiver-chan%02d-sigmix_c.dat" % i))) if logging: self.connect((self.ofdm_frame_acq,0), gr.file_sink(gr.sizeof_gr_complex*occupied_tones, "ofdm_mimo-receiver-frame_acq_c.dat")) self.connect((self.ofdm_frame_acq,1), gr.file_sink(1, "ofdm_mimo-receiver-found_corr_b.dat")) self.connect(self.nco, gr.file_sink(gr.sizeof_gr_complex, "ofdm_mimo-receiver-nco_c.dat")) self.connect(self.chan_filt[0], self.ofdm_sync) # into the synchronization alg. self.connect((self.sampler[0],1), (self.ofdm_frame_acq,0)) # send timing signal to signal frame start self.connect((self.sampler[i],1), gr.null_sink(fft_length*gr.sizeof_char)) self.connect((self.ofdm_frame_acq,0), (self,0)) # finished with fine/coarse freq correction, self.connect((self.ofdm_frame_acq,1), (self,1)) # frame and symbol timing, and equalization
def __init__(self, fft_length, cp_length, occupied_tones, snr, logging=False): """ Hierarchical block for receiving OFDM symbols. The input is the complex modulated signal at baseband. Synchronized packets are sent back to the demodulator. @param fft_length: total number of subcarriers @type fft_length: int @param cp_length: length of cyclic prefix as specified in subcarriers (<= fft_length) @type cp_length: int @param occupied_tones: number of subcarriers used for data @type occupied_tones: int @param snr: estimated signal to noise ratio used to guide cyclic prefix synchronizer @type snr: float @param logging: turn file logging on or off @type logging: bool """ gr.hier_block2.__init__( self, "ofdm_receiver", gr.io_signature(1, 1, gr.sizeof_gr_complex), # Input signature gr.io_signature2(2, 2, gr.sizeof_gr_complex * fft_length, gr.sizeof_char * fft_length)) # Output signature bw = (float(occupied_tones) / float(fft_length)) / 2.0 tb = bw * 0.08 chan_coeffs = gr.firdes.low_pass( 1.0, # gain 1.0, # sampling rate bw + tb, # midpoint of trans. band tb, # width of trans. band gr.firdes.WIN_HAMMING) # filter type #self.chan_filt = gr.fft_filter_ccc(1, chan_coeffs) self.chan_filt = gr.multiply_cc(1) win = [1 for i in range(fft_length)] ks0time = fft_length * (0, ) SYNC = "ml" if SYNC == "ml": #TODO -1.0/... nco_sensitivity = -1.0 / fft_length # correct for fine frequency self.ofdm_sync = ofdm_sync_ml.ofdm_sync_ml(fft_length, cp_length, snr, ks0time, logging) elif SYNC == "pn": nco_sensitivity = -2.0 / fft_length # correct for fine frequency self.ofdm_sync = ofdm_sync_pn.ofdm_sync_pn(fft_length, cp_length, logging) elif SYNC == "pnac": nco_sensitivity = -2.0 / fft_length # correct for fine frequency self.ofdm_sync = ofdm_sync_pnac.ofdm_sync_pnac( fft_length, cp_length, ks0time, logging) # for testing only; do not user over the air # remove filter and filter delay for this elif SYNC == "fixed": self.chan_filt = gr.multiply_const_cc(1.0) nsymbols = 18 # enter the number of symbols per packet freq_offset = 0.0 # if you use a frequency offset, enter it here nco_sensitivity = -2.0 / fft_length # correct for fine frequency self.ofdm_sync = ofdm_sync_fixed.ofdm_sync_fixed( fft_length, cp_length, nsymbols, freq_offset, logging) # Set up blocks #self.grnull = gr.null_sink(4); self.nco = gr.frequency_modulator_fc( nco_sensitivity ) # generate a signal proportional to frequency error of sync block self.sigmix = gr.multiply_cc() self.sampler = digital_swig.ofdm_sampler(fft_length, fft_length + cp_length) self.fft_demod = gr.fft_vcc(fft_length, True, win, True) self.connect(self, self.chan_filt) # filter the input channel self.connect(self.chan_filt, self.ofdm_sync) # into the synchronization alg. self.connect( (self.ofdm_sync, 0), self.nco, (self.sigmix, 1)) # use sync freq. offset output to derotate input signal self.connect(self.chan_filt, (self.sigmix, 0)) # signal to be derotated self.connect( self.sigmix, (self.sampler, 0)) # sample off timing signal detected in sync alg #self.connect(self.chan_filt, (self.sampler,0)) # sample off timing signal detected in sync alg self.connect((self.ofdm_sync, 1), (self.sampler, 1)) # timing signal to sample at self.connect((self.sampler, 0), self.fft_demod) # send derotated sampled signal to FFT self.connect(self.fft_demod, (self, 0)) # frequency domain signal sent to output 0 self.connect((self.sampler, 1), (self, 1)) # timing sent to output 1 print "setup OK" logging = 0 if logging: self.connect( self.chan_filt, gr.file_sink(gr.sizeof_gr_complex, "ofdm_receiver-chan_filt_c.dat")) self.connect((self.ofdm_sync, 0), gr.file_sink(gr.sizeof_float, "ofdm_receiver-sync_0.dat")) self.connect((self.ofdm_sync, 1), gr.file_sink(gr.sizeof_char, "ofdm_receiver-sync_1.dat")) self.connect( self.nco, gr.file_sink(gr.sizeof_gr_complex, "ofdm_receiver-nco_c.dat")) self.connect( self.sigmix, gr.file_sink(gr.sizeof_gr_complex, "ofdm_receiver-sigmix_c.dat")) self.connect((self.sampler, 0), gr.file_sink(gr.sizeof_gr_complex * fft_length, "ofdm_receiver-sampler_0.dat")) self.connect((self.sampler, 1), gr.file_sink(gr.sizeof_char * fft_length, "ofdm_receiver-sampler_1.dat")) self.connect( self.fft_demod, gr.file_sink(gr.sizeof_gr_complex * fft_length, "ofdm_receiver-fft_out_c.dat"))
def __init__(self): grc_wxgui.top_block_gui.__init__(self, title="Rds Tx") _icon_path = "/home/azimout/.local/share/icons/hicolor/32x32/apps/gnuradio-grc.png" self.SetIcon(wx.Icon(_icon_path, wx.BITMAP_TYPE_ANY)) ################################################## # Variables ################################################## self.usrp_interp = usrp_interp = 500 self.dac_rate = dac_rate = 128e6 self.wav_rate = wav_rate = 44100 self.usrp_rate = usrp_rate = int(dac_rate / usrp_interp) self.fm_max_dev = fm_max_dev = 120e3 ################################################## # Blocks ################################################## self.band_pass_filter_0 = gr.interp_fir_filter_fff( 1, firdes.band_pass(1, usrp_rate, 54e3, 60e3, 3e3, firdes.WIN_HAMMING, 6.76)) self.band_pass_filter_1 = gr.interp_fir_filter_fff( 1, firdes.band_pass(1, usrp_rate, 23e3, 53e3, 2e3, firdes.WIN_HAMMING, 6.76)) self.blks2_rational_resampler_xxx_1 = blks2.rational_resampler_fff( interpolation=usrp_rate, decimation=wav_rate, taps=None, fractional_bw=None, ) self.blks2_rational_resampler_xxx_1_0 = blks2.rational_resampler_fff( interpolation=usrp_rate, decimation=wav_rate, taps=None, fractional_bw=None, ) self.gr_add_xx_0 = gr.add_vff(1) self.gr_add_xx_1 = gr.add_vff(1) self.gr_char_to_float_0 = gr.char_to_float() self.gr_diff_encoder_bb_0 = gr.diff_encoder_bb(2) self.gr_frequency_modulator_fc_0 = gr.frequency_modulator_fc( 2 * math.pi * fm_max_dev / usrp_rate) self.gr_map_bb_0 = gr.map_bb(([-1, 1])) self.gr_map_bb_1 = gr.map_bb(([1, 2])) self.gr_multiply_xx_0 = gr.multiply_vff(1) self.gr_multiply_xx_1 = gr.multiply_vff(1) self.gr_rds_data_encoder_0 = rds.data_encoder( "/media/dimitris/mywork/gr/dimitris/rds/trunk/src/test/rds_data.xml" ) self.gr_rds_rate_enforcer_0 = rds.rate_enforcer(256000) self.gr_sig_source_x_0 = gr.sig_source_f(usrp_rate, gr.GR_COS_WAVE, 19e3, 0.3, 0) self.gr_sub_xx_0 = gr.sub_ff(1) self.gr_unpack_k_bits_bb_0 = gr.unpack_k_bits_bb(2) self.gr_wavfile_source_0 = gr.wavfile_source( "/media/dimitris/mywork/gr/dimitris/rds/trunk/src/python/limmenso_stereo.wav", True) self.low_pass_filter_0 = gr.interp_fir_filter_fff( 1, firdes.low_pass(1, usrp_rate, 1.5e3, 2e3, firdes.WIN_HAMMING, 6.76)) self.low_pass_filter_0_0 = gr.interp_fir_filter_fff( 1, firdes.low_pass(1, usrp_rate, 15e3, 2e3, firdes.WIN_HAMMING, 6.76)) self.usrp_simple_sink_x_0 = grc_usrp.simple_sink_c(which=0, side="A") self.usrp_simple_sink_x_0.set_interp_rate(500) self.usrp_simple_sink_x_0.set_frequency(107.2e6, verbose=True) self.usrp_simple_sink_x_0.set_gain(0) self.usrp_simple_sink_x_0.set_enable(True) self.usrp_simple_sink_x_0.set_auto_tr(True) self.wxgui_fftsink2_0 = fftsink2.fft_sink_f( self.GetWin(), baseband_freq=0, y_per_div=20, y_divs=10, ref_level=0, ref_scale=2.0, sample_rate=usrp_rate, fft_size=1024, fft_rate=30, average=False, avg_alpha=None, title="FFT Plot", peak_hold=False, ) self.Add(self.wxgui_fftsink2_0.win) ################################################## # Connections ################################################## self.connect((self.gr_sig_source_x_0, 0), (self.gr_rds_rate_enforcer_0, 1)) self.connect((self.gr_char_to_float_0, 0), (self.gr_rds_rate_enforcer_0, 0)) self.connect((self.gr_map_bb_0, 0), (self.gr_char_to_float_0, 0)) self.connect((self.gr_frequency_modulator_fc_0, 0), (self.usrp_simple_sink_x_0, 0)) self.connect((self.gr_add_xx_1, 0), (self.gr_frequency_modulator_fc_0, 0)) self.connect((self.gr_sig_source_x_0, 0), (self.gr_add_xx_1, 1)) self.connect((self.gr_sub_xx_0, 0), (self.gr_multiply_xx_1, 2)) self.connect((self.gr_sig_source_x_0, 0), (self.gr_multiply_xx_1, 1)) self.connect((self.gr_sig_source_x_0, 0), (self.gr_multiply_xx_1, 0)) self.connect((self.gr_sig_source_x_0, 0), (self.gr_multiply_xx_0, 3)) self.connect((self.gr_sig_source_x_0, 0), (self.gr_multiply_xx_0, 2)) self.connect((self.blks2_rational_resampler_xxx_1_0, 0), (self.gr_add_xx_0, 1)) self.connect((self.blks2_rational_resampler_xxx_1, 0), (self.gr_add_xx_0, 0)) self.connect((self.blks2_rational_resampler_xxx_1_0, 0), (self.gr_sub_xx_0, 1)) self.connect((self.blks2_rational_resampler_xxx_1, 0), (self.gr_sub_xx_0, 0)) self.connect((self.gr_wavfile_source_0, 1), (self.blks2_rational_resampler_xxx_1_0, 0)) self.connect((self.gr_wavfile_source_0, 0), (self.blks2_rational_resampler_xxx_1, 0)) self.connect((self.gr_rds_data_encoder_0, 0), (self.gr_diff_encoder_bb_0, 0)) self.connect((self.gr_diff_encoder_bb_0, 0), (self.gr_map_bb_1, 0)) self.connect((self.gr_map_bb_1, 0), (self.gr_unpack_k_bits_bb_0, 0)) self.connect((self.gr_unpack_k_bits_bb_0, 0), (self.gr_map_bb_0, 0)) self.connect((self.gr_rds_rate_enforcer_0, 0), (self.low_pass_filter_0, 0)) self.connect((self.low_pass_filter_0, 0), (self.gr_multiply_xx_0, 0)) self.connect((self.gr_multiply_xx_0, 0), (self.band_pass_filter_0, 0)) self.connect((self.band_pass_filter_0, 0), (self.gr_add_xx_1, 0)) self.connect((self.gr_multiply_xx_1, 0), (self.band_pass_filter_1, 0)) self.connect((self.band_pass_filter_1, 0), (self.gr_add_xx_1, 3)) self.connect((self.gr_add_xx_1, 0), (self.wxgui_fftsink2_0, 0)) self.connect((self.gr_sig_source_x_0, 0), (self.gr_multiply_xx_0, 1)) self.connect((self.gr_add_xx_0, 0), (self.low_pass_filter_0_0, 0)) self.connect((self.low_pass_filter_0_0, 0), (self.gr_add_xx_1, 2))