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 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392
|
unit unit_hjd;
{ Converts Julian day to Heliocentric Julian Day. Difference is maximum +- 500 sec / 8.3 minutes }
{Copyright (C) 2017, 2024 by Han Kleijn, www.hnsky.org
email: han.k.. at...hnsky.org
This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this
file, You can obtain one at https://mozilla.org/MPL/2.0/. }
{$mode delphi}
interface
uses
Classes, SysUtils, math, LazSysUtils, {nowUtc}
astap_main {for theader};
var
ra_mean : double=0;
dec_mean: double=0;
site_lat_radians, site_long_radians,wtime2actual : double;
function calc_jd_now: double; {get julian day for now}
function JD_to_HJD(jd,ra_object,dec_object: double): double;{conversion JD to HJD} {see https://en.wikipedia.org/wiki/Heliocentric_Julian_Day}
procedure equ_gal(ra,dec:double;out l,b: double);{equatorial to galactic coordinates}
function airmass_calc(h: double): double; // where h is apparent altitude in degrees.
function atmospheric_absorption(airmass: double):double;{magnitudes}
procedure calculate_az_alt(calc_mode : integer;head: Theader; out az,alt : double);{calculate az, alt. Move try to use header values else force calculation. Unit degrees}
procedure altitude_and_refraction(lat,long,julian,temperature,pressure,ra3,dec3: double; out az,alt : double);{altitude calculation and correction ra, dec for refraction}
function calculate_az_alt_basic(ra,dec : double; out az,alt : double): boolean;{calculate azimuth, altitude and initialize wtime2actual/sidereal time if site_lat_radians>999. For mouse pointer}
procedure polar2(x,y,z:double;out r,theta,phi:double);
function get_lat_long(out site_lat_radians, site_long_radians : double): boolean;//retrieve latitude and longitude
procedure az_ra(az,alt,lat,long,t:double;out ra,dcr: double);{conversion az,alt to ra,dec}
procedure ra_az(ra,de,LAT,LONG,t:double;out azimuth2,altitude2: double);{conversion ra & dec to altitude,azimuth}
implementation
uses
unit_stack, unit_ephemerides,unit_asteroid, unit_aberration;
function calc_jd_now: double; {get julian day for now}
var
yy,mm,dd :word;
hour,min, ss,ms: Word;
dt :tdatetime;
begin
dt:=LazSysUtils.NowUTC;
DeCodeDate(dt,YY,MM,DD);
DecodeTime(dt,hour,min,ss,ms);
result:=julian_calc(yy,mm,dd,hour,min,ss+ms/1000);{calculate julian day}
end;
{ sun: low precision solar coordinates (approx. 1') }
{ jd : julian day }
{ ra : right ascension (in radians; equinox of date) }
{ dec: declination (in radians; equinox of date) }
{ Factors from "Astronomy on the personal computer" }
procedure sun(jd:real; var ra,dec: double); {jd var ra 0..2*pi, dec [0..pi/2] of Sun equinox of date}
const
cos_ecl=cos(23.43929111*pi/180);{obliquity of ecliptic}
sin_ecl=sin(23.43929111*pi/180);{obliquity of ecliptic}
var
angle,l,m,dl,sin_l,cos_l,y,z,rho,t: double;
begin
t:=(jd-2451545)/36525; {time in julian centuries since j2000 }
m := 2*pi*frac(0.993133+99.997361*t);
dl:= 6893.0*sin(m)+72.0*sin(2*m);
angle:=frac(0.7859453 + m/(2*pi) + (6191.2*t+dl)/1296e3);{orbit position}
if angle<0 then angle:=angle+1; {frac(-1.1) is -0.1, should become 0.9}
l := 2*pi*angle; {orbit position in radians}
sincos(l,sin_l,cos_l);
y:=cos_ecl*sin_l;{convert helio to geocentric coordinates}
z:=sin_ecl*sin_l;
rho:=sqrt(1.0-z*z);
dec := arctan(z/rho);
ra := 2*arctan(y/(cos_l+rho));
if (ra<0) then ra:=ra+(2*pi);
end;
//procedure precession(jd, ra1,dec1 : double; var ra2,dec2 : double); {precession correction, simple formula, new Meeus chapter precession}
//var
// t,dra,ddec,sin_ra1,cos_ra1,m,n,n2 : double;
//begin
// t:=(jd-2451545)/36525; {time in julian centuries since j2000 }
// m:=3.075+0.00186*t;{seconds}
// n:=1.33621-0.00057*t; {seconds}
// n2:=20.043-0.0085*t;{arcsec}
// sincos(ra1,sin_ra1,cos_ra1);
// dra:=(m + n *sin_ra1*tan(dec1))*pi/(3600*12);{yearly ra drift in radians}
// ddec:=n2*cos_ra1*pi/(3600*180); {yearly dec drift in radians}
// ra2:=ra1+(dra*t*100);{multiply with number of years is t*100}
// dec2:=dec1+(ddec*t*100);
//end;
function JD_to_HJD(jd,ra_object,dec_object: double): double;{conversion Julian Day to Heliocentric Julian Day}
var {see https://en.wikipedia.org/wiki/Heliocentric_Julian_Day}
ra_sun, dec_sun : double;
sin_dec_object,cos_dec_object,sin_dec_sun,cos_dec_sun : double;
begin
sun(jd,ra_sun,dec_sun);{get sun position in equinox of date coordinates}
precession3(jd, 2451545 {J2000},ra_sun,dec_sun); {precession}
sincos(dec_object,sin_dec_object,cos_dec_object);
sincos(dec_sun,sin_dec_sun,cos_dec_sun);
result:=jd - 500{sec}*(1/(24*3600))*(sin_dec_object* sin_dec_sun + cos_dec_object * cos_dec_sun * cos(ra_object - ra_sun)); {assume 500 sec travel time Sun- Earth}
end;
procedure equ_gal(ra,dec:double;out l,b: double);{equatorial to galactic coordinates}
const
{North_galactic pole (J2000)}
pole_ra : double = (12+51/60+26.27549/3600)*pi/12; {12h51m26.27549 https://www.aanda.org/articles/aa/pdf/2011/02/aa14961-10.pdf }
pole_dec: double = (27+7/60+41.7043/3600)*pi/180; {+27◦07′41.7043′′}
posangle: double = (122.93191857-90)*pi/180; {122.93191857◦}
// Converting between galactic to equatorial coordinates
// The galactic north pole is at RA = 12:51.4, Dec = +27:07 (2000.0),
// the galactic center at RA = 17:45.6, Dec = -28:56 (2000.0).
// The inclination of the galactic equator to the celestial equator is thus 62.9°.
// The intersection, or node line, of the two equators is at
// RA = 282.25°, Dec = 0:00 (2000.0), and at l = 33°, b=0.
var
sin_b, cos_b, sin_pole_dec, cos_pole_dec :double;
begin
sincos(pole_dec,sin_pole_dec, cos_pole_dec);
b:=arcsin(cos(dec)*cos_pole_dec*cos(ra - pole_ra) + sin(dec)*sin_pole_dec);
sincos(b,sin_b, cos_b);
l:=arctan2( (sin(dec) - sin_b *sin_pole_dec ) , (cos(dec)*cos_pole_dec*sin(ra - pole_ra)) ) + posangle;
end;
//function altitude(ra3,dec3 {2000},lat,long,julian:double):double;{conversion ra & dec to altitude only. This routine is created for speed, only the altitude is calculated}
//{input RA [0..2pi], DEC [-pi/2..+pi/2],lat[-pi/2..pi/2], long[-pi..pi] West positive, East negative !!,time[0..2*pi]}
//var t5,wtime2actual : double;
// sin_lat,cos_lat,sin_dec,cos_dec:double;
//const
// siderealtime2000=(280.46061837)*pi/180;{[radians], 90 degrees shifted sidereal time at 2000 jan 1.5 UT (12 hours) =Jd 2451545 at meridian greenwich, see new meeus 11.4}
// earth_angular_velocity = pi*2*1.00273790935; {about(365.25+1)/365.25) or better (365.2421874+1)/365.2421874 velocity dailly. See new Meeus page 83}
//begin
// wtime2actual:=fnmodulo((long)+siderealtime2000 +(julian-2451545 )* earth_angular_velocity,2*pi); {As in the FITS header in ASTAP the site longitude is positive if east and has to be added to the time}
{change by time & longitude in 0 ..pi*2, simular as siderial time}
{2451545...for making dayofyear not to big, otherwise small errors occur in sin and cos}
// precession3(2451545 {J2000},julian,ra3,dec3); {precession, from J2000 to Jnow}
// t5:=wtime2actual-ra3;
// sincos(lat,sin_lat,cos_lat);
// sincos(dec3,sin_dec,cos_dec);
// try
// {***** altitude calculation from RA&DEC, meeus new 12.5 *******}
// result:=arcsin(SIN_LAT*SIN_DEC+COS_LAT*COS_DEC*COS(T5));
// except
// {ignore floating point errors outside builder}
// end;
//end;
{-----------------------------------------------------------------------}
{ POLAR2: conversion of cartesian coordinates (x,y,z) }
{ into polar coordinates (r,theta,phi) }
{ (theta in [-pi/2 deg,+pi/2]; phi in [0 ,+ 2*pi radians] }
{-----------------------------------------------------------------------}
procedure polar2(x,y,z:double;out r,theta,phi:double);
var rho: double;
begin
rho:=x*x+y*y; r:=sqrt(rho+z*z);
phi:=arctan2(y,x);
if phi<0 then phi:=phi+2*pi;
rho:=sqrt(rho);
theta:=arctan2(z,rho);
end;
{----------------------------------------------------------------}
{ EQUHOR: conversion of equatorial into horizontal coordinates }
{ DEC : declination (-pi/2 .. +pi/2) }
{ TAU : hour angle (0 .. 2*pi) }
{ PHI : geographical latitude (in rad) }
{ H : altitude (in rad) }
{ AZ : azimuth (0 deg .. 2*pi rad, counted S->W->N->E->S) }
{----------------------------------------------------------------}
procedure equhor2 (dec,tau,phi: double; out h,az: double);
var cos_phi,sin_phi, cos_dec,sin_dec,cos_tau, sin_tau, x,y,z, dummy: double;
begin
sincos(phi,sin_phi,cos_phi);
sincos(dec,sin_dec,cos_dec);
sincos(tau,sin_tau,cos_tau);
x:=cos_dec*sin_phi*cos_tau - sin_dec*cos_phi;
y:=cos_dec*sin_tau;
z:=cos_dec*cos_phi*cos_tau + sin_dec*sin_phi;
polar2(x,y,z, dummy,h,az)
end;
procedure ra_az(ra,de,LAT,LONG,t:double;out azimuth2,altitude2: double);{conversion ra & dec to altitude,azimuth}
{input RA [0..2pi], DEC [-pi/2..+pi/2],lat[-0.5*pi..0.5*pi],long[0..2*pi],time[0..2*pi]}
begin
EQUHOR2(de,ra-long-t,lat, {var:} altitude2,azimuth2);
azimuth2:=pi-azimuth2;
if azimuth2<0 then azimuth2:=azimuth2+2*Pi;
end;
procedure az_ra(az,alt,lat,long,t:double;out ra,dcr: double);{conversion az,alt to ra,dec}
{input AZ [0..2pi], ALT [-pi/2..+pi/2],lat[-0.5*pi..0.5*pi],long[0..2pi],time[0..2*pi]}
begin
EQUHOR2(alt,az,lat,{var:} dcr,ra);
ra:=pi-ra+long +t;
while ra<0 do ra:=ra+2*pi;
while ra>=2*pi do ra:=ra-2*pi;
end;
function atmospheric_refraction(altitude_real {degrees},p {mbar},t {celsius} :double):double; {atmospheric refraction correction, input and output in degrees}
var hn :real;
begin
hn:=(altitude_real + 10.3/(altitude_real +5.11))*pi/180; {radians}
result:=((p/1010)*283/(273+t)) * (1.02/60)/(sin(hn)/cos(hn) ); {note: tan(x) = sin(x)/cos(x)}
{bases on meeus 1991 page 102, formula 15.4}
end;
procedure altitude_and_refraction(lat,long,julian,temperature,pressure,ra3,dec3: double; out az,alt : double);{altitude calculation and correction ra, dec for refraction}
{input RA [0..2pi], DEC [-pi/2..+pi/2],lat[-pi/2..pi/2], long[-pi..pi] West NEGATIVE, East POSTIVE !!,time[0..2*pi]}
var wtime2actual : double;
const
siderealtime2000=(280.46061837)*pi/180;{[radians],sidereal time at 2000 jan 1.5 UT (12 hours) =Jd 2451545 at meridian greenwich, see new meeus 11.4}
earth_angular_velocity = pi*2*1.00273790935; {about(365.25+1)/365.25) or better (365.2421874+1)/365.2421874 velocity dailly. See new Meeus page 83}
begin
wtime2actual:=fnmodulo(+long+siderealtime2000 +(julian-2451545 )* earth_angular_velocity,2*pi);{Local sidereal time. As in the FITS header in ASTAP the site longitude is positive if east and has to be added to the time}
RA_AZ(ra3,dec3,lat,0,wtime2actual,{var} az,alt);{conversion ra & dec to altitude,azimuth}
{correct for temperature and correct head.ra0, head.dec0 for refraction}
if temperature>=100 {999} then temperature:=10 {default temperature celsius};
az:=az*180/pi;{in degrees}
alt:=alt*180/pi;
alt:=alt+atmospheric_refraction(alt,pressure {mbar},temperature {celsius});{astrometric to apparant altitude}
// AZ_RA(azimuth2,result,LAT,0,wtime2actual, {var} ra_mean,dec_mean);{conversion az,alt to ra_mean,dec_mean reverse corrected for refraction}
// RA_AZ((23+9/60)*pi/12,(-6-43/60)*pi/180,(38+55/60)*pi/180,-(5+8/60)*pi/12,(8+(34)/60)*pi/12,{var} azimuth2,altitude2);{conversion ra & dec to altitude,azimuth}
// RA_AZ2((23+9/60)*pi/12,(-6-43/60)*pi/180,(38+55/60)*pi/180,0,(8-5+(34-8)/60)*pi/12,{var} azimuth2,altitude2);{conversion ra & dec to altitude,azimuth}
// RA_AZ2((23+9/60)*pi/12,(-6-43/60)*pi/180,(38+55/60)*pi/180,+(5+8/60)*pi/12,(8+(34)/60)*pi/12,{var} azimuth2,altitude2);{conversion ra & dec to altitude,azimuth}
// AZ_RA(AZIMUTH2,ALTITUDE2,39*pi/180,0,(8-5+(34-8)/60)*pi/12, {var} ra_mean,dec_mean);{conversion az,alt to ra_mean,dec_mean reverse corrected for refraction}
// AZ_RA2(AZIMUTH2,ALTITUDE2,39*pi/180,0,(8-5+(34-8)/60)*pi/12, {var} ra_mean,dec_mean);{conversion az,alt to ra_mean,dec_mean reverse corrected for refraction}
// AZ_RA2(AZIMUTH2,ALTITUDE2,39*pi/180,+(5+8/60)*pi/12,(8+(34)/60)*pi/12, {var} ra_mean,dec_mean);{conversion az,alt to ra_mean,dec_mean reverse corrected for refraction}
// beep;
end;
function get_lat_long(out site_lat_radians, site_long_radians : double): boolean;//retrieve latitude and longitude
var
errordecode : boolean;
err : integer;
begin
result:=false;
if sitelat='' then
begin
sitelat:=lat_default;
sitelong:=long_default;
end;
val(sitelat,site_lat_radians,err); {try to process 3.7E+01}
if err=0 then
begin site_lat_radians:=site_lat_radians*pi/180; errordecode:=false end
else {try to process string 37 00 00}
dec_text_to_radians(sitelat,site_lat_radians,errordecode);
if errordecode=false then
begin
val(sitelong,site_long_radians,err); {try to process 3.7E+01}
if err=0 then
begin site_long_radians:=site_long_radians*pi/180; errordecode:=false end
else {try to process string 37 00 00}
dec_text_to_radians(sitelong,site_long_radians,errordecode);
if errordecode=false then result:=true;
end;
if errordecode then memo2_message('Error decoding site longitude or latitude!');
end;
procedure calculate_az_alt(calc_mode : integer;head: Theader; out az,alt : double);{calculate az, alt. Move try to use header values else force calculation. Unit degrees}
var
site_lat_radians,site_long_radians,ra,dec : double;
errordecode : boolean;
err : integer;
begin
{calc_mode 0: use from header or calculate from position. If not available calculate}
{calc_mode 1: force calculation from time, location and position without nutation and aberration}
{calc_mode 2: force high accuracy calculation including nutation and aberration) from time, location and position}
az:=strtofloat2(centaz);
alt:=strtofloat2(centalt);
if (((alt=0) or (calc_mode>0)) and (head.cd1_1<>0)) then {calculate from observation location, image center and time the altitude}
begin
if get_lat_long(site_lat_radians, site_long_radians) then
begin
date_to_jd(head.date_obs,head.date_avg,head.exposure);{convert date-obs to jd_start, jd_mid}
if jd_mid>2400000 then {valid JD}
begin
ra:=head.ra0; {duplicate to protect J2000 position}
dec:=head.dec0;
if calc_mode=2 then {high accuracy including nutation and aberration}
J2000_to_apparent(jd_mid,ra,dec) {from J2000 to Jnow apparent, aberrration, precession nutation without refraction}
else
precession3(2451545 {J2000},jd_mid,ra,dec); {from J2000 to Jnow mean, precession only. without refraction}
altitude_and_refraction(site_lat_radians,site_long_radians,jd_mid,focus_temp,pressure,ra,dec,az,alt);{In formulas the longitude is positive to west!!!. }
end
else memo2_message('Error decoding Julian day!');
end;
end;
end;
function calculate_az_alt_basic(ra,dec : double; out az,alt : double): boolean;{calculate azimuth, altitude and initialize wtime2actual/sidereal time if site_lat_radians>999. For mouse pointer}
const
siderealtime2000=(280.46061837)*pi/180;{[radians],sidereal time at 2000 jan 1.5 UT (12 hours) =Jd 2451545 at meridian greenwich, see new meeus 11.4}
earth_angular_velocity = pi*2*1.00273790935; {about(365.25+1)/365.25) or better (365.2421874+1)/365.2421874 velocity dailly. See new Meeus page 83}
var
temperature : double;
begin
result:=false;//assume failure
if site_lat_radians>998 then //initialize wtime2actual/sidereal time
begin
if get_lat_long(site_lat_radians, site_long_radians)=false then exit;//retrieve latitude and longitude
date_to_jd(head.date_obs,head.date_avg,head.exposure);{convert date-obs to jd_start, jd_mid}
if jd_mid>2400000 then {valid JD}
begin
wtime2actual:=fnmodulo(+site_long_radians+siderealtime2000 +(jd_mid-2451545 )* earth_angular_velocity,2*pi);{Local sidereal time. As in the FITS header in ASTAP the site longitude is positive if east and has to be added to the time}
end
else
begin
memo2_message('Error decoding Julian day!');
exit;
end;
end;
precession3(2451545 {J2000},jd_mid,ra,dec); {from J2000 to Jnow mean, precession only. without refraction}
ra_az(ra,dec,site_lat_radians,0,wtime2actual,{out} az,alt);{conversion ra & dec to altitude,azimuth}
if focus_temp>=100 {999} then temperature:=10 {default temperature celsius} else temperature:=focus_temp;
alt:=alt*180/pi;
alt:=(alt+atmospheric_refraction(alt,pressure {mbar},temperature {celsius}))*pi/180;{astrometric to apparant altitude}
result:=true;
end;
function airmass_calc(h: double): double; // where h is apparent altitude in degrees.
begin
// Pickering, 2002, https://en.wikipedia.org/wiki/Air_mass_(astronomy)
if h>=0.0000001 then
result := 1 / sin((pi/180) * (h + (244 / (165 + 47 * power(h,1.1)))))
else
result:=999;
end;
function atmospheric_absorption(airmass: double):double;{magnitudes relative to vacuum}
{The Extinction, Scattering, Absorption due to the atmosphere expressed in magnitudes.
Reference http://www.icq.eps.harvard.edu/ICQExtinct.html
see also https://www.skyandtelescope.com/astronomy-resources/transparency-and-atmospheric-extinction/}
var
a_ozon,a_ray,a_aer : double;
begin
a_ozon:=airmass*0.016; {Schaefer's (1992) value Aoz =0.016 magnitudes per air mass for the small ozone component contributing to atmospheric extinction.}
a_ray:=airmass*0.1451; {Rayleigh scattering by air molecules. Expressed in magnitudes}
a_aer:=airmass*0.120; {Extinction due to aerosol scattering is due to particulates including dust, water droplets and manmade pollutants. Expressed in magnitudes}
result:=a_ozon+a_ray+a_aer;{Total extinction, scattering, absorption due to the atmosphere expressed in magnitudes. 0.2811*airmass}
end;
end.
|