diff options
-rw-r--r-- | gsm-tvoid/src/lib/Makefile.am | 4 | ||||
-rwxr-xr-x | gsm-tvoid/src/lib/gsm.i | 7 | ||||
-rwxr-xr-x | gsm-tvoid/src/lib/gsm_burst.cc | 2 | ||||
-rwxr-xr-x | gsm-tvoid/src/lib/gsm_burst.h | 8 | ||||
-rwxr-xr-x | gsm-tvoid/src/lib/gsm_burst_cf.cc | 58 | ||||
-rwxr-xr-x | gsm-tvoid/src/lib/gsm_burst_cf.h | 21 | ||||
-rw-r--r-- | gsm-tvoid/src/lib/mm_c.cc | 73 | ||||
-rw-r--r-- | gsm-tvoid/src/lib/mm_c.h | 48 | ||||
-rw-r--r-- | gsm-tvoid/src/lib/mm_f.cc | 55 | ||||
-rw-r--r-- | gsm-tvoid/src/lib/mm_f.h | 34 | ||||
-rwxr-xr-x | gsm-tvoid/src/python/gsm_scan.py | 61 |
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, "" #################### |