About setting custom "dt"

Questions about the LÖVE API, installing LÖVE and other support related questions go here.
Forum rules
Before you make a thread asking for help, read this.
User avatar
T-Bone
Inner party member
Posts: 1492
Joined: Thu Jun 09, 2011 9:03 am

Re: About setting custom "dt"

Post by T-Bone »

misterspok wrote:
T-Bone wrote:I'm also curious why you would need to repeat the same simulation twice with exactly identical results.
Well, the result is not identical! :) The timescale required to be identical. The result you get is continously updated vertical and horizontal velosities (pardon me, radial and tangential would be more accurate), altitude and distance. Also, during the burn, propellant mass will decrease, causing reactive acceleration to increase. That is why I need to repeat the same simulation continously, if I understood your question right.

Though I will try Robin's solution and report here as soon as I can.

Edit: Well, Robin's solution seem to work damn fine to me :) I got some legit results now. Now I just regret that I don't have enough programming skill yet to figure it out by myself :) Thank you.
I don't really see why you'd need a set time step for that. It's certainly easier that way, but not an absolute requirement. You could absolutely create an at least approximate solution using dt. It wouldn't be perfectly deterministic but if you do it well it would probably be good enough.

But yeah, Robin's solution is much easier.

Also, about Box2D: As you can read in the text you posted, Box2D isn't really deterministic (although it is true that it doesn't depend on the time step (which isn't always a good thing)).
User avatar
misterspok
Prole
Posts: 20
Joined: Fri Apr 19, 2013 12:40 pm

Re: About setting custom "dt"

Post by misterspok »

T-Bone wrote:I don't really see why you'd need a set time step for that. It's certainly easier that way, but not an absolute requirement. You could absolutely create an at least approximate solution using dt. It wouldn't be perfectly deterministic but if you do it well it would probably be good enough.
You're right. I don't really need a precise time step. It works well fine without it. But the fuel consumption step changes correspondingly to time step, and it makes the engine change it's momental thrust. That is not right, though plausible.

Think of it as my personal desire to make everything as accurately calculated as possible. That is the only answer I can give you :)
User avatar
micha
Inner party member
Posts: 1083
Joined: Wed Sep 26, 2012 5:13 pm

Re: About setting custom "dt"

Post by micha »

To me it sound not like you need a deterministic simulation. The problem that you have, is that dt is not implemented correctly.
misterspok wrote:
micha wrote:Can you specify, what you mean by "all your math will collapse"?
Sure I can. Delta-V, that is calculated for the spacecraft, depends on propellant mass loss that craft uses to bun. Basically, it is the Tsiolkovsky's equation. To calculate maximum mass loss for given engine thrust I need delta-time (dt). So, as you can see, if dt varies between, say, 0.001 and 0.002, it means that during burn time engine thrust will sporadically increase/decrease TWICE the value.

If you add here a gravitational influence, to calculate how it changes the vertical speed of the craft you also need dt.
It is correct, that dt varies, but so does the time elapsed between two frames. If the time between two frames is larger, then also the mass loss in this time interval is larger. This is exactly what you want. The only reason, why you might have problems, is, that you have not implemented dt in all places, where it should be.
What exactly is the equation you implemented and how did you do it? Can you post some code? I'd like to have a look at ti.
misterspok wrote:
micha wrote:You cannot directly control the frame rate. But you can ignore the framerate

Code: Select all

function love.update(dt)
dt = 1/60
[...]
end
However, I don't recommend that.
Ignore the frame rate? That is interesting. But why would you not recommend that? I must try it and see :)
If you ignore the frame rate, then you don't need to use dt in the first place. The purpose of dt is to make simulations run at the same speed on all computer (in terms of e.g. pixels per seconds). If you ignore dt, you get the same speed in terms of pixels per frame, but as the framerate is possibly different on different computers, the game will run at different speed.
User avatar
misterspok
Prole
Posts: 20
Joined: Fri Apr 19, 2013 12:40 pm

