Weaver method SSB Modulator
The Weaver scripts were created from diagrams in this application note
Update: previous version claimed that changing the sum from gr.add_ff()
to gr.sub_ff() would change the sideband - that worked in the earlier
weaver graph with seperate I/Q pathways, but in this version using
combined complex pathways, the sideband is changed by changing the
sign of the rf local oscillator frequency. in rf_loc, change rf_LO
to -rf_LO for USB. Also change the sign in calculating the carrier
point rf_LO to + for USB. This can all be done with one variable 's',
set to '1' for LSB and '-1' for USB.
This is the latest, final script that will likely be used on
the air. I'm using this for generating SSB for PSK31 - so far I'm getting
IMD of better than -27db running 20W into a dummy load and picking up on
a nearby receiver. See the spectrum analysis bullet for details on spectral
purity.
weaver_gen_2.py
#!/usr/bin/env python
#
# Weaver SSB generation
#
# af_loc rf_loc
# | |
# [audio]=[f2c]--(x)-----[lpf1c]---[lpf2c]---(x)--[c2f]=(+)--- ssb out
# af_mixc rf_mixc
#
#
from gnuradio import gr
from gnuradio import usrp
from gnuradio import audio
import sys
def build_graph ():
usrp_interp = 80
usrp_duc = 3600e3
sink = usrp.sink_c (0, usrp_interp)
print "requesting: ", usrp_duc, "hz"
sink.set_tx_freq(0, usrp_duc)
# use usrp.tx_freq(0) to get actual freq, and use that
# to set rf_LO
actual_freq = sink.tx_freq(0)
print "got ", actual_freq, "hz"
sink.set_nchannels(1)
sink.set_mux(0x98)
target_freq = 3615e3
offset_freq = target_freq - actual_freq
print "Offset freq:", offset_freq
af_LO = 1.8e3
# set s = 1 for LSB, s = -1 for USB
s = 1
rf_LO = s * ( offset_freq - ( s * af_LO ))
print "rf_LO: ", rf_LO
af_sample_rate = 32000
rf_sample_rate = 1600000
fir_interp = rf_sample_rate / af_sample_rate
print "fir_interp: ", fir_interp
fg = gr.flow_graph ()
# transmit an audio file:
# audio_file = gr.file_source (gr.sizeof_short, "x-1_b32.sw",1)
# audio_conv = gr.short_to_float()
# src = gr.multiply_const_ff(.00003)
# fg.connect(audio_file, audio_conv)
# fg.connect(audio_conv, src)
# microphone/line-in source:
src_mic = audio.source(af_sample_rate)
src = gr.multiply_const_ff(13)
fg.connect (src_mic, src)
# two-tone test:
# src1 = gr.sig_source_f (af_sample_rate,gr.GR_SIN_WAVE,1400,1,0)
# src = gr.sig_source_f (af_sample_rate,gr.GR_SIN_WAVE,440,1,0)
# src = gr.add_ff()
# fg.connect (src1, (src, 0))
# fg.connect (src2, (src, 1))
f2c = gr.float_to_complex()
af_loc = gr.sig_source_c (af_sample_rate,gr.GR_COS_WAVE,af_LO,1,0)
af_mixc = gr.multiply_cc ()
lpf1_taps = gr.firdes.low_pass ( \
1.0, af_sample_rate, 1.8e3, 600, gr.firdes.WIN_HAMMING)
lpf1c = gr.fir_filter_ccf (1, lpf1_taps)
lpf2_taps = gr.firdes.low_pass ( \
1.0, rf_sample_rate, 5e3, 10e3, gr.firdes.WIN_HAMMING)
lpf2c = gr.interp_fir_filter_ccf (fir_interp, lpf2_taps)
rf_loc = gr.sig_source_c (rf_sample_rate,gr.GR_COS_WAVE,rf_LO,2,0)
rf_mixc = gr.multiply_cc ()
c2f = gr.complex_to_float()
sum = gr.add_ff ()
scale = gr.multiply_const_ff(40 * 500)
hilbert = gr.hilbert_fc(197)
# out = gr.file_sink (gr.sizeof_short, "ssb_mod")
fg.connect (src, (f2c, 0))
fg.connect (src, (f2c, 1))
fg.connect (f2c, (af_mixc, 0))
fg.connect (af_loc, (af_mixc, 1))
fg.connect (af_mixc, lpf1c)
fg.connect (lpf1c, lpf2c)
fg.connect (lpf2c, (rf_mixc, 0))
fg.connect (rf_loc, (rf_mixc, 1))
fg.connect (rf_mixc, c2f)
fg.connect ((c2f, 0), (sum, 0))
fg.connect ((c2f, 1), (sum, 1))
fg.connect (sum, scale)
fg.connect (scale, hilbert)
fg.connect (hilbert, sink)
return fg
def main ():
fg = build_graph ()
fg.start ()
raw_input ('Press Enter to quit: ')
fg.stop ()
if __name__ == '__main__':
main ()