☰
葵花8 AHI机器学习反演地面太阳辐射完整流程
2026/10/2 4:03:35 网站建设 项目流程

简介:一份面向遥感、气象与环境监测方向开发者及科研人员的完整Python实践项目,基于葵花8号气象卫星AHI多光谱传感器数据,借助机器学习算法反演地表太阳辐射,适用于气候研究、环境监测与光伏能源评估等场景。压缩包共3个文件,整体约2.58MB,包含已训练模型文件、数据加载与建模脚本及示例卫星数据,覆盖从影像读取、特征构建到模型推理的完整链路。已有251人浏览学习。借助压缩包内的模型与脚本可快速复现机器学习遥感反演方案,了解监督学习在辐射估算中的特征选择、参数调优与模型验证思路,并可基于示例数据检验模型效果,进一步扩展至近实时太阳辐射监测系统的开发部署,对气候变化应对与灾害预警研究具有实用参考价值。

1. 卫星不直接测辐射:葵花8 的 AHI 数据怎么靠机器学习算出地面太阳辐射

地面太阳辐射数据是光伏选址、农业气象和建筑能耗模拟的刚需,但地面辐照度观测站稀疏,很多区域根本没有实测。葵花8 卫星的 AHI 传感器能看到整个圆盘,10 分钟一景,多光谱覆盖可见光到热红外,但卫星测的是大气顶的反射辐射,不是地面接受到的辐照度。物理反演模型要处理气溶胶、水汽、云等多种参数,调起来很繁琐,而且在不同地表和大气条件下经常失灵。机器学习把这个问题变成了回归任务:用 AHI 的反射率、观测几何和时间信息去拟合地面辐射值,效果往往比传统查表法更稳。这份资源包给出的正是完整反演流程,适合做太阳能资源评估、遥感反演或相关课程设计的人直接拿来改。

2. 反演前的数据底子:AHI 波段特点、辐亮度定标与几何参数处理

2.1 为什么选葵花8 的 AHI 而不是 MODIS

做地面太阳辐射反演,数据源选择直接影响模型上限。MODIS 有 36 个波段,光谱信息丰富,但它是极轨卫星,一天过境两次,无法捕捉一天内辐射的连续变化。葵花8 是静止轨道卫星,固定在东经 140.7 度赤道上空,对同一区域每 10 分钟输出一景全圆盘影像,时间分辨率远高于极轨卫星。AHI 的波段设置也适合辐射反演:可见光 0.47、0.51、0.64 微米反映云和地表反射,近红外 0.86、1.6、2.3 微米对植被和水汽敏感,热红外波段 10.4、11.2、12.4 微米可以辅助云检测。这套波段组合基本覆盖了辐射传输中关键的散射和吸收窗口。

空间分辨率方面,AHI 可见光波段最高 0.5 公里,红外波段约 2 公里。反演地面辐射不需要太高的空间分辨率,2 公里尺度已经能匹配大部分太阳能评估场景,而且能避开 MODIS 那样的条带拼接问题。如果做站点尺度的验证,把 AHI 数据重采样到站点经纬度附近窗口取平均即可。资源包里的脚本默认按 2 公里分辨率统一处理,理由就在这里:可见光波段降采样到 2 公里后,噪声明显减少,训练出的模型更稳定,不会因单像元异常导致辐射预测跳变。

2.2 辐亮度定标:从 DN 值到反射率,别跳过这步

AHI 原始数据常见的有两个层级:一种是 JMA 发布的 HRIT 格式,另一种是经预处理的 L1 级 NetCDF。无论是哪种,拿到手的第一步都是辐射定标,即把原始数字量化值 DN 转换成物理量。可见光与近红外波段需要得到表观反射率,红外波段需要得到亮温或辐射亮度。资源包脚本在读入 NetCDF 后会检查数据属性中的 scale 和 offset,缺少这一步直接用原始 DN 值训练,模型学到的只是传感器响应的线性变换,换一个时段的数据立刻失效。