Re: About setting custom "dt"

Post by misterspok »

micha wrote:It is correct, that dt varies, but so does the time elapsed between two frames. If the time between two frames is larger, then also the mass loss in this time interval is larger. This is exactly what you want. The only reason, why you might have problems, is, that you have not implemented dt in all places, where it should be.
What exactly is the equation you implemented and how did you do it? Can you post some code? I'd like to have a look at ti.
I am not a greedy person :) I will give you the whole love.update part with comments!

Code: Select all

function love.update(dt)
	timeLeft = dt;     --This is where I start to implement Robin's solution
	
	--[[Assigning "new" coordinates values from previous iteration
	to "old" coordinates of current iteration--]]
	x1 = x2;
	y1 = y2;
	
	maxFt = q * epsilon;		--calculating maximum propellant mass loss during epsilon-time
	
	--turn on/off precise parameters setting
	if love.keyboard.isDown("lshift") then
		precFlag = true;
	else
		precFlag = false;
	end
		
	--changing engine thrust here
	if precFlag then
		if love.keyboard.isDown("w") then
			ft = ft + (0.0005 * dt);
		elseif love.keyboard.isDown("s") then
			ft = ft - (0.0005 * dt);
		end
	else
		if love.keyboard.isDown("w") then
			ft = ft + (0.005 * dt);
		elseif love.keyboard.isDown("s") then
			ft = ft - (0.005 * dt);
		end
	end
	
	--Checking engine thrust not to exceed max/min values
	if ft >= maxFt then ft = maxFt
		elseif ft <= 0 then ft = 0
	end
	
	--Changing vector of thrust here
	if precFlag then
		if love.keyboard.isDown("a") then
			ang = ang - 0.005;
		elseif love.keyboard.isDown("d") then
			ang = ang + 0.005;
		end
	else
		if love.keyboard.isDown("a") then
			ang = ang - 0.05;
		elseif love.keyboard.isDown("d") then
			ang = ang + 0.05;
		end
	end
	
	--Checking if angle exceeds +/- 360 degrees scale
	if ((ang >= 360) or (ang <= -360)) then ang = 0 end
	
	--Check if the engine start button pressed
	if love.mouse.isDown("l") then
		engFlag = true;
	else
		engFlag = false;
	end
	
	if fmass <= 0 then         --Check if fuel is not depledet during manouver
		engFlag = false;
	end
	
	-- Magic!
	while timeLeft > epsilon do
		if engFlag then      --engine ON, flying
			--Calculating acceleration during manouvers (to display it later, we don't really need that for physics)
			areac = w * math.log((cmass + fmass)/(cmass + fmass - ft)) / epsilon + ((gravConst * lunaMass) / math.pow((lunaRad + altitude), 2) - math.pow(xvel, 2) / (lunaRad + altitude)) * math.cos(ang / 57.295779513);
			
			--Calculating vertical velocity and altitude change
			oldAltitude = altitude;
			yvel = yvel + math.cos(ang / 57.295779513) * w * math.log((cmass + fmass)/(cmass + fmass - ft)) - ((gravConst * lunaMass) / math.pow((lunaRad + altitude), 2) - math.pow(xvel, 2) / (lunaRad + altitude)) * epsilon;
			altitude = oldAltitude + yvel * epsilon;
			
			--Calculating horizontal velocit change and distance that craft's radius-vector went through on the surface
			xvel = (xvel + math.sin(ang / 57.295779513) * w * math.log((cmass + fmass)/(cmass + fmass - ft))) * (lunaRad + oldAltitude) / (lunaRad + altitude);
			landDist = landDist + (xvel / (lunaRad + altitude)) * lunaRad * epsilon;
			
			fmass = fmass - ft;			--decrement of total fuel mass		
		else    --Engine OFF, falling		
			oldAltitude = altitude;
			yvel = yvel - ((gravConst * lunaMass) / math.pow((lunaRad + altitude), 2) - math.pow(xvel, 2) / (lunaRad + altitude)) * epsilon;
			altitude = oldAltitude + yvel * epsilon;
				
			xvel = xvel * (lunaRad + oldAltitude) / (lunaRad + altitude);          --Calculting tangential speed change depending on altitude change
			landDist = landDist + (xvel / (lunaRad + altitude)) * lunaRad * epsilon;
		end
		timeLeft = timeLeft - epsilon;
		
		--new X coordinate for line drawing
		x2 = x2 + xvel * epsilon;
	end
		
	--Calsulating the resulting grav acceleration that influences the craft and depends on altitude and tangential speed
	gravity = (gravConst * lunaMass) / math.pow((lunaRad + altitude), 2) - math.pow(xvel, 2) / (lunaRad + altitude);
	
	areac = areac / 9.81;		--Converting to Gees
	
	--Chech of surface collision
	if ((altitude <= 0) and (yvel < -5)) or ((altitude <= 0) and (math.abs(xvel) > 2)) then
		altitude = 0; xvel = 0;
		yvel = 0; ang = 0;
		engFlag = false;
		crashed = "Crash!";
	elseif altitude <= 0 then
		altitude = 0; xvel = 0;
		yvel = 0; ang = 0;
		engFlag = false;
		landed = "Landed!";
	else
		crashed = "_______";
		landed = "_______";
	end
	
	--updating new Y coordinates to draw line
	y2 = altitude;
end
Thus you can see, that I want the calculations to be as accurate as it can be, and not to depend on some unstable value. But, you also can see that I, for now, use the simple line to represent craft's trajectory. And later, when I will be able to add real graphics, it will use dt. But not my physics :)
Last edited by misterspok on Thu May 30, 2013 8:49 pm, edited 1 time in total.
User avatar
Plu
Inner party member
Posts: 722
Joined: Fri Mar 15, 2013 9:36 pm

Re: About setting custom "dt"

Post by Plu »

If you want to make the engine even more precise, consider changing the first line to

Code: Select all

timeLeft = timeLeft + dt;
Right now you are ignoring the leftover segments of timeLeft that are smaller than epsilon.

(Imagine timeLeft = 30 and epsilon = 4, you will do 7 loops, but then timeLeft will be 2, and you will simply discard it.)

It might not even be noticable, but if you're going for exact, better save up those leftovers until they form a full cycle on their own :)
User avatar
misterspok
Prole
Posts: 20
Joined: Fri Apr 19, 2013 12:40 pm

Re: About setting custom "dt"

Post by misterspok »

Plu wrote:If you want to make the engine even more precise, consider changing the first line to

Code: Select all

timeLeft = timeLeft + dt;
Right now you are ignoring the leftover segments of timeLeft that are smaller than epsilon.

(Imagine timeLeft = 30 and epsilon = 4, you will do 7 loops, but then timeLeft will be 2, and you will simply discard it.)

It might not even be noticable, but if you're going for exact, better save up those leftovers until they form a full cycle on their own :)
Oh, you are very right about that one, sir! Thank you for noticing :)
User avatar
micha
Inner party member
Posts: 1083
Joined: Wed Sep 26, 2012 5:13 pm

