With pyephem I can take orbital elements from the Minor Planet Center and add them into a ephem.EllipticalBody().
To plot the orbit I've been getting the computing the sun distance, heliocentric latitiude and longitude over a the period of the orbit and plotting that:
dt = body._epoch
period = (sqrt(a**3))
timespace = np.linspace(dt-((period*365)/2),
dt+((period*365)/2), 720)
theta_e = []
r_e = []
phi_e = []
for t in timespace:
body.compute(t)
theta_e.append(body.hlon)
phi_e.append(body.hlat)
r_e.append(body.sun_distance)
subplot = figure(figsize=(20, 20)).add_subplot(111, polar=True)
subplot.scatter(theta_e, r_e*cos(phi_e), s=0.5)
This approch works ok for minor planets that have short periods (a few years). However when I go to the extreme and plot say Sedna I get:
http://i.stack.imgur.com/wxRCW.png
So it looks as though pyephem is being clever and taking apsidal precession into account. Which isn't something I need for this.
Any suggestions so on how I can plot the orbit from the orbital elements or what I'm doing wrong here? Ideally I'll like to be able to do plots from different 'views' to show the inclination as well as eccentricity or perhaps a live mayavi scene.
I suspect that the phenomenon here is not apsidal precession, because the libastro library beneath PyEphem uses simple Keplerian orbits when given elliptical coordinates.
Instead, my guess is that you are seeing the Earth’s polar precession, which is moving the heliocentric latitude and longitude system out from under you as you are trying to plot. For most objects the effect is negligible, but an 11,000-year orbit is enough time for the Earth’s pole to make it a good bit of the way around the sky.
The only coordinates that libastro produces that are likely to be immune to the effect (assuming that a compute(…, epoch=J2000) does not make the heliocentric longitude stable?) are the a_ra and a_dec coordinates, so you might have to pull those for both the Sun and Sedna, convert them into vectors, and subtract.
Related
I would like to write a program for plotting an animated 3D ribbon image in python. The ribbon follows the flight path as provided by a log containing the following information:
Timestamp, pitch, roll, altitude, latitude, longitude, heading, turn rate.
The final figure should look something like this (without the aircraft figure).
Aircraft manoeuvres:
Please let me know how this can be done.
Edit:
Heading is the angle between the flight and the north direction. It is a scalar quantity measured in degrees.
Turn rate is rate of change of heading.
Pitch is up/down rotation and roll is rotation given by rolling over on either side. They are measured in degrees.
Below is a sample of the data:
Time: 801.475 alt (ft): 12599.88668 lat(deg): 63.94230675 lon(deg): -22.72656178 pitch(deg): 39.60080719 roll(deg): 40.49394608 heading(deg): 344.7094606 turnspeed: 8.104816363
These are all from the inertial frame of reference, which can also serve as axes for this plot.
Thank you
This is not a complete answer.
First, you need to convert your data to x,y,z coordinates.
let's say that you use feet, then you have to convert latitude and longitude to x,y.
It will not work if the plane moved a long distance, because the earth is not flat.
Your pitch, roll and heading data serves to calculate the (x,y,z) coordinates of the tips of the wings (or the border of the ribbon) relative to the (x,y,z) of the center of the plane.
You need quaternions or geometric algebra to do that. You can also do it with basic trigonometry, but you risk gimbal lock bugs.
Then you need to interpolate your data, for the timestep you choose.
With your interpolated data, you get 2 arrays of (x,y,z) for each ribbon border, which you can plot as lines in 3D.
To do the plot you need to choose a position of the viewer, and a direction to which he is looking at.
If you want to do an animation, you use the same data, but google how to do animations after you managed to do the interpolations.
When the position of the plane at the time t, t+1 is
position[t] =[x,y,z]
position[t+1]=[x1,y1,z1]
the direction at which the plane is moving is
velocity[t+1/2]=position[t+1]-position[t]=[x1-x,y1-y,z1-z]/(t+1/2-t)
From the Position[t], you have to calculate the position of the right wing tip WR[t], and left wing tip WL[t], which are the [x,y,z] coordinates of the ribbons at the time t
Now, following this convention from Wikipedia
If we conjecture that the viewer is looking at the North, X is positive towards East, Y is positive towards the North, and Z is positive away from the center of earth (That depends on how did you converted latitude/longitude to x,y)
-If the length of a wing is L, then the coordinate of the rigth wing tip, relative to the center of the plane Position[t], would be [L,0,0], when the plane is leveled, aiming at the North.
At the time t the right wing tip WR[t] shold be at coordinates:
WR[t] = Position[t] + RotateVectorByRoll(RotateVectorByPitch(RotateVectorByHeading([L,0,0], Θh), ΘP), ΘR)
So I have two different datasets. I have one that is a polar orbiting satellite that starts near the north pole goes down towards Africa then goes over the south pole and back up the Atlantic ocean. I also have a Global composite of a number of Geostationary satellites. That grid is a full global coverage from -90 to 90 latitude, and 0 to -0.2 (around the dateline) longitudes.
So when I plot my polar orbiting data. I get a funny striping across the northern hemisphere where the satellite crosses the dateline. Like this...
polar orbiting data
I did a search and found that if I do this to my longitude values
lons[lons < 0] += 360
that it then removes the strange striping. I think it actually just moves the stripes to the southern hemisphere (where is crosses the meridian), but since that area is all "missing" values it doesn't show on the plot, so I don't care.
polar orbiting data - longitudes all positive
So now there is the problem of the full Global dataset. When I plot it without converting all the longitudes to positive values, it has quite a few stripes going on. I believe it is every place there is rain that crosses the dateline.
Global dataset
When I try to apply the "fix" that worked for the polar data I get a really nasty very uninformative error.
IllegalArgumentException: Invalid number of points in LinearRing found 3 - must be 0 or >= 4
Process finished with exit code 139 (interrupted by signal 11: SIGSEGV)
There is no traceback or anything, so I'm not even sure if it is matplotlib or cartopy or what that is throwing the error.
I've tried cropping the image by using set_extent() but it still has the stripes.
Any ideas how to fix this, or how to trick matplotlib/cartopy into plotting the data correctly?
Adding code, but not sure how much it will actually be of help. It is pretty basic. The issue is more with the fact that the rain data covers the full globe.
normal_proj = ccrs.PlateCarree(central_longitude=0)
pos_lons = lon_data.copy()
pos_lons[pos_lons < 0] += 360
cs = plt.contourf(pos_lons, lat_data, rr_data, clevs, cmap=cmap,
transform=normal_proj, norm=norm)
I think you're running into an annoying, but difficult to track down bug in CartoPy. Basically, in transforming the contours and clipping them to the map extent it generates some Shapely geometries incorrectly. Some things that have worked to get around the problem (not solve it) include slightly adjusting the map boundaries and adjusting the contour levels.
I'm looking to create AI that elegantly rounds corners. To compute the path around a corner I have a set of 2d points start and end that exist exclusively as 90 degree angle pairs like in the image below.
Each point is either in the "north", "south", "east", or "west" most portion of the ellipse, and I can extrapolate the a and b values for the major and minor axes of the ellipse along these points.
The simulation is played on a grid, so the ellipse will never be rotated -- the major and minor axes will lie parallel to the x and y axes.
Moving the point along an ellipse by an angle is simple:
x = x + (a * math.cos(angle)) # where a is major axis
y = y + (b * math.cos(angle)) # where b is minor axis
However, I want to control the speed at which the AI traverses across the arc on the ellipse between the two points and eventually have them stop at the end position.
Ultimately, I need to compute the following:
The remaining_distance between start and end along the ellipse
The new location of a point after moving distance across the ellipse
Questions:
Are there common tools/solutions for computing the above?
Are there better or more common solutions for this problem in AI, gamedev, or other practices? I saw Bezier curves came up in my search, for example.
Thanks!
Meta:
I found similar questions asking for this problem on the stack exchange, but none really seemed to fit my use case or answered the question by offering language-specific non-python solutions.
I chose to ask here rather than the mathematics stack exchange, because I imagine there may be other solutions for the same problem more commonplace in gamedev and other programming projects.
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 ...
I've been tasked with writing a python based plugin for a graph drawing program that generates an STL model of a graph. A graph being an object made up of vertices and edges, where a vertex is represented by a 3D ball (a tessellated icosahedron), and an edge is represented with a cylinder that connects with two balls at either end. The end result of the 3D model is that it will get dumped out to an STL file for 3D printing. I'm able to generate the 3D models for the balls and cylinders without any issues, but I'm having some issues generating the overall model, and getting the balls and cylinders to connect properly.
My original idea was to create tessellated icosahedrons at the origin, then translate them out to the positions of the vertices. This works fine. I then, for each edge, I would create a cylinder at the origin, rotate it to the correct angle so that it points in the correct direction, then translate it to the midpoint between the two vertices so that the ends of the cylinders are embedded in the icosahedrons. This is where things are going wrong. I'm having some difficulties getting the rotations correct. To calculate the rotations, I'm doing the following:
First, I find the angle between the two points as follows (where source and target are both vertices in the graph, belonging to the edge that I'm currently processing):
deltaX = source.x - target.x
deltaY = source.y - target.y
deltaZ = source.z - target.z
xyAngle = math.atan2(deltaX, deltaY)
xzAngle = math.atan2(deltaX, deltaZ)
yzAngle = math.atan2(deltaY, deltaZ)
The angles being calculated seem reasonable, and as far as I can tell, do actually represent the angle between the vertices. For example, if I have a vertex at (1, 1, 0) and another vertex at (3, 3, 0), the angle edge connecting them does show up as a 45 degree angle between the two vertices. (That, or -135 degrees, depending which vertex is the source and which is the target).
Once I have the angles calculated, I create a cylinder and rotate it by the angles that have been calculated, like so, using some other classes that I've created:
c = cylinder()
c.createCylinder(edgeThickness, edgeLength)
c.rotateX(-yzAngle)
c.rotateY(xzAngle)
c.rotateZ(-xyAngle)
c.translate(edgePosition.x, edgePosition.y, edgePosition.z)
(Where edgePosition is the midpoint between the two vertices in the graph, edgeThickness is the radius of the cylinder being created, and edgeLength is the distance between the two vertices).
As mentioned, its the rotating of the cylinders that doesn't work as expected. It seems to do the correct rotation on the x/y plane, but as soon as an edge has vertices that differ in all three components (x, y, and z), the rotation fails. Here's an example of a graph that differs in the x, and y components, but not in the z component:
And here's the resulting STL file, as seen in Makerware (which is used to send the 3D models to the 3D printer):
(The extra cylinder looking bit in the bottom left is something I've currently left in for testing purposes - a cylinder that points in the direction of the z axis, located at the origin).
If I take that same graph and move the middle vertex out in the z axis, so now all the edges involve angles in all three axis, I get a result something like the following:
As show in the app:
The resulting STL file, as show in Makerware:
...and that same model as viewed from the side:
As you can see, the cylinders definitely aren't meeting up with the balls like I thought they would. My question is this: Is my approach to doing this flawed, or is it some small but critical mistake that I'm making somewhere in my rotations? I'm pretty sure it isn't a problem with the rotation functions themselves, as I've been able to independently verify that they work as expected. I also tried creating a rotate function that takes in a yaw, pitch, and roll and does all three at once, and it seemed to generate the same result, like so:
c.rotateYawPitchRoll(xzAngle, -yzAngle, -xyAngle)
So... anyone have any ideas on what I might be doing wrong?
UPDATE: As joojaa pointed out, it was a combination of calculating the correct angles as well as the order that they were applied. In order to get things working, I first calculate the rotation on the x axis, as follows:
zyAngle = math.atan2(deltaVector.z, deltaVector.y)
where deltaVector is the difference between the target and source vectors. This rotation is not yet applied though! The next step is to calculate the rotation on the y axis, as follows:
angle = vector.angleBetweenVectors(vector(target.x - source.x, target.y - source.y, target.z - source.z), vector(target.x - source.x, target.y - source.y, 0.0))
Once both rotations are calculated, they are then applied... in the reverse order! First, the x, then the y:
c.rotateY(angle)
c.rotateX(-zyAngle) #... where c is a cylinder object
There still seems to be a few bugs, but this seems to at least work for a simple test case.
Rotation happens in successive order, so the angles affect each other. It is not possible to use a Euler model to rotate them at once. This is why you can not just calculate the rotations based on the first static situation. Just imagine turning a cube so that it is standing on its corner upright. Yes the first rotation is 45 but the second is not since the cube is already turned by that time (draw a each step of the sequence and see what happens). Space rotations aren't trivial.
So you need to rotate one angle then re calculate the second angle and so forth. This is also why your first rotation works right. You only need 2 rotations unless your interested in making sure the rotation around the shaft has a certain direction.
I would suggest you use axis angles or matrices instead to do this. Mainly because in axis angles this is trivial the angle is the dot between the along tube start and end vectors and the axis is the cross between those 2. You can then convert those to Euler angles if you need. But probably you can just use the matrix directly. For ideas on how conversions and how the rotation could directly be calculated see: transformations.py by Christoph Gohlke. Also see the accompanying c source.
I think i need to expand this answer a bit
There is a really easy way out for this question that sidesteps all your and many other persons problems. The answer is do not use Euler angle rotation. Ive used a lot of brainpower to try to explain Euler rotations to problems that are ultimately solved more easily without Euler rotations. To justify i will leave just one reason for this if you want more think up of some more answers.
The reason most to use Euler rotation sequences is that you probably don't understand Euler angles. There are in fact only a handful of situations where they are good. No self respecting programmer uses Euler rotations to solve this issue. What you do is you use vector math instead.
So you have the direction vector from the source to target which is usually calculated:
along = normalize(target-source)
this is simply one of your matrix rows (or column notation is up to model maker), the one that corresponds to your cylinders original direction (the rows are just x y z w), then you need another vector perpendicular to this one. Choose a arbitrary vector like up (or left if your along is pointing close to up). cross product this up vector by your along for the second row direction. and finally put your source as the last row with 1 in the last column. Done fully formed affine matrix describing the cylinders prition. Much easier to understand since you can draw the vectors.
There are shorter ways but this one is easy to understand.