From de1460aa9438f6a466a5fe4455ed968033d4ecdb Mon Sep 17 00:00:00 2001 From: tvoid Date: Tue, 15 Apr 2008 15:09:00 -0600 Subject: added m&m to burst_cf doubles to floats --- gsm-tvoid/src/lib/Makefile.am | 4 +++ gsm-tvoid/src/lib/gsm.i | 7 ++-- gsm-tvoid/src/lib/gsm_burst.cc | 2 +- gsm-tvoid/src/lib/gsm_burst.h | 8 ++--- gsm-tvoid/src/lib/gsm_burst_cf.cc | 58 ++++++++++++++++--------------- gsm-tvoid/src/lib/gsm_burst_cf.h | 21 +++++++---- gsm-tvoid/src/lib/mm_c.cc | 73 +++++++++++++++++++++++++++++++++++++++ gsm-tvoid/src/lib/mm_c.h | 48 +++++++++++++++++++++++++ gsm-tvoid/src/lib/mm_f.cc | 55 +++++++++++++++++++++++++++++ gsm-tvoid/src/lib/mm_f.h | 34 ++++++++++++++++++ gsm-tvoid/src/python/gsm_scan.py | 61 ++++++++++++++++++++++++++------ 11 files changed, 319 insertions(+), 52 deletions(-) create mode 100644 gsm-tvoid/src/lib/mm_c.cc create mode 100644 gsm-tvoid/src/lib/mm_c.h create mode 100644 gsm-tvoid/src/lib/mm_f.cc create mode 100644 gsm-tvoid/src/lib/mm_f.h 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 -#include +#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 + +#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 + +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, "" #################### -- cgit v1.2.3