Integrate function - c++
I have this function to reach a certain 1 dimensional value accelerated and damped with overshoot. That is: given an inital value, a velocity and a acceleration (force/mass), the target value is attained by accelerating to it and gets increasingly damped while getting closer to the target value.
This all works fine, howver If i want to know what the TotalAngle is after time 't' I have to run this function say N steps with a 'small' dt to find the 'limit'.
I was wondering If i can (and how) to intergrate over dt so that the TotalAngle can be determined given a time 't' initially.
Regards, Tanks for any help.
dt = delta time step per frame
input = 1
TotalAngle = 0 at t=0
Velocity = 0 at t=0
void FAccelDampedWithOvershoot::Update(float dt, float input, float& Velocity, float& TotalAngle)
{
const float Force = 500000.f;
const float DampForce = 5000.f;
const float MaxAngle = 45.f;
const float InvMass = 1.f / 162400.f;
float target = MaxAngle * input;
float ratio = (target - TotalAngle) / MaxAngle;
float fMove = Force * ratio;
float fDamp = -Velocity * DampForce;
Velocity += (fMove + fDamp) * invMass * dt;
TotalAngle += Velocity * dt;
}
Updated with fixed bugs in math
Originally I've lost mass and MaxAngle a few times. This is why you should first solve it on a paper and then enter to the SO rather than trying to solve it in the text editor.
Anyway, I've fixed the math and now it seems to work reasonably well. I put fixed solution just over previous one.
Well, this looks like a Newtonian mechanics which means differential equations. Let's try to solve them.
SO is not very friendly to math formulas and I'm a bit bored to type characters so here is what I use:
F = Force
Fd = DampForce
MA = MaxAngle
A= TotalAngle
v = Velocity
m = 1 / InvMass
' for derivative i.e. something' is 1-st derivative of something by t and something'' is 2-nd derivative
if I divide you last two lines of code by dt and merge in all the other lines I can get (I also assume that input = 1 as other case is obviously symmetrical)
v' = ([F * (1 - A / MA)] - v * Fd) / m
and applying A' = v we get
m * A'' = F(1 - A/MA) - Fd * A'
or moving to one side we get a simple 2-nd order differential equation
m * A'' + Fd * A' + F/MA * A = F
IIRC, the way to solve it is to first solve characteristic equation which here is
m * x^2 + Fd * x + F/MA = 0
x[1,2] = (-Fd +/- sqrt(Fd^2 - 4*F*m/MA))/ (2*m)
I expect that part under sqrt i.e. (Fd^2 - 4*F*m/MA) is negative thus solution should be of the following form. Let
Dm = Fd/(2*m)
K = sqrt(F/MA/m - Dm^2)
(note the negated value under sqrt so it works now) then
A(t) = e^(-Dm*t) * [P * sin(K*t) + Q * cos(K*t)] + C
where P, Q and C are some constants.
The solution is easier to find as a sum of two solutions: some specific solution for
m * A'' + Fd * A' + F/MA * A = F
and a general solution for homogeneou
m * A'' + Fd * A' + F/MA * A = 0
that makes original conditions fit. Obviously specific solution A(t) = MA works and thus C = MA. So now we need to fit P and Q of general solution to match starting conditions. To find them we need
A(0) = - MA
A'(0) = V(0) = 0
Given that e^0 = 1, sin(0) = 0 and cos(0) = 1 you get something like
Q = -MA
P = 0
or
P = 0
Q = - MA
C = MA
thus
A(t) = MA * [1 - e^(-Dm*t) * cos(K*t)]
where
Dm = Fd/(2*m)
K = sqrt(F/MA/m - Dm^2)
which kind of makes sense given your task.
Note also that this equation assumes that everything happens in radians rather than degrees (i.e. derivative of [sin(t)]' is just cos(t)) so you should transform all your constants accordingly or transform the solution.
const float Force = 500000.f * M_PI / 180;
const float DampForce = 5000.f * M_PI / 180;
const float MaxAngle = M_PI_4;
which on my machine produces
Dm = 0.000268677541
K = 0.261568546
This seems to be similar to original funcion is I step with dt = 0.01f and the main obstacle seems to be precision loss because of float
Hope this helps!
This is not a full answer and I am sure someone else can work it out, but there is no room in the comments and it may help you find a better solution.
The image below shows the velocity (blue) as your function integrates at time steps 1. The red shows the function below that calculates the value for time t
The function F(t)
F(t) = sin((t / f) * pi * 2) * (1 / (((t / f) + a) ^ c)) * b
With f = 23.7, a = 1.4, c = 2, and b= 50 that give the red plot in the image above
All the values are just approximation.
f determines the frequency and is close to a match,
a,b,c control the falloff in amplitude and are a by eye guestimate.
If it does not matter that you have a perfect match then this will work for you. totalAngle uses the same function but t has 0.25 added to it. Unfortunately I did not get any values for a,b,c for totalAngle and I did notice that it was offset so you will have to add the offset value d (I normalised everything so have no idea what the range of totalAngle was)
Function F(t) for totalAngle
F(t) = sin(((t+0.25) / f) * pi * 2) * (1 / ((((t+0.25) / f) + a) ^ c)) * b + d
Sorry only have f = 23.7, c= 2, a~1.4 nothing for b=? d=?
Related
Runge Kutta in Fortran
I'm trying to implement the Runge Kutta method in Fortran and am facing a convergence problem. I don't know how much of the code I should show, so I'll describe the problem in detail, and please guide me as to what I should add/remove to/from the post to make it answerable. I have a 6-dimensional vector of position and velocity of a ball, and a corresponding system of diff. eqs. that describe the equations of motions, from which I want to calculate the trajectory of the ball, and compare results for different orders of the RK method. Let's focus on 3rd order RK. The model I use is implemented as follows: k1 = h * f(vec_old,omega,phi) k2 = h * f(vec_old + 0.5d0 * k1,omega,phi) k3 = h * f(vec_old + 2d0 * k2 - k1,omega,phi) vec = vec_old + (k1 + 4d0 * k2 + k3) / 6d0 Where f is the function that constitutes the equations of motion (or equivalently the RHS of my system of diff. eqs). Note that f is time independent, therefore has only 1 argument. h takes the role of a small time step dt. If we wish to calculate the trajectory of the ball for a finite time total_time, and allow for a total error of epsilon, then we need to ensure each step takes a proportional fraction of the error. For the first step, I then did the following: vec1 = solve(3,vec_old,h,omega,phi) vec2 = solve(3,vec_old,h/2d0,omega,phi) do while (maxval((/(abs(vec1(i) - vec2(i)),i=1,6)/)) > eps * h / (tot_time - current_time)) h = h / 2d0 vec1 = solve(3,vec_old,h,omega,phi) vec2 = solve(3,vec_old,h/2d0,omega,phi) end do vec = (8d0/7d0) * vec2 - (1d0/7d0) * vec1 Where solve(3,vec_old,h,omega,phi) is the function that calculates the single RK step described above. 3 denotes the RK order we are using, vec_old is the current state of the position-velocity vector, h, h/2d0 both represent the time step being used, and omega,phi are just some extra parameters for f. Finally, for the first step we set current_time = 0d0. The point is that if we use a 3rd order RK, we should have an error in $O(h^3)$, and thus fall off faster than linearly in h. Therefore, we should expect the while loop to eventually come to a halt for small enough h. My problem is that the loop doesn't converge, and not even close - the ratio maxval(...) / eps * (...) remains pretty much constant, all the way until eps * h / (tot_time - current_time)) becomes zero due to finite precision. For completeness, this is my definition for f: function f(vec_old,omega,phi) result(vec) real(8),intent(in) :: vec_old(6),omega,phi real(8) :: vec(6) real(8) :: v,Fv v = sqrt(vec_old(4)**2+vec_old(5)**2+vec_old(6)**2) Fv = 0.0039d0 + 0.0058d0 / (1d0 + exp((v-35d0)/5d0)) vec(1) = vec_old(4) vec(2) = vec_old(5) vec(3) = vec_old(6) vec(4) = -Fv * v * vec_old(4) + 4.1d-4 * omega * (vec_old(6)*sin(phi) - vec_old(5)*cos(phi)) vec(5) = -Fv * v * vec_old(5) + 4.1d-4 * omega * vec_old(4)*cos(phi) vec(6) = -Fv * v * vec_old(6) - 4.1d-4 * omega * vec_old(4)*sin(phi) - 9.8d0 end function f Does anyone have any idea as to why the while loop doesn't converge? If anything else is needed (output, other pieces of code etc.) please tell me and I'll add it. Also, if trimming is required, I'll cut whatever would be considered unnecessary. Thanks!
To compute the step error using the half step method, you need to compute the approximation at t+h in both cases, which means two steps with step size h/2. As it is now you compare the approximation at t+h to the approximation at t+h/2 which gives you an error of size f(vec(t+h/2))*h/2. Thus change to a 3-step procedure vec1 = solve(3,vec_old,h,omega,phi) vec2 = solve(3,vec_old,h/2d0,omega,phi) vec2 = solve(3,vec2 ,h/2d0,omega,phi) in both locations, the difference of vec2-vec1 should then be of order h^4.
Solving Differential Equation Sympy
I haven't been able to find particular solutions to this differential equation. from sympy import * m = float(raw_input('Mass:\n> ')) g = 9.8 k = float(raw_input('Drag Coefficient:\n> ')) v = Function('v') f1 = g * m t = Symbol('t') v = Function('v') equation = dsolve(f1 - k * v(t) - m * Derivative(v(t)), 0) print equation for m = 1000 and k = .2 it returns Eq(f(t), C1*exp(-0.0002*t) + 49000.0) which is correct but I want the equation solved for when v(0) = 0 which should return Eq(f(t), 49000*(1-exp(-0.0002*t))
I believe Sympy is not yet able to take into account initial conditions. Although dsolve has the option ics for entering initial conditions (see the documentation), it appears to be of limited use. Therefore, you need to apply the initial conditions manually. For example: C1 = Symbol('C1') C1_ic = solve(equation.rhs.subs({t:0}),C1)[0] print equation.subs({C1:C1_ic}) Eq(v(t), 49000.0 - 49000.0*exp(-0.0002*t))
Coeficients in numerical calculations of exp() function
I am trying to understand the implementation of exp_ps() from http://gruntthepeon.free.fr/ssemath/sse_mathfun.h or exp256_ps() from http://software-lisc.fbk.eu/avx_mathfun/avx_mathfun.h. I understand almost everything in the calculation, except for how constant cephes_exp_C2 is determined. It seems that it increases the accuracy of the calculation. If it is removed from the calculation then resulting function is significantly faster and slightly less precise (relative error is still under 1% for values around +/- 10). I found such coefficients in other numerical libraries, but without closer explanation.
After a bit of searching through the Cephes source, I think it's an error in Pommier's translation. This is not the first time I have seen errors in Pommier's code. I recommend using math library in Gromacs. From exp.c in Cephe's, static double C1 = 6.93145751953125E-1; static double C2 = 1.42860682030941723212E-6; .... px = floor( LOG2E * x + 0.5 ); n = px; x -= px * C1; x -= px * C2; From Pommier, _PS_CONST(cephes_exp_C1, 0.693359375); _PS_CONST(cephes_exp_C2, -2.12194440e-4); <-- Wrong value .... // // fx = LOG2E * x + 0.5 // fx = _mm_mul_ps(x, *(v4sf*)_ps_cephes_LOG2EF); fx = _mm_add_ps(fx, *(v4sf*)_ps_0p5); // // fx = floor(fx) // emm0 = _mm_cvttps_epi32(fx); tmp = _mm_cvtepi32_ps(emm0); v4sf mask = _mm_cmpgt_ps(tmp, fx); mask = _mm_and_ps(mask, one); fx = _mm_sub_ps(tmp, mask); // // x -= fx * C1; // x -= fx * C2; (Using z allows for better ILP in this step) // tmp = _mm_mul_ps(fx, *(v4sf*)_ps_cephes_exp_C1); v4sf z = _mm_mul_ps(fx, *(v4sf*)_ps_cephes_exp_C2); x = _mm_sub_ps(x, tmp); x = _mm_sub_ps(x, z);
Audio equalization
I'm developing audio player using FFmpeg and I want to add audio equaliqer to my app. I use FFmpeg to get audio samples and compute FFT, but when I try to apply one of IIR filters, I'm geting very noisy audio signal. This is my code: double Q = 1.0; double omega = 2.0 * PI * 1000.0 / 44100.0; double sine = sin(omega); double alpha = sine / ( 2.0 * Q); double cosine = cos(omega); double b0 = (1 + cosine)/2; double b1 = (-1) * (1 + cosine); double b2 = (1 + cosine)/2; double a0 = 1 + alpha; double a1 = (-2) * cosine; double a2 = 1 - alpha; for( int n = 2; n < fftSize; n++ ) { leftChannel2[n].re = ((b0/a0)*leftChannel[n].re + (b1/a0)*leftChannel[n-1].re + (b2/a0)*leftChannel[n-2].re - (a1/a0)*leftChannel2[n-1].re - (a2/a0)*leftChannel2[n-2].re); rightChannel2[n].re = ((b0/a0)*rightChannel[n].re + (b1/a0)*rightChannel[n-1].re + (b2/a0)*rightChannel[n-2].re - (a1/a0)*rightChannel2[n-1].re - (a2/a0)*rightChannel2[n-2].re); leftChannel2[n].im = leftChannel[n].im; rightChannel2[n].im = rightChannel[n].im; } Can anybody told me what is wrong with this code?
Does this filter perform correctly in Excel or Matlab? At first look, i don't see here syntax or semantic errors. By the way, this filter (difference equation) computes frequency response in time domain. What about the imaginary part of the signal? If it is non-zero, you have to filter it in the same way.
Box2D & Cocos2d-x finding future location of a body
I'm in the process of making a mobile game and am having trouble predicting the future location of a body/sprite pair. The method I am using to do this is below. 1 --futureX is passed in as the cocos2d sprite's location, found using CCSprite.getPosition().x 2 -- I am using b2Body values for acceleration and velocity, so I must correct the futureX coordinate by dividing it by PTM_RATIO (defined elsewhere) 3 -- the function solves for the time it will take for a the b2Body to reach the futureX position (based off of its x-direction acceleration and velocity) and then uses that time to determine where the futureY position for the body should be. I multiply by PTM_RATIO at the end because the coordinate is meant to be used for creating another sprite. 4 -- when solving for time I have two cases: one with x acceleration != 0 and one for x acceleration == 0. 5 -- I am using the quadratic formula and kinematic equations to solve my equations. Unfortunately, the sprite I'm creating is not where I expect it to be. It ends up in the correct x location, however, the Y location is always too large. Any idea why this could be? Please let me know what other information is helpful here, or if there is an easier way to solve this! float Sprite::getFutureY(float futureX) { b2Vec2 vel = this->p_body->GetLinearVelocity(); b2Vec2 accel = p_world->GetGravity(); //we need to solve a quadratic equation: // --> 0 = 1/2(accel.x)*(time^2) + vel.x(time) - deltaX float a = accel.x/2; float b = vel.x; float c = this->p_body->GetPosition().x - futureX/PTM_RATIO; float t1; float t2; //if Acceleration.x is not 0, solve quadratically if(a != 0 ){ t1 = (-b + sqrt( b * b - 4 * a * c )) / (2 * a); t2 = (-b - sqrt( b * b - 4 * a * c )) / (2 * a); //otherwise, solve linearly }else{ t2 = -1; t1 = (c/b)*(-1); } //now that we know how long it takes to get to posX, we can tell the y location on the sprites path float time; if(t1 >= 0){ time = t1; }else{ time = t2; } float posY = this->p_body->GetPosition().y; float futureY = (posY + (vel.y)*time + (1/2)*accel.y*(time*time))*PTM_RATIO; return futureY; }
SOLVED: The issue was in this line: float futureY = (posY + (vel.y)*time + (1/2)*accel.y*(time*time))*PTM_RATIO; I needed to explicitley cast the (1/2) as a float. I fixed it with this: float futureY = (posY + (vel.y)*time + (float).5*accel.y*(time*time))*PTM_RATIO; Note, otherwise, the term with acceleration was evaluated to zero.