-
Notifications
You must be signed in to change notification settings - Fork 0
/
convert_ra_dec_to_alt_az.html
250 lines (211 loc) · 9.45 KB
/
convert_ra_dec_to_alt_az.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
<!DOCTYPE html>
<html>
<head>
<title>Convert RA/DEC to Alt/Az</title>
<link rel="stylesheet" href="default.css">
<link rel="stylesheet" href="highlight/styles/default.css">
<meta name="viewport" content="width=device-width, initial-scale=1" />
<style>
.algorithmdiv{
border: solid;
display: inline-block;
padding: 10px;
margin: 10px;
}
</style>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/katex.min.css" integrity="sha384-Um5gpz1odJg5Z4HAmzPtgZKdTBHZdw8S29IecapCSB31ligYPhHQZMIlWLYQGVoc" crossorigin="anonymous">
<script defer src="https://cdn.jsdelivr.net/npm/[email protected]/dist/katex.min.js" integrity="sha384-YNHdsYkH6gMx9y3mRkmcJ2mFUjTd0qNQQvY9VYZgQd7DcN7env35GzlmFaZ23JGp" crossorigin="anonymous"></script>
<script defer src="https://cdn.jsdelivr.net/npm/[email protected]/dist/contrib/auto-render.min.js" integrity="sha384-vZTG03m+2yp6N6BNi5iM4rW4oIwk5DfcNdFfxkk9ZWpDriOkXX8voJBFrAO7MpVl" crossorigin="anonymous"
onload="renderMathInElement(document.body);"></script>
</head>
<body>
<h1>Convert RA/DEC to Alt/Az</h1>
<p>Converts a RA/DEC (J2000) coordinate to approximate Alt/Az (J2000) coordinate. This uses Greenwich <b>Mean</b> Sidereal Time to compute the approximate horizon coordiates, if you need
the coordiates also corrected for nutation, you will need to modify this to use Greenwhich <b>Apparent</b> Sidereal Time. It is assumed that all corrections the user has
interest in have already been applied to the RA/Dec coordinates.</p>
<p>
You will likely come across different sets of equations for the RA/Dec to Alt/Az conversion. I have included three below
from three different sources. The first is derived from spherical trigonometry and is from the Explanatory Supplement to
the Astronomical Almanac 3rd ed. The second is from Astronomical Algorithms, using this in combination with the atan2 function
included in most programming languages, is usually the easiest to implement. And the last is a matrix form, which is useful
if you already have your coordinates in matrix form, or want to generalize the transformations.
</p>
<p>
The matrix form is likely the most useful for most applications since you will likely need to perform the conversion to
rectagular coordinates for other purposes. But, if you need to provide both the RA/Dec and Alt/Az coordinates, Meuus' method
will save you a few steps.
</p>
This implementation uses the Astronomical Algorithms set, but an implementation of the other
is available in the set of <a href="radec_to_altaz_testtdata.html">test data</a> which validates both sets of equations, and can be used as an example of how to implement the Explanatory
Supplement style. I have altered the algorithm from the method it is described in the book. I have converted it so that Longitudes to the West are negative (like GPS
coordinates), and so that 0 Azimuth is North (like a compass). I believe these changes make it behave more like a user would expect.
</p>
<span class="algorithmdiv">
<b>Explanatory Supplement eq 7.16</b><br>
<br>
\(
\textbf eq1\ \ \ \cos \mathit{a} \sin A_{z} = -\cos \delta \sin \mathit{h}
\\
\textbf eq2\ \ \ \cos \mathit{a} \cos A_{z} = \sin \delta \cos \phi - \cos \delta \cos \mathit{h} \sin \phi
\\
\textbf eq3\ \ \ \sin \mathit{a} = \sin \delta \sin \phi + \cos \delta \cos \mathit{h} \cos \phi
\)
<p>
Where \(h\) is the hour angle, \(\delta\) is the declination, \(A_{z}\) is azimuth, \(a\) is altitude, \(\phi\) is the lattitude.
You will need to check the signs of \(\cos A_z\) and \(\sin A_z\) to determine the propper quadrant:
</p>
<p>if \(\cos A_z\) > 0 and \(\sin A_z\) > 0: use either eq1 or eq2</p>
<p>if \(\cos A_z\) > 0 and \(\sin A_z\) < 0: use eq1</p>
<p>if \(\cos A_z\) < 0 and \(\sin A_z\) < 0: use \(A_z\) = 360 - eq2</p>
<p>if \(\cos A_z\) < 0 and \(\sin A_z\) > 0: use eq2</p>
</span><span class="algorithmdiv">
<b>Astronomical Algorithms eq 13.5, 13.6</b><br>
<br>
\(
\tan A = \dfrac{\sin H}{\cos H \sin \varphi - \tan \delta \cos \varphi}
\)
<br><br>
\(
\sin h = \sin \varphi \sin \delta + \cos \varphi \cos \delta \cos H
\)
<p>
Where \(H\) is the hour angle, \(\delta\) is the declination, \(A\) is azimuth, \(h\) is altitude, \(\varphi\) is the lattitude.
</p>
</span>
<span class="algorithmdiv">
<b>Computational Spherical Astronomy (Taff) 1.1, 2.7</b><br>
<br>
\(
\\
\mathbf{l}(h,\delta)=
\begin{bmatrix}
\cos \delta\cos h \\
\cos \delta\sin h \\
\sin \delta \\
\end{bmatrix}\\
\\~\\
\mathbf{l}(A,a)=R_2(90^{\circ}-\Phi )\ \mathbf{l}(h,\delta)
\)
<p>
Where \(h\) is the hour angle, \(\delta\) is the declination, \(A\) is azimuth, \(a\) is altitude, \(\Phi\) is the lattitude.
</p>
\(\mathbf{l}(A,a)\) will be in cartesian coordinates (\(x, y, z\)), to convert to RA/Dec:
<p>
\(
r = \sqrt{ x^2+y^2+z^2} \\
\cos A = z / r \\
\tan a = y / x \\
\)
</p>
</span>
<form>
<table>
<tr><td align=right>Julian Date:</td><td><input type=text id="jd" value="2459349.210248739"></td><td><input type=button value="Now" onclick='setJDToNow();'></td></tr>
<tr><td align=right>Lattitude:</td><td><input type=text id="lat" value="38.2464000"></td><td><input type=button value="Get Location" onclick='getUserPosition();'><td></tr>
<tr><td align=right>Longitude:</td><td><input type=text id="lon" value=274.236400></td></tr>
<tr><td align=right>Right Ascension:</td><td><input type=text id="ra" value="3.4299545354"></td><td>Decimal hours, eg. 10.382938</td></tr>
<tr><td align=right>Declination:</td><td><input type=text id="dec" value="18.726708585"></td><td>Decimal degrees, eg. 249.382988</td></tr>
<tr><td></td><td><input type=button value="Compute" onclick="compute();"></td></tr>
</table>
</form>
<pre id="output"></pre>
<pre id="sourceOutput">
<code class="JavaScript" id='code1'></code>
</pre>
<script id='sourceCode'>
//Greg Miller ([email protected]) 2021
//Released as public domain
//http://www.celestialprogramming.com/
//All input and output angles are in radians, jd is Julian Date in UTC
function raDecToAltAz(ra,dec,lat,lon,jd_ut){
//Meeus 13.5 and 13.6, modified so West longitudes are negative and 0 is North
const gmst=greenwichMeanSiderealTime(jd_ut);
let localSiderealTime=(gmst+lon)%(2*Math.PI);
let H=(localSiderealTime - ra);
if(H<0){H+=2*Math.PI;}
if(H>Math.PI){H=H-2*Math.PI;}
let az = (Math.atan2(Math.sin(H), Math.cos(H)*Math.sin(lat) - Math.tan(dec)*Math.cos(lat)));
let a = (Math.asin(Math.sin(lat)*Math.sin(dec) + Math.cos(lat)*Math.cos(dec)*Math.cos(H)));
az-=Math.PI;
if(az<0){az+=2*Math.PI;}
return [az,a, localSiderealTime,H];
}
function greenwichMeanSiderealTime(jd){
//"Expressions for IAU 2000 precession quantities" N. Capitaine1,P.T.Wallace2, and J. Chapront
const t = ((jd - 2451545.0)) / 36525.0;
let gmst=this.earthRotationAngle(jd)+(0.014506 + 4612.156534*t + 1.3915817*t*t - 0.00000044 *t*t*t - 0.000029956*t*t*t*t - 0.0000000368*t*t*t*t*t)/60.0/60.0*Math.PI/180.0; //eq 42
gmst%=2*Math.PI;
if(gmst<0) gmst+=2*Math.PI;
return gmst;
}
function earthRotationAngle(jd){
//IERS Technical Note No. 32
const t = jd- 2451545.0;
const f = jd%1.0;
let theta = 2*Math.PI * (f + 0.7790572732640 + 0.00273781191135448 * t); //eq 14
theta%=2*Math.PI;
if(theta<0)theta+=2*Math.PI;
return theta;
}
</script>
<script>
compute();
function compute(){
const toRad=Math.PI/180;
const jd=document.getElementById("jd").value
//Convert all values to radians
const lat=document.getElementById("lat").value*toRad;
const lon=document.getElementById("lon").value*toRad;
const ra=document.getElementById("ra").value*toRad*15; //Convert RA from hours to degrees, then to radians
const dec=document.getElementById("dec").value*toRad;
const altaz=raDecToAltAz(ra,dec,lat,lon,jd);
const r="Alt:"+degreesToDMS(altaz[1]/toRad)+"<br>Az: "+degreesToDMS(altaz[0]/toRad);
document.getElementById("output").innerHTML="Result:\r\n"+r;
}
function getUserPosition(){
navigator.geolocation.getCurrentPosition(showPosition);
}
function showPosition(p){
document.getElementById("lat").value=p.coords.latitude;
document.getElementById("lon").value=-p.coords.longitude;
}
function JulianDateFromUnixTime(t){
//Not valid for dates before Oct 15, 1582
return (t / 86400000) + 2440587.5;
}
function UnixTimeFromJulianDate(jd){
//Not valid for dates before Oct 15, 1582
return (jd-2440587.5)*86400000;
}
function setJDToNow(){
const date=new Date();
const jd=JulianDateFromUnixTime(date.getTime());
document.getElementById("jd").value=jd;
}
function degreesToDMS(d){
let sign="+";
if(d<0){sign="-";}
d=Math.abs(d);
let deg=Math.floor(d);
d-=deg;
d*=60;
let min=Math.floor(d);
d-=min;
d*=60;
let sec=d.toFixed(2);
if(deg<100){deg="0"+deg;}
if(deg<10){deg="0"+deg;}
if(min<10){min="0"+min;}
if(sec<10){sec="0"+sec;}
return sign+deg+"° "+min+"' "+sec+"\"";
}
</script>
<script>
let t=document.getElementById("sourceCode").innerText;
t=t.replaceAll("&","&")
t=t.replaceAll("<","<")
t=t.replaceAll(">",">")
document.getElementById("code1").innerHTML=t;
</script>
<script src="highlight/highlight.pack.js"></script>
<script>hljs.initHighlightingOnLoad();</script>