Derive an exponential value from a for loop's index - math

I have a collection of objects that will animate onto screen. I want the random delay of each animation to progressively grow depending on where the item is in the collection.
At the moment I can do this linearly fairly easily like so (Swift).
let proportionThroughContents = CGFloat(Double(idx) / Double(allNodes.count))
let delayRandomiserBaseValue: CGFloat = 40
let delayRandomiserGrowthValue: CGFloat = 60
let delayRandomiserValue = UInt32(delayRandomiserBaseValue + (delayRandomiserGrowthValue * proportionThroughContents))
I actually want some mathematical function to give me a bit of a hockey-stick like effect, where items in the middle still have low values, but items toward the very end get much higher values.
This may be more a mathematical question rather than a programming one, but I feel like this might be common enough to warrant it being here.

There are many possible options. The simplest is probably a quadratic like a x^2 + b x + c, where x is your proportion and a, b, c are appropriate constants. In code you would need to write this as a*x*x + b*x + c.
For true exponential functions you want k exp(l x) in code k * Math.exp(l*x).
Choosing the constants is the trickier bit. To get the same initial rates for quadratic just choose b = delayRandomiserGrowthValue and c = delayRandomiserBaseValue. You could then choose the a value depending on how much longer you the delay to be. a + b + c would give you the maximum delay.
let proportionThroughContents = CGFloat(Double(idx) / Double(allNodes.count))
let delayRandomiserBaseValue: CGFloat = 40 // c
let delayRandomiserGrowthValue: CGFloat = 60 // b
let delayRandomiserQuadraticValue: CGFloat = 60 // a
let delayRandomiserValue = UInt32(delayRandomiserBaseValue
+ delayRandomiserGrowthValue * proportionThroughContents
+ delayRandomiserQuadraticValue * proportionThroughContents * proportionThroughContents )
For exponential k is the initial value and l*k is initial growth rate. The final delay would be k e^l.
let proportionThroughContents = CGFloat(Double(idx) / Double(allNodes.count))
let delayRandomiserBaseValue: CGFloat = 40 // k
let delayRandomiserGrowthValue: CGFloat = 60 //
let l: CGFloat = delayRandomiserGrowthValue / delayRandomiserBaseValue // l
let delayRandomiserValue = UInt32(delayRandomiserBaseValue * Math.exp(l*proportionThroughContents))
With these value l = 60/40 = 1.5 and the maximum delay would be 40*exp(1.5) = 179.

Related

How do I apply velocity and acceleration to match the result of math formulas

So I have an initial velocity iv a final velocity fv (that is always 0) a time t and an acceleration variable a
I use these variables to calculate final distance fd
Note: language used here is Kotlin
Note: Formula used for calculating fd and a are not something I came up with
var iv = 10.0 // initial velocity
var fv = 0.0 // final velocity
var t = 8.0 // time
var a = ((fv - iv)/t) // acceleration
var fd: Double = ((iv*t) + (a/2.0*Math.pow(t,2.0)))
I get the result that fd = 40.0
when I try to model this the way I would try to apply it in code.
var d = 0.0 // current distance traveled
var i = 0 // current time elapsed
while (i < t) {
d += v
v += a
i++
}
I end up with the result of d = 45.0 when d should equal fd at the end.
what am I doing wrong in applying velocity and acceleration to velocity so that my results differ from what the mathematical formulas show they should be?
Don't worry about "formulas" - think about the physics.
If you have ever studied calculus and physics you know that:
a = dv/dt // a == acceleration; v == velocity; t == time
v = ds/dt // v == velocity; s == distance; t == time
If you know calculus well enough you can integrate the equation for acceleration twice to get the distance traveled as a function of time:
a(t) = dv/dt = a0
v(t) = ds/dt = a0*t + v0
s(t) = (a0/2)*t^2 + v0*t + s0
You can calculate the constants:
a0 = -1.25 m/sec^s
v0 = 10 m/s
s0 = 0 m
Substituting:
a(t) = -1.25
v(t) = 10 - 1.25*t
s(t) = -0.625*t^2 + 10*t = (10 - 0.625*t)*t
You can also calculate the answer numerically. That's what you're doing with Kotlin.
If you know the initial conditions
a(0), v(0), and s(0)
you can calculate the value at the end of a time increment dt like this:
a(t+dt) = f(t+dt)
v(t+dt) = v(t) + a(t)*dt
s(t+dt) = s(t) + v(t)*dt
Looks like you are assuming that acceleration is constant throughout the time you're interested in.
You don't say what units you're using. I'll assume metric units: length in meters and time in seconds.
You decelerate from an initial velocity of 10 m/sec to a final velocity of 0 m/second over 8 seconds. That means a constant acceleration of -1.25 m/sec^2.
You should be able to substitute values into these equations and get the answers you need.
Do the calculations by hand before you try to code them.