import xarray as xr import numpy as np ds = xr.open_dataset("AHI_L1_202407151030.nc") # 波段 03 是 0.64 微米可见光,提取后做定标 band03 = ds["band03"].values.astype(np.float64) scale = ds["band03"].attrs.get("scale_factor", 1.0) offset = ds["band03"].attrs.get("add_offset", 0.0) refl = band03 * scale + offset # 表观反射率 refl = np.clip(refl, 0.0, 1.2) # 极端值截断,防止太阳耀斑带来的异常高值

这段代码先把波段数据转为 float64 防止溢出,再通过属性中记录的 scale_factor 和 add_offset 完成定标。最后用 clip 限制反射率范围,原因是云边和耀斑区可能出现大于 1 的反射率,直接保留会影响模型对晴空和云像元的区分。如果你使用的 AHI 数据已经是反射率产品,可以跳过这一步;但建议仍然打印数值范围确认,很多公开数据集的定标系数在不同版本间改过,肉眼检查是对黑匣子的基本尊重。

太阳天顶角余弦值是辐射反演中最强的单变量特征之一,需要单独计算。AHI 产品的几何文件通常提供每个像元的太阳天顶角,若只有时间戳和经纬度,可以用 pysolar 或 astropy 按过境时间计算,然后重采样到波段网格:

from pysolar.solar import get_altitude from datetime import datetime, timezone lat, lon = 30.5, 114.2 dt = datetime(2024, 7, 15, 2, 30, tzinfo=timezone.utc) altitude = get_altitude(lat, lon, dt) # 太阳高度角,度 cos_sza = np.cos(np.radians(90.0 - altitude)) # 转为天顶角余弦

这里用的是站点经纬度而不是像元中心经纬度,因为全圆盘影像中远离星下点的区域像元几何形变大,站点位置处的几何参数才是实际观测时刻的太阳位置。如果数据产品自带几何波段,优先用产品值;自算几何仅作为补充或校验手段。

2.3 云像元过滤:不滤云,模型会拼命学云的特征

地面太阳辐射反演有个天然矛盾:云是影响辐射最大的因子,但可见光通道里云和地表在反射率上有重叠,模型容易把厚云判成高反射率地表。资源包里的做法是先做云掩膜,再分晴空与云天分别建模。最简单可靠的云掩膜用红外亮温差实现:云顶亮温低,地表在 11 微米附近的亮温通常高于 270K,取 10.4 微米与 12.4 微米亮温差可以识别卷云。

bt11 = ds["band14"].values * scale + offset # 10.4 微米亮温 bt12 = ds["band15"].values * scale + offset # 12.4 微米亮温 cloud_mask = (bt11 < 270.0) | ((bt11 - bt12) > 2.0)

第一项用绝对亮温 270K 区分低云和地表,第二项是分裂窗差值识别卷云。单靠阈值会误伤高海拔冷地表,比如青藏高原冬季地表亮温低于 270K,会被当成云。保险做法是叠加可见光反射率判断:反射率大于 0.4 且亮温低于 280K 才是云。你可以在资源包的预处理脚本里看到这套组合判断逻辑,实际使用时建议根据你研究区域的气候特性微调阈值。

3. 特征工程与训练集构建:不是把所有波段丢给模型就完事

3.1 波段相关性分析:选特征先看冗余

AHI 16 个波段中不少是相关的。0.47 和 0.51 微米都受瑞利散射影响,晴空下二者反射率高度相关;近红外 0.86 与 1.6 微米在植被覆盖区也强相关。把全部波段堆给模型不是不行,随机森林能容忍一定冗余,但会导致训练时间变长、模型解释性变差,尤其在样本量不大的情况下还容易过拟合。资源包脚本内置了相关性筛选逻辑:先计算各波段与辐射真值的 Pearson 相关系数,再计算波段之间的相关系数,保留与真值相关高、且互相相关低于 0.85 的波段。

