Adjustable Sigmoid Curve (S-Curve) from $(0,0)$ to $ (1,1)$

14.4k Views Asked by At

I feel like this is such a simple question but I am at such a loss. I currently have a set of values that I would like to weigh by an S Curve. My data ranges from $0$ to $1$ and never leaves those bounds, but nearly every version of a Sigmoid I see assumes $x = 0$ is the point of inflection. Furthermore many of the Sigmoids reach y=0 at approximately $x = -6$, and $y=1$ at approx $x= 6$. However in my case I need to reach $y=0$ at $x=0$ and $y=1$ at $x=1$, and the point to of inflection to be at $x = 0.5$.

To summarize I need a S Curve that meets the following requirements..

  • $x$ from $0$ to $1$
  • $y$ from $0$ to $1$
  • $0$ remains $0$ and $1$ remains $1$
  • Adjustable shape for different Curves
  • Bonus If I can adjust the point of inflection while maintaining the above

Here is an example of the above (except for a movable inflection) http://www.guillermoluijk.com/misc/contrast.gif

I have looked at Sigmoids, Logistics, tan and sing approximations, contrast and AI equations, and nothing quite gets me what I need. Any explanation to go along with an answer would be much appreciated!

6

There are 6 best solutions below

2
On
  1. Select one extreme "setting" of your curve (eg, the magenta curve in your link).Define your criteria for this shape a bit more carefully, eg: $f(0) = 0$, $f(.5) = .5$, $f(1) = 1$, and function is both continuous and differentiable everywhere. Furthermore, $f(x) > x$ for $0 < x < .5$ and $f(x) > x$ for $.5 < x < 1$.

  2. Divide it in two at what you call the "inflection point" ($x=.5$).

  3. Construct a piecewise smooth function in two pieces (one below $.5$ and one above) with the properties selected in step 1. I recommend using trig functions, but exponential and log functions can be made to work as well. I will call this function $g(x)$. One possibility is given by: $$ .5 sin( 10x/pi ), x\leq.5 \\ -.5 sin( 10x/pi )+1, x>.5 $$ Other options exist, of course.

  4. To achieve other, less extreme, curves in the same family, interpolate linearly, between $g(x)$ and $x$, eg: $f(x) = a * g(x) + (1-a) * x$, where $0 < a < 1$. To other curves in the same family but in the other direction, you will have to extrapolate, but this is simple: $f(x) = a * g(x) + (1-a) * x$, where $-1 < a < 0$. Thus, the complete family is given simply by $f(x) = a * g(x) + (1-a) * x$, where $-1 < a < 1$.

5
On

I really hate to answer my own question but I believe I found the answer. I tripped across an equation by Game Dev Dino Dini which creates a half normal tunable sigmoid that ranges from $(0,0)$ to $(1,1)$. However the $K$ value is rather wonky in this case. Dino however created another version which he posted via Twitter leading to a half normal tunable sigmoid with a K range from -1 to 1. This equation is...

$$\large \frac{kx-x}{2kx-k-1}=f(x)$$

$$ 0\leq x\leq 1,-1\leq k\leq 1$$

To achieve a S curve in the same range I simply had to scale down the equation and make it piecewise. The lower half then becomes...

$$\large \frac{k*2x-2x}{2k*2x-k-1}*0.5$$ $$or$$ $$\large f(2x)*0.5$$ $$for$$ $$x\leq0.5, -1\leq k \leq 1$$

And then the upper half of the curve is...

$$\large 0.5*\frac{(-k*2(x-0.5))-(2(x-0.5)))}{2*-k*2(x-0.5)-(-k)-1}+0.5$$ $$or$$ $$\large 0.5*f(2(x-0.5))+0.5$$ $$for$$ $$ x>0.5, -1\leq -k \leq 1$$

note the $k$ is negative for the upper half of the curve. Here is an example of the lower half and the upper half. The only issue that remains with this equation is that technically $k = -1,1$ returns $y = 0$, however $k = -0.9...,0.9...$ is close enough. Unfortunately it would appear I cannot adjust my point of inflection to be anything other than $y=x=0.5$ but that was not necessary for the core operation.

0
On

In computer graphics one often needs something like this for smooth interpolations, also called Smoothstep functions. What is great is that these functions have zero derivatives at the end-points and they are chosen for fast computation, however, they are not so easily adjustable.

1
On

Following Micah's comment above I've tried out the cumulative distribution function of the beta distribution, which is available in scipy.special.betainc. It produces nice curves for $a=b\geq 1$. For $a=b<1$ there is a kink, probably due to numerical issues. It might not be the fastest function to compute, but it is readily available.

Plot of the Beta cdf

%matplotlib inline
from scipy.special import betainc
import numpy as np
import math
import matplotlib.pyplot as plt

x = np.linspace(0., 1., 100)
N = 7
for i in range(N):
    k = 0.5 * np.exp(i) / N
    plt.plot(x, betainc(k, k, x))

plt.gca().set_xlim(0,1)
plt.gca().set_ylim(0,1)
plt.show()
0
On

Taking the best of all of these comments and Dino's updated formula:

$$\frac{(k-1)(2x-1)}{2(4k|x-0.5|-k-1)}+\frac12,\quad\quad-1\leq k\leq 1.$$

Animation: https://www.desmos.com/calculator/uzf18tbyij

It meets all of your criteria (except inflection option), and best of all it's not piecewise.

1
On

The equation provided by Taylor Vance can also be modified to have a tunable inflection point, using an additional parameter "b":

$$ y = \frac{\left(\frac{b\left(k-1\right)\left(\frac{x}{b}-1\right)}{\left(4k\left|x-b\right|-k-1\right)}+\frac{b\left(k-1\right)}{4bk-k-1}\right)}{\left(\frac{b\left(k-1\right)\left(\frac{1}{b}-1\right)}{\left(4k\left|1-b\right|-k-1\right)}+\frac{b\left(k-1\right)}{4bk-k-1}\right)}, \;\;\;\;\;\;\;\;\;\; 0 < b < 1;\;\;\;\;\;\; −1 ≤ k ≤ 1. $$

https://www.desmos.com/calculator/ym0phzdvll