summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBen Reynwar2010-12-10 23:42:13 -0700
committerBen Reynwar2010-12-10 23:42:13 -0700
commitee21aaed629cfe9cec2e561c0e3d10374ec80e29 (patch)
treed30c3681b9b3ca44153b9f86e3f8b008bd3105bd
parent704825a27f69f1f3b5cd24e413d4a10a291167e7 (diff)
downloadgnuradio-ee21aaed629cfe9cec2e561c0e3d10374ec80e29.tar.gz
gnuradio-ee21aaed629cfe9cec2e561c0e3d10374ec80e29.tar.bz2
gnuradio-ee21aaed629cfe9cec2e561c0e3d10374ec80e29.zip
Fixing generic demodulation.
-rw-r--r--gnuradio-core/src/lib/general/gr_constellation_receiver_cb.cc32
-rw-r--r--gnuradio-core/src/python/gnuradio/blks2impl/generic_mod_demod.py94
-rw-r--r--gnuradio-core/src/python/gnuradio/blks2impl/qam.py49
-rw-r--r--gnuradio-examples/python/digital/simple_qam.py20
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)