pyEphem - Calculating Positions of non-Earthy Moons - python

I'm trying to get the Earth distance and the right ascension (relative to my observer point in Earth) of a satellite not orbiting the Earth, but pyEphem isn't returning the same properties as other solar bodies.
With Ganymede (the largest moon of Jupiter), for instance:
import math, ephem
Observer = ephem.city('London')
Observer.date = '2013-04-23'
Observer.pressure, Observer.elevation = 0, 100
moonGanymede = ephem.Ganymede(Observer)
print math.cos(moonGanymede.ra) # right ascension
print moonGanymede.earth_distance * ephem.meters_per_au # distance
I get this error:
AttributeError: 'Ganymede' object has no attribute 'earth_distance'
The ra attribute exists, but is it relative to my Observer or to Jupiter?
Seems to be relative to the Observer, since if I change the location, the value changes too.
I've read the documentation and I know that these properties are not defined for moons, but I have no idea how to compute those relative to the Earth given the additional defined properties of moon bodies:
On planetary moons, also sets:
Position of moon relative to planet (measured in planet radii)
x — offset +east or –west
y — offset +south or –north
z — offset +front or –behind
Doing:
print moonGanymede.x, moonGanymede.y, moonGanymede.z
Outputs:
-14.8928060532 1.52614057064 -0.37974858284
Since Jupiter has an average radius of 69173 kilometers, those values translate to:
moonGanymede.x = 1030200 kilometers (west)
moonGanymede.y = 105570 kilometers (south)
moonGanymede.z = 26268 kilometers (behind)
Given that I know the distance and right ascension of Jupiter relative to the Observer, how can I calculate the distance and right ascension of moonGanymede (also relative to the Observer)?
I'm using pyEphem 3.7.5.1 (with Python 2.7).

Just some thoughts; You probably need to do it two steps.
Get location of satellite relative to parent planet
Get location of planet relative to observer
Trigonometry calculation; get the location of satellite relative to observer.
You already did 1, and can easily do 2. Convert all values to x,y,z and add then back to angular. Or I'm sure you / ephym can do this for you directly.
HTH

I'm still trying to figure it out (if anyone spots something, please do tell), but it seems that if I do:
sqrt((-14.8928060532)^2 + (1.52614057064)^2 + (-0.37974858284)^2) = 14.9756130481
I'll always get a value that always falls within the min/max distance from orbit center (14.95 - 14.99).
Since that's specified in orbit center radii, I'll need to multiply it by 69173 * 1000 to get the SI unit:
14.9756130481 * 69173 * 1000 = 1.0359080813762213 * 10^9 meters
Since pyEphem deals in distances with AU:
print (1.0359080813762213 * 10**9) / ephem.meters_per_au # 0.00692461785302
At the same time, the Earth-Jupiter distance was 5.79160547256 AU.
Now, to get the distance, I should either add or subtract depending on the sign of the z coordinate:
5.79160547256 - 0.00692461785302 = 5.78468085470698 AU
Running the same code for today (now) returns 6.03799937821 which seems to very close to the value of 6.031 that WolframAlpha is returning at the present time, it doesn't match 100% but perhaps that could be accounted for by some different underlying ephemeris library or data source. Not sure...

Looks like right ascension, declination, azimuth, etc are computed correctly:
In [31]: g = ephem.Ganymede(Observer)
In [32]: j = ephem.Jupiter(Observer)
In [33]: g.ra, g.az, g.dec
Out[33]: (1.3024204969406128, 5.586287021636963, 0.38997682929039)
In [34]: j.ra, j.az, j.dec
Out[34]: (1.303646765055829, 5.5853118896484375, 0.39010250333236757)
Values for Ganimede and Jupiter are close enough, it looks like you get correct results for everything except distance to object.

Related

find if an device is in perpendicular to the current location from ariel view / map view

