feat: 扩展天文计算能力
- 新增日食、月食、本地可见性、中心线、半影区域、SVG 图示与沙罗周期信息 - 新增行星冲合、留、方照、物理星历、视直径、相位、亮肢角、轨道节点等计算 - 新增木星伽利略卫星位置、现象与接触事件计算 - 新增恒星星表、星座判定、自行修正与观测辅助能力 - 新增 coord、formula、orbit、sundial、lite/sun、lite/moon 等扩展包 - 完善农历年号、月相英文别名、视差角、大气质量、折射、日晷与双星计算 - 增加 NASA、JPL Horizons、IMCCE 等回归测试数据与基线测试 - 重构基础算法文件组织,补充大量公开 API 注释和语义回归测试 - 更新中文和英文 README,补充示例、精度说明、SVG 配图
This commit is contained in:
@@ -0,0 +1,60 @@
|
||||
package formula
|
||||
|
||||
import "math"
|
||||
|
||||
// AirmassPlaneParallel 平行平板大气模型 / plane-parallel airmass.
|
||||
//
|
||||
// altitude 为真高度角,单位度。该模型等价于 sec(z),其中 z 为天顶距。
|
||||
// 中高空可作几何近似;接近地平线时会发散,不宜用于低空精细估算。
|
||||
// altitude is true altitude in degrees. The model is sec(z) with zenith
|
||||
// distance z = 90° - altitude. It is a geometric approximation that diverges
|
||||
// near the horizon.
|
||||
func AirmassPlaneParallel(altitude float64) float64 {
|
||||
if !isFinitePhotometry(altitude) || altitude < 0 || altitude > 90 {
|
||||
return math.NaN()
|
||||
}
|
||||
if altitude == 0 {
|
||||
return math.Inf(1)
|
||||
}
|
||||
return 1 / math.Sin(altitude*math.Pi/180)
|
||||
}
|
||||
|
||||
// AirmassPlaneParallelByZenithDistance 按天顶距的平行平板大气质量 / plane-parallel airmass by zenith distance.
|
||||
func AirmassPlaneParallelByZenithDistance(zenithDistance float64) float64 {
|
||||
if !isFinitePhotometry(zenithDistance) || zenithDistance < 0 || zenithDistance > 90 {
|
||||
return math.NaN()
|
||||
}
|
||||
if zenithDistance == 90 {
|
||||
return math.Inf(1)
|
||||
}
|
||||
return 1 / math.Cos(zenithDistance*math.Pi/180)
|
||||
}
|
||||
|
||||
// AirmassKastenYoung Kasten-Young 1989 大气质量模型 / Kasten-Young 1989 airmass.
|
||||
//
|
||||
// apparentAltitude 为视高度角,单位度。该经验公式在低空通常比 sec(z) 更稳健。
|
||||
// apparentAltitude is apparent altitude in degrees. This empirical model is
|
||||
// generally more robust than sec(z) at low altitude.
|
||||
func AirmassKastenYoung(apparentAltitude float64) float64 {
|
||||
if !isFinitePhotometry(apparentAltitude) || apparentAltitude < 0 || apparentAltitude > 90 {
|
||||
return math.NaN()
|
||||
}
|
||||
return 1 / (math.Sin(apparentAltitude*math.Pi/180) + 0.50572*math.Pow(apparentAltitude+6.07995, -1.6364))
|
||||
}
|
||||
|
||||
// AirmassPickering Pickering 2002 大气质量模型 / Pickering 2002 airmass.
|
||||
//
|
||||
// apparentAltitude 为视高度角,单位度。该经验公式专门面向低空观测修正。
|
||||
// apparentAltitude is apparent altitude in degrees. This empirical model is
|
||||
// intended for low-altitude observational use.
|
||||
func AirmassPickering(apparentAltitude float64) float64 {
|
||||
if !isFinitePhotometry(apparentAltitude) || apparentAltitude < 0 || apparentAltitude > 90 {
|
||||
return math.NaN()
|
||||
}
|
||||
correctedAltitude := apparentAltitude + 244/(165+47*math.Pow(apparentAltitude, 1.1))
|
||||
return 1 / math.Sin(correctedAltitude*math.Pi/180)
|
||||
}
|
||||
|
||||
func isFinitePhotometry(value float64) bool {
|
||||
return !math.IsNaN(value) && !math.IsInf(value, 0)
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package formula
|
||||
|
||||
import (
|
||||
"math"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestAirmassModels(t *testing.T) {
|
||||
assertFormulaClose(t, "AirmassPlaneParallel(90)", AirmassPlaneParallel(90), 1, 1e-15)
|
||||
assertFormulaClose(t, "AirmassPlaneParallel(30)", AirmassPlaneParallel(30), 2, 1e-15)
|
||||
if !math.IsInf(AirmassPlaneParallel(0), 1) {
|
||||
t.Fatal("expected plane-parallel airmass at horizon to be +Inf")
|
||||
}
|
||||
|
||||
assertFormulaClose(t, "AirmassPlaneParallelByZenithDistance(0)", AirmassPlaneParallelByZenithDistance(0), 1, 1e-15)
|
||||
assertFormulaClose(t, "AirmassPlaneParallelByZenithDistance(60)", AirmassPlaneParallelByZenithDistance(60), 2, 1e-12)
|
||||
if !math.IsInf(AirmassPlaneParallelByZenithDistance(90), 1) {
|
||||
t.Fatal("expected sec(z) at z=90 to be +Inf")
|
||||
}
|
||||
|
||||
assertFormulaClose(t, "AirmassKastenYoung(90)", AirmassKastenYoung(90), 0.9997119918558381, 1e-15)
|
||||
assertFormulaClose(t, "AirmassKastenYoung(30)", AirmassKastenYoung(30), 1.9942928525292503, 1e-15)
|
||||
assertFormulaClose(t, "AirmassKastenYoung(0)", AirmassKastenYoung(0), 37.91960837783633, 1e-12)
|
||||
|
||||
assertFormulaClose(t, "AirmassPickering(90)", AirmassPickering(90), 1.000000196171337, 1e-15)
|
||||
assertFormulaClose(t, "AirmassPickering(30)", AirmassPickering(30), 1.9931538464145713, 1e-15)
|
||||
assertFormulaClose(t, "AirmassPickering(0)", AirmassPickering(0), 38.749398755780355, 1e-12)
|
||||
}
|
||||
|
||||
func TestAirmassInvalidInput(t *testing.T) {
|
||||
for name, value := range map[string]float64{
|
||||
"plane-parallel negative altitude": AirmassPlaneParallel(-1),
|
||||
"plane-parallel >90 altitude": AirmassPlaneParallel(91),
|
||||
"plane-parallel zenith <0": AirmassPlaneParallelByZenithDistance(-1),
|
||||
"plane-parallel zenith >90": AirmassPlaneParallelByZenithDistance(91),
|
||||
"kasten-young negative altitude": AirmassKastenYoung(-1),
|
||||
"pickering >90 altitude": AirmassPickering(91),
|
||||
} {
|
||||
if !math.IsNaN(value) {
|
||||
t.Fatalf("%s should be NaN, got %.15f", name, value)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
// Package formula 提供与具体时刻、星历表无关的研究型天文公式。
|
||||
package formula
|
||||
|
||||
import "math"
|
||||
|
||||
const (
|
||||
planckConstant = 6.62607015e-34
|
||||
speedOfLight = 299792458.0
|
||||
boltzmannConstant = 1.380649e-23
|
||||
stefanBoltzmannConstant = 5.670374419e-8
|
||||
wienDisplacementConstant = 2.897771955e-3
|
||||
)
|
||||
|
||||
// WienPeakWavelength 维恩峰值波长 / Wien peak wavelength.
|
||||
//
|
||||
// temperatureK: 黑体温度,单位开尔文
|
||||
//
|
||||
// 返回:
|
||||
//
|
||||
// 峰值波长,单位米
|
||||
func WienPeakWavelength(temperatureK float64) float64 {
|
||||
if temperatureK <= 0 || math.IsNaN(temperatureK) || math.IsInf(temperatureK, 0) {
|
||||
return math.NaN()
|
||||
}
|
||||
return wienDisplacementConstant / temperatureK
|
||||
}
|
||||
|
||||
// StefanBoltzmannFlux 斯特藩-玻尔兹曼通量 / Stefan-Boltzmann flux.
|
||||
//
|
||||
// temperatureK: 黑体温度,单位开尔文
|
||||
//
|
||||
// 返回:
|
||||
//
|
||||
// 单位面积总出射度,单位 W/m^2
|
||||
func StefanBoltzmannFlux(temperatureK float64) float64 {
|
||||
if temperatureK < 0 || math.IsNaN(temperatureK) || math.IsInf(temperatureK, 0) {
|
||||
return math.NaN()
|
||||
}
|
||||
return stefanBoltzmannConstant * math.Pow(temperatureK, 4)
|
||||
}
|
||||
|
||||
// PlanckRadianceByWavelength 按波长的普朗克谱辐亮度 / Planck spectral radiance by wavelength.
|
||||
//
|
||||
// wavelengthM: 波长,单位米
|
||||
// temperatureK: 黑体温度,单位开尔文
|
||||
//
|
||||
// 返回:
|
||||
//
|
||||
// 谱辐亮度,单位 W·sr^-1·m^-3
|
||||
//
|
||||
// 例:
|
||||
//
|
||||
// b := formula.PlanckRadianceByWavelength(500e-9, 5772)
|
||||
func PlanckRadianceByWavelength(wavelengthM, temperatureK float64) float64 {
|
||||
if wavelengthM <= 0 || temperatureK <= 0 ||
|
||||
math.IsNaN(wavelengthM) || math.IsInf(wavelengthM, 0) ||
|
||||
math.IsNaN(temperatureK) || math.IsInf(temperatureK, 0) {
|
||||
return math.NaN()
|
||||
}
|
||||
|
||||
exponent := planckConstant * speedOfLight / (wavelengthM * boltzmannConstant * temperatureK)
|
||||
denominator := math.Expm1(exponent)
|
||||
if denominator == 0 {
|
||||
return math.Inf(1)
|
||||
}
|
||||
return 2 * planckConstant * speedOfLight * speedOfLight / math.Pow(wavelengthM, 5) / denominator
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
package formula
|
||||
|
||||
import (
|
||||
"math"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func assertFormulaClose(t *testing.T, name string, got, want, tolerance float64) {
|
||||
t.Helper()
|
||||
if math.Abs(got-want) > tolerance {
|
||||
t.Fatalf("%s mismatch: got %.15f want %.15f", name, got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBlackbodyFormulas(t *testing.T) {
|
||||
assertFormulaClose(t, "WienPeakWavelength", WienPeakWavelength(5772), 5.020394931568954e-07, 1e-15)
|
||||
assertFormulaClose(t, "StefanBoltzmannFlux", StefanBoltzmannFlux(5772), 6.293859246828887e+07, 1e-6)
|
||||
assertFormulaClose(t, "PlanckRadianceByWavelength", PlanckRadianceByWavelength(500e-9, 5772), 2.6238540568595848e+13, 1e-1)
|
||||
|
||||
if !math.IsNaN(WienPeakWavelength(0)) {
|
||||
t.Fatal("expected WienPeakWavelength(0) to be NaN")
|
||||
}
|
||||
}
|
||||
|
||||
func TestPhotometryFormulas(t *testing.T) {
|
||||
assertFormulaClose(t, "DistanceModulus(10pc)", DistanceModulus(10), 0, 1e-15)
|
||||
assertFormulaClose(t, "DistanceModulus(100pc)", DistanceModulus(100), 5, 1e-15)
|
||||
assertFormulaClose(t, "ApparentMagnitudeFromAbsolute", ApparentMagnitudeFromAbsolute(4.83, 100), 9.83, 1e-15)
|
||||
assertFormulaClose(t, "AbsoluteMagnitudeFromApparent", AbsoluteMagnitudeFromApparent(9.83, 100), 4.83, 1e-12)
|
||||
}
|
||||
|
||||
func TestStellarParameterFormulas(t *testing.T) {
|
||||
luminosity := LuminosityFromRadiusTemperature(2.5*solarRadiusM, 9000)
|
||||
radius := RadiusFromLuminosityTemperature(luminosity, 9000)
|
||||
temperature := EffectiveTemperatureFromLuminosityRadius(luminosity, 2.5*solarRadiusM)
|
||||
assertFormulaClose(t, "RadiusFromLuminosityTemperature", radius, 2.5*solarRadiusM, 1e-4)
|
||||
assertFormulaClose(t, "EffectiveTemperatureFromLuminosityRadius", temperature, 9000, 1e-9)
|
||||
|
||||
luminositySolar := LuminositySolarFromRadiusTemperature(2.5, 9000)
|
||||
radiusSolar := RadiusSolarFromLuminosityTemperature(luminositySolar, 9000)
|
||||
temperatureSolar := EffectiveTemperatureFromLuminositySolarRadius(luminositySolar, 2.5)
|
||||
assertFormulaClose(t, "RadiusSolarFromLuminosityTemperature", radiusSolar, 2.5, 1e-12)
|
||||
assertFormulaClose(t, "EffectiveTemperatureFromLuminositySolarRadius", temperatureSolar, 9000, 1e-9)
|
||||
assertFormulaClose(t, "SolarEffectiveTemperature", SolarEffectiveTemperature(), 5772, 1e-12)
|
||||
}
|
||||
|
||||
func TestSynodicPeriod(t *testing.T) {
|
||||
assertFormulaClose(t, "Earth-Venus synodic period", SynodicPeriod(365.25636, 224.70069), 583.9206352820089, 1e-9)
|
||||
if !math.IsInf(SynodicPeriod(365.25636, 365.25636), 1) {
|
||||
t.Fatal("expected equal periods to yield +Inf synodic period")
|
||||
}
|
||||
}
|
||||
|
||||
func TestTelescopeFormulas(t *testing.T) {
|
||||
assertFormulaClose(t, "LightGatheringPowerRatio", LightGatheringPowerRatio(200, 100), 4, 1e-15)
|
||||
assertFormulaClose(t, "DawesLimitArcsec", DawesLimitArcsec(100), 1.16, 1e-15)
|
||||
assertFormulaClose(t, "RayleighLimitArcsec", RayleighLimitArcsec(100), 1.384, 1e-15)
|
||||
assertFormulaClose(t, "LimitingMagnitudeEmpirical", LimitingMagnitudeEmpirical(70, 6), 11, 1e-15)
|
||||
|
||||
if !math.IsNaN(LightGatheringPowerRatio(0, 100)) {
|
||||
t.Fatal("expected invalid aperture to produce NaN")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package formula
|
||||
|
||||
import "math"
|
||||
|
||||
// SynodicPeriod 会合周期 / synodic period.
|
||||
//
|
||||
// period1: 第一个天体的恒星周期或朔望周期,单位自定,但必须与 period2 一致
|
||||
// period2: 第二个天体的周期,单位需与 period1 一致
|
||||
//
|
||||
// 返回:
|
||||
//
|
||||
// 会合周期,单位与输入相同
|
||||
//
|
||||
// 例:
|
||||
//
|
||||
// // 地球与金星的会合周期,单位天
|
||||
// s := formula.SynodicPeriod(365.25636, 224.70069)
|
||||
func SynodicPeriod(period1, period2 float64) float64 {
|
||||
if period1 <= 0 || period2 <= 0 ||
|
||||
math.IsNaN(period1) || math.IsInf(period1, 0) ||
|
||||
math.IsNaN(period2) || math.IsInf(period2, 0) {
|
||||
return math.NaN()
|
||||
}
|
||||
frequencyDiff := math.Abs(1/period1 - 1/period2)
|
||||
if frequencyDiff == 0 {
|
||||
return math.Inf(1)
|
||||
}
|
||||
return 1 / frequencyDiff
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package formula
|
||||
|
||||
import "math"
|
||||
|
||||
// DistanceModulus 距离模数 / distance modulus.
|
||||
//
|
||||
// distanceParsec: 天体距离,单位秒差距 pc
|
||||
//
|
||||
// 返回:
|
||||
//
|
||||
// 距离模数 m-M
|
||||
func DistanceModulus(distanceParsec float64) float64 {
|
||||
if distanceParsec <= 0 || math.IsNaN(distanceParsec) || math.IsInf(distanceParsec, 0) {
|
||||
return math.NaN()
|
||||
}
|
||||
return 5 * math.Log10(distanceParsec/10)
|
||||
}
|
||||
|
||||
// ApparentMagnitudeFromAbsolute 由绝对星等求视星等 / apparent magnitude from absolute magnitude.
|
||||
//
|
||||
// absoluteMagnitude: 绝对星等 M
|
||||
// distanceParsec: 天体距离,单位秒差距 pc
|
||||
//
|
||||
// 返回:
|
||||
//
|
||||
// 视星等 m
|
||||
func ApparentMagnitudeFromAbsolute(absoluteMagnitude, distanceParsec float64) float64 {
|
||||
modulus := DistanceModulus(distanceParsec)
|
||||
if math.IsNaN(modulus) {
|
||||
return math.NaN()
|
||||
}
|
||||
return absoluteMagnitude + modulus
|
||||
}
|
||||
|
||||
// AbsoluteMagnitudeFromApparent 由视星等求绝对星等 / absolute magnitude from apparent magnitude.
|
||||
//
|
||||
// apparentMagnitude: 视星等 m
|
||||
// distanceParsec: 天体距离,单位秒差距 pc
|
||||
//
|
||||
// 返回:
|
||||
//
|
||||
// 绝对星等 M
|
||||
func AbsoluteMagnitudeFromApparent(apparentMagnitude, distanceParsec float64) float64 {
|
||||
modulus := DistanceModulus(distanceParsec)
|
||||
if math.IsNaN(modulus) {
|
||||
return math.NaN()
|
||||
}
|
||||
return apparentMagnitude - modulus
|
||||
}
|
||||
@@ -0,0 +1,133 @@
|
||||
package formula
|
||||
|
||||
import "math"
|
||||
|
||||
const (
|
||||
solarLuminosityW = 3.828e26
|
||||
solarRadiusM = 6.957e8
|
||||
solarEffectiveTempK = 5772.0
|
||||
)
|
||||
|
||||
// LuminosityFromRadiusTemperature 由半径和温度求光度 / luminosity from radius and temperature.
|
||||
//
|
||||
// radiusM: 恒星半径,单位米
|
||||
// temperatureK: 恒星有效温度,单位开尔文
|
||||
//
|
||||
// 返回:
|
||||
//
|
||||
// 总光度,单位瓦特
|
||||
func LuminosityFromRadiusTemperature(radiusM, temperatureK float64) float64 {
|
||||
if radiusM <= 0 || temperatureK <= 0 ||
|
||||
math.IsNaN(radiusM) || math.IsInf(radiusM, 0) ||
|
||||
math.IsNaN(temperatureK) || math.IsInf(temperatureK, 0) {
|
||||
return math.NaN()
|
||||
}
|
||||
return 4 * math.Pi * radiusM * radiusM * StefanBoltzmannFlux(temperatureK)
|
||||
}
|
||||
|
||||
// RadiusFromLuminosityTemperature 由光度和温度求半径 / radius from luminosity and temperature.
|
||||
//
|
||||
// luminosityW: 恒星总光度,单位瓦特
|
||||
// temperatureK: 恒星有效温度,单位开尔文
|
||||
//
|
||||
// 返回:
|
||||
//
|
||||
// 恒星半径,单位米
|
||||
func RadiusFromLuminosityTemperature(luminosityW, temperatureK float64) float64 {
|
||||
if luminosityW <= 0 || temperatureK <= 0 ||
|
||||
math.IsNaN(luminosityW) || math.IsInf(luminosityW, 0) ||
|
||||
math.IsNaN(temperatureK) || math.IsInf(temperatureK, 0) {
|
||||
return math.NaN()
|
||||
}
|
||||
denominator := 4 * math.Pi * StefanBoltzmannFlux(temperatureK)
|
||||
if denominator == 0 {
|
||||
return math.NaN()
|
||||
}
|
||||
return math.Sqrt(luminosityW / denominator)
|
||||
}
|
||||
|
||||
// EffectiveTemperatureFromLuminosityRadius 由光度和半径求温度 / effective temperature from luminosity and radius.
|
||||
//
|
||||
// luminosityW: 恒星总光度,单位瓦特
|
||||
// radiusM: 恒星半径,单位米
|
||||
//
|
||||
// 返回:
|
||||
//
|
||||
// 恒星有效温度,单位开尔文
|
||||
func EffectiveTemperatureFromLuminosityRadius(luminosityW, radiusM float64) float64 {
|
||||
if luminosityW <= 0 || radiusM <= 0 ||
|
||||
math.IsNaN(luminosityW) || math.IsInf(luminosityW, 0) ||
|
||||
math.IsNaN(radiusM) || math.IsInf(radiusM, 0) {
|
||||
return math.NaN()
|
||||
}
|
||||
denominator := 4 * math.Pi * radiusM * radiusM * stefanBoltzmannConstant
|
||||
if denominator == 0 {
|
||||
return math.NaN()
|
||||
}
|
||||
return math.Pow(luminosityW/denominator, 0.25)
|
||||
}
|
||||
|
||||
// LuminositySolarFromRadiusTemperature 由太阳半径单位和温度求光度 / luminosity in solar units from radius and temperature.
|
||||
//
|
||||
// radiusSolar: 恒星半径,单位为太阳半径
|
||||
// temperatureK: 恒星有效温度,单位开尔文
|
||||
//
|
||||
// 返回:
|
||||
//
|
||||
// 总光度,单位为太阳光度 L☉
|
||||
func LuminositySolarFromRadiusTemperature(radiusSolar, temperatureK float64) float64 {
|
||||
if radiusSolar <= 0 || temperatureK <= 0 ||
|
||||
math.IsNaN(radiusSolar) || math.IsInf(radiusSolar, 0) ||
|
||||
math.IsNaN(temperatureK) || math.IsInf(temperatureK, 0) {
|
||||
return math.NaN()
|
||||
}
|
||||
return LuminosityFromRadiusTemperature(radiusSolar*solarRadiusM, temperatureK) / solarLuminosityW
|
||||
}
|
||||
|
||||
// RadiusSolarFromLuminosityTemperature 由太阳光度单位和温度求半径 / radius in solar units from luminosity and temperature.
|
||||
//
|
||||
// luminositySolar: 恒星总光度,单位为太阳光度 L☉
|
||||
// temperatureK: 恒星有效温度,单位开尔文
|
||||
//
|
||||
// 返回:
|
||||
//
|
||||
// 恒星半径,单位为太阳半径 R☉
|
||||
func RadiusSolarFromLuminosityTemperature(luminositySolar, temperatureK float64) float64 {
|
||||
if luminositySolar <= 0 || temperatureK <= 0 ||
|
||||
math.IsNaN(luminositySolar) || math.IsInf(luminositySolar, 0) ||
|
||||
math.IsNaN(temperatureK) || math.IsInf(temperatureK, 0) {
|
||||
return math.NaN()
|
||||
}
|
||||
return RadiusFromLuminosityTemperature(luminositySolar*solarLuminosityW, temperatureK) / solarRadiusM
|
||||
}
|
||||
|
||||
// EffectiveTemperatureFromLuminositySolarRadius 由太阳光度和半径单位求温度 / effective temperature from solar luminosity and radius.
|
||||
//
|
||||
// luminositySolar: 恒星总光度,单位为太阳光度 L☉
|
||||
// radiusSolar: 恒星半径,单位为太阳半径 R☉
|
||||
//
|
||||
// 返回:
|
||||
//
|
||||
// 恒星有效温度,单位开尔文
|
||||
//
|
||||
// 例:
|
||||
//
|
||||
// // 半径 2.5 R☉、光度 20 L☉ 的主序星
|
||||
// t := formula.EffectiveTemperatureFromLuminositySolarRadius(20, 2.5)
|
||||
func EffectiveTemperatureFromLuminositySolarRadius(luminositySolar, radiusSolar float64) float64 {
|
||||
if luminositySolar <= 0 || radiusSolar <= 0 ||
|
||||
math.IsNaN(luminositySolar) || math.IsInf(luminositySolar, 0) ||
|
||||
math.IsNaN(radiusSolar) || math.IsInf(radiusSolar, 0) {
|
||||
return math.NaN()
|
||||
}
|
||||
return EffectiveTemperatureFromLuminosityRadius(luminositySolar*solarLuminosityW, radiusSolar*solarRadiusM)
|
||||
}
|
||||
|
||||
// SolarEffectiveTemperature 太阳有效温度常数 / solar effective temperature constant.
|
||||
//
|
||||
// 返回:
|
||||
//
|
||||
// 太阳有效温度,单位开尔文
|
||||
func SolarEffectiveTemperature() float64 {
|
||||
return solarEffectiveTempK
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
package formula
|
||||
|
||||
import "math"
|
||||
|
||||
const darkAdaptedPupilDiameterMM = 7.0
|
||||
|
||||
// LightGatheringPowerRatio 集光力比值 / light-gathering power ratio.
|
||||
//
|
||||
// diameter1MM: 第一个望远镜口径,单位毫米
|
||||
// diameter2MM: 第二个望远镜口径,单位毫米
|
||||
//
|
||||
// 返回:
|
||||
//
|
||||
// 集光力比值,等于 (diameter1MM / diameter2MM)^2
|
||||
func LightGatheringPowerRatio(diameter1MM, diameter2MM float64) float64 {
|
||||
if diameter1MM <= 0 || diameter2MM <= 0 ||
|
||||
math.IsNaN(diameter1MM) || math.IsInf(diameter1MM, 0) ||
|
||||
math.IsNaN(diameter2MM) || math.IsInf(diameter2MM, 0) {
|
||||
return math.NaN()
|
||||
}
|
||||
return math.Pow(diameter1MM/diameter2MM, 2)
|
||||
}
|
||||
|
||||
// DawesLimitArcsec Dawes 极限 / Dawes limit in arcseconds.
|
||||
//
|
||||
// diameterMM: 望远镜口径,单位毫米
|
||||
//
|
||||
// 返回:
|
||||
//
|
||||
// Dawes 极限,单位角秒
|
||||
func DawesLimitArcsec(diameterMM float64) float64 {
|
||||
if diameterMM <= 0 || math.IsNaN(diameterMM) || math.IsInf(diameterMM, 0) {
|
||||
return math.NaN()
|
||||
}
|
||||
return 116 / diameterMM
|
||||
}
|
||||
|
||||
// RayleighLimitArcsec Rayleigh 极限 / Rayleigh limit in arcseconds.
|
||||
//
|
||||
// diameterMM: 望远镜口径,单位毫米
|
||||
//
|
||||
// 返回:
|
||||
//
|
||||
// Rayleigh 极限,单位角秒
|
||||
func RayleighLimitArcsec(diameterMM float64) float64 {
|
||||
if diameterMM <= 0 || math.IsNaN(diameterMM) || math.IsInf(diameterMM, 0) {
|
||||
return math.NaN()
|
||||
}
|
||||
return 138.4 / diameterMM
|
||||
}
|
||||
|
||||
// LimitingMagnitudeEmpirical 经验极限星等 / empirical limiting magnitude.
|
||||
//
|
||||
// diameterMM: 望远镜有效口径,单位毫米
|
||||
// nakedEyeLimit: 观测地裸眼极限星等,例如乡村暗空可近似取 6
|
||||
//
|
||||
// 返回:
|
||||
//
|
||||
// 经验极限星等;这是经验值,不包含天空背景、倍率、透过率和观测经验修正
|
||||
//
|
||||
// 例:
|
||||
//
|
||||
// // 70mm 小型折射镜,裸眼极限 6 等
|
||||
// mag := formula.LimitingMagnitudeEmpirical(70, 6)
|
||||
func LimitingMagnitudeEmpirical(diameterMM, nakedEyeLimit float64) float64 {
|
||||
if diameterMM <= 0 ||
|
||||
math.IsNaN(diameterMM) || math.IsInf(diameterMM, 0) ||
|
||||
math.IsNaN(nakedEyeLimit) || math.IsInf(nakedEyeLimit, 0) {
|
||||
return math.NaN()
|
||||
}
|
||||
return nakedEyeLimit + 5*math.Log10(diameterMM/darkAdaptedPupilDiameterMM)
|
||||
}
|
||||
Reference in New Issue
Block a user