Flong

Printed from www.flong.com/texts/code/shapers_exp/
Contents © 2020 Golan Levin and Collaborators

Golan Levin and Collaborators

Code

Exponential Shaping Functions

  • Exponential Ease-In and Ease-Out
  • Double-Exponential Seat
  • Double-Exponential Sigmoid
  • The Logistic Sigmoid

Exponential Ease-In and Ease-Out

In this implementation of an exponential shaping function, the control parameter a permits the designer to vary the function from an ease-out form to an ease-in form.

Exponential Ease-In:


Exponential Ease-Out:


//-----------------------------------------
float exponentialEasing (float x, float a){
  
  float epsilon = 0.00001;
  float min_param_a = 0.0 + epsilon;
  float max_param_a = 1.0 - epsilon;
  a = max(min_param_a, min(max_param_a, a));
  
  if (a < 0.5){
    // emphasis
    a = 2.0*(a);
    float y = pow(x, a);
    return y;
  } else {
    // de-emphasis
    a = 2.0*(a-0.5);
    float y = pow(x, 1.0/(1-a));
    return y;
  }
}


Double-Exponential Seat

A seat-shaped function can be created with a coupling of two exponential functions. This has nicer derivatives than the cubic function, and more continuous control in some respects, at the expense of greater CPU cycles. The recommended range for the control parameter a is from 0 to 1. Note that these equations are very similar to the Double-Exponential Sigmoid described below.


//---------------------------------------------
float doubleExponentialSeat (float x, float a){

  float epsilon = 0.00001;
  float min_param_a = 0.0 + epsilon;
  float max_param_a = 1.0 - epsilon;
  a = min(max_param_a, max(min_param_a, a)); 

  float y = 0;
  if (x<=0.5){
    y = (pow(2.0*x, 1-a))/2.0;
  } else {
    y = 1.0 - (pow(2.0*(1.0-x), 1-a))/2.0;
  }
  return y;
}


Double-Exponential Sigmoid

The same doubling-and-flipping scheme can be used to create sigmoids from pairs of exponential functions. These have the advantage that the control parameter a can be continously varied between 0 and 1, and are therefore very useful as adjustable-contrast functions. However, they are more expensive to compute than the polynomial sigmoid flavors. The Double-Exponential Sigmoid approximates the Raised Inverted Cosine to within 1% when the parameter a is approximately 0.426.


//------------------------------------------------
float doubleExponentialSigmoid (float x, float a){

  float epsilon = 0.00001;
  float min_param_a = 0.0 + epsilon;
  float max_param_a = 1.0 - epsilon;
  a = min(max_param_a, max(min_param_a, a));
  a = 1.0-a; // for sensible results
  
  float y = 0;
  if (x<=0.5){
    y = (pow(2.0*x, 1.0/a))/2.0;
  } else {
    y = 1.0 - (pow(2.0*(1.0-x), 1.0/a))/2.0;
  }
  return y;
}


The Logistic Sigmoid

The so-called "Logistic Curve" is an elegant sigmoidal function which is believed by many scientists to best represent the growth of organic populations and many other natural phenomena. In software engineering, it is often used for weighting signal-response functions in neural networks. In this implementation, the parameter a regulates the slope or "growth rate" of the sigmoid during its rising portion. When a=0, this version of the Logistic function collapses to the Identity Function (y=x). The Logistic Sigmoid has very natural rates of change, but is expensive to calculate due to the use of many exponential functions.

//---------------------------------------
float logisticSigmoid (float x, float a){
  // n.b.: this Logistic Sigmoid has been normalized.

  float epsilon = 0.0001;
  float min_param_a = 0.0 + epsilon;
  float max_param_a = 1.0 - epsilon;
  a = max(min_param_a, min(max_param_a, a));
  a = (1/(1-a) - 1);

  float A = 1.0 / (1.0 + exp(0 -((x-0.5)*a*2.0)));
  float B = 1.0 / (1.0 + exp(a));
  float C = 1.0 / (1.0 + exp(0-a)); 
  float y = (A-B)/(C-B);
  return y;
}