Simbody  3.6
Smoothed step functions

Functions stepUp(), stepDown() and stepAny() provide smooth, S-shaped step functions that are useful for "softening" abrupt transitions between two values. More...

## Functions

double SimTK::stepUp (double x)
Interpolate smoothly from 0 up to 1 as the input argument goes from 0 to 1, with first and second derivatives zero at either end of the interval. More...

double SimTK::stepDown (double x)
Interpolate smoothly from 1 down to 0 as the input argument goes from 0 to 1, with first and second derivatives zero at either end of the interval. More...

double SimTK::stepAny (double y0, double yRange, double x0, double oneOverXRange, double x)
Interpolate smoothly from y0 to y1 as the input argument goes from x0 to x1, with first and second derivatives zero at either end of the interval. More...

double SimTK::dstepUp (double x)
First derivative of stepUp(): d/dx stepUp(x). More...

double SimTK::dstepDown (double x)
First derivative of stepDown(): d/dx stepDown(x). More...

double SimTK::dstepAny (double yRange, double x0, double oneOverXRange, double x)
First derivative of stepAny(): d/dx stepAny(x). More...

double SimTK::d2stepUp (double x)
Second derivative of stepUp(): d^2/dx^2 stepUp(x). More...

double SimTK::d2stepDown (double x)
Second derivative of stepDown(): d^2/dx^2 stepDown(x). More...

double SimTK::d2stepAny (double yRange, double x0, double oneOverXRange, double x)
Second derivative of stepAny(): d^2/dx^2 stepAny(x). More...

double SimTK::d3stepUp (double x)
Third derivative of stepUp(): d^3/dx^3 stepUp(x). More...

double SimTK::d3stepDown (double x)
Third derivative of stepDown(): d^3/dx^3 stepDown(x). More...

double SimTK::d3stepAny (double yRange, double x0, double oneOverXRange, double x)
Third derivative of stepAny(): d^3/dx^3 stepAny(x). More...

float SimTK::stepUp (float x)
Interpolate smoothly from 0 up to 1 as the input argument goes from 0 to 1, with first and second derivatives zero at either end of the interval. More...

float SimTK::stepDown (float x)
Interpolate smoothly from 1 down to 0 as the input argument goes from 0 to 1, with first and second derivatives zero at either end of the interval. More...

float SimTK::stepAny (float y0, float yRange, float x0, float oneOverXRange, float x)
Interpolate smoothly from y0 to y1 as the input argument goes from x0 to x1, with first and second derivatives zero at either end of the interval. More...

float SimTK::dstepUp (float x)
First derivative of stepUp(): d/dx stepUp(x). More...

float SimTK::dstepDown (float x)
First derivative of stepDown(): d/dx stepDown(x). More...

float SimTK::dstepAny (float yRange, float x0, float oneOverXRange, float x)
First derivative of stepAny(): d/dx stepAny(x). More...

float SimTK::d2stepUp (float x)
Second derivative of stepUp(): d^2/dx^2 stepUp(x). More...

float SimTK::d2stepDown (float x)
Second derivative of stepDown(): d^2/dx^2 stepDown(x). More...

float SimTK::d2stepAny (float yRange, float x0, float oneOverXRange, float x)
Second derivative of stepAny(): d^2/dx^2 stepAny(x). More...

float SimTK::d3stepUp (float x)
Third derivative of stepUp(): d^3/dx^3 stepUp(x). More...

float SimTK::d3stepDown (float x)
Third derivative of stepDown(): d^3/dx^3 stepDown(x). More...

float SimTK::d3stepAny (float yRange, float x0, float oneOverXRange, float x)
Third derivative of stepAny(): d^3/dx^3 stepAny(x). More...

double SimTK::stepUp (int x)
Interpolate smoothly from 0 up to 1 as the input argument goes from 0 to 1, with first and second derivatives zero at either end of the interval. More...

double SimTK::stepDown (int x)
Interpolate smoothly from 1 down to 0 as the input argument goes from 0 to 1, with first and second derivatives zero at either end of the interval. More...

## Detailed Description