A device is traveling from source to destination and has support for GPS,
we are able to locate the nearest signal using (current loc - static fixed traffic signals array)
here D1 is nearest, but we want to select D2 as it is facing our direction,
my approach is to find the perpendicular to the current location if a signal is perpendicular, then select that one, but I can't figure out how to, thought of using another value attached to each signal called angle, which is the angle from the north ie 180 deg in our case and somehow calculate the angle of the andriod from the north and compare it. if it is opposite (180 - south , 0 - north) select that one.
using gmaps API to find the direction from source to destination and converting the string(Encoded Polyline) to lat log using python decode polyline function.)
How can I implement the above solution, is it functional, or do I have any other options
I was able to only find out this code, but it is for the angle between a straight line to the x-axis
I think math.atan2(x, y) also provides an angle, right?
import math
def calculate_initial_compass_bearing(pointA, pointB):
"""
Calculates the bearing between two points.
The formulae used is the following:
θ = atan2(sin(Δlong).cos(lat2),
cos(lat1).sin(lat2) − sin(lat1).cos(lat2).cos(Δlong))
:Parameters:
- `pointA: The tuple representing the latitude/longitude for the
first point. Latitude and longitude must be in decimal degrees
- `pointB: The tuple representing the latitude/longitude for the
second point. Latitude and longitude must be in decimal degrees
:Returns:
The bearing in degrees
:Returns Type:
float
"""
if (type(pointA) != tuple) or (type(pointB) != tuple):
raise TypeError("Only tuples are supported as arguments")
lat1 = math.radians(pointA[0])
lat2 = math.radians(pointB[0])
diffLong = math.radians(pointB[1] - pointA[1])
x = math.sin(diffLong) * math.cos(lat2)
y = math.cos(lat1) * math.sin(lat2) - (math.sin(lat1)
* math.cos(lat2) * math.cos(diffLong))
initial_bearing = math.atan2(x, y)
#print(initial_bearing)
# Now we have the initial bearing but math.atan2 return values
# from -180° to + 180° which is not what we want for a compass bearing
# The solution is to normalize the initial bearing as shown below
initial_bearing = math.degrees(initial_bearing)
compass_bearing = (initial_bearing + 360) % 360
return compass_bearing
You're assuming the phone is installed straight forward and not at an angle. That isn't a good assumption. My phone is rarely straight forwared, its usually thrown in the center console in whatever way it lands. Or sitting on the passenger seat, same thing. A better idea would be to look at the heading the last time their speed was non-zero- that will show the direction they were going in. Of course if they made a last minute lane change it could be a bit off, but it will be more accurate.

Converting between WGS84 degrees latitude/longitude and meters?

So, I am doing some work with data from an INS unit, in order to calculate the errors in its readings by integrating its velocity data over time to get a change in position, and then comparing that to its actual recorded change in position. The problem is that it gives its position with Latitude and Longitude in degrees (to 11 decimal places), and its documentation indicates that these are using the WGS84 standard, while its velocities are given in meters/second (to 10 decimal places).
I found this other question, but the answers to it were giving answers that assumed that the Earth is a sphere, while the WGS standard uses an ellipsoid, and it seems possible that using calculations that assume that the Earth is spherical might introduce errors into my calculations.
I'm intending to use Python to perform my data analysis with, so ideally answers should use Python as well, but using another language to do the data cleaning would work as long as I can save the cleaned data into a text file that Python can read.
Perhaps you could use LatLon (or for python3 LatLon23), which does enable treating eearth as an ellipsoid.
see an example code using LatLon23 for python3:
from LatLon23 import LatLon, Latitude, Longitude
palmyra = LatLon(Latitude(5.8833), Longitude(-162.0833)) # Location of Palmyra Atoll
honolulu = LatLon(Latitude(21.3), Longitude(-157.8167)) # Location of Honolulu, HI
distance = palmyra.distance(honolulu) # WGS84 distance in km
print(distance)
print(palmyra.distance(honolulu, ellipse = 'sphere')) # FAI distance in km
initial_heading = palmyra.heading_initial(honolulu) # Heading from Palmyra to Honolulu on WGS84 ellipsoid
print(initial_heading)
hnl = palmyra.offset(initial_heading, distance) # Reconstruct Honolulu based on offset from Palmyra
print(hnl.to_string('D')) # Coordinates of Honolulu

