# Formula Helpers [中文](../formula.md) | [Back to README](../../../README.en.md) `formula` holds the common formulas that are unrelated to a specific date or ephemeris; they suit popular-science estimates, novel settings, and teaching demonstrations. It performs no time-scale conversion and reads no ephemeris tables: the inputs are only instantaneous or constant parameters such as temperature, wavelength, distance, aperture, and altitude. Altitude and zenith-distance conventions follow [Observing-angle semantics](sun-moon.md#observing-angle-semantics); when coordinate-layer refraction is needed, use `coord`'s [airmass](coord.md#airmass); overall accuracy and applicability are in the manual [Scope And Accuracy](accuracy.md). ## Contents - [Magnitude, synodic period and blackbody radiation](#magnitude-synodic-period-and-blackbody-radiation) - [API Reference](#api-reference) - [Blackbody and Radiation](#blackbody-and-radiation) - [Synodic Period](#synodic-period) - [Magnitude and Distance](#magnitude-and-distance) - [Distance Units](#distance-units) - [Telescope Metrics](#telescope-metrics) - [Stellar Parameter Conversions](#stellar-parameter-conversions) - [Airmass Models](#airmass-models) - [Usage examples](#usage-examples) - [Blackbody peak, total flux and stellar parameters](#blackbody-peak-total-flux-and-stellar-parameters) - [Synodic period and magnitude/distance](#synodic-period-and-magnitudedistance) - [Telescope limiting magnitude and resolution](#telescope-limiting-magnitude-and-resolution) - [Comparing airmass models](#comparing-airmass-models) - [Parameter and result conventions](#parameter-and-result-conventions) - [Units](#units) - [Time Scales](#time-scales) - [Angle Quadrants and Degree/Radian Boundaries](#angle-quadrants-and-degreeradian-boundaries) - [Zero Values and Invalid Input](#zero-values-and-invalid-input) - [Accuracy and Applicability](#accuracy-and-applicability) ## Magnitude, synodic period and blackbody radiation ```go package main import ( "fmt" "b612.me/astro/formula" ) func main() { // Empirical limiting magnitude for a 70 mm refractor at a site with naked-eye limit 6. fmt.Printf("limiting=%.6f\n", formula.LimitingMagnitudeEmpirical(70, 6)) // Synodic period of Earth and Venus. Inputs and output are days. fmt.Printf("synodic=%.6f\n", formula.SynodicPeriod(365.25636, 224.70069)) // Apparent magnitude of a Sun-like absolute-magnitude object at 100 pc. fmt.Printf("apparent=%.6f\n", formula.ApparentMagnitudeFromAbsolute(4.83, 100)) // Treat the Sun as a 5772 K blackbody; compute peak wavelength and total radiant exitance. fmt.Printf("peak=%.9em flux=%.6e\n", formula.WienPeakWavelength(5772), formula.StefanBoltzmannFlux(5772), ) } ``` Output: ```text limiting=11.000000 synodic=583.920635 apparent=9.830000 peak=5.020394932e-07m flux=6.293859e+07 ``` ## API Reference The interfaces, units, and return values are listed below by what is computed. The group snippets omit shared preamble: `fmt` is imported at the top of the file, and `formula` means `b612.me/astro/formula`. ### Blackbody and Radiation | Name | Purpose | Units and conventions | | --- | --- | --- | | `PlanckRadianceByWavelength` | Planck spectral radiance by wavelength | wavelength meters, temperature K; returns W·sr⁻¹·m⁻³; non-positive temperature or wavelength returns NaN | | `WienPeakWavelength` | Wien displacement peak wavelength | temperature K; returns meters; temperature `≤ 0` or non-finite returns NaN | | `StefanBoltzmannFlux` | total radiant exitance per unit area | temperature K; returns W/m²; `0 K` is valid and returns `0` | | `SolarEffectiveTemperature` | built-in solar effective temperature constant | no arguments; returns K, currently `5772` | ```go // Treat the Sun as a 5772 K blackbody: peak wavelength, total exitance, and spectral radiance at 500 nm. tSun := formula.SolarEffectiveTemperature() fmt.Printf("peak=%.9e m flux=%.6e W/m^2\n", formula.WienPeakWavelength(tSun), formula.StefanBoltzmannFlux(tSun)) fmt.Printf("radiance@500nm=%.6e W·sr^-1·m^-3\n", formula.PlanckRadianceByWavelength(500e-9, tSun)) ``` ### Synodic Period | Name | Purpose | Units and conventions | | --- | --- | --- | | `SynodicPeriod` | synodic period of two orbiting bodies | both inputs must share one unit and the output uses it; a period `≤ 0` or non-finite returns NaN, equal periods return `+Inf` | ```go // Synodic periods of Earth with other planets; inputs and outputs are days. earth := 365.25636 fmt.Printf("venus=%.6f mars=%.6f jupiter=%.6f\n", formula.SynodicPeriod(earth, 224.70069), formula.SynodicPeriod(earth, 686.980), formula.SynodicPeriod(earth, 4332.589)) ``` ### Magnitude and Distance | Name | Purpose | Units and conventions | | --- | --- | --- | | `DistanceModulus` | distance modulus | distance pc; returns `m − M`; it is `0` at `10 pc`, and a distance `≤ 0` returns NaN | | `ApparentMagnitudeFromAbsolute` | absolute magnitude plus distance to apparent magnitude | magnitude mag, distance pc; equals `M + distance modulus` | | `AbsoluteMagnitudeFromApparent` | apparent magnitude plus distance to absolute magnitude | magnitude mag, distance pc; equals `m − distance modulus` | ```go // Sun-like absolute magnitude 4.83 placed at 10 pc / 100 pc / 1 kpc, and the inverse. for _, d := range []float64{10, 100, 1000} { m := formula.ApparentMagnitudeFromAbsolute(4.83, d) fmt.Printf("d=%.0f pc m=%.6f M=%.6f mod=%.6f\n", d, m, formula.AbsoluteMagnitudeFromApparent(m, d), formula.DistanceModulus(d)) } ``` ### Distance Units | Name | Purpose | Units and convention | | --- | --- | --- | | `Distance` | Converts parsecs, light-years or astronomical units to parsecs | A positive value plus a `DistanceUnit`; non-positive values, NaN and unknown units return NaN | | Constant | Meaning | | --- | --- | | `DistanceParsec` | Parsecs, an identity conversion | | `DistanceLightYear` | Light-years | | `DistanceAU` | Astronomical units | ```go // Sirius has a parallax of 0.375 arcseconds, i.e. 2.667 pc or 8.70 light-years. pc := formula.Distance(1/0.375, formula.DistanceParsec) fmt.Printf("%.3f pc = %.2f ly\n", pc, formula.Distance(pc, formula.DistanceParsec)/formula.Distance(1, formula.DistanceLightYear)) ``` Convention: the astronomical unit is `149597870.7` km, the light-year is the IAU defined `9460730472580.8` km, and the parsec follows from the exact relation `648000/π` astronomical units, giving `1 pc = 3.261563777 ly`. ### Telescope Metrics | Name | Purpose | Units and conventions | | --- | --- | --- | | `DawesLimitArcsec` | Dawes resolution limit | aperture mm; returns arcseconds from the empirical `116 / D` | | `RayleighLimitArcsec` | Rayleigh resolution limit | aperture mm; returns arcseconds from the empirical `138.4 / D` | | `LightGatheringPowerRatio` | light-gathering power ratio | two apertures in mm; returns `(D1 / D2)²`, dimensionless | | `LimitingMagnitudeEmpirical` | empirical limiting magnitude | aperture mm, naked-eye limit mag; estimated as `naked-eye limit + 5·log10(D / 7)`, with 7 mm as the built-in dark-adapted pupil | ```go // 70 mm refractor: resolution limits, light grasp relative to a 7 mm dark-adapted pupil, and empirical limit at naked-eye limit 6. fmt.Printf("dawes=%.6f rayleigh=%.6f\n", formula.DawesLimitArcsec(70), formula.RayleighLimitArcsec(70)) fmt.Printf("power=%.6f limiting=%.6f\n", formula.LightGatheringPowerRatio(70, 7), formula.LimitingMagnitudeEmpirical(70, 6)) ``` ### Stellar Parameter Conversions | Name | Purpose | Units and conventions | | --- | --- | --- | | `LuminosityFromRadiusTemperature` | radius plus temperature to luminosity | radius meters, temperature K; returns W via `4πR²σT⁴` | | `LuminositySolarFromRadiusTemperature` | same, solar units | radius R☉, temperature K; returns L☉ | | `RadiusFromLuminosityTemperature` | luminosity plus temperature to radius | luminosity W, temperature K; returns meters | | `RadiusSolarFromLuminosityTemperature` | same, solar units | luminosity L☉, temperature K; returns R☉ | | `EffectiveTemperatureFromLuminosityRadius` | luminosity plus radius to effective temperature | luminosity W, radius meters; returns K | | `EffectiveTemperatureFromLuminositySolarRadius` | same, solar units | luminosity L☉, radius R☉; returns K | | `SolarEffectiveTemperature` | built-in solar effective temperature | no arguments; returns K | ```go // A 2.5 R☉, 20 L☉ main-sequence star: solve for temperature, then recompute luminosity and radius. t := formula.EffectiveTemperatureFromLuminositySolarRadius(20, 2.5) fmt.Printf("Teff=%.6f K\n", t) fmt.Printf("L=%.6f Lsun R=%.6f Rsun\n", formula.LuminositySolarFromRadiusTemperature(2.5, t), formula.RadiusSolarFromLuminosityTemperature(20, t)) // The MKS version of the same quantities; the solar radius is the built-in constant 6.957e8 m. rM := 2.5 * 6.957e8 lW := formula.LuminosityFromRadiusTemperature(rM, t) fmt.Printf("L=%.6e W R=%.6e m Teff=%.6f K\n", lW, formula.RadiusFromLuminosityTemperature(lW, t), formula.EffectiveTemperatureFromLuminosityRadius(lW, rM)) ``` ### Airmass Models | Name | Purpose | Units and conventions | | --- | --- | --- | | `AirmassPlaneParallel` | plane-parallel model | true altitude in degrees; equivalent to `sec(z)`, returns `+Inf` at `0°` | | `AirmassPlaneParallelByZenithDistance` | plane-parallel model by zenith distance | zenith distance in degrees; returns `+Inf` at `90°` | | `AirmassKastenYoung` | Kasten-Young 1989 | apparent altitude in degrees; more robust than `sec(z)` at low altitude | | `AirmassPickering` | Pickering 2002 | apparent altitude in degrees; intended for low-altitude correction | All four limit the input to `[0,90]` and return NaN outside that range or for non-finite input; altitude is measured from the horizon at `0°` to the zenith at `+90°`, zenith distance is its complement, and the convention is described under [Observing-angle semantics](sun-moon.md#observing-angle-semantics). ```go fmt.Println(formula.AirmassPlaneParallel(30)) fmt.Println(formula.AirmassKastenYoung(5)) fmt.Println(formula.AirmassPickering(5)) fmt.Println(formula.AirmassPlaneParallelByZenithDistance(60)) ``` If coordinate-layer refraction correction is not needed, `formula` also provides the three airmass models directly, with more direct input semantics: - `AirmassPlaneParallel`: true altitude input, equivalent to the geometric `sec(z)` approximation - `AirmassPlaneParallelByZenithDistance`: zenith-distance input - `AirmassKastenYoung` / `AirmassPickering`: apparent-altitude input, no automatic refraction correction ## Usage examples ### Blackbody peak, total flux and stellar parameters ```go fmt.Println(formula.WienPeakWavelength(5772)) // peak wavelength (metres) fmt.Println(formula.StefanBoltzmannFlux(5772)) // flux per unit area (W/m^2) fmt.Println(formula.RadiusSolarFromLuminosityTemperature(1, 5772)) // radius from luminosity and temperature fmt.Println(formula.EffectiveTemperatureFromLuminositySolarRadius(1, 1)) // temperature from luminosity and radius ``` ```text 5.020394932432432e-07 6.293859246828887e+07 1.0000011882005775 5772.003429145848 ``` The three conversions invert each other and return the input under one convention (the `1 -> 1.0000012` and `5772 -> 5772.0034` residuals come from both sides rounding to 5772 K); the `...Solar` variants use solar units and the plain ones use SI. ### Synodic period and magnitude/distance ```go fmt.Println(formula.SynodicPeriod(365.25636, 224.70069)) // Earth and Venus (days) fmt.Println(formula.DistanceModulus(10)) // distance modulus at 10 pc fmt.Println(formula.ApparentMagnitudeFromAbsolute(4.83, 100)) // absolute magnitude 4.83 seen from 100 pc fmt.Println(formula.AbsoluteMagnitudeFromApparent(4.83, 100)) // the inverse conversion ``` ```text 583.9206352820089 0 9.83 -0.16999999999999993 ``` `DistanceModulus(10)` is 0 because 10 pc is the defining distance of absolute magnitude; synodic periods take and return days, and the argument order does not matter. ### Telescope limiting magnitude and resolution ```go fmt.Println(formula.DawesLimitArcsec(70), formula.RayleighLimitArcsec(70)) // both resolution limits at 70 mm fmt.Println(formula.LightGatheringPowerRatio(200, 70)) // 200 mm against 70 mm fmt.Println(formula.LimitingMagnitudeEmpirical(70, 6)) // limiting magnitude at 70 mm with a naked-eye limit of 6 ``` ```text 1.6571428571428573 1.9771428571428573 8.16326530612245 11 ``` Dawes and Rayleigh differ by a coefficient (1.66" versus 1.98" at 70 mm), so state which one a report uses; the second argument of `LimitingMagnitudeEmpirical` is the naked-eye limit of the site and changes with it. ### Comparing airmass models ```go for _, alt := range []float64{5, 30, 60, 90} { fmt.Printf("alt=%.0f KY=%.6f Pickering=%.6f plane=%.6f\n", alt, formula.AirmassKastenYoung(alt), formula.AirmassPickering(alt), formula.AirmassPlaneParallel(alt)) } ``` ```text alt=5 KY=10.305791 Pickering=10.333706 plane=11.473713 alt=30 KY=1.994293 Pickering=1.993154 plane=2.000000 alt=60 KY=1.153992 Pickering=1.154058 plane=1.154701 alt=90 KY=0.999712 Pickering=1.000000 plane=1.000000 ``` The three models nearly coincide at moderate and high altitude and differ most at 5 degrees (Kasten-Young against the plane-parallel model is about 1.2 airmasses); the plane-parallel model diverges at 0 degrees, so use Kasten-Young or Pickering for careful low-altitude work. Pressure- and temperature-corrected versions live in [Coordinate tools](coord.md#airmass) and this package keeps the raw formulas. ## Parameter and result conventions ### Units - Blackbody family: wavelength meters, temperature kelvin; `PlanckRadianceByWavelength` returns spectral radiance `W·sr⁻¹·m⁻³`, `StefanBoltzmannFlux` returns `W/m²`, and `WienPeakWavelength` returns meters. - Stellar family: the MKS variants use radius meters, luminosity watts, and temperature kelvin; the Solar variants use solar radius R☉, solar luminosity L☉, and temperature kelvin, and both inputs and outputs are dimensionless solar multiples. - Magnitude family: distance parsecs, magnitude mag; `DistanceModulus` returns `m − M`, also in mag. - Distance units: `Distance` performs unit conversion only; the input unit comes from `DistanceUnit` and the return value is always parsecs. - Telescope family: aperture millimeters; `DawesLimitArcsec` and `RayleighLimitArcsec` return **arcseconds**, not degrees; `LightGatheringPowerRatio` and `LimitingMagnitudeEmpirical` return a dimensionless ratio and a magnitude respectively. - Airmass family: altitude (or zenith distance) in degrees; the return value is the dimensionless relative airmass with 1 at the zenith. - Synodic period: the unit is chosen by the caller, both inputs must match, and the output matches them; the package does not assume days. - This package produces no apparent diameter or apparent radius. Apparent-radius fields in the eclipse and occultation manuals are in arcseconds; here only the two Dawes/Rayleigh limits use arcseconds while all other angles are degrees, so do not interchange them. ### Time Scales - No entry point accepts an instant or performs any time-scale conversion: the formulas depend only on parameters such as temperature, wavelength, distance, aperture, and altitude, and are independent of UTC, UT1, and TT. - The synodic period is a length of time, not the instant of the next conjunction. Landing on a date requires the conjunction APIs in the planet packages plus civil time, whose convention is in the manual [Time Scale Conventions](timescale.md). - The package has no ΔT, leap-second, or UT1 entry point; those only appear in instant-dependent chains such as `coord`, `eclipse`, and `moon`. ### Angle Quadrants and Degree/Radian Boundaries - All angle parameters are degrees, are converted to radians internally, and come back as degrees or arcseconds; radians never leak to the caller. - Altitude and zenith distance are both limited to `[0,90]`: the horizon is `0°`, the zenith is `+90°`, and zenith distance is the complement of altitude. The package performs no quadrant folding, so a negative altitude (below the horizon) is simply invalid and is never folded to the zenith or replaced by an absolute value. - Zenith distance `z` and altitude `h` satisfy `z = 90° − h`; `AirmassPlaneParallel` takes `h` and `AirmassPlaneParallelByZenithDistance` takes `z`, and both must agree for the same geometry. - Dawes/Rayleigh return arcseconds; divide by 3600 to compare with the degree-based angles in the other manuals. ### Zero Values and Invalid Input - The blackbody family deliberately treats invalid input differently: `WienPeakWavelength` and `PlanckRadianceByWavelength` return NaN for temperature `≤ 0` or non-finite, while `StefanBoltzmannFlux` only returns NaN for temperature `< 0` or non-finite, so `0 K` is valid and returns `0` (a 0 K body has zero flux, while its peak wavelength is undefined). - Synodic period: either period `≤ 0` or non-finite returns NaN; equal periods make the frequency difference zero and return `+Inf`. - Magnitude family: `distanceParsec ≤ 0` or non-finite makes `DistanceModulus` return NaN, and the two conversion functions then return NaN as well; `DistanceModulus(10)` is always `0`. - Telescope family: an aperture (or the second aperture) `≤ 0` or non-finite returns NaN; a zero second aperture in `LightGatheringPowerRatio` is rejected as invalid rather than dividing by zero; `LimitingMagnitudeEmpirical` takes no pupil argument, and 7 mm is a built-in constant. - Stellar family: every input must be `> 0` or the function returns NaN; `EffectiveTemperatureFromLuminositySolarRadius`, `LuminositySolarFromRadiusTemperature`, and `RadiusSolarFromLuminosityTemperature` convert solar units to SI before computing. - Airmass family: an altitude or zenith distance outside `[0,90]` (including negative values) or non-finite returns NaN; `AirmassPlaneParallel(0)` and `AirmassPlaneParallelByZenithDistance(90)` return `+Inf`, while `AirmassKastenYoung(0)` and `AirmassPickering(0)` stay finite. - The package has no `(value, error)` or `(value, ok)` returns: invalid input is always expressed as NaN, which the caller checks with `math.IsNaN`. ### Accuracy and Applicability - The blackbody family is an ideal-blackbody model with no absorption lines, interstellar extinction, or atmospheric extinction. `WienPeakWavelength` uses the Wien displacement constant `b = 2.897771955e-3 m·K`; because the per-frequency and per-wavelength peak conventions differ, `b/T` is strictly the peak in the wavelength convention. - Constant conventions: `h = 6.62607015e-34 J·s`, `c = 299792458 m/s`, `k = 1.380649e-23 J/K`, `σ = 5.670374419e-8 W·m⁻²·K⁻⁴`; solar parameters `L☉ = 3.828e26 W`, `R☉ = 6.957e8 m`, `Teff = 5772 K`, the last exposed through `SolarEffectiveTemperature`. - The magnitude family assumes no extinction, no K-correction, and no cosmological term; the two conversion functions merely add or subtract `DistanceModulus`, so their accuracy is entirely that of the externally supplied absolute magnitude and distance. - The telescope family contains visible-light empirical values: Dawes and Rayleigh use fixed coefficients (`116` and `138.4`, aperture in mm) and do not vary with wavelength; `LightGatheringPowerRatio` compares aperture squares only and ignores central obstruction, transmission, and secondary-mirror losses; `LimitingMagnitudeEmpirical` ignores sky background, magnification, transmission, and observer skill. - The stellar family solves `L = 4πR²σT⁴` in both directions, assuming spherical symmetry with no limb-darkening correction, rotation, or magnetic effects; the Solar and MKS variants share the same solar constants, so any difference between them comes only from that constant convention. - Airmass family: the plane-parallel model is purely geometric `sec(z)`, usable only at moderate and high altitude, and it diverges near the horizon; Kasten-Young (1989) and Pickering (2002) are empirical fits that agree at moderate altitude and differ most near the horizon. With an apparent altitude already in hand, call `AirmassKastenYoung` / `AirmassPickering` directly; with only a true altitude plus refraction, use `coord`'s [airmass](coord.md#airmass). - Every function in this package is a stateless pure function: it caches nothing and reads no global time-scale state, so it can be called in any order and, with caller-side synchronization, concurrently.