Skip to main content
  • Home
  • Development
  • Documentation
  • Donate
  • Operational login
  • Browse the archive

swh logo
SoftwareHeritage
Software
Heritage
Archive
Features
  • Search

  • Downloads

  • Save code now

  • Add forge now

  • Help

Revision 4dbf0ec391b877f21402aed9e8351fe8f7468d14 authored by D019 Rig on 19 December 2019, 23:25:22 UTC, committed by D019 Rig on 19 December 2019, 23:25:22 UTC
Update Calibration
1 parent 4cac1d4
  • Files
  • Changes
  • cb6e09d
  • /
  • Tools
  • /
  • Program_Maestro_and_CX
  • /
  • v410
  • /
  • cxdata_src_V410
  • /
  • pertmgr.c
Raw File Download

To reference or cite the objects present in the Software Heritage archive, permalinks based on SoftWare Hash IDentifiers (SWHIDs) must be used.
Select below a type of object currently browsed in order to display its associated SWHID and permalink.

  • revision
  • directory
  • content
revision badge
swh:1:rev:4dbf0ec391b877f21402aed9e8351fe8f7468d14
directory badge
swh:1:dir:7cb7f028037ea1fe6743e8c4ed8776a4befa1faa
content badge
swh:1:cnt:f996ab137db615f1bae94b7dbaacd1a43c0847db

This interface enables to generate software citations, provided that the root directory of browsed objects contains a citation.cff or codemeta.json file.
Select below a type of object currently browsed in order to generate citations for them.

  • revision
  • directory
  • content
Generate software citation in BibTex format (requires biblatex-software package)
Generating citation ...
Generate software citation in BibTex format (requires biblatex-software package)
Generating citation ...
Generate software citation in BibTex format (requires biblatex-software package)
Generating citation ...
pertmgr.c
//=====================================================================================================================
//
// pertmgr.c : READCXDATA helper functions -- reproduction of Maestro perturbation waveforms modulating a trial target
// trajectory.
//
// AUTHOR:  saruffner
//
// DESCRIPTION:
// Maestro/MaestroDRIVER supports the perturbation of trial target trajectories via the application of one of several 
// kinds of perturbation waveforms, defined by the TARGET_PERTURB trial code group. This module encapsulates the 
// details of processing the TARGET_PERTURB trial codes and calculating the contributions of any defined perturbations
// on a tick-by-tick basis. It essentially reproduces the code from the class CCxPertHelper, which is part of 
// MaestroDRIVER's code base. It also includes the uniform and Gaussian random number generators that implement the 
// PERT_ISNOISE and PERT_ISGAUSS perturbation types.
//
// REVISION HISTORY:
// 29jul2005-- Began development.
// 16jul2007-- Added support for perturbing target window or pattern speed (PERT_ON_SWIN, PERT_ON_SPAT), which was 
//             introduced in Maestro 2.1.2.
// 06sep2007-- Added support for perturing target window AND pattern speed at the same time (PERT_ON_SPD), or target 
//             window and pattern direction at the same time (PERT_ON DIR). These were introduced in Maestro 2.1.3.
//=====================================================================================================================

#include "math.h"                      // for various math/trig functions

#ifndef M_PI                           // this is defined on UNIX/Linux/Mac, but not Windows
   #define M_PI 3.14159265359
#endif

#include "pertmgr.h"

#define TORADIANS(D) (((double)D) * M_PI / 180.0)


//=====================================================================================================================
// MODULE-PRIVATE FUNCTION PROTOTYPES
//=====================================================================================================================
double computePert( int iTime, PMPERTOBJ pPert );


