使用 PVLib 计算光伏板排布的最佳倾角和朝向
本文面向已经会用 Python、对光伏发电有基本概念的工程师,目标是: 在掌握“经验规则”的基础上,用 PVLib 做一套可以落地的 最佳倾角 / 朝向 计算流程。
问题背景与总体思路
在实际项目里,“组件怎么摆”通常会落到三个问题:
- 朝哪边?(方位角:东、南、西还是介于它们之间?)
- 抬多高?(倾角:离水平面多少度?)
- 在地形限制下,能不能做到既不遮挡又发得多?
行业里已经有大量工程经验,比如 北半球朝南、倾角 ≈ 当地纬度附近 等。 但当你手里已经有了气象数据、能用上 PVLib 时,其实可以把这件事做得再精细一点:
先用经验缩小范围,再用 PVLib 做数值优化,选出在本场址条件下真正最合适的排布。
下面从朝向、倾角,再到 PVLib 实战,一步步走。
朝向选择
基本原则
最常见的经验规则可以一句话概括:
南半球朝北,北半球朝南,让电池板在白天尽量正对太阳。
在北半球,如果组件偏离正南方向,每偏 30°,年发电量大致会跌 10%–15%; 如果干脆朝东或朝西,年发电量一般会比朝正南少 约 20%。
好消息是: 在多数场址中,只要方位在 正南 ±20° 之内,发电量差异并不夸张,工程上是可以接受的。
为什么有些屋顶会选东西向?
有些国家在推广屋顶光伏时,会刻意把组件铺在 东西向的屋面,理由并不是“发更多”,而是:
- 把发电峰值 从正午拉平,让早晚也有比较高的出力;
- 对配电网友好,避免中午瞬时功率“扎堆”过高。
因此,在“自发自用 + 限制上网功率”的场景下,东西向有时是种 策略选择,不完全是“度电量最大化”的问题。
复杂地形下:南北向阵列通常仍占优
《光伏电站设计技术》一书中,对复杂地形下固定式方阵的排布方案做过对比。 在同等条件下,南北向布置整体发电量表现最好。


综合来看:
- 初步选型:在北半球,优先考虑“组件朝南 ±20°”的方案;
- 有特殊电价 / 用电曲线要求时:可以用 PVLib 先模拟南向 vs 东西向的年出力,再做取舍。
倾角选择
倾角与入射角:为什么“尽量垂直”这么重要?
组件表面接收到的有效辐照度,与 入射角的余弦 直接相关。 当光线几乎垂直于组件时(入射角很小),单位面积上接收的能量最多。
所以,对于固定倾角系统,目标可以简单理解为:
找到一个全年意义上 平均最垂直 的组件倾角。

方法一:基于纬度的经验选取
常见的工程经验:
- 南方地区:倾角 ≈ 纬度 + 10° ~ 15°
- 北方地区:倾角 ≈ 纬度 + 5° ~ 10°
- 纬度较大时,适当减小“额外增加”的角度
这种经验本质上是在权衡:
- 冬季太阳高度低 → 倾角大一些能提升冬季发电;
- 夏季太阳高度高 → 倾角太大反而不划算。
优点是:简单好记,前期方案阶段非常实用。
方法二:基于太阳高度角的解析公式
如果只看理论模型,可以用一个简单公式给出“固定组件”的最佳倾角近似值:
[ \theta_\text{best} = \frac{(90^\circ - (\varphi - 23.43^\circ)) + (90^\circ - (\varphi + 23.43^\circ))}{2} ]
其中:
- (\varphi):场址纬度(北纬为正)
- 23.43°:南北回归线的纬度(地轴倾角)
这个公式等价于: 在北半球,把夏至与冬至正午时刻的高度角折中, 求一个折衷的“平均最有利”倾角。

