diff options
4 files changed, 131 insertions, 64 deletions
diff --git a/gnuradio-core/src/lib/general/gr_constellation_receiver_cb.cc b/gnuradio-core/src/lib/general/gr_constellation_receiver_cb.cc index 0a2309ac0..93af6d078 100644 --- a/gnuradio-core/src/lib/general/gr_constellation_receiver_cb.cc +++ b/gnuradio-core/src/lib/general/gr_constellation_receiver_cb.cc @@ -50,12 +50,14 @@ gr_make_constellation_receiver_cb(gr_constellation constell, fmin, fmax)); } +static int ios[] = {sizeof(char), sizeof(float), sizeof(float), sizeof(float)}; +static std::vector<int> iosig(ios, ios+sizeof(ios)/sizeof(int)); gr_constellation_receiver_cb::gr_constellation_receiver_cb (gr_constellation constellation, float alpha, float beta, float fmin, float fmax) : gr_block ("constellation_receiver_cb", gr_make_io_signature (1, 1, sizeof (gr_complex)), - gr_make_io_signature (1, 1, sizeof (unsigned char))), + gr_make_io_signaturev (1, 4, iosig)), d_constellation(constellation), d_alpha(alpha), d_beta(beta), d_freq(0), d_max_freq(fmax), d_min_freq(fmin), d_phase(0), d_current_const_point(0) @@ -93,29 +95,43 @@ gr_constellation_receiver_cb::general_work (int noutput_items, const gr_complex *in = (const gr_complex *) input_items[0]; unsigned char *out = (unsigned char *) output_items[0]; - int i=0, o=0; + int i=0; float phase_error; unsigned int sym_value; - gr_complex sample; + gr_complex sample, nco; - while((o < noutput_items) && (i < ninput_items[0])) { + float *out_err = 0, *out_phase = 0, *out_freq = 0; + if(output_items.size() == 4) { + out_err = (float *) output_items[1]; + out_phase = (float *) output_items[2]; + out_freq = (float *) output_items[3]; + } + + while((i < noutput_items) && (i < ninput_items[0])) { sample = in[i]; + nco = gr_expj(d_phase); // get the NCO value for derotating the current sample + sample = nco*sample; // get the downconverted symbol sym_value = d_constellation.decision_maker(sample); - //std::cout << "sym_value: " << sym_value << " sample: " << sample << std::endl; phase_error = -arg(sample*conj(d_constellation.constellation()[sym_value])); + //std::cout << "sym_value: " << sym_value << " sample: " << sample << "phase_error: " << phase_error << std::endl; phase_error_tracking(phase_error); // corrects phase and frequency offsets - out[o++] = sym_value; + out[i] = sym_value; + if(output_items.size() == 4) { + out_err[i] = phase_error; + out_phase[i] = d_phase; + out_freq[i] = d_freq; + } i++; } #if 0 printf("ninput_items: %d noutput_items: %d consuming: %d returning: %d\n", - ninput_items[0], noutput_items, i, o); + ninput_items[0], noutput_items, i, i); #endif consume_each(i); - return o; + return i; } // Base Constellation Class diff --git a/gnuradio-core/src/python/gnuradio/blks2impl/generic_mod_demod.py b/gnuradio-core/src/python/gnuradio/blks2impl/generic_mod_demod.py index 8bc33d4dc..69e11fcb0 100644 --- a/gnuradio-core/src/python/gnuradio/blks2impl/generic_mod_demod.py +++ b/gnuradio-core/src/python/gnuradio/blks2impl/generic_mod_demod.py @@ -25,7 +25,7 @@ differential BPSK modulation and demodulation. """ -from gnuradio import gr, gru, modulation_utils +from gnuradio import gr, gru, modulation_utils2 from math import pi, sqrt import psk import cmath @@ -44,7 +44,7 @@ _def_timing_alpha = 0.100 _def_timing_beta = 0.010 _def_timing_max_dev = 1.5 # Fine frequency / Phase correction -_def_costas_alpha = 0.1 +_def_phase_alpha = 0.1 # ///////////////////////////////////////////////////////////////////////////// # Generic modulator @@ -138,7 +138,8 @@ class generic_mod(gr.hier_block2): """ Given command line options, create dictionary suitable for passing to __init__ """ - return {} + return modulation_utils2.extract_kwargs_from_options( + generic_mod.__init__, ('self',), options) extract_kwargs_from_options=staticmethod(extract_kwargs_from_options) @@ -174,7 +175,7 @@ class generic_demod(gr.hier_block2): freq_alpha=_def_freq_alpha, timing_alpha=_def_timing_alpha, timing_max_dev=_def_timing_max_dev, - costas_alpha=_def_costas_alpha, + phase_alpha=_def_phase_alpha, verbose=_def_verbose, log=_def_log): """ @@ -195,8 +196,8 @@ class generic_demod(gr.hier_block2): @type timing_alpha: float @param timing_max_dev: timing loop maximum rate deviations @type timing_max_dev: float - @param costas_alpha: loop filter gain in costas loop - @type costas_alphas: float + @param phase_alpha: loop filter gain in phase loop + @type phase_alphas: float @param verbose: Print information about modulator? @type verbose: bool @param debug: Print modualtion data to files? @@ -210,7 +211,7 @@ class generic_demod(gr.hier_block2): self._constellation = constellation self._samples_per_symbol = samples_per_symbol self._excess_bw = excess_bw - self._costas_alpha = costas_alpha + self._phase_alpha = phase_alpha self._freq_alpha = freq_alpha self._freq_beta = 0.10*self._freq_alpha self._timing_alpha = timing_alpha @@ -241,13 +242,14 @@ class generic_demod(gr.hier_block2): taps, nfilts, nfilts/2, self._timing_max_dev) self.time_recov.set_beta(self._timing_beta) - self._costas_beta = 0.25 * self._costas_alpha * self._costas_alpha + #self._phase_beta = 0.25 * self._phase_alpha * self._phase_alpha + self._phase_beta = 0.25 * self._phase_alpha * self._phase_alpha fmin = -0.25 fmax = 0.25 self.receiver = gr.constellation_receiver_cb( self._constellation, - self._costas_alpha, self._costas_beta, + self._phase_alpha, self._phase_beta, fmin, fmax) # Do differential decoding based on phase change of symbols @@ -276,26 +278,43 @@ class generic_demod(gr.hier_block2): print "\nDemodulator:" print "bits per symbol: %d" % self.bits_per_symbol() print "RRC roll-off factor: %.2f" % self._excess_bw - print "Costas Loop alpha: %.2e" % self._costas_alpha - print "Costas Loop beta: %.2e" % self._costas_beta - print "M&M mu: %.2f" % self._mm_mu - print "M&M mu gain: %.2e" % self._mm_gain_mu - print "M&M omega: %.2f" % self._mm_omega - print "M&M omega gain: %.2e" % self._mm_gain_omega - print "M&M omega limit: %.2f" % self._mm_omega_relative_limit + print "FLL gain: %.2e" % self._freq_alpha + print "Timing alpha gain: %.2e" % self._timing_alpha + print "Timing beta gain: %.2e" % self._timing_beta + print "Timing max dev: %.2f" % self._timing_max_dev + print "Phase track alpha: %.2e" % self._phase_alpha + print "Phase track beta: %.2e" % self._phase_beta def _setup_logging(self): print "Modulation logging turned on." - self.connect(self.pre_scaler, - gr.file_sink(gr.sizeof_gr_complex, "rx_prescaler.dat")) self.connect(self.agc, gr.file_sink(gr.sizeof_gr_complex, "rx_agc.dat")) - self.connect(self.rrc_filter, - gr.file_sink(gr.sizeof_gr_complex, "rx_rrc_filter.dat")) - self.connect(self.receiver, - gr.file_sink(gr.sizeof_gr_complex, "rx_receiver.dat")) + self.connect((self.freq_recov, 0), + gr.file_sink(gr.sizeof_gr_complex, "rx_freq_recov.dat")) + self.connect((self.freq_recov, 1), + gr.file_sink(gr.sizeof_float, "rx_freq_recov_freq.dat")) + self.connect((self.freq_recov, 2), + gr.file_sink(gr.sizeof_float, "rx_freq_recov_phase.dat")) + self.connect((self.freq_recov, 3), + gr.file_sink(gr.sizeof_gr_complex, "rx_freq_recov_error.dat")) + self.connect((self.time_recov, 0), + gr.file_sink(gr.sizeof_gr_complex, "rx_time_recov.dat")) + self.connect((self.time_recov, 1), + gr.file_sink(gr.sizeof_float, "rx_time_recov_error.dat")) + self.connect((self.time_recov, 2), + gr.file_sink(gr.sizeof_float, "rx_time_recov_rate.dat")) + self.connect((self.time_recov, 3), + gr.file_sink(gr.sizeof_float, "rx_time_recov_phase.dat")) + self.connect((self.receiver, 0), + gr.file_sink(gr.sizeof_char, "rx_receiver.dat")) + self.connect((self.receiver, 1), + gr.file_sink(gr.sizeof_float, "rx_receiver_error.dat")) + self.connect((self.receiver, 2), + gr.file_sink(gr.sizeof_float, "rx_receiver_phase.dat")) + self.connect((self.receiver, 3), + gr.file_sink(gr.sizeof_float, "rx_receiver_freq.dat")) self.connect(self.diffdec, - gr.file_sink(gr.sizeof_gr_complex, "rx_diffdec.dat")) + gr.file_sink(gr.sizeof_char, "rx_diffdec.dat")) self.connect(self.unpack, gr.file_sink(gr.sizeof_char, "rx_unpack.dat")) @@ -304,25 +323,28 @@ class generic_demod(gr.hier_block2): Adds generic demodulation-specific options to the standard parser """ parser.add_option("", "--excess-bw", type="float", default=_def_excess_bw, - help="set RRC excess bandwith factor [default=%default] (PSK)") - parser.add_option("", "--costas-alpha", type="float", default=None, - help="set Costas loop alpha value [default=%default] (PSK)") - parser.add_option("", "--gain-mu", type="float", default=_def_gain_mu, - help="set M&M symbol sync loop gain mu value [default=%default] (GMSK/PSK)") - parser.add_option("", "--mu", type="float", default=_def_mu, - help="set M&M symbol sync loop mu value [default=%default] (GMSK/PSK)") - parser.add_option("", "--omega-relative-limit", type="float", default=_def_omega_relative_limit, - help="M&M clock recovery omega relative limit [default=%default] (GMSK/PSK)") + help="set RRC excess bandwith factor [default=%default]") + parser.add_option("", "--freq-alpha", type="float", default=_def_freq_alpha, + help="set frequency lock loop alpha gain value [default=%default]") + parser.add_option("", "--phase-alpha", type="float", default=_def_phase_alpha, + help="set phase tracking loop alpha value [default=%default]") + parser.add_option("", "--timing-alpha", type="float", default=_def_timing_alpha, + help="set timing symbol sync loop gain alpha value [default=%default]") + parser.add_option("", "--timing-beta", type="float", default=_def_timing_beta, + help="set timing symbol sync loop gain beta value [default=%default]") + parser.add_option("", "--timing-max-dev", type="float", default=_def_timing_max_dev, + help="set timing symbol sync loop maximum deviation [default=%default]") add_options=staticmethod(add_options) def extract_kwargs_from_options(options): """ Given command line options, create dictionary suitable for passing to __init__ """ - return {} + return modulation_utils2.extract_kwargs_from_options( + generic_demod.__init__, ('self',), options) extract_kwargs_from_options=staticmethod(extract_kwargs_from_options) -# +## # Add these to the mod/demod registry # -#modulation_utils.add_type_1_mod('dbpsk', dbpsk_mod) -#modulation_utils.add_type_1_demod('dbpsk', dbpsk_demod) +#modulation_utils2.add_type_1_mod('generic', generic_mod) +#modulation_utils2.add_type_1_demod('generic', generic_demod) diff --git a/gnuradio-core/src/python/gnuradio/blks2impl/qam.py b/gnuradio-core/src/python/gnuradio/blks2impl/qam.py index 55081bcc0..9da7ca58e 100644 --- a/gnuradio-core/src/python/gnuradio/blks2impl/qam.py +++ b/gnuradio-core/src/python/gnuradio/blks2impl/qam.py @@ -26,11 +26,12 @@ QAM modulation and demodulation. from math import pi, sqrt, log from itertools import islice -from gnuradio import gr, gru, modulation_utils +from gnuradio import gr, gru, modulation_utils2 from gnuradio.blks2impl.generic_mod_demod import generic_mod, generic_demod # default values (used in __init__ and add_options) +_def_constellation_points = 16 _def_samples_per_symbol = 2 _def_excess_bw = 0.35 _def_verbose = False @@ -43,7 +44,7 @@ _def_timing_alpha = 0.100 _def_timing_beta = 0.010 _def_timing_max_dev = 1.5 # Fine frequency / Phase correction -_def_costas_alpha = 0.1 +_def_phase_alpha = 0.1 def is_power_of_four(x): v = log(x)/log(4) @@ -145,7 +146,7 @@ def make_constellation(m): class qam_mod(generic_mod): - def __init__(self, m, + def __init__(self, constellation_points=_def_constellation_points, samples_per_symbol=_def_samples_per_symbol, excess_bw=_def_excess_bw, verbose=_def_verbose, @@ -169,15 +170,23 @@ class qam_mod(generic_mod): @type log: bool """ - if not isinstance(m, int) or not is_power_of_four(m): - raise ValueError("m must be a power of two integer greater than or equal to 4.") + if not isinstance(constellation_points, int) or not is_power_of_four(constellation_points): + raise ValueError("number of constellation points must be a power of four.") - points = make_constellation(m) + points = make_constellation(constellation_points) constellation = gr.gr_constellation(points) super(qam_mod, self).__init__(constellation, samples_per_symbol, excess_bw, verbose, log) + def add_options(parser): + """ + Adds QAM modulation-specific options to the standard parser + """ + parser.add_option("-p", "--constellation-points", type="int", default=_def_constellation_points, + help="set the number of constellation points (must be a power of 4) [default=%default]") + generic_mod.add_options(parser) + add_options=staticmethod(add_options) # ///////////////////////////////////////////////////////////////////////////// # QAM demodulator @@ -186,13 +195,13 @@ class qam_mod(generic_mod): class qam_demod(generic_demod): - def __init__(self, m, + def __init__(self, constellation_points=_def_constellation_points, samples_per_symbol=_def_samples_per_symbol, excess_bw=_def_excess_bw, freq_alpha=_def_freq_alpha, timing_alpha=_def_timing_alpha, timing_max_dev=_def_timing_max_dev, - costas_alpha=_def_costas_alpha, + phase_alpha=_def_phase_alpha, verbose=_def_verbose, log=_def_log): @@ -214,25 +223,33 @@ class qam_demod(generic_demod): @type timing_alpha: float @param timing_max_dev: timing loop maximum rate deviations @type timing_max_dev: float - @param costas_alpha: loop filter gain in costas loop - @type costas_alphas: float + @param phase_alpha: loop filter gain in phase loop + @type phase_alphas: float @param verbose: Print information about modulator? @type verbose: bool @param debug: Print modualtion data to files? @type debug: bool """ - points = make_constellation(m) + points = make_constellation(constellation_points) constellation = gr.gr_constellation(points) super(qam_demod, self).__init__(constellation, samples_per_symbol, excess_bw, freq_alpha, timing_alpha, - timing_max_dev, costas_alpha, verbose, + timing_max_dev, phase_alpha, verbose, log) - + + def add_options(parser): + """ + Adds QAM demodulation-specific options to the standard parser + """ + parser.add_option("", "--constellation-points", type="int", default=_def_constellation_points, + help="set the number of constellation points (must be a power of 4) [default=%default]") + generic_demod.add_options(parser) + add_options=staticmethod(add_options) + # # Add these to the mod/demod registry # -# NOT READY TO BE USED YET -- ENABLE AT YOUR OWN RISK -#modulation_utils.add_type_1_mod('qam16', qam16_mod) -#modulation_utils.add_type_1_demod('qam16', qam16_demod) +modulation_utils2.add_type_1_mod('qam', qam_mod) +modulation_utils2.add_type_1_demod('qam', qam_demod) diff --git a/gnuradio-examples/python/digital/simple_qam.py b/gnuradio-examples/python/digital/simple_qam.py index dee57baeb..947d7faad 100644 --- a/gnuradio-examples/python/digital/simple_qam.py +++ b/gnuradio-examples/python/digital/simple_qam.py @@ -2,18 +2,20 @@ from gnuradio import gr, blks2, packet_utils # Some constants -NOISE_VOLTAGE = 0 -FREQUENCY_OFFSET = 0 +NOISE_VOLTAGE = 0.1 +FREQUENCY_OFFSET = 0.0000 TIMING_OFFSET = 1.0 SAMPLES_PER_SYMBOL = 2 GAIN = 1.0 SW_DECIM = 1 BAND_MIDPOINT = 1.0 BAND_WIDTH = 0.5 +FREQ_ALPHA = 0.005 +EXCESS_BW = 0.35 # Modulation/Demodulation methods -modulator = blks2.qam_mod(4, SAMPLES_PER_SYMBOL) -demodulator = blks2.qam_demod(4, SAMPLES_PER_SYMBOL) +modulator = blks2.qam_mod(16, SAMPLES_PER_SYMBOL) +demodulator = blks2.qam_demod(16, SAMPLES_PER_SYMBOL, freq_alpha=FREQ_ALPHA) #Transmission Blocks packet_transmitter = blks2.mod_pkts(modulator, access_code=None, msgq_limit=4, @@ -41,6 +43,11 @@ sender = packet_transmitter.send_pkt # Some some packets (The second will not be recieved because it gets cut off # before it can finish. I think this occurs during modulation.) + +# Send some large messages to start off with to let things lock. +for i in range(0, int(20.0/SAMPLES_PER_SYMBOL)): + sender('a'*4000) + sender('hello1') sender('hello2') sender('hello3') @@ -48,6 +55,11 @@ sender('hello4') sender('hello5') sender('hello6') sender('hello7') +sender('hello8') +sender('hello9') +sender('hello10') +sender('hello11') +sender('hello12') sender('world') sender(eof=True) |