本文面向已经会用 Python、对光伏发电有基本概念的工程师,目标是: 在掌握“经验规则”的基础上,用 PVLib 做一套可以落地的 最佳倾角 / 朝向 计算流程。

问题背景与总体思路

在实际项目里,“组件怎么摆”通常会落到三个问题:

  1. 朝哪边?(方位角:东、南、西还是介于它们之间?)
  2. 抬多高?(倾角:离水平面多少度?)
  3. 在地形限制下,能不能做到既不遮挡又发得多?

行业里已经有大量工程经验,比如 北半球朝南倾角 ≈ 当地纬度附近 等。 但当你手里已经有了气象数据、能用上 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 对固定支架系统做一个 扫描 + 优选

计算思路

大致流程可以分为几步:

  1. 定义场址信息:经纬度、海拔、时区;
  2. 生成时间序列:例如按小时覆盖一整年;
  3. 获取太阳位置:太阳高度 / 方位角等;
  4. 获取辐照数据

    • 简化场景下,可用 晴空模型(clearsky)
    • 更严谨时,用实测站或第三方数据库(SolarGIS / PVGIS)。
  5. 枚举一组候选倾角 / 朝向,用 PVLib 计算每种组合下的平面辐照度(POA);
  6. 对每种组合 累计全年 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° 内变化,模拟设计约束;
  • 或者固定屋顶已有朝向,只优化倾角。

按日计算最佳倾角,再求年平均(基于太阳位置)

如果只做一个更“理论向”的估算,也可以按最简单的思路:

  1. 用 PVLib 计算一年中每天的太阳位置;
  2. 按公式为每一天算出一个“当天最佳倾角”;
  3. 最后对全年结果求平均,得到一个“年意义”的最佳固定倾角近似值。

示意代码(思路示例,简化处理):

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° 的区域,通常不适合平单轴支架。

在设计流程上,比较合理的一种做法是:

  1. 先做坡度筛选:在 GIS / 设计平台里筛掉不合适的坡向与坡度;
  2. 在“候选区域”里,用 PVLib 做 最佳倾角 / 朝向扫描
  3. 再结合道路、升压站位置、占地、土建条件等,做最终布置。

小结:如何在项目中落地这套方法?

  1. 场址级

    • 用地形数据筛选合适的坡度和坡向;
  2. 经验级

    • 按纬度 + 经验偏移量给出一个倾角初值;
    • 朝向选在正南 ±20° 区间;
  3. 模型级(PVLib)

    • 准备时间序列 + 太阳位置 + 辐照数据;
    • 在工程可行的倾角 / 朝向范围内做扫描;
    • 找出在当前约束下“度电量意义上的最佳组合”;
  4. 验证级

    • 将结果与 SolarGIS / PVGIS 做对比,校验合理性;
  5. 施工约束回写

    • 根据支架、打桩机能力和土建条件微调角度,重新用 PVLib 做一次快速检查。

做到这一步,你就不再只是“照着经验值抄”, 而是可以说:“这是在当前地形和气象条件下,通过 PVLib 计算得出的最优或次优排布方案。”