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

📄 synch_rcv.c

📁 This a framework to test new ideas in transmission technology. Actual development is a LDPC-coder in
💻 C
字号:
/*************************************************************************** *                  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 * 04/01/07 - ineiti - added a search for other peaks and signal them by *                     lowering synch_amp and putting synch_pos to -10 * 04/03/01 - ineiti - fixed for ICS-cards (stupid data-format) * 04/03/08 - ineiti - adjusted description * 04/03/08 - ineiti - deleted synch_move, as it's not used anymore * 04/03/29 - ineiti - adjusted synch-movement if there is no synch * **************************************************************************//*************************************************************************** *                                                                         * *   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. */#include "spc.h"#include "mmx.h"#include "antenna.h"#include "synch.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}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 {  mmx_t *buffer;  int *synch;  int slot_length_chips;  int stfa_id;  int offset;  int fine_pos;  int fine_adj;  SAMPLE_S12 *output;}private_t;/* * The initialisation function, or constructor,  * is called the first time this module is instantiated. */int rcv_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_SYMBOL_MMX;  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;  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_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;  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_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) / DAQ_SAMPLES_PER_CHIP ) {    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 / DAQ_SAMPLES_PER_CHIP;    len = ( private->slot_length_chips + 240 ) * sizeof( SYMBOL_MMX );    private->buffer = swr_malloc( len );    memset( private->buffer, 0, len );    stats->buffer.data = private->buffer;    stats->buffer.size = len / sizeof( SYMBOL_MMX );    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 = 4 * ( private->slot_length_chips - SYNCH_PRIM_LENGTH_SYMBOLS ) +          2 * PRE_POST_LENGTH;    private->output = swr_malloc( len * sizeof( SAMPLE_S12 ) );    port_out(0).data = private->output + PRE_POST_LENGTH;  }  // Output 0  size_out(0) = size_in(0) - SYNCH_PRIM_LENGTH_SAMPLES;  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_pdata( swr_sdb_t *context ) {  // Definition of variables - don't touch  stats_t *stats;  config_t *config;  int i, temp, slot_length, synch_pos, fine_pos = -1, fine_amp = 0, j,      synch_amp, total_energy, other_peaks;  S32 *synch;  SYMBOL_MMX *in, *buffer, fine_mmx;  SAMPLE_S12 *out, *in_s12;  swr_sdb_get_config_struct( context->id, (void**)&config );  swr_sdb_free_config_struct( context->id, (void**)&config );  slot_length = 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;  synch_amp = 0;  synch_pos = -1;  memcpy( private->buffer, &buffer[ slot_length - 240 ], 240 * sizeof( mmx_t ) );  for ( i=0; i<slot_length; i++ ) {    movq_m2r(in[i],mm1);    pxor_r2r(mm0,mm0);    movq_m2r(in[i-1],mm2);    psraw_i2r(8,mm1);    psraw_i2r(8,mm2);    paddsw_r2r(mm1,mm0);                       /*  +1  */    movq_m2r(in[i-2],mm1);    psubsw_r2r(mm2,mm0);                       /*  -1 */    movq_m2r(in[i-3],mm2);    psraw_i2r(8,mm1);    psraw_i2r(8,mm2);    psubsw_r2r(mm1,mm0);                       /*  -1  */    movq_m2r(in[i-4],mm1);    paddsw_r2r(mm2,mm0);                       /*  +1 */    movq_m2r(in[i-5],mm2);    psraw_i2r(8,mm1);    psraw_i2r(8,mm2);    psubsw_r2r(mm1,mm0);                       /*  -1  */    movq_m2r(in[i-6],mm1);    paddsw_r2r(mm2,mm0);                       /*  +1 */    movq_m2r(in[i-7],mm2);    psraw_i2r(8,mm1);    psraw_i2r(8,mm2);    psubsw_r2r(mm1,mm0);                       /*  -1  */    movq_m2r(in[i-8],mm1);    paddsw_r2r(mm2,mm0);                       /*  +1 */    movq_m2r(in[i-9],mm2);    psraw_i2r(8,mm1);    psraw_i2r(8,mm2);    psubsw_r2r(mm1,mm0);                       /*  -1  */    movq_m2r(in[i-10],mm1);    psubsw_r2r(mm2,mm0);                       /*  -1 */    movq_m2r(in[i-11],mm2);    psraw_i2r(8,mm1);    psraw_i2r(8,mm2);    paddsw_r2r(mm1,mm0);                       /*  +1  */    movq_m2r(in[i-12],mm1);    paddsw_r2r(mm2,mm0);                       /*  +1 */    movq_m2r(in[i-13],mm2);    psraw_i2r(8,mm1);    psraw_i2r(8,mm2);    paddsw_r2r(mm1,mm0);                       /*  +1  */    movq_m2r(in[i-14],mm1);    paddsw_r2r(mm2,mm0);                       /*  +1 */    movq_m2r(in[i-15],mm2);    psraw_i2r(8,mm1);    psraw_i2r(8,mm2);    paddsw_r2r(mm1,mm0);                       /*  +1  */    paddsw_r2r(mm2,mm0);                       /*  +1 */    movq_r2m(mm0,buffer[i]);    pxor_r2r(mm3,mm3);    movq_m2r(buffer[i-16],mm1);    paddsw_r2r(mm0,mm3);                       /* +1 */    movq_m2r(buffer[i-32],mm2);    paddsw_r2r(mm1,mm3);                       /* +1 */    movq_m2r(buffer[i-48],mm1);    psubsw_r2r(mm2,mm3);                       /*  -1 */    movq_m2r(buffer[i-64],mm2);    paddsw_r2r(mm1,mm3);                       /* +1 */    movq_m2r(buffer[i-80],mm1);    psubsw_r2r(mm2,mm3);                       /*  -1 */    movq_m2r(buffer[i-96],mm2);    paddsw_r2r(mm1,mm3);                       /* +1 */    movq_m2r(buffer[i-112],mm1);    paddsw_r2r(mm2,mm3);                       /* +1 */    movq_m2r(buffer[i-128],mm2);    paddsw_r2r(mm1,mm3);                       /* +1 */    movq_m2r(buffer[i-144],mm1);    psubsw_r2r(mm2,mm3);                       /*  -1 */    movq_m2r(buffer[i-160],mm2);    psubsw_r2r(mm1,mm3);                       /*  -1 */    movq_m2r(buffer[i-176],mm1);    paddsw_r2r(mm2,mm3);                       /* +1 */    movq_m2r(buffer[i-192],mm2);    psubsw_r2r(mm1,mm3);                       /*  -1 */    movq_m2r(buffer[i-208],mm1);    psubsw_r2r(mm2,mm3);                       /*  -1 */    movq_m2r(buffer[i-224],mm2);    paddsw_r2r(mm1,mm3);                       /* +1 */    movq_m2r(buffer[i-240],mm1);    paddsw_r2r(mm2,mm3);                       /* +1 */    paddsw_r2r(mm1,mm3);                       /* +1 */    movq_r2m( mm3, fine_mmx );    pmaddwd_r2r(mm3,mm3);    movq_r2r(mm3,mm1);    psrlq_i2r(32,mm3);    paddd_r2r(mm1,mm3);    movd_r2m(mm3,temp);    //    synch[i] = (synch[i]*2 + temp)/3;    synch[i] = temp;    total_energy += temp;    if (synch[i] > synch_amp) {      synch_pos = i % slot_length;      synch_amp = synch[i];      fine_amp = abs( fine_mmx.w[0] );      fine_pos = 0;      for ( j=1; j<4; j++ ) {        if ( abs( fine_mmx.w[j] ) > fine_amp ) {          fine_amp = abs( fine_mmx.w[j] );          fine_pos = j;        }      }    }  }  // Search for other, erroneous peaks  for ( other_peaks = 0, i=0; i<slot_length; 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;  // One of these magic numbers...  synch_pos -= SYNCH_PRIM_LENGTH_SYMBOLS - 1;  if ( other_peaks > 10 ){    PR_DBG( 2, "Other_peaks: %i\n", other_peaks );    synch_pos = -slot_length / 2;    synch_amp /= other_peaks * other_peaks;  }  emms();  // Perhaps we have to synchronise?  if ( private->stfa_id >= 0 ) {    if ( private->fine_adj ) {      private->fine_pos += fine_pos;      if ( private->fine_pos >= 4 ) {        private->offset++;        private->fine_pos -= 4;      }      swr_sdb_set_config_int( private->stfa_id, "offset_samples_rcv",                              private->fine_pos );    }    private->offset += synch_pos;    swr_sdb_set_config_int( private->stfa_id, "offset_chips_rcv", private->offset );  }  // Copy the input-buffer to the output-buffer with omitting the middle  out = buffer_out(0);  if ( out ) {    in_s12 = (SAMPLE_S12*)in;    memcpy( private->output, 	    in_s12 - PRE_POST_LENGTH + SYNCH_PRIM_LENGTH_SAMPLES,            ( size_out(0) + 2 * PRE_POST_LENGTH ) * 	    sizeof( SAMPLE_S12 ) );  }  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_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_id;int rcv_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, 2, 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", PARAMETER_DEBUG );  UM_CONFIG_INT( "fine_adj", PARAMETER_DEBUG );  UM_STATS_INT( "synch_pos" );  UM_STATS_INT( "synch_amp" );  UM_STATS_INT( "fine_pos", PARAMETER_DEBUG );  UM_STATS_INT( "fine_amp", PARAMETER_DEBUG );  UM_STATS_BLOCK( "buffer", PARAMETER_DEBUG );  UM_STATS_BLOCK( "synch" );  UM_INPUT( SIG_SAMPLE_S12, 0 );  UM_OUTPUT( SIG_SAMPLE_S12, 0 );  // Initialise the callback-functions. NULL for not-used functions  desc->fn_init              = rcv_init;  desc->fn_reconfigure       = rcv_reconfig;  desc->fn_process_data      = rcv_pdata;  desc->fn_finalize          = rcv_finalize;  desc->fn_configure_outputs = rcv_configure_outputs;  // And register the module in the SPM  rcv_id = swr_cdb_register_spc( &desc, "synch_rcv" );  if ( rcv_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_module_exit( void ) {  PR_DBG( 4, "Freeing id: %i\n", rcv_id );  if ( swr_cdb_unregister_spc( rcv_id ) < 0 ) {    PR_DBG( 0, "Still in use somewhere\n" );  }}

⌨️ 快捷键说明

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