consistency between attributes (ra,dec) and (hlon, hlat) - pyephem

I just start learning astronomy.
I use pyephem to understand different coordinate systems such as geocentric equtorial,
geocentric ecliptic, heliocentric ecliptic.
In phephem, planet body such as mars has attributes (ra,dec) in geocentric equtorial,
(hlon, hlat) in heliocentric ecliptic. I try to check the consistency between them.
My method(scripts attached below) is as follows:
define function earthtilt to get earth axis tilt
define functions radec2cart and cart2radec to perform coordinate transform
between spherical coordinates and cartesian coordinates.
define function R_x to get rotation matrix.
get geocentric equtorial coordinates of sun/mars using (ra,dec) attributes.
use R_x and earthtilt to rotate geocentric equtorial coordinates to geocentric ecliptic coordinates
(heliocentric ecliptic cartesian coordinates of mars)=
(geocentric ecliptic coordinates of mars) - (geocentric ecliptic coordinates of sun)
change above heliocentric cartesian ecliptic coordinates of mars to
heliocentric spherical ecliptic coordinates of mars.
compare above heliocentric spherical ecliptic coordinates of mars with
mars attributes hlon and hlat.
I got :
difference between ecliptic longitude is about 16.9".
difference between ecliptic latitude is about 9.2".
Such a defference is a little too large.
Is my computation/concept wrong or ...?
===================
import ephem
import numpy as np
import math
def R_x(theta):
return np.array([[1,0,0],[0,math.cos(theta),math.sin(theta)],[0,-math.sin(theta),math.cos(theta)]])
def radec2cart(rho,ra,dec):
return np.array([rho*math.cos(dec)*math.cos(ra),rho*math.cos(dec)*math.sin(ra),rho*math.sin(dec)])
def cart2radec(X):
r=math.sqrt(X[0]*X[0]+X[1]*X[1])
ra=ephem.hours(math.atan2(X[1],X[0])).norm
dec=ephem.degrees(math.atan2(X[2],r))
rho=math.sqrt(X[0]*X[0]+X[1]*X[1]+X[2]*X[2])
return (rho,ra,dec)
def earthtilt(date):
pos=ephem.Ecliptic('90','0',epoch=date)
return pos.to_radec()[1]
def verifyhlonhlat(star,date):
star.compute(date)
sun=ephem.Sun(date)
starx=radec2cart(star.earth_distance,star.g_ra,star.g_dec)
eps=earthtilt(date)
starx=R_x(eps).dot(starx)
sunx=radec2cart(sun.earth_distance,sun.g_ra,sun.g_dec)
sunx=R_x(eps).dot(sunx)
starx=starx-sunx
distance,hlon,hlat=cart2radec(starx)
hlon=ephem.degrees(hlon)
print([distance-star.sun_distance,ephem.degrees(hlon-star.hlon),ephem.degrees(hlat-star.hlat)])
verifyhlonhlat(ephem.Mars(),ephem.Date('2016/6/7'))
===========
>>> verifyhlonhlat(ephem.Mars(),ephem.Date('2016/6/7'))
[1.3654961393161358e-05, -0:00:16.9, 0:00:09.2]

The error is at:
6. (heliocentric ecliptic cartesian coordinates of mars)= (geocentric ecliptic coordinates of mars) - (geocentric ecliptic coordinates of sun)
The reason is as follows:
When we see a planet/star, we look at where planet/star WAS, not where planet/star IS. The difference in time is for light travel from planet/star to earth.

Related

Lunar Librations and Subsolar Point in Matlab

