⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 synch_complex_rcv.c

📁 This a framework to test new ideas in transmission technology. Actual development is a LDPC-coder in
💻 C
字号:
/*************************************************************************** *          synch_complex_rcv.c  - Software Radio to detect primary synch *                           ------------------- *   begin                :  02/10/22 *   authors              :  Linus Gasser *   emails               :  Linus.Gasser@epfl.ch ***************************************************************************//*************************************************************************** *                                Changes *                                ------- * date - name - description * 02/10/22 - ineiti - init * 03/11/24 - ineiti - added complex function * 04/03/08 - ineiti - adjuste description * 04/03/08 - ineiti - deleted synch_move * 04/03/11 - ineiti - added skip-configuration, like complex_ics_rcv * 04/03/27 - ineiti - fixed skip-configuration to be less paranoid, like *                     ics_rcv ;) * **************************************************************************//*************************************************************************** *                                                                         * *   This program is free software; you can redistribute it and/or modify  * *   it under the terms of the GNU General Public License as published by  * *   the Free Software Foundation; either version 2 of the License, or     * *   (at your option) any later version.                                   * *                                                                         * ***************************************************************************//** *  The desynchronisation uses a convolution to find the most probable * synchronistaion-signal. Due to the special format of the synch-signal, * it is possible to implement this as two convolutions, which reduces a * lot the computational complexity of the task. *  This is different in that it takes a complex input. */#include "spc.h"#include "mmx.h"#include "antenna.h"#include "synch.h"#include <math.h>#include <complex.h>#define DBG_LVL 0#define PRE_POST_LENGTH 32typedef struct {  // If this is set to a valid id, it will set the offset for the stfa  int stfa_id; // -1  // If this is 1, the sycnh_rcv also sets the offset_samples_rcv of the stfa  int fine_adj; // 0  // Skip synchronisation if more than this number of other high peaks.  // Useful numbers start at 5, 10 is a good bet.  int skip; // 10}config_t;typedef struct {  // The position of the strongest synchronisation signal  int synch_pos;  // The amplitude of the strongest signal  int synch_amp;  // The fine position, 0-3  int fine_pos;  // The fine amplitude  int fine_amp;  // The internal buffer - not really interesting  block_t buffer;  // The synchronisation signal - OK to look at it  block_t synch;}stats_t;typedef struct {  complex double *buffer;  int *synch;  int slot_length_chips;  int stfa_id;  int offset;  int fine_pos;  int fine_adj;  SYMBOL_COMPLEX *output;  int skip;}private_t;/* * The initialisation function, or constructor,  * is called the first time this module is instantiated. */int rcv_complex_init( swr_sdb_t *context ) {  // Definition of variables - don't touch if you're not an expert  config_t *config;  stats_t *stats;  MOD_INC_USE_COUNT;  if ( sizeof( private_t ) > 0 ) {    context->private_data = swr_malloc( sizeof( private_t ) );  }  swr_sdb_get_config_struct( context->id, (void**)&config );  swr_sdb_get_stats_struct( context->id, (void**)&stats );  private->slot_length_chips = 0;  private->buffer = NULL;  private->synch = NULL;  private->output = NULL;  private->fine_pos = 0;  private->stfa_id = config->stfa_id = -1;  stats->buffer.data = 0;  stats->buffer.size = 0;  stats->buffer.type = SIG_DOUBLE_COMPLEX;  stats->synch.data = 0;  stats->synch.size = 0;  stats->synch.type = SIG_S32;  stats->synch_pos = 0;  stats->synch_amp = 0;  stats->fine_pos = 0;  stats->fine_amp = 0;  config->fine_adj = 0;  config->skip = 10;  port_out(0).flags |= SWR_PORT_OWN_MALLOC;  // Definition - don't touch  swr_sdb_free_config_struct( context->id, (void**)&config );  swr_sdb_free_stats_struct( context->id, (void**)&stats );  return 0;}/* * Every time modules from the outside change the value of a configuration parameter, * this function is called. */int rcv_complex_reconfig( swr_sdb_t *context ) {  // Definition of variables - don't touch  config_t *config;  swr_sdb_get_config_struct( context->id, (void**)&config );  if ( config->stfa_id != private->stfa_id ) {    private->stfa_id = config->stfa_id;    if ( private->stfa_id >= 0 ) {      private->offset = swr_sdb_get_config_int( private->stfa_id,                        "offset_chips_rcv" );    }  }  private->fine_adj = config->fine_adj;  private->skip = config->skip;  PR_DBG( 4, "(%i) reconfig: %p\n", context->id, port_in(0).data );  // Definition - don't touch  swr_sdb_free_config_struct( context->id, (void**)&config );  return(0);}/* * Reconfigure outputs, abused to set up internal structures */int rcv_complex_configure_outputs( swr_sdb_t *context ) {  stats_t *stats;  config_t *config;  int len;  swr_sdb_get_stats_struct( context->id, (void**)&stats );  swr_sdb_get_config_struct( context->id, (void**)&config );  if ( private->slot_length_chips != size_in(0) ) {    if ( private->slot_length_chips ) {      swr_free( private->buffer );      swr_free( private->synch );      swr_free( private->output );    }    private->slot_length_chips = port_in(0).size;    len = ( private->slot_length_chips + 240 ) * sizeof( complex double );    private->buffer = swr_malloc( len );    memset( private->buffer, 0, len );    stats->buffer.data = private->buffer;    stats->buffer.size = len / sizeof( complex double );    len = private->slot_length_chips * sizeof( S32 );    private->synch = swr_malloc( len );    memset( private->synch, 0, len );    stats->synch.data = private->synch;    stats->synch.size = len / sizeof( S32 );    // This is in order to offer some 'buffer-room' to the matched filter    // before and after the actual slot, so as to simplify the filtering.    len = private->slot_length_chips - SYNCH_PRIM_LENGTH_SYMBOLS +          2 * PRE_POST_LENGTH;    //    PR_DBG( 0, "Allocating %i bytes for synch_complex_rcv_output\n", len );    private->output = swr_malloc( len * sizeof( SYMBOL_COMPLEX ) );    port_out(0).data = private->output + PRE_POST_LENGTH;  }  // Output 0  size_out(0) = size_in(0) - SYNCH_PRIM_LENGTH_SYMBOLS;  PR_DBG( 4, "(%i) config-out: %p\n", context->id, port_in(0).data );  swr_sdb_free_config_struct( context->id, (void**)&config );  swr_sdb_free_stats_struct( context->id, (void**)&stats );  return 0;}/* * This is function that impements the `main method' of the class * Every calss has got just ONE method/working-mode. */int rcv_complex_pdata( swr_sdb_t *context ) {  // Definition of variables - don't touch  stats_t *stats;  config_t *config;  int i, slot_length_symbols, synch_pos, fine_pos = -1, fine_amp = 0, j,    synch_amp, total_energy, other_peaks;  complex double *buffer;   S32 *synch;  SYMBOL_COMPLEX *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 };  swr_sdb_get_config_struct( context->id, (void**)&config );  swr_sdb_free_config_struct( context->id, (void**)&config );  slot_length_symbols = private->slot_length_chips;  buffer = private->buffer + 240;  synch = private->synch;  in = buffer_in(0);  // As total_energy is divided by SLOT_LENGTH_CHIPS and then used  // as a divisor itself, it has to be at least 1!!!  total_energy = slot_length_symbols;  synch_amp = 0;  synch_pos = -1;  for ( i=16; i<slot_length_symbols; i++ ) {    complex double res = 0;    for ( j=0; j<16; j++ ){      res += ( in[ i - j ].real  + in[ i - j ].imag * I ) * gold_inner[ j ];    }    buffer[ i ] = res;    memcpy( private->buffer, buffer + slot_length_symbols - 240, 240 * sizeof( complex double ) );    res = buffer[ i ] * gold_outer[ 0 ];    for ( j=1; j<16; j++ ){      res += buffer[ i - j * 16 ] * gold_outer[ j ];      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] ) );      }    }    synch[i] = cabs( res );    total_energy += cabs( res );    if (synch[i] > synch_amp) {      synch_pos = i % slot_length_symbols;      synch_amp = synch[i];      PR_DBG(4,"amp[%i]=%i\n",i,synch_amp);      }  }  // Search for other, erroneous peaks  for ( other_peaks = 0, i=0; i<slot_length_symbols; 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_symbols;  // One of these magic numbers...  synch_pos -= SYNCH_PRIM_LENGTH_SYMBOLS - 1 +     private->fine_adj / 2;  // If there are too many other peaks, consider another place  if ( other_peaks > private->skip && private->skip ){    PR_DBG( 2, "Other_peaks: %i\n", other_peaks );    synch_pos = -slot_length_symbols / 2;    synch_amp /= other_peaks * other_peaks;  }  // Perhaps we have to synchronise?  if ( private->stfa_id >= 0 ) {    private->offset += synch_pos;    PR_DBG( 4, "Setting new synch: %i(%i)\n", private->offset,	    private->fine_adj );    swr_sdb_set_config_int( private->stfa_id, "offset_chips_rcv", 			    private->offset );    swr_sdb_set_config_int( private->stfa_id, "offset_samples_rcv",			    ( private->fine_adj % 2 ) );  }  // Copy the input-buffer to the output-buffer with omitting the middle  out = buffer_out(0);  if ( out ) {    memcpy( out - PRE_POST_LENGTH, 	    in - PRE_POST_LENGTH + SYNCH_PRIM_LENGTH_SYMBOLS,            ( size_out(0) + 2 * PRE_POST_LENGTH ) * 	    sizeof( SYMBOL_COMPLEX ) );  }  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;  stats->fine_pos = fine_pos;  stats->fine_amp = fine_amp;  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 );  return(0);}/* * This is the `destructor'. */int rcv_complex_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_id;int rcv_complex_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, 3, 6 );  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_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_INPUT( SIG_SYMBOL_COMPLEX, 0 );  UM_OUTPUT( SIG_SYMBOL_COMPLEX, 0 );  // Initialise the callback-functions. NULL for not-used functions  desc->fn_init              = rcv_complex_init;  desc->fn_reconfigure       = rcv_complex_reconfig;  desc->fn_process_data      = rcv_complex_pdata;  desc->fn_finalize          = rcv_complex_finalize;  desc->fn_configure_outputs = rcv_complex_configure_outputs;  // And register the module in the SPM  rcv_complex_id = swr_cdb_register_spc( &desc, "synch_complex_rcv" );  if ( rcv_complex_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_module_exit( void ) {  PR_DBG( 4, "Freeing id: %i\n", rcv_complex_id );  if ( swr_cdb_unregister_spc( rcv_complex_id ) < 0 ) {    PR_DBG( 0, "Still in use somewhere\n" );  }}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -