diff --git a/csdr.c b/csdr.c index 7353b85..c227819 100644 --- a/csdr.c +++ b/csdr.c @@ -2348,6 +2348,38 @@ int main(int argc, char *argv[]) fwrite(output_buffer, sizeof(complexf), the_bufsize, stdout); //fprintf(stderr, "| o"); TRY_YIELD; + } + + if(!strcmp(argv[1],"timing_recovery_cc")) // [--add_q] + { + if(argc<=2) return badsyntax("need required parameter (algorithm)"); + timing_recovery_algorithm_t algorithm = timing_recovery_get_algorithm_from_string(argv[2]); + /* if(algorithm == TIMING_RECOVERY_ALGORITHM_DEFAULT) */ + fprintf(stderr,"timing_recovery_cc: algorithm = %s\n",timing_recovery_get_string_from_algorithm(algorithm)); + if(argc<=3) return badsyntax("need required parameter (decimation factor)"); + int decimation; + sscanf(argv[3],"%d",&decimation); + if(decimation<=4 || decimation&3) badsyntax("decimation factor should be a positive integer divisible by 4"); + + int add_q = (argc>=5 && !strcmp(argv[4], "--add_q")); + + if(!initialize_buffers()) return -2; + sendbufsize(the_bufsize/decimation); + + timing_recovery_state_t state = timing_recovery_init(algorithm, decimation, add_q); + + FREAD_C; + for(;;) + { + FEOF_CHECK; + timing_recovery((complexf*)input_buffer, (complexf*)output_buffer, the_bufsize, &state); + //fprintf(stderr, "os %d\n",state->output_size); + fwrite(output_buffer, sizeof(complexf), state->output_size, stdout); + fflush(stdout); + TRY_YIELD; + memmove((complexf*)input_buffer,((complexf*)input_buffer)+state->input_processed,(the_bufsize-state->input_processed)*sizeof(complexf)); //memmove lets the source and destination overlap + fread(((complexf*)input_buffer)+(the_bufsize-state->input_processed), sizeof(complexf), state->input_processed, stdin); + //fprintf(stderr,"iskip=%d state->output_size=%d start=%x target=%x skipcount=%x \n",state->input_processed,state->output_size,input_buffer, ((complexf*)input_buffer)+(BIG_BUFSIZE-state->input_processed),(BIG_BUFSIZE-state->input_processed)); } } diff --git a/libcsdr.c b/libcsdr.c index 5f0bdb0..e7cc163 100644 --- a/libcsdr.c +++ b/libcsdr.c @@ -1572,6 +1572,17 @@ void binary_slicer_f_u8(float* input, unsigned char* output, int input_size) for(int i=0;i 0; } +/* + _____ _ _______ _ _ _____ + / ____| (_) ___ |__ __(_) (_) | __ \ + | | __ _ _ __ _ __ _ ___ _ __ ( _ ) | | _ _ __ ___ _ _ __ __ _ | |__) |___ ___ _____ _____ _ __ _ _ + | | / _` | '__| '__| |/ _ \ '__| / _ \/\ | | | | '_ ` _ \| | '_ \ / _` | | _ // _ \/ __/ _ \ \ / / _ \ '__| | | | + | |___| (_| | | | | | | __/ | | (_> < | | | | | | | | | | | | | (_| | | | \ \ __/ (_| (_) \ V / __/ | | |_| | + \_____\__,_|_| |_| |_|\___|_| \___/\/ |_| |_|_| |_| |_|_|_| |_|\__, | |_| \_\___|\___\___/ \_/ \___|_| \__, | + __/ | __/ | + |___/ |___/ +*/ + void pll_cc_init_pi_controller(pll_t* p, float bandwidth, float ko, float kd, float damping_factor) { //kd: detector gain @@ -1620,7 +1631,7 @@ void pll_cc(pll_t* p, complexf* input, float* output_dphase, complexf* output_nc p->dphase = new_dphase * p->alpha + p->iir_temp; p->iir_temp += new_dphase * p->beta; - while(p->dphase>PI) p->dphase-=2*PI; //ez nem fog kelleni + while(p->dphase>PI) p->dphase-=2*PI; //won't need this one while(p->dphase<-PI) p->dphase+=2*PI; } else if(p->pll_type == PLL_P_CONTROLLER) @@ -1633,6 +1644,116 @@ void pll_cc(pll_t* p, complexf* input, float* output_dphase, complexf* output_nc } } +timing_recovery_state_t timing_recovery_init(timing_recovery_algorithm_t algorithm, int decimation_rate, int use_q) +{ + timing_recovery_state_t to_return; + to_return.algorithm = algorithm; + to_return.decimation_rate = decimation_rate; + to_return.use_q = use_q; + return to_return; +} + +int timing_recovery(complexf* input, complexf* output, int input_size, timing_recovery_state_t* state) +{ + //We always assume that the input starts at center of the first symbol cross before the first symbol. + //Last time we consumed that much from the input samples that it is there. + int current_bitstart_index = 0; + int num_samples_bit = state->decimation_rate; + int num_samples_halfbit = state->decimation_rate / 2; + int num_samples_quarterbit = state->decimation_rate / 4; + float error; + int si; + if(state->algorithm == TIMING_RECOVERY_ALGORITHM_GARDNER) + { + for(si=0;;si++) + { + if(current_bitstart_index + num_samples_halfbit * 3 >= input_size) break; + output[si++] = input[current_bitstart_index + num_samples_halfbit]; + error = ( + iof(input, current_bitstart_index + num_samples_halfbit * 3) - iof(input, current_bitstart_index + num_samples_halfbit) + ) * iof(input, current_bitstart_index + num_samples_halfbit * 2); + if(state->use_q) + { + error += ( + qof(input, current_bitstart_index + num_samples_halfbit * 3) - qof(input, current_bitstart_index + num_samples_halfbit) + ) * qof(input, current_bitstart_index + num_samples_halfbit * 2); + error /= 2; + } + current_bitstart_index += num_samples_halfbit * 2 + (error)?((error>0)?1:-1):0; + + } + state->input_processed = current_bitstart_index; + state->output_size = si; + } + else if(state->algorithm == TIMING_RECOVERY_ALGORITHM_EARLYLATE) + { + for(si=0;;si++) + { + if(current_bitstart_index + num_samples_bit >= input_size) break; + output[si++] = input[current_bitstart_index + num_samples_halfbit]; + error = ( + iof(input, current_bitstart_index + num_samples_quarterbit * 3) - iof(input, current_bitstart_index + num_samples_quarterbit) + ); //* iof(input, current_bitstart_index + num_samples_halfbit); //I don't think we need the end of the Nutaq formula + if(state->use_q) + { + error += qof(input, current_bitstart_index + num_samples_quarterbit * 3) - qof(input, current_bitstart_index + num_samples_quarterbit); + error /= 2; + } + //Correction method #1: this version can only move a single sample in any direction + //current_bitstart_index += num_samples_halfbit * 2 + (error)?((error<0)?1:-1):0; + //Correction method #2: this can move in proportional to the error + if(error>2) error=2; + if(error<-2) error=-2; + current_bitstart_index += num_samples_halfbit * 2 + num_samples_halfbit * (-error/2); + } + state->input_processed = current_bitstart_index; + state->output_i = si; + } +} + +#define MTIMINGR_GAS(NAME) \ + if(!strcmp( #NAME , input )) return TIMING_RECOVERY_ALGORITHM_ ## NAME; + +timing_recovery_algorithm_t timing_recovery_get_algorithm_from_string(char* input) +{ + MTIMINGR_GAS(GARDNER); + MTIMINGR_GAS(EARLYLATE); + return TIMING_RECOVERY_ALGORITHM_DEFAULT; +} + +#define MTIMINGR_GSA(NAME) \ + if(algorithm == TIMING_RECOVERY_ALGORITHM_ ## NAME) return #NAME; + +char* timing_recovery_get_string_from_algorithm(timing_recovery_algorithm_t algorithm) +{ + MTIMINGR_GSA(GARDNER); + MTIMINGR_GSA(EARLYLATE); + return "INVALID"; +} + +/* +in struct: + char* debug_string; + char* debug_string_end; + int debug_string_length; + int debug_mode; + int debug_first_n_symbols; +func: +void timing_recovery_write_debug_string +( + int input, + int input_length, + int current_bitstart_index, + int current_output_index, + int current_p1_index, + int current_p2_index, + timing_recovery_state_t* state +) +{ + if(state->debug_string_end==state->debug_string+debug_string_length) return; +}*/ + + /* _____ _ _ | __ \ | | (_) diff --git a/libcsdr.h b/libcsdr.h index 0ae8fbc..8259c37 100644 --- a/libcsdr.h +++ b/libcsdr.h @@ -287,3 +287,25 @@ typedef struct pll_s void pll_cc_init_pi_controller(pll_t* p, float bandwidth, float ko, float kd, float damping_factor); void pll_cc_init_p_controller(pll_t* p, float alpha); void pll_cc(pll_t* p, complexf* input, float* output_dphase, complexf* output_nco, int input_size); + +typedef enum timing_recovery_algorithm_e +{ + TIMING_RECOVERY_ALGORITHM_GARDNER, + TIMING_RECOVERY_ALGORITHM_EARLYLATE +} timing_recovery_algorithm_t; + +#define TIMING_RECOVERY_ALGORITHM_DEFAULT TIMING_RECOVERY_ALGORITHM_GARDNER + +typedef struct timing_recovery_state_s +{ + timing_recovery_algorithm_t algorithm; + int decimation_rate; // = input_rate / output_rate. We should get an input signal that is N times oversampled. + int output_size; + int input_processed; + int use_q; //use both I and Q for calculating the error +} timing_recovery_state_t; + +timing_recovery_state_t timing_recovery_init(timing_recovery_algorithm_t algorithm, int decimation_rate, int use_q); +int timing_recovery(complexf* input, complexf* output, int input_length, timing_recovery_state_t* state); +timing_recovery_algorithm_t timing_recovery_get_algorithm_from_string(char* input); +char* timing_recovery_get_string_from_algorithm(timing_recovery_algorithm_t algorithm);