So I have been trying to write a program to generate the latitude and longitude of the lunar subsolar point in Matlab.
I have the ephemeris data from aero toolbox, but I can't seem to get values that make sense.
The method I'm currently trying (without success) is...
Generate a juliandate for a specific time
Find the position of the sun relative to the moon from the ephemeris data for the specified date
Find the (φ, θ, ψ) lunar attitude from the ephemeris data
Create a rotational matrix from the lunar attitude values
Transpose the matrix to get the inverse rotation (to convert the vector from the ICRF frame to the moon's coordinate system)
Apply that rotation to the direction of the sun vector
Convert to spherical coordinates (longitude, latitude)
mission_time = juliandate(2022, 1, 1);
sun_pos = planetEphemeris(mission_time, 'Moon', 'Sun');
moon_rot = moonLibration(mission_time);
rotm = eul2rotm(moon_rot);
rotm = transpose(rotm);
sun_vec = sun_pos / norm(sun_pos);
sun_vec = sun_vec * rotm;
[ss_long, ss_lat] = cart2sph(sun_vec(1), sun_vec(2), sun_vec(3))
fprintf("Subsolar Lat: %2.2f°\tSubsolar Long: %2.2f°\n", rad2deg(ss_long), rad2deg(ss_lat))
The subsolar latitude should be like ±1.57° but this calculation goes all over the place. What am I missing?

How to find the local horizon longitude of the highest point of the ecliptic

I would like to use pyephem or skyfield to find the degree of the local horizon (starting from South = 0°) at which is located the highest point of the ecliptic. Note that I am not trying to find the culmination of a planet. It could well be that, when looking South, there is no planet on the ecliptic by that time/latitude, but there will still be a highest point of the ecliptic. Can anyone help?
While it’s likely that someone will soon jump in with a closed-form solution that uses spherical trigonometry — in which case it’s likely that Skyfield or PyEphem will only be used to determine the Earth orientation — here’s a quick way to get an answer within about a degree:
Generate the ecliptic as 360 points one degree apart across the sky.
Compute the altitude and azimuth of each one.
Choose the highest.
The result agrees closely to what I see if I open Stellarium, turn on the ecliptic, and choose a field star right near the point where the ecliptic reaches the highest point in the sky.
import numpy as np
from skyfield import api, framelib
from skyfield.positionlib import Apparent
𝜏 = api.tau
ts = api.load.timescale()
eph = api.load('de421.bsp')
bluffton = api.Topos('40.74 N', '84.11 W')
t = ts.utc(2021, 2, 16, 22, 52)
angle = np.arange(360) / 360.0 * 𝜏
zero = angle * 0.0
f = framelib.ecliptic_frame
d = api.Distance([np.sin(angle), np.cos(angle), zero])
v = api.Velocity([zero, zero, zero])
p = Apparent.from_time_and_frame_vectors(t, f, d, v)
p.center = bluffton
alt, az, distance = p.altaz()
i = np.argmax(alt.degrees) # Which of the 360 points has highest altitude?
print('Altitude of highest point on ecliptic:', alt.degrees[i])
print('Azimuth of highest point on ecliptic:', az.degrees[i])
The result:
Altitude of highest point on ecliptic: 67.5477569215633
Azimuth of highest point on ecliptic: 163.42529398930515
This is probably a computationally expensive enough approach that it won’t interest you once you or someone else does the spherical trigonometry to find an equation for the azimuth; but at the very least this might provide numbers to check possible formulae against.

Ecliptic coordinates of an Observer in PyEphem

I would like to have the ecliptic coordinates of a point on Earth. I can set up an observer using Pyephem:
station = ephem.Observer()
station.lon = '14:18:40.7'
station.lat = '48:19:14.0'
station.pressure = 0
station.epoch = ephem.J2000
station.elevation = 100.0
Then setup a date
station.date = ephem.date(datetime.utcnow())
But I don't know how to get this point coordinates in the Ecliptic system. If I try the Ecliptic function on the station Object it fails. Is there a way to do that in PyEphem?
If by “the ecliptic coordinates of a point on Earth” you mean “the ecliptic latitude and longitude which are overhead for a point on Earth,” then you might be able to generate a correct position by asking for the RA and declination of the point in the sky directly overhead for the location — where “directly overhead” is expressed astronomically as “at 90° altitude in the sky.” You would follow your code above with something like:
ra, dec = station.radec_of('0', '90')
ec = ephem.Ecliptic(ra, dec)
print 'Ecliptic latitude:', ec.lat
print 'Ecliptic longitude:', ec.lon
Try this technique out and see whether it returns a value anything like what you are expecting!

How to interpolate ECEF coordinates on an WGS84 ellipsoid

Is there a direct method (not involving converting the coordinates to lat/lon) to interpolate between 2 ECEF coordinates (xyz) in order for the interpolated point to be located on the WGS84 ellispoid. The original 2 points are computed from geodetic coordinates.
Interpolating on a sphere seem obvious but I can't seem to derive a solution for the ellipsoid.
Thank you in advance.
Let assume you got 2 points p0(x,y,z) and p1(x,y,z) and want to interpolate some p(t) where t=<0.0,1.0> between the two.
you can:
rescale your ellipsoid to sphere
simply like this:
const double mz=6378137.00000/6356752.31414; // [m] equatoreal/polar radius of Earth
p0.z*=mz;
p1.z*=mz;
now you got Cartesian coordinates refering to spherical Earth model.
interpolate
simple linear interpolation would do
p(t) = p0+(p1-p0)*t
but of coarse you also need to normalize to earth curvature so:
r0 = |p0|
r1 = |p1|
p(t) = p0+(p1-p0)*t
r(t) = r0+(r1-r0)*t
p(t)*=r/|p(t)|
where |p0| means length of vector p0.
rescale back to ellipsoid
by dividing with the same value
p(t).z/=mz
This is simple and cheap but the interpolated path will not have linear time scale.
Here C++ example:
void XYZ_interpolate(double *pt,double *p0,double *p1,double t)
{
const double mz=6378137.00000/6356752.31414;
const double _mz=6356752.31414/6378137.00000;
double p[3],r,r0,r1;
// compute spherical radiuses of input points
r0=sqrt((p0[0]*p0[0])+(p0[1]*p0[1])+(p0[2]*p0[2]*mz*mz));
r1=sqrt((p1[0]*p1[0])+(p1[1]*p1[1])+(p1[2]*p1[2]*mz*mz));
// linear interpolation
r = r0 +(r1 -r0 )*t;
p[0]= p0[0]+(p1[0]-p0[0])*t;
p[1]= p0[1]+(p1[1]-p0[1])*t;
p[2]=(p0[2]+(p1[2]-p0[2])*t)*mz;
// correct radius and rescale back
r/=sqrt((p[0]*p[0])+(p[1]*p[1])+(p[2]*p[2]));
pt[0]=p[0]*r;
pt[1]=p[1]*r;
pt[2]=p[2]*r*_mz;
}
And preview:
Yellow squares are the used p0,p1 Cartesian coordinates, the White curve is the interpolated path where t=<0.0,1.0> ...

Draw circle using latitude and longitude

I want to plot a latitude and longitude using matlab. Using that latitude and longitude as center of the circle, I want to plot a circle of radius 5 Nm.
r = 5/60;
nseg = 100;
x = 25.01;
y = 55.01;
theta = 0 : (2 * pi / nseg) : (2 * pi);
pline_x = r * cos(theta) + x;
pline_y = r * sin(theta) + y;
hold all
geoshow(pline_x, pline_y)
geoshow(x, y)
The circle does not look of what I expected.
Drawing a circle on earth is more complex that it looks like.
Drawing a line or a poly line is simple, because the vertices are defined.
Not so on circle.
a circle is defined by all points having the same distance from center (in meters! not in degrees!!!)
Unfortuantley lat and lon coordinates have not the same scale.
(The distance between two degrees of latidtude is always approx. 111.3 km, while for longitude this is only true at the equator. At the poles the distance between two longitudes approach zero. In Europe the factor is about 0.6. (cos(48deg))
There are two solution, the first is more universal, usefull for nearly all problems.
convert spherical coordinate (of circle center) to cartesian plane with unit = 1m, using a transformation (e.g equidistant transformation, also called equirectangular transf., this transformation works with the cos(centerLat) compensation factor)
calculate points (e.g circle points) in x,y plane using school mathematics.
transform all (x,y) points back to spherical (lat, lon) coordinates, using the inverse transformation of point 1.
Other solution
1. write a function which draws an ellipse in defined rectangle (all cartesian x,y)
2. define bounding of the circle to draw:
2a: calculate north-south diameter of circle/ in degrees: this a bit tricky: the distance is define in meters, you need a transformation to get the latitudeSpan: one degrees of lat is approx 111.3 km (eart circumence / 360.0): With this meters_per_degree value calc the N-S disatcne in degrees.
2b: calculate E-W span in degrees: now more tricky: calculate like 2a, but now divide by cos(centerLatitude) to compensate that E-W distances need more degrees when moving north to have the same meters.
Now draw ellipseInRectangle using N-S and E_W span for heigh and width.
But a circle on a sphere looks on the projected monitor display (or paper) only like a circle in the center of the projection. This shows:
Tissot's Error Ellipse