Skyfield topocentric to ICRS transformation. Is there anything like SOFA / ERFA atic13? - transformation

I'm currently working on astronomy mount support tool. This need to transform coordinates between JNow and J2000. I've don this using the ERFA implementation in the SOFA library, which is also present in astropy. As I starting in looking after Skyfield for satellite tracking, I want to reduce the number of libraries used.
Actually the transformation from J2000 (or ICRS) to JNow (Topocentric) could be done on ERFA with "atic13" routine:
rc, dc, eo = self.ERFA.atic13(self.ERFA.anp(ra * self.ERFA.D2PI /24 + self.ERFA.eo06a(jdtt, 0.0)),
dec * self.ERFA.D2PI / 360,
<topo julian date>,
0.0)
val1 = rc * 24.0 / self.ERFA.D2PI
val2 = dc * self.ERFA.DR2D
The same way of doing that on Skyfield is
result = earth.at(<topo julian date>).observe(<coordinates>).apparent()
and I could access the coordinates from the result. Now what made me sad, because I might have on the wrong path, I would do it the other way round. So in ERFA it is simply:
ri, di, eo = self.ERFA.atci13(ra * self.ERFA.D2PI / 24,
dec * self.ERFA.D2PI / 360,
0,
0,
0,
0,
<topo julian date>,
0)
val1 = self.ERFA.anp(ri - eo) * 24 / self.ERFA.D2PI
val2 = di * 360 / self.ERFA.D2PI
but I don't find the right way with Skyfield. If somebody could direct me in the right way, this would be very helpful. I'm actually using the newest one (1.6)
Michel

Skyfield does not, alas, currently implement iterative approximations to the inverses of aberration and light deflection — it can only apply them in the usual, forward direction. By contrast, the ERFA routine you reference does indeed reverse them:
“Iterative techniques are used for the aberration and light deflection corrections so that the functions eraAtic13 (or eraAticq) and eraAtci13 (or eraAtciq) are accurate inverses; even at the edge of the Sun's disk the discrepancy is only about 1 nanoarcsecond.”
— https://juliaastro.github.io/ERFA.jl/v0.4/api.html#ERFA.atic13-NTuple{4,Any}
You will want to keep using AstroPy for that transform.

Related

Generate 12 (perceptually) uniformly-spaced colours using d3

This question follows from https://stackoverflow.com/questions/29589186/generating-a-perceptually-accurate-colour-wheel-in-javascript
I'm trying to create 12 colours that are roughly uniformly spaced from one another perceptually.
d3 provides HSL, so d3.hsl( (i/12)*360, 0.5, 0.5 )
However, this doesn't work very well for greeny-yellowy colours.
d3 appears to provide HCL and LAB, but I can't see how to use these.
Is there any mathematical approach I can use, or should I just implement my own HSL hue transfer function?
I am not familiar with d3, but assume it uses the typical CIELab convention which is L: 0::255, a: -100::100, b: -100::100
You can try
d3.lab( 128, 100 * Math.sin(2 * Math.PI * i/12), 100 * Math.cos(2 * Math.PI * i/12) )
This should create a visually uniform color wheel

Algorithm to control acceleration until a position is reached