在实际工程中,经验 + 解析公式 可以给出一个不错的起点, 但要真正“抠度电量”,还是建议上 PVLib 做数值分析。
用 PVLib 计算最佳倾角与朝向
下面进入实战部分:用 PVLib 对固定支架系统做一个 扫描 + 优选。
计算思路
大致流程可以分为几步:
- 定义场址信息:经纬度、海拔、时区;
- 生成时间序列:例如按小时覆盖一整年;
- 获取太阳位置:太阳高度 / 方位角等;
-
获取辐照数据:
- 简化场景下,可用 晴空模型(clearsky);
- 更严谨时,用实测站或第三方数据库(SolarGIS / PVGIS)。
- 枚举一组候选倾角 / 朝向,用 PVLib 计算每种组合下的平面辐照度(POA);
- 对每种组合 累计全年 POA 能量,取最大值对应的倾角 / 朝向。
下面先从“只优化倾角,朝向固定正南”开始。
示例:在北半球固定朝南,扫描最佳倾角
准备环境
pip install pvlib pandas numpy
代码示例
下面以某个场址(北纬 27.578408°,东经 117.250487°)为例:
import numpy as np
import pandas as pd
import pvlib
# === 1. 场址信息 ===
latitude, longitude = 27.578408, 117.250487
altitude = 10 # 海拔 (m)
timezone = 'Asia/Shanghai'
location = pvlib.location.Location(
latitude,
longitude,
tz=timezone,
altitude=altitude
)
# === 2. 时间序列:覆盖一整年 ===
times = pd.date_range(
start='2023-01-01 00:00',
end='2023-12-31 23:00',
freq='1h',
tz=timezone
)
# === 3. 太阳位置 ===
solar_position = pvlib.solarposition.get_solarposition(
times,
latitude,
longitude
)
# === 4. 辐照数据:使用晴空模型(示意) ===
clearsky = location.get_clearsky(times, model='ineichen')
dni = clearsky['dni']
ghi = clearsky['ghi']
dhi = clearsky['dhi']
# === 5. 扫描一组候选倾角 ===
tilt_candidates = np.arange(10, 50, 1) # 10° 到 49°,步长 1°
surface_azimuth = 180 # 北半球朝正南
energy_per_tilt = []
for tilt in tilt_candidates:
poa = pvlib.irradiance.get_total_irradiance(
surface_tilt=tilt,
surface_azimuth=surface_azimuth,
dni=dni,
ghi=ghi,
dhi=dhi,
solar_zenith=solar_position['apparent_zenith'],
solar_azimuth=solar_position['azimuth']
)
# 这里简单地对全年 POA_global 求和,作为“相对年能量”
annual_energy = poa['poa_global'].sum()
energy_per_tilt.append(annual_energy)
best_index = int(np.argmax(energy_per_tilt))
best_tilt = tilt_candidates[best_index]
print(f"推荐倾角: {best_tilt}°")
这个结果通常会和“纬度 ± 若干度”的经验值比较接近。
如果你把 tilt_candidates 改成更细的范围,例如围绕经验值 ±5° 微调,可以得到更精细的结果。
同时扫描倾角和朝向(可选)
如果还想顺便验证一下“朝南 ±20°”究竟差多少,可以把方位角也一并扫描:
tilt_candidates = np.arange(10, 50, 2) # 倾角
azimuth_candidates = np.arange(150, 211, 5) # 150° ~ 210°,基本覆盖正南 ±30°
results = []
for tilt in tilt_candidates:
for azimuth in azimuth_candidates:
poa = pvlib.irradiance.get_total_irradiance(
surface_tilt=tilt,
surface_azimuth=azimuth,
dni=dni,
ghi=ghi,
dhi=dhi,
solar_zenith=solar_position['apparent_zenith'],
solar_azimuth=solar_position['azimuth']
)
annual_energy = poa['poa_global'].sum()
results.append((tilt, azimuth, annual_energy))
# 找到能量最大的组合
best_tilt, best_azimuth, best_energy = max(results, key=lambda x: x[2])
print(f"推荐倾角: {best_tilt}°, 推荐方位角: {best_azimuth}°")
根据实际项目需求,你可以:
- 只让朝向在正南 ±20° 内变化,模拟设计约束;
- 或者固定屋顶已有朝向,只优化倾角。
按日计算最佳倾角,再求年平均(基于太阳位置)
如果只做一个更“理论向”的估算,也可以按最简单的思路:
- 用 PVLib 计算一年中每天的太阳位置;
- 按公式为每一天算出一个“当天最佳倾角”;
- 最后对全年结果求平均,得到一个“年意义”的最佳固定倾角近似值。
示意代码(思路示例,简化处理):
import numpy as np
import pandas as pd
import pvlib
latitude, longitude = 27.578408, 117.250487
timezone = 'Asia/Shanghai'
dates = pd.date_range('2023-01-01', '2023-12-31', freq='D', tz=timezone)
# 这里简单取每日中午 12:00 作为代表时刻
noon_times = dates + pd.Timedelta(hours=12)
solar_position = pvlib.solarposition.get_solarposition(
noon_times,
latitude,
longitude
)
# 使用太阳高度角 (90° - 太阳天顶角) 近似求当天最佳倾角
solar_zenith = solar_position['apparent_zenith']
solar_altitude = 90 - solar_zenith
# 这里仅示意:最佳倾角 ≈ 某种函数 f(纬度, 太阳高度)
# 简单起见,我们取:倾角 ≈ 纬度 - (太阳高度 - (90 - 纬度))
daily_optimal_tilt = latitude - (solar_altitude - (90 - latitude))
annual_optimal_tilt = float(daily_optimal_tilt.mean())
print(f'按日折算得到的年平均最佳倾角近似值: {annual_optimal_tilt:.2f}°')
这一块的重点不是公式多完美, 而是提供一个利用 PVLib 批量处理太阳位置 → 折算倾角 的思路。
与第三方工具结果对比(SolarGIS / PVGIS)
在实际项目中,很多团队会把 PVLib 的结果和 SolarGIS / PVGIS 等外部工具做个对照, 既是 sanity check,也方便向业主 / 设计院说明“方案不是拍脑袋”。
下面是某组对比示例(单位:度):
| Lat, Lng | SolarGIS | PVLib | PVLib 发电量最优倾角 | PVGIS |
|---|---|---|---|---|
| 40.299639, 116.055174 | 37 | 39 | 41 | 41 |
| 37.843628, 116.318846 | 33 | 36.62 | 38 | 39 |
| 35.578704, 116.547362 | 30 | 34.37 | 35 | 36 |
| 33.295641, 116.811034 | 27 | 32.1 | 30 | 33 |
| 31.402411, 117.27246 | 25 | 30.22 | 27 | 31 |
| 30.175525, 117.228515 | 24 | 29 | 26 | 29 |
| 28.586452, 117.228515 | 22 | 27.42 | 22 | 27 |
| 27.578408, 117.250487 | 22 | 26.41 | 21 | 26 |
从表里可以看出:
- PVLib 的“理论最佳倾角” 往往略大一些;
- 结合实际发电量(用组件模型 + POA 进一步折算后)得到的最优倾角,与 PVGIS 给出的数值已经非常接近。
坡度与地形
倾角和朝向不是在真空里选的,实际工作过程中还要考虑地形:
-
北半球优先平坦地或北高南低的山坡
- 山地坡度一般不宜超过 30°(打桩机仰角限制);
-
北坡一般尽量回避
- 除非北坡角度极小(对于北纬 30°–40°,通常建议不超过 5°–10°);
-
东西向坡度
- 建议控制在 20° 以内;
-
支架形式的约束
- 坡度大于 10° 的区域,通常不适合平单轴支架。
在设计流程上,比较合理的一种做法是:
- 先做坡度筛选:在 GIS / 设计平台里筛掉不合适的坡向与坡度;
- 在“候选区域”里,用 PVLib 做 最佳倾角 / 朝向扫描;
- 再结合道路、升压站位置、占地、土建条件等,做最终布置。
小结:如何在项目中落地这套方法?
-
场址级:
- 用地形数据筛选合适的坡度和坡向;
-
经验级:
- 按纬度 + 经验偏移量给出一个倾角初值;
- 朝向选在正南 ±20° 区间;
-
模型级(PVLib):
- 准备时间序列 + 太阳位置 + 辐照数据;
- 在工程可行的倾角 / 朝向范围内做扫描;
- 找出在当前约束下“度电量意义上的最佳组合”;
-
验证级:
- 将结果与 SolarGIS / PVGIS 做对比,校验合理性;
-
施工约束回写:
- 根据支架、打桩机能力和土建条件微调角度,重新用 PVLib 做一次快速检查。
做到这一步,你就不再只是“照着经验值抄”, 而是可以说:“这是在当前地形和气象条件下,通过 PVLib 计算得出的最优或次优排布方案。”