Path between two Topos() locations: determine latitude and longitude where a given altitude is reached

I am quite new to field of orbital mechanics and currently struggling a bit with the following problem, which should be quite easy to solve with Skyfield, yet I am a bit overwhelmed by all the different coordinate systems and the translation between them.
I have a Topos location on Earth and a Topos location of a LEO satellite. I am considering the line-of-sight between them. I want to determine the latitude and longitude of the position along this path, where it intersects a specific layer of the atmosphere.
An example would be the mesosphere and an existing dataset on its properties at around 100km that is given based on latitude and longitude. The intersection would allow me to better understand the interaction these properties have on the communication with the satellite.
I tried doing it with Skyfield directly, but only end up with an Apparent object that I cannot convert back to latitude, longitude on Earth. First, I trigonometrically determined the distance from Earth to the point, where the height of 100km is reached.
Then, I took the position on Earth and used the unchanged elevation, azimuth to keep the direction of the path and finally added the calculated distance to arrive at this position. I think I need to get a Geocentric object to use subpoint() in order to get the desired latitude, longitude of this location.
This is what I have so far:
from skyfield.api import load, Distance
from skyfield.toposlib import Topos
import numpy as np
ts = load.timescale()
earth_position = Topos('52.230039 N', '4.842402 E', elevation_m=10)
space_position = Topos('51.526200 N', '5.347795 E', elevation_m=625 * 1000)
difference = (space_position - earth_position).at(ts.now()).altaz()
distance_to_height = 100 / np.sin(difference[0].radians)
position = earth_position.at(ts.now()).from_altaz(alt_degrees=difference[0].degrees, az_degrees=difference[1].degrees, distance=Distance(km=distance_to_height))
I have gone through the documentation multiple times, and stumbled upon frame_latlon(frame) for Generic ICRF objects, but am not sure how to further proceed.
Trying it completely trigonomatrically with the latitudes and longitudes didn't yield the desired results either.
Unfortunately I do not really have any validated results that could be used to solve this problem more easily. Imagining it again trigonometrically, it is obvious that an increase in altitude of the satellite position would move the lat, lon of the intersection closer to the position on Earth. Decreasing the altitude would then move this intersection closer to the satellite.
That is an interesting problem, which Skyfield’s API provides no easy way to ask about; if you could outline the larger problem that will be solved by knowing the intersection of the line-of-sight with a particular altitude, then it is possible that a routine addressing that problem could be written for future users tackling the same question.
In the meantime:
To get your script running I had to import Distance from api.
The name dis was not recognized, so I replaced it with distance_to_height, hoping that it was the name intended.
Calling ts.now() is giving you a slightly different date and time on each call. While the script runs so fast that it probably does not matter, I have for clarity pivoted to calling now() only once at the beginning of the script, which is also slightly faster than calling it repeatedly. (Actually in this case it’s much faster, because the rotation matrices only get computed once rather than having to be computed over again for each separate time object, but that’s a hidden detail that’s not easy to see.)
I suspect a problem with your geometry: the 100 / sin() maneuver would only work if the Earth were flat, I think? But maybe you are always dealing with nearly-overhead satellites and so the error is manageable? (Or maybe I am mis-imagining the geometry; feel free to provide a diagram if the math is in fact correct.)
For readability I’ll give the components of altaz() names rather than numbers.
With those tweaks in place,
I think the answer is that you need to manually construct a Geocentric
position by adding together the position of the observer
and the relative vector you have created
between the observer and the kind-of-100km point along the line of sight.
Having to take a manual step like this suggests a possible area
where Skyfield can improve.
Here is how it looks in code:
from skyfield.api import load, Distance
from skyfield.positionlib import Geocentric
from skyfield.toposlib import Topos
import numpy as np
ts = load.timescale()
t = ts.now()
earth_position = Topos('52.230039 N', '4.842402 E', elevation_m=10)
space_position = Topos('51.526200 N', '5.347795 E', elevation_m=625 * 1000)
alt, az, distance = (space_position - earth_position).at(t).altaz()
distance_to_height = 100 / np.sin(alt.radians)
e = earth_position.at(t)
p = e.from_altaz(alt_degrees=alt.degrees, az_degrees=az.degrees, distance=Distance(km=distance_to_height))
g = Geocentric(e.position.au + p.position.au, t=t)
s = g.subpoint()
print(s)
print(s.elevation.km, '<- warning: 100/sin() did not produce exactly 100')
The result I see is:
Topos 52deg 06' 30.0" N 04deg 55' 51.7" E
100.02752954478532 <- warning: 100/sin() did not produce exactly 100
And for the future,
I have added some thoughts to the Skyfield TODO.rst file
that together might move towards unlocking a more idiomatic way
to perform this kind of calculation in the future —
though I suspect that a few more steps even beyond these will be necessary:
https://github.com/skyfielders/python-skyfield/commit/ba1172a0ccfef84473436d9d7b8a7d7011344cbd

