
简介《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)标称辐亮度海洋上限阈值云上限NEdLSNR标称B13802093139.5143.1634.40.0939981B241220100150152601.60.09511050B34432092.5145.8148679.10.08111145B44902072.2115.5116682.10.0591128B55102064.9108.5122665.30.0551180B65552055.385.287649.70.0491124B76202053.364.165.5629.50.0481102B8660103258.3615890.031060B96801027.146.247549.30.03914B107091027.750.651.54500.03914B117452017.73333429.80.02903B12865401223.424343.80.015788B13643.5483------表里 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.1B3 是 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(tol0.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 单位 radphi_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*j1还原奇次幂对应 Φ 的一次、三次、五次如果照抄公式里 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 被写成 2412B11 被写成 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(tol0.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, fB{b} 带宽非正 assert v[1] v[0], fB{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, fB{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], fB{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 自洽性那条断言下活不过一秒可当时没有断言它硬是活过了整条流水线。从那以后我每次接入新版本参数表都强制先跑一遍这套断言再谈业务逻辑参数不对后面写多少代码都是白搭。希望这套清单能帮到你。本文还有配套的精品资源点击获取