InjectTimeSeries.c

Go to the documentation of this file.
00001 /*
00002 *  Copyright (C) 2007 Jolien Creighton, Teviet Creighton, John Whelan
00003 *
00004 *  This program is free software; you can redistribute it and/or modify
00005 *  it under the terms of the GNU General Public License as published by
00006 *  the Free Software Foundation; either version 2 of the License, or
00007 *  (at your option) any later version.
00008 *
00009 *  This program is distributed in the hope that it will be useful,
00010 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00011 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012 *  GNU General Public License for more details.
00013 *
00014 *  You should have received a copy of the GNU General Public License
00015 *  along with with program; see the file COPYING. If not, write to the
00016 *  Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
00017 *  MA  02111-1307  USA
00018 */
00019 
00020 /***************************** <lalVerbatim file="InjectTimeSeriesCV">
00021 Author: Creighton, T. D.
00022 $Id: InjectTimeSeries.c,v 1.10 2007/06/08 14:41:47 bema Exp $
00023 **************************************************** </lalVerbatim> */
00024 
00025 /********************************************************** <lalLaTeX>
00026 
00027 \subsection{Module \texttt{InjectTimeSeries.c}}
00028 \label{ss:InjectTimeSeries.c}
00029 
00030 Injects a time series of floating-point numbers into a time series of
00031 integers, with dithering.
00032 
00033 \subsubsection*{Prototypes}
00034 \vspace{0.1in}
00035 \input{InjectTimeSeriesCP}
00036 \idx{LALSI2InjectTimeSeries()}
00037 \idx{LALSSInjectTimeSeries()}
00038 
00039 \subsubsection*{Description}
00040 
00041 The function \verb@LALSI2InjectTimeSeries()@ (i.e.\ ``Single-precision
00042 to \verb@INT2@'') dithers each sample in \verb@*output@, adds the
00043 nearest time sample from \verb@*signal@, and rounds to the nearest
00044 integer, storing the result back in \verb@*output@.  If desired, the
00045 random parameters for the dithering can be created outside this
00046 routine and passed in as \verb@*params@ (see \verb@Random.h@); if this
00047 pointer is \verb@NULL@, the parameters will be generated internally.
00048 
00049 The function \verb@LALSSInjectVector()@ (i.e.\ ``Single-precision to
00050 single-precision'') simply takes each sample from \verb@*output@ and
00051 adds the nearest corresponding time sample from \verb@*signal@,
00052 without performing any dithering.
00053 
00054 \subsubsection*{Algorithm}
00055 
00056 The algorithm is as given in \verb@InjectVector.c@, with the following
00057 additional considerations.  Since the two time series each carry their
00058 own information about epoch and sampling interval, the value to be
00059 injected at a given point in \verb@*output@ is found by taking the
00060 nearest time sample in \verb@*signal@.  Injection is only performed
00061 over the range in times that \verb@*output@ and \verb@*signal@
00062 overlap; other values in \verb@*output@ are untouched.
00063 
00064 Previous versions of this algorithm found the value to be injected by
00065 interpolating the two nearest samples in \verb@*signal@, which reduces
00066 high-frequency aliasing noise and ensures that the pre- and
00067 post-injection signals agree in timing to within a fraction of a
00068 sample.  However, this interpolation effectively convolved the signal
00069 with a triangular function of width $2\Delta t$, where $\Delta t$ is
00070 the sampling interval of the \emph{signal}.  This has the effect of a
00071 low-pass filter with an attenuation factor of $\sim0.8$ at frequencies
00072 $\sim1/4\Delta t$.  Since input signals are typically sampled at or
00073 near their Nyquist frequencies, this would represent an unacceptable
00074 level of attenuation.  For this reason, the current version of the
00075 algorithm eliminates the interpolation procedure.
00076 
00077 
00078 \subsubsection*{Uses}
00079 \begin{verbatim}
00080 LALCreateRandomParams()
00081 LALDestroyRandomParams()
00082 LALUniformDeviate()
00083 \end{verbatim}
00084 
00085 \subsubsection*{Notes}
00086 
00087 \vfill{\footnotesize\input{InjectTimeSeriesCV}}
00088 
00089 ******************************************************* </lalLaTeX> */
00090 
00091 #include <math.h>
00092 #include <lal/LALStdio.h>
00093 #include <lal/LALStdlib.h>
00094 #include <lal/LALError.h>
00095 #include <lal/Units.h>
00096 #include <lal/Random.h>
00097 #include <lal/Inject.h>
00098 
00099 NRCSID( INJECTTIMESERIESC, "$Id: InjectTimeSeries.c,v 1.10 2007/06/08 14:41:47 bema Exp $" );
00100 
00101 /* <lalVerbatim file="InjectTimeSeriesCP"> */
00102 void
00103 LALSI2InjectTimeSeries( LALStatus       *stat,
00104                         INT2TimeSeries  *output,
00105                         REAL4TimeSeries *signal,
00106                         RandomParams    *params )
00107 { /* </lalVerbatim> */
00108   INT4 n;  /* 1 + highest index of output touched by the injection */
00109   INT4 i;  /* index over output data */
00110   INT2 *outData; /* pointer to output->data->data */
00111   REAL8 dt;      /* output->deltaT in units of signal->deltaT */
00112   REAL8 offset;  /* the time from the start of *signal to the start
00113                      of *output, in units of signal->deltaT. */
00114   RandomParams *internal = NULL; /* internal random parameters */
00115 
00116   const INT2 max = 32767;  /* largest INT2 */
00117   const INT2 min = -32768; /* smallest INT2 */
00118 
00119   INITSTATUS( stat, "LALSI2InjectTimeSeries", INJECTTIMESERIESC );
00120   ATTATCHSTATUSPTR( stat );
00121 
00122   /* Make sure parameter structures and their fields exist. */
00123   ASSERT( signal, stat, INJECTH_ENUL, INJECTH_MSGENUL );
00124   ASSERT( signal->data, stat, INJECTH_ENUL, INJECTH_MSGENUL );
00125   ASSERT( signal->data->data, stat, INJECTH_ENUL, INJECTH_MSGENUL );
00126   ASSERT( output, stat, INJECTH_ENUL, INJECTH_MSGENUL );
00127   ASSERT( output->data, stat, INJECTH_ENUL, INJECTH_MSGENUL );
00128   ASSERT( output->data->data, stat, INJECTH_ENUL, INJECTH_MSGENUL );
00129   outData = output->data->data;
00130 
00131   /* Make sure we never divide by zero. */
00132   ASSERT( signal->deltaT != 0.0, stat, INJECTH_EBAD, INJECTH_MSGEBAD );
00133   dt = output->deltaT / signal->deltaT;
00134   ASSERT( dt != 0.0, stat, INJECTH_EBAD, INJECTH_MSGEBAD );
00135 
00136   /* Check dimensions. */
00137   {
00138     CHAR newName[LALNameLength];
00139     BOOLEAN unitsOK;
00140     LALUnitPair pair;
00141 
00142     pair.unitOne = &(signal->sampleUnits);
00143     pair.unitTwo = &lalADCCountUnit;
00144     TRY( LALUnitCompare( stat->statusPtr, &unitsOK, &pair ), stat );
00145     ASSERT( unitsOK, stat, INJECTH_EUNIT, INJECTH_MSGEUNIT );
00146     pair.unitOne = &(output->sampleUnits);
00147     TRY( LALUnitCompare( stat->statusPtr, &unitsOK, &pair ), stat );
00148     ASSERT( unitsOK, stat, INJECTH_EUNIT, INJECTH_MSGEUNIT );
00149     LALSnprintf( newName, LALNameLength, "%s plus %s", output->name,
00150                  signal->name );
00151     memcpy( output->name, newName, LALNameLength*sizeof(CHAR) );
00152   }
00153 
00154   /* If params = NULL, generate an internal set of parameters. */
00155   if ( !params )
00156     TRY( LALCreateRandomParams( stat->statusPtr, &internal, 0 ),
00157          stat );
00158   else
00159     internal = params;
00160 
00161   /* Compute offset. */
00162   offset = ( output->epoch.gpsSeconds - signal->epoch.gpsSeconds ) /
00163     signal->deltaT;
00164   offset += ( output->epoch.gpsNanoSeconds -
00165               signal->epoch.gpsNanoSeconds ) * 1.0e-9 /
00166     signal->deltaT;
00167 
00168   /* Compute initial value of i, and correct to ensure we will never
00169      index either array out of its bounds. */
00170   i = (INT4)( -offset / dt );
00171   if ( i < 0 )
00172     i = 0;
00173   while ( offset + i*dt < 0.0 )
00174     i++;
00175   if ( i >= (INT4)( output->data->length ) )
00176     LALWarning( stat, "Signal starts after the end of the output"
00177                 " time series." );
00178 
00179   /* Compute final value of i+1, and correct to ensure we will never
00180      index either array out of its bounds. */
00181   n = (INT4)( ( signal->data->length - offset ) / dt );
00182   if ( n > (INT4)( output->data->length ) )
00183     n = output->data->length;
00184   while ( offset + n*dt > signal->data->length )
00185     n--;
00186   if ( n <= 0 )
00187     LALWarning( stat, "Signal ends before the start of the output"
00188                 " time series." );
00189 
00190   /* Start injecting... */
00191   for ( ; i < n; i++ ) {
00192     REAL4 x = (REAL4)( outData[i] ); /* current output sample */
00193     REAL4 d;                         /* current dithering */
00194 
00195     /* Interpolate the signal.  ***REMOVED***
00196     REAL8 t = offset + i*dt;          interpolated signal index
00197     INT4 j = (INT4)floor( t );        signal index preceding t
00198     REAL4 frac = (REAL4)( t - j );    interpolation fraction
00199     REAL4 y = frac*(signal->data->data[j+1]) +    interpolated signal
00200       ( 1.0 - frac )*(signal->data->data[j]);     value */
00201 
00202     /* Extract the nearest signal sample. */
00203     INT4 j = (INT4)floor( offset + i*dt + 0.5 );
00204     REAL4 y = signal->data->data[j];
00205 
00206     /* Compute the dithering. */
00207     LALUniformDeviate( stat->statusPtr, &d, internal ); 
00208     BEGINFAIL( stat )
00209       if ( !params ) {
00210         TRY( LALDestroyRandomParams( stat->statusPtr, &internal ),
00211              stat );
00212       }
00213     ENDFAIL( stat );
00214 
00215     /* Dither and inject. */
00216     x += d + y;
00217     if ( x > max )
00218       outData[i] = max;
00219     else if ( x < min )
00220       outData[i] = min;
00221     else
00222       outData[i] = (INT2)( floor( x ) );
00223   }
00224 
00225   /* Cleanup and exit. */
00226   if ( !params ) {
00227     TRY( LALDestroyRandomParams( stat->statusPtr, &internal ), stat );
00228   }
00229   DETATCHSTATUSPTR( stat );
00230   RETURN( stat );
00231 }
00232 
00233 
00234 /* <lalVerbatim file="InjectTimeSeriesCP"> */
00235 void
00236 LALSSInjectTimeSeries( LALStatus       *stat,
00237                        REAL4TimeSeries *output,
00238                        REAL4TimeSeries *signal )
00239 { /* </lalVerbatim> */
00240   INT4 n;  /* 1 + highest index of output touched by the injection */
00241   INT4 i;  /* index over output data */
00242   REAL4 *outData; /* pointer to output->data->data */
00243   REAL8 dt;       /* output->deltaT in units of signal->deltaT */
00244   REAL8 offset;   /* the time from the start of *signal to the start
00245                      of *output, in units of signal->deltaT. */
00246 
00247   INITSTATUS( stat, "LALSSInjectTimeSeries", INJECTTIMESERIESC );
00248   ATTATCHSTATUSPTR( stat );
00249 
00250   /* Make sure parameter structures and their fields exist. */
00251   ASSERT( signal, stat, INJECTH_ENUL, INJECTH_MSGENUL );
00252   ASSERT( signal->data, stat, INJECTH_ENUL, INJECTH_MSGENUL );
00253   ASSERT( signal->data->data, stat, INJECTH_ENUL, INJECTH_MSGENUL );
00254   ASSERT( output, stat, INJECTH_ENUL, INJECTH_MSGENUL );
00255   ASSERT( output->data, stat, INJECTH_ENUL, INJECTH_MSGENUL );
00256   ASSERT( output->data->data, stat, INJECTH_ENUL, INJECTH_MSGENUL );
00257   outData = output->data->data;
00258 
00259   /* Make sure we never divide by zero. */
00260   ASSERT( signal->deltaT != 0.0, stat, INJECTH_EBAD, INJECTH_MSGEBAD );
00261   dt = output->deltaT / signal->deltaT;
00262   ASSERT( dt != 0.0, stat, INJECTH_EBAD, INJECTH_MSGEBAD );
00263 
00264   /* Check dimensions. */
00265   {
00266     CHAR newName[LALNameLength];
00267     BOOLEAN unitsOK;
00268     LALUnitPair pair;
00269 
00270     pair.unitOne = &(signal->sampleUnits);
00271     pair.unitTwo = &lalADCCountUnit;
00272     TRY( LALUnitCompare( stat->statusPtr, &unitsOK, &pair ), stat );
00273     ASSERT( unitsOK, stat, INJECTH_EUNIT, INJECTH_MSGEUNIT );
00274     pair.unitOne = &(output->sampleUnits);
00275     TRY( LALUnitCompare( stat->statusPtr, &unitsOK, &pair ), stat );
00276     ASSERT( unitsOK, stat, INJECTH_EUNIT, INJECTH_MSGEUNIT );
00277     LALSnprintf( newName, LALNameLength, "%s plus %s", output->name,
00278                  signal->name );
00279     memcpy( output->name, newName, LALNameLength*sizeof(CHAR) );
00280   }
00281 
00282   /* Compute offset. */
00283   offset = ( output->epoch.gpsSeconds - signal->epoch.gpsSeconds ) /
00284     signal->deltaT;
00285   offset += ( output->epoch.gpsNanoSeconds -
00286               signal->epoch.gpsNanoSeconds ) * 1.0e-9 /
00287     signal->deltaT;
00288 
00289   /* Compute initial value of i, and correct to ensure we will never
00290      index either array out of its bounds. */
00291   i = (INT4)( -offset / dt );
00292   if ( i < 0 )
00293     i = 0;
00294   while ( offset + i*dt < 0.0 )
00295     i++;
00296   if ( i >= (INT4)( output->data->length ) )
00297     LALWarning( stat, "Signal starts after the end of the output"
00298                 " time series." );
00299 
00300   /* Compute final value of i+1, and correct to ensure we will never
00301      index either array out of its bounds. */
00302   n = (INT4)( ( signal->data->length - offset ) / dt );
00303   if ( n > (INT4)( output->data->length ) )
00304     n = output->data->length;
00305   while ( offset + n*dt > signal->data->length )
00306     n--;
00307   if ( n <= 0 )
00308     LALWarning( stat, "Signal ends before the start of the output"
00309                 " time series." );
00310 
00311   /* Start injecting... */
00312   for ( ; i < n; i++ ) {
00313 
00314     /* Interpolate the signal.  ***REMOVED***
00315     REAL8 t = offset + i*dt;          interpolated signal index
00316     INT4 j = (INT4)floor( t );        signal index preceding t
00317     REAL4 frac = (REAL4)( t - j );    interpolation fraction
00318     REAL4 y = frac*(signal->data->data[j+1]) +    interpolated signal
00319       ( 1.0 - frac )*(signal->data->data[j]);     value */
00320 
00321     /* Extract the nearest signal sample. */
00322     INT4 j = (INT4)floor( offset + i*dt + 0.5 );
00323     REAL4 y = signal->data->data[j];
00324 
00325     /* Add the signal to the output. */
00326     outData[i] += y;
00327   }
00328 
00329   /* Exit. */
00330   DETATCHSTATUSPTR( stat );
00331   RETURN( stat );
00332 }

Generated on Sun Oct 12 02:31:59 2008 for LAL by  doxygen 1.5.2