import pandas as pd # df 每一行是一个样本:特征列 + 辐射真值列 corr_target = df.corr()["ghi"].abs().sort_values(ascending=False) drop_list = [] for i in range(len(corr_target.index)): for j in range(i + 1, len(corr_target.index)): f1, f2 = corr_target.index[i], corr_target.index[j] if f1 == "ghi" or f2 == "ghi": continue if abs(df[[f1, f2]].corr().iloc[0, 1]) > 0.85: # 保留与目标相关性更高的那个,去掉另一个 drop_list.append(f2 if corr_target[f1] > corr_target[f2] else f1) features = [c for c in df.columns if c not in set(drop_list) and c != "ghi"]

这段循环按 0.85 阈值做冗余筛除,保留与地面辐射相关性更高的波段。0.85 的经验值来自常见遥感特征选择实践,你如果用 XGBoost 这类对冗余不敏感的模型,可以放宽到 0.92;但如果你用线性模型或 BP 神经网络,建议收紧到 0.8。资源包默认给出的特征子集是 0.47、0.64、0.86、1.6、2.3 微米反射率加上太阳天顶角余弦和相对方位角,共 7 个特征。实测中这组特征能覆盖约 90% 的解释信息,增加更多波段对精度提升有限。

3.2 辐射-几何-时间三元特征:为什么几何参数比部分波段还重要

地面太阳辐射的物理机制是:辐射量等于大气层顶辐射乘以大气透过率。大气层顶辐射由太阳常数和太阳天顶角决定,因此太阳天顶角余弦本身就是辐射值的下界估计。把 cos(SZA) 作为特征等于给了模型一个物理锚点,模型只需要学透射率的修正项。观测几何中还有一个容易被忽略的参数是相对方位角,即太阳方位角与卫星观测方位角的差值,它影响地表二向反射,在可见光波段中会带来显著的方向性变化。

时间特征是必要的补充。葵花8 覆盖范围内季节变化明显,太阳高度角逐日变化,只给模型瞬时几何参数而不给日期,模型无法区分同一几何角出现在冬季还是夏季。资源包中的常用处理是把日期转为年积日和当地太阳时两个连续变量,年积日用正弦余弦编码避免 12 月 31 日与 1 月 1 日的跳变。

df["doy_sin"] = np.sin(2 * np.pi * df["doy"] / 365.25) df["doy_cos"] = np.cos(2 * np.pi * df["doy"] / 365.25) df["hour_local"] = df["hour_utc"] + 8.0 # 东八区示例,按目标区调整

正弦余弦编码保证了 1 月 1 日和 12 月 31 日在特征空间中是相邻的,不会出现数值上的断裂。当地太阳时的计算要考虑经度修正,单用 UTC+8 在西部省份会有明显偏差,建议用经度除以 15 做修正。这套编码在资源包的多处脚本中都有体现,也是模型在跨季度预测时不掉链子的关键。

3.3 训练集构建:站点匹配、时间对齐与样本平衡

训练样本来自地面站点。常见做法是取卫星过境时刻前后 10 分钟内的地面辐射平均值作为真值,与 AHI 影像像元对应。这里有三个细节直接影响样本质量:第一,地面辐射计观测的是水平面总辐射 GHI,而卫星像元对应的物理量是大气顶反射率,两者之间是透过率关系,模型学习的是这个非线性映射;第二,站点经纬度所在像元和周围 3x3 像元窗口的均值更稳定,单像元容易受配准误差影响;第三,站点数据需要质量控制,剔除辐射值异常、太阳高度角过低和仪器维护时段的数据。

# 假设站点观测为逐分钟数据,提取卫星过境时刻前后10分钟均值 obs_time = pd.Timestamp("2024-07-15 02:30:00", tz="UTC") window = obs_time - pd.Timedelta(minutes=10), obs_time + pd.Timedelta(minutes=10) ghi_mean = station_df.loc[window[0]:window[1], "ghi"].mean() sample = {"ghi": ghi_mean, "cos_sza": cos_sza, "band03": refl_3x3}

这里取了 20 分钟的观测窗口取平均,能有效平滑辐射计的瞬时波动。资源包训练集默认只保留太阳高度角大于 5 度的样本,原因是低角度下大气路径长、辐射值小,观测噪声相对大,且卫星观测几何不佳。样本平衡上,晴天和云天样本比例如果不控制,模型会偏向样本多的那一类。常见方式是分别统计晴空和云天样本量,按较少类别的数量对较多类别做不放回采样,或给少数类更高的样本权重。

