//not applicable to angles
inline float  minmax( float Input_i, float MIN, float MAX)
{
return Input_i> MAX?  MAX : (Input_i< MIN? MIN : Input);
}
 
	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;		
}
	
	
//not applicable to angles
	float threshold( float Input_i, float  MIN, float  MAX)
	{
	return ( Input_i- minmax(Input_i, MIN, MAX)) ;
	}
		
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);
}
	
 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);
}
	
//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;
}
	
	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;
}