It is currently May 14th, 2024, 8:59 am

Equation of Kepler

Get help with creating, editing & fixing problems with skins
Fulmar
Posts: 21
Joined: July 24th, 2012, 4:50 pm
Location: Belgium

Equation of Kepler

Post by Fulmar »

Hello,

I am writing a skin concerning the orbits of celestial bodies.
One of the formulas to use is the equation of Kepler:
E = M + e sin E
E is the eccentric anomaly, M is the mean anomaly (< 360°) and e is the eccentricity (0 < e < 1 for an ellipse). M and e are known, E is the value to find.
Because this is not a linear function it's difficult to resolve.
Normally one could start with:
E0 = M
E1 = M + e sin E0
E2 = M + e sin E1
E3 = M + e sin E2
etc.
This is repeated until the required accuracy is obtained.
To obtain the value E many iterations can be needed (possible more than 50).

But when e is larger than 0.4 for instance, the calculation may be very slow. So a better iteration formula should be used:

E1 = E0 + (M + e0 sin E0 - E0)/(1 - e cos E0)
where E0 is the last obtained value for E.
All quantities are expressed in degrees, except e that is expressed in radians.

So, the first step would be:
E1 = E0 + (M + e0 sin E0 - E0)/(1 - e cos E0)
Second step:
E2 = E1 + (M + e0 sin E1 - E1)/(1 - e cos E1)
Third step:
E3 = E2 + (M + e0 sin E2 - E2)/(1 - e cos E2)
and so on till the value of Ex is the same as the value of Ex-1.

Finally my question:
How can I write this in Rainmeter?

Thanks for your help.
User avatar
Kaelri
Developer
Posts: 1721
Joined: July 25th, 2009, 4:47 am

Re: Equation of Kepler

Post by Kaelri »

I haven't done trigonometry in a couple years, so my understanding of the formula might be a little rough. But here's a Lua script that will return the result given e and M:

Code: Select all

[MeasureKeplerScript]
Measure=Script
ScriptFile=Kepler.lua
M=
e=
Kepler.lua

Code: Select all

function Initialize()
	local M = SELF:GetNumberOption('M')
	local e = SELF:GetNumberOption('e')

	M = math.rad(M)

	E = M

	repeat
		local LastE = E
		E = E + (M + e * math.sin(E) - E) / (1 - e * math.cos(E))
	until E == LastE

	E = math.deg(E)
end

function Update()
	return E
end
Notes:

- Lua's trig functions (math.sin and math.cos, here) require radian values, so I made it convert M to radians at the beginning, and then convert the final value of E back to degrees.

- I also assumed that "e0" in your original post was supposed to be just "e," since the eccentricity is a known constant. Correct me if I'm wrong.

- My understanding of Kepler's Equation (very rough) is that this method will never give you a mathematically exact match. So when the function checks that "E == LastE," they're simply equal up to the maximum precision of Lua's math engine.

EDIT: I cleaned up a couple of typos and misplaced variables. Make sure to use the latest version if you grabbed the earlier one.

EDIT 2: Thanks to Smurfier for simplifying my loop.
Fulmar
Posts: 21
Joined: July 24th, 2012, 4:50 pm
Location: Belgium

Re: Equation of Kepler

Post by Fulmar »

OK, thank you for your work. I will give feedback as soon as possible.

:)
Fulmar
Posts: 21
Joined: July 24th, 2012, 4:50 pm
Location: Belgium

Re: Equation of Kepler

Post by Fulmar »

I don't know much about Lua script. So I am struggling through a mass of examples and tutorials. Despite this the script keeps returning 0.

First of all please take note that e is expressed in radians (the eccentricity, between 0 and 1 for an ellipse).
e0 is expressed in degrees (= e * 57.29577951).

In my skin I have:



[MeasureKeplerScript]
Measure=Script
ScriptFile=#CURRENTPATH#Kepler.lua
M=MeadObject1
e=EcorObject1
e0=EcorObject1*#Rad#

[MeterLuaReturn]
Meter=String
MeasureName=MeasureKeplerScript
FontColor=#Color1#
X=50
Y=50
NumOfDecimals=7
Text=Script Returned: %1



MeadObject1 is the mean anomaly expressed in degrees, EcorObject1 is the eccentricity and EcorObject1*#Rad# is the eccentricity muliplied by 57.29577951.

In my Lua script I have:



PROPERTIES =
{

M = "";
e = "";
e0 = "";

}

function Initialize()
local M = SELF:GetNumberOption('M')
local e = SELF:GetNumberOption('e')
local e0 = SELF:GetNumberOption('e0')

M = math.rad(M)

E = M

repeat
local LastE = E
E = E + (M + e0 * math.sin(E) - E)/(1 - e * math.cos(E))
until E == LastE

E = math.deg(E)

end

function Update()
return E
end



I added the PROPERTIES to your script, but I don't know if that's right. Sorry if i did this erroneously.