Functionally idiomatic FFT

I've written the this radix-2 FFT with the goal of making it functionally idiomatic without sacrificing too much performance:
let reverse x bits =
let rec reverse' x bits y =
match bits with
| 0 -> y
| _ -> ((y <<< 1) ||| (x &&& 1))
|> reverse' (x >>> 1) (bits - 1)
reverse' x bits 0
let radix2 (vector: Complex[]) (direction: int) =
let z = vector.Length
let depth = floor(Math.Log(double z, 2.0)) |> int
if (1 <<< depth) <> z then failwith "Vector length is not a power of 2"
// Complex roots of unity; "twiddle factors"
let unity: Complex[] =
let xpn = float direction * Math.PI / double z
Array.Parallel.init<Complex> (z/2) (fun i ->
Complex.FromPolarCoordinates(1.0, (float i) * xpn))
// Permutes elements of input vector via bit-reversal permutation
let pvec = Array.Parallel.init z (fun i -> vector.[reverse i depth])
let outerLoop (vec: Complex[]) =
let rec recLoop size =
if size <= z then
let mid, step = size / 2, z / size
let rec inrecLoop i =
if i < z then
let rec bottomLoop idx k =
if idx < i + mid then
let temp = vec.[idx + mid] * unity.[k]
vec.[idx + mid] <- (vec.[idx] - temp)
vec.[idx] <- (vec.[idx] + temp)
bottomLoop (idx + 1) (k + step)
bottomLoop i 0
inrecLoop (i + size)
inrecLoop 0
recLoop (size * 2)
recLoop 2
vec
outerLoop pvec
The outerLoop segment is the biggest nested tail-recursive mess I have ever written. I replicated the algorithm in the Wikipedia article for the Cooley-Tukey algorithm, but the only functional constructs I could think to implement using higher-order functions result in massive hits to both performance and memory efficiency. Are there other solutions that would yield the same results without resulting in massive slow-downs, while still being idiomatic?
I'm not an expert on how the algorithm works, so there might be a nice functional implementation, but it is worth noting that using a localised mutation is perfectly idiomatic in F#.
Your radix2 function is functional from the outside - it takes vector array as an input, never mutates it, creates a new array pvec which it then initializes (using some mutation along the way) and then returns it. This is a similar pattern to what built-in functions like Array.map use (which initializes a new array, mutates it and then returns it). This is often a sensible way of doing things, because some algorithms are better written using mutation.
In this case, it's perfectly reasonable to also use local mutable variables and loops. Doing that will make your code more readable compared to the tail-recursive version. I have not tested this, but my naive translation of your outerLoop function would just be to use three nested loops - something like this:
let mutable size = 2
while size <= z do
let mid, step = size / 2, z / size
let mutable i = 0
while i < z do
for j in 0 .. mid - 1 do
let idx, k = i + j, step * j
let temp = pvec.[idx + mid] * unity.[k]
pvec.[idx + mid] <- (pvec.[idx] - temp)
pvec.[idx] <- (pvec.[idx] + temp)
i <- i + size
size <- size * 2
This might not be exactly right (I did this just be refactoring your code), but I think it's actually more idiomatic than using complex nested tail-recursive functions in this case.

Keeping exact wave form in memory

Let's say I have a program that calculates the value of the sine wave at time t. The sine wave is of the form sin(f*t + phi). Amplitude is 1.
If I only have one sin term all is fine. I can easily calculate the value at any time t.
But, at runtime, the wave form becomes modified when it combines with other waves. sin(f1 * t + phi1) + sin(f2 * t + phi2) + sin(f3 * t + phi3) + ...
The simplest solution is to have a table with columns for phi and f, iterate over all rows, and sum the results. But to me it feels that once I reach thousands of rows, the computation will become slow.
Is there a different way of doing this? Like combining all the sines into one statement/formula?
If you have a Fourier series (i.e. f_i = i f for some f) you can use the Clenshaw recurrence relation which is significantly faster than computing all the sines (but it might be slightly less accurate).
In your case you can consider the sequence:
f_k = exp( i ( k f t + phi_k) ) , where i is the imaginary unit.
Notice that Im(f_k) = sin( k f t + phi_k ), that is your sequence.
Also
f_k = exp( i ( k f t + phi_k) ) = exp( i k f t ) exp( i phi_k )
Hence you have a_k = exp(i phi_k). You can precompute these values and store them in an array. For simplicity from now on assume a_0 = 0.
Now, exp( i (k + 1) f t) = exp(i k f t) * exp(i f t), so alpha_k = exp(i f t) and beta_k = 0.
You can now apply the recurrence formula, in C++ you can do something like this:
complex<double> clenshaw_fourier(double f, double t, const vector< complex<double> > & a )
{
const complex<double> alpha = exp(f * t * i);
complex<double> b = 0;
for (int k = a.size() - 1; k >0; -- k )
b = a[k] + alpha * b;
return a[0] + alpha * b;
}
Assuming that a[k] == exp( i phi_k ).
The real part of the answer is the sum of cos(k f t + phi_k), while the imaginary part is the sum of sin(k f t + phi_k).
As you can see this only uses addition and multiplications, except for exp(f * t * i) that is only computed once.
There are different bases (plural of basis) that can be advantageous (i.e. compact) for representing different waveforms. The most common and well-known one is that which you mention, called the Fourier basis usually. Daubechies wavelets for example are a relatively recent addition that cope with more discontinuous waveforms much better than a Fourier basis does. But this is really a math topic and probably if you post on Math Overflow you will get better answers.