//=====================================================================================================================
// FUNCTIONS FOR RANDOM NUMBER GENERATION
//
// These functions and the corresponding state information essentially reproduce the functionality of Maestro CXDRIVER
// classes CUniformRNG and CGaussRNG defined in cxdriver/utilities.cpp.  The header comments for those two classes are
// copied below...
//
// Implementation of class CUniformRNG
// -----------------------------------
// This class encapsulates a pseudo-random number generator that returns a sequence of uniformly distributed floating-
// point values in (0.0 .. 1.0), endpoints excluded.  It encapsulates the "ran1" algorithm presented on p.282 in:
// Press, WH; et al.  "Numerical recipes in C: the art of acientific computing".  New York:  Cambridge University
// Press, Copyright 1988-1992.
//
// The algorithm uses a 32-entry table to shuffle the output of a "Minimal Standard" linear congruential generator, of
// the form I(n+1) = A*I(n) % M (with A and M carefully chosen).  Schrage's method is used to compute I(n+1) without
// an integer overflow.  The 32-bit integers output by the algorithm fall in the range [1..M-1]; dividing by M=2^31
// gives a double-valued output in (0..1).  For algorithmic details, consult the book.  There are few comments here.
//
// Portability note:  We assume here that int is 32-bit!!
//
// IAW the licensing policy of "Numerical Recipes in C", this class is not distributable in source code form without
// obtaining the appropriate license; however, it may appear in an executable file that is distributed.
//
// Implementation of class CGaussRNG
// ---------------------------------
// This class encapsulates a pseudo-random number generator that returns a sequence of normally distributed floating-
// point values with zero mean and unit variance.  It encapsulates the "gasdev" algorithm presented on p.289 in:
// Press, WH; et al.  "Numerical recipes in C: the art of acientific computing".  New York:  Cambridge University
// Press, Copyright 1988-1992.
//
// The algorithm uses the polar form of the Box-Muller transformation to transform a sequence of uniform deviates to
// a sequence of Gaussian deviates.  We use CUniformRNG as the source of the uniform sequence.  For algorithmic
// details, consult the book.
//
// IAW the licensing policy of "Numerical Recipes in C", this class is not distributable in source code form without
// obtaining the appropriate license; however, it may appear in an executable file that is distributed.
//=====================================================================================================================

VOID seedUniformRNG( PUNIFORMRNG pUnif, int seed )
{
   int j, k;

   pUnif->curr = (seed == 0) ? 1 : ((seed < 0) ? -seed : seed);      // start at strictly positive seed value

   for( j = URNG_TABLESZ+7; j >= 0; j-- )                            // after discarding first 8 integers generated
   {                                                                 // by the algorithm, fill shuffle table with
      k = pUnif->curr/URNG_Q;                                        // next TABLESZ integers generated
      pUnif->curr = URNG_A * (pUnif->curr - k*URNG_Q) - k*URNG_R;
      if( pUnif->curr < 0 ) pUnif->curr += URNG_M;
      if( j < URNG_TABLESZ ) pUnif->shuffle[j] = pUnif->curr;
   }

   pUnif->lastOut = pUnif->shuffle[0];
}

double getUniformRNG( PUNIFORMRNG pUnif )
{
   int k, index;

   k = pUnif->curr/URNG_Q;                                     // compute I(n+1) = A*I(n) % M using Schrage's method
   pUnif->curr = URNG_A * (pUnif->curr - k*URNG_Q) - k*URNG_R; // to avoid integer overflows
   if( pUnif->curr < 0 ) pUnif->curr += URNG_M;

   index = pUnif->lastOut / URNG_NDIV;                         // use last # retrieved from shuffle table to calc
   pUnif->lastOut = pUnif->shuffle[index];                     // index of next # to retrieve. Replace that entry in
   pUnif->shuffle[index] = pUnif->curr;                        // shuffle table with curr output of LC generator

   return( URNG_DSCALE * pUnif->lastOut );                     // convert int in [1..M-1] to double in (0..1)
}

VOID seedGaussRNG( PGAUSSRNG pGauss, int seed )
{
   seedUniformRNG( &(pGauss->uniformRNG), seed );
   pGauss->bGotNext = FALSE;
}

double getGaussRNG( PGAUSSRNG pGauss )
{
   double dVal = 0;
   double v1, v2, rsq, fac;

   if( !pGauss->bGotNext )
   {
      do                                                          // get two uniform deviates v1,v2 such that (v1,v2)
      {                                                           // lies strictly inside the unit circle, but not at
         v1 = 2.0 * getUniformRNG( &(pGauss->uniformRNG) ) - 1.0; // the origin
         v2 = 2.0 * getUniformRNG( &(pGauss->uniformRNG) ) - 1.0;
         rsq = v1*v1 + v2*v2;
      } while( rsq >= 1.0 || rsq == 0.0 );

      fac = sqrt( -2.0 * log(rsq) / rsq );                        // use Box-Muller transformation to transform the
      pGauss->dNext = v1*fac;                                     // the uniform deviates to two Gaussian deviates, one
      pGauss->bGotNext = TRUE;                                    // of which is saved for next call to this function!
      dVal = v2*fac;
   }
   else
   {
      dVal = pGauss->dNext;
      pGauss->bGotNext = FALSE;
   }

   return( dVal );
}