Random Walk of a Photon Through the Sun

For a project, I am trying to determine the time it would take for a photon to leave the Sun. However, I am having trouble with my code (found below).
More specifically, I set up a for loop with an if statement, and if some randomly generated probability is less than the probability of collision, that means the photon collides and it changes direction.
What I am having trouble with is setting up a condition where the for loop stops if the photon escapes (when distance > Sun radius). The one I have set up already doesn't appear to work.
I use a very scaled down measurement of the Sun's radius because if I didn't it would take a long time for the photon to escape in my simulation.
from numpy.random import random as rng # we want them random numbers
import numpy as np # for the math functions
import matplotlib.pyplot as plt # to make pretty pretty class
mass_proton = 1.67e-27
mass_electron = 9.11e-31
Thompson_cross = 6.65e-29
Sun_density = 150000
Sun_radius = .005
Mean_Free = (mass_proton + mass_electron)/(Thompson_cross*Sun_density*np.sqrt(2))
time_step= 10**-13 # Used this specifically in order for the path length to be < Mean free Path
path_length = (3e8)*time_step
Probability = 1-np.exp(-path_length/Mean_Free) # Probability of the photon colliding
def Random_walk():
x = 0 # Start at origin (0,0)
y = 0
N = 1000
m=0 # This is a counter I have set up for the number of collisions
for i in range(1,N+1):
prand = rng(N+1) # Randomly generated probability
if prand[i] < Probability: # If my prand is less than the probability
# of collision, the photon collides and changes
# direction
x += Mean_Free*np.cos(2*np.pi*prand)
y += Mean_Free*np.sin(2*np.pi*prand)
m += 1 # Everytime a collision occurs 1 is added to my collision counter
distance = np.sqrt(x**2 + y**2) # Final distance the photon covers
if np.all(distance) > Sun_radius: # if the distance the photon travels
break # is greater than the Radius of the Sun,
# the for loop stops, meaning the
#photon escaped
print(m)
return x,y,distance
x,y,d = Random_walk()
plt.plot(x,y, '--')
plt.plot(x[-1], y[-1], 'ro')
Any criticisms of my code are welcome, this is for a grade and I do want to learn how to do this correctly, so please tell me if you notice any other errors.
I don't understand the motivation for the formulas you've implemented. I'll explain my own motivation here, but if your instructor told you to do something else, I guess you should listen to them instead.
If I were going to do this, I would generate a sequence of movements of a photon, stopping when distance of the photon to the center of the sun is greater than the solar radius. Each movement is a sample from a distribution which has two components: one for the distance, and one for the direction. I will assume that these are independent (this may be questioned in a more careful simulation).
It seems plausible that the distribution of distance is an exponential distribution with parameter 1/(mean free path). Then the density is p(d) = (1/MFP) exp(-d/MFP). Its cdf is 1 - exp(-d/MFP) and the inverse of the cdf is -MFP log(1 - p) where p = cdf(d). Now you can sample from the distribution of distances: let p = rand(0, 1) where rand = uniform random and plug it into the inverse cdf to get d. This is called the inverse cdf method of sampling; a web search will find more info about it.
As for the direction, you can let angle = rand(0, 2*pi) and then (x, y) = (cos(angle), sin(angle)).
Now you can construct the series of positions. From an initial location, let the new location = previous + d*(x, y). Stop when distance of location to center is greater than radius.
Looks like a great problem! Good luck and have fun. Let me know if you have any questions.
Here is a way of thinking about the problem that you may find helpful. At each moment, the photon has a position (x, y) and a direction (dx, dy). The (dx, dy) variables are coefficients of the unit vector, so sqrt(dx**2 + dy**2) = 1.0. The distance traveled by the photon during one step is path_length * direction.
At each step you do 4 things:
calculate the photon's new position
figure out if the photon has left the sun by computing its distance from the center point
determine, with a single random number, whether or not the photon collides. If it does you randomly generate a new direction.
Append the photon's current position to a list. You might want to do this as a function of distance from the center rather than x,y.
At the end, you plot the list you have built up.
You should also choose a random direction at the very start.
I don't know how you will terminate the loop, for the photon isn't ever guaranteed to leave the sun - just like in the real world. In principle the program might run forever (or until the sun burns out).
There is a slight inaccuracy in that the photon can collide at any instant, not just at the end of one step. But since the steps are small, so is the error introduced by this simplification.
I will point out that you do not need numpy for any of this except perhaps the final plot. The standard Python library has all the math functions you need. Numpy is of course great for manipulating arrays of data, but the only array you will have here is the one you build, a step at a time, of photon position versus time.
As I pointed out in one of my comments, you are modeling the sun as a 2-dimensional object. If you want to do this calculation in three dimensions, you don't need to change this basic approach.

