From 0a452fcc8e030f5bdb7187e1db7182cfc488aa31 Mon Sep 17 00:00:00 2001 From: Piotr Krysik Date: Thu, 28 May 2009 19:39:56 +0200 Subject: cleanup of unneeded test code, separation of longer parts of fch_search into two functions, addidion of 'synchronized' state and reading of sch in this state --- src/lib/gsm_constants.h | 10 +- src/lib/gsm_receiver_cf.cc | 333 +++++++++++++++++++++++---------------------- src/lib/gsm_receiver_cf.h | 203 ++++++++++++++++++++++++--- src/python/gsm_findfcch.py | 108 --------------- 4 files changed, 362 insertions(+), 292 deletions(-) delete mode 100755 src/python/gsm_findfcch.py diff --git a/src/lib/gsm_constants.h b/src/lib/gsm_constants.h index 9ba70cb..d08df17 100644 --- a/src/lib/gsm_constants.h +++ b/src/lib/gsm_constants.h @@ -6,7 +6,7 @@ //Burst timing #define TAIL_BITS 3 -#define GUARD_BITS 8 //8.25 +#define GUARD_BITS 8.25 #define DATA_BITS 58 //size of 1 data block in normal burst #define N_TRAIN_BITS 26 #define N_SYNC_BITS 64 @@ -16,7 +16,7 @@ #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 FRAME_BITS (TS_PER_FRAME * TS_BITS) #define FCCH_POS TAIL_BITS #define SYNC_POS 39 #define TRAIN_POS 58 @@ -25,6 +25,8 @@ #define FCCH_HITS_NEEDED (USEFUL_BITS - 4) #define FCCH_MAX_MISSES 1 +#define CHAN_IMP_RESP_LENGTH 5 + static const int SYNC_BITS[] = { 1, 0, 1, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, @@ -32,6 +34,10 @@ static const int SYNC_BITS[] = { 0, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 1, 1 }; +const unsigned FCCH_FRAMES[] = {0,10,20,30,40}; +const unsigned SCH_FRAMES[] = {1,11,21,31,41}; + + // Sync : .+...++.+..+++.++++++.++++++....++.+..+.+.+++.+.+...+..++++..+.. // Diff Encoded Sync: .++..+.+++.+..++.....++.....+...+.+++.+++++..+++++..++.+...+.++. diff --git a/src/lib/gsm_receiver_cf.cc b/src/lib/gsm_receiver_cf.cc index 578cd80..089a563 100644 --- a/src/lib/gsm_receiver_cf.cc +++ b/src/lib/gsm_receiver_cf.cc @@ -38,6 +38,9 @@ #define FCCH_BUFFER_SIZE (FCCH_HITS_NEEDED) #define SYNC_SEARCH_RANGE 40 +//TODO !! - move this methods to some else place + +// - move it to some else place !! typedef std::list list_float; typedef std::vector vector_float; @@ -62,14 +65,15 @@ gsm_receiver_cf::gsm_receiver_cf(gr_feval_dd *tuner, int osr) gr_make_io_signature(MIN_IN, MAX_IN, sizeof(gr_complex)), gr_make_io_signature(MIN_OUT, MAX_OUT, 142 * sizeof(float))), d_OSR(osr), + d_chan_imp_length(CHAN_IMP_RESP_LENGTH), d_tuner(tuner), d_counter(0), d_fcch_start_pos(0), d_freq_offset(0), - d_state(first_fcch_search), - d_fcch_count(0), //!! - d_x_temp(0),//!! - d_x2_temp(0)//!! + d_state(first_fcch_search) +// d_fcch_count(0), //!! +// d_x_temp(0),//!! +// d_x2_temp(0)//!! { gmsk_mapper(SYNC_BITS, d_sch_training_seq, N_SYNC_BITS); } @@ -98,6 +102,7 @@ gsm_receiver_cf::general_work(int noutput_items, float prev_freq_offset; switch (d_state) { + //bootstrapping case first_fcch_search: if (find_fcch_burst(in, ninput_items[0])) { set_frequency(d_freq_offset); @@ -113,7 +118,6 @@ gsm_receiver_cf::general_work(int noutput_items, prev_freq_offset = d_freq_offset; if (find_fcch_burst(in, ninput_items[0])) { if (abs(d_freq_offset) > 100) { - float mean_freq_offset = (prev_freq_offset + d_freq_offset) / 2; set_frequency(d_freq_offset); } produced_out = 0; @@ -126,15 +130,59 @@ gsm_receiver_cf::general_work(int noutput_items, case sch_search: if (find_sch_burst(in, ninput_items[0], out)) { -// d_state = read_bcch; - d_state = next_fcch_search;//read_bcch; + d_channel_conf.set_multiframe_type(0, multiframe_51); + d_channel_conf.set_burst_types(0, FCCH_FRAMES, sizeof(FCCH_FRAMES) / sizeof(unsigned), fcch_burst); + d_channel_conf.set_burst_types(0, SCH_FRAMES, sizeof(SCH_FRAMES) / sizeof(unsigned), sch_burst); + d_burst_nr++; + d_state = synchronized; } else { d_state = sch_search; } break; - case read_bcch: - consume_each(ninput_items[0]); + //in this state receiver is synchronized and it processes bursts according to burst type for given burst number + case synchronized: { + gr_complex chan_imp_resp[100];//!! + burst_type b_type = d_channel_conf.get_burst_type(d_burst_nr); + int burst_start; + int offset = 0; + int to_consume = 0; + unsigned char output_binary[BURST_SIZE]; + + switch (b_type) { + case fcch_burst: { + + } + break; + case sch_burst: { + int t1, t2, t3, d_ncc, d_bcc; + burst_start = get_sch_chan_imp_resp(in, chan_imp_resp); + detect_burst(in, chan_imp_resp, burst_start, output_binary); + if(decode_sch(&output_binary[3], &t1, &t2, &t3, &d_ncc, &d_bcc) == 0){ +// d_burst_nr.set(t1, t2, t3, 0); + printf("bcc: %d, ncc: %d, t1: %d, t2: %d, t3: %d\n", d_bcc, d_ncc, t1, t2, t3); + offset = burst_start - GUARD_BITS * d_OSR; + to_consume += offset; + } + std::cout << offset << std::endl; + } + break; + case normal_burst: + + break; + + case rach_burst: + break; + case dummy: + break; + case empty: + break; + } + + d_burst_nr++; + to_consume += floor(TS_BITS * d_OSR); + consume_each(to_consume); + } break; } @@ -158,7 +206,6 @@ bool gsm_receiver_cf::find_fcch_burst(const gr_complex *in, const int nitems) int sample_number = 0; bool end = false; bool result = false; -// float mean=0, phase_offset=0, freq_offset=0; circular_buffer_float::iterator buffer_iter; enum states { @@ -208,7 +255,6 @@ bool gsm_receiver_cf::find_fcch_burst(const gr_complex *in, const int nitems) if ((miss_count >= FCCH_MAX_MISSES * d_OSR) && (hit_count <= FCCH_HITS_NEEDED * d_OSR)) { fcch_search_state = init; - //DCOUT("hit_count: " << hit_count << " miss_count: " << miss_count << " d_counter: " << d_counter); continue; } else if (((miss_count >= FCCH_MAX_MISSES * d_OSR) && (hit_count > FCCH_HITS_NEEDED * d_OSR)) || (hit_count > 2 * FCCH_HITS_NEEDED * d_OSR)) { fcch_search_state = fcch_found; @@ -241,18 +287,15 @@ bool gsm_receiver_cf::find_fcch_burst(const gr_complex *in, const int nitems) } phase_diff = compute_phase_diff(in[sample_number], in[sample_number-1]); -// std::cout << phase_diff << "\n"; phase_diff_buffer.push_back(phase_diff); fcch_search_state = found_something; break; case fcch_found: - DCOUT("znalezione fcch na pozycji" << d_counter + start_pos); + DCOUT("fcch found on position: " << d_counter + start_pos); to_consume = start_pos + FCCH_HITS_NEEDED * d_OSR + 1; -// mean = d_best_sum / FCCH_HITS_NEEDED; -// phase_offset = mean - (M_PI / 2); -// freq_offset = phase_offset * 1625000.0 / (12.0 * M_PI); + d_fcch_start_pos = d_counter + start_pos; compute_freq_offset(); end = true; @@ -281,13 +324,13 @@ double gsm_receiver_cf::compute_freq_offset() freq_offset = phase_offset * 1625000.0 / (12.0 * M_PI); d_freq_offset -= freq_offset; - d_fcch_count++; - d_x_temp += freq_offset; - d_x2_temp += freq_offset * freq_offset; - d_mean = d_x_temp / d_fcch_count; +// d_fcch_count++; +// d_x_temp += freq_offset; +// d_x2_temp += freq_offset * freq_offset; +// d_mean = d_x_temp / d_fcch_count; - DCOUT("freq_offset: " << freq_offset );//" d_best_sum: " << d_best_sum -// DCOUT("wariancja: " << sqrt((d_x2_temp / d_fcch_count - d_mean * d_mean)) << " fcch_count:" << d_fcch_count << " d_mean: " << d_mean); + DCOUT("freq_offset: " << freq_offset );//" d_best_sum: " << d_best_sum +// DCOUT("wariance: " << sqrt((d_x2_temp / d_fcch_count - d_mean * d_mean)) << " fcch_count:" << d_fcch_count << " d_mean: " << d_mean); return freq_offset; } @@ -305,41 +348,23 @@ inline float gsm_receiver_cf::compute_phase_diff(gr_complex val1, gr_complex val bool gsm_receiver_cf::find_sch_burst(const gr_complex *in, const int nitems , float *out) { -// int sample_number = 0; int to_consume = 0; bool end = false; bool result = false; int sample_nr_near_sch_start = d_fcch_start_pos + (FRAME_BITS - SAFETY_MARGIN) * d_OSR; - vector_complex correlation_buffer; - vector_float power_buffer; - vector_float window_energy_buffer; - int strongest_window_nr; - int chan_imp_resp_center; - float max_correlation = 0; + gr_complex chan_imp_resp[CHAN_IMP_RESP_LENGTH*d_OSR]; +// vector_complex correlation_buffer; +// vector_float power_buffer; +// vector_float window_energy_buffer; enum states { - start, reach_sch, find_sch_start, search_not_finished, sch_found + start, reach_sch, find_sch_start, detect_and_decode_sch, search_not_finished, sch_found } sch_search_state; sch_search_state = start; - //!!!! - int chan_imp_length = 5; - //!!!! - gr_complex chan_imp_resp[100]; - gr_complex rhh_temp[100]; - gr_complex rhh[6]; - gr_complex filtered_burst[148]; - //!!!! - int fn_o; - int bsic_o; + int t1, t2, t3; int burst_start = 0; - unsigned int stop_states[2] = {4,12}; - float output[BURST_SIZE]; unsigned char output_binary[BURST_SIZE]; - - float energy = 0; - bool loop_end = false; - vector_float::iterator iter; while (!end) { switch (sch_search_state) { @@ -362,115 +387,16 @@ bool gsm_receiver_cf::find_sch_burst(const gr_complex *in, const int nitems , fl break; case find_sch_start: -// DCOUT("find_sch_start d_counter" << d_counter); - for (int ii = SYNC_POS * d_OSR; ii < (SYNC_POS + SYNC_SEARCH_RANGE)*d_OSR; ii++) { - to_consume++; - gr_complex correlation = correlate_sequence(&d_sch_training_seq[5], &in[ii], N_SYNC_BITS - 10); - correlation_buffer.push_back(correlation); // tylko do znalezienia odp imp kanału - power_buffer.push_back(pow(abs(correlation), 2)); - if (abs(correlation) > 30000 / 54) { -// DCOUT("znaleziono środek sch na pozycji: " << ii - SYNC_POS * d_OSR); - } - } - - //compute window energies - - iter = power_buffer.begin(); - while (iter != power_buffer.end()) { - vector_float::iterator iter_ii = iter; - energy = 0; - - for (int ii = 0; ii < (chan_imp_length)*d_OSR; ii++, iter_ii++) { - if (iter_ii == power_buffer.end()) { - loop_end = true; - break; - } - energy += (*iter_ii); - } -// std::cout << "\n"; - - if (loop_end) { - break; - } - iter++; -// std::cout << energy << "\n"; - window_energy_buffer.push_back(energy); - } - - strongest_window_nr = max_element(window_energy_buffer.begin(), window_energy_buffer.end()) - window_energy_buffer.begin(); - d_channel_imp_resp.clear(); - -// std::cout << "# name: h_est\n" ; -// std::cout << "# type: complex matrix\n" ; -// std::cout << "# rows: 1\n" ; -// std::cout << "# columns: " << (chan_imp_length)*d_OSR << "\n"; - - max_correlation = 0; - for (int ii = 0; ii < (chan_imp_length)*d_OSR; ii++) { - gr_complex correlation = correlation_buffer[strongest_window_nr + ii]; - if (abs(correlation) > max_correlation) { - chan_imp_resp_center = ii; - max_correlation = abs(correlation); - } -// std::cout << correlation << " "; - d_channel_imp_resp.push_back(correlation); - chan_imp_resp[ii] = correlation; - } -// DCOUT("\nSrodek odp_imp:" << chan_imp_resp_center ); - - autocorrelation(chan_imp_resp, rhh_temp, chan_imp_length*d_OSR); -// std::cout << "\n# name: rhh_temp\n" ; -// std::cout << "# type: complex matrix\n" ; -// std::cout << "# rows: 1\n" ; -// std::cout << "# columns: " << (chan_imp_length)*d_OSR << "\n"; - -// for (int ii = 0; ii < (chan_imp_length)*d_OSR; ii++) { -// std::cout << rhh_temp[ii] << " "; -// } - -// std::cout << "\n# name: Rhh\n" ; -// std::cout << "# type: complex matrix\n" ; -// std::cout << "# rows: 1\n" ; -// std::cout << "# columns: " << (chan_imp_length) << "\n"; - - for (int ii = 0; ii < (chan_imp_length); ii++) { - rhh[ii] = conj(rhh_temp[ii*d_OSR]); -// std::cout << rhh[ii] << " "; - } - -// std::cout << "\n# name: normal_burst\n" ; -// std::cout << "# type: complex matrix\n" ; -// std::cout << "# rows: 1\n" ; -// std::cout << "# columns: " << 156*d_OSR << "\n"; - burst_start = strongest_window_nr + chan_imp_resp_center - 48 * d_OSR - 2 * d_OSR + 2 + SYNC_POS * d_OSR; - for (int ii = 0; ii < 156*d_OSR; ii++) { - gr_complex sample = in[burst_start+ii]; -// std::cout << sample << " "; - } - - mafi(&in[burst_start], 148, chan_imp_resp, chan_imp_length*d_OSR, filtered_burst); - -// std::cout << "\n# name: Y\n" ; -// std::cout << "# type: complex matrix\n" ; -// std::cout << "# rows: 1\n" ; -// std::cout << "# columns: " << 148 << "\n"; - for (int ii = 0; ii < 148; ii++) { - gr_complex filtered_sample = filtered_burst[ii]; -// std::cout << filtered_sample << " "; - } - - viterbi_detector(filtered_burst, 148, rhh, 3, stop_states, 2, output); -// printf("# name: output\n# type: matrix\n# rows: 1\n# columns: 148\n"); - for(int i=0; i0); -// printf(" %d", output_binary[i]); - } -// printf("\n"); - decode_sch(&output_binary[3], &fn_o, &bsic_o); - -// std::cout << "fn: " << fn_o << " bsic: " << bsic_o << "\n"; -// DCOUT("strongest_window_nr: " << strongest_window_nr); + burst_start = get_sch_chan_imp_resp(in, chan_imp_resp); + sch_search_state = detect_and_decode_sch; + break; + case detect_and_decode_sch: + detect_burst(in, chan_imp_resp, burst_start, output_binary); + decode_sch(&output_binary[3], &t1, &t2, &t3, &d_ncc, &d_bcc); + d_burst_nr.set(t1, t2, t3, 0); + printf("bcc: %d, ncc: %d, t1: %d, t2: %d, t3: %d\n", d_bcc, d_ncc, t1, t2, t3); + to_consume += burst_start + BURST_SIZE * d_OSR; sch_search_state = sch_found; break; @@ -491,6 +417,87 @@ bool gsm_receiver_cf::find_sch_burst(const gr_complex *in, const int nitems , fl return result; } +int gsm_receiver_cf::get_sch_chan_imp_resp(const gr_complex *in, gr_complex * chan_imp_resp) +{ + vector_complex correlation_buffer; + vector_float power_buffer; + vector_float window_energy_buffer; + + int strongest_window_nr; + int burst_start = 0; + int chan_imp_resp_center; + float max_correlation = 0; + float energy = 0; + + for (int ii = SYNC_POS * d_OSR; ii < (SYNC_POS + SYNC_SEARCH_RANGE)*d_OSR; ii++) { + gr_complex correlation = correlate_sequence(&d_sch_training_seq[5], &in[ii], N_SYNC_BITS - 10); + correlation_buffer.push_back(correlation); + power_buffer.push_back(pow(abs(correlation), 2)); + } + + //compute window energies + vector_float::iterator iter = power_buffer.begin(); + bool loop_end = false; + while (iter != power_buffer.end()) { + vector_float::iterator iter_ii = iter; + energy = 0; + + for (int ii = 0; ii < (d_chan_imp_length)*d_OSR; ii++, iter_ii++) { + if (iter_ii == power_buffer.end()) { + loop_end = true; + break; + } + energy += (*iter_ii); + } + if (loop_end) { + break; + } + iter++; + window_energy_buffer.push_back(energy); + } + + strongest_window_nr = max_element(window_energy_buffer.begin(), window_energy_buffer.end()) - window_energy_buffer.begin(); + d_channel_imp_resp.clear(); + + max_correlation = 0; + for (int ii = 0; ii < (d_chan_imp_length)*d_OSR; ii++) { + gr_complex correlation = correlation_buffer[strongest_window_nr + ii]; + if (abs(correlation) > max_correlation) { + chan_imp_resp_center = ii; + max_correlation = abs(correlation); + } + d_channel_imp_resp.push_back(correlation); + chan_imp_resp[ii] = correlation; + } + + burst_start = strongest_window_nr + chan_imp_resp_center - 48 * d_OSR - 2 * d_OSR + 2 + SYNC_POS * d_OSR; + return burst_start; +} + +void gsm_receiver_cf::detect_burst(const gr_complex * in, gr_complex * chan_imp_resp, int burst_start, unsigned char * output_binary) +{ + float output[BURST_SIZE]; + gr_complex rhh_temp[CHAN_IMP_RESP_LENGTH*d_OSR]; + gr_complex rhh[CHAN_IMP_RESP_LENGTH]; + gr_complex filtered_burst[BURST_SIZE]; + int start_state = 3; + unsigned int stop_states[2] = {4, 12}; + + autocorrelation(chan_imp_resp, rhh_temp, d_chan_imp_length*d_OSR); + for (int ii = 0; ii < (d_chan_imp_length); ii++) { + rhh[ii] = conj(rhh_temp[ii*d_OSR]); + } + + mafi(&in[burst_start], BURST_SIZE, chan_imp_resp, d_chan_imp_length*d_OSR, filtered_burst); + + viterbi_detector(filtered_burst, BURST_SIZE, rhh, start_state, stop_states, 2, output); + + for (int i = 0; i < BURST_SIZE ; i++) { + output_binary[i] = (output[i] > 0); + } +} + +//TODO consider placing this funtion in a separate class for signal processing void gsm_receiver_cf::gmsk_mapper(const int * input, gr_complex * output, int ninput) { gr_complex j = gr_complex(0.0, 1.0); @@ -511,6 +518,7 @@ void gsm_receiver_cf::gmsk_mapper(const int * input, gr_complex * output, int ni } } +//TODO consider use of some generalized function for correlation and placing it in a separate class for signal processing gr_complex gsm_receiver_cf::correlate_sequence(const gr_complex * sequence, const gr_complex * input_signal, int length) { gr_complex result(0.0, 0.0); @@ -521,7 +529,7 @@ gr_complex gsm_receiver_cf::correlate_sequence(const gr_complex * sequence, cons result += sequence[ii] * conj(input_signal[sample_number]); } - result = result/gr_complex(length, 0); + result = result / gr_complex(length, 0); return result; } @@ -543,6 +551,7 @@ gr_complex gsm_receiver_cf::correlate_sequence(const gr_complex * sequence, cons // } //oblicza dodatnią część autokorelacji +//TODO consider placing this funtion in a separate class for signal processing inline void gsm_receiver_cf::autocorrelation(const gr_complex * input, gr_complex * out, int length) { int i, k; @@ -554,29 +563,23 @@ inline void gsm_receiver_cf::autocorrelation(const gr_complex * input, gr_comple } } +//TODO consider use of some generalized function for filtering and placing it in a separate class for signal processing //funkcja matched filter inline void gsm_receiver_cf::mafi(const gr_complex * input, int input_length, gr_complex * filter, int filter_length, gr_complex * output) { int ii = 0, n, a; -// std::cout << "\nfilter:"; -// for(n = 0; n < filter_length; n++) -// { -// std::cout << filter[n] << " "; -// } -// std::cout << "\n"; + for (n = 0; n < input_length; n++) { a = n * d_OSR; output[n] = 0; ii = 0; - + while (ii < filter_length) { if ((a + ii) >= input_length*d_OSR) break; -// if(n==0) -// std::cout << input[a+ii] << " "; output[n] += input[a+ii] * filter[ii]; //!!conj ii++; } - output[n] = output[n]*gr_complex(0,-1);//!!nie powinno tego tu być + output[n] = output[n] * gr_complex(0, -1);//!!this shouldn't be here } } diff --git a/src/lib/gsm_receiver_cf.h b/src/lib/gsm_receiver_cf.h index 20d66da..2bad50e 100644 --- a/src/lib/gsm_receiver_cf.h +++ b/src/lib/gsm_receiver_cf.h @@ -29,19 +29,176 @@ #include +//TODO !! - move this classes to some other place +#include +#include +typedef enum {empty, fcch_burst, sch_burst, normal_burst, rach_burst, dummy} burst_type; +typedef enum {unknown, multiframe_26, multiframe_51} multiframe_type; + +class multiframe_configuration +{ + private: + multiframe_type d_type; + std::vector d_burst_types; + public: + multiframe_configuration() { + d_type = unknown; + fill(d_burst_types.begin(), d_burst_types.end(), empty); + } + +// multiframe_configuration(multiframe_type type, const std::vector & burst_types): +// d_type(type) { +// d_burst_types.resize(burst_types.size()); +// copy(burst_types.begin(), burst_types.end(), d_burst_types.begin()); +// } + +// multiframe_configuration(multiframe_configuration & conf) { +// d_type = conf.d_type; +// copy(conf.d_burst_types.begin(), conf.d_burst_types.end(), d_burst_types.begin()); +// } + + ~multiframe_configuration() {} + + void set_type(multiframe_type type) { + if (type == multiframe_26) { + d_burst_types.resize(26); + } else { + d_burst_types.resize(51); + } + + d_type = type; + } + + void set_burst_type(int nr, burst_type type) { + d_burst_types[nr] = type; + } + + multiframe_type get_type() { + return d_type; + } + + burst_type get_burst_type(int nr) { + return d_burst_types[nr]; + } +}; + +class burst_counter +{ + private: + uint32_t d_t1, d_t2, d_t3, d_timeslot_nr; + public: + burst_counter(): + d_t1(0), + d_t2(0), + d_t3(0), + d_timeslot_nr(0) { + } + + burst_counter(uint32_t t1, uint32_t t2, uint32_t t3, uint32_t timeslot_nr): + d_t1(t1), + d_t2(t2), + d_t3(t3), + d_timeslot_nr(timeslot_nr) { + } + + burst_counter & operator++(int) { + d_timeslot_nr++; + if (d_timeslot_nr == TS_PER_FRAME) { + d_timeslot_nr = 0; + + if ((d_t2 == 25) && (d_t3 == 50)) { + d_t1 = (d_t1 + 1) % (1 << 11); + } + + d_t2 = (d_t2 + 1) % 26; + d_t3 = (d_t3 + 1) % 51; + } + return (*this); + } + + void set(uint32_t t1, uint32_t t2, uint32_t t3, uint32_t timeslot_nr) { + d_t1 = t1; + d_t2 = t2; + d_t3 = t3; + d_timeslot_nr = timeslot_nr; + } + + uint32_t get_t1() { + return d_t1; + } + + uint32_t get_t2() { + return d_t2; + } + + uint32_t get_t3() { + return d_t3; + } + + uint32_t get_timeslot_nr() { + return d_timeslot_nr; + } + + uint32_t get_frame_nr() { + return (51 * 26 * d_t1) + (51 * (((d_t3 + 26) - d_t2) % 26)) + d_t3; + } +}; + +class channel_configuration +{ + private: + multiframe_configuration d_timeslots_descriptions[TS_PER_FRAME]; + public: + channel_configuration() { + for (int i = 0; i < TS_PER_FRAME; i++) { + d_timeslots_descriptions[i].set_type(unknown); + } + } +// void set_timeslot_desc(int timeslot_nr, multiframe_configuration conf){ +// d_timeslots_descriptions[timeslot_nr] = conf; +// } + void set_multiframe_type(int timeslot_nr, multiframe_type type) { + d_timeslots_descriptions[timeslot_nr].set_type(type); + } + + void set_burst_types(int timeslot_nr, const unsigned mapping[], unsigned mapping_size, burst_type b_type) { + unsigned i; + for (i = 0; i < mapping_size; i++) { + d_timeslots_descriptions[timeslot_nr].set_burst_type(mapping[i], b_type); + } + } + + void set_single_burst_type(int timeslot_nr, int burst_nr, burst_type b_type) { + d_timeslots_descriptions[timeslot_nr].set_burst_type(burst_nr, b_type); + } + + burst_type get_burst_type(burst_counter burst_nr); +}; + +burst_type channel_configuration::get_burst_type(burst_counter burst_nr) +{ + uint32_t timeslot_nr = burst_nr.get_timeslot_nr(); + multiframe_type m_type = d_timeslots_descriptions[timeslot_nr].get_type(); + uint32_t nr; + + switch (m_type) { + case multiframe_26: + nr = burst_nr.get_t2(); + break; + case multiframe_51: + nr = burst_nr.get_t3(); + break; + default: + nr = 0; + break; + } + + return d_timeslots_descriptions[timeslot_nr].get_burst_type(nr); +} +// move it to some other place !! + class gsm_receiver_cf; -/* - * We use boost::shared_ptr's instead of raw pointers for all access - * to gr_blocks (and many other data structures). The shared_ptr gets - * us transparent reference counting, which greatly simplifies storage - * management issues. This is especially helpful in our hybrid - * C++ / Python system. - * - * See http://www.boost.org/libs/smart_ptr/smart_ptr.htm - * - * As a convention, the _sptr suffix indicates a boost::shared_ptr - */ typedef boost::shared_ptr gsm_receiver_cf_sptr; typedef std::vector vector_complex; @@ -65,6 +222,8 @@ class gsm_receiver_cf : public gr_block private: const int d_OSR; + const int d_chan_imp_length; + gr_complex d_sch_training_seq[N_SYNC_BITS]; //encoded training sequence of a SCH burst gr_feval_dd *d_tuner; @@ -74,14 +233,22 @@ class gsm_receiver_cf : public gr_block int d_fcch_start_pos; float d_freq_offset; double d_best_sum; - - int d_fcch_count; //!!! - double d_x_temp, d_x2_temp, d_mean;//!! - + +// int d_fcch_count; //!!! +// double d_x_temp, d_x2_temp, d_mean;//!! + + burst_counter d_burst_nr; + channel_configuration d_channel_conf; + vector_complex d_channel_imp_resp; + int d_ncc; + int d_bcc; + enum states { - first_fcch_search, next_fcch_search, sch_search, read_bcch + //synchronization search part + first_fcch_search, next_fcch_search, sch_search, synchronized + // } d_state; friend gsm_receiver_cf_sptr gsm_make_receiver_cf(gr_feval_dd *tuner, int osr); @@ -91,8 +258,10 @@ class gsm_receiver_cf : public gr_block double compute_freq_offset(); void set_frequency(double freq_offset); inline float compute_phase_diff(gr_complex val1, gr_complex val2); - + bool find_sch_burst(const gr_complex *in, const int nitems , float *out); + int get_sch_chan_imp_resp(const gr_complex *in, gr_complex * chan_imp_resp); + void detect_burst(const gr_complex * in, gr_complex * chan_imp_resp, int burst_start, unsigned char * output_binary); void gmsk_mapper(const int * input, gr_complex * gmsk_output, int ninput); gr_complex correlate_sequence(const gr_complex * sequence, const gr_complex * input_signal, int ninput); inline void autocorrelation(const gr_complex * input, gr_complex * out, int length); diff --git a/src/python/gsm_findfcch.py b/src/python/gsm_findfcch.py deleted file mode 100755 index 2050d33..0000000 --- a/src/python/gsm_findfcch.py +++ /dev/null @@ -1,108 +0,0 @@ -#!/usr/bin/env python -#!/usr/bin/env python - -from gnuradio import gr, gru, blks2 -#, gsm -from gnuradio.eng_option import eng_option -from optparse import OptionParser -from os import sys - -for extdir in ['../../debug/src/lib','../../debug/src/lib/.libs']: - if extdir not in sys.path: - sys.path.append(extdir) -import gsm - -class tune(gr.feval_dd): - def __init__(self, top_block): - gr.feval_dd.__init__(self) - self.top_block = top_block - # self.center_freq = 0 - def eval(self, freq_offet): - # self.center_freq = self.center_freq - freq_offet - self.top_block.set_frequency(freq_offet) - return freq_offet - -class gsm_receiver_first_blood(gr.top_block): - def __init__(self): - gr.top_block.__init__(self) - (options, args) = self._przetworz_opcje() - self.tune_callback = tune(self) - self.options = options - self.args = args - self._ustaw_taktowanie() - self.zrodlo = self._ustaw_zrodlo() - self.filtr = self._ustaw_filtr() - self.interpolator = self._ustaw_interpolator() - self.odbiornik = self._ustaw_odbiornik() - self.konwerter = self._ustaw_konwerter() - self.ujscie = self._ustaw_ujscie() - - self.connect(self.zrodlo, self.filtr, self.interpolator, self.odbiornik, self.konwerter, self.ujscie) -# self.connect(self.zrodlo, self.ujscie) - - def _ustaw_ujscie(self): - nazwa_pliku_wy = self.options.outputfile - ujscie = gr.file_sink(gr.sizeof_float, nazwa_pliku_wy) - return ujscie - - def _ustaw_zrodlo(self): - nazwa_pliku = self.options.inputfile - zrodlo = gr.file_source(gr.sizeof_gr_complex, nazwa_pliku, False) - return zrodlo - - def _ustaw_taktowanie(self): - options = self.options - clock_rate = 64e6 - self.clock_rate = clock_rate - self.input_rate = clock_rate / options.decim - self.gsm_symb_rate = 1625000.0 / 6.0 - self.sps = self.input_rate / self.gsm_symb_rate / self.options.osr - - def _ustaw_filtr(self): - filter_cutoff = 145e3 - filter_t_width = 10e3 - offset = 0 - #print "input_rate:", self.input_rate, "sample rate:", self.sps, " filter_cutoff:", filter_cutoff, " filter_t_width:", filter_t_width - filter_taps = gr.firdes.low_pass(1.0, self.input_rate, filter_cutoff, filter_t_width, gr.firdes.WIN_HAMMING) - filtr = gr.freq_xlating_fir_filter_ccf(1, filter_taps, offset, self.input_rate) - return filtr - - def _ustaw_konwerter(self): - v2s = gr.vector_to_stream(gr.sizeof_float, 142) - return v2s - - def _ustaw_interpolator(self): - interpolator = gr.fractional_interpolator_cc(0, self.sps) -# interpolator = blks2.rational_resampler_ccf(13, 6) - return interpolator - - def _ustaw_odbiornik(self): - odbiornik = gsm.receiver_cf(self.tune_callback, self.options.osr) - return odbiornik - - def _przetworz_opcje(self): - parser = OptionParser(option_class=eng_option) - parser.add_option("-d", "--decim", type="int", default=128, - help="Set USRP decimation rate to DECIM [default=%default]") - parser.add_option("-r", "--osr", type="int", default=4, - help="Oversampling ratio [default=%default]") - parser.add_option("-I", "--inputfile", type="string", default="cfile", - help="Input filename") - parser.add_option("-O", "--outputfile", type="string", default="cfile2.out", - help="Output filename") - (options, args) = parser.parse_args () - return (options, args) - - def set_frequency(self, center_freq): - self.filtr.set_center_freq(center_freq) - -def main(): - try: - gsm_receiver_first_blood().run() - except KeyboardInterrupt: - pass - -if __name__ == '__main__': - main() - - -- cgit v1.2.3