//=====================================================================================================================
// FUNCTIONS FOR THE PERTURBATION MANAGER
//
// These functions duplicate similarly named functions in the MaestroDRIVER class CCxPertHelper.  Each function has
// a header **copied from the CCxPertHelper source file**.  You can think of the PERTMGR pointer argument in these
// methods as roughly equivalent to the hidden 'this' pointer in C++.
//=====================================================================================================================

//=== Reset ===========================================================================================================
//
//    Remove all currently defined perturbations.  Release any random number generators that were created to implement
//    noise perturbations.
//
//    ARGS:       NONE.
//    RETURNS:    NONE.
//
VOID resetPertManager( PMPERTMGR pPertMgr )
{
   pPertMgr->nPerts = 0;
}

//=== ProcessTrialCodes ===============================================================================================
//
//    Translates a TARGET_PERTURB trial code set into a new perturbation object to be applied during the trial.  The
//    index of the affected target, the perturbation's start time within the trial, and the affected target velocity
//    component are all included in the trial code set, along with the parameters defining the perturbation itself.
//
//    ARGS:       pCodes -- [in] ptr to a set of five TRIALCODEs representing a TARGET_PERTURB code group.
//
//    RETURNS:    TRUE if successful, FALSE otherwise.
//
BOOL processPertCodes( PMPERTMGR pPertMgr, TRIALCODE* pCodes )
{
   PMPERTOBJ pNew;

   if( pPertMgr->nPerts == MAX_TRIALPERTS || pCodes[0].code != TARGET_PERTURB ) return( FALSE );

   pNew = &(pPertMgr->perts[ pPertMgr->nPerts ]);
   pNew->iTgt = (int) pCodes[1].code;
   pNew->idCmpt = (int) (pCodes[1].time >> 4);
   pNew->iStart = (int) pCodes[0].time;
   pNew->fAmp = ((float) pCodes[2].code) / 10.0f;
   pNew->def.iType = (int) (pCodes[1].time & 0x0F);
   pNew->def.iDur = (int) pCodes[2].time;

   switch( pNew->def.iType )                                      // translate type-specific perturbation parameters
   {
      case PERT_ISSINE :
         pNew->def.sine.iPeriod = (int) pCodes[3].code;
         pNew->def.sine.fPhase = ((float) pCodes[3].time)/100.0f;
         break;
      case PERT_ISTRAIN :
         pNew->def.train.iPulseDur = (int) pCodes[3].code;
         pNew->def.train.iRampDur = (int) pCodes[3].time;
         pNew->def.train.iIntv = (int) pCodes[4].code;
         break;
      case PERT_ISNOISE :
      case PERT_ISGAUSS :
         pNew->def.noise.iUpdIntv = (int) pCodes[3].code;
         pNew->def.noise.fMean = ((float) pCodes[3].time)/1000.0f;
         pNew->def.noise.iSeed = (int) MAKELONG(pCodes[4].time, pCodes[4].code);
         if( pNew->def.iType == PERT_ISNOISE )
            seedUniformRNG( &(pNew->uniformRNG), pNew->def.noise.iSeed );
         else
            seedGaussRNG( &(pNew->gaussRNG), pNew->def.noise.iSeed );
         pNew->dLastRandom = 0.0;
         break;
      default :
         return( FALSE );
   }

   ++(pPertMgr->nPerts);
   return( TRUE );
}