4. 模型训练与调参:随机森林、XGBoost 和 LightGBM 的取舍

4.1 模型选型逻辑:先跑基线再看复杂度

辐射反演的机器学习模型不需要一上来就上深度学习。AHI 波段数和特征总数在几十量级,样本量如果是数万到数十万,树模型已经能拟合大部分非线性关系,而且训练快、调参直观、可解释性也好。资源包里的基线模型是随机森林,n_estimators 设为 300,max_depth 限制在 12,min_samples_leaf 设为 5。这么设的原因在于,辐射反演不是要完美拟合训练集,而是要在地理外推时保持稳定;树深度过大容易记住特定站点的大气特征。

如果随机森林精度不够,再换 XGBoost 和 LightGBM。两者都支持正则化,对特征尺度不敏感,训练速度比随机森林快一个量级。XGBoost 在中小数据集上通常表现更稳,LightGBM 的直方图算法在大样本上占优势。资源包的对比实验中,样本量小于 10 万时 XGBoost 的 R² 略高于 LightGBM,超过 10 万后两者基本持平,但 LightGBM 训练时间只有前者三分之一。如果你只是为了课程设计或验证方法,随机森林足够了;如果要做业务级精度,可以重点调 XGBoost 的 max_depth 和学习率。

4.2 数据划分:随机划分是最大的错误

时间序列数据最忌讳随机打乱后划分训练集和测试集。卫星影像和站点观测都有强时间自相关,相邻时刻的样本高度相似,随机划分会让模型在测试集上偷看到邻近时刻的信息,验证指标虚高。正确做法是按时间顺序划分:例如用 2023 年 1 月到 10 月的数据训练,11 月到 12 月验证,再用 2024 年数据测试。资源包里三种划分方式都有,默认推荐的是时间和空间双重划分。

train = df[df["time"] < "2024-01-01"] val = df[(df["time"] >= "2024-01-01") & (df["time"] < "2024-04-01")] test = df[df["time"] >= "2024-04-01"]

空间上的划分更严格:选择某些站点只用于训练、另一些站点只用于测试,检验模型的地理泛化能力。很多卫星反演模型在训练站点上精度很高,一换站点性能立刻下降,问题就出在地表类型差异上。如果资源包允许按站点拆分,我会优先这么做,因为它更贴近实际应用场景——你最终要把模型用到没有地面观测站的地方。

4.3 关键超参数与调参方向

核心超参数就那么几个:树模型的 max_depth 控制单棵树复杂度,learning_rate 控制学习速度,subsample 和 colsample_bytree 控制随机性。经验规律是:先固定 learning_rate 为 0.05,用网格搜索确定 max_depth 在 6 到 12 之间的最优值;然后增大 n_estimators,观察验证集损失是否继续下降;如果过拟合明显,加大 min_child_weight 和 subsample。

import xgboost as xgb params = { "objective": "reg:squarederror", "max_depth": 8, "learning_rate": 0.05, "subsample": 0.8, "colsample_bytree": 0.7, "min_child_weight": 3, "eval_metric": "rmse", } dtrain = xgb.DMatrix(X_train, label=y_train) dval = xgb.DMatrix(X_val, label=y_val) bst = xgb.train( params, dtrain, num_boost_round=2000, evals=[(dval, "val")], early_stopping_rounds=50, verbose_eval=100, )

colsample_bytree 设为 0.7 意味着每棵树只用 70% 的特征,这能降低特征间的共线性影响。early_stopping_rounds 设为 50,验证集 RMSE 连续 50 轮不下降就停止,避免过拟合。注意这里的 eval_metric 用 RMSE 而不是 R²,因为 RMSE 直接反映辐射值误差的大小,单位是瓦每平方米,更容易和业务需求挂钩。调参的一个底线原则是:每改一次参数,都要重新按时间划分验证,绝不能用测试集反复试,否则测试集就变成了训练集的一部分。

4.4 模型对比与评估口径