Re: About setting custom "dt"

Post by micha »

misterspok wrote:I am not a greedy person :) I will give you the whole love.update part with comments!
I looked through your code and it looks like the time step is implemented properly. When you said the math would break down, did you actually experience that or did you just think it could happen? I am still quiet sure that, if dt is implemented correctly, you don't need to fix the time step.

However, since the method robin proposed, works for you and is implemented already, you should stick to it.
User avatar
misterspok
Prole
Posts: 20
Joined: Fri Apr 19, 2013 12:40 pm

Re: About setting custom "dt"

Post by misterspok »

micha wrote:I looked through your code and it looks like the time step is implemented properly. When you said the math would break down, did you actually experience that or did you just think it could happen? I am still quiet sure that, if dt is implemented correctly, you don't need to fix the time step.
If you look at my code, "q" variable resresents maximum fuel usage per second, so you can say it represents maximum thrust of an engine. To calculate fuel usage per delta-time (maxFt) I need to do this:

Code: Select all

maxFt = q * dt
If dt deviate I get different values of maxFt. Also, I use "ft" variable. It stores the value of current thrust (fuel usage). To calculate delta-V that craft acquire while burning "ft" kilograms of fuel during "dt" time I use Tsiolkovsky's equation. Note that "ft" does not change correspondingly to "dt" deviations:

