📄 synch_complex_ics_rcv.c
字号:
S32 *synch; SYMBOL_COMPLEX_S32 *in, *out; // SAMPLE_S12 *out, *in_s12; short int gold_inner[] = { +1, -1, -1, +1, -1, +1, -1, +1, -1, -1, +1, +1, +1, +1, +1, +1 }; short int gold_outer[] = { +1, +1, -1, +1, -1, +1, +1, +1, -1, -1, +1, -1, -1, +1, +1, +1 }; INIT_WATCH(4); swr_sdb_get_config_struct( context->id, (void**)&config ); swr_sdb_free_config_struct( context->id, (void**)&config ); slot_length_samples = private->slot_length_samples; buffer = private->buffer + 240 * 2; synch = private->synch; // The size of the buffer is slot_length_samples + 32 of the // gold_inner length and 4 for the 'shift'. buffer_ics = swr_malloc( sizeof( complex double ) * ( slot_length_samples + 32 + 4 ) ); in = buffer_in(0); out = buffer_out(0); port_out(0).data = port_in(0).data + SYNCH_PRIM_LENGTH_SAMPLES_QI * sizeof( SYMBOL_COMPLEX_S32 ) * 2; // As total_energy is divided by SLOT_LENGTH_SAMPLES and then used // as a divisor itself, it has to be at least 1!!! total_energy = slot_length_samples; synch_amp = 0; synch_pos = -1;#define RX_INDEX(i) ( (i) + ( (i) & ~3 ) ) p = (unsigned int)in; shift = ( p & 0x3f ) / 0x10; in = (SYMBOL_COMPLEX_S32*)(p & ~0x3f); WATCH_CLOCK( "Initialized" ); // Prepare a first buffer for calculations // buffer_ics[0] = in[ RC_INDEX( -32 ) ]; for ( i=0; i<slot_length_samples + 32 + shift; i++ ){ buffer_ics[i] = SC_TO_CD( in[ RX_INDEX( i - 32 ) ] ); } // buffer_ics[0] = in[ RC_INDEX( 0 ) ]; // But this time we have some space to do the convolution buffer_ics += shift + 32; WATCH_CLOCK( "Init buffer_ics" ); // First make the convolution with gold_inner. As gold_inner is at // symbol-level, and our input is at sample-level, we only take each // second sample for the convolution. BUT we do the convolutions at // every sample-position for ( i=0; i<slot_length_samples; i++ ) { complex double res = 0; for ( j=0; j<16; j++ ){ res += buffer_ics[ i - 2 * j ] * gold_inner[ j ]; } buffer[ i ] = res / ( 1 << 12 ); } buffer_ics -= shift + 32; swr_free( buffer_ics ); WATCH_CLOCK( "Init inner gold" ); // Copy the end of the buffer to the beginning, so we can more easily do // the convolutions at the corners of the buffer memcpy( private->buffer, private->buffer + slot_length_samples, 240 * 2 * sizeof( complex double ) ); // Now do the outer convolution with gold_outer. for ( i=0; i<slot_length_samples; i++ ) { complex double res; res = buffer[ i ] * gold_outer[ 0 ]; for ( j=1; j<16; j++ ){ res += buffer[ i - j * 16 * 2 ] * gold_outer[ j ]; // Debugging if( ( i-j*16 ) < 0 ) { PR_DBG( 4, "buffer[%i]=%g+%gi\n", i-j*16, creal( buffer[i-j*16] ), cimag( buffer[i-j*16] ) ); } } if ( private->mean > 1 ){ synch[i] = ( synch[i] * ( private->mean - 1 ) + cabs( res ) ) / private->mean; } else { synch[i] = cabs( res ); } total_energy += cabs( res ); if (synch[i] > synch_amp) { synch_pos = i % slot_length_samples; synch_amp = synch[i]; PR_DBG(4,"amp[%i]=%i\n",i,synch_amp); } } WATCH_CLOCK( "Init outer gold code" ); // Search for other, erroneous peaks for ( other_peaks = 0, i=0; i<slot_length_samples; i++ ) { if ( synch[i] > synch_amp / 2 && synch_pos != i ){ // There is another peak with at least half the amplitude, // let's search further other_peaks++; } } total_energy /= slot_length_samples; // One of these magic numbers... synch_pos -= SYNCH_PRIM_LENGTH_SAMPLES_QI - 2 + private->fine_adj; // If there are too many other peaks, consider another place if ( other_peaks > private->skip && private->skip ){ // The other peaks indicate that we aren't synchronised PR_DBG( 2, "Other_peaks: %i\n", other_peaks ); synch_pos = -slot_length_samples / 2; private->mean = 1; synch_amp /= other_peaks * other_peaks; } else { if ( synch_pos == 0 ){ // Only do averaging on a correctly synchronised slot private->mean = private->config_mean; } } if ( synch_pos ){ PR_DBG( 4, "Synch-pos: %5i, we're at: %i\n", synch_pos, private->offset_samples ); } WATCH_CLOCK( "Recalculated positions" ); // Perhaps we have to synchronise? if ( private->stfa_id >= 0 ) { private->offset_samples += synch_pos; length_frame = slot_length_samples * private->slots_per_frame;/* if ( private->offset_samples > length_frame ){ *//* private->offset_samples %= length_frame; *//* } else if ( private->offset_samples < 0 ){ *//* private->offset_samples += length_frame; *//* } */ PR_DBG( 4, "Setting new synch: %i(%i)\n", private->offset_samples, private->fine_adj ); swr_sdb_set_config_int( private->stfa_id, "offset_chips_rcv", private->offset_samples / 2 ); swr_sdb_set_config_int( private->stfa_id, "offset_samples_rcv", ( private->offset_samples % 2 ) ); WATCH_CLOCK( "Set up stfa" ); } swr_sdb_get_stats_struct( context->id, (void**)&stats ); if ( synch_amp > ( 1 << 24 ) ) { PR_DBG( 3, "Synch amp is REALLY big: %i\n", synch_amp ); } stats->synch_amp = synch_amp; // To have synch_pos in chips stats->synch_pos = synch_pos / 2; stats->fine_pos = fine_pos; stats->fine_amp = fine_amp; stats->mean = private->mean; swr_sdb_free_stats_struct( context->id, (void**)&stats ); PR_DBG( 4, "Tot_energy: %i, synch_amp: %i, pos: %i, offset: %i\n", total_energy, synch_amp, synch_pos, private->offset_samples ); WATCH_CLOCK( "Finished" ); return(0);}/* * This is the `destructor'. */int rcv_complex_ics_finalize( swr_sdb_t *context ) { swr_free( private->buffer ); swr_free( private->synch ); swr_free( private ); MOD_DEC_USE_COUNT; return(0);}/* * This function is called upon "insmod" and is used to register the * different parts of the module to the SPM. */swr_spc_id_t rcv_complex_ics_id;int rcv_complex_ics_module_init(void) { swr_spc_desc_t *desc; // Get a description-part from SPM // Give the following parameters: // In-ports, output-ports, config-params, stat-params desc = swr_spc_get_new_desc( 1, 1, 4, 7 ); if ( !desc ) { PR_DBG( 0, "Can't initialise the module. This is BAD!\n" ); return -1; } // Define the different parts of config and stats UM_CONFIG_INT( "stfa_id" ); UM_CONFIG_INT( "fine_adj" ); UM_CONFIG_INT( "skip" ); UM_CONFIG_INT( "mean" ); UM_STATS_INT( "synch_pos" ); UM_STATS_INT( "synch_amp" ); UM_STATS_INT( "fine_pos" ); UM_STATS_INT( "fine_amp" ); UM_STATS_BLOCK( "buffer" ); UM_STATS_BLOCK( "synch" ); UM_STATS_INT( "mean" ); UM_INPUT( SIG_SYMBOL_COMPLEX_S32, 0 ); UM_OUTPUT( SIG_SYMBOL_COMPLEX_S32, 0 ); // Initialise the callback-functions. NULL for not-used functions desc->fn_init = rcv_complex_ics_init; desc->fn_reconfigure = rcv_complex_ics_reconfig; desc->fn_process_data = rcv_complex_ics_pdata; desc->fn_finalize = rcv_complex_ics_finalize; desc->fn_configure_outputs = rcv_complex_ics_configure_outputs; // And register the module in the SPM rcv_complex_ics_id = swr_cdb_register_spc( &desc, "synch_complex_ics_rcv" ); if ( rcv_complex_ics_id == SWR_SPM_INVALID_ID ) { swr_spc_free_desc( desc ); PR_DBG( 0, "Couldn't register the module!\n" ); return 1; } PR_DBG( 4, "Ready to synch\n" ); return 0;}/* * This is called upon rmmod */void rcv_complex_ics_module_exit( void ) { PR_DBG( 4, "Freeing id: %i\n", rcv_complex_ics_id ); if ( swr_cdb_unregister_spc( rcv_complex_ics_id ) < 0 ) { PR_DBG( 0, "Still in use somewhere\n" ); }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -