90 lines
3.3 KiB
Go
90 lines
3.3 KiB
Go
|
|
package basic
|
||
|
|
|
||
|
|
import "math"
|
||
|
|
|
||
|
|
const (
|
||
|
|
refractionStandardPressureHPa = 1010.0
|
||
|
|
refractionStandardTemperatureK = 283.0
|
||
|
|
refractionAbsoluteZeroC = -273.15
|
||
|
|
refractionLowerLimitAltitudeDeg = -5.0
|
||
|
|
refractionUpperLimitAltitudeDeg = 90.0
|
||
|
|
)
|
||
|
|
|
||
|
|
// RefractionFromApparentAltitude 大气折射修正量,单位度;输入为视高度角。
|
||
|
|
// 返回值应从真高度角加上后得到视高度角。
|
||
|
|
func RefractionFromApparentAltitude(apparentAltitude, pressureHPa, temperatureC float64) float64 {
|
||
|
|
if !validRefractionInputs(apparentAltitude, pressureHPa, temperatureC) {
|
||
|
|
return math.NaN()
|
||
|
|
}
|
||
|
|
if apparentAltitude < refractionLowerLimitAltitudeDeg || apparentAltitude > refractionUpperLimitAltitudeDeg {
|
||
|
|
return 0
|
||
|
|
}
|
||
|
|
angle := (apparentAltitude + 10.3/(apparentAltitude+5.11)) * math.Pi / 180
|
||
|
|
return refractionScale(pressureHPa, temperatureC) * (1.02 / math.Tan(angle)) / 60
|
||
|
|
}
|
||
|
|
|
||
|
|
// TrueAltitude 真高度角,单位度;输入为视高度角。
|
||
|
|
func TrueAltitude(apparentAltitude, pressureHPa, temperatureC float64) float64 {
|
||
|
|
refraction := RefractionFromApparentAltitude(apparentAltitude, pressureHPa, temperatureC)
|
||
|
|
if math.IsNaN(refraction) {
|
||
|
|
return math.NaN()
|
||
|
|
}
|
||
|
|
return apparentAltitude - refraction
|
||
|
|
}
|
||
|
|
|
||
|
|
// ApparentAltitude 视高度角,单位度;输入为真高度角。
|
||
|
|
func ApparentAltitude(trueAltitude, pressureHPa, temperatureC float64) float64 {
|
||
|
|
if !validRefractionInputs(trueAltitude, pressureHPa, temperatureC) {
|
||
|
|
return math.NaN()
|
||
|
|
}
|
||
|
|
if trueAltitude < refractionLowerLimitAltitudeDeg || trueAltitude > refractionUpperLimitAltitudeDeg {
|
||
|
|
return trueAltitude
|
||
|
|
}
|
||
|
|
|
||
|
|
estimate := trueAltitude + RefractionFromApparentAltitude(trueAltitude, pressureHPa, temperatureC)
|
||
|
|
for i := 0; i < 8; i++ {
|
||
|
|
refraction := RefractionFromApparentAltitude(estimate, pressureHPa, temperatureC)
|
||
|
|
if math.IsNaN(refraction) {
|
||
|
|
return math.NaN()
|
||
|
|
}
|
||
|
|
value := estimate - refraction - trueAltitude
|
||
|
|
if math.Abs(value) < 1e-12 {
|
||
|
|
break
|
||
|
|
}
|
||
|
|
|
||
|
|
const delta = 1e-6
|
||
|
|
refractionPlus := RefractionFromApparentAltitude(estimate+delta, pressureHPa, temperatureC)
|
||
|
|
refractionMinus := RefractionFromApparentAltitude(estimate-delta, pressureHPa, temperatureC)
|
||
|
|
if math.IsNaN(refractionPlus) || math.IsNaN(refractionMinus) {
|
||
|
|
return math.NaN()
|
||
|
|
}
|
||
|
|
|
||
|
|
derivative := 1 - (refractionPlus-refractionMinus)/(2*delta)
|
||
|
|
if derivative == 0 {
|
||
|
|
break
|
||
|
|
}
|
||
|
|
estimate -= value / derivative
|
||
|
|
}
|
||
|
|
return estimate
|
||
|
|
}
|
||
|
|
|
||
|
|
// RefractionFromTrueAltitude 大气折射修正量,单位度;输入为真高度角。
|
||
|
|
// 返回值应从真高度角加上后得到视高度角。
|
||
|
|
func RefractionFromTrueAltitude(trueAltitude, pressureHPa, temperatureC float64) float64 {
|
||
|
|
apparentAltitude := ApparentAltitude(trueAltitude, pressureHPa, temperatureC)
|
||
|
|
if math.IsNaN(apparentAltitude) {
|
||
|
|
return math.NaN()
|
||
|
|
}
|
||
|
|
return apparentAltitude - trueAltitude
|
||
|
|
}
|
||
|
|
|
||
|
|
func validRefractionInputs(altitude, pressureHPa, temperatureC float64) bool {
|
||
|
|
return !(math.IsNaN(altitude) || math.IsInf(altitude, 0) ||
|
||
|
|
math.IsNaN(pressureHPa) || math.IsInf(pressureHPa, 0) || pressureHPa <= 0 ||
|
||
|
|
math.IsNaN(temperatureC) || math.IsInf(temperatureC, 0) || temperatureC <= refractionAbsoluteZeroC)
|
||
|
|
}
|
||
|
|
|
||
|
|
func refractionScale(pressureHPa, temperatureC float64) float64 {
|
||
|
|
return pressureHPa / refractionStandardPressureHPa * refractionStandardTemperatureK / (273 + temperatureC)
|
||
|
|
}
|