summaryrefslogtreecommitdiff
path: root/gsm-tvoid
diff options
context:
space:
mode:
authortvoid <tvoid@lesaige.com>2008-04-15 15:09:00 -0600
committertvoid <tvoid@lesaige.com>2008-04-15 15:09:00 -0600
commitde1460aa9438f6a466a5fe4455ed968033d4ecdb (patch)
treeb5266d210be220272b0bf2ff0f4d0e78735faf42 /gsm-tvoid
parentd2107cd98e683e10645f64d61a2544b628a955ea (diff)
added m&m to burst_cf
doubles to floats
Diffstat (limited to 'gsm-tvoid')
-rw-r--r--gsm-tvoid/src/lib/Makefile.am4
-rwxr-xr-xgsm-tvoid/src/lib/gsm.i7
-rwxr-xr-xgsm-tvoid/src/lib/gsm_burst.cc2
-rwxr-xr-xgsm-tvoid/src/lib/gsm_burst.h8
-rwxr-xr-xgsm-tvoid/src/lib/gsm_burst_cf.cc58
-rwxr-xr-xgsm-tvoid/src/lib/gsm_burst_cf.h21
-rw-r--r--gsm-tvoid/src/lib/mm_c.cc73
-rw-r--r--gsm-tvoid/src/lib/mm_c.h48
-rw-r--r--gsm-tvoid/src/lib/mm_f.cc55
-rw-r--r--gsm-tvoid/src/lib/mm_f.h34
-rwxr-xr-xgsm-tvoid/src/python/gsm_scan.py61
11 files changed, 319 insertions, 52 deletions
diff --git a/gsm-tvoid/src/lib/Makefile.am b/gsm-tvoid/src/lib/Makefile.am
index 88b8faa..1854fc6 100644
--- a/gsm-tvoid/src/lib/Makefile.am
+++ b/gsm-tvoid/src/lib/Makefile.am
@@ -46,6 +46,8 @@ _gsm_la_SOURCES = \
gsm.cc \
gsm_burst.cc \
gsm_burst_ff.cc \
+ mm_c.cc \
+ mm_f.cc \
gsm_burst_cf.cc \
gsm_burst_sink_c.cc
@@ -72,6 +74,8 @@ grinclude_HEADERS = \
cch.h \
system.h \
gsm_burst_ff.h \
+ mm_c.h \
+ mm_f.h \
gsm_burst_cf.h \
gsm_burst_sink_c.h \
gsm_constants.h
diff --git a/gsm-tvoid/src/lib/gsm.i b/gsm-tvoid/src/lib/gsm.i
index 106e378..0ddd8b2 100755
--- a/gsm-tvoid/src/lib/gsm.i
+++ b/gsm-tvoid/src/lib/gsm.i
@@ -32,7 +32,7 @@
#define PRINT_DUMMY 0x00000100
#define PRINT_NORMAL 0x00000200
-#define PRINT_GSM_DECODE 0x00000400
+#define PRINT_GSM_DECODE 0x00004000
#define PRINT_HEX 0x00001000
@@ -82,7 +82,7 @@ public:
int sync_state();
float last_freq_offset(void);
- double mean_freq_offset(void);
+ float mean_freq_offset(void);
//Methods
void full_reset(void);
@@ -104,6 +104,9 @@ GR_SWIG_BLOCK_MAGIC(gsm,burst_cf);
gsm_burst_cf_sptr gsm_make_burst_cf (gr_feval_ll *,float);
class gsm_burst_cf : public gr_block, public gsm_burst {
+public:
+ float get_omega();
+
private:
gsm_burst_cf (gr_feval_ll *,float);
};
diff --git a/gsm-tvoid/src/lib/gsm_burst.cc b/gsm-tvoid/src/lib/gsm_burst.cc
index c7f0acc..6d02ea6 100755
--- a/gsm-tvoid/src/lib/gsm_burst.cc
+++ b/gsm-tvoid/src/lib/gsm_burst.cc
@@ -103,7 +103,7 @@ void gsm_burst::full_reset(void)
}
-double gsm_burst::mean_freq_offset(void)
+float gsm_burst::mean_freq_offset(void)
{
if (d_freq_off_weight)
return d_freq_off_sum / d_freq_off_weight;
diff --git a/gsm-tvoid/src/lib/gsm_burst.h b/gsm-tvoid/src/lib/gsm_burst.h
index 48fafac..6a206b1 100755
--- a/gsm-tvoid/src/lib/gsm_burst.h
+++ b/gsm-tvoid/src/lib/gsm_burst.h
@@ -35,7 +35,7 @@
#define PRINT_DUMMY 0x00000100
#define PRINT_NORMAL 0x00000200
-#define PRINT_GSM_DECODE 0x00000400
+#define PRINT_GSM_DECODE 0x00004000
#define PRINT_HEX 0x00001000
@@ -123,8 +123,8 @@ protected:
int d_color_code;
float d_freq_offset;
- double d_freq_off_sum;
- double d_freq_off_weight;
+ float d_freq_off_sum;
+ float d_freq_off_weight;
gr_feval_ll *p_tuner;
@@ -178,7 +178,7 @@ public:
//Frequency
float last_freq_offset() {return d_freq_offset;}
- double mean_freq_offset(void);
+ float mean_freq_offset(void);
long next_arfcn;
};
diff --git a/gsm-tvoid/src/lib/gsm_burst_cf.cc b/gsm-tvoid/src/lib/gsm_burst_cf.cc
index a584cd6..a7d0e11 100755
--- a/gsm-tvoid/src/lib/gsm_burst_cf.cc
+++ b/gsm-tvoid/src/lib/gsm_burst_cf.cc
@@ -20,24 +20,26 @@ static const int MIN_OUT = 0; // minimum number of output streams
static const int MAX_OUT = 1; // maximum number of output streams
gsm_burst_cf::gsm_burst_cf (gr_feval_ll *t, float sample_rate) :
- gsm_burst(t),
- gr_block ( "burst_cf",
+ gr_block( "burst_cf",
gr_make_io_signature (MIN_IN, MAX_IN, sizeof (gr_complex)),
- gr_make_io_signature (MIN_OUT, MAX_OUT, USEFUL_BITS * sizeof (float))),
+ gr_make_io_signature (MIN_OUT, MAX_OUT, USEFUL_BITS * sizeof (float)) //TODO: pad to ^2 = 256 ?
+ ),
+ gsm_burst(t),
d_clock_counter(0.0),
- d_mu(0.5),
d_last_sample(0.0,0.0),
- d_interp(new gri_mmse_fir_interpolator_cc())
+ mm(sample_rate / GSM_SYMBOL_RATE),
+ d_interp(new gri_mmse_fir_interpolator_cc()
+ )
{
//clocking parameters
- d_sample_interval = 1.0 / sample_rate;
- d_relative_sample_rate = sample_rate / GSM_SYMBOL_RATE;
+ //d_sample_interval = 1.0 / sample_rate;
+ //d_omega = sample_rate / GSM_SYMBOL_RATE;
- fprintf(stderr,"Sample interval : %e\n",d_sample_interval);
- fprintf(stderr,"Relative sample rate : %g\n",d_relative_sample_rate);
-
+// fprintf(stderr,"Sample interval : %e\n",d_sample_interval);
+// fprintf(stderr,"Relative sample rate : %g\n",d_omega);
+
set_history(4); //need history for interpolator
}
@@ -51,10 +53,9 @@ void gsm_burst_cf::forecast (int noutput_items, gr_vector_int &ninput_items_requ
{
unsigned ninputs = ninput_items_required.size ();
for (unsigned i = 0; i < ninputs; i++)
- ninput_items_required[i] = noutput_items * (int)ceil(d_relative_sample_rate) * BBUF_SIZE + history();
+ ninput_items_required[i] = noutput_items * (int)ceil(mm.d_omega) * BBUF_SIZE + history();
}
-
int gsm_burst_cf::general_work (int noutput_items,
gr_vector_int &ninput_items,
gr_vector_const_void_star &input_items,
@@ -65,7 +66,8 @@ int gsm_burst_cf::general_work (int noutput_items,
int ii=0;
int rval = 0; //default to no output
- int do_output = output_items.size() > 0 ? 1 : 0;
+ int num_outputs = output_items.size();
+ int do_output = num_outputs > 0 ? 1 : 0;
int ninput = ninput_items[0];
//fprintf(stderr,"#i=%d/#o=%d",n_input,noutput_items);
@@ -75,17 +77,19 @@ int gsm_burst_cf::general_work (int noutput_items,
while (( rval < noutput_items) && ( ii < ni ) ) {
//clock symbols
//TODO: this is very basic and can be improved. Need tracking...
- //TODO: use burst_start offsets as timing feedback
//TODO: save complex samples for Viterbi EQ
- //from m&m
- gr_complex sample = d_interp->interpolate (&in[ii], d_mu); //FIXME: this seems noisy, make sure it is being used correctly
+ //get interpolated sample
+ gr_complex x_0 = d_interp->interpolate (&in[ii], mm.d_mu);
- gr_complex conjprod = sample * conj(d_last_sample);
+ //calulate phase difference (demod)
+ gr_complex conjprod = x_0 * conj(d_last_sample);
float diff_angle = gr_fast_atan2f(imag(conjprod), real(conjprod));
- d_last_sample = sample;
-
+ //mM&M
+ //mm.update(x_0); //mm_c
+ mm.update(diff_angle); //mm_f
+
assert(d_bbuf_pos <= BBUF_SIZE );
if (d_bbuf_pos >= 0) //could be negative offset from burst alignment. TODO: perhaps better just to add some padding to the buffer
@@ -111,12 +115,12 @@ int gsm_burst_cf::general_work (int noutput_items,
switch ( d_clock_options & QB_MASK ) {
case QB_QUARTER: //extra 1/4 bit each burst
- d_mu -= d_relative_sample_rate / 4.0;
+ mm.d_mu -= mm.d_omega / 4.0;
//d_clock_counter -= GSM_SYMBOL_PERIOD / 4.0;
break;
case QB_FULL04: //extra bit on timeslot 0 & 4
if (!(d_ts%4))
- d_mu -= d_relative_sample_rate;
+ mm.d_mu -= mm.d_omega;
//d_clock_counter -= GSM_SYMBOL_PERIOD;
break;
case QB_NONE: //don't adjust for quarter bits at all
@@ -130,12 +134,12 @@ int gsm_burst_cf::general_work (int noutput_items,
}
}
- //TODO: timing adjust
- //d_mu = d_mu + d_omega + d_gain_mu * mm_val;
- d_mu += d_relative_sample_rate;
- ii += (int)floor(d_mu);
- d_sample_count += (int)floor(d_mu);
- d_mu -= floor(d_mu);
+ //process mu / ii advance
+ ii += (int)floor(mm.d_mu);
+ d_sample_count += (int)floor(mm.d_mu);
+ mm.d_mu -= floor(mm.d_mu);
+
+ d_last_sample = x_0;
}
//fprintf(stderr,"/ii=%d/rval=%d\n",ii,rval);
diff --git a/gsm-tvoid/src/lib/gsm_burst_cf.h b/gsm-tvoid/src/lib/gsm_burst_cf.h
index 40ccc83..fe3663c 100755
--- a/gsm-tvoid/src/lib/gsm_burst_cf.h
+++ b/gsm-tvoid/src/lib/gsm_burst_cf.h
@@ -2,7 +2,8 @@
#define INCLUDED_GSM_BURST_CF_H
#include <gr_block.h>
-#include <gsm_burst.h>
+#include "gsm_burst.h"
+#include "mm_f.h"
class gsm_burst_cf;
@@ -20,15 +21,18 @@ private:
gsm_burst_cf(gr_feval_ll *,float);
//clocking parameters
- double d_sample_interval;
- double d_clock_counter;
+ float d_sample_interval;
+ float d_clock_counter; //??? sample count ???
+
gr_complex d_last_sample;
- float d_relative_sample_rate; //omega
- float d_mu;
-
- gri_mmse_fir_interpolator_cc *d_interp; //sub-sample interpolator from GR
+ //M&M clock recovery
+ mm_f mm;
+ gri_mmse_fir_interpolator_cc *d_interp; //sub-sample interpolator from GR
+
+ gr_complex slicer(gr_complex x);
+
public:
~gsm_burst_cf ();
@@ -38,6 +42,9 @@ public:
gr_vector_int &ninput_items,
gr_vector_const_void_star &input_items,
gr_vector_void_star &output_items);
+
+ float get_omega() {return mm.d_omega;}
+
};
#endif /* INCLUDED_GSM_BURST_CF_H */
diff --git a/gsm-tvoid/src/lib/mm_c.cc b/gsm-tvoid/src/lib/mm_c.cc
new file mode 100644
index 0000000..7b3e335
--- /dev/null
+++ b/gsm-tvoid/src/lib/mm_c.cc
@@ -0,0 +1,73 @@
+
+#include "mm_c.h"
+
+mm_c::mm_c(float omega):
+ d_omega(omega),
+ d_mu(0.5),
+ d_x_1(0.0,0.0),
+ d_x_2(0.0,0.0),
+ d_a_1(0.0,0.0),
+ d_a_2(0.0,0.0),
+ d_gain_mu(0.01),
+ d_gain_omega(0.25 * d_gain_mu * d_gain_mu)
+{}
+
+
+gr_complex mm_c::slicer(gr_complex x)
+{
+ float real=SLICE_0_R, imag=SLICE_0_I;
+
+ if(x.real() > 0.0)
+ real = SLICE_1_R;
+
+ if(x.imag() > 0.0)
+ imag = SLICE_1_I;
+
+ return gr_complex(real,imag);
+}
+
+float mm_c::update(gr_complex x_0, gr_complex a_0)
+{
+ //mm vars
+ gr_complex x,y,u;
+
+ x = (a_0 - d_a_2) * conj(d_x_1);
+ y = (x_0 - d_x_2) * conj(d_a_1);
+ u = y - x;
+ d_mm = u.real(); //error signal
+
+ //limit d_mm
+ if (d_mm > 1.0) d_mm = 1.0;
+ else if (d_mm < -1.0) d_mm = -1.0;
+
+ //error feedback
+ d_omega = d_omega + d_gain_omega * d_mm;
+
+ //limit omega
+/*
+ if (d_omega > d_max_omega)
+ d_omega = d_max_omega;
+ else if (d_omega < d_min_omega)
+ d_omega = d_min_omega;
+*/
+ //update mu
+ d_mu = d_mu + d_omega + d_gain_mu * d_mm;
+ //process mu / ii advances after burst processing for burst timing
+
+ //update delay taps
+ d_x_2 = d_x_1;
+ d_x_1 = x_0;
+ d_a_2 = d_a_1;
+ d_a_1 = a_0;
+
+ return d_mu;
+}
+
+
+float mm_c::update(gr_complex x_0)
+{
+ return update(x_0, slicer(x_0) );
+}
+
+
+
diff --git a/gsm-tvoid/src/lib/mm_c.h b/gsm-tvoid/src/lib/mm_c.h
new file mode 100644
index 0000000..e9881dd
--- /dev/null
+++ b/gsm-tvoid/src/lib/mm_c.h
@@ -0,0 +1,48 @@
+#ifndef INCLUDED_MM_C_H
+#define INCLUDED_MM_C_H
+
+#include <gr_math.h>
+
+#if 0
+#define SLICE_0_R 0.0
+#define SLICE_0_I 0.0
+#define SLICE_1_R 1.0
+#define SLICE_1_I 1.0
+#else
+#define SLICE_0_R -1.0
+#define SLICE_0_I -1.0
+#define SLICE_1_R 1.0
+#define SLICE_1_I 1.0
+#endif
+
+class mm_c {
+private:
+public:
+
+ float d_mm;
+
+ float d_omega; //relative sample rate
+ float d_mu;
+
+ float d_gain_mu;
+ float d_gain_omega;
+
+ //delay taps
+ gr_complex d_x_1; //last input sample
+ gr_complex d_x_2;
+ gr_complex d_a_1; //last decision
+ gr_complex d_a_2;
+
+ mm_c (float omega);
+
+ gr_complex slicer(gr_complex x);
+
+ float update(gr_complex sample, gr_complex decision); //return mu
+
+ float update(gr_complex sample); //use built in decision
+
+};
+
+
+
+#endif
diff --git a/gsm-tvoid/src/lib/mm_f.cc b/gsm-tvoid/src/lib/mm_f.cc
new file mode 100644
index 0000000..4637149
--- /dev/null
+++ b/gsm-tvoid/src/lib/mm_f.cc
@@ -0,0 +1,55 @@
+
+#include "mm_f.h"
+
+mm_f::mm_f(float omega):
+ d_omega(omega),
+ d_mu(0.5),
+ d_x_1(0.0),
+ d_a_1(0.0),
+ d_gain_mu(0.01),
+ d_gain_omega(0.25 * d_gain_mu * d_gain_mu)
+{}
+
+
+float mm_f::slicer(float x)
+{
+ return x < 0 ? -1.0 : 1.0;
+}
+
+float mm_f::update(float x_0, float a_0)
+{
+ d_mm = (d_a_1 * x_0) - (a_0 * d_x_1);
+
+ //limit d_mm
+ if (d_mm > 1.0) d_mm = 1.0;
+ else if (d_mm < -1.0) d_mm = -1.0;
+
+ //error feedback
+ d_omega = d_omega + d_gain_omega * d_mm;
+
+ //limit omega
+/*
+ if (d_omega > d_max_omega)
+ d_omega = d_max_omega;
+ else if (d_omega < d_min_omega)
+ d_omega = d_min_omega;
+*/
+ //update mu
+ d_mu = d_mu + d_omega + d_gain_mu * d_mm;
+ //process mu / ii advances after burst processing for burst timing
+
+ //update delay taps
+ d_x_1 = x_0;
+ d_a_1 = a_0;
+
+ return d_mu;
+}
+
+
+float mm_f::update(float x_0)
+{
+ return update(x_0, slicer(x_0) );
+}
+
+
+
diff --git a/gsm-tvoid/src/lib/mm_f.h b/gsm-tvoid/src/lib/mm_f.h
new file mode 100644
index 0000000..8b359be
--- /dev/null
+++ b/gsm-tvoid/src/lib/mm_f.h
@@ -0,0 +1,34 @@
+#ifndef INCLUDED_MM_F_H
+#define INCLUDED_MM_F_H
+
+#include <gr_math.h>
+
+class mm_f {
+private:
+public:
+
+ float d_mm;
+
+ float d_omega; //relative sample rate
+ float d_mu;
+
+ float d_gain_mu;
+ float d_gain_omega;
+
+ //delay taps
+ float d_x_1; //last input sample
+ float d_a_1; //last decision
+
+ mm_f (float omega);
+
+ float slicer(float x);
+
+ float update(float sample, float decision); //return mu
+
+ float update(float sample); //use built in decision
+
+};
+
+
+
+#endif
diff --git a/gsm-tvoid/src/python/gsm_scan.py b/gsm-tvoid/src/python/gsm_scan.py
index 5e3edfc..478b460 100755
--- a/gsm-tvoid/src/python/gsm_scan.py
+++ b/gsm-tvoid/src/python/gsm_scan.py
@@ -173,7 +173,7 @@ class app_flow_graph(stdgui.gui_flow_graph):
#decoder options
- parser.add_option("-D", "--decoder", type="string", default="f",
+ parser.add_option("-D", "--decoder", type="string", default="c",
help="Select decoder block to use. (c)omplex,(f)loat [default=%default]")
parser.add_option("-E", "--equalizer", type="string", default="none",
help="Type of equalizer to use. none, fixed-dfe [default=%default]")
@@ -280,9 +280,6 @@ class app_flow_graph(stdgui.gui_flow_graph):
if options.print_console.count('D'):
popts |= gsm.PRINT_DUMMY
- if options.print_console.count('C'):
- popts |= gsm.PRINT_BITS | gsm.PRINT_CORR_BITS
-
if options.print_console.count('x'):
popts |= gsm.PRINT_BITS | gsm.PRINT_HEX
@@ -292,6 +289,9 @@ class app_flow_graph(stdgui.gui_flow_graph):
elif options.print_console.count('b'):
popts |= gsm.PRINT_BITS
+ elif options.print_console.count('C'):
+ popts |= gsm.PRINT_BITS | gsm.PRINT_CORR_BITS
+
print "Print flags: 0x%8.8x\n" %(popts)
self.burst.d_print_options = popts
@@ -357,7 +357,7 @@ class app_flow_graph(stdgui.gui_flow_graph):
print >> sys.stderr, "% offset = ", percent_offset, "clock = ", clock_rate
self.clock_rate = clock_rate
- self.input_rate = clock_rate / options.decim
+ self.input_rate = clock_rate / options.decim #TODO: what about usrp value?
self.gsm_symb_rate = 1625000.0 / 6.0
self.sps = self.input_rate / self.gsm_symb_rate
@@ -394,18 +394,41 @@ class app_flow_graph(stdgui.gui_flow_graph):
gain_omega,
0.5, #mu
gain_mu,
- 0.3) #omega_relative_limit,
+ 0.5) #omega_relative_limit,
self.burst = gsm.burst_ff(self.burst_cb)
self.connect(self.filter, self.demod, self.clocker, self.burst)
####################
+ def setup_f_flowgraph2(self):
+ #This version uses a complex clock recovery prior to demod
+ #one advantage is the availability of clock error output in the cc version
+
+ #configure clock recovery
+ gain_mu = 0.01
+ gain_omega = .25 * gain_mu * gain_mu # critically damped
+ self.clocker = gr.clock_recovery_mm_cc( self.sps,
+ gain_omega,
+ 0.5, #mu
+ gain_mu,
+ 0.3) #omega_relative_limit,
+
+ # configure demodulator
+ # adjust the phase gain for sampling rate
+ self.demod = gr.quadrature_demod_cf(self.sps);
+
+ self.burst = gsm.burst_ff(self.burst_cb)
+ self.connect(self.filter, self.clocker, self.demod, self.burst)
+
+####################
def setup_c_flowgraph(self):
#use the sink version if burst scope not selected
- if self.scopes.count("b"):
- self.burst = gsm.burst_cf(self.burst_cb,input_rate)
- else:
- self.burst = gsm.burst_sink_c(self.burst_cb,input_rate)
+# if self.scopes.count("b"):
+# self.burst = gsm.burst_cf(self.burst_cb,self.input_rate)
+# else:
+# self.burst = gsm.burst_sink_c(self.burst_cb,self.input_rate)
+
+ self.burst = gsm.burst_cf(self.burst_cb,self.input_rate)
self.connect(self.filter, self.burst)
@@ -418,7 +441,7 @@ class app_flow_graph(stdgui.gui_flow_graph):
#Filter FFT
if self.scopes.count("F"):
- self.filter_fft_scope = fftsink.fft_sink_c (self, self.panel, fft_size=1024, sample_rate=input_rate)
+ self.filter_fft_scope = fftsink.fft_sink_c (self, self.panel, fft_size=1024, sample_rate=self.input_rate)
self.connect(self.filter, self.filter_fft_scope)
#Burst Scope
@@ -433,8 +456,13 @@ class app_flow_graph(stdgui.gui_flow_graph):
self.connect(self.demod, self.demod_scope)
if self.scopes.count("c"):
+ #f_flowgraph
self.clocked_scope = scopesink.scope_sink_f(self, self.panel, sample_rate=self.gsm_symb_rate,v_scale=1)
self.connect(self.clocker, self.clocked_scope)
+ #for testing: f_flowgraph2
+ #self.clocked_scope = scopesink.scope_sink_c(self, self.panel, sample_rate=self.gsm_symb_rate,v_scale=1)
+ #self.connect(self.clocker, self.clocked_scope)
+ #self.connect((self.clocker,1),(self.clocked_scope,1))
####################
def configure_burst_decoder(self):
@@ -496,6 +524,7 @@ class app_flow_graph(stdgui.gui_flow_graph):
self.setup_c_flowgraph()
elif options.decoder.count("f"):
self.setup_f_flowgraph()
+ #self.setup_f_flowgraph2()
self.configure_burst_decoder()
@@ -630,6 +659,16 @@ class app_flow_graph(stdgui.gui_flow_graph):
print >> out, 'known_count: ',n_known
if n_total:
print >> out, '%known: ', 100.0 * n_known / n_total
+
+ #timing
+ if self.options.decoder.count("c"):
+ omega = self.burst.get_omega()
+ else:
+ omega = self.clocker.omega()
+
+ percent_sps = omega / self.sps
+ print >> out, 'omega: %f (%f / %f)' % (omega,self.sps,percent_sps)
+
print >> out, ""
####################
personal git repositories of Harald Welte. Your mileage may vary