评估时不能只报告 R²。R² 对异常值不敏感,而辐射反演中最怕的是在阴天边缘时刻预测偏差大。资源包里统一用三个指标:R²、RMSE 和 MAPE。RMSE 反映大误差,MAPE 反映相对误差,但 MAPE 在辐射值接近零时会爆炸,所以只在太阳高度角大于 10 度的样本上计算。晴天和云天样本分别统计也很重要,因为晴天的 RMSE 通常只有几十瓦每平方米,云天会到一百以上,混在一起统计会把晴天的优势掩盖掉。

模型对比表按数据段划分:晴空、云天、全部。如果你的资源包里只有随机森林脚本而没做对比,建议至少跑一个简单线性回归作基线。辐射反演问题中,线性回归用同样的特征通常能拿到 0.85 左右的 R²,如果树模型连 0.88 都达不到,说明特征或数据处理有问题,不是模型的问题。这个排查思路能在训练早期快速发现问题。

5. 避坑与常见问题:反演结果偏低或发飘的五类根源

5.1 现象:晴空反演结果整体偏低 20 到 40 瓦每平方米

原因分析:地面辐射真值用的是水平面总辐射 GHI,而模型输入的表观反射率受大气分子散射影响,晴空下瑞利散射会抬高可见光波段的反射率。模型学到的是反射率与 GHI 的关系,如果训练集里缺少低气溶胶、高透明度的高辐射样本,模型对晴空高值区的外推能力不足,预测结果就会整体偏低。

解决方案:先检查训练集辐射真值的分布,看最大值是否超过 1000 瓦每平方米。如果最大只有 900 左右,说明缺少夏季正午的强辐射样本。常见做法是按太阳高度角分层采样,确保 cos(SZA) 大于 0.8 的样本占比不低于 15%。另一个补救措施是给特征中加入气溶胶光学厚度 AOD 产品数据,如果没有外部 AOD,可以用 0.47 和 0.64 微米波段的比值做近似代替,瑞利散射在短波更强,比值偏离理论值的程度能间接反映气溶胶负荷。

5.2 现象:模型在冬季表现尚可,夏季误差突然增大

原因分析:夏季太阳高度角高,地表辐射强,但也是对流云高发季节。云的种类多样,积云边缘的反射率梯度大,AHI 的 2 公里分辨率无法完全分辨云的边界。一个 2 公里像元内含半云半晴,平均反射率对应着一个不存在的辐射状态,模型给出的预测值也落在非晴非云的中间区域,误差自然大。

解决方案:有两种路径。一是过滤掉混合像元:用 3x3 窗口内反射率的变异系数做筛选,变异系数大于 0.3 的样本直接丢弃,这类样本本身代表空间不均匀,站点观测的 20 分钟均值也难以代表面尺度辐射。二是单独训练云天模型和晴空模型,把问题拆开。资源包做法是同时保留两条路径,先分类后回归。

5.3 现象:模型在 A 区域验证很好,换到 B 区域性能骤降

原因分析:训练站点集中在单一地表类型上。例如站点都在城市周边,训练样本的地表反射率特征主要来自建筑和裸土;换到植被茂密的区域,近红外波段的反射率特征完全不同,模型学到的映射关系失效。这是空间外推失败的典型案例。

解决方案:确认训练集站点覆盖的经纬度范围是否与实际应用区域一致,不一致时至少要保证特征空间覆盖度足够。一个实用做法是统计训练站点 NDVI 的分布,计算方式是 (0.86 微米反射率 - 0.64 微米反射率) 除以二者之和,然后用核密度匹配,保证应用区域的 NDVI 值落在训练集的覆盖区间内。超出覆盖范围的像元,预测结果应标记为低置信度。

5.4 现象:白天时段预测稳定,日出日落时段误差明显

原因分析:太阳高度角低时,大气路径增长,气溶胶和水汽的影响被放大,而 AHI 在低角度下的观测几何导致反射率的信噪比下降。另外训练样本中低角度样本占比天然少,模型在该区域拟合不充分。误差集中在日出后和日落前两小时。