//=== Perturb =========================================================================================================
//
//    Calculate the offset vectors (DH, DV) that represent the net effect of any perturbations applied to the nominal
//    window and pattern velocities of the specified target.  If none of the currently defined perturbations affect
//    the specified target at the current time, then both offset vectors will be (0,0).
//
//    IMPORTANT:  By design, the two directional perturbations (PERT_ON_DWIN, PERT_ON_DPAT) rotate the *nominal*
//    velocity vector by some random angle. The offset vector returned gives the horizontal and vertical deltas
//    necessary to achieve this rotation. Applying a directional and a velocity component or speed perturbation at the 
//    same time would be rather confusing!
//
//    ARGS:       iTgt        -- [in] index of target in the trial target map.
//                iTime       -- [in] current trial time in ms.
//                fpWin       -- [in] current "nominal" window velocity of tgt
//                fpPat       -- [in] current "nominal" pattern velocity of tgt
//                fpPertWin   -- [out] net offset in "nominal" window velocity due to any defined perturbations
//                fpPertPat   -- [out] net offset in "nominal" pattern velocity due to any defined perturbations
//
//    RETURNS:    NONE.
//
VOID perturbTarget( PMPERTMGR pPertMgr, int iTgt, int iTime, double winVelH, double winVelV, double patVelH,
   double patVelV, double* pWinOffsetH, double* pWinOffsetV, double* pPatOffsetH, double* pPatOffsetV )
{
   int i;
   double dCurr;
   double dR, dTheta;                                             // for handling directional perts
   PMPERTOBJ pPert;

   *pWinOffsetH = 0.0;                                            // make sure net perturbations start at (0,0)!
   *pWinOffsetV = 0.0;
   *pPatOffsetH = 0.0;
   *pPatOffsetV = 0.0;

   for( i = 0; i < pPertMgr->nPerts; i++ )                        // for each active perturbation...
   {
      pPert = &(pPertMgr->perts[i]);
      if( iTgt == pPert->iTgt )                                   // ...if pert affects this tgt,
      {
         dCurr = computePert( iTime, pPert );                     //    compute the current value of the velocity
         if( dCurr == 0.0 ) continue;                             //    or directional pert.  if 0, no effect.

         switch( pPert->idCmpt )                                  //    if perturbed, update the appropriate offset
         {                                                        //    vector IAW what trajectory cmpt is perturbed
            case PERT_ON_HWIN :
               *pWinOffsetH += dCurr;
               break;
            case PERT_ON_VWIN :
               *pWinOffsetV += dCurr;
               break;
            case PERT_ON_HPAT :
               *pPatOffsetH += dCurr;
               break;
            case PERT_ON_VPAT :
               *pPatOffsetV += dCurr;
               break;
            case PERT_ON_DWIN :                                   //   NOTE: the directional pert is a rotation in
               dR = sqrt( winVelH*winVelH + winVelV*winVelV );    //   in degrees, not radians!
               dTheta = atan2( winVelV, winVelH );
               dTheta += TORADIANS(dCurr);
               *pWinOffsetH += dR * cos(dTheta) - winVelH;
               *pWinOffsetV += dR * sin(dTheta) - winVelV;
               break;
            case PERT_ON_DPAT :
               dR = sqrt( patVelH * patVelH + patVelV * patVelV );
               dTheta = atan2( patVelV, patVelH );
               dTheta += TORADIANS(dCurr);
               *pPatOffsetH += dR * cos(dTheta) - patVelH;
               *pPatOffsetV += dR * sin(dTheta) - patVelV;
               break;
            case PERT_ON_SWIN :
               dR = sqrt( winVelH*winVelH + winVelV*winVelV ); 
               dR += dCurr;
               dTheta = atan2( winVelV, winVelH );
               *pWinOffsetH += dR * cos(dTheta) - winVelH;
               *pWinOffsetV += dR * sin(dTheta) - winVelV;
               break;
            case PERT_ON_SPAT :
               dR = sqrt( patVelH * patVelH + patVelV * patVelV );
               dR += dCurr;
               dTheta = atan2( patVelV, patVelH );
               *pPatOffsetH += dR * cos(dTheta) - patVelH;
               *pPatOffsetV += dR * sin(dTheta) - patVelV;
               break;
            case PERT_ON_DIR :
               dR = sqrt( winVelH*winVelH + winVelV*winVelV ); 
               dTheta = atan2( winVelV, winVelH );
               dTheta += TORADIANS(dCurr);
               *pWinOffsetH += dR * cos(dTheta) - winVelH;
               *pWinOffsetV += dR * sin(dTheta) - winVelV;
               dR = sqrt( patVelH * patVelH + patVelV * patVelV );
               dTheta = atan2( patVelV, patVelH );
               dTheta += TORADIANS(dCurr);
               *pPatOffsetH += dR * cos(dTheta) - patVelH;
               *pPatOffsetV += dR * sin(dTheta) - patVelV;
               break;
            case PERT_ON_SPD :
               dR = sqrt( winVelH*winVelH + winVelV*winVelV ); 
               dR += dCurr;
               dTheta = atan2( winVelV, winVelH );
               *pWinOffsetH += dR * cos(dTheta) - winVelH;
               *pWinOffsetV += dR * sin(dTheta) - winVelV;
               dR = sqrt( patVelH * patVelH + patVelV * patVelV );
               dR += dCurr;
               dTheta = atan2( patVelV, patVelH );
               *pPatOffsetH += dR * cos(dTheta) - patVelH;
               *pPatOffsetV += dR * sin(dTheta) - patVelV;
               break;
         }
      }
   }
}