Difficulties with RA/Dec and Alt/Azi conversions with pyEphem

I'm trying to go from alt/azi to RA/Dec for a point on the sky at a fixed location, trying out pyEphem. I've tried a couple of different ways, and I get sort of the right answer, within a couple of degrees, but I'm expecting better, and I can't figure out where the problems lie.
I've been using Canopus as a test case (I'm not after stars specifically, so I can't use the in-built catalogue). So in my case, I know that at
stn = ephem.Observer()
# yalgoo station, wa
stn.long = '116.6806'
stn.lat = '-28.3403'
stn.elevation = 328.0
stn.pressure = 0 # no refraction correction.
stn.epoch = ephem.J2000
stn.date = '2014/12/15 14:32:09' #UTC
Stellarium, checked with other web sites tell me Canopus should be at
azi, alt '138:53:5.1', '56:09:52.6' or in equatorial RA 6h 23m 57.09s/ Dec. -52deg 41' 44.6"
but trying:
cano = ephem.FixedBody()
cano._ra = '6:23:57.1'
cano._dec = '-52:41:44.0'
cano._epoch = ephem.J2000
cano.compute( stn)
print( cano.az, cano.alt)
>>>(53:22:44.0, 142:08:03.0)
about 3 degrees out. I've also tried the reverse,
ra, dec = stn.radec_of('138:53:5.1', '56:09:52.6')
>>>(6:13:18.52, -49:46:09.5)
where I'm expecting 6:23 not 6:13. Turning on refraction correction makes a small difference, but not enough, and I've always understood aberration and nutation were much smaller effects than this offset as well?
As a follow up, I've tried manual calculations, based on 'Practical Astronomy with your calculator'; so for dec:
LAT = math.radians(-28.340335)
LON = math.radians(116.680621667)
ALT = math.radians(56.16461)
AZ = math.radians(138.88475)
sinDEC = (math.sin( LAT)*math.sin( ALT)
+ math.cos( LAT)*math.cos( ALT)*math.cos( AZ) )
DEC = math.asin( sinDEC)
DEC_deg = math.degrees(DEC)
print( 'dec = ', DEC_deg )
>>>('dec = ', -49.776032754148986)
again, quite different from '56:09:52.6', but reasonably close to pyEphem - so now I'm thoroughly confused! So now I'm suspecting the problem is my understanding, rather than pyEphem - could someone enlighten me about the correct way to go do RADEC/ALTAZI conversions, and why things are not lining up?!
First some notes
Atmospheric scattering and relative speed between observer and object
have the maximal error (near horizon) up to 0.6 degree which is nowhere near your error.
how can altitude be over 90 degrees?
you got swapped data for azimut and altitude
I put your observer data into mine program and result was similar to yours
but I visually search for that star instead of putting the coordinates. Result was also about 3-4 degrees off in RA axis
RA=6.4h Dec=-52.6deg
azi=142.4deg alt=53.9deg
mine engine is in C++, using Kepler's equation
Now what can be wrong:
mine stellar catalog can be wrongly converted
rotated wrongly with some margin but strongly doubt that it is 3 degrees. Also perspective transforms can add some error while rendering at 750AU distance from observer. I never tested for Southern sky (not visible from mine place).
we are using different Earth reference frame then the data you comparing to
I found out that some sites like NASA Horizon use different reference frame which does not correspond with mine observations. Look here
calculate the time when the sun is X degrees below/above the Horizon
at the start of the answer is link to 2 sites with different reference frames when you compare the result they are off. The second link is corresponding with mine observations the rest is dealing (included source code) with Kepler's equation based Solar system simulation. The other sublinks are also worth looking into.
I could have a bug in mine simulation/data
I have referenced data to this engine which could partially hide any computation errors from mine observer position so handle all above text with taken that it mind.
you could use wrong time/Julian date to stellar time conversions
if your time is off then the angles will not match...
How to resolve this?
pick up your Telescope, set up equatoreal coordinate system/mount to it and measure Ra/Dec Azi/Alt for known (distant) object in reality and compare with computed positions. Only this way you can decide which value is good or wrong (for reference frame you are using). Do this on star not planet !!! Do this on high altitude angles not near Horizon !!!
How to transform between azimutal and equatoreal coordinates
I compute transform matrix Eath representing earth's coordinate system (upper right) in heliocentric coordinate system as global coordinate system (left) then I compute another matrix NEH representing observer on Earth's surface (North,East,High/Altitude ... lower right).
After this it is just a matter of matrix and vector multiplications and conversion between Cartesian and spherical coordinate systems look here:
Representing Points on a Circular Radar Math approach
for more insight to azimutal coordinates. if you use just that simple equation like in your example then you do not account for many things... The Earth position is computed by Kepler's equation, rotation is given by daily rotation, nutation and precession included.
I use 64 bit floating point values which can create round errors but not that high ...
I use geometric North Pole as observer reference (this could add some serious error near poles).
The biggest thing that can affect this is the speed of light but that account for near earth 'moving' objects like planets not stars (except Sun) because their computed position is visible after some time ... For example Sun-Earth distance is about 8 light minutes so we see the Sun where it was 8 minutes ago. If the effemerides data is geometrical only (not account for this) then this can lead to high errors if not computed properly.
Newer effemerides models use gravity integration instead of Kepler so their data must be geometrical and the final output is then corrected by the time shift ...

Categories