home >> Low level routines for simulation >> pseudo code/code >> Simple non-linear dynsysts

Simple non-linear dynsysts

Bounder (Saturation)

It is the zero order filter that every one uses. Only here because I use it a lot in the following.
Behavior: its output is the input bounded to the [MIN, MAX] range with MIN< MAX.

//not applicable to angles
inline float minmax( float Input_i, float MIN, float MAX)
{
return Input_i> MAX? MAX : (Input_i< MIN? MIN : Input);
}

Bounder for angles

Behavior: the output is always one of the values encountered when starting a rotation from MIN included and moving counterclockwise till MAX is reached.
If Input is outside range, the return value is the closest of MIN and MAX.

//for angles only
float minmaxAng( float Input_i, float MIN, float MAX)// all in [0,PERIOD[
{
float TmpHalfRange= 0.5f*( MAX- MIN);
float TmpCenter= 0.5f*( MAX+ MIN);
if( MIN> MAX)
{
TmpCenter+= HALFPERIOD;
if( TmpCenter> PERIOD) TmpCenter-= PERIOD;
TmpHalfRange+= HALFPERIOD;
}
float TmpDelta= wrapHalfPrd(Input_i- TmpCenter);
if( TmpDelta> TmpHalfRange) return MAX;
else if( TmpDelta< -TmpHalfRange) return MIN;
return Input_i;
}

Threshold (Dead range)

Time step independant zero order filter.
Behavior: the output is zero when the input is within [MIN, MAX] range, with MIN< MAX;
for Input> MAX, Output= Input- MAX; ( and not Output=Input ie no jump at bounds).
for Input< MIN, Output= Input- MIN; ( and not Output=Input).

As threshold(Input)+ minmax(Input)= Input, it can be viewed as the complementary filter of minmax().

//not applicable to angles
float threshold( float Input_i, float MIN, float MAX)
{
return ( Input_i- minmax(Input_i, MIN, MAX)) ;
}

Threshold for angles

Threshold for angles, symmetrical and centered on "PrmCenter"

// for angles only
float thresholdSymAng( float Input_i, float PrmCenter_i, float PrmHalfRange_i)//all in [0, PERIOD[
{
float D_a= wrapHalfPrd( Input_i- PrmCenter_i);
if( D_a> PrmHalfRange_i)
{
Input_i-= PrmHalfRange_i;
if( Input_i< 0) Input_i+= PERIOD;
return Input_i;
}
else if( D_a< -PrmHalfRange_i)
{
Input_i+= PrmHalfRange_i;
if( Input_i>= PERIOD) Input_i-= PERIOD;
return Input_i;
}
return PrmCenter_i;
}

Threshold for angles, general case

for angles only
float thresholdAng( float InputAng_i, float MIN, float MAX)//all in [0, PERIOD[
{
float TmpHR= 0.5f*( MAX- MIN);
float TmpC= 0.5f*( MAX+ MIN);
if( MIN> MAX)
{
TmpC+= HALFPERIOD;
if( TmpC> PERIOD) TmpC-= PERIOD;
TmpHR+= HALFPERIOD;
}
return thresholdSymAng( InputAng_i, TmpC, TmpHR);
}

Backlash ( or Play)

timestep independent 1st order dynsyst. Sometimes ( wrongly) referred to as hysteresis.
Behavior: it is a "floating" dead-range around the current input value ,and is actually implemented by placing a threshold on (Input-Output).

//not applicable to angles
inline float backlash( float Output_i/*previous step value*/, float Input_i, float HALFDEADRANGE)
{
return Output_i+ threshold( Input_i- Output_i, -HALFDEADRANGE, HALFDEADRANGE);
//or: return Input_i- minmax( Input_i- Output_i, -HALFDEADRANGE, HALFDEADRANGE);
}

Backlash for angles

//for angles only
float backlashAng( float Output_i/*previous step value*/, float Input_i, float HALFDEADRANGE)
{
float TmpDelta= wrapHalfPrd( Input_i- Output_i);
Output_i+= TmpDelta;
TmpDelta= minmax( TmpDelta,-HALFDEADRANGE,+ HALFDEADRANGE);
Output_i-= TmpDelta;
Output_i= wrapPrd( Output_i);
return Output_i;
}

Rate(speed) bounder

time step dependent 1st order dynsysts.
Behavior: the output rate of increase or "Speed"=(Xn - Xn-1)/T is bounded to the [SPEEDMIN, SPEEDMAX] range, with SPEEDMIN<0< SPEEDMAX.


float minmaxSpeed( float T/*current timestep*/, float Output_i/*previous step value*/, float Input_i, float SPEEDMIN, float SPEEDMAX)
{
float TmpDelta= (Input_i- Output_i);
TmpDelta= wrapHalfPrd( TmpDelta);
float TmpSpeed= TmpDelta/ T;
TmpSpeed= minmax( TmpSpeed, SPEEDMIN, SPEEDMAX);

Output_i= Output_i+ T* TmpSpeed;
Output_i= wrapPrd( Output_i);
return Output_i;
}