使用 PVLib 与 PVGIS 计算光伏电站发电量
在做前期测算或可研分析时,我们通常会问三个问题:
- 这个地点的光照条件大概如何?
- 按规划装机容量,首年发多少电?
- 用不用“代表年”(TMY)来做更稳健的评估?
这一节,我们用 PVLib 结合 PVGIS 数据接口,演示两种常见的计算思路,并给出对应的 Python 示例。
数据与工具概览
PVGIS 数据源简介
PVGIS(Photovoltaic Geographical Information System) 是欧盟联合研究中心(JRC)提供的一个光伏资源数据库和在线工具。它提供:
- 历史逐小时辐照度、气象数据(如
PVGIS-ERA5数据库) - 光伏发电模拟接口(考虑组件、系统损耗等)
- 典型气象年(TMY,Typical Meteorological Year)数据,用于“代表年”分析
通过 PVGIS 的 HTTP API,我们可以直接在代码里获取:
- 逐小时辐照度 & 发电量(
get_pvgis_hourly) - 典型年(TMY)气象数据(
get_pvgis_tmy)
PVLib 是什么?
PVLib 是一个专门为光伏建模设计的 Python 库,提供:
- 太阳位置计算
- 辐照度模型(GHI/DNI/DHI → 倾斜面辐照度)
- 组件和逆变器电气模型
- 与各类气象/资源数据库的 I/O 接口(包括 PVGIS)
在本例中,我们主要用到:
pvlib.iotools模块:从 PVGIS 拉数据pvlib.location.Location:封装站点经纬度和时区信息pvlib.irradiance:把水平面辐照度转换为组件平面上的辐照度(POA, Plane of Array)
方法一:直接使用 PVGIS 的“峰值功率”计算
第一种做法,是把系统规划容量直接丢给 PVGIS,让它帮我们算出逐小时发电量。适用于快速估算首年发电量的场景。
核心思路
- 指定站点经纬度、时间范围(如 2020 年全年)。
-
告诉 PVGIS 下列指标:
- 系统装机容量(AC/DC 峰值功率,单位 W)
- 系统损耗(百分比)
- 让它自动优化组件倾角和方位,或手动指定。
- PVGIS 返回逐小时的辐照度和发电功率,我们对功率做全年求和即可得到总发电量。
示例代码
import pvlib
poa, inputs, metadata = pvlib.iotools.get_pvgis_hourly(
latitude=latitude,
longitude=longitude,
start=2020,
end=2020,
# surface_tilt=tilt,
# surface_azimuth=-azimuth,
optimal_surface_tilt=True, # 自动优化倾角
optimalangles=True, # 自动优化组件朝向
pvcalculation=True, # 让 PVGIS 进行光伏发电计算
components=True, # 返回分量数据
peakpower=294_630, # 系统峰值功率,单位 W,这里是 294.63 MW
loss=14, # 系统损耗 14%
raddatabase="PVGIS-ERA5", # 辐照度数据库
url="https://re.jrc.ec.europa.eu/api/v5_2/",
)
# poa['P'] 单位为 Wh,逐小时数据
annual_energy_mwh = poa['P'].sum() / 1_000_000 # Wh -> MWh
print(annual_energy_mwh)
说明:
poa['P']是 PVGIS 直接给出的发电功率时间序列。- 调用中使用了
PVGIS-ERA5数据库,基于 ERA5 再分析数据,空间分辨率和时间精度都较高。 loss=14是系统损耗假设,可根据项目实际配置(线损、逆变器效率、温度损失等)调整。
本例结果
- 最佳倾角:≈ 35°
- 规划容量:294.63 MW
- 首年发电量:约 422111.42 MWh
这一方法的优点是:一行 API 完整包办从气象到发电,非常适合快速评估,缺点是可控性较低,细节上更多依赖 PVGIS 内部模型。
方法二:使用代表年(TMY)+ PVLib 自建辐照模型
第二种做法是更偏“工程师风格”的:拿到 TMY 数据后,用 PVLib 自己搭建辐照度与发电量计算流程。
核心思路
- 通过
get_pvgis_tmy从 PVGIS 获取某地的典型气象年(TMY)数据。 - 用
pvlib.location.Location建立站点对象,计算太阳位置、晴空辐照度。 - 利用
pvlib.irradiance.get_total_irradiance计算组件平面(倾斜面)的总辐照度(POA)。 - 根据系统容量和辐照度,估算发电量。
这一路线更适合:
- 做不同倾角/朝向的敏感性分析
- 自己选用、替换不同辐照模型或组件模型
- 与已有仿真流程(如 PVSyst、内部模型)对接
示例代码
import pvlib
from pvlib import location, irradiance
# 时区与站点
tz = 'Asia/Shanghai'
latitude, longitude = 35.60873126, 112.67871068
# 创建站点对象
site = location.Location(latitude, longitude, tz=tz)
# 1. 获取代表年(TMY)数据
tmy_data, tmy_months_selected, tmy_inputs, tmy_metadata = pvlib.iotools.get_pvgis_tmy(
latitude,
longitude,
map_variables=True,
# raddatabase="PVGIS-ERA5", # 可按需指定
url="https://re.jrc.ec.europa.eu/api/v5_2/",
)
tilt = 35 # 组件倾角(度)
surface_azimuth = 0 # 方位角:0 表示正南,东负西正
# 2. 太阳位置与晴空辐照度
clearsky = site.get_clearsky(tmy_data.index) # 晴空 GHI/DHI/DNI
solar_position = site.get_solarposition(tmy_data.index)
# 3. 计算组件平面总辐照度(POA)
POA_irradiance = irradiance.get_total_irradiance(
surface_tilt=tilt,
surface_azimuth=surface_azimuth,
dni=clearsky["dni"],
ghi=clearsky["ghi"],
dhi=clearsky["dhi"],
solar_zenith=solar_position["apparent_zenith"],
solar_azimuth=solar_position["azimuth"],
)
# 4. 简单按线性比例估算年发电量
# - poa_global 单位 W/m²
# - 累加后 /1000 -> kWh/m²
# - 再乘以装机容量(kWp),得到约略发电量(忽略细致电气模型)
installed_kwp = 294_630 # kWp,同 294.63 MW
annual_energy_kwh = (POA_irradiance['poa_global'].sum() / 1000) * installed_kwp
annual_energy_mwh = annual_energy_kwh / 1000
print(annual_energy_mwh)
说明:
- 这里为了演示,将发电量视作“POA 辐照度 × 容量”的线性关系,忽略了温度效应、组件效率曲线等细节。
- 实际工程项目中,可以继续接入 PVLib 的组件/逆变器模型,构建更完整的 DC/AC 仿真。
本例结果
- 最佳倾角:35°(人工设定,可做敏感性分析)
- 规划容量:294.63 MW
- 首年发电量(代表年):约 351965.05 MWh
和方法一相比,这里的发电量略低,原因可能包括:
- 使用了代表年数据而非某具体年份(气象条件不同)
- 我们这里采用了简化的“线性比例”估算,没有考虑温度、电气损耗等细节
- 不同方法对组件倾角/朝向、损耗假设的处理略有差异
在实际可研或投融资模型中,往往会同时参考: “某具体年份模拟结果” + “代表年结果” + “多年份统计” 来共同判断项目的发电水平区间。
两种方法的对比与使用建议
可以简单理解为:
-
方法一:一键黑盒
- 适合:快速评估、方案比选初期
- 优点:实现简单、结果直观
- 缺点:细节受控程度有限,对内部假设透明度较低
-
方法二:自建模型路线
- 适合:需要深入分析、做敏感性或不确定性评估
- 优点:灵活,可插入更多物理、电气模型;方便与内部工具集成
- 缺点:实现成本稍高,需要对 PVLib 更熟悉
在实际项目中,一个比较自然的工作流是:
- 用 方法一 快速扫一遍,看看不同地点/容量方案的发电量大致区间。
- 对重点场址,使用 方法二 搭完整模型,做更细的倾角、组件选型、损耗假设敏感性分析。
- 将 PVLib 计算结果嵌入到你现有的技术经济测算流程中(IRR/LCOE 等)。