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 那种人类可读的格式。主流格式就两种:GRIB2NetCDF

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 知识体系总览

我把这一章的核心逻辑画成了图,方便你理解整个数据获取的流程。

预报产品获取流程 数据源选择 GFS / ECMWF API 接口调用 RESTful / 频率控制 数据格式解析 GRIB2 / NetCDF 输出 GFS 特点 • 免费,分辨率 0.25° • 每天 4 次更新 • 适合短期预报 • 极端天气偏差较大 ECMWF 特点 • 商业授权,分辨率 0.1° • 每天 2 次更新 • 适合中期调度 • 极端天气表现优秀 解析工具推荐 • GRIB2 → pygrib • NetCDF → xarray • 注意坐标顺序 • 风速需合成计算

这张图把整个流程串起来了。从选源到调接口,再到解析格式,每一步都有对应的工具和注意事项。你照着这个流程走,基本不会出大问题。

最后说一句:数据获取是整个预报链条的起点。起点错了,后面全白干。我见过太多团队花大价钱建模型,结果数据源选错了,或者解析时坐标搞反了,最后预报结果一塌糊涂。所以,把基础打牢,比什么都重要

专注资料整理