3、预报产品获取:GFS/ECMWF数据源、API接口调用、数据格式解析
好,咱们进入正题。预报产品怎么拿到手?这是所有后续工作的基础。你算法再牛,模型再先进,拿不到数据,一切都是空谈。
我个人习惯把数据获取分成三步:选源、调接口、解格式。每一步都有坑,我踩过的坑,今天都给你摆出来。
3.1 两大主流数据源:GFS 与 ECMWF
目前风电调度用得最多的,就是美国的 GFS 和欧洲的 ECMWF。说白了,一个免费但粗糙,一个收费但精细。
| 对比项 | GFS(全球预报系统) | ECMWF(欧洲中期天气预报中心) |
|---|---|---|
| 空间分辨率 | 约 13 km(0.25°) | 约 9 km(0.1°) |
| 时间分辨率 | 3 小时(0-240h),12 小时(240-384h) | 1 小时(0-90h),3 小时(90-240h) |
| 更新频次 | 每天 4 次(00,06,12,18 UTC) | 每天 2 次(00,12 UTC) |
| 获取成本 | 免费 | 商业授权(较贵) |
| 适用场景 | 短期功率预测、资源评估 | 中期调度、极端天气预警 |
我的建议:日常调度用 GFS 就够了,省钱。但遇到台风、寒潮这类极端天气,我强烈建议你切到 ECMWF。我在福建项目上吃过亏,GFS 对台风路径的预报偏差了 80 公里,差点导致电网切负荷。
3.2 API 接口调用:别让数据卡在第一步
拿到数据源之后,怎么调?现在主流方式是通过 RESTful API。我给你看一个我常用的 Python 示例,调用 NOAA 的 GFS 数据接口。
import requests
import json
# GFS 数据 API 端点(示例)
url = "https://api.weather.gov/points/39.7456,-97.0892"
headers = {
"User-Agent": "MyWindApp/1.0 (myemail@example.com)",
"Accept": "application/json"
}
try:
response = requests.get(url, headers=headers, timeout=10)
response.raise_for_status()
data = response.json()
print("数据获取成功!")
# 后续解析...
except requests.exceptions.Timeout:
print("请求超时,检查网络或重试。")
except requests.exceptions.HTTPError as e:
print(f"HTTP 错误:{e.response.status_code}")
except Exception as e:
print(f"其他错误:{e}")
避坑指南:我曾经因为没加 User-Agent,被 NOAA 的 API 直接封了 IP。记住,很多免费 API 都有频率限制,别用默认的 Python requests 头,容易被当成爬虫。
为什么会这样?因为这些气象机构要防止滥用。你想想看,如果每个人都不加限制地狂刷数据,服务器早崩了。所以,加 User-Agent、控制请求频率、做好重试机制,这是基本功。
3.3 数据格式解析:GRIB2 与 NetCDF
数据拿到手了,但打开一看,一堆二进制乱码。嗯,这里要注意,气象数据不是 CSV 或 JSON 那种人类可读的格式。主流格式就两种:GRIB2 和 NetCDF。
3.3.1 GRIB2 格式
GRIB2 是 WMO(世界气象组织)的标准。说白了,它把数据压缩得很小,但解析起来麻烦。我推荐用 pygrib 库。
import pygrib
# 打开 GRIB2 文件
grbs = pygrib.open("gfs.t00z.pgrb2.0p25.f006")
# 遍历所有消息
for grb in grbs:
print(f"参数: {grb.name}, 层次: {grb.level}, 时间: {grb.validDate}")
# 提取 10 米风速
u10 = grbs.select(name="10 metre U wind component")[0]
v10 = grbs.select(name="10 metre V wind component")[0]
# 计算风速大小
import numpy as np
speed = np.sqrt(u10.values**2 + v10.values**2)
print(f"风速矩阵形状: {speed.shape}")
grbs.close()
注意:GRIB2 文件里,风速是拆成 U 分量和 V 分量的。我见过新手直接拿 U 分量当风速用,结果功率预测全错了。记住,风速 = sqrt(U² + V²),方向用 arctan2 算。
3.3.2 NetCDF 格式
NetCDF 更现代一些,自描述性强。ECMWF 的数据很多用这个格式。我用 xarray 库解析,非常方便。
import xarray as xr
# 打开 NetCDF 文件
ds = xr.open_dataset("ecmwf_20250101.nc")
# 查看数据结构
print(ds)
# 提取特定经纬度的风速序列
lat, lon = 39.5, 116.3
wind_speed = ds["si10"].sel(latitude=lat, longitude=lon, method="nearest")
print(wind_speed)
# 转换为 pandas DataFrame 方便后续处理
df = wind_speed.to_dataframe()
print(df.head())
ds.close()
我的经验:NetCDF 文件里,经纬度坐标有时是降序排列的(从北到南)。我第一次用的时候没注意,把内蒙古的风电场坐标对应到了广东。所以,拿到数据后第一件事,画个简单的经纬度散点图,确认坐标顺序。
3.4 知识体系总览
我把这一章的核心逻辑画成了图,方便你理解整个数据获取的流程。
这张图把整个流程串起来了。从选源到调接口,再到解析格式,每一步都有对应的工具和注意事项。你照着这个流程走,基本不会出大问题。
最后说一句:数据获取是整个预报链条的起点。起点错了,后面全白干。我见过太多团队花大价钱建模型,结果数据源选错了,或者解析时坐标搞反了,最后预报结果一塌糊涂。所以,把基础打牢,比什么都重要。