@typescriptify/sweph 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +422 -0
- package/ephe/semo_18.se1 +0 -0
- package/ephe/sepl_18.se1 +0 -0
- package/originalCode/.eslintrc.json +124 -0
- package/originalCode/.gitattributes +2 -0
- package/originalCode/.github/FUNDING.yml +5 -0
- package/originalCode/.github/workflows/test.yml +35 -0
- package/originalCode/LICENSE +840 -0
- package/originalCode/README.md +91 -0
- package/originalCode/binding.gyp +41 -0
- package/originalCode/constants.js +366 -0
- package/originalCode/docs.gif +0 -0
- package/originalCode/index.d.ts +5115 -0
- package/originalCode/index.js +7 -0
- package/originalCode/index.mjs +109 -0
- package/originalCode/package.json +55 -0
- package/originalCode/src/functions/azalt.cpp +39 -0
- package/originalCode/src/functions/azalt_rev.cpp +35 -0
- package/originalCode/src/functions/calc.cpp +29 -0
- package/originalCode/src/functions/calc_pctr.cpp +31 -0
- package/originalCode/src/functions/calc_ut.cpp +29 -0
- package/originalCode/src/functions/close.cpp +6 -0
- package/originalCode/src/functions/cotrans.cpp +26 -0
- package/originalCode/src/functions/cotrans_sp.cpp +26 -0
- package/originalCode/src/functions/cs2degstr.cpp +19 -0
- package/originalCode/src/functions/cs2lonlatstr.cpp +23 -0
- package/originalCode/src/functions/cs2timestr.cpp +23 -0
- package/originalCode/src/functions/csnorm.cpp +15 -0
- package/originalCode/src/functions/csroundsec.cpp +15 -0
- package/originalCode/src/functions/d2l.cpp +15 -0
- package/originalCode/src/functions/date_conversion.cpp +30 -0
- package/originalCode/src/functions/day_of_week.cpp +15 -0
- package/originalCode/src/functions/degnorm.cpp +15 -0
- package/originalCode/src/functions/deltat.cpp +15 -0
- package/originalCode/src/functions/deltat_ex.cpp +24 -0
- package/originalCode/src/functions/difcs2n.cpp +19 -0
- package/originalCode/src/functions/difcsn.cpp +19 -0
- package/originalCode/src/functions/difdeg2n.cpp +19 -0
- package/originalCode/src/functions/difdegn.cpp +19 -0
- package/originalCode/src/functions/fixstar.cpp +32 -0
- package/originalCode/src/functions/fixstar2.cpp +32 -0
- package/originalCode/src/functions/fixstar2_mag.cpp +28 -0
- package/originalCode/src/functions/fixstar2_ut.cpp +32 -0
- package/originalCode/src/functions/fixstar_mag.cpp +28 -0
- package/originalCode/src/functions/fixstar_ut.cpp +32 -0
- package/originalCode/src/functions/gauquelin_sector.cpp +44 -0
- package/originalCode/src/functions/get_ayanamsa.cpp +15 -0
- package/originalCode/src/functions/get_ayanamsa_ex.cpp +27 -0
- package/originalCode/src/functions/get_ayanamsa_ex_ut.cpp +27 -0
- package/originalCode/src/functions/get_ayanamsa_name.cpp +19 -0
- package/originalCode/src/functions/get_ayanamsa_ut.cpp +15 -0
- package/originalCode/src/functions/get_current_file_data.cpp +28 -0
- package/originalCode/src/functions/get_library_path.cpp +8 -0
- package/originalCode/src/functions/get_orbital_elements.cpp +29 -0
- package/originalCode/src/functions/get_planet_name.cpp +19 -0
- package/originalCode/src/functions/get_tid_acc.cpp +7 -0
- package/originalCode/src/functions/heliacal_pheno_ut.cpp +52 -0
- package/originalCode/src/functions/heliacal_ut.cpp +52 -0
- package/originalCode/src/functions/helio_cross.cpp +33 -0
- package/originalCode/src/functions/helio_cross_ut.cpp +33 -0
- package/originalCode/src/functions/house_name.cpp +20 -0
- package/originalCode/src/functions/house_pos.cpp +36 -0
- package/originalCode/src/functions/houses.cpp +35 -0
- package/originalCode/src/functions/houses_armc.cpp +38 -0
- package/originalCode/src/functions/houses_armc_ex2.cpp +47 -0
- package/originalCode/src/functions/houses_ex.cpp +37 -0
- package/originalCode/src/functions/houses_ex2.cpp +46 -0
- package/originalCode/src/functions/jdet_to_utc.cpp +38 -0
- package/originalCode/src/functions/jdut1_to_utc.cpp +38 -0
- package/originalCode/src/functions/julday.cpp +25 -0
- package/originalCode/src/functions/lat_to_lmt.cpp +27 -0
- package/originalCode/src/functions/lmt_to_lat.cpp +27 -0
- package/originalCode/src/functions/lun_eclipse_how.cpp +34 -0
- package/originalCode/src/functions/lun_eclipse_when.cpp +31 -0
- package/originalCode/src/functions/lun_eclipse_when_loc.cpp +39 -0
- package/originalCode/src/functions/lun_occult_when_glob.cpp +35 -0
- package/originalCode/src/functions/lun_occult_when_loc.cpp +43 -0
- package/originalCode/src/functions/lun_occult_where.cpp +34 -0
- package/originalCode/src/functions/mooncross.cpp +26 -0
- package/originalCode/src/functions/mooncross_node.cpp +30 -0
- package/originalCode/src/functions/mooncross_node_ut.cpp +30 -0
- package/originalCode/src/functions/mooncross_ut.cpp +26 -0
- package/originalCode/src/functions/nod_aps.cpp +42 -0
- package/originalCode/src/functions/nod_aps_ut.cpp +42 -0
- package/originalCode/src/functions/orbit_max_min_true_distance.cpp +37 -0
- package/originalCode/src/functions/pheno.cpp +29 -0
- package/originalCode/src/functions/pheno_ut.cpp +29 -0
- package/originalCode/src/functions/radnorm.cpp +15 -0
- package/originalCode/src/functions/refrac.cpp +23 -0
- package/originalCode/src/functions/refrac_extended.cpp +32 -0
- package/originalCode/src/functions/revjul.cpp +33 -0
- package/originalCode/src/functions/rise_trans.cpp +44 -0
- package/originalCode/src/functions/rise_trans_true_hor.cpp +46 -0
- package/originalCode/src/functions/set_delta_t_userdef.cpp +14 -0
- package/originalCode/src/functions/set_ephe_path.cpp +14 -0
- package/originalCode/src/functions/set_jpl_file.cpp +14 -0
- package/originalCode/src/functions/set_sid_mode.cpp +20 -0
- package/originalCode/src/functions/set_tid_acc.cpp +14 -0
- package/originalCode/src/functions/set_topo.cpp +20 -0
- package/originalCode/src/functions/sidtime.cpp +15 -0
- package/originalCode/src/functions/sidtime0.cpp +21 -0
- package/originalCode/src/functions/sol_eclipse_how.cpp +34 -0
- package/originalCode/src/functions/sol_eclipse_when_glob.cpp +31 -0
- package/originalCode/src/functions/sol_eclipse_when_loc.cpp +39 -0
- package/originalCode/src/functions/sol_eclipse_where.cpp +30 -0
- package/originalCode/src/functions/solcross.cpp +26 -0
- package/originalCode/src/functions/solcross_ut.cpp +26 -0
- package/originalCode/src/functions/split_deg.cpp +35 -0
- package/originalCode/src/functions/time_equ.cpp +25 -0
- package/originalCode/src/functions/utc_time_zone.cpp +48 -0
- package/originalCode/src/functions/utc_to_jd.cpp +37 -0
- package/originalCode/src/functions/version.cpp +8 -0
- package/originalCode/src/functions/vis_limit_mag.cpp +50 -0
- package/originalCode/src/sweph.cpp +150 -0
- package/originalCode/src/sweph.h +119 -0
- package/originalCode/swisseph/swecl.c +6428 -0
- package/originalCode/swisseph/swedate.c +588 -0
- package/originalCode/swisseph/swedate.h +81 -0
- package/originalCode/swisseph/swehel.c +3511 -0
- package/originalCode/swisseph/swehouse.c +3143 -0
- package/originalCode/swisseph/swehouse.h +98 -0
- package/originalCode/swisseph/swejpl.c +958 -0
- package/originalCode/swisseph/swejpl.h +103 -0
- package/originalCode/swisseph/swemmoon.c +1930 -0
- package/originalCode/swisseph/swemplan.c +967 -0
- package/originalCode/swisseph/swemptab.h +10640 -0
- package/originalCode/swisseph/swenut2000a.h +2819 -0
- package/originalCode/swisseph/sweodef.h +326 -0
- package/originalCode/swisseph/sweph.c +8614 -0
- package/originalCode/swisseph/sweph.h +849 -0
- package/originalCode/swisseph/swephexp.h +1020 -0
- package/originalCode/swisseph/swephlib.c +4634 -0
- package/originalCode/swisseph/swephlib.h +189 -0
- package/package.json +28 -0
- package/scripts/gen-swemptab.js +177 -0
- package/scripts/gen-swenut2000a.js +106 -0
- package/src/SwissEph/README.md +268 -0
- package/src/SwissEph/UseCases/Ayanamsa.md +363 -0
- package/src/SwissEph/UseCases/AzimuthAltitude.md +408 -0
- package/src/SwissEph/UseCases/CoordinateSystems.md +337 -0
- package/src/SwissEph/UseCases/DateAndTime.md +368 -0
- package/src/SwissEph/UseCases/DeltaT.md +258 -0
- package/src/SwissEph/UseCases/EphemerisFiles.md +338 -0
- package/src/SwissEph/UseCases/FixedStars.md +300 -0
- package/src/SwissEph/UseCases/GauquelinSectors.md +304 -0
- package/src/SwissEph/UseCases/HeliacalEvents.md +396 -0
- package/src/SwissEph/UseCases/HelioCrossings.md +325 -0
- package/src/SwissEph/UseCases/HousePosition.md +254 -0
- package/src/SwissEph/UseCases/HouseSystems.md +279 -0
- package/src/SwissEph/UseCases/LunarEclipse.md +326 -0
- package/src/SwissEph/UseCases/MeridianTransit.md +279 -0
- package/src/SwissEph/UseCases/MoonCrossings.md +373 -0
- package/src/SwissEph/UseCases/NodesAndApsides.md +307 -0
- package/src/SwissEph/UseCases/Occultation.md +352 -0
- package/src/SwissEph/UseCases/OrbitalElements.md +469 -0
- package/src/SwissEph/UseCases/Phenomena.md +328 -0
- package/src/SwissEph/UseCases/PlanetPositions.md +366 -0
- package/src/SwissEph/UseCases/Planetocentric.md +278 -0
- package/src/SwissEph/UseCases/Refraction.md +314 -0
- package/src/SwissEph/UseCases/RiseAndSet.md +433 -0
- package/src/SwissEph/UseCases/SiderealTime.md +302 -0
- package/src/SwissEph/UseCases/SolarEclipse.md +379 -0
- package/src/SwissEph/UseCases/SunCrossings.md +275 -0
- package/src/SwissEph/UseCases/TopocentricCorrection.md +335 -0
- package/src/SwissEph/errors.ts +10 -0
- package/src/SwissEph/index.ts +823 -0
- package/src/SwissEph/types.ts +291 -0
- package/src/constants.ts +762 -0
- package/src/file-reader.ts +147 -0
- package/src/index.ts +10 -0
- package/src/swecl.ts +4526 -0
- package/src/swedate.ts +376 -0
- package/src/swehel.ts +1939 -0
- package/src/swehouse.ts +2167 -0
- package/src/swejpl.ts +470 -0
- package/src/swemmoon.ts +1318 -0
- package/src/swemplan.ts +585 -0
- package/src/swemptab.ts +4448 -0
- package/src/swenut2000a.ts +2763 -0
- package/src/sweph.ts +3993 -0
- package/src/swephlib.ts +2720 -0
- package/src/types.ts +490 -0
- package/tests/c-style/ayanamsa.test.ts +63 -0
- package/tests/c-style/config.test.ts +96 -0
- package/tests/c-style/crossings.test.ts +81 -0
- package/tests/c-style/date-time.test.ts +114 -0
- package/tests/c-style/eclipses.test.ts +84 -0
- package/tests/c-style/fixed-stars.test.ts +66 -0
- package/tests/c-style/heliacal.test.ts +34 -0
- package/tests/c-style/houses.test.ts +135 -0
- package/tests/c-style/math-utils.test.ts +160 -0
- package/tests/c-style/orbital.test.ts +78 -0
- package/tests/c-style/phenomena.test.ts +42 -0
- package/tests/c-style/planetocentric.test.ts +26 -0
- package/tests/c-style/planets.test.ts +117 -0
- package/tests/c-style/rise-set.test.ts +71 -0
- package/tests/helpers.ts +21 -0
- package/tests/modern/ayanamsa.test.ts +47 -0
- package/tests/modern/calc.test.ts +113 -0
- package/tests/modern/config.test.ts +46 -0
- package/tests/modern/crossings.test.ts +45 -0
- package/tests/modern/eclipses.test.ts +81 -0
- package/tests/modern/errors.test.ts +71 -0
- package/tests/modern/heliacal.test.ts +30 -0
- package/tests/modern/houses.test.ts +87 -0
- package/tests/modern/orbital.test.ts +79 -0
- package/tests/modern/phenomena.test.ts +41 -0
- package/tests/modern/rise-set.test.ts +60 -0
- package/tests/modern/statics.test.ts +99 -0
- package/tests/modern/utilities.test.ts +70 -0
- package/tsconfig.json +20 -0
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
# Planetocentric Positions
|
|
2
|
+
|
|
3
|
+
**Planetocentric coordinates** give you the position of a celestial body as seen from a planet other than Earth. Normal astronomical calculations are **geocentric** -- they describe positions as seen from Earth's center. But what if you wanted to know where Jupiter appears in the sky as seen from Mars? Or where Earth is positioned from the perspective of Venus?
|
|
4
|
+
|
|
5
|
+
The `calcPlanetocentric()` method lets you place your virtual observer on any planet and look at the sky from there.
|
|
6
|
+
|
|
7
|
+
This is useful for:
|
|
8
|
+
- **Space mission planning**: understanding what the sky looks like from another planet's reference frame
|
|
9
|
+
- **Comparative planetology**: how do planetary configurations (conjunctions, oppositions, etc.) look from other vantage points?
|
|
10
|
+
- **Science fiction worldbuilding**: if you are writing a story set on Mars, what constellations and planetary motions would your characters observe?
|
|
11
|
+
- **Educational purposes**: illustrating that geocentric positions are not absolute -- they depend on where you are standing
|
|
12
|
+
- **Verification**: geocentric positions of a planet should closely match planetocentric positions computed "from Earth" -- this serves as a sanity check
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## Quick Example
|
|
17
|
+
|
|
18
|
+
```typescript
|
|
19
|
+
import { SwissEph } from '../index';
|
|
20
|
+
import { SE_MARS, SE_JUPITER } from '../../constants';
|
|
21
|
+
|
|
22
|
+
const swe = new SwissEph();
|
|
23
|
+
const jd = SwissEph.julianDay(2025, 6, 15, 12);
|
|
24
|
+
|
|
25
|
+
// Where does Jupiter appear as seen from Mars?
|
|
26
|
+
const jupFromMars = swe.calcPlanetocentric(jd, SE_JUPITER, SE_MARS);
|
|
27
|
+
|
|
28
|
+
console.log(`Jupiter as seen from Mars:`);
|
|
29
|
+
console.log(` Longitude: ${jupFromMars.longitude.toFixed(4)} deg`);
|
|
30
|
+
console.log(` Latitude: ${jupFromMars.latitude.toFixed(4)} deg`);
|
|
31
|
+
console.log(` Distance: ${jupFromMars.distance.toFixed(6)} AU`);
|
|
32
|
+
|
|
33
|
+
swe.close();
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
## Detailed Examples
|
|
39
|
+
|
|
40
|
+
### Earth as seen from Mars
|
|
41
|
+
|
|
42
|
+
What would a Martian astronomer observe when looking at Earth? Earth would appear as a bright inner planet (similar to how we see Venus), going through phases and never straying far from the Sun.
|
|
43
|
+
|
|
44
|
+
```typescript
|
|
45
|
+
import { SwissEph } from '../index';
|
|
46
|
+
import { SE_EARTH, SE_MARS } from '../../constants';
|
|
47
|
+
|
|
48
|
+
const swe = new SwissEph();
|
|
49
|
+
|
|
50
|
+
// Track Earth's position as seen from Mars over one Martian year (~687 days)
|
|
51
|
+
const startJd = SwissEph.julianDay(2025, 1, 1, 0);
|
|
52
|
+
|
|
53
|
+
const signs = ['Ari','Tau','Gem','Can','Leo','Vir','Lib','Sco','Sag','Cap','Aqu','Pis'];
|
|
54
|
+
|
|
55
|
+
console.log('Earth as seen from Mars (monthly snapshots):');
|
|
56
|
+
for (let i = 0; i < 24; i++) {
|
|
57
|
+
const jd = startJd + i * 30;
|
|
58
|
+
const earth = swe.calcPlanetocentric(jd, SE_EARTH, SE_MARS);
|
|
59
|
+
const date = SwissEph.fromJulianDay(jd);
|
|
60
|
+
|
|
61
|
+
const signIdx = Math.floor(earth.longitude / 30);
|
|
62
|
+
const degInSign = earth.longitude - signIdx * 30;
|
|
63
|
+
|
|
64
|
+
console.log(
|
|
65
|
+
` ${date.year}-${String(date.month).padStart(2,'0')}-${String(date.day).padStart(2,'0')} ` +
|
|
66
|
+
`${degInSign.toFixed(1).padStart(5)} ${signs[signIdx]} ` +
|
|
67
|
+
`dist=${earth.distance.toFixed(4)} AU ` +
|
|
68
|
+
`speed=${earth.longitudeSpeed.toFixed(4)} deg/day`
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
swe.close();
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### Verifying: Mars from Earth vs geocentric Mars
|
|
76
|
+
|
|
77
|
+
Geocentric positions are simply planetocentric positions "from Earth." Calculating Mars from Earth using `calcPlanetocentric()` should produce results nearly identical to a regular `calc()` call.
|
|
78
|
+
|
|
79
|
+
```typescript
|
|
80
|
+
import { SwissEph } from '../index';
|
|
81
|
+
import { SE_MARS, SE_EARTH } from '../../constants';
|
|
82
|
+
|
|
83
|
+
const swe = new SwissEph();
|
|
84
|
+
const jd = SwissEph.julianDay(2025, 6, 15, 12);
|
|
85
|
+
|
|
86
|
+
// Standard geocentric calculation
|
|
87
|
+
const marsGeo = swe.calc(jd, SE_MARS);
|
|
88
|
+
|
|
89
|
+
// Planetocentric: Mars as seen from Earth
|
|
90
|
+
const marsPctr = swe.calcPlanetocentric(jd, SE_MARS, SE_EARTH);
|
|
91
|
+
|
|
92
|
+
console.log('Mars positions comparison:');
|
|
93
|
+
console.log(` Geocentric longitude: ${marsGeo.longitude.toFixed(6)} deg`);
|
|
94
|
+
console.log(` Planetocentric (Earth): ${marsPctr.longitude.toFixed(6)} deg`);
|
|
95
|
+
console.log(` Difference: ${Math.abs(marsGeo.longitude - marsPctr.longitude).toFixed(6)} deg`);
|
|
96
|
+
// The difference should be very small (< 0.01 deg)
|
|
97
|
+
|
|
98
|
+
console.log(`\n Geocentric distance: ${marsGeo.distance.toFixed(6)} AU`);
|
|
99
|
+
console.log(` Planetocentric distance: ${marsPctr.distance.toFixed(6)} AU`);
|
|
100
|
+
|
|
101
|
+
swe.close();
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### The Sun as seen from different planets
|
|
105
|
+
|
|
106
|
+
How does the Sun's apparent position differ when viewed from different planets?
|
|
107
|
+
|
|
108
|
+
```typescript
|
|
109
|
+
import { SwissEph } from '../index';
|
|
110
|
+
import {
|
|
111
|
+
SE_SUN, SE_MERCURY, SE_VENUS, SE_MARS,
|
|
112
|
+
SE_JUPITER, SE_SATURN,
|
|
113
|
+
} from '../../constants';
|
|
114
|
+
|
|
115
|
+
const swe = new SwissEph();
|
|
116
|
+
const jd = SwissEph.julianDay(2025, 3, 20, 12); // near vernal equinox
|
|
117
|
+
|
|
118
|
+
const observers = [
|
|
119
|
+
{ id: SE_MERCURY, name: 'Mercury' },
|
|
120
|
+
{ id: SE_VENUS, name: 'Venus' },
|
|
121
|
+
{ id: SE_MARS, name: 'Mars' },
|
|
122
|
+
{ id: SE_JUPITER, name: 'Jupiter' },
|
|
123
|
+
{ id: SE_SATURN, name: 'Saturn' },
|
|
124
|
+
];
|
|
125
|
+
|
|
126
|
+
console.log('The Sun as seen from each planet:');
|
|
127
|
+
for (const obs of observers) {
|
|
128
|
+
const sun = swe.calcPlanetocentric(jd, SE_SUN, obs.id);
|
|
129
|
+
console.log(
|
|
130
|
+
` From ${obs.name.padEnd(8)}: ` +
|
|
131
|
+
`lon=${sun.longitude.toFixed(2).padStart(7)} deg ` +
|
|
132
|
+
`dist=${sun.distance.toFixed(4)} AU`
|
|
133
|
+
);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// For reference: the Sun from Earth (geocentric)
|
|
137
|
+
const sunGeo = swe.calc(jd, SE_SUN);
|
|
138
|
+
console.log(
|
|
139
|
+
` From Earth : ` +
|
|
140
|
+
`lon=${sunGeo.longitude.toFixed(2).padStart(7)} deg ` +
|
|
141
|
+
`dist=${sunGeo.distance.toFixed(4)} AU`
|
|
142
|
+
);
|
|
143
|
+
|
|
144
|
+
swe.close();
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
### Retrograde motion from a different planet
|
|
148
|
+
|
|
149
|
+
On Earth, Mars appears retrograde for about 2 months every ~26 months. What does Jupiter's motion look like from Mars?
|
|
150
|
+
|
|
151
|
+
```typescript
|
|
152
|
+
import { SwissEph } from '../index';
|
|
153
|
+
import { SE_JUPITER, SE_MARS } from '../../constants';
|
|
154
|
+
|
|
155
|
+
const swe = new SwissEph();
|
|
156
|
+
|
|
157
|
+
// Check Jupiter's speed as seen from Mars over two years
|
|
158
|
+
const startJd = SwissEph.julianDay(2025, 1, 1, 0);
|
|
159
|
+
|
|
160
|
+
console.log('Jupiter longitude speed as seen from Mars:');
|
|
161
|
+
for (let i = 0; i < 24; i++) {
|
|
162
|
+
const jd = startJd + i * 30;
|
|
163
|
+
const jup = swe.calcPlanetocentric(jd, SE_JUPITER, SE_MARS);
|
|
164
|
+
const date = SwissEph.fromJulianDay(jd);
|
|
165
|
+
const direction = jup.longitudeSpeed < 0 ? 'RETRO' : 'direct';
|
|
166
|
+
console.log(
|
|
167
|
+
` ${date.year}-${String(date.month).padStart(2,'0')}-${String(date.day).padStart(2,'0')} ` +
|
|
168
|
+
`speed=${jup.longitudeSpeed.toFixed(4).padStart(8)} deg/day ${direction}`
|
|
169
|
+
);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
swe.close();
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
### Multiple bodies from Jupiter
|
|
176
|
+
|
|
177
|
+
View the inner solar system from Jupiter's perspective -- all the inner planets and the Sun.
|
|
178
|
+
|
|
179
|
+
```typescript
|
|
180
|
+
import { SwissEph } from '../index';
|
|
181
|
+
import {
|
|
182
|
+
SE_SUN, SE_MERCURY, SE_VENUS, SE_EARTH, SE_MARS,
|
|
183
|
+
SE_SATURN, SE_JUPITER,
|
|
184
|
+
} from '../../constants';
|
|
185
|
+
|
|
186
|
+
const swe = new SwissEph();
|
|
187
|
+
const jd = SwissEph.julianDay(2025, 7, 4, 12);
|
|
188
|
+
|
|
189
|
+
const targets = [
|
|
190
|
+
{ id: SE_SUN, name: 'Sun' },
|
|
191
|
+
{ id: SE_MERCURY, name: 'Mercury' },
|
|
192
|
+
{ id: SE_VENUS, name: 'Venus' },
|
|
193
|
+
{ id: SE_EARTH, name: 'Earth' },
|
|
194
|
+
{ id: SE_MARS, name: 'Mars' },
|
|
195
|
+
{ id: SE_SATURN, name: 'Saturn' },
|
|
196
|
+
];
|
|
197
|
+
|
|
198
|
+
console.log('Sky from Jupiter on 2025-Jul-04:');
|
|
199
|
+
for (const t of targets) {
|
|
200
|
+
const pos = swe.calcPlanetocentric(jd, t.id, SE_JUPITER);
|
|
201
|
+
console.log(
|
|
202
|
+
` ${t.name.padEnd(8)} ` +
|
|
203
|
+
`lon=${pos.longitude.toFixed(2).padStart(7)} ` +
|
|
204
|
+
`lat=${pos.latitude.toFixed(2).padStart(6)} ` +
|
|
205
|
+
`dist=${pos.distance.toFixed(3).padStart(7)} AU`
|
|
206
|
+
);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
swe.close();
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
---
|
|
213
|
+
|
|
214
|
+
## Deep Explanation
|
|
215
|
+
|
|
216
|
+
### What "planetocentric" means
|
|
217
|
+
|
|
218
|
+
In standard (geocentric) astronomy, all positions are computed relative to the center of the Earth. The Earth is the implied observer. **Planetocentric** means the observer is at the center of a different planet. The computation is conceptually the same -- it is a coordinate transformation that shifts the origin from Earth to the specified planet.
|
|
219
|
+
|
|
220
|
+
Mathematically, if you know the heliocentric position of both the target body and the observer body, the planetocentric position is:
|
|
221
|
+
|
|
222
|
+
```
|
|
223
|
+
target_from_observer = target_heliocentric - observer_heliocentric
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
The Swiss Ephemeris then applies the same corrections it normally does (light-time, aberration, etc.) but relative to the new observer position.
|
|
227
|
+
|
|
228
|
+
### Why results differ from geocentric
|
|
229
|
+
|
|
230
|
+
When you compute Mars from Earth (geocentric) and Mars from Jupiter (Jupitocentric), you get very different results because:
|
|
231
|
+
|
|
232
|
+
1. **Different vantage point**: You are looking at Mars from a completely different position in space. The ecliptic longitude of Mars depends on the angle between the observer and Mars, which changes dramatically depending on where the observer is.
|
|
233
|
+
|
|
234
|
+
2. **Different distance**: The distance to Mars is different from Earth vs from Jupiter, which affects light-time correction and apparent position.
|
|
235
|
+
|
|
236
|
+
3. **Different retrograde patterns**: Retrograde motion is an apparent effect caused by the observer's own orbital motion. Since different planets move at different speeds and in different sized orbits, the retrograde patterns of other planets look completely different from each vantage point.
|
|
237
|
+
|
|
238
|
+
### The center parameter
|
|
239
|
+
|
|
240
|
+
The `center` parameter specifies which planet the observer is on. Use the standard planet constants:
|
|
241
|
+
|
|
242
|
+
| Constant | Value | Observer is on |
|
|
243
|
+
|----------|-------|---------------|
|
|
244
|
+
| `SE_MERCURY` | 2 | Mercury |
|
|
245
|
+
| `SE_VENUS` | 3 | Venus |
|
|
246
|
+
| `SE_EARTH` | 14 | Earth (equivalent to geocentric `calc()`) |
|
|
247
|
+
| `SE_MARS` | 4 | Mars |
|
|
248
|
+
| `SE_JUPITER` | 5 | Jupiter |
|
|
249
|
+
| `SE_SATURN` | 6 | Saturn |
|
|
250
|
+
| `SE_URANUS` | 7 | Uranus |
|
|
251
|
+
| `SE_NEPTUNE` | 8 | Neptune |
|
|
252
|
+
| `SE_PLUTO` | 9 | Pluto |
|
|
253
|
+
|
|
254
|
+
You cannot use the Sun as the center (use `SEFLG_HELCTR` in `calc()` for heliocentric positions). You also cannot use the Moon as the center because it is a satellite of Earth, not an independent heliocentric body in this context.
|
|
255
|
+
|
|
256
|
+
### Relationship to geocentric and heliocentric
|
|
257
|
+
|
|
258
|
+
The three main reference frames in positional astronomy are:
|
|
259
|
+
|
|
260
|
+
- **Heliocentric**: positions relative to the Sun's center. Pure orbital mechanics. No observer effects. Get this with `calc(jd, planet, SEFLG_HELCTR)`.
|
|
261
|
+
- **Geocentric**: positions relative to Earth's center. This is the standard for Earth-based astronomy and astrology. Get this with `calc(jd, planet)`.
|
|
262
|
+
- **Planetocentric**: positions relative to another planet's center. Get this with `calcPlanetocentric(jd, planet, center)`.
|
|
263
|
+
|
|
264
|
+
Geocentric is simply the special case of planetocentric where the center is Earth (`SE_EARTH`).
|
|
265
|
+
|
|
266
|
+
### Limitations
|
|
267
|
+
|
|
268
|
+
- Not all flag combinations may work with `calcPlanetocentric()`. The basic ecliptic coordinates are always available. Equatorial coordinates (`SEFLG_EQUATORIAL`) should work. Sidereal mode (`SEFLG_SIDEREAL`) works but uses Earth's precession/ayanamsa, not the other planet's.
|
|
269
|
+
- You cannot compute the position of a planet as seen from itself (e.g., `calcPlanetocentric(jd, SE_MARS, SE_MARS)` is meaningless and will produce zero or an error).
|
|
270
|
+
- The calculation does not account for the **topography** of the other planet -- it places the observer at the planet's center, not on its surface. There is no "topocentric from Mars" capability.
|
|
271
|
+
|
|
272
|
+
### Practical uses
|
|
273
|
+
|
|
274
|
+
**Space missions**: When a spacecraft is orbiting or approaching Mars, mission planners need to know where other bodies appear in the Martian sky. While actual mission planning uses more sophisticated tools, planetocentric calculations provide a useful first approximation.
|
|
275
|
+
|
|
276
|
+
**Astrology from other planets**: Some astrologers have experimented with computing charts for other planets -- for example, a "Martian natal chart" for a Mars rover landing. Planetocentric positions would be the basis for such a chart.
|
|
277
|
+
|
|
278
|
+
**Understanding parallax**: Comparing geocentric and planetocentric positions for the same target illustrates the concept of parallax on a solar-system scale. The Sun is at nearly the same ecliptic longitude from all planets, but the direction shifts by 180 degrees for the inner planets (because you are looking "back" toward the Sun from the other side).
|
|
@@ -0,0 +1,314 @@
|
|
|
1
|
+
# Refraction
|
|
2
|
+
|
|
3
|
+
**Atmospheric refraction** is the bending of light as it passes through Earth's atmosphere. Because the atmosphere acts like a giant lens -- denser near the ground, thinner higher up -- light from celestial objects follows a slightly curved path rather than a straight line. The result is that objects in the sky appear **higher** than they actually are.
|
|
4
|
+
|
|
5
|
+
The effect is dramatic near the horizon and negligible high in the sky:
|
|
6
|
+
|
|
7
|
+
- At the horizon (0 degrees altitude), refraction lifts an object by about **34 arcminutes** -- which is larger than the Sun's or Moon's apparent diameter (~31 arcminutes). This means that when you see the Sun sitting right on the horizon at sunset, its geometric center has actually already dropped below the horizon. The "sunset" you see is an atmospheric illusion.
|
|
8
|
+
- At 10 degrees altitude, refraction is about 5 arcminutes.
|
|
9
|
+
- At 45 degrees altitude, refraction is about 1 arcminute.
|
|
10
|
+
- At the zenith (90 degrees altitude), refraction is zero.
|
|
11
|
+
|
|
12
|
+
The Swiss Ephemeris provides a `refraction()` function to compute this correction in both directions: given the true (geometric) altitude, compute the apparent (observed) altitude, and vice versa.
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## Quick Example
|
|
17
|
+
|
|
18
|
+
```typescript
|
|
19
|
+
import { SwissEph } from '../index';
|
|
20
|
+
import { SE_TRUE_TO_APP, SE_APP_TO_TRUE } from '../../constants';
|
|
21
|
+
|
|
22
|
+
const swe = new SwissEph();
|
|
23
|
+
|
|
24
|
+
// An object at true altitude 0 degrees (geometric horizon)
|
|
25
|
+
// What apparent altitude does it appear at?
|
|
26
|
+
const apparent = swe.refraction(0, 1013.25, 15, SE_TRUE_TO_APP);
|
|
27
|
+
console.log(`True alt 0 deg -> Apparent alt: ${(apparent * 60).toFixed(1)} arcmin above horizon`);
|
|
28
|
+
// ~34.5 arcminutes
|
|
29
|
+
|
|
30
|
+
// An object observed at apparent altitude 1 degree
|
|
31
|
+
// What is its true geometric altitude?
|
|
32
|
+
const correction = swe.refraction(1, 1013.25, 15, SE_APP_TO_TRUE);
|
|
33
|
+
const trueAlt = 1 + correction; // correction is negative for APP_TO_TRUE
|
|
34
|
+
console.log(`Apparent alt 1 deg -> True alt: ${(trueAlt * 60).toFixed(1)} arcmin`);
|
|
35
|
+
|
|
36
|
+
swe.close();
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
## Detailed Examples
|
|
42
|
+
|
|
43
|
+
### True-to-apparent: how high does an object appear?
|
|
44
|
+
|
|
45
|
+
When you know the true (geometric) altitude and want to know where the object appears in the refracted sky:
|
|
46
|
+
|
|
47
|
+
```typescript
|
|
48
|
+
import { SwissEph } from '../index';
|
|
49
|
+
import { SE_TRUE_TO_APP } from '../../constants';
|
|
50
|
+
|
|
51
|
+
const swe = new SwissEph();
|
|
52
|
+
|
|
53
|
+
// Standard atmosphere: 1013.25 mbar, 15 degrees C
|
|
54
|
+
const pressure = 1013.25;
|
|
55
|
+
const temperature = 15;
|
|
56
|
+
|
|
57
|
+
console.log('True Altitude Apparent Altitude Refraction');
|
|
58
|
+
console.log('------------- ----------------- ----------');
|
|
59
|
+
|
|
60
|
+
const altitudes = [0, 0.5, 1, 2, 5, 10, 15, 20, 30, 45, 60, 90];
|
|
61
|
+
|
|
62
|
+
for (const trueAlt of altitudes) {
|
|
63
|
+
const apparentAlt = swe.refraction(trueAlt, pressure, temperature, SE_TRUE_TO_APP);
|
|
64
|
+
const refraction = apparentAlt - trueAlt;
|
|
65
|
+
console.log(
|
|
66
|
+
`${trueAlt.toFixed(1).padStart(8)} deg` +
|
|
67
|
+
`${apparentAlt.toFixed(4).padStart(14)} deg` +
|
|
68
|
+
`${(refraction * 60).toFixed(2).padStart(12)} arcmin`
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
swe.close();
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Expected approximate output:
|
|
76
|
+
|
|
77
|
+
| True Altitude | Apparent Altitude | Refraction |
|
|
78
|
+
|---------------|-------------------|-------------|
|
|
79
|
+
| 0.0 deg | 0.575 deg | 34.5 arcmin |
|
|
80
|
+
| 0.5 deg | 1.038 deg | 32.3 arcmin |
|
|
81
|
+
| 1.0 deg | 1.478 deg | 28.7 arcmin |
|
|
82
|
+
| 2.0 deg | 2.353 deg | 21.2 arcmin |
|
|
83
|
+
| 5.0 deg | 5.159 deg | 9.5 arcmin |
|
|
84
|
+
| 10.0 deg | 10.088 deg | 5.3 arcmin |
|
|
85
|
+
| 20.0 deg | 20.044 deg | 2.6 arcmin |
|
|
86
|
+
| 45.0 deg | 45.016 deg | 1.0 arcmin |
|
|
87
|
+
| 90.0 deg | 90.000 deg | 0.0 arcmin |
|
|
88
|
+
|
|
89
|
+
### Apparent-to-true: where is an object really?
|
|
90
|
+
|
|
91
|
+
When you have observed an object at a certain apparent altitude and want to know its true geometric altitude:
|
|
92
|
+
|
|
93
|
+
```typescript
|
|
94
|
+
import { SwissEph } from '../index';
|
|
95
|
+
import { SE_APP_TO_TRUE } from '../../constants';
|
|
96
|
+
|
|
97
|
+
const swe = new SwissEph();
|
|
98
|
+
|
|
99
|
+
// Standard atmosphere
|
|
100
|
+
const pressure = 1013.25;
|
|
101
|
+
const temperature = 15;
|
|
102
|
+
|
|
103
|
+
// I observed a star at apparent altitude 2 degrees.
|
|
104
|
+
// What is its true altitude?
|
|
105
|
+
const apparentAlt = 2;
|
|
106
|
+
const correction = swe.refraction(apparentAlt, pressure, temperature, SE_APP_TO_TRUE);
|
|
107
|
+
|
|
108
|
+
// For SE_APP_TO_TRUE, the function returns a negative correction value.
|
|
109
|
+
// Add it to the apparent altitude to get the true altitude.
|
|
110
|
+
const trueAlt = apparentAlt + correction;
|
|
111
|
+
|
|
112
|
+
console.log(`Observed (apparent) altitude: ${apparentAlt.toFixed(4)} deg`);
|
|
113
|
+
console.log(`Refraction correction: ${(correction * 60).toFixed(2)} arcmin`);
|
|
114
|
+
console.log(`True (geometric) altitude: ${trueAlt.toFixed(4)} deg`);
|
|
115
|
+
|
|
116
|
+
swe.close();
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
### Effect of pressure and temperature
|
|
120
|
+
|
|
121
|
+
Atmospheric refraction depends on air density, which is controlled by pressure and temperature. Higher pressure and lower temperature both mean denser air and more refraction.
|
|
122
|
+
|
|
123
|
+
```typescript
|
|
124
|
+
import { SwissEph } from '../index';
|
|
125
|
+
import { SE_TRUE_TO_APP } from '../../constants';
|
|
126
|
+
|
|
127
|
+
const swe = new SwissEph();
|
|
128
|
+
|
|
129
|
+
const trueAlt = 0; // Horizon -- where the effect is most pronounced
|
|
130
|
+
|
|
131
|
+
const conditions = [
|
|
132
|
+
{ label: 'Standard atmosphere (sea level, mild)', pressure: 1013.25, temp: 15 },
|
|
133
|
+
{ label: 'Hot sea level (tropical noon)', pressure: 1013.25, temp: 40 },
|
|
134
|
+
{ label: 'Cold sea level (arctic winter)', pressure: 1013.25, temp: -30 },
|
|
135
|
+
{ label: 'Mountain (3000m, cool)', pressure: 700, temp: 5 },
|
|
136
|
+
{ label: 'High mountain (5000m, cold)', pressure: 540, temp: -15 },
|
|
137
|
+
{ label: 'No atmosphere (vacuum)', pressure: 0, temp: 0 },
|
|
138
|
+
];
|
|
139
|
+
|
|
140
|
+
console.log('Refraction at the horizon under different conditions:');
|
|
141
|
+
console.log('');
|
|
142
|
+
|
|
143
|
+
for (const c of conditions) {
|
|
144
|
+
const apparentAlt = swe.refraction(trueAlt, c.pressure, c.temp, SE_TRUE_TO_APP);
|
|
145
|
+
const refractionArcmin = apparentAlt * 60;
|
|
146
|
+
console.log(`${c.label}`);
|
|
147
|
+
console.log(` Pressure: ${c.pressure} mbar, Temp: ${c.temp} C`);
|
|
148
|
+
console.log(` Refraction: ${refractionArcmin.toFixed(1)} arcmin`);
|
|
149
|
+
console.log('');
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
swe.close();
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
### Why sunset is later than you think
|
|
156
|
+
|
|
157
|
+
The Sun's apparent diameter is about 32 arcminutes. The standard definition of sunrise/sunset is when the Sun's upper limb touches the apparent horizon. The geometric center of the Sun at this moment is about 50 arcminutes (34' refraction + 16' solar semi-diameter) below the geometric horizon.
|
|
158
|
+
|
|
159
|
+
```typescript
|
|
160
|
+
import { SwissEph } from '../index';
|
|
161
|
+
import { SE_TRUE_TO_APP } from '../../constants';
|
|
162
|
+
|
|
163
|
+
const swe = new SwissEph();
|
|
164
|
+
|
|
165
|
+
// At standard sunset, the Sun's center is at about -0.833 degrees true altitude
|
|
166
|
+
// (-50 arcminutes: -34' refraction + -16' semi-diameter)
|
|
167
|
+
const sunsetTrueAlt = -50 / 60; // -0.833 degrees
|
|
168
|
+
|
|
169
|
+
const apparentAlt = swe.refraction(Math.abs(sunsetTrueAlt), 1013.25, 15, SE_TRUE_TO_APP);
|
|
170
|
+
console.log(`At sunset, the Sun's true altitude: ${sunsetTrueAlt.toFixed(3)} deg`);
|
|
171
|
+
console.log(`Refraction at the horizon: ${(0.575 * 60).toFixed(1)} arcmin`);
|
|
172
|
+
console.log(`Sun's semi-diameter: ~16 arcmin`);
|
|
173
|
+
console.log(`Total geometric depression at sunset: ~50 arcmin`);
|
|
174
|
+
console.log('');
|
|
175
|
+
console.log('This means the Sun is already geometrically below the horizon');
|
|
176
|
+
console.log('when you see it touching the horizon at sunset!');
|
|
177
|
+
|
|
178
|
+
// How much time does this add?
|
|
179
|
+
// The Sun moves about 1 degree per day = 4 minutes per degree
|
|
180
|
+
// 50 arcminutes = 0.833 degrees, so sunset is delayed by:
|
|
181
|
+
const delayMinutes = (50 / 60) * 4;
|
|
182
|
+
console.log(`\nSunset is delayed by approximately ${delayMinutes.toFixed(1)} minutes due to refraction`);
|
|
183
|
+
|
|
184
|
+
swe.close();
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
### Building a refraction table
|
|
188
|
+
|
|
189
|
+
```typescript
|
|
190
|
+
import { SwissEph } from '../index';
|
|
191
|
+
import { SE_TRUE_TO_APP } from '../../constants';
|
|
192
|
+
|
|
193
|
+
const swe = new SwissEph();
|
|
194
|
+
|
|
195
|
+
console.log('Refraction Table (Standard Atmosphere: 1013.25 mbar, 15 C)');
|
|
196
|
+
console.log('==========================================================');
|
|
197
|
+
console.log('True Alt (deg) Refraction (arcmin) Refraction (deg)');
|
|
198
|
+
console.log('-------------- ------------------- ----------------');
|
|
199
|
+
|
|
200
|
+
// Fine steps near the horizon, coarser steps higher up
|
|
201
|
+
const altitudes = [
|
|
202
|
+
-1, -0.5, 0, 0.25, 0.5, 0.75, 1, 1.5, 2, 3, 4, 5,
|
|
203
|
+
7, 10, 15, 20, 25, 30, 40, 50, 60, 70, 80, 90,
|
|
204
|
+
];
|
|
205
|
+
|
|
206
|
+
for (const alt of altitudes) {
|
|
207
|
+
const apparentAlt = swe.refraction(alt, 1013.25, 15, SE_TRUE_TO_APP);
|
|
208
|
+
const refraction = apparentAlt - alt;
|
|
209
|
+
console.log(
|
|
210
|
+
`${alt.toFixed(2).padStart(10)}` +
|
|
211
|
+
`${(refraction * 60).toFixed(2).padStart(18)}` +
|
|
212
|
+
`${refraction.toFixed(5).padStart(20)}`
|
|
213
|
+
);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
swe.close();
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
---
|
|
220
|
+
|
|
221
|
+
## Deep Explanation
|
|
222
|
+
|
|
223
|
+
### How refraction works physically
|
|
224
|
+
|
|
225
|
+
Earth's atmosphere is a gas whose density decreases with altitude -- dense and thick at sea level, thinning to essentially vacuum in space. When light passes from a less dense medium to a more dense medium (or through a medium with a continuous density gradient), it bends toward the denser region. This is the same principle as Snell's law of refraction, applied continuously rather than at a single surface.
|
|
226
|
+
|
|
227
|
+
A ray of light from a celestial object enters the top of the atmosphere traveling in a straight line. As it descends into progressively denser air, it curves gently downward (toward the Earth's surface). By the time it reaches the observer's eye, it is arriving at a steeper angle than it originally entered the atmosphere. The observer, tracing the light ray backward in a straight line, perceives the object as being higher in the sky than it geometrically is.
|
|
228
|
+
|
|
229
|
+
The atmosphere can be modeled as a stack of thin concentric shells, each with a slightly different refractive index. The total bending is the integral of all these small refractions. For objects high in the sky, the light passes through less atmosphere (shorter path) and at a steeper angle (less bending per layer), so refraction is small. Near the horizon, the light passes through a maximum amount of atmosphere and grazes the layers at a shallow angle, producing the largest bending.
|
|
230
|
+
|
|
231
|
+
### Bennett's formula
|
|
232
|
+
|
|
233
|
+
The Swiss Ephemeris uses a formula based on Bennett (1982) for computing refraction. For the true-to-apparent direction, the refraction R (in arcminutes) at true altitude h (in degrees) is approximately:
|
|
234
|
+
|
|
235
|
+
```
|
|
236
|
+
R = 1 / tan(h + 7.31 / (h + 4.4))
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
This gives the refraction in arcminutes for standard conditions (1013.25 mbar, 10 degrees C in Bennett's original; the Swiss Ephemeris adjusts to 15 degrees C). For non-standard pressure P (in mbar) and temperature T (in Celsius), the result is scaled:
|
|
240
|
+
|
|
241
|
+
```
|
|
242
|
+
R_actual = R * (P / 1010) * (283 / (273 + T))
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
The formula is an empirical fit, accurate to about 0.1 arcminute for altitudes above 1 degree. Below 1 degree (very near the horizon), refraction becomes increasingly unpredictable.
|
|
246
|
+
|
|
247
|
+
### SE_TRUE_TO_APP vs SE_APP_TO_TRUE
|
|
248
|
+
|
|
249
|
+
| Flag | Value | Input | Output |
|
|
250
|
+
|-------------------|-------|--------------------|----------------------------------|
|
|
251
|
+
| `SE_TRUE_TO_APP` | 0 | True (geometric) altitude | Returns the apparent (refracted) altitude |
|
|
252
|
+
| `SE_APP_TO_TRUE` | 1 | Apparent (observed) altitude | Returns a negative correction to add to apparent altitude to get true altitude |
|
|
253
|
+
|
|
254
|
+
Note the asymmetry: `SE_TRUE_TO_APP` returns the full apparent altitude directly, while `SE_APP_TO_TRUE` returns a negative correction that you add to the input:
|
|
255
|
+
|
|
256
|
+
```typescript
|
|
257
|
+
// True to apparent (direct result)
|
|
258
|
+
const apparentAlt = swe.refraction(trueAlt, P, T, SE_TRUE_TO_APP);
|
|
259
|
+
|
|
260
|
+
// Apparent to true (correction to add)
|
|
261
|
+
const correction = swe.refraction(apparentAlt, P, T, SE_APP_TO_TRUE);
|
|
262
|
+
const trueAlt = apparentAlt + correction; // correction is negative
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
### Why refraction is unreliable near the horizon
|
|
266
|
+
|
|
267
|
+
Below about 1 degree altitude, the standard refraction formula becomes increasingly inaccurate because:
|
|
268
|
+
|
|
269
|
+
1. **Temperature inversions**: Normally, air temperature decreases with altitude. But near the ground, temperature inversions (warm air above cool air) can occur, creating abnormal density profiles that bend light in unusual ways. This is the cause of **mirages** -- the shimmering "water" on hot roads, or the occasional inverted images of distant ships.
|
|
270
|
+
|
|
271
|
+
2. **Turbulence**: Near the horizon, light passes through the maximum thickness of atmosphere and encounters more turbulent layers, causing the image to shimmer and distort unpredictably.
|
|
272
|
+
|
|
273
|
+
3. **The green flash**: Under rare conditions, the differential refraction of different colors (atmospheric dispersion) produces a momentary green flash at the very top of the setting Sun. Red light is refracted less than green/blue light, so the last sliver of sunlight to disappear is skewed toward green.
|
|
274
|
+
|
|
275
|
+
4. **Ducting**: In extreme inversions, light can be "ducted" along a layer, allowing you to see objects far beyond the normal geometric horizon. This can make refraction effectively infinite at the horizon.
|
|
276
|
+
|
|
277
|
+
For these reasons, the standard refraction formula should be treated as an approximation below about 1 degree altitude, and as unreliable below about 0 degrees (below the geometric horizon). The actual refraction at any given moment depends on the specific atmospheric conditions, which vary from minute to minute.
|
|
278
|
+
|
|
279
|
+
### Standard atmosphere values
|
|
280
|
+
|
|
281
|
+
The standard values used as defaults are:
|
|
282
|
+
|
|
283
|
+
| Parameter | Standard Value | Unit |
|
|
284
|
+
|-------------|----------------|-------|
|
|
285
|
+
| Pressure | 1013.25 | mbar (= hPa) |
|
|
286
|
+
| Temperature | 15 | degrees C |
|
|
287
|
+
|
|
288
|
+
These represent average sea-level conditions (the ISA -- International Standard Atmosphere). If you set pressure to 0, the function returns 0 refraction (vacuum, no atmosphere).
|
|
289
|
+
|
|
290
|
+
Approximate pressure at altitude (assuming standard lapse rate):
|
|
291
|
+
|
|
292
|
+
| Elevation | Pressure | Refraction at horizon |
|
|
293
|
+
|-----------|----------|----------------------|
|
|
294
|
+
| Sea level | 1013 mbar | ~34 arcmin |
|
|
295
|
+
| 1000 m | 899 mbar | ~30 arcmin |
|
|
296
|
+
| 2000 m | 795 mbar | ~27 arcmin |
|
|
297
|
+
| 3000 m | 701 mbar | ~24 arcmin |
|
|
298
|
+
| 5000 m | 540 mbar | ~18 arcmin |
|
|
299
|
+
|
|
300
|
+
### Practical applications
|
|
301
|
+
|
|
302
|
+
- **Rise and set times**: The standard definition of sunrise/sunset uses -50 arcminutes for the Sun's center (-34' refraction - 16' semi-diameter) and -34 arcminutes for stars and planets. The `rise()` and `set()` methods in SwissEph already account for refraction internally.
|
|
303
|
+
|
|
304
|
+
- **Telescope pointing**: If your telescope's mount uses true (geometric) coordinates from an ephemeris, you need to add refraction to point accurately at low-altitude targets. Most modern Go-To mounts have built-in refraction correction.
|
|
305
|
+
|
|
306
|
+
- **Satellite tracking**: For low-Earth orbit satellites near the horizon, refraction must be corrected to accurately predict their apparent positions.
|
|
307
|
+
|
|
308
|
+
- **Surveying and navigation**: Celestial navigation (sextant observations) requires refraction corrections, especially for objects measured near the horizon. Traditional navigation tables include refraction corrections for this purpose.
|
|
309
|
+
|
|
310
|
+
- **Atmospheric science**: The amount of refraction at a given altitude can be used to estimate atmospheric conditions (temperature profile, density). Monitoring refraction over time can reveal changes in atmospheric structure.
|
|
311
|
+
|
|
312
|
+
### Relationship to azalt()
|
|
313
|
+
|
|
314
|
+
The `azalt()` method in SwissEph already applies refraction automatically, returning both `trueAltitude` and `apparentAltitude`. You only need the standalone `refraction()` function when you want to apply refraction corrections independently, for example when working with altitude values from external sources, when building lookup tables, or when you need fine control over the atmospheric parameters.
|