docs: bilingual comments for the validation tools

Also makes the table generators emit the bilingual module docs, so a
regenerated table matches the committed one.
This commit is contained in:
ApsisRS contributors 2026-10-02 01:44:36 +08:00
parent 0e3d735935
commit 82a5a418a8
8 changed files with 221 additions and 13 deletions

View File

@ -6,6 +6,13 @@
//! //!
//! Source: the MHB2000 model, as distributed with the IAU SOFA library //! Source: the MHB2000 model, as distributed with the IAU SOFA library
//! and implemented by ERFA. //! and implemented by ERFA.
//!
//! 分点方程式的 IAU 2000 补充项。
//!
//! 该表由 `validation/tools/generate_eect_table.py` 从参考实现生成,
//! 原样再现,未经改动。
//!
//! 出处:MHB2000 模型,随 IAU SOFA 库分发并由 ERFA 实现。
use super::ComplementaryTerm; use super::ComplementaryTerm;

View File

@ -10,6 +10,16 @@
//! Source: the MHB2000 model of Mathews, Herring and Buffett, adopted by //! Source: the MHB2000 model of Mathews, Herring and Buffett, adopted by
//! the International Astronomical Union in 2000 and distributed as part //! the International Astronomical Union in 2000 and distributed as part
//! of the IAU SOFA library, as implemented by ERFA. //! of the IAU SOFA library, as implemented by ERFA.
//!
//! IAU 2000A 章动级数。
//!
//! 该表由 `validation/tools/generate_nutation_table.py` 从该模型的参考
//! 实现生成,原样再现,未经改动。
//!
//! 字段次序遵循参考实现,它并非论文中列出系数的次序。
//!
//! 出处:Mathews、Herring 与 Buffett 的 MHB2000 模型,2000 年由国际
//! 天文学联合会采纳,随 IAU SOFA 库分发,由 ERFA 实现。
use super::{PlanetaryTerm, SeriesTerm}; use super::{PlanetaryTerm, SeriesTerm};

View File

@ -6,6 +6,13 @@
//! //!
//! Source: ITU-R Recommendation P.839-4, *Rain height model for prediction //! Source: ITU-R Recommendation P.839-4, *Rain height model for prediction
//! methods*. //! methods*.
//!
//! ITU-R P.839-4 零度等温线高度表。
//!
//! 该表由 `validation/tools/generate_p839_table.py` 从随该建议书发布的
//! 数据生成,此处以米为单位的整数再现,这正是该建议书发布的分辨率。
//!
//! 出处:ITU-R 建议书 P.839-4,*Rain height model for prediction methods*。
/// The height of the zero degree isotherm, in metres. /// The height of the zero degree isotherm, in metres.
/// ///

View File