Functions stepUp(), stepDown() and stepAny() provide smooth, S-shaped step functions that are useful for "softening" abrupt transitions between two values.

Functions that return the first three derivatives of these step functions are also provided.

y=stepUp(x) for x=0:1 returns a smooth, S-shaped step function y(x), symmetric about the midpoint x=0.5, such that y(0)=0, y(1)=1, y'(0)=y''(0)=y'(1)=y''(1)=0, where the primes indicate differentiation with respect to x. No guarantees are made about the behavior of higher derivatives except to say that y''' does exist.

y=stepDown(x) for x=0:1 is a mirror image S curve that takes y down from 1 to 0 smoothly as x goes from 0 to 1. As with stepUp() y' and y'' are 0 at both ends, but here y(0)=1 and y(1)=0.

The stepAny() function is also available to make a step function that takes y smoothly from y0 to y1 as x goes from x0 to x1.

We also provide functions that calculate the first three derivatives of stepUp(), stepDown(), and stepAny(), namely: dstepUp(), d2stepUp(), d3stepUp(), and similarly dstepDown(), dstepAny() and so on. Note again that the third derivative is not guaranteed to be well behaved.

Costs of the current implementations of these inline functions are:

The corresponding stepDown() methods cost one extra flop; the stepAny() methods cost 6 extra flops (provided you do some precalculation; see the stepAny() documentation).

## ◆ stepUp() [1/3]

 double SimTK::stepUp ( double x )
inline

Interpolate smoothly from 0 up to 1 as the input argument goes from 0 to 1, with first and second derivatives zero at either end of the interval.

Parameters
 [in] x The control parameter, in range [0,1].
Returns
The smoothed output value, in range [0,1] but with first and second derivatives smoothly approaching zero as x approaches either end of its interval.

See the documentation for stepAny() for a discussion about how to shift and scale this function to produce arbitrary steps.

This function is overloaded for all the floating point precisions. Cost is 7 flops.

stepDown(), stepAny()

## ◆ stepDown() [1/3]

 double SimTK::stepDown ( double x )
inline

Interpolate smoothly from 1 down to 0 as the input argument goes from 0 to 1, with first and second derivatives zero at either end of the interval.

Parameters
 [in] x The control parameter, in range [0,1].
Returns
The smoothed output value, in range [1,0] but with first and second derivatives smoothly approaching zero as x approaches either end of its interval.

See the documentation for stepAny() for a discussion about how to shift and scale this function to produce arbitrary steps.

This function is overloaded for all the floating point precisions. Cost is 8 flops.

stepUp(), stepAny()

## ◆ stepAny() [1/2]

 double SimTK::stepAny ( double y0, double yRange, double x0, double oneOverXRange, double x )
inline

Interpolate smoothly from y0 to y1 as the input argument goes from x0 to x1, with first and second derivatives zero at either end of the interval.

Parameters
 [in] y0 The output value when x=x0. [in] yRange The amount by which the output can change over the full interval, that is, yRange=(y1-y0) where y1 is the value of the output when x=x1. [in] x0 The minimum allowable value for x. [in] oneOverXRange 1/xRange, where xRange is the amount by which the input variable x can change over its full interval, that is, xRange=(x1-x0) where x1 is the maximum allowable value for x. [in] x The control parameter, in range [x0,x1]. This is often a time over which the output transition from y0 to y1 is to occur.
Returns
The smoothed output value, in range [y0,y1] (where y1=y0+yRange) but with first and second derivatives smoothly approaching zero as x approaches either end of its interval.

Note that the desired curve is defined in terms of y0 and (y1-y0), and x0 and 1/(x1-x0), rather than y0,y1,x0,x1 which would make for a nicer calling signature. This is a concession to efficiency since the two ranges are likely to be unchanged during many calls to this function and can thus be precalculated. It wouldn't matter except that division is so expensive (equivalent to 15-20 floating point operations). If you aren't concerned about that (and in most cases it won't matter), you can call this function using y0,y1,x0,x1 like this:

y = stepAny(y0,y1-y0,x0,1/(x1-x0), x);

Not counting the cost of calculating the ranges, each call to this function requires 13 flops. Calculating the ranges in the argument list as shown above raises the per-call cost to about 30 flops. However, there are many common special cases that are much simpler. For example, if y is to go from -1 to 1 while x goes from 0 to 1, then you can write:

y = stepAny(-1,2,0,1, x);

which is still only 13 flops despite the lack of pre-calculation.

Theory

stepUp() and stepDown() and their derivatives are defined only for arguments in the range 0 to 1. To create a general step function that smoothly interpolates from y=y0 to y1 while x goes from x0 to x1, and three derivatives, we use the stepUp() functions like this:

ooxr = 1/(x1-x0); // one over x range (signed)
yr = y1-y0; // y range (signed)
xadj = (x-x0)*ooxr // x adjusted into 0:1 range (watch for roundoff)
y = y0 + yr * stepUp(xadj);
dy = yr*ooxr * dstepUp(xadj);
d2y = yr*ooxr^2 * d2stepUp(xadj);
d3y = yr*ooxr^3 * d3stepUp(xadj);

As a common special case, note that when y has a general range but x is still in [0,1], the above simplifies considerably and you can save a few flops if you want by working with stepUp() or stepDown() directly. For example, in the common case where you want y to go from -1 to 1 as x goes from 0 to 1:

y = stepAny(-1,2,0,1, x); // y in [-1,1]; 13 flops
y = -1 + 2*stepUp(x); // equivalent, saves 4 flops
dy = 2*dstepUp(x); // these save 5 flops over dstepAny(), etc.
d2y = 2*d2stepUp(x);
d3y = 2*d3stepUp(x);

It would be extremely rare for these few flops to matter at all; you should almost always choose based on what looks better and/or is less error prone instead.

## ◆ dstepUp() [1/2]

 double SimTK::dstepUp ( double x )
inline

First derivative of stepUp(): d/dx stepUp(x).

Parameters
 [in] x Control parameter in range [0,1].
Returns
First derivative of stepUp() at x.

## ◆ dstepDown() [1/2]

 double SimTK::dstepDown ( double x )
inline

First derivative of stepDown(): d/dx stepDown(x).

Parameters
 [in] x Control parameter in range [0,1].
Returns
First derivative of stepDown() at x.

## ◆ dstepAny() [1/2]

 double SimTK::dstepAny ( double yRange, double x0, double oneOverXRange, double x )
inline

First derivative of stepAny(): d/dx stepAny(x).

See stepAny() for parameter documentation.

Returns
First derivative of stepAny() at x.

## ◆ d2stepUp() [1/2]

 double SimTK::d2stepUp ( double x )
inline

Second derivative of stepUp(): d^2/dx^2 stepUp(x).

Parameters
 [in] x Control parameter in range [0,1].
Returns
Second derivative of stepUp() at x.

## ◆ d2stepDown() [1/2]

 double SimTK::d2stepDown ( double x )
inline

Second derivative of stepDown(): d^2/dx^2 stepDown(x).

Parameters
 [in] x Control parameter in range [0,1].
Returns
Second derivative of stepDown() at x.

## ◆ d2stepAny() [1/2]

 double SimTK::d2stepAny ( double yRange, double x0, double oneOverXRange, double x )
inline

Second derivative of stepAny(): d^2/dx^2 stepAny(x).

See stepAny() for parameter documentation.

Returns
Second derivative of stepAny() at x.

## ◆ d3stepUp() [1/2]

 double SimTK::d3stepUp ( double x )
inline

Third derivative of stepUp(): d^3/dx^3 stepUp(x).

Parameters
 [in] x Control parameter in range [0,1].
Returns
Third derivative of stepUp() at x.

## ◆ d3stepDown() [1/2]

 double SimTK::d3stepDown ( double x )
inline

Third derivative of stepDown(): d^3/dx^3 stepDown(x).

Parameters
 [in] x Control parameter in range [0,1].
Returns
Third derivative of stepDown() at x.

## ◆ d3stepAny() [1/2]

 double SimTK::d3stepAny ( double yRange, double x0, double oneOverXRange, double x )
inline

Third derivative of stepAny(): d^3/dx^3 stepAny(x).

See stepAny() for parameter documentation.

Returns
Third derivative of stepAny() at x.

## ◆ stepUp() [2/3]

 float SimTK::stepUp ( float x )
inline

Interpolate smoothly from 0 up to 1 as the input argument goes from 0 to 1, with first and second derivatives zero at either end of the interval.

Parameters
 [in] x The control parameter, in range [0,1].
Returns
The smoothed output value, in range [0,1] but with first and second derivatives smoothly approaching zero as x approaches either end of its interval.

See the documentation for stepAny() for a discussion about how to shift and scale this function to produce arbitrary steps.

This function is overloaded for all the floating point precisions. Cost is 7 flops.

stepDown(), stepAny()

## ◆ stepDown() [2/3]

 float SimTK::stepDown ( float x )
inline

Interpolate smoothly from 1 down to 0 as the input argument goes from 0 to 1, with first and second derivatives zero at either end of the interval.

Parameters
 [in] x The control parameter, in range [0,1].
Returns
The smoothed output value, in range [1,0] but with first and second derivatives smoothly approaching zero as x approaches either end of its interval.

See the documentation for stepAny() for a discussion about how to shift and scale this function to produce arbitrary steps.

This function is overloaded for all the floating point precisions. Cost is 8 flops.

stepUp(), stepAny()

## ◆ stepAny() [2/2]

 float SimTK::stepAny ( float y0, float yRange, float x0, float oneOverXRange, float x )
inline

Interpolate smoothly from y0 to y1 as the input argument goes from x0 to x1, with first and second derivatives zero at either end of the interval.

Parameters
 [in] y0 The output value when x=x0. [in] yRange The amount by which the output can change over the full interval, that is, yRange=(y1-y0) where y1 is the value of the output when x=x1. [in] x0 The minimum allowable value for x. [in] oneOverXRange 1/xRange, where xRange is the amount by which the input variable x can change over its full interval, that is, xRange=(x1-x0) where x1 is the maximum allowable value for x. [in] x The control parameter, in range [x0,x1]. This is often a time over which the output transition from y0 to y1 is to occur.
Returns
The smoothed output value, in range [y0,y1] (where y1=y0+yRange) but with first and second derivatives smoothly approaching zero as x approaches either end of its interval.

Note that the desired curve is defined in terms of y0 and (y1-y0), and x0 and 1/(x1-x0), rather than y0,y1,x0,x1 which would make for a nicer calling signature. This is a concession to efficiency since the two ranges are likely to be unchanged during many calls to this function and can thus be precalculated. It wouldn't matter except that division is so expensive (equivalent to 15-20 floating point operations). If you aren't concerned about that (and in most cases it won't matter), you can call this function using y0,y1,x0,x1 like this:

y = stepAny(y0,y1-y0,x0,1/(x1-x0), x);

Not counting the cost of calculating the ranges, each call to this function requires 13 flops. Calculating the ranges in the argument list as shown above raises the per-call cost to about 30 flops. However, there are many common special cases that are much simpler. For example, if y is to go from -1 to 1 while x goes from 0 to 1, then you can write:

y = stepAny(-1,2,0,1, x);

which is still only 13 flops despite the lack of pre-calculation.

Theory

stepUp() and stepDown() and their derivatives are defined only for arguments in the range 0 to 1. To create a general step function that smoothly interpolates from y=y0 to y1 while x goes from x0 to x1, and three derivatives, we use the stepUp() functions like this:

ooxr = 1/(x1-x0); // one over x range (signed)
yr = y1-y0; // y range (signed)
xadj = (x-x0)*ooxr // x adjusted into 0:1 range (watch for roundoff)
y = y0 + yr * stepUp(xadj);
dy = yr*ooxr * dstepUp(xadj);
d2y = yr*ooxr^2 * d2stepUp(xadj);
d3y = yr*ooxr^3 * d3stepUp(xadj);

As a common special case, note that when y has a general range but x is still in [0,1], the above simplifies considerably and you can save a few flops if you want by working with stepUp() or stepDown() directly. For example, in the common case where you want y to go from -1 to 1 as x goes from 0 to 1:

y = stepAny(-1,2,0,1, x); // y in [-1,1]; 13 flops
y = -1 + 2*stepUp(x); // equivalent, saves 4 flops
dy = 2*dstepUp(x); // these save 5 flops over dstepAny(), etc.
d2y = 2*d2stepUp(x);
d3y = 2*d3stepUp(x);

It would be extremely rare for these few flops to matter at all; you should almost always choose based on what looks better and/or is less error prone instead.

## ◆ dstepUp() [2/2]

 float SimTK::dstepUp ( float x )
inline

First derivative of stepUp(): d/dx stepUp(x).

Parameters
 [in] x Control parameter in range [0,1].
Returns
First derivative of stepUp() at x.

## ◆ dstepDown() [2/2]

 float SimTK::dstepDown ( float x )
inline

First derivative of stepDown(): d/dx stepDown(x).

Parameters
 [in] x Control parameter in range [0,1].
Returns
First derivative of stepDown() at x.

## ◆ dstepAny() [2/2]

 float SimTK::dstepAny ( float yRange, float x0, float oneOverXRange, float x )
inline

First derivative of stepAny(): d/dx stepAny(x).

See stepAny() for parameter documentation.

Returns
First derivative of stepAny() at x.

## ◆ d2stepUp() [2/2]

 float SimTK::d2stepUp ( float x )
inline

Second derivative of stepUp(): d^2/dx^2 stepUp(x).

Parameters
 [in] x Control parameter in range [0,1].
Returns
Second derivative of stepUp() at x.

## ◆ d2stepDown() [2/2]

 float SimTK::d2stepDown ( float x )
inline

Second derivative of stepDown(): d^2/dx^2 stepDown(x).

Parameters
 [in] x Control parameter in range [0,1].
Returns
Second derivative of stepDown() at x.

## ◆ d2stepAny() [2/2]

 float SimTK::d2stepAny ( float yRange, float x0, float oneOverXRange, float x )
inline

Second derivative of stepAny(): d^2/dx^2 stepAny(x).

See stepAny() for parameter documentation.

Returns
Second derivative of stepAny() at x.

## ◆ d3stepUp() [2/2]

 float SimTK::d3stepUp ( float x )
inline

Third derivative of stepUp(): d^3/dx^3 stepUp(x).

Parameters
 [in] x Control parameter in range [0,1].
Returns
Third derivative of stepUp() at x.

## ◆ d3stepDown() [2/2]

 float SimTK::d3stepDown ( float x )
inline

Third derivative of stepDown(): d^3/dx^3 stepDown(x).

Parameters
 [in] x Control parameter in range [0,1].
Returns
Third derivative of stepDown() at x.

## ◆ d3stepAny() [2/2]

 float SimTK::d3stepAny ( float yRange, float x0, float oneOverXRange, float x )
inline

Third derivative of stepAny(): d^3/dx^3 stepAny(x).

See stepAny() for parameter documentation.

Returns
Third derivative of stepAny() at x.

## ◆ stepUp() [3/3]

 double SimTK::stepUp ( int x )
inline

Interpolate smoothly from 0 up to 1 as the input argument goes from 0 to 1, with first and second derivatives zero at either end of the interval.

Parameters
 [in] x The control parameter, in range [0,1].
Returns
The smoothed output value, in range [0,1] but with first and second derivatives smoothly approaching zero as x approaches either end of its interval.

See the documentation for stepAny() for a discussion about how to shift and scale this function to produce arbitrary steps.

This function is overloaded for all the floating point precisions. Cost is 7 flops.

stepDown(), stepAny() Treats int argument as a double (avoids ambiguity).

## ◆ stepDown() [3/3]

 double SimTK::stepDown ( int x )
inline

Interpolate smoothly from 1 down to 0 as the input argument goes from 0 to 1, with first and second derivatives zero at either end of the interval.

Parameters
 [in] x The control parameter, in range [0,1].
Returns
The smoothed output value, in range [1,0] but with first and second derivatives smoothly approaching zero as x approaches either end of its interval.

See the documentation for stepAny() for a discussion about how to shift and scale this function to produce arbitrary steps.

This function is overloaded for all the floating point precisions. Cost is 8 flops.