Thank you for your help.
User avatar
jsmorley
Developer
Posts: 22632
Joined: April 19th, 2009, 11:02 pm
Location: Fort Hunt, Virginia, USA

Re: Equation of Kepler

Post by jsmorley »

You don't want or need a PROPERTIES section in Lua scripts anymore. That has been deprecated in favor of SELF:GetOption() and SELF:GetNumberOption()
Fulmar
Posts: 21
Joined: July 24th, 2012, 4:50 pm
Location: Belgium

Re: Equation of Kepler

Post by Fulmar »

Okay, obviously I have to do some more studywork in Lua script.
I removed the part about PROPERTIES, but it still doesn't work.
User avatar
Kaelri
Developer
Posts: 1721
Joined: July 25th, 2009, 4:47 am

Re: Equation of Kepler

Post by Kaelri »

Your problem is here:

Code: Select all

M=MeadObject1
e=EcorObject1
e0=EcorObject1*#Rad#
The "SELF:GetNumberOption()" function in Lua assumes that these are actual numbers. If these are the names of other measures whose values you want to use, you'll need to do this differently. Here's what I'd do:

Code: Select all

[MeasureKeplerScript]
Measure=Script
ScriptFile=#CURRENTPATH#Kepler.lua
M=MeadObject1
e=EcorObject1

Code: Select all

function Initialize()
	local MeasureName_M = SELF:GetOption('M')
	local MeasureName_e = SELF:GetOption('e')
	--Get the "M" and "e" options on the script measure as the other measures' names.

	local Measure_M = SKIN:GetMeasure(MeasureName_M)
	local Measure_e = SKIN:GetMeasure(MeasureName_e)
	--Identify the other measures by their names.

	local M = Measure_M:GetValue()
	local e = Measure_e:GetValue()
	--Get the values of the other measures.

	M = math.rad(M)
	e0 = math.rad(e)

	E = M

	repeat
		local LastE = E
		E = E + (M + e0 * math.sin(E) - E)/(1 - e * math.cos(E))
	until E == LastE

	E = math.deg(E)	

end

function Update()
	return E
end
Fulmar
Posts: 21
Joined: July 24th, 2012, 4:50 pm
Location: Belgium

Re: Equation of Kepler

Post by Fulmar »

I can follow what concerns the first step, but only when I drop "local":

function Initialize()
MeasureName_M = SELF:GetOption('M')
MeasureName_e = SELF:GetOption('e')
--Get the "M" and "e" options on the script measure as the other measures'names.

I found out that "MeasureName_M" returns "MeadObject1" and "MeasureName_e" returns "EcorObject1". Happy for that...
But when I leave "local", 0 is returned. Not pretty much yet but it is at least something.
The following steps still return 0.
User avatar
Kaelri
Developer
Posts: 1721
Joined: July 25th, 2009, 4:47 am

Re: Equation of Kepler

Post by Kaelri »

Ok, one more thing to try: if the measures are not constant, you'll need to get their values on each update, not just at the beginning. This just means moving the bulk of the script out of "Initialize" and into "Update".

Code: Select all

function Initialize()
   local MeasureName_M = SELF:GetOption('M')
   local MeasureName_e = SELF:GetOption('e')

   Measure_M = SKIN:GetMeasure(MeasureName_M)
   Measure_e = SKIN:GetMeasure(MeasureName_e)
end

function Update()
   local M = Measure_M:GetValue()
   local e = Measure_e:GetValue()
   --Get the values of the other measures.

   M = math.rad(M)
   local e0 = math.rad(e)

   local E = M

   repeat
      local LastE = E
      E = E + (M + e0 * math.sin(E) - E)/(1 - e * math.cos(E))
   until E == LastE

   E = math.deg(E)   

   return E
end
Fulmar
Posts: 21
Joined: July 24th, 2012, 4:50 pm
Location: Belgium

Re: Equation of Kepler

Post by Fulmar »

It's working!!!

But I changed the expression of the equation a bit, because all values are expressed in degrees, except e0 that's e multiplied by 57,...

The script is as follows now:

function Initialize()
MeasureName_M = SELF:GetOption("M")
MeasureName_e = SELF:GetOption("e")

Measure_M = SKIN:GetMeasure(MeasureName_M)
Measure_e = SKIN:GetMeasure(MeasureName_e)
end

function Update()
local M = Measure_M:GetValue()
local e = Measure_e:GetValue()

local E = M

repeat
local LastE = E
E = E + (M + math.deg(e)*math.sin(math.rad(E)) - E)/(1 - e*math.cos(math.rad(E)))
until E == LastE

return E
end

One last question in this topic maybe: I will calculate the orbits for n objects in the same skin. Can this be done by this one Lua script? Do I create another Measure "MeasureKeplerScript" and another Meter "MeterLuaReturn" for each object?

Thank you for your kind help.

:bow: