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.
It is currently May 14th, 2024, 8:59 am
Equation of Kepler
-
- Posts: 21
- Joined: July 24th, 2012, 4:50 pm
- Location: Belgium
-
- Developer
- Posts: 1721
- Joined: July 25th, 2009, 4:47 am
Re: Equation of Kepler
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:
Kepler.lua
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.
Code: Select all
[MeasureKeplerScript]
Measure=Script
ScriptFile=Kepler.lua
M=
e=
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
- 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.
-
- Posts: 21
- Joined: July 24th, 2012, 4:50 pm
- Location: Belgium
Re: Equation of Kepler
OK, thank you for your work. I will give feedback as soon as possible.
-
- Posts: 21
- Joined: July 24th, 2012, 4:50 pm
- Location: Belgium
Re: Equation of Kepler
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.
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.
-
- Developer
- Posts: 22632
- Joined: April 19th, 2009, 11:02 pm
- Location: Fort Hunt, Virginia, USA
Re: Equation of Kepler
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()
-
- Posts: 21
- Joined: July 24th, 2012, 4:50 pm
- Location: Belgium
Re: Equation of Kepler
Okay, obviously I have to do some more studywork in Lua script.
I removed the part about PROPERTIES, but it still doesn't work.
I removed the part about PROPERTIES, but it still doesn't work.
-
- Developer
- Posts: 1721
- Joined: July 25th, 2009, 4:47 am
Re: Equation of Kepler
Your problem is here:
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
M=MeadObject1
e=EcorObject1
e0=EcorObject1*#Rad#
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
-
- Posts: 21
- Joined: July 24th, 2012, 4:50 pm
- Location: Belgium
Re: Equation of Kepler
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.
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.
-
- Developer
- Posts: 1721
- Joined: July 25th, 2009, 4:47 am
Re: Equation of Kepler
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
-
- Posts: 21
- Joined: July 24th, 2012, 4:50 pm
- Location: Belgium
Re: Equation of Kepler
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.
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.