简介:《GOCI2 说明手册 波段信息说明》面向海洋遥感、卫星载荷标定与定量反演方向的研究人员、工程师及研究生,聚焦第二代地球同步轨道海洋水色成像仪 GOCI-II 的波段设置与辐射性能指标,帮助读者厘清短波至近红外各波段在藻华识别、悬浮颗粒物监测等场景中的分工与观测能力。压缩包共 1 个文件,为 2.93MB 的 PDF 文档,内容以英文图表与参数表为主,便于离线查阅与引用。资源已有 1161 人学习下载,具备一定的行业关注度。文档给出 GOCI 与 GOCI-II 的波段对照,逐条列出中心波长、带宽以及名义辐射亮度、最大海洋辐射亮度、阈值辐射亮度、最大云辐射亮度和 NEdLSNR 等指标,并附带仪器结构示意,包括快门罩、滤波轮、焦平面组件、指向镜、遮光罩与望远镜机构;同时展示视场角规划与月球成像可行性判据,涉及 2nd Joint GSICS/IVOS Lunar Calibration Workshop 中的月球定标方案与 MTF 测量计划。读者可据此快速掌握载荷参数口径,为传感器选型、辐射定标与反演算法参数配置提供依据。
1. 拆手册先拆数字:13 个波段、四档辐亮度,GOCI2 说明手册到底给了什么
《GOCI2 说明手册 波段信息说明》这份材料,我最初是当成一张参数表去翻的:13 个波段、中心波长、带宽、四档辐射亮度、NEdL 与 SNR。真拿它去配流程才发现,表格只是入口,后面还拖着视场几何、月球成像窗口、ROLO 反射率模型和一整套积分辐照度链路。它解决的不是“这个载荷有几个波段”这种问题,而是“我手上这批 L1B 辐射值凭什么信、怎么验、定标增益怎么随时间退化”这类落地问题。已经在做水色反演、或者要给在轨载荷搭定标监控流程的人,能直接从后半段的公式里抠出可执行的部分;纯新手照着波段表和月球窗口表抄,也能先把数据入库这一关跑通。
2. 波段表怎么读:中心波长、带宽与四档辐射亮度的对应关系
拿到一张波段表,最容易犯的错是只看中心波长。中心波长决定“测什么”,带宽决定“混进来多少别的东西”,四档辐射亮度决定“什么时候这个测量还有效”,NEdL 和 SNR 决定“这个测量能分辨多小的差异”。四件事少看一件,后面的反演就会在某个环节莫名其妙地崩掉。
2.1 13 个通道的波长排布与设计意图
手册给出的通道从 380 nm 一路铺到 865 nm,其中 8 个是 20 nm 或 10 nm 的常规水色通道,1 个是 40 nm 的宽近红外通道,最后挂了一个中心 643.5 nm、带宽 483 nm 的超宽通道。这个排布不是随手凑的:380 nm 和 412 nm 盯的是黄色物质与悬浮颗粒的短波吸收,443 nm 是叶绿素吸收的经典位置,490/510/555 nm 是叶绿素浓度反演的骨架波段,620 nm 用来辅助分离悬浮物,660/680/709 nm 三个 10 nm 窄带专门伺候叶绿素荧光和大气校正基线,745 nm 和 865 nm 落在近红外,做气溶胶校正和水汽参考。
680 nm 给 10 nm 是有讲究的,这一带紧邻氧气吸收,带宽一放宽,荧光信号就被吃掉。709 nm 也是 10 nm,它的作用是抓荧光抬升,同时给 680 nm 提供一个邻近的对比点,两个窄带配合才能把荧光从背景里剥出来。865 nm 反而放到 40 nm,因为它主要用于气溶胶散射的平滑估计,不需要精细光谱结构,放宽带宽换信噪比更划算。常见做法是先用 865 nm 定气溶胶,再回推可见光的路径辐射,这个顺序反了,整条反演链都会飘。
| 通道 | 中心波长(nm) | 带宽(nm) | 标称辐亮度 | 海洋上限 | 阈值 | 云上限 | NEdL | SNR@标称 |
|---|---|---|---|---|---|---|---|---|
| B1 | 380 | 20 | 93 | 139.5 | 143.1 | 634.4 | 0.0939 | 981 |
| B2 | 412 | 20 | 100 | 150 | 152 | 601.6 | 0.0951 | 1050 |
| B3 | 443 | 20 | 92.5 | 145.8 | 148 | 679.1 | 0.0811 | 1145 |
| B4 | 490 | 20 | 72.2 | 115.5 | 116 | 682.1 | 0.059 | 1128 |
| B5 | 510 | 20 | 64.9 | 108.5 | 122 | 665.3 | 0.055 | 1180 |
| B6 | 555 | 20 | 55.3 | 85.2 | 87 | 649.7 | 0.049 | 1124 |
| B7 | 620 | 20 | 53.3 | 64.1 | 65.5 | 629.5 | 0.048 | 1102 |
| B8 | 660 | 10 | 32 | 58.3 | 61 | 589 | 0.03 | 1060 |
| B9 | 680 | 10 | 27.1 | 46.2 | 47 | 549.3 | 0.03 | 914 |
| B10 | 709 | 10 | 27.7 | 50.6 | 51.5 | 450 | 0.03 | 914 |
| B11 | 745 | 20 | 17.7 | 33 | 33 | 429.8 | 0.02 | 903 |
| B12 | 865 | 40 | 12 | 23.4 | 24 | 343.8 | 0.015 | 788 |
| B13 | 643.5 | 483 | - | - | - | - | - | - |
表里 B13 全是横杠,不是漏抄,手册原本就没给这一档的辐射指标和信噪比——它是超宽通道,用途更偏信噪比兜底而不是定量反演,处理时不能按常规通道的饱和判据去卡它。另外 B4 那一行在原始排版里数字是连在一起的,标称辐亮度与 SNR 的比值和 NEdL 对不上,这一行必须回原表核对,后面第 6 章的自检脚本会把这类不自洽直接顶出来。
2.2 四档辐射亮度与 NEdL 的实际用途
标称辐亮度是设计参考点,SNR 指标就是在这个点上定义的,它不代表“正常观测就是这么多”,而是“在这个量级下我能达到这个信噪比”。海洋上限是清澈大洋水在典型观测几何下的上界,超过它说明视野里大概率不是干净水体。阈值是饱和警戒线,一旦像元值逼近阈值,这个像元的定量结果就该打问号。云上限则是云顶反射的量级,用来看动态范围够不够,不是让你拿它去反演云。
NEdL 是噪声等效差分辐亮度,单位与辐亮度一致,含义是“这套系统能分辨的最小辐亮度差”。它和 SNR 在设计点上是同一件事的两种写法,近似满足 NEdL ≈ 标称辐亮度 / SNR。拿 B1 验算:93 / 981 ≈ 0.0948,手册给 0.0939,差 1% 以内,属于有效数字取舍。B12 验算:12 / 788 ≈ 0.0152,手册 0.015,也对得上。这个关系看着平淡,但它是我校验波段表抄录是否准确的唯一低成本手段,只要有一行对不上 5%,那一行就值得回头翻原表。
提示:NEdL 是差分量的量级,别拿它当绝对误差上限去卡质量控制。它是用来算信噪比预算的,不是用来做像元剔除阈值的。
阈值辐亮度和海洋上限在多数通道只差几个百分点,比如 B1 是 139.5 和 143.1,B3 是 145.8 和 148,这个小间隙正好给了饱和前的缓冲。落到代码里,我一般把海洋上限当“可疑”标志位、把阈值当“作废”标志位,两级分开打,事后回溯能看出到底是水体异常还是接近饱和。
2.3 把波段表落成可 import 的配置
手抄参数进代码是翻车的经典起点。我的做法是先把表落成一份结构化的字典,单位单独存,再写一段一致性校验,把 NEdL 与 SNR 的比值关系全部跑一遍。这样下一次换版本或者换通道,只要跑一遍校验就知道有没有抄错。
# goci2_bands.py —— 手册波段表的结构化落地 # 字段顺序: (中心波长nm, 带宽nm, 标称辐亮度, 海洋上限, 阈值, 云上限, NEdL, SNR@标称) BANDS = { 1: (380.0, 20.0, 93.0, 139.5, 143.1, 634.4, 0.0939, 981), 2: (412.0, 20.0, 100.0, 150.0, 152.0, 601.6, 0.0951, 1050), 3: (443.0, 20.0, 92.5, 145.8, 148.0, 679.1, 0.0811, 1145), 4: (490.0, 20.0, 72.2, 115.5, 116.0, 682.1, 0.0590, 1128), 5: (510.0, 20.0, 64.9, 108.5, 122.0, 665.3, 0.0550, 1180), 6: (555.0, 20.0, 55.3, 85.2, 87.0, 649.7, 0.0490, 1124), 7: (620.0, 20.0, 53.3, 64.1, 65.5, 629.5, 0.0480, 1102), 8: (660.0, 10.0, 32.0, 58.3, 61.0, 589.0, 0.0300, 1060), 9: (680.0, 10.0, 27.1, 46.2, 47.0, 549.3, 0.0300, 914), 10: (709.0, 10.0, 27.7, 50.6, 51.5, 450.0, 0.0300, 914), 11: (745.0, 20.0, 17.7, 33.0, 33.0, 429.8, 0.0200, 903), 12: (865.0, 40.0, 12.0, 23.4, 24.0, 343.8, 0.0150, 788), 13: (643.5, 483.0, None, None, None, None, None, None), # 超宽通道,无辐射指标 } RADIANCE_UNIT = "W/m^2/um/sr" # 手册辐射亮度单位 def check_bands(tol=0.05): """用 NEdL ≈ 标称辐亮度/SNR 做抄录校验,返回超差通道""" bad = [] for b, (cw, bw, lnom, lmax, lthr, lcloud, nedl, snr) in BANDS.items(): if nedl is None or snr in (None, 0): continue # B13 之类无指标通道直接跳过 expect = lnom / snr rel = abs(expect - nedl) / nedl if rel > tol: bad.append((b, round(expect, 4), nedl, round(rel * 100, 2))) return bad if __name__ == "__main__": print(check_bands())这段代码的关键不在前半段的抄表,而在check_bands这个函数:它把“标称辐亮度除以 SNR 应该约等于 NEdL”当成一个物理约束,容差设 5%,正好能容忍有效数字取舍,又能卡住真实的抄录错误。tol不要往下调到 1%,手册本身的有效位数不够,会给你一堆假报警。跑完如果 B4 那条被报出来,说明原始排版确实粘连了,这时候不要改参数去迁就数据,回原表核对才是正解。
3. 视场与月球成像窗口:±11.4°、±8.6° 怎么算出可观测时段
月球定标这件事,难的不是公式,是“什么时候能拍”。GOCI-II 是静止轨道载荷,视场固定,月球每天从视场里过一趟,能拍的时间窗短则十来分钟。手册给了七条优先级判据和一张按月排布的候选窗口表,把这张表读懂,等于把一整年的定标计划提前排好了。
3.1 视场四个角度的几何自洽性
手册在结构描述部分给出的量是:南北向视场 ±11.4°,东西向 ±8.6°,地球圆盘对应 8.7°,仪器视场 1.1°,月球与恒星可用视场 1.1°,指向偏差余量 0.5°。后面讲月球成像判据时又出现了一组 ±11.0° 和 ±8.7°。两组数字不一致,这种时候不能靠“取平均”糊弄过去,要拿几何关系验一下哪组自洽。
南北向:地球圆盘 8.7° 加上仪器视场 1.1°、月球可用视场 1.1°、指向余量 0.5°,合计 11.4°,和第一组完全对上。东西向:东西向有效区域 8.06° 加指向余量 0.5° 等于 8.56°,取整就是 8.6°,也对上。换成 11.0° 和 8.7°,这个加和关系就断了。所以我采信 ±11.4°(南北)和 ±8.6°(东西),后面所有窗口计算都用这一组。
这个余量分配方式本身值得记一下:地球圆盘占掉绝大部分视场,剩下的边角才是月球和恒星的可用区域,再往里扣指向偏差。也就是说,月球能不能进视场,取决于它偏离地球圆盘多远,而不是它在地心坐标里的绝对位置。做窗口筛选时,判据永远落在“月球与地球圆盘的角距”上,这条搞错了,排出来的窗口全是废的。
3.2 七条优先级判据的筛选顺序
手册列的七条判据不是并列的,按优先级往下砍,前面的不满足,后面的算了也没意义。第一条是硬约束:月球必须落在视场内,且不做姿态机动,尤其禁止滚转机动。静止轨道载荷做机动代价太高,一旦要动机动,整个成像计划都得重排。第二条把时间锁在标称运行时段内,也就是本地时 05:15 到 19:45,出了这个区间,载荷本身处于待机或者别的任务状态。
第三条是月相,照亮面积要超过 50%。这条直接砍掉一半的日子,新月前后根本没法用。第四条是与其他载荷的运行时间不能完全重叠,GOCI-II 每小时能分到 15 到 45 分钟,这个额度决定了单次拍摄的帧数上限。第五条是连续单次可观测时长不低于 10 分钟,这条最容易被忽略——很多日子月球在视场里,但只待了几分钟,攒不够积分帧。
第六条是地球杂散光排除:月球像元如果离地球圆盘边缘太近,散射光会污染,所以要把距地球圆盘 1° 以内的区域整体剔掉。第七条才是质量优化,为了漫射板老化监测挑一个合适的相角范围,因为 ROLO 模型对相角的相对不确定度大约 1%,相角选得好,模型误差就压得住。
实际排计划时,我按 1→2→3→4→5→6→7 的顺序层层过滤,每一层保留中间结果,这样某一层砍太狠的时候能回头看清是哪条判据在起作用。直接把七条揉进一个 if 语句,出了问题连日志都读不出来。
3.3 把年度窗口表跑成风险清单
手册给了一张按月排的候选表,列出可观测天数、可观测时段、推荐时段和大致时长。2023 年往后没表怎么办?用同样的判据推,几何部分每年只有微小漂移,判据逻辑是不变的。我先把表整理成结构,再筛出时长压线的月份。
import pandas as pd # 手册年度候选窗口(月, 可观测天数, 推荐时段时长_min) win = pd.DataFrame({ "month": list(range(1, 13)), "obs_days": [21, 3, 12, 12, 11, 21, 22, 22, 11, 21, 4, 32], "duration_min": [30, 30, 38, 46, 29, 30, 39, 43, 30, 11, 12, 44], }) # 判据 5:连续单次可观测时长 >= 10 min,这里把 15 min 以下视为高风险 risky = win[win["duration_min"] < 15] print(risky) # month obs_days duration_min # 10 21 11 # 11 4 12 # 可观测天数异常检查:一个月不可能超过 31 天 print(win[win["obs_days"] > 31])这段代码做了两件事。第一件是把判据 5 的 10 分钟门槛往保守方向抬到 15 分钟,因为 10 分钟是理论下限,实际排计划还要留出指向稳定、快门动作、多个积分帧的余量,压着 11 分钟去排,一次指向漂移就白拍了。第二件是卡obs_days > 31这种明显不可能的值——表里 12 月写了 32 天,这不是我看错,是原始表格的笔误,脚本里做一次范围断言就能拦住,省得后面按 32 天去分配资源。
duration_min这个字段的单位要留意,手册给的是“约”,实际可用时长还受月球赤纬变化速度影响,冬半年月球在视场里移动更快,可用窗口更短。所以 10 月和 11 月这两个月不是“勉强能用”,是“基本排不出一次完整的月球序列”,真要在这两个月做定标,得提前接受掉帧的准备,或者干脆把定标周期设计成一年四次、绕开这两个月。
4. 月球校准链路:从 ROLO 系数到 R_Moon 比因子
月球定标的核心思路很朴素:月球反射率稳定,用模型算一个“应该看到多少”,再用载荷算一个“实际看到多少”,两者一除就是定标因子。难点全在“应该看到多少”这一侧——ROLO 模型给了逐波段的经验系数,公式里挂着相角、日月几何、月面经纬度,任何一项口径搞错,结果就偏出百分之几,而这个量级的偏差足以掩盖一年的增益退化。
4.1 ROLO 模型的 ln A_k 公式拆解
模型给的是盘等效反射率的自然对数,形式是一串多项式加指数项。相角 g 的高次项到三次,日经度 Φ 的奇次项到五次,再加观测点月面纬度 θ、经度 φ 的一次交叉项,最后三项是指数衰减和相角余弦修正。相角接近 0(满月)时,指数项主导,反射率的非线性最强;相角拉开之后,多项式项占比上来。这解释了为什么满月附近的定标结果对相角误差特别敏感。
手册给了 12 个波段的 a0 到 a3、b1 到 b3、d1 到 d3,系数值都带 5 到 6 位有效数字。注意 b 的下标:公式里写的是 j 从 0 到 3,但表里只给了 b1、b2、b3,也就是说实际参与运算的是 Φ 的一次、三次、五次项,b0 那一项不存在。同理,公式里的 c1 到 c4 四个交叉项系数,以及指数项里的 p1 到 p4 四个常数,手册只给了符号没给数值。
这是整份材料里最容易埋雷的地方。系数缺了,有人图省事就把缺失项整体清零,代码是跑通了,结果偏多少完全不知道。我的处理是把缺失项做成显式异常,宁可算不出来,也不要算出一个看似正常的值。
import numpy as np # 手册给出的 ROLO 系数(截取 B1、B8、B12 三条做示例,完整表按同样结构补全) ROLO_COEF = { 1: dict(a=[-2.53875, -1.73218, 0.424342, -0.222120], b=[0.034985, 0.010926, -0.003620], d=[0.345536, -0.01098, -0.00502]), 8: dict(a=[-1.89995, -1.58457, 0.308405, -0.180340], b=[0.043984, 0.009842, -0.003890], d=[0.371440, -0.13387, 0.012067]), 12: dict(a=[-1.74580, -1.58485, 0.350134, -0.195720], b=[0.041439, 0.016106, -0.005500], d=[0.391924, -0.18828, 0.009775]), } # 手册未给出数值的项,在这里显式声明,禁止静默置零 MISSING = {"c": [None] * 4, "p": [None] * 4} def ln_ak(band, g, phi_sun, theta, phi_obs): """计算 ln(A_k)。g/theta/phi 单位 rad;phi_sun 为太阳月面经度""" co = ROLO_COEF[band] a, b, d = co["a"], co["b"], co["d"] if any(v is None for v in MISSING["c"]) or any(v is None for v in MISSING["p"]): raise NotImplementedError( "ROLO 公式中 c1~c4 与 p1~p4 系数未在手册给出,必须补齐后再计算" ) # 以下为补齐系数后的完整形式,保留结构便于对齐 poly_g = sum(a[i] * g ** i for i in range(4)) poly_phi = sum(b[j] * phi_sun ** (2 * j + 1) for j in range(3)) c1, c2, c3, c4 = MISSING["c"] p1, p2, p3, p4 = MISSING["p"] cross = c1 * theta + c2 * phi_obs + c3 * phi_sun * theta + c4 * phi_sun * phi_obs expo = a[0] * 0 + d[0] * np.exp(-g / p1) + d[1] * np.exp(-g / p2) \ + d[2] * np.cos(g - p3) / p4 return poly_g + poly_phi + cross + expo这里的关键设计是MISSING这个常量字典和那个raise。它强迫使用者在拿到完整系数之前无法得到任何“看起来正常”的输出。poly_phi里我用2*j+1还原奇次幂,对应 Φ 的一次、三次、五次;如果照抄公式里 j 从 0 开始的下标去写phi_sun**j,幂次就全错了,这是纯抄公式最容易翻的一处。
4.2 积分月球辐照度的两步算法
有了逐波段的盘等效反射率,下一步是把它变成载荷能直接对比的积分辐照度。手册给的是一条带光谱响应加权的积分式:分子是太阳参考光谱、载荷光谱响应、月球反射率三者相乘后对波长积分,分母是光谱响应自身的积分,再乘一个月球立体角除以 π。这个 π 和立体角的前置因子最容易被漏,漏了就是量级错误。
第二步是距离改正。太阳到月球、月球到卫星的距离每天都在变,辐照度按距离平方反比走,所以要乘一个距离改正因子。手册里把它写成测量值等于参考值乘以改正因子,方向是“参考值 × 改正因子 = 测量值”。落到代码里,改正因子的分子分母谁在上面必须和这一致,反过来算,结果会差出十几个百分点。
立体角的取值手册给了 6.4177×10⁻⁵ sr,这是个固定常数,代表月球圆盘的平均张角对应的等效立体角,不要拿单次观测的几何去重算它。分母的光谱响应积分不能省,很多人直接把分子除以带宽,短波通道带宽窄、响应陡,这样算出来的偏差能到百分之几。
import numpy as np OMEGA_MOON = 6.4177e-5 # 月球等效立体角 sr,手册给定常数 def integrated_irradiance(wl, esun, resp, ak): """按光谱响应加权积分参考月球辐照度 wl : 波长网格 nm,等间隔 esun : 参考太阳光谱辐照度,与 wl 同长 resp : 该通道光谱响应,与 wl 同长,峰值归一到 1 ak : 该通道盘等效反射率(由 ln_ak 取 exp 得到) """ num = np.trapz(esun * resp * ak, wl) # 分子:三者相乘后积分 den = np.trapz(resp, wl) # 分母:响应自身积分 return OMEGA_MOON / np.pi * num / den # 单位 W/m^2/um def distance_corrected(i_ref, cdis): """距离改正:参考值 × 改正因子 = 测量值""" return i_ref * cdisnp.trapz的第二个参数是波长网格,单位要统一,全用 nm 或者全用 μm 都行,但esun的单位必须跟着改,混用会差三个数量级。resp峰值归一不是必须的,因为分子分母同比例缩放会抵消,但归一之后不同通道之间可以直接比数值大小,排查问题时省事。cdis这个改正因子按“日月距离 / 月卫距离”的平方比构造,具体口径要跟着手册走,我见过把它写成倒数导致整条定标序列单调漂移的案例,排查了两周才发现是一个除号写反。
4.3 过采样改正与像元立体角
GOCI-II 用的是二维 CMOS 步进凝视成像,没有扫描镜,所以不需要扫描速率改正,这一点手册明确写了。但月球和卫星在积分时间内都在动,像元会把月球“抹”开,形成过采样,必须做空间过采样改正。
手册给的判据很具体:积分时间设 4.5 秒以内,卫星平均轨道角速度约 72.9 μrad/s,单像元视场约 7 μrad。也就是说 1 秒内月球在焦面上移动约 10 个像元,4.5 秒最坏能到 50 个像元。月球角直径在 9000 μrad 量级,对应 1200 多个像元,被抹开 50 个像元大约是 4% 的展宽,这个量级直接吃掉定标精度。
改正因子的形式是月球真实角直径的反正切值与图像中实测角尺寸之比,本质是面积比。算的时候注意两个量的单位必须一致,arctan出来是弧度,图像角尺寸也得换成弧度,一个用 μrad 一个用 rad,结果差六个数量级。
像元立体角那条更简单:天底地面采样距离除以轨道高度再平方。轨道高度 35786 km,地面采样距离优于 250 m,代进去得到单像元立体角约 4.88×10⁻¹¹ sr。这个值小得离谱是正常的,因为它是从 3.6 万公里外看 250 米。把观测辐亮度乘上这个立体角再对月球圆盘内所有像元求和,才得到载荷侧的积分辐照度。
import numpy as np H_KM = 35786.0 # 轨道高度 km,手册给定 MOON_D_KM = 3476.4 # 月球直径 km def pixel_solid_angle(gsd_km): """单像元立体角,gsd 单位 km""" return (gsd_km / H_KM) ** 2 def oversample_factor(d_msat_km, y_moon_img): """过采样改正因子;y_moon_img 为图像中月球角尺寸,单位与 arctan 一致(rad)""" true_ang = np.arctan(MOON_D_KM / d_msat_km) # 真实角直径 return true_ang / y_moon_img if __name__ == "__main__": print("单像元立体角 =", pixel_solid_angle(0.25), "sr") # ~4.88e-11 # 地月距离 384400 km 时,真实角直径约 9.04e-3 rad print("CSAM =", oversample_factor(384400.0, 9.39e-3)) # ~0.963gsd_km传的是天底地面采样距离,手册说优于 250 m,那就按 0.25 km 算,得到一个保守的立体角上界。oversample_factor的两个输入必须同单位,我在这里统一用弧度,实际图像量出来的角尺寸是 μrad 的话,先除以 1e6 再传进去。算例里图像角尺寸比真实角直径大了 4%,改正因子 0.963,这个数乘到辐照度上,正好把抹开造成的能量摊薄补回来。
4.4 R_Moon 与老化因子的口径差异
手册最后定义了两个月球因子,一个叫月球辐照度比因子,等于载荷测得的积分辐照度除以模型参考值;另一个叫月球老化因子,等于参考值除以载荷测得值。两者互为倒数,用哪个取决于你要表达什么:比因子大于 1 说明载荷响应偏高,老化因子大于 1 说明性能在退化,需要一个大于 1 的补偿系数。
这两个量混用是常见事故。做时间序列监控时,如果前半段用比因子、后半段用老化因子,画出来的曲线会在切换点出现一个倒数的跳变,看起来像载荷突变了。我的习惯是内部统一只存比因子,需要老化因子的时候现取倒数,绝不把两个量同时落库。
手册还提到一个技术限制:月球在一次成像里只覆盖部分探测像元,而 ROLO 模型只能给整个圆盘的积分值,所以月球定标不适合做逐像元的绝对定标去直接更新增益,它给的是全画幅的平均退化趋势,逐像元的不一致性要靠平场数据单独处理。这句话决定了整个定标流程的定位——月球定标是慢变量监控,不是快变量校正,指望它修好坏像元是不现实的。
5. 避坑与排查:五处能让流程静默出错的参数陷阱
5.1 波段编号被当成波长写进了公式
现象:某次交接的文档里写着“波段中心范围从 2412 nm 到 743.5 nm”,照这个范围去建波长网格,短波端直接越界,光谱响应插值全返回 NaN,程序不报错,积分结果一路是空值。
原因:把通道编号和中心波长混在了一起,B2 被写成 2412,B11 被写成 743.5。这类错误在二手整理文档里特别常见,因为表格一压缩,编号列和波长列就黏上了。
解决:波长网格永远从结构化配置里取,不从文档描述里抄。建网格之前先断言“中心波长单调递增且落在 300 到 900 之间”,越界直接抛异常。上面 2.3 节那份字典就是为此存在的,它是唯一事实来源。
5.2 视场角度出现两组数值时不要取平均
现象:手册前后两处分别给出南北向 ±11.4° / ±11.0°、东西向 ±8.6° / ±8.7°,按平均后的值去排窗口,边界日的月球会时而在视场内、时而在视场外,可观测天数统计每个月都差一两天。
原因:不同章节写作时用了不同的取整或不同的设计余量定义,两组数不是同一口径下的测量重复。
解决:用几何加和去验,地球圆盘 8.7° 加两级各 1.1° 的视场再加 0.5° 指向余量正好等于 11.4°,这组才是设计口径。验不出来就先按保守值(较小的一组)排窗口,宁可少拍一天,也不要拍到一半发现月球在视场边缘被截断。
5.3 辐亮度与辐照度的单位混用
现象:把 W/m²/μm/sr 的辐亮度直接和 W/m²/μm 的辐照度相除,得到的比因子量级在 10⁻¹¹ 附近,看着像极了真实值,其实是立体角没乘进去。
原因:两个量的量纲差一个立体角,单位符号又长得很像,肉眼扫过去区分不出来。
解决:配置里给每个物理量单独存单位字符串,参与运算前做一次量纲断言。辐亮度到辐照度的转换必须显式乘立体角,代码里把这步单独写成一个函数,函数名带上to_irradiance,让调用处一眼能看出来这里发生了量纲变化。
5.4 距离改正因子的乘除方向搞反
现象:定标序列在半年内单调漂移 8% 左右,同期没有其他异常,换成别的定标源又对不上,排查很久找不到原因。
原因:距离改正因子该乘的地方除掉了。地月距离的年变化幅度在 3% 到 5% 量级,平方之后正好能解释这个漂移量级,特征就是“平滑、单调、与季节相关”。
解决:把改正关系写成一句断言式注释贴在函数上——“参考值 × 改正因子 = 测量值”,函数内部只允许这一个方向。再用一个已知日期的样例数据做回归测试,地月距离近地点附近改正因子应略大于 1,远地点附近略小于 1,跑一遍就知道方向对不对。
5.5 超宽通道没有辐射指标,别按常规通道处理
现象:批处理跑全 13 个通道,跑到最后一个通道时质量控制全部判为异常,或者直接除零崩掉。
原因:643.5 nm 中心、483 nm 带宽的这个通道,手册的辐射指标列全是横杠,没有标称辐亮度也没有 SNR,标称辐亮度除以 SNR 这一步必然出错。
解决:在配置里显式标记该通道的可计算性,None就是None,不要用 0 填充。质量控制、饱和判据、信噪比预算这三条链路都要先判断该通道是否有指标,没有指标就走单独的分支,只做几何和信噪比兜底,不参与定量反演链的逐级传递。
6. 把参数变成断言:一套跑在数据入库前的自检清单
参数表最大的价值不是给人看,是给机器验。我把这份手册里所有能验证的关系整理成一组断言,挂在数据入库之前,跑完不到一秒,能拦住九成以上的参数类事故。下面是精简后的版本,实际用的时候每个断言后面都带一条中文提示,失败时直接告诉排错的人去看手册哪一节。
import numpy as np from goci2_bands import BANDS def assert_baseline(tol=0.05): # 1) 通道数量与编号连续性 assert len(BANDS) == 13 and sorted(BANDS) == list(range(1, 14)), "通道数或编号不连续" # 2) 中心波长单调递增,且落在可见近红外合理区间 cw = [v[0] for v in BANDS.values()] assert all(b > a for a, b in zip(cw, cw[1:])), "中心波长非单调" assert 300 < min(cw) and max(cw) < 900, "中心波长越界" # 3) 带宽为正,且不超过中心波长的量级 for b, v in BANDS.items(): assert v[1] > 0, f"B{b} 带宽非正" assert v[1] < v[0], f"B{b} 带宽大于中心波长,疑似单位错" # 4) NEdL 与 SNR 的自洽性 for b, v in BANDS.items(): nedl, snr = v[6], v[7] if nedl is None or snr is None: continue rel = abs(v[2] / snr - nedl) / nedl assert rel <= tol, f"B{b} NEdL/SNR 不自洽,偏差 {rel:.1%},回原表核对" # 5) 四档辐亮度的大小顺序 for b, v in BANDS.items(): if v[3] is None: continue assert v[2] < v[3] < v[5], f"B{b} 标称/海洋/云上限顺序异常" # 6) 像元立体角量级 omega = (0.25 / 35786.0) ** 2 assert 1e-12 < omega < 1e-10, "像元立体角量级异常,检查 GSD 或轨道高度单位" return True if __name__ == "__main__": try: assert_baseline() print("参数基线通过") except AssertionError as e: print("基线校验失败:", e)六个断言各自盯一类问题:通道数和编号连续性防止表格被截断;波长单调和范围防止编号波长混写;带宽与中心波长的比值能抓到单位混用,真正把 μm 当 nm 抄进来的时候,带宽会大于中心波长;NEdL 与 SNR 的自洽性就是第 5 章那个 B4 行的照妖镜;四档辐亮度的大小顺序能抓出上下限写反;像元立体角的量级检查纯粹是防单位,gsd_km要是误传成 250 而不是 0.25,立体角会大六个数量级,这个断言一秒拦住。
这套东西我从一次特别低级的翻车里总结出来:当时换了新一批数据,反演结果的叶绿素浓度整体偏高两倍,查了三天以为是大气校正出了问题,最后发现是有人在配置里把 555 nm 通道的标称辐亮度抄成了 85.3,而正确值是 55.3,两个数字调了个个儿。这个错误在 NEdL 自洽性那条断言下活不过一秒,可当时没有断言,它硬是活过了整条流水线。从那以后我每次接入新版本参数表,都强制先跑一遍这套断言,再谈业务逻辑;参数不对,后面写多少代码都是白搭。希望这套清单能帮到你。
本文还有配套的精品资源,点击获取