//=== Compute =========================================================================================================
//
//    Compute value of specified perturbation waveform for the specified trial time.
//
//    ARGS:       iTime -- [in] trial time in ms.
//                pPert -- [in] the perturbation object
//
//    RETURNS:    perturbation value (either velocity in deg/s or a directional offset in deg)
//
double computePert( int iTime, PMPERTOBJ pPert )
{
   int t, t1, t2, t3;
   double dVal, dAmp, dTwoPi, dOmega_t, dRad, dSlope, dTime;

   if( iTime < pPert->iStart ||                                   // perturbation off
       iTime >= (pPert->iStart + pPert->def.iDur) )
      return( 0.0 );

   t = iTime - pPert->iStart;                                     // time since perturbation started
   dVal = 0.0;                                                    // computed value of perturbation waveform

   if( pPert->def.iType == PERT_ISSINE )                          // SINE: v(t) = A*sin(2PI*t/T + phi), where A = amp
   {                                                              // in deg/s, T = period in ms, phi = phase in deg.
      dAmp = (double) pPert->fAmp;
      dTwoPi = M_PI * 2.0;
      dOmega_t = dTwoPi * ((double) t) / ((double)pPert->def.sine.iPeriod);
      dRad = dOmega_t + TORADIANS( pPert->def.sine.fPhase );
      while( dRad >= dTwoPi ) dRad -= dTwoPi;

      dVal = dAmp * sin( dRad );
   }
   else if( pPert->def.iType == PERT_ISTRAIN )                    // TRAIN: Let D= pulse dur(ms), I= intv (ms),
   {                                                              // R= ramp dur(ms), and A = pulse amp(deg/s).
      t = t % pPert->def.train.iIntv;                             //    t' = time within a pulse presentation
      t1 = pPert->def.train.iRampDur;                             //    end of acceleration phase
      t2 = t1 + pPert->def.train.iPulseDur;                       //    end of constant-velocity phase
      t3 = t2 + pPert->def.train.iRampDur;                        //    end of deceleration phase

      dSlope = ((double)pPert->fAmp) * 1000.0;                    //    ramp "slope" = A/(R/1000) in deg/sec^2
      dSlope /= (double) pPert->def.train.iRampDur;

      dTime = ((double) t) / 1000.0;                              //    t' converted from ms --> sec

      if( t >= 0 && t < t1 ) dVal = dSlope * dTime;               //    for t' in [0..R), v(t') = slope * t'.
      else if( t >= t1 && t < t2 ) dVal = ((double) pPert->fAmp); //    for t' in [R..R+D), v(t') = A.
      else if( t >= t2 && t < t3 )                                //    for t' in [R+D..2R+D),
         dVal = dSlope * (((double)t3)/1000.0 - dTime);           //       v(t') = slope * (2R+D-t' in sec)
   }
   else if( pPert->def.iType == PERT_ISNOISE )                    // Uniform NOISE: Steplike waveform changes once per
   {                                                              // update interval.
      if( t % pPert->def.noise.iUpdIntv == 0 )
      {
         dVal = 2.0*getUniformRNG( &(pPert->uniformRNG) ) - 1.0;  //    2*U(0..1) - 1 ==> U(-1..1)
         dVal += (double) pPert->def.noise.fMean;                 //    U(-1_mean .. 1+mean)
         dVal *= (double) pPert->fAmp;                            //    U(-1+mean .. 1+mean)*amplitude
         pPert->dLastRandom = dVal;                               //    remember value until next update
      }
      else
         dVal = pPert->dLastRandom;
   }
   else if( pPert->def.iType == PERT_ISGAUSS )                    // Gaussian NOISE: Steplike waveform changes once per
   {                                                              // update interval.
      if( t % pPert->def.noise.iUpdIntv == 0 )
      {
         dVal = getGaussRNG( &(pPert->gaussRNG) );                //    N(0,1) [Gaussian w/zero mean and 1 std dev]
         dVal *= (double) pPert->fAmp;                            //    N(0,amplitude)
         dVal += (double) (pPert->def.noise.fMean * pPert->fAmp); //    N(mean*amplitude, amplitude)
         pPert->dLastRandom = dVal;                               //    remember value until next update
      }
      else
         dVal = pPert->dLastRandom;
   }

   return( dVal );
}

The diff you're trying to view is too large. Only the first 1000 changed files have been loaded.
Showing with 0 additions and 0 deletions (0 / 0 diffs computed)
swh spinner

Computing file changes ...

back to top

Software Heritage — Copyright (C) 2015–2026, The Software Heritage developers. License: GNU AGPLv3+.
The source code of Software Heritage itself is available on our development forge.
The source code files archived by Software Heritage are available under their own copyright and licenses.
Terms of use: Archive access, API— Content policy— Contact— JavaScript license information— Web API