I've witten some code to transmit an fm stereo signal. I don't have a USRP to test it with a hardware reciever, but I did check the output with the fm stereo recieving code avalible. If anyone with a USRP could test this code I would apperciate it. What I am most intereted in finding out is if the basictx card can generate a signal in the fm broadcast band from the aliasing of the dac.
I have not added preemphasis because I'm not sure of how to do it accurately. #!/usr/bin/env python from gnuradio import gr, eng_notation, optfir # from gnuradio import usrp # uncomment for usrp output from gnuradio import audio from gnuradio.eng_option import eng_option from optparse import OptionParser import math from gnuradio.wxgui import stdgui, fftsink, scopesink import wx def stereompxgen( fg , audio_rate , audio_interp ): mpx_rate= audio_rate * audio_interp pilot = gr.sig_source_f (mpx_rate, gr.GR_SIN_WAVE, 19000, .08) # pilot amplitune default is .08 , may be set to zero for test purposes subcar = gr.sig_source_f (mpx_rate, gr.GR_SIN_WAVE, 38000, 1) lplusr = gr.add_ff() lminusr = gr.sub_ff() laudio = gr.multiply_const_ff( .9 ) raudio = gr.multiply_const_ff( .9 ) lminusr_sig = gr.multiply_ff() mpxcomposite = gr.add_ff() sw_interp = audio_interp fs = mpx_rate upsample_taps = gr.firdes.low_pass (sw_interp, # gain fs, # sampling rate 16000, # cutoff 2500, # trans width gr.firdes.WIN_HANN) print "length of audio filters ( 2 ) = ", len (upsample_taps) lplusr_or = gr.interp_fir_filter_fff (sw_interp, upsample_taps) lminusr_or = gr.interp_fir_filter_fff (sw_interp, upsample_taps) fg.connect (laudio, (lplusr, 0)) fg.connect (raudio, (lplusr, 1)) fg.connect (laudio, (lminusr, 0)) fg.connect (raudio, (lminusr, 1)) fg.connect (lplusr, lplusr_or ) fg.connect (lminusr, lminusr_or ) fg.connect (lminusr_or, (lminusr_sig,0) ) fg.connect (subcar, (lminusr_sig,1) ) fg.connect (lplusr_or, (mpxcomposite,0) ) fg.connect (lminusr_sig, (mpxcomposite,1) ) fg.connect (pilot, (mpxcomposite,2) ) return ( laudio,raudio , mpxcomposite ) def fold_freq(freq, fs): while freq > fs: freq = freq - fs if freq > fs/2: freq = fs - freq return freq class fsk_tx_graph (stdgui.gui_flow_graph): def __init__(self, frame, panel, vbox, argv): stdgui.gui_flow_graph.__init__ (self, frame, panel, vbox, argv) parser = OptionParser (option_class=eng_option) parser.add_option ("-c", "--cordic-freq", type="eng_float", default=96.9e6, help="set Tx cordic frequency to FREQ", metavar="FREQ") parser.add_option ("-d", "--device", type="string", default="hw:0,0", help="set audio input device") parser.add_option ("-f", "--filename", type="string", default="fmstereooutput_512k_complex.dat", help="write output to FILENAME") parser.add_option ("-g", "--gain", type="eng_float", default=0, help="set Tx PGA gain in dB [-20, 0] (default=0)") (options, args) = parser.parse_args () cordic_freq=fold_freq( options.cordic_freq , 128000000 ) print "cordic_freq = %s" % (eng_notation.num_to_str (cordic_freq)) # ---------------------------------------------------------------- audio_rate = 32000 audio_interp = 8 mpx_interp = 2 mpx_low_rate = audio_rate * audio_interp mpx_high_rate = audio_rate * audio_interp * mpx_interp self.usrp_interp = int (128e6 / mpx_high_rate ) max_deviation = 75e3 print "audio rate = ", audio_rate print "audio interp = ", audio_interp print "baseband interp = ", mpx_interp print "fm complex sample rate = ", eng_notation.num_to_str(mpx_high_rate) print "usrp_interp = ", self.usrp_interp src = audio.source ( audio_rate , options.device ) ltone = gr.sig_source_f (audio_rate, gr.GR_SIN_WAVE, 1000, .92) rtone = gr.sig_source_f (audio_rate, gr.GR_SIN_WAVE, 1000, 0) interp_taps = gr.firdes.low_pass (mpx_interp, # gain mpx_high_rate, # sampling rate 70e3, # cutoff 30e3, # trans width gr.firdes.WIN_HANN) print "len = ", len (interp_taps) (mpxinl, mpxinr, mpxout) = stereompxgen( self , audio_rate , audio_interp ) k = 2 * math.pi * max_deviation / mpx_high_rate fmmod = gr.frequency_modulator_fc (k) interp = gr.interp_fir_filter_fff (mpx_interp, interp_taps) gain = gr.multiply_const_cc (4000) # was 16000 fsink = gr.file_sink( gr.sizeof_gr_complex , options.filename ) self.frame = frame msg = "Frequency: %s" % (eng_notation.num_to_str(options.cordic_freq) ) self.frame.SetStatusText (msg,0 ) msg = "Fundamental: %s" % (eng_notation.num_to_str(cordic_freq) ) self.frame.SetStatusText (msg,1 ) if 1: # 1 for audio 0 for test tones self.connect ((src,0) , (mpxinl) ) self.connect ((src,1) , (mpxinr) ) else: self.connect (ltone , (mpxinl) ) self.connect (rtone , (mpxinr) ) self.connect (mpxout , interp , fmmod , gain ) if 0: # 1 for usrp output u = usrp.sink_c (0, self.usrp_interp) u.set_tx_freq (0, cordic_freq) u.set_pga (0, options.gain) u.set_pga (1, options.gain) self.connect ( gain, u) else: self.connect ( gain, fsink ) probe = gr.file_sink( gr.sizeof_float , "fmstereompx.dat" ) # self.connect (mpxout, probe ) if 1: mpx_scope = \ scopesink.scope_sink_f(self, panel, "MPX Baseband", sample_rate=mpx_low_rate) self.connect ( mpxout , (mpx_scope, 0)) vbox.Add (mpx_scope.win, 1, wx.EXPAND) if 1: mpx_fft = fftsink.fft_sink_f (self, panel, fft_size=1024, fft_rate=10, sample_rate=mpx_low_rate, ref_level=40 , title="MPX Baseband FFT" ) self.connect (mpxout , mpx_fft) vbox.Add (mpx_fft.win, 1, wx.EXPAND) def main (): app = stdgui.stdapp (fsk_tx_graph, "FM Stereo Tx") app.MainLoop () if __name__ == '__main__': main () # eof __________________________________ Discover Yahoo! Get on-the-go sports scores, stock quotes, news and more. Check it out! http://discover.yahoo.com/mobile.html _______________________________________________ Discuss-gnuradio mailing list Discuss-gnuradio@gnu.org http://lists.gnu.org/mailman/listinfo/discuss-gnuradio