diff options
-rw-r--r--[-rwxr-xr-x] | gsm-tvoid/src/lib/Makefile.am | 24 | ||||
-rwxr-xr-x | gsm-tvoid/src/lib/gsm.i | 16 | ||||
-rwxr-xr-x | gsm-tvoid/src/lib/gsm_burst.cc | 63 | ||||
-rwxr-xr-x | gsm-tvoid/src/lib/gsm_burst.h | 26 | ||||
-rwxr-xr-x | gsm-tvoid/src/lib/gsm_burst_cf.cc | 70 | ||||
-rwxr-xr-x | gsm-tvoid/src/lib/gsm_burst_cf.h | 21 | ||||
-rwxr-xr-x[-rw-r--r--] | gsm-tvoid/src/lib/gsm_burst_ff_single.cc | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | gsm-tvoid/src/lib/gsm_burst_ff_single.h | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | gsm-tvoid/src/lib/gsm_burst_sink_c.cc | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | gsm-tvoid/src/lib/gsm_burst_sink_c.h | 0 | ||||
-rw-r--r--[-rwxr-xr-x] | gsm-tvoid/src/lib/gsm_constants.h | 2 | ||||
-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 | 80 |
16 files changed, 407 insertions, 105 deletions
diff --git a/gsm-tvoid/src/lib/Makefile.am b/gsm-tvoid/src/lib/Makefile.am index e8f093f..fa876b2 100755..100644 --- a/gsm-tvoid/src/lib/Makefile.am +++ b/gsm-tvoid/src/lib/Makefile.am @@ -37,17 +37,19 @@ ourpython_PYTHON = \ ourlib_LTLIBRARIES = _gsm.la # These are the source files that go into the shared library -_gsm_la_SOURCES = \ +_gsm_la_SOURCES = \ fire_crc.c \ gsmstack.c \ - interleave.c \ + interleave.c \ conv.c \ sch.c \ cch.c \ gsm.cc \ - gsm_burst.cc \ - gsm_burst_ff.cc \ - gsm_burst_cf.cc \ + gsm_burst.cc \ + gsm_burst_ff.cc \ + mm_c.cc \ + mm_f.cc \ + gsm_burst_cf.cc \ gsm_burst_sink_c.cc @@ -64,18 +66,20 @@ gsm.cc gsm.py: $(LOCAL_IFILES) $(ALL_IFILES) $(SWIG) $(SWIGPYTHONARGS) -module gsm -o gsm.cc $(LOCAL_IFILES) # These headers get installed in ${prefix}/include/gnuradio -grinclude_HEADERS = \ +grinclude_HEADERS = \ fire_crc.h \ gsm_burst.h \ gsmstack.h \ - interleave.h \ + interleave.h \ conv.h \ sch.h \ cch.h \ system.h \ - gsm_burst_ff.h \ - gsm_burst_cf.h \ - gsm_burst_sink_c.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..af644d9 100755 --- a/gsm-tvoid/src/lib/gsm.i +++ b/gsm-tvoid/src/lib/gsm.i @@ -16,6 +16,9 @@ // ---------------------------------------------------------------- +#define OPT_TEST_HOP_SPEED 0x00000001 + + #define PRINT_NOTHING 0x00000000 #define PRINT_EVERYTHING 0x7FFFFFFF //7 for SWIG overflow check work around #define PRINT_BITS 0x00000001 @@ -32,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 @@ -66,6 +69,8 @@ public: unsigned long d_clock_options; unsigned long d_print_options; + unsigned long d_test_options; + EQ_TYPE d_equalizer_type; //stats @@ -80,9 +85,13 @@ public: long next_arfcn; + //hop testing + long d_hop_good_arfcn; + long d_hop_bad_arfcn; + 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 +113,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..c52ff38 100755 --- a/gsm-tvoid/src/lib/gsm_burst.cc +++ b/gsm-tvoid/src/lib/gsm_burst.cc @@ -17,6 +17,9 @@ gsm_burst::gsm_burst (gr_feval_ll *t) : p_tuner(t), d_clock_options(DEFAULT_CLK_OPTS), d_print_options(0), + d_test_options(0), + d_hop_good_arfcn(1), + d_hop_bad_arfcn(2), d_equalizer_type(EQ_FIXED_DFE) { @@ -33,15 +36,17 @@ gsm_burst::gsm_burst (gr_feval_ll *t) : tsync[i] = 2.0*SYNC_BITS[i] - 1.0; } + diff_encode(tsync,corr_sync,N_SYNC_BITS); + +/* fprintf(stderr," Sync: "); print_bits(tsync,N_SYNC_BITS); fprintf(stderr,"\n"); - diff_encode(tsync,corr_sync,N_SYNC_BITS); fprintf(stderr,"DSync: "); print_bits(corr_sync,N_SYNC_BITS); fprintf(stderr,"\n\n"); - +*/ for (int i=0; i < 10; i++) { for (int j=0; j < N_TRAIN_BITS; j++) { @@ -49,9 +54,11 @@ gsm_burst::gsm_burst (gr_feval_ll *t) : } diff_encode(tsync,corr_train_seq[i],N_TRAIN_BITS); +/* fprintf(stderr,"TSC%d: ",i); print_bits(corr_train_seq[i],N_TRAIN_BITS); fprintf(stderr,"\n"); +*/ } /* Initialize GSM Stack */ @@ -103,7 +110,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; @@ -650,7 +657,6 @@ int gsm_burst::get_burst(void) d_ts = 0; //TODO: check this break; case SCH: -#ifndef TEST_TUNE_TIMING //TODO: it would be better to adjust tuning on first FCCH (for better SCH detection), // but tuning can run away with false FCCHs // Some logic to retune back to original offset on false FCCH might work @@ -661,7 +667,6 @@ int gsm_burst::get_burst(void) p_tuner->calleval(BURST_CB_SYNC_OFFSET); } -#endif d_burst_count++; d_sch_count++; d_last_sch = d_burst_count; @@ -704,35 +709,39 @@ int gsm_burst::get_burst(void) ///////////////////// //start tune testing -#ifdef TEST_TUNE_TIMING - +#ifdef TEST_HOP_SPEED static int good_count = -1; //-1: wait sch, >=0: got sch, counting static int wait_count = 0; + + if (OPT_TEST_HOP_SPEED & d_test_options ) { + //have we started counting? + if ( good_count >= 0 ) { + + if (UNKNOWN == d_burst_type) { + if (good_count >= 0) { + fprintf(stdout,"good_count: %d\n",good_count); - if (UNKNOWN == d_burst_type) { - if (good_count >= 0) { - fprintf(stdout,"good_count: %d\n",good_count); - - if (p_tuner) { - next_arfcn = TEST_TUNE_GOOD_ARFCN; - p_tuner->calleval(BURST_CB_TUNE); + if (p_tuner) { + next_arfcn = d_hop_good_arfcn; + p_tuner->calleval(BURST_CB_TUNE); + } + } + good_count = -1; // start again at resync + + } else { + //count good bursts + good_count++; } - } - good_count = -1; // start again at resync - - } else { - - if (good_count >= 0 ) { - good_count++; - } - - if (SCH == d_burst_type) { - if ((good_count < 0) && (++wait_count > 20)) { // get some good syncs before trying again - fprintf(stdout,"restarting good_count\n"); + + } else { + //haven't started counting + // get some good syncs before trying again + if ((SCH == d_burst_type) && (++wait_count > 5)) { + //fprintf(stdout,"restarting good_count\n"); good_count = wait_count = 0; //tune away if (p_tuner) { - next_arfcn = TEST_TUNE_EMPTY_ARFCN; + next_arfcn = d_hop_bad_arfcn; p_tuner->calleval(BURST_CB_TUNE); } } diff --git a/gsm-tvoid/src/lib/gsm_burst.h b/gsm-tvoid/src/lib/gsm_burst.h index 48fafac..056516c 100755 --- a/gsm-tvoid/src/lib/gsm_burst.h +++ b/gsm-tvoid/src/lib/gsm_burst.h @@ -13,10 +13,10 @@ //Testing Modes //Tune test measures hopping latency by hopping between good and empty ARFCNs -#undef TEST_TUNE_TIMING -#define TEST_TUNE_GOOD_ARFCN 658 -#define TEST_TUNE_EMPTY_ARFCN 655 +#define TEST_HOP_SPEED +//Test Options +#define OPT_TEST_HOP_SPEED 0x00000001 //Console printing options #define PRINT_NOTHING 0x00000000 @@ -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 @@ -59,7 +59,8 @@ // G T D1 TS D2 T G // Start ^ -#define MAX_SYNC_WAIT 32 //Number of missed bursts before reverting to WAIT_FCCH. +//#define MAX_SYNC_WAIT 32 //Number of missed bursts before reverting to WAIT_FCCH. +#define MAX_SYNC_WAIT 64 //Number of missed bursts before reverting to WAIT_FCCH. #define MAX_CORR_DIST 7 // 4 + 3 = 1/2 GUARD + TAIL #define SCH_CORR_THRESHOLD 0.80 @@ -75,6 +76,7 @@ enum EQ_TYPE { EQ_ADAPTIVE_LINEAR, EQ_FIXED_DFE, EQ_ADAPTIVE_DFE, + EQ_ADAPT_TRAINING, EQ_VITERBI }; @@ -123,8 +125,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; @@ -166,11 +168,15 @@ public: long d_total_count; ////// Options + unsigned long d_test_options; unsigned long d_clock_options; unsigned long d_print_options; EQ_TYPE d_equalizer_type; - - + + //Hop speed info + long d_hop_good_arfcn; + long d_hop_bad_arfcn; + //Methods void full_reset(void); @@ -178,7 +184,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..caddb5f 100755 --- a/gsm-tvoid/src/lib/gsm_burst_cf.cc +++ b/gsm-tvoid/src/lib/gsm_burst_cf.cc @@ -20,24 +20,30 @@ 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_relative_rate( mm.d_omega / 156); + set_relative_rate( 1.0 / (mm.d_omega * 156) ); + set_history(4); //need history for interpolator } @@ -49,12 +55,13 @@ gsm_burst_cf::~gsm_burst_cf () void gsm_burst_cf::forecast (int noutput_items, gr_vector_int &ninput_items_required) { - 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(); + unsigned ninputs = ninput_items_required.size (); + for (unsigned i = 0; i < ninputs; i++) { + ninput_items_required[i] = noutput_items * (int)ceil(mm.d_omega) * TS_BITS; + //fprintf(stderr,"forecast[%d]: %d = %d\n",i,noutput_items,ninput_items_required[i]); + } } - int gsm_burst_cf::general_work (int noutput_items, gr_vector_int &ninput_items, gr_vector_const_void_star &input_items, @@ -65,27 +72,30 @@ 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); + //fprintf(stderr,"#i=%d/#o=%d",ninput,noutput_items); int ni = ninput - d_interp->ntaps() - 16; // interpolator need -4/+3 samples NTAPS = 8 , - 16 for safety margin 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 +121,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 +140,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/gsm_burst_ff_single.cc b/gsm-tvoid/src/lib/gsm_burst_ff_single.cc index ff6c354..ff6c354 100644..100755 --- a/gsm-tvoid/src/lib/gsm_burst_ff_single.cc +++ b/gsm-tvoid/src/lib/gsm_burst_ff_single.cc diff --git a/gsm-tvoid/src/lib/gsm_burst_ff_single.h b/gsm-tvoid/src/lib/gsm_burst_ff_single.h index 553fe65..553fe65 100644..100755 --- a/gsm-tvoid/src/lib/gsm_burst_ff_single.h +++ b/gsm-tvoid/src/lib/gsm_burst_ff_single.h diff --git a/gsm-tvoid/src/lib/gsm_burst_sink_c.cc b/gsm-tvoid/src/lib/gsm_burst_sink_c.cc index 58787bb..58787bb 100644..100755 --- a/gsm-tvoid/src/lib/gsm_burst_sink_c.cc +++ b/gsm-tvoid/src/lib/gsm_burst_sink_c.cc diff --git a/gsm-tvoid/src/lib/gsm_burst_sink_c.h b/gsm-tvoid/src/lib/gsm_burst_sink_c.h index 1197a2c..1197a2c 100644..100755 --- a/gsm-tvoid/src/lib/gsm_burst_sink_c.h +++ b/gsm-tvoid/src/lib/gsm_burst_sink_c.h diff --git a/gsm-tvoid/src/lib/gsm_constants.h b/gsm-tvoid/src/lib/gsm_constants.h index c404b57..942736d 100755..100644 --- a/gsm-tvoid/src/lib/gsm_constants.h +++ b/gsm-tvoid/src/lib/gsm_constants.h @@ -13,7 +13,7 @@ #define USEFUL_BITS 142 //(2*DATA_BITS + N_TRAIN_BITS )
#define FCCH_BITS USEFUL_BITS
-#define TS_BITS (TAIL_BITS+USEFUL_BITS+TAIL_BITS+GUARD_BITS) //a full TS
+#define TS_BITS (TAIL_BITS+USEFUL_BITS+TAIL_BITS+GUARD_BITS) //a full TS (156)
#define TS_PER_FRAME 8
#define FRAME_BITS (TS_PER_FRAME * TS_BITS + 2) // +2 for extra 8*0.25 guard bits
#define FCCH_POS TAIL_BITS
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..fab6ce8 100755 --- a/gsm-tvoid/src/python/gsm_scan.py +++ b/gsm-tvoid/src/python/gsm_scan.py @@ -39,7 +39,6 @@ class burst_callback(gr.feval_ll): def eval(self, x): #print "burst_callback: eval(",x,")\n"; try: - #TODO: rework so this will work on file input if gsm.BURST_CB_SYNC_OFFSET == x: #print "burst_callback: SYNC_OFFSET\n"; if self.fg.options.tuning.count("o"): @@ -72,7 +71,7 @@ class burst_callback(gr.feval_ll): self.fg.offset -= self.fg.mean_offset self.fg.set_channel(self.fg.channel) - elif gsm.BURST_CB_TUNE == x and self.fg.options.tuning.count("h"): + elif gsm.BURST_CB_TUNE == x: #print "burst_callback: BURST_CB_TUNE: ARFCN: ", self.fg.burst.next_arfcn, "\n"; if self.fg.options.tuning.count("h"): #print "burst_callback: tuning.\n"; @@ -173,10 +172,10 @@ 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]") + help="Type of equalizer to use. none, fixed-dfe, fixed-linear [default=%default]") parser.add_option("-t", "--timing", type="string", default="cn", help="Type of timing techniques to use. [default=%default] \n" + "(n)one, (c)orrelation track, (q)uarter bit, (f)ull04 ") @@ -214,13 +213,20 @@ class app_flow_graph(stdgui.gui_flow_graph): parser.add_option("-g", "--gain", type="eng_float", default=None, help="Set gain in dB (default is midpoint)") parser.add_option("-c", "--channel", type="int", default=1, - help="Tune to GSM ARFCN. Overrides --freq") + help="Tune to GSM ARFCN.") parser.add_option("-r", "--region", type="string", default="u", help="Frequency bands to use for channels. (u)s or (e)urope [default=%default]") + #testing options + parser.add_option("--test-hop-speed",action="store_true", dest="test_hop_speed", + help="Test hopping speed.") + parser.add_option("--hopgood", type="int", default=658, + help="Good ARFCN [default=%default]") + parser.add_option("--hopbad", type="int", default=655, + help="Emtpy ARFCN [default=%default]") (options, args) = parser.parse_args() - if (len(args) != 0) or (not (options.channel or options.inputfile)): + if (len(args) != 0): parser.print_help() sys.exit(1) @@ -228,6 +234,9 @@ class app_flow_graph(stdgui.gui_flow_graph): # print "datafile option cannot be used with USRP options." # sys.exit(1) + if options.test_hop_speed: + options.tuning = 'h' #hopping only, no offset + options.channel = options.hopgood self.options = options self.scopes = options.scopes @@ -280,9 +289,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,7 +298,10 @@ class app_flow_graph(stdgui.gui_flow_graph): elif options.print_console.count('b'): popts |= gsm.PRINT_BITS - print "Print flags: 0x%8.8x\n" %(popts) + 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,12 +366,16 @@ 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 #################### def setup_filter(self): + #test w/o filter (for buffer latency) + #self.filter = self.source + #return + options = self.options # configure channel filter @@ -394,7 +407,7 @@ 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) @@ -402,10 +415,12 @@ class app_flow_graph(stdgui.gui_flow_graph): #################### 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 +433,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,15 +448,20 @@ 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): options = self.options # equalizer - eq_types = {'none': gsm.EQ_NONE, 'fixed-dfe': gsm.EQ_FIXED_DFE} + eq_types = {'none': gsm.EQ_NONE, 'fixed-dfe': gsm.EQ_FIXED_DFE, 'fixed-linear': gsm.EQ_FIXED_LINEAR } self.burst.d_equalizer_type = eq_types[options.equalizer] # timing @@ -458,6 +478,20 @@ class app_flow_graph(stdgui.gui_flow_graph): self.burst.d_clock_options = topts + #test modes + testopts = 0 + + if options.test_hop_speed: + testopts |= gsm.OPT_TEST_HOP_SPEED + self.burst.d_hop_good_arfcn = options.hopgood + self.burst.d_hop_bad_arfcn = options.hopbad + + print "!!!!! Enabling Hop Speed Testing (good=%d, bad=%d) !!!!!" % (options.hopgood,options.hopbad) + + self.burst.d_test_options = testopts + #print "Test Options: 0x%8.8x" % (self.burst.d_test_options) + + #################### def setup_flowgraph(self): @@ -630,6 +664,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, "" #################### |