解决方案:对低太阳高度角样本单独训练一个校正模型,或直接在这些时段降低模型输出的权重。资源包里更实用的做法是:预测结束后用太阳高度角余弦加权的局部线性回归对残差做一次薄板样条校正,输出的最终 = 模型预测值 + 校正值。这个技巧能显著改善日出日落时段的连续性。

5.5 现象:预测值出现明显条带或块状噪声

原因分析:AHI 影像在拼接和重采样过程中可能出现行与行之间的亮度差异,尤其在全圆盘边缘区域。如果训练时没有对输入影像做空间平滑,模型会把这种条带噪声当成真实反射率特征。另一种可能是辐亮度定标参数在影像边缘部分失效,导致反射率值偏移。

解决方案:在预处理中增加一步 3x3 中值滤波,只对反射率特征做,不动原始影像。中值滤波能有效去除椒盐噪声而不模糊云边界。同时建议在建模前把所有特征矩阵标准化,但不要用全局均值方差,而是按月份分别标准化。辐射值的季节变化显著,全局标准化会压缩夏季特征的变化范围,导致季节性的预测精度下降。

6. 验证指标与进阶用法:从单时刻反演到批量处理管线

6.1 验证指标怎么算才能真实反映模型能力

验证时按天聚合再计算指标,比按样本直接计算更符合业务需求。站点观测和卫星观测在样本级别上的随机误差会在日均值中抵消一部分,按天计算 RMSE 更能反映实际日累积辐射预测的精度。具体做法是:先对每个站点每天做平均,再在日平均值上计算 R² 和 RMSE。

daily_pred = test_df.groupby(["station", "date"])["pred"].mean() daily_true = test_df.groupby(["station", "date"])["true"].mean() rmse_daily = np.sqrt(((daily_pred - daily_true) ** 2).mean())

如果你关注的是光伏发电量,还要单独计算日累积辐射量误差。瞬时辐射的 RMSE 达到 80 瓦每平方米并不算大问题,但累计到一天可能导致日辐射总量偏差百分之十五以上。这个指标最容易让业务方理解模型的价值。资源包脚本输出的评估报告里包含瞬时和日累积两种统计口径,建议你在实际项目中保留同样的双口径分析。

6.2 批量处理管线:单景影像怎么拓展到全年

把单景预处理脚本扩展成批量管线有三个关键改动:一是按文件时间自动排序并记录处理状态,防止中断后重复计算;二是为每个站点建立独立的输入文件,避免特征拼接时索引错乱;三是把模型预测和验证分成两个独立脚本,训练只用历史数据,预测只读取最新影像。推荐用配置文件管理路径和参数,而不是硬编码在脚本里。

python preprocess.py --input ./AHI_netcdf/ --output ./features/ --config config.yaml python train_model.py --features ./features/train/ --model ./output/model.pkl python predict_batch.py --features ./features/infer/ --model ./output/model.pkl --out ./output/prediction.nc

三个命令行脚本各干一件事,配上配置文件后在服务器上可以丢进 crontab 定时执行。实际部署时要注意内存管理:葵花8 全圆盘单景数据大小在几百兆到 1G 之间,一年数据量可观,建议按天分批处理,处理完压缩特征表并删除元数据。

6.3 进阶方向:分季节建模与极端辐射值修正

提升精度的两个实用技巧:分季节建模和极端值修正。把训练集按气象季节分成四个子集,分别训练四个模型,预测时根据日期自动选用对应模型,这样能避开季节不stationary问题。极端值修正针对的是高辐射晴空场景,随机森林预测的高辐射值容易偏低,因为树模型无法超出训练集最大值的外推限制。常见做法是二次建模:对残差大于阈值的高辐射样本单独训练一个线性回归,叠加到主模型输出上。

从资源包整理出的这整套流程,我在自己的光伏资源评估项目中跑了不下十遍。从那以后我每次换区域或者换数据集,都强制走一遍同样的路线:先画特征相关性矩阵,再按时间划分验证,最后按天聚合评估,三条缺一不可,避免了很多后续返工。整个流程的主体框架、参数设置和处理思路都在资源包里,下载后对照本文逐节复现,跑通一条站点到辐射预测的完整链路不会太费周折,希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询