2D Physics Engine collision response rotation of objects

I'm writing my own basic physic engine and now I come to a problem I can't solve. Probably because I don't how to google this problem.
So here is my problem. I hope this image can explain it:
Collision response
I have two objects. The gray one is fixed and don't move and the green one which falls from the top.
The green object has three vectors: a force, the acceleration and the velocity. It collides with the fixed gray object.
The real question is how can I get the rotation of the green object when it falls down?
It sounds like you may not have an understanding of the fundamental physics underlying rigid body dynamics. I say that only because you don't mention any of the terminology commonly used when talking about this kind of problem. You'll need to introduce the idea of orientation and angular velocity (the rotational analogs of position and linear velocity) to each dynamic body in the system, and compute all kinds of intermediate quantities like moment of inertia, angular acceleration, and torque.
Perhaps the best introductory reference for this is Chris Hecker's series of articles for Game Developer Magazine. Assuming you already have non-rotational dynamics (covered in part 1) and collision detection (not covered by this series) solved, you should begin with part 2 and proceed to part 3. They'll give you a solid foundation in the physics and mathematics necessary for implementing rotational collision response.
You do as described below once, when the objects collide.
Let us call the green rectangle "a", and the other one "b".
1.
First you need the rectangles "rotational mass", mass of inertia.
a.i = 4/3 * width * height * (width^2 + height^2) * a.density
2.
Then you need the vector pointing from the rectangle's center of mass (average position of all corners) to the contact position (where the rectangles collide), let us call it "r".
3.
Then you need to find the collision normal. This normal is the direction of an impulse being applied to a from b. The normal is a vector with length 1 unit. In your example the normal would probably point upwards. Let us call the normal vector "n".
4.
Now you will need the velocity of the contact point on a. If a is not rotating, the formula would be:
vp = a.vel
If a is rotating the formula would be:
vp = a.vel + cross(a.r_vel, r)
a.r_vel is a's rotational velocity given in radians and positive direction is counter clockwise.
cross() means cross product, the function is:
cross (v,i) = [-i * v.y , i * v.x]
The expanded formula would be:
vp = a.v + [-r * a.r_vel.y , r * a.r_vel.x]
5.
Now you need to calculate whether the objects are moving towards each other. Project the vp onto n.
vp_p = dot(vp, n)
dot (v1, v2) = v1.x * v2.x + v1.y * v2.y
vp_p is a scalar (a value, not a vector).
If vp_p is negative the obejcts are moving towards each other, if it is > 0 they are moving apart.
6.
Now you need to calculate the impulse to stop a from moving into b, the impulse is:
j = -vp_p / (
1/a.mass + cross(r,n)^2 / a.i
)
The cross product between two vectors are:
cross(v1,v2) = v1.x * v2.y - v1.y * v2.x
It returns a scalar.
Multiply the impulse with the normal to get the impulse vector:
jn = j * n
7.
Now you need to apply the impulse to a:
a.new_vel = a.old_vel + jn / a.mass;
a.new_r_vel = a.old_r_vel + cross(r,jn) / a.i;
If you want the collision to be fully elastic, you must multiply the impulse by 2. Let us call this multiplier "e". e needs to be between 1 and 2. 1 means no energy is conserved, 2 means all energy is conserved.
Example code:
var vp = a.vel + cross(a.r_vel, r);
var vp_p = dot(vp,n); // negative val = moving towards each other
if (vp_p >= 0) { // do they move apart?
return false;
}
// normal impulse
var j = - e * vp_p / (
1/a.mass + cross(r,n)^2 / a.i
);
var jn = j * n;
//
a.vel = a.vel + jn / a.mass;
a.r_vel = a.r_vel + cross(r,jn) / a.i;
If b is not static the algorithm will be slightly different:
a.r = vector pointing from a's center of mass to the contact position
var vp = a.vel + cross(a.r_vel, a.r) - b.vel - cross(b.r_vel, b.r);
var vp_p = dot(vp,n); // negative val = moving towards each other
if (vp_p >= 0) { // do they move apart?
return false;
}
// normal impulse
var j = - e * vp_p / (
1/a.mass + cross(a.r,n)^2 / a.i +
1/b.mass + cross(b.r,n)^2 / b.i
);
var jn = j * n;
//
a.vel = a.vel + jp / a.mass;
a.r_vel = a.r_vel + cross(a.r,jn) / a.i;
b.vel = b.vel - jp / b.mass;
b.r_vel = b.r_vel - cross(b.r,jn) / b.i;
How the formulas work / sources:
http://www.myphysicslab.com/collision.html#resting_contact