@ -13,6 +13,20 @@ Usage:
Exit status is zero when every quantity agrees within tolerance and one Exit status is zero when every quantity agrees within tolerance and one
otherwise. otherwise.
用 ERFA 交叉核对 ApsisRS 的 IAU 2000/2006 地球定向。
读取由 ``cargo run -p apsis-rs --features physics --example dump_iau2000``
写出的量,并用 ERFA 逐个重算,后者是国际天文学联合会通过 SOFA 库及其
ERFA 衍生物分发的参考实现。
本脚本不需要网络访问。
用法:
pixi run python validation/python/time/check_iau2000.py [path]
每个量都在容差内一致时退出状态为零,否则为一。
""" """
from __future__ import annotations from __future__ import annotations
@ -35,13 +49,27 @@ import erfa
# `gst06a` is built on the non-rotating origin while the Rust value is built # `gst06a` is built on the non-rotating origin while the Rust value is built
# on the equinox. The two formulations agree to about two microarcseconds, # on the equinox. The two formulations agree to about two microarcseconds,
# which is 1e-11 radians, and that is what is allowed here. # which is 1e-11 radians, and that is what is allowed here.
#
# 容差。
#
# 章动、黄赤交角与岁差在双精度最后几位的水平上被复现,故它们以 1e-14
# 比较。
#
# 恒星时与各矩阵累积了若干次转动的双精度误差,故容许更大。
#
# 格林尼治视恒星时有其自己的容差,因为 ERFA 的 `gst06a` 建立在非旋转原点
# 之上,而 Rust 值建立在春分点之上。两种表述相符到约两微角秒,即 1e-11
# 弧度,此处容许的就是这个。
SCALAR_TOLERANCE = 1e-14 SCALAR_TOLERANCE = 1e-14
SIDEREAL_TOLERANCE = 1e-10 SIDEREAL_TOLERANCE = 1e-10
MATRIX_TOLERANCE = 1e-9 MATRIX_TOLERANCE = 1e-9
def tolerance_for(quantity: str) -> float: def tolerance_for(quantity: str) -> float:
"""Returns the tolerance that applies to a quantity.""" """Returns the tolerance that applies to a quantity.
返回适用于某个量的容差。
"""
if quantity == "gast": if quantity == "gast":
return SIDEREAL_TOLERANCE return SIDEREAL_TOLERANCE
if quantity in ("bpn", "c2t"): if quantity in ("bpn", "c2t"):
@ -51,18 +79,25 @@ def tolerance_for(quantity: str) -> float:
DEFAULT_INPUT = Path("validation/data/expected/rust_iau2000.csv") DEFAULT_INPUT = Path("validation/data/expected/rust_iau2000.csv")
# The Terrestrial Time offset from UTC, in seconds, matching the Rust side. # The Terrestrial Time offset from UTC, in seconds, matching the Rust side.
# 地球时相对 UTC 的偏移,单位为秒,与 Rust 侧一致。
TT_MINUS_UTC_SECONDS = 32.184 + 37.0 TT_MINUS_UTC_SECONDS = 32.184 + 37.0
def read_rows(path: Path) -> list[dict[str, str]]: def read_rows(path: Path) -> list[dict[str, str]]:
"""Reads the CSV rows.""" """Reads the CSV rows.
读取 CSV 各行。
"""
with path.open(newline="") as handle: with path.open(newline="") as handle:
reader = csv.DictReader(handle) reader = csv.DictReader(handle)
return [row for row in reader if row.get("mjd")] return [row for row in reader if row.get("mjd")]
def tt_julian_date(utc_mjd: float) -> float: def tt_julian_date(utc_mjd: float) -> float:
"""Returns the Terrestrial Time Julian date for a UTC Modified Julian Date.""" """Returns the Terrestrial Time Julian date for a UTC Modified Julian Date.
返回某 UTC 约化儒略日对应的地球时儒略日。
"""
return utc_mjd + 2400000.5 + TT_MINUS_UTC_SECONDS / 86400.0 return utc_mjd + 2400000.5 + TT_MINUS_UTC_SECONDS / 86400.0
@ -122,6 +157,8 @@ def main(argv: list[str]) -> int:
elif quantity == "c2t": elif quantity == "c2t":
# The equinox based chain: the bias, precession and nutation, # The equinox based chain: the bias, precession and nutation,
# then Greenwich apparent sidereal time, then the polar motion. # then Greenwich apparent sidereal time, then the polar motion.
# 基于春分点的链条:先偏差、岁差与章动,再格林尼治视恒星时,
# 然后极移。
matrix = erfa.c2t06a(d1, d2, d1, d2, 0.0, 0.0) matrix = erfa.c2t06a(d1, d2, d1, d2, 0.0, 0.0)
reference = matrix[index // 3][index % 3] reference = matrix[index // 3][index % 3]
else: else:

View File

@ -27,6 +27,29 @@ Usage:
Exit status is zero when every instant agrees within tolerance and one Exit status is zero when every instant agrees within tolerance and one
otherwise. otherwise.
交叉核对 ApsisRS 的时标换算。
读取由 ``cargo run -p apsis-rs --features physics --example dump_time`` 写出
的样本,并用 astropy 逐个重算瞬时,然后报告最大差异。
把某 UTC 瞬时写为浮点日有两种约定。本工作区用带阶跃偏移的线性约化儒略日,
故偏移 ``TAI - UTC`` 在闰秒处改变,其间恒定。Astropy 经 ERFA 用的是准儒略
日,其中含闰秒的一天有 86 401 秒长,故其 ``tai - utc`` 之差在这样一天中
斜坡变化。因此把两者作为儒略日之差比较,度量的是约定的差异而非数值误差。
本检查改为比较 TAI 瞬时。两侧被赋予相同的 UTC 日历瞬时,所得 TAI 约化
儒略日按两部分比较:整数日与小数,这避免了单个浮点日在接近 60 000 处会
遭受的精度损失。
本脚本不需要网络访问;它禁用 astropy 对地球定向数据的自动下载,这些换算
并不使用该数据。
用法:
pixi run python validation/python/time/check_time.py [path]
每个瞬时都在容差内一致时退出状态为零,否则为一。
""" """
from __future__ import annotations from __future__ import annotations
@ -38,25 +61,33 @@ from pathlib import Path
from astropy.time import Time from astropy.time import Time
# The TAI instant is compared to one microsecond. # The TAI instant is compared to one microsecond.
# TAI 瞬时比较到一微秒。
TOLERANCE_SECONDS = 1e-6 TOLERANCE_SECONDS = 1e-6
SECONDS_PER_DAY = 86400.0 SECONDS_PER_DAY = 86400.0
# The Modified Julian Date scale starts half a day after the Julian Date # The Modified Julian Date scale starts half a day after the Julian Date
# scale, so this is the offset between the two day counts. # scale, so this is the offset between the two day counts.
# 约化儒略日的起点比儒略日晚半天,故这是两种日计数之间的偏移。
MJD_OFFSET_FROM_JD = 2400000.5 MJD_OFFSET_FROM_JD = 2400000.5
DEFAULT_INPUT = Path("validation/data/expected/rust_time.csv") DEFAULT_INPUT = Path("validation/data/expected/rust_time.csv")
def disable_remote_data() -> None: def disable_remote_data() -> None:
"""Stops astropy from trying to download Earth orientation data.""" """Stops astropy from trying to download Earth orientation data.
阻止 astropy 尝试下载地球定向数据。
"""
from astropy.utils import iers from astropy.utils import iers
iers.conf.auto_download = False iers.conf.auto_download = False
def read_rows(path: Path) -> tuple[list[dict[str, str]], dict[str, str]]: def read_rows(path: Path) -> tuple[list[dict[str, str]], dict[str, str]]:
"""Reads the CSV rows and the trailing comment metadata.""" """Reads the CSV rows and the trailing comment metadata.
读取 CSV 各行以及末尾的注释元数据。
"""
metadata: dict[str, str] = {} metadata: dict[str, str] = {}
data_lines = [] data_lines = []
with path.open(newline="") as handle: with path.open(newline="") as handle:
@ -74,7 +105,10 @@ def read_rows(path: Path) -> tuple[list[dict[str, str]], dict[str, str]]:
def rust_tai_parts(row: dict[str, str]) -> tuple[int, float]: def rust_tai_parts(row: dict[str, str]) -> tuple[int, float]:
"""Returns the Rust TAI instant as an integer day and a fraction.""" """Returns the Rust TAI instant as an integer day and a fraction.
把 Rust 的 TAI 瞬时返回为整数日与小数。
"""
return int(row["tai_day"]), float(row["tai_frac"]) return int(row["tai_day"]), float(row["tai_frac"])
@ -83,6 +117,11 @@ def reference_tai_parts(row: dict[str, str]) -> tuple[float, float]:
The two part form of an astropy time keeps the day count in ``jd1`` and The two part form of an astropy time keeps the day count in ``jd1`` and
the within-day offset in ``jd2``, so the subtraction below is exact. the within-day offset in ``jd2``, so the subtraction below is exact.
把 astropy 的 TAI 瞬时返回为整数日与小数。
astropy 时间的两部分形式把日计数保存在 ``jd1``、把日内偏移保存在
``jd2``,故下面的减法精确。
""" """
iso = ( iso = (
f"{int(row['year']):04d}-{int(row['month']):02d}-{int(row['day']):02d}" f"{int(row['year']):04d}-{int(row['month']):02d}-{int(row['day']):02d}"
@ -137,6 +176,8 @@ def main(argv: list[str]) -> int:
# against the reference only at the points where the reference is # against the reference only at the points where the reference is
# constant in the workspace's sense, which the instant comparison # constant in the workspace's sense, which the instant comparison
# above has already validated. # above has already validated.
# 本工作区报告的偏移是阶跃函数。只在参考值于本工作区意义下恒定的点
# 处对它作核对,而上面的瞬时比较已验证了这些点。
rust_offset = float(row["tai_minus_utc"]) rust_offset = float(row["tai_minus_utc"])
if abs(error) <= TOLERANCE_SECONDS and abs(rust_offset) > worst_offset: if abs(error) <= TOLERANCE_SECONDS and abs(rust_offset) > worst_offset:
worst_offset = rust_offset worst_offset = rust_offset

View File

@ -15,6 +15,21 @@ Fetch the reference with:
Usage: Usage:
python validation/tools/generate_eect_table.py path/to/eect00.c python validation/tools/generate_eect_table.py path/to/eect00.c
生成 IAU 2000 分点方程式补充项的 Rust 源码。
补充项是黄经章动不包含的、分点方程式的小周期附加项。它们来自与章动相同的
理论,为使分点方程式与章动级数一致所必需。
参考实现是 ERFA 库,它是 IAU SOFA 库的衍生物。
获取参考源码:
curl -O https://raw.githubusercontent.com/liberfa/erfa/master/src/eect00.c
用法:
python validation/tools/generate_eect_table.py path/to/eect00.c
""" """
from __future__ import annotations from __future__ import annotations
@ -25,7 +40,10 @@ from pathlib import Path
def extract_array(source: str, name: str) -> str: def extract_array(source: str, name: str) -> str:
"""Returns the body of a C array initializer.""" """Returns the body of a C array initializer.
返回一个 C 数组初始化器的正文。
"""
start = source.index(name + "[] = {") start = source.index(name + "[] = {")
brace = source.index("{", start) brace = source.index("{", start)
depth = 0 depth = 0
@ -42,13 +60,19 @@ def extract_array(source: str, name: str) -> str:
def parse_terms(body: str) -> list[tuple[str, str]]: def parse_terms(body: str) -> list[tuple[str, str]]:
"""Returns the multiplier and coefficient groups of each term.""" """Returns the multiplier and coefficient groups of each term.
返回每一项的乘数组与系数组。
"""
body = re.sub(r"/\*.*?\*/", "", body, flags=re.S) body = re.sub(r"/\*.*?\*/", "", body, flags=re.S)
return re.findall(r"\{\{([^{}]*)\},\s*([^}]*)\}", body) return re.findall(r"\{\{([^{}]*)\},\s*([^}]*)\}", body)
def emit(name: str, doc: str, terms: list[tuple[str, str]]) -> None: def emit(name: str, doc: str, terms: list[tuple[str, str]]) -> None:
"""Prints one Rust constant.""" """Prints one Rust constant.
打印一个 Rust 常量。
"""
print(doc) print(doc)
print(f"pub static {name}: [ComplementaryTerm; {len(terms)}] = [") print(f"pub static {name}: [ComplementaryTerm; {len(terms)}] = [")
for multipliers, coefficients in terms: for multipliers, coefficients in terms:
@ -78,17 +102,24 @@ def main(argv: list[str]) -> int:
print("//!") print("//!")
print("//! Source: the MHB2000 model, as distributed with the IAU SOFA library") print("//! Source: the MHB2000 model, as distributed with the IAU SOFA library")
print("//! and implemented by ERFA.") print("//! and implemented by ERFA.")
print("//!")
print("//! 分点方程式的 IAU 2000 补充项。")
print("//!")
print("//! 该表由 `validation/tools/generate_eect_table.py` 从参考实现生成,")
print("//! 原样再现,未经改动。")
print("//!")
print("//! 出处:MHB2000 模型,随 IAU SOFA 库分发并由 ERFA 实现。")
print() print()
print("use super::ComplementaryTerm;") print("use super::ComplementaryTerm;")
print() print()
emit( emit(
"CONSTANT_TERMS", "CONSTANT_TERMS",
"/// The terms that do not depend on time.\n///\n/// The eight multipliers apply to the arguments `l`, `l'`, `F`, `D`, `Om`,\n/// the mean longitude of Venus, the mean longitude of the Earth, and the\n/// general accumulated precession, in that order.", "/// The terms that do not depend on time.\n///\n/// The eight multipliers apply to the arguments `l`, `l'`, `F`, `D`, `Om`,\n/// the mean longitude of Venus, the mean longitude of the Earth, and the\n/// general accumulated precession, in that order.\n///\n/// 不依赖时间的各项。\n///\n/// 八个乘数按 `l`、`l'`、`F`、`D`、`Om`、金星的平黄经、地球的平黄经,以及\n/// 一般累积岁差的次序施加于这些参数。",
constant, constant,
) )
emit( emit(
"LINEAR_TERMS", "LINEAR_TERMS",
"/// The terms whose amplitude grows linearly with time.\n///\n/// The arguments are the same as for the constant terms.", "/// The terms whose amplitude grows linearly with time.\n///\n/// The arguments are the same as for the constant terms.\n///\n/// 幅度随时间线性增长的各项。\n///\n/// 参数与常数项相同。",
linear, linear,
) )
return 0 return 0

View File

@ -27,6 +27,31 @@ Fetch the reference with:
Usage: Usage:
python validation/tools/generate_nutation_table.py path/to/nut00a.c python validation/tools/generate_nutation_table.py path/to/nut00a.c
生成 IAU 2000A 章动级数的 Rust 源码。
该级数即 MHB2000 模型。它有一个日月部分与一个行星部分,二者都是长长的
整数辐角乘数与实数系数表,故它们是机械地从参考实现转录而非手写。
参考实现是 ERFA 库,它是国际天文学联合会维护的 IAU SOFA 库的衍生物。其
源码是该级数的权威表述。
字段次序即参考实现所用者,它并非论文中列出系数的次序:
日月:乘数 l、l'、F、D、Om;然后 sp、spt、cp、ce、cet、se
行星:乘数 l、F、D、Om、Me、Ve、E、Ma、Ju、Sa、Ur、Ne、pa;
然后 sp、cp、se、ce
两个级数使用不同的辐角集合,且对黄赤交角使用不同的系数分组,故生成的
Rust 类型将它们分开。
获取参考源码:
curl -O https://raw.githubusercontent.com/liberfa/erfa/master/src/nut00a.c
用法:
python validation/tools/generate_nutation_table.py path/to/nut00a.c
""" """
from __future__ import annotations from __future__ import annotations
@ -37,7 +62,10 @@ from pathlib import Path
def extract_array(source: str, name: str) -> str: def extract_array(source: str, name: str) -> str:
"""Returns the body of a C array initializer.""" """Returns the body of a C array initializer.
返回一个 C 数组初始化器的正文。
"""
start = source.index(name + "[] = {") start = source.index(name + "[] = {")
brace = source.index("{", start) brace = source.index("{", start)
depth = 0 depth = 0
@ -54,7 +82,10 @@ def extract_array(source: str, name: str) -> str:
def parse_terms(body: str) -> list[list[str]]: def parse_terms(body: str) -> list[list[str]]:
"""Returns the numeric terms of an array of brace groups.""" """Returns the numeric terms of an array of brace groups.
返回一组花括号组的数组中的数值项。
"""
body = re.sub(r"/\*.*?\*/", "", body, flags=re.S) body = re.sub(r"/\*.*?\*/", "", body, flags=re.S)
terms = [] terms = []
for group in re.findall(r"\{([^{}]*)\}", body): for group in re.findall(r"\{([^{}]*)\}", body):
@ -92,6 +123,16 @@ def main(argv: list[str]) -> int:
print("//! Source: the MHB2000 model of Mathews, Herring and Buffett, adopted by") print("//! Source: the MHB2000 model of Mathews, Herring and Buffett, adopted by")
print("//! the International Astronomical Union in 2000 and distributed as part") print("//! the International Astronomical Union in 2000 and distributed as part")
print("//! of the IAU SOFA library, as implemented by ERFA.") print("//! of the IAU SOFA library, as implemented by ERFA.")
print("//!")
print("//! IAU 2000A 章动级数。")
print("//!")
print("//! 该表由 `validation/tools/generate_nutation_table.py` 从该模型的参考")
print("//! 实现生成,原样再现,未经改动。")
print("//!")
print("//! 字段次序遵循参考实现,它并非论文中列出系数的次序。")
print("//!")
print("//! 出处:Mathews、Herring 与 Buffett 的 MHB2000 模型,2000 年由国际")
print("//! 天文学联合会采纳,随 IAU SOFA 库分发,由 ERFA 实现。")
print() print()
print("use super::{PlanetaryTerm, SeriesTerm};") print("use super::{PlanetaryTerm, SeriesTerm};")
print() print()
@ -102,6 +143,12 @@ def main(argv: list[str]) -> int:
print("/// in that order. The coefficients are the longitude sine, its time") print("/// in that order. The coefficients are the longitude sine, its time")
print("/// derivative, the longitude cosine, the obliquity cosine, its time") print("/// derivative, the longitude cosine, the obliquity cosine, its time")
print("/// derivative, and the obliquity sine, in units of 0.1 microarcsecond.") print("/// derivative, and the obliquity sine, in units of 0.1 microarcsecond.")
print("///")
print("/// 级数中的日月各项。")
print("///")
print("/// 各乘数按 `l`、`l'`、`F`、`D`、`Om` 的次序施加于这些参数。各系数依次是")
print("/// 黄经正弦、其时间导数、黄经余弦、黄赤交角余弦、其时间导数,以及黄赤交角")
print("/// 正弦,单位为 0.1 微角秒。")
print(f"pub static LUNI_SOLAR: [SeriesTerm; {len(lunisolar)}] = [") print(f"pub static LUNI_SOLAR: [SeriesTerm; {len(lunisolar)}] = [")
for term in lunisolar: for term in lunisolar:
multipliers = ", ".join(term[:5]) multipliers = ", ".join(term[:5])
@ -124,6 +171,12 @@ def main(argv: list[str]) -> int:
print("/// coefficients are the longitude sine, the longitude cosine, the") print("/// coefficients are the longitude sine, the longitude cosine, the")
print("/// obliquity sine, and the obliquity cosine, in units of 0.1") print("/// obliquity sine, and the obliquity cosine, in units of 0.1")
print("/// microarcsecond.") print("/// microarcsecond.")
print("///")
print("/// 级数中的行星各项。")
print("///")
print("/// 各乘数按 `l`、`F`、`D`、`Om`、水星到天王星的平黄经、海王星的平黄经,")
print("/// 以及一般累积岁差的次序施加于这些参数。各系数依次是黄经正弦、黄经余弦、")
print("/// 黄赤交角正弦与黄赤交角余弦,单位为 0.1 微角秒。")
print(f"pub static PLANETARY: [PlanetaryTerm; {len(planetary)}] = [") print(f"pub static PLANETARY: [PlanetaryTerm; {len(planetary)}] = [")
for term in planetary: for term in planetary:
multipliers = ", ".join(term[:13]) multipliers = ", ".join(term[:13])

View File

@ -10,6 +10,16 @@ publishes.
Usage: Usage:
python validation/tools/generate_p839_table.py > /tmp/p839_table.rs python validation/tools/generate_p839_table.py > /tmp/p839_table.rs
生成 ITU-R P.839-4 雨顶高度表的 Rust 源码。
该建议书把零度等温线高度给出为 1.5 度分辨率的全球列表网格。本脚本从
``itur`` 参考包读取该网格,并输出一个 Rust 模块,把它以十分之一千米的整数
嵌入,这正是该建议书发布的分辨率。
用法:
python validation/tools/generate_p839_table.py > /tmp/p839_table.rs
""" """
from __future__ import annotations from __future__ import annotations
@ -23,6 +33,7 @@ BASE = (
) )
# The grid resolution, in degrees. # The grid resolution, in degrees.
# 网格分辨率,单位为度。
STEP_DEGREES = 1.5 STEP_DEGREES = 1.5
@ -36,11 +47,13 @@ def main() -> int:
# The grid is regular: latitude runs from 90 down to -90 and longitude # The grid is regular: latitude runs from 90 down to -90 and longitude
# from 0 to 360, both in steps of 1.5 degrees. # from 0 to 360, both in steps of 1.5 degrees.
# 该网格是规则的:纬度自 90 降到 -90,经度自 0 到 360,步长均为 1.5 度。
assert np.allclose(latitudes[:, 0], np.linspace(90.0, -90.0, rows)), "latitude grid" assert np.allclose(latitudes[:, 0], np.linspace(90.0, -90.0, rows)), "latitude grid"
assert np.allclose(longitudes[0, :], np.linspace(0.0, 360.0, columns)), "longitude grid" assert np.allclose(longitudes[0, :], np.linspace(0.0, 360.0, columns)), "longitude grid"
# The recommendation publishes the height to the nearest metre, so the # The recommendation publishes the height to the nearest metre, so the
# table is stored in metres to avoid losing precision. # table is stored in metres to avoid losing precision.
# 该建议书把高度发布到最近一米,故该表以米存储以避免损失精度。
metres = np.round(heights * 1000.0).astype(np.uint16) metres = np.round(heights * 1000.0).astype(np.uint16)
print("/// The height of the zero degree isotherm, in metres.") print("/// The height of the zero degree isotherm, in metres.")
@ -53,6 +66,15 @@ def main() -> int:
print("///") print("///")
print("/// Source: ITU-R Recommendation P.839-4, *Rain height model for prediction") print("/// Source: ITU-R Recommendation P.839-4, *Rain height model for prediction")
print("/// methods*, which tabulates the isotherm height on this grid.") print("/// methods*, which tabulates the isotherm height on this grid.")
print("///")
print("/// 零度等温线的高度,单位为米。")
print("///")
print("/// 网格在行方向上自北纬 90 度到南纬 90 度,在列方向上自东经 0 度到")
print("/// 360 度,步长均为 1.5 度,故有 121 行 241 列。分数纬度或经度处的值")
print("/// 由周围四点之间的双线性插值求得。")
print("///")
print("/// 出处:ITU-R 建议书 P.839-4,*Rain height model for prediction methods*,")
print("/// 它在该网格上列出等温线高度。")
print(f"pub static ZERO_ISOTHERM_HEIGHT_METRES: [[u16; {columns}]; {rows}] = [") print(f"pub static ZERO_ISOTHERM_HEIGHT_METRES: [[u16; {columns}]; {rows}] = [")
for row in range(rows): for row in range(rows):
values = ", ".join(str(int(value)) for value in metres[row]) values = ", ".join(str(int(value)) for value in metres[row])