1

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;
}
  • `current` appears to be undeclared. – Igor Tandetnik Mar 19 '17 at 14:47
  • can you post function you are integrating? – Semyon Burov Mar 19 '17 at 15:00
  • Lots of software written to integrate differential equations: https://scicomp.stackexchange.com/questions/20786/c-library-for-numerical-intergration-quadrature – duffymo Mar 19 '17 at 15:10
  • Possible duplicate of [Numerical integration in C++](http://stackoverflow.com/questions/16512817/numerical-integration-in-c) – duffymo Mar 19 '17 at 15:11
  • I am actually only interested in the Velocity after a certain time t, so I tried something like: V(1) = ((Force - V(0)*DampForce) / Mass) * dt – Bart Knuiman Mar 19 '17 at 15:40
  • What is `input`? and is it constant?. BTW if you are integrating with `dt` not a constant you will not find an equation to match the integration. – Blindman67 Mar 19 '17 at 16:52
  • Input is either -1 or 1. But, you can ignore it. The idea is to Accelerate damped to a certain angle from 0 to eg 45 with overshoot. So the target angle is either -45 or 45 depending on whether input is positive or negative. I dont want to integrate with dt, but with 't'. However the velocity will change as the time progresses so it is not constant. Perhaps I am not saying this 'completely' correct in math terms though. – Bart Knuiman Mar 19 '17 at 17:10
  • I just plotted the equation and its cyclic. By eye Velocity is about 90deg out of phase with TotalAngle and the frequency looks like its constant. Not my strong point, but just have to find the equation to calculate the precise frequency, and the amplitude over time looks fairly simple. So quick guess the equation will look something like sin(t) * f(t) with f(t) something like 1/(t^2) and a bunch of constants – Blindman67 Mar 19 '17 at 17:27

2 Answers2

1

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

enter image description here

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=?

Blindman67
  • 51,134
  • 11
  • 73
  • 136
  • A thanks for so much effort. Ill have a look into it. In what program did you do the plot? How did you get to that 'cyclic' function ? The totalAngle should be in range of 0 to 45 (maxAngle), though it can overshoot the target depending of the damping force, more damping is less overshoot. So roughly, 0 to 45, but 0 to 50 or more also possible if little dampingForce is applied. – Bart Knuiman Mar 19 '17 at 22:17
  • Plotted just with javascript and canvas. I started by just iterating your code and plotting it over time. As soon as a saw it I knew the form of the solution, I just did not know how to get the constants so I just guessed and found a reasonable fit. – Blindman67 Mar 19 '17 at 23:52
1

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!

SergGr
  • 23,570
  • 2
  • 30
  • 51