My math is a bit elementary so I apologize for any assumptions in advance.
I want to fetch values that exist on a simulated bell curve. I don't want to actually create a bell curve or plot one, I'd just like to use a function that given an input value can tell me the corresponding Y axis value on a hypothetical bell curve.
Here's the full problem statement:
I am generating floating point values between 0.0 and 1.0.
0.50 represents 2.0 on the bell curve, which is the maximum. The values < 0.50 and > 0.50 start dropping on this bell curve, so for example 0.40 and 0.60 are the same and could be something like 1.8. 1.8 is arbitrarily chosen for this example, and I'd like to know how I can tweak this 'gradient'.
Right now Im doing a very crude implementation, for example, for any value > 0.40 and < 0.60 the function returns 2.0, but I'd like to 'smooth' this and gain more 'control' over the descent/gradient
Any ideas how I can achieve this in Go
Gaussian function described here : https://en.wikipedia.org/wiki/Gaussian_function
has a bell-curve shape. Example of implementation :
package main
import (
"math"
)
const (
a = 2.0 // height of curve's peak
b = 0.5 // position of the peak
c = 0.1 // standart deviation controlling width of the curve
//( lower abstract value of c -> "longer" curve)
)
func curveFunc(x float64) float64 {
return a *math.Exp(-math.Pow(x-b, 2)/(2.0*math.Pow(c, 2)))
}
Related
I have plotted my data on linear scale in xmgrace by using these numbers:
0.001 0
0.00589391 0.10
0.155206 0.20
0.294695 0.30
0.43222 0.40
0.436149 0.50
0.489194 0.60
0.611002 0.70
0.860511 0.80
0.939096 0.90
0.964637 1
1 1
I have use xmgrace in Ubuntu to plot my date and calculate area under the curve (AUC; Data ->Transformation -> Integration-> SumOnly).
After converting linear curve to the logarithmic one, I am having a problem with calculating area under logarithmic curve.
Has anybody else encountered similar issue?
When you set the axis scale to "logarithmic" you are not actually changing your data, just the way you display it. Therefore, since data transformations such as integration act on the actual data you have, the result is bound to be the same.
In other words, you are integrating f(x) regardless of the scale of the axes. If you want to integrate log(f(x)) you have to first convert f(x) to log(f(x)) by using the Data -> Transformation -> Expression, writing something like y = ln(y) and pressing "apply". Be careful though: the first point (which has y = 0) will get an "inf". You'll need to get rid of it manually (double click on a set, select the first row and use edit -> delete) or don't use exactly 0 in your dataset. If you want to convert also the x axis then open the same "Expression" window and write x = ln(x). Integrate the new dataset and you should get the right number (I got -7.9 I think).
I have a curve between dff(x axis) and dc(y axis) and I calculated the area under the curve using IN_TABULATED function.
X=[-0.00205553,-0.00186668,-0.00167783,-0.00148899,-0.00130014,-0.00111129,-0.000922443,-0.000733597,-0.000450326,-0.000261480,0.000116216,0.000399487, 0.000588333,0.000777179,0.000966027,0.00115488,0.00134372,0.00153257,0.00172141,0.00181584,0.00200468]
F=[0.00000,21.0000,26.0000,57.0000,94.0000,148.000,248.000,270.000,388.000,418.000,379.000,404.000,358.000,257.000,183.000,132.000,81.0000,47.0000,23.0000,17.0000,431.000]
A=INT_TABULATED(X,F)
print, A
Now, I need to have a loop start from n,0 (from right to left) and calculate A1 which is 0.01 of A and to stop there, then print dff values which represent A1's area. How can I do this? Any suggestion will be helpful.
I'm not sure I fully understand the question, so let me begin by stating my interpretation. You have a curve which integrates to A. Starting from the right, you want the X-value (let's call it X1) which encloses 0.01 of A (the total area under the curve). In other words, 0.99 of the total area under the curve F is to the left of X1, and 0.01 of the area is to the right.
Assuming this interpretation is correct, here's a solution:
First, loop through the data and calculate the integral from 0 to each point.
npoints = n_elements(x)
; Initialize a vector to hold integration results
area_cumulative = []
; Loop through each data point, calculating integrals from 0 to that point
for index = 0, npoints-1 do begin
; Assume area under first point is zero, otherwise, calculate integral
if index eq 0 then area_up_to_point = 0d0 $
else area_up_to_point = int_tabulated(x[0:index], f[0:index])
; Store integral value in the cumulative vector
area_cumulative = [area_cumulative, area_up_to_point]
endfor
Then, you can interpolate to find X1:
;;; Find where cumulative distribution reaches 0.99 of A
a1 = 0.99 * a
x1 = interpol(x, area_cumulative, a1)
Here's an illustration. The upper plot is your data, and the lower plot is the cumulative area (integral from x[0] to x). The red dashed lines show X1 = 0.001952. The gray shaded region contains 0.01 of the total area.
Hope this helps!
I want a density plot, and here is the code:
d = as.matrix(read.csv(file = '1.csv'))
plot(density(d))
my data is a list of number. What I don't understand is that the value of y axis large than 1
I think there is something wrong and search the internet, but i can't find any resource, Can you guys help me?
enter image description here
here is the data:
link:http://pan.baidu.com/s/1hsE8Ony password:7a4z
There is nothing wrong with the density being greater than 1 at some points. The area under the curve must be 1, but at specific points the density can be greater than 1. For example,
dnorm(0,0, 0.1)
[1] 3.989423
See this Cross Validated post
Edit:
I think that the dnorm part above could be amplified a little.
For a Gaussian distribution, with mean μ and standard deviation σ approximately 99.73% of the area under the density curve lies between
μ-3σ and μ+3σ. The example above used μ=0 and σ=0.1 so the area under the curve between -0.3 and 0.3 should be 0.9973. The width of the curve here is 0.6. Compare this with a rectangle of equal area (0.9973) and the same base (0.6).
If the area of the rectangle is 0.9973 and the base is 0.6, the height must be 0.9973/0.6 = 1.6621, i.e. the average height of the curve must be 1.6621. Clearly there must be some points with height greater than 1.
I am given 3 values y0, y1, y2. They are supposed to be evenly spaced, say x0 = -0.5, x1 = 0.5, x2 = 1.5. And to be able to draw a spline through all of them, the derivatives at all points are said to be dy/dx = 0.
Now the result of rendering two Catmull-Rom-Splines (which is done via GLSL fragment shader, including a nonlinear transformation) looks pretty rigit. I.e. where the curve bends, it does so smoothly, though, but the bending area is very small. Zooming out makes the bends look too sharp.
I wanted to switch to TCB-Splines (aka. Kochanek-Bartels Splines), as those provide a tension parameter - thus I hoped I could smooth the look. But I realized that all TCB-Parameters applied to a zero tangent won't do any good.
Any ideas how I could get a smoother looking curve?
The tangent vector for a 2d parametric curve f(t)=(x(t), y(t)) is defined as f'(t)=(dx(t)/dt, dy(t)/dt). When you require your curve to have dy/dx = 0 at some points, it simply means the tangent vector at those points will go horizontally (i.e., dy/dt = 0). It does not necessarily mean the tangent vector itself is a zero vector. So, you should still be able to use TCB spline to do whatever you want to do.
Obviously nobody had a good answer, but as it's my job, I found a solution: The Points are evenly spaced, and the idea is to make transitions smoother. Now it's given, that the tangents are zero at all given Points, so it is most likely that close to the points we get the strongest curvature y''(x). This means, we'd like to stretch these "areas around the points".
Considering that currently we use Catmull-Rom-Splines, sectioned between the points. That makes y(x) => y(t) , t(x) = x-x0.
This t(x) needs to be stretched around the 0- and the 1-areas. So the cosine function jumped into my mind:
Replacing t(x) = x-x0 with t(x) = 0.5 * (1.0 - cos( PI * ( x-x0 ) ) did the job for me.
Short explanation:
cosine in the range [0,PI] runs smoothly from 1 to -1.
we want to run from 0 to 1, though
so flip it: 1-cos() -> now it runs from 0 to 2
halve that: 0.5*xxx -> now it runs from 0 to 1
Another problem was to find the correct tangents. Normally, calculating such a spline using Matrix-Vector-Math, you simply derive your t-vector to get the tangents, so deriving [t³ t² t 1] yields [3t² 2t 1 0]. But here, t is not simple. Using this I found the right derived vector:
| 0.375*PI*sin(PI*t)(1-cos(PI*t))² |
| 0.500*PI*sin(PI*t)(1-cos(PI*t)) |
| 0.500*PI*sin(PI*t) |
| 0 |
I've written a a little function that gives me out a value based on a sine wave when I put in a float between 0 and 1. I'm using it to lerp things around in a game.
public static class Utilities
{
public static float SineMe(float prop)
{
float output = (prop*180f)-90f;
output = Mathf.Sin(output*Mathf.Deg2Rad);
output = (output+1f)/2f;
return output;
}
}
It works fine.. But I was wondering is there a mathematical way of altering the sine wave so I can make it 'steeper' or 'shallower' in the middle?
In the diagram below the blue curve is a sine wave, I'm wondering if I can make it more like the green line.
What you're showing already isn't really sine - the range of sine is between -1 and +1. You're applying the linear function f(x) = (x+1)/2 to change that range. So place another function between the sine and that transform.
To change the shape, you need a non-linear function. So, here's a cubic equation you might try...
g(x) = Ax^3 + Bx^2 + Cx + D
D = 0
C = p
B = 3 - 3C
A = 1 - (B + C)
The parameter p should be given a value between 0.0 and 9.0. If it's 1.0, g(x) is the identity function (the output is the unmodified input). With values between 0.0 and 1.0, it will tend to "fatten" your sine wave (push it away from 0.0 and towards 1.0 or -1.0) which is what you seem to require.
I once "designed" this function as a way to get "fractal waveforms". Using values of p between 1.0 and 9.0 (and particularly between around 3.0 and 6.0) iterative application of this formula is chaotic. I stole the idea from the population fluctuation modelling chaotic function by R. M. May, but that's a quadratic - I wanted something symmetric, so I needed a cubic function. Not really relevant here, and a pretty aweful idea as it happens. Although you certainly get chaotic waveforms, what that really means is huge problems with aliassing - change the sample rate and you get a very different sound. Still, without the iteration, maybe this will give you what you need.
If you iterate enough times with p between 0.0 and 1.0, you end up with a square wave with slightly rounded corners.
Most likely you can just choose a value of p between 0.0 and 1.0, apply that function once, then apply your function to change the range and you'll get what you want.
By the way, there's already a comment suggesting a cheat sheet of "easing functions". "Easing" is a term from animation, and computer animation software often uses Bezier curves for that purpose - the same Bezier curves that vector graphics software often uses. Bezier curves come in quadratic and cubic variants, with cubic being the more common. So what this is doing probably isn't that different. However, cubic Bezier easing gives you more control - you can control the "ease-in" independently of the "ease-out", where my function only provides one parameter.
You can use the y(x) = 1-(1-x)^n function when x = [0..1], as a transform function.
You will just have to replace x by the absolute value of your sinus and report the sign of sinus to the result. In that way you can tweak the sinus slope by increasing n. So what you want is this:
float sinus = Mathf.Sin(output*Mathf.Deg2Rad);
int sign = (sinus >= 0 ? 1 : -1);
int n = 4; // slope parameter
float waveform = sign * ( 1-Mathf.Pow(1-Mathf.Abs(sinus), n) );
You can root the sine function to make it steeper (only working for positive values). The higher the root, the steeper the sine.
Graph of a steeper sine wave function
I discovered this nifty trick for a steeper sine wave (0..1).
f(x) = cos(sin(x)^3)^10
If you need (-1..1):
2 * (f(x) - 0.5)
I think I found the solution.
(0.5+sin(x*π-π/2)/2)^((2*(1-x))^k)
in the interval x = [0.0, 1.0]
with k that control the steepness.
k=0.0 for the unmodified sinus (purple)
k=1.0 (green)
k=2.0 (blue)
https://www.desmos.com/calculator/wdtfsassev
I was looking for a similar function, not for the whole sine but just half the period.
I bumped into the Logistic function:
f(x) = L / (1 + e^(-k(x-x0)))
where
e = the natural logarithm base (also known as Euler's number),
x0 = the x-value of the sigmoid's midpoint,
L = the curve's maximum value, and
k = the steepness of the curve.
See https://en.wikipedia.org/wiki/Logistic_function
Works for me
what about
sign(sin(x))*sqrt(abs(sin(x))
https://www.desmos.com/calculator/5nn34xqkfr