Math - mapping numbers

How do I map numbers, linearly, between a and b to go between c and d.
That is, I want numbers between 2 and 6 to map to numbers between 10 and 20... but I need the generalized case.
My brain is fried.
If your number X falls between A and B, and you would like Y to fall between C and D, you can apply the following linear transform:
Y = (X-A)/(B-A) * (D-C) + C
That should give you what you want, although your question is a little ambiguous, since you could also map the interval in the reverse direction. Just watch out for division by zero and you should be OK.
Divide to get the ratio between the sizes of the two ranges, then subtract the starting value of your inital range, multiply by the ratio and add the starting value of your second range. In other words,
R = (20 - 10) / (6 - 2)
y = (x - 2) * R + 10
This evenly spreads the numbers from the first range in the second range.
It would be nice to have this functionality in the java.lang.Math class, as this is such a widely required function and is available in other languages.
Here is a simple implementation:
final static double EPSILON = 1e-12;
public static double map(double valueCoord1,
double startCoord1, double endCoord1,
double startCoord2, double endCoord2) {
if (Math.abs(endCoord1 - startCoord1) < EPSILON) {
throw new ArithmeticException("/ 0");
}
double offset = startCoord2;
double ratio = (endCoord2 - startCoord2) / (endCoord1 - startCoord1);
return ratio * (valueCoord1 - startCoord1) + offset;
}
I am putting this code here as a reference for future myself and may be it will help someone.
As an aside, this is the same problem as the classic convert celcius to farenheit where you want to map a number range that equates 0 - 100 (C) to 32 - 212 (F).
https://rosettacode.org/wiki/Map_range
[a1, a2] => [b1, b2]
if s in range of [a1, a2]
then t which will be in range of [b1, b2]
t= b1 + ((s- a1) * (b2-b1))/ (a2-a1)
In addition to #PeterAllenWebb answer, if you would like to reverse back the result use the following:
reverseX = (B-A)*(Y-C)/(D-C) + A
Each unit interval on the first range takes up (d-c)/(b-a) "space" on the second range.
Pseudo:
var interval = (d-c)/(b-a)
for n = 0 to (b - a)
print c + n*interval
How you handle the rounding is up to you.
if your range from [a to b] and you want to map it in [c to d] where x is the value you want to map
use this formula (linear mapping)
double R = (d-c)/(b-a)
double y = c+(x*R)+R
return(y)
Where X is the number to map from A-B to C-D, and Y is the result:
Take the linear interpolation formula, lerp(a,b,m)=a+(m*(b-a)), and put C and D in place of a and b to get Y=C+(m*(D-C)). Then, in place of m, put (X-A)/(B-A) to get Y=C+(((X-A)/(B-A))*(D-C)). This is an okay map function, but it can be simplified. Take the (D-C) piece, and put it inside the dividend to get Y=C+(((X-A)*(D-C))/(B-A)). This gives us another piece we can simplify, (X-A)*(D-C), which equates to (X*D)-(X*C)-(A*D)+(A*C). Pop that in, and you get Y=C+(((X*D)-(X*C)-(A*D)+(A*C))/(B-A)). The next thing you need to do is add in the +C bit. To do that, you multiply C by (B-A) to get ((B*C)-(A*C)), and move it into the dividend to get Y=(((X*D)-(X*C)-(A*D)+(A*C)+(B*C)-(A*C))/(B-A)). This is redundant, containing both a +(A*C) and a -(A*C), which cancel each other out. Remove them, and you get a final result of: Y=((X*D)-(X*C)-(A*D)+(B*C))/(B-A)
TL;DR: The standard map function, Y=C+(((X-A)/(B-A))*(D-C)), can be simplified down to Y=((X*D)-(X*C)-(A*D)+(B*C))/(B-A)
int srcMin = 2, srcMax = 6;
int tgtMin = 10, tgtMax = 20;
int nb = srcMax - srcMin;
int range = tgtMax - tgtMin;
float rate = (float) range / (float) nb;
println(srcMin + " > " + tgtMin);
float stepF = tgtMin;
for (int i = 1; i < nb; i++)
{
stepF += rate;
println((srcMin + i) + " > " + (int) (stepF + 0.5) + " (" + stepF + ")");
}
println(srcMax + " > " + tgtMax);
With checks on divide by zero, of course.

Resources