Logo Search packages:      
Sourcecode: xdemorse version File versions  Download package

detect.c

/*  detect.c
 *
 *  Signal detection functions of xdemorse application
 */

/*
 *  xdemorse: An application to decode Morse code signals to text
 *
 *  Copyright (C) 2002  Neoklis Kyriazis
 *
 *  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.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details:
 *
 *  http://www.gnu.org/copyleft/gpl.txt
 */


#include "xdemorse.h"
#include "detect.h"

/* Runtime config data */
extern rc_data_t rc_data;

/*------------------------------------------------------------------------*/

/*  Get_Fragment()
 *
 *  Detects the cw beat frequency signal o/p from the radio
 *  receiver and determines the status, (mark or space) of a
 *  'fragment' (a small fraction, ~1/8) of a Morse code element.
 *  Signal detection is done by using a Goertzel algorithm.
 */

  int
Get_Fragment( void )
{
  int
      frag_lev,    /* Level of the Morse signal 'fragment'     */
      frag_timer,  /* Counter for timing duration of fragment  */
      block_size,  /* Block size (N) of the Goertzel algorithm */
      up_steps,    /* Num of consecutive increasing signal levels */
      dn_steps,    /* Num of consecutive decreasing signal levels */
      idx;

  /* Variables for the Goertzel algorithm */
  double q0, q1, q2;


  /* Goertzel block size depends on Morse speed */
  block_size = detector_data.frag_len * rc_data.unit_elem;
  
  /* Buffer dsp samples of input signal for a fragment */
  for(frag_timer = 0; frag_timer < detector_data.frag_len; frag_timer++ )
  {
      /* Get next signal sample from buffer, abort on error */
      detector_data.samples_buff[detector_data.samples_buff_idx] =
        Signal_Sample();
      if( isFlagSet(DSP_IO_ERROR) )
        return(-1);

      /* Advance/Reset circular buffers' index */
      if( ++detector_data.samples_buff_idx >= detector_data.samples_buff_len )
        detector_data.samples_buff_idx = 0;

  } /* for( frag_timer = 0; frag_timer < frag_len ... */

  /** Calculate signal fragment level over a block **/
  /* Backstep buffer index for use of samples */
  detector_data.samples_buff_idx -= block_size;
  if( detector_data.samples_buff_idx < 0 )
      detector_data.samples_buff_idx += detector_data.samples_buff_len;

  /* Calculate fragment level using Goertzel algorithm */
  q1 = q2 = 0.0;
  for( idx = 0; idx < block_size; idx++ )
  {
      q0 = detector_data.coeff * q1 - q2 +
        detector_data.samples_buff[detector_data.samples_buff_idx];
      q2 = q1;
      q1 = q0;

      /* Reset circular buffers' index */
      if( ++detector_data.samples_buff_idx >= detector_data.samples_buff_len )
        detector_data.samples_buff_idx = 0;
  }

  /* Scalar magnitude of input signal scaled by block size */
  q1 /= (double)block_size;
  q2 /= (double)block_size;
  frag_lev = (int)(q1*q1 + q2*q2 - q1*q2*detector_data.coeff);

  /* Save signal power level to circular buffer */
  detector_data.sig_level_buff[detector_data.sig_level_idx] = frag_lev;
  if( ++detector_data.sig_level_idx >= rc_data.max_unit )
      detector_data.sig_level_idx = 0;

  /* Backstep buffer index for use of fragment levels */
  detector_data.sig_level_idx -= rc_data.unit_elem;
  if( detector_data.sig_level_idx < 0 )
      detector_data.sig_level_idx += rc_data.max_unit;

  /* Count the number of "steps" in the signal's edge that are
   * in the same direction (increasing or decreasing amplitude) */
  up_steps = dn_steps = 0;
  for( idx = 1; idx < rc_data.unit_elem; idx++ )
  {
      int tmp1, tmp2;

      /* Compare successive signal levels */
      tmp1 = detector_data.sig_level_buff[detector_data.sig_level_idx];
      if( ++detector_data.sig_level_idx >= rc_data.max_unit )
        detector_data.sig_level_idx = 0;
      tmp2 = detector_data.sig_level_buff[detector_data.sig_level_idx];

      /* Successive levels are compared for more
       * than STEP_THRESHOLD difference up or down */
      if( STEP_THRESHOLD*tmp1 < 100*tmp2 )
        up_steps++;
      else if( 100*tmp1 > STEP_THRESHOLD*tmp2 )
        dn_steps++;
  }
  if( ++detector_data.sig_level_idx >= rc_data.max_unit )
      detector_data.sig_level_idx = 0;

  /* Set tone status. */
  if( 100*up_steps > rc_data.det_thr*(rc_data.unit_elem-1) )
      Set_Flag( MARK_TONE );
  else
      if( 100*dn_steps > rc_data.det_thr*(rc_data.unit_elem-1) )
        Clear_Flag( MARK_TONE );

  /* Display signal graph (scope) */
  if( isFlagSet(DISPLAY_DETECTOR) )
      Display_Detector( (87*up_steps)/rc_data.unit_elem );
  else
      if( isFlagSet(DISPLAY_SIGNAL) )
        Display_Signal( frag_lev );

  return( frag_lev );

} /* End of Get_Fragment() */

/*------------------------------------------------------------------------*/

/* Initialize_Detector()
 *
 * Initializes variables and allocates buffers
 * for the Goertzel tone detector
 */
gboolean
Initialize_Detector( void )
{
      double w =
        2.0 * M_PI * (double)rc_data.tone_freq /
        (double)rc_data.dsp_speed;
      detector_data.cosw  = cos(w);
      detector_data.sinw  = sin(w);
      detector_data.coeff = 2.0 * detector_data.cosw;

      detector_data.samples_buff_idx = 0;
      detector_data.sig_level_idx    = 0;
      detector_data.frag_len =
        ( rc_data.dsp_speed * CYCLES_PER_FRAG ) / rc_data.tone_freq;
      detector_data.samples_buff_len =
      (CYCLES_PER_FRAG *rc_data.max_unit *rc_data.dsp_speed) / rc_data.tone_freq;

      size_t alloc =
        (CYCLES_PER_FRAG *rc_data.max_unit *rc_data.dsp_speed) / rc_data.tone_freq;
      if( !mem_alloc((void *)&detector_data.samples_buff, alloc) )
        return( FALSE );
      alloc = sizeof(int) * rc_data.max_unit;
      if( !mem_alloc( (void *)&detector_data.sig_level_buff, alloc) )
        return( FALSE );

      return( TRUE );
} /* Initialize_Detector() */

/*------------------------------------------------------------------------*/


Generated by  Doxygen 1.6.0   Back to index