Code: Select all

new_V = old_V + w * ln(craftmass / (craftmass - ft))
So, if delta-time deviate, say, 0.001 to 0.002. The result would be, that craft acuqired same delva-V during longer period of time while travalling longer distance. Which is not right.
User avatar
easy82
Party member
Posts: 184
Joined: Thu Apr 18, 2013 10:46 pm
Location: Hungary

Re: About setting custom "dt"

Post by easy82 »

I'm also a big fan of this solution. See this conversation!
User avatar
micha
Inner party member
Posts: 1083
Joined: Wed Sep 26, 2012 5:13 pm

Re: About setting custom "dt"

Post by micha »

misterspok wrote:If you look at my code, "q" variable resresents maximum fuel usage per second, so you can say it represents maximum thrust of an engine. To calculate fuel usage per delta-time (maxFt) I need to do this:

Code: Select all

maxFt = q * dt
If dt deviate I get different values of maxFt. Also, I use "ft" variable. It stores the value of current thrust (fuel usage). To calculate delta-V that craft acquire while burning "ft" kilograms of fuel during "dt" time I use Tsiolkovsky's equation. Note that "ft" does not change correspondingly to "dt" deviations:

Code: Select all

new_V = old_V + w * ln(craftmass / (craftmass - ft))
So, if delta-time deviate, say, 0.001 to 0.002. The result would be, that craft acuqired same delva-V during longer period of time while travalling longer distance. Which is not right.
Now I understand, what these equations mean. The "ft" is, indeed, implemented incorrectly. I didn't see that the first time. The "ft" stores in absolute value, how much fuel is burned in one time step (unit is kg). And that, of course, has to depend on "dt". You need to store a "fuel rate", which is in kg per second. Also the maxFt has to be stored as a rate in kg per second. Let's call this rate ftpers. Then you go:
Instead of

Code: Select all

if precFlag then
      if love.keyboard.isDown("w") then
         ft = ft + (0.0005 * dt);
      elseif love.keyboard.isDown("s") then
         ft = ft - (0.0005 * dt);
      end
   else ...
you want

Code: Select all

if precFlag then
      if love.keyboard.isDown("w") then
         ftpers = ftpers + (0.0005 * dt);
      elseif love.keyboard.isDown("s") then
         ftpers = ftpers - (0.0005 * dt);
      end
   else ...
Then the maximum check is:

Code: Select all

if ftpers >= maxFtpers then ft = maxFtpers
      elseif ftpers <= 0 then ftpers = 0
   end
And right before you put ft into the equation you calculate

Code: Select all

ft = ftpers * dt
By the way, you should also use dt for changing the angle (and use an angular velocity in "1 per second"):

Code: Select all

    if love.keyboard.isDown("a") then
         ang = ang - angularVelocity * dt
...
I insist so much on this point, because there are two issues with dt, namely
- implementing dt correctly
- getting reproducible (deterministic) simulations
Robins solution is a solution for the second problem. But by implementing this solution, incorrectly implemented time steps are not noticed anymore because the time step is the same in each frame. So it looks like this solution also solves the first problem. But it does not. In the end you will have variables carrying values, that are not physical, because you messed up the units (e.g. kg instead of kg/s).
If you want to get it correctly very much depends on why you write your game. If you need physically correct simulations, then you should implement everything properly. If you want something that looks good and feels smooth, then you will probably be faster if you accept some mathematical errors in the code.
Post Reply

Who is online

Users browsing this forum: Bing [Bot] and 3 guests