I have a point that moves (in one dimension), and I need it to move smoothly. So I think that it's velocity has to be a continuous function and I need to control the acceleration and then calculate it's velocity and position.
The algorithm doesn't seem something obvious to me, but I guess this must be a common problem, I just can't find the solution.
Notes:
The final destination of the object may change while it's moving and the movement needs to be smooth anyway.
I guess that a naive implementation would produce bouncing, and I need to avoid that.
This is a perfect candidate for using a "critically damped spring".
Conceptually you attach the point to the target point with a spring, or piece of elastic. The spring is damped so that you get no 'bouncing'. You can control how fast the system reacts by changing a constant called the "SpringConstant". This is essentially how strong the piece of elastic is.
Basically you apply two forces to the position, then integrate this over time. The first force is that applied by the spring, Fs = SpringConstant * DistanceToTarget. The second is the damping force, Fd = -CurrentVelocity * 2 * sqrt( SpringConstant ).
The CurrentVelocity forms part of the state of the system, and can be initialised to zero.
In each step, you multiply the sum of these two forces by the time step. This gives you the change of the value of the CurrentVelocity. Multiply this by the time step again and it will give you the displacement.
We add this to the actual position of the point.
In C++ code:
float CriticallyDampedSpring( float a_Target,
float a_Current,
float & a_Velocity,
float a_TimeStep )
{
float currentToTarget = a_Target - a_Current;
float springForce = currentToTarget * SPRING_CONSTANT;
float dampingForce = -a_Velocity * 2 * sqrt( SPRING_CONSTANT );
float force = springForce + dampingForce;
a_Velocity += force * a_TimeStep;
float displacement = a_Velocity * a_TimeStep;
return a_Current + displacement;
}
In systems I was working with a value of around 5 was a good point to start experimenting with the value of the spring constant. Set it too high will result in too fast a reaction, and too low the point will react too slowly.
Note, you might be best to make a class that keeps the velocity state rather than have to pass it into the function over and over.
I hope this is helpful, good luck :)
EDIT: In case it's useful for others, it's easy to apply this to 2 or 3 dimensions. In this case you can just apply the CriticallyDampedSpring independently once for each dimension. Depending on the motion you want you might find it better to work in polar coordinates (for 2D), or spherical coordinates (for 3D).
I'd do something like Alex Deem's answer for trajectory planning, but with limits on force and velocity:
In pseudocode:
xtarget: target position
vtarget: target velocity*
x: object position
v: object velocity
dt: timestep
F = Ki * (xtarget-x) + Kp * (vtarget-v);
F = clipMagnitude(F, Fmax);
v = v + F * dt;
v = clipMagnitude(v, vmax);
x = x + v * dt;
clipMagnitude(y, ymax):
r = magnitude(y) / ymax
if (r <= 1)
return y;
else
return y * (1/r);
where Ki and Kp are tuning constants, Fmax and vmax are maximum force and velocity. This should work for 1-D, 2-D, or 3-D situations (magnitude(y) = abs(y) in 1-D, otherwise use vector magnitude).
It's not quite clear exactly what you're after, but I'm going to assume the following:
There is some maximum acceleration;
You want the object to have stopped moving when it reaches the destination;
Unlike velocity, you do not require acceleration to be continuous.
Let A be the maximum acceleration (by which I mean the acceleration is always between -A and A).
The equation you want is
v_f^2 = v_i^2 + 2 a d
where v_f = 0 is the final velocity, v_i is the initial (current) velocity, and d is the distance to the destination (when you switch from acceleration A to acceleration -A -- that is, from speeding up to slowing down; here I'm assuming d is positive).
Solving:
d = v_i^2 / (2A)
is the distance. (The negatives cancel).
If the current distance remaining is greater than d, speed up as quickly as possible. Otherwise, begin slowing down.
Let's say you update the object's position every t_step seconds. Then:
new_position = old_position + old_velocity * t_step + (1/2)a(t_step)^2
new_velocity = old_velocity + a * t_step.
If the destination is between new_position and old_position (i.e., the object reached its destination in between updates), simply set new_position = destination.
You need an easing formula, which you would call at a set interval, passing in the time elapsed, start point, end point and duration you want the animation to be.
Doing time-based calculations will account for slow clients and other random hiccups. Since it calculates on time elapsed vs. the time in which it has to compkete, it will account for slow intervals between calls when returning how far along your point should be in the animation.
The jquery.easing plugin has a ton of easing functions you can look at:
http://gsgd.co.uk/sandbox/jquery/easing/
I've found it best to pass in 0 and 1 as my start and end point, since it will return a floating point between the two, you can easily apply it to the real value you are modifying using multiplication.

How can I transform latitude and longitude to x,y in Java?

I am working on a geographic project in Java.
The input are coordinates : 24.4444 N etc
Output: a PLAIN map (not round) showing the point of the coordinates.
I don't know the algorithm to transform from coordinates to x,y on a JComponent, can somebody help me?
The map looks like this:
http://upload.wikimedia.org/wikipedia/commons/7/74/Mercator-projection.jpg
Thank you
Given your sparse example, the range of your inputs will be (90.0N - 90.0S) and (180W - 180E). It is easiest - and standard - if you convert South and West to negatives giving you latitudes of (90.0..-90.0) and longitudes of (180.0..-180.0).
Given the size of your canvas - let's say it is 140x120 pixels - you get:
x = (latitude * canvas_height / 180.0) + (canvas_height / 2)
y = (longitude * canvas_width / 360.0) + (canvas_width / 2)
or:
x = (longitude * 120.0 / 180.0) + (120/2)
y = (latitude * 140.0 / 360.0) + (140/2)
where I have ordered the operations to minimize rounding error. This assumes the canvas has point (0,0) in the upper-left or, if not, that you are Australian.
Added: you just threw in the bit about Mercator projections making my simple answer incorrect (but possibly still usable by you if you don't actually care about projection)
MSW provided a good example. Ultimately the algorithm depends on the map projection used. Here are a couple of good resources I used in the past.
The following link is a good reference to a number of different map projections with enough math formulas to choke a horse.
http://www.remotesensing.org/geotiff/proj_list/
Here is a decent reference for doing this in PhP. While not Java, it should be straight forward enough to apply the principles outlined.
http://www.web-max.ca/PHP/article_1.php

Spatial Rotation in Gmod Expression2

I'm using expression2 to program behavior in Garry's mod. Expression2 (archive link)
Okay so, to set the precedent. In Gmod I have a block and I am at a complete loss of how to get it to rotate around the 3 up, down and right vectors (Which are local. ie; if I pitch it 45 degrees the forward vector is 0.707, 0.707, 0). Essentially, From the 3 vectors I'd like to be able to get local Pitch/Roll/Yaw. By Local Pitch Roll Yaw I mean that they are completely independent of one another allowing true 3d rotation. So for example; if I place my craft so its nose is parallel to the floor the X,Y,Z would be 0,0,0. If I turn it parallel to the floor (World and Local Yaw) 90 degrees it's now 0, 0, 90. If I then pitch it (World Roll, Local Pitch) it 180 degrees it's now 180, 0, 90. I've already explored quaternions however I don't believe I should post my code here as I think I was re-inventing the wheel.
I know I didn't explain that well but I believe the problem is pretty generic. Any help anyone could offer is greatly appreciated.
Oh, I'd like to avoid gimblelock too.
Essentially calculating the rotation around each of the crafts up/forward/right vectors using the up/forward/right vectors.
To simply the question a generic implementation rather than one specific to Gmod is absolutely fine.
I'm not sure what the application you are looking forward to implementing, however, in this sort of situation, I would usually suggest applying angular force. Would that be sufficient for your needs in this regard?
Well if that is all that you need, then i have managed to perfect the angular force equation to having entities point at a given position.
EntityVector = Entity:massCenter()
Leverage = sqrt( ( Entity:inertia():length()^2 ) / 3 )
LookPos = EntityVector - Target:pos()
A = ang(
toDeg( atanr( LookPos:z() , sqrt( LookPos:x()^2 + LookPos:y()^2) ) ) ,
toDeg( atanr( -LookPos:y(), -LookPos:x() ) ) ,
0 )
EntityAngle = ( ( Entity:angles() - angnorm(A) ) * 5 + Entity:angVel() ) * 5
Entity:applyAngForce( -EntityAngle * Leverage )
This set of equations has helped me through countless projects

How can I do efficient range searching + counting with latitude/longitude data?

I'm working with a large set of points represented by latitude/longitude pairs (the points are not necessarily unique, there could be several points in the set that are at the same location). The points are stored in a database.
What I need to do is figure out a way to efficiently perform a search to get the number of points that lie within a given radius (say, 25 miles) of an arbitrary point.
The count does not need to be 100% accurate - more importantly, it just has to be fast, and reasonably close to the correct count. Doing this with SQL is possible, by using a query with some trigonometry in the WHERE clause to filter points by their distance to a reference point. Unfortunately, this query is very, very expensive and caching is not likely to provide much help because the locations will be very spread out.
I'm ultimately looking to build some kind of in-memory structure that will be able to handle this kind of operation efficiently - trading off some of the accuracy and liveness of the data (maybe rebuilding it only once a day) in return for speed. I've been doing some research on kd-trees, but i'm not clear yet on how well this can be applied to latitude/longitude data (as opposed to x,y data in a 2d plane).
If anybody has any ideas or solutions I should look into, I'd really appreciate it - so thanks in advance.
I don't think you should use this solution. Having randomly thought about it a few days ago, I think that measuring the distance from a specific point the grid squares' locations will be based on circles rather than a uniformed grid. The further away from 0,0 you are the less accurate this will be!
What I did was to have 2 additional values on my PostalCode class. Whenever I update the Long/Lat on a PostalCode I calculate an X,Y distance from Long 0, Lat 0.
public static class MathExtender
{
public static double GetDistanceBetweenPoints(double sourceLatitude, double sourceLongitude, double destLatitude, double destLongitude)
{
double theta = sourceLongitude - destLongitude;
double distance =
Math.Sin(DegToRad(sourceLatitude))
* Math.Sin(DegToRad(destLatitude))
+ Math.Cos(DegToRad(sourceLatitude))
* Math.Cos(DegToRad(destLatitude))
* Math.Cos(DegToRad(theta));
distance = Math.Acos(distance);
distance = RadToDeg(distance);
distance = distance * 60 * 1.1515;
return (distance);
}
public static double DegToRad(double degrees)
{
return (degrees * Math.PI / 180.0);
}
public static double RadToDeg(double radians)
{
return (radians / Math.PI * 180.0);
}
}
Then I update my class like so:
private void CalculateGridReference()
{
GridReferenceX = MathExtender.GetDistanceBetweenPoints(0, 0, 0, Longitude);
GridReferenceY = MathExtender.GetDistanceBetweenPoints(0, 0, Latitude, 0);
}
So now I have an x,y grid distance (in miles) from grid reference 0,0 for each row in my DB. If I want to find all places with 5 miles of a long/lat I would first get the X,Y grid reference (say 25,75) then I would search 20..30, 70..80 in the DB, and further filter the results in memory using
MathExtensder.GetDistanceBetweenPoints(candidate.Lat, candidate.Long, search.Lat, search.Long) < TheRadiusOfInterest
The in DB part is ultra fast, and the in-memory part works on a smaller set to make it ultra accurate.
Use R-Trees.
In Oracle, using Oracle Spatial, you can create an index:
CREATE INDEX ix_spatial ON spatial_table (locations) INDEXTYPE IS MDSYS.SPATIAL_INDEX;
that will create an R-Tree for you and search over it.
You may use any Earth Model you like: WGS84, PZ-90 etc.
Use some kind of search tree for spatial data, e.g. a quad tree. More such data structures are referenced under "See also".
This UDF (SQL Server) will get you the distance between two lat/lon points:
CREATE FUNCTION [dbo].[zipDistance] (
#Lat1 decimal(11, 6),
#Lon1 decimal(11, 6),
#Lat2 decimal(11, 6),
#Lon2 decimal(11, 6)
)
RETURNS
decimal(11, 6) AS
BEGIN
IF #Lat1 = #Lat2 AND #Lon1 = #Lon2
RETURN 0 /* same lat/long points, 0 distance = */
DECLARE #x decimal(18,13)
SET #x = 0.0
/* degrees -> radians */
SET #Lat1 = #Lat1 * PI() / 180
SET #Lon1 = #Lon1 * PI() / 180
SET #Lat2 = #Lat2 * PI() / 180
SET #Lon2 = #Lon2 * PI() / 180
/* accurate to +/- 30 feet */
SET #x = Sin(#Lat1) * Sin(#Lat2) + Cos(#Lat1) * Cos(#Lat2) * Cos(#Lon2 - #Lon1)
IF 1 = #x
RETURN 0
DECLARE #EarthRad decimal(5,1)
SET #EarthRad = 3963.1
RETURN #EarthRadius * (-1 * ATAN(#x / SQRT(1 - #x * #x)) + PI() / 2)
END
And, obviously, you can use this in a separate query, such as:
SELECT * FROM table WHERE [dbo].[zipDistance] < 25.0
You can find an excellent explaination of Bombe's suggestion in the Jan Philip Matuschek's article "Finding Points Within a Distance of a Latitude/Longitude Using Bounding Coordinates".
Could you maybe supply a sample of your existing expensive query?
If you're doing proper great-circle calculation based on taking the sine() and cosine() of the reference point and the other data points, then a very substantial optimisation could be made by actually storing those sin/cos values in the database in addition to the lat/long values.
Alternatively, just use your database to extract a rectangle of lat/long ranges that match, and only afterwards filter out the ones that are outside the true circular radius.
But do bear in mind that one degree of longitude is a somewhat shorter distance at high latitudes than at the equator. It should be easy to figure out the right aspect ratio for that rectangle, though. You'd also have errors if you need to consider areas very close to the poles, as a rectanglar selection wouldn't cope with a circle that overlapped a pole.

Resources