建设光伏电站是一项巨大的投资,为了保证收益,需要在建设前期进行大量分析与计算。这些计算涉及到气象学、电力科学、经济学等许多领域的许多模型。如何根据实际情况选择相应的模型与算法以提高电站的整体发电效率与收益,是一项非常复杂的操作,对相关人员的技术储备与实际经验都有非常高的要求。
针对这种「模型泛滥」的情况,pvlib应运而生。pvlib是一个python的第三方库,为光伏发电系统相关的计算模型提供了开放、可靠、可交互的基准实现。换言之,用户通过pvlib可以自由地搭配各种计算模型,并得到最终的计算结果(如果在某地建设光伏电站,它的发电量是怎样的)。
使用pvlib的一个基本场景是:为了计算在某地(已知经纬度等位置信息)建设光伏电站所能带来的经济效益,需要根据该地的气象预报数据对辐照度等数据进行预测,并结合光伏组件的参数及配置信息,对发电量进行预测。
针对上述场景,本文基于pvlib的介绍文档,梳理了pvlib的基本用法以及光伏发电中涉及到的其他术语与知识。除大段引用外,文中的相关知识均整理自互联网上的公开内容,不再给出参考链接。
光伏发电是一个相对比较专业的领域,因此有必要先对该领域涉及到的专有名词及术语进行了解。下面表格中总结了一些术语的中英文表示及其含义,如有不准确的地方,欢迎指出。
英文 | 中文 | 含义 |
---|---|---|
inverter | 逆变器 | 将直流电转变为交流电的仪器。光伏电厂发的电都是直流电,如果需要并入交流电网,则需要逆变器进行转化。 |
PV modules | 光伏模块 | 一个独立的将光能转化为电能的组件,常见的光伏板是其主要部件之一。 |
Array | (光伏)阵列 | 如果多个邻近的光伏模块具有相同的设备参数(材料等)和安装参数(倾斜度、方向、模块数量等),那么它们就组成一个光伏阵列,简称阵列。 |
tilt | 倾角 | 光伏板的倾斜角度,取值从0(水平)到90(垂直)。 |
azimuth | 方位角 | 光伏板的方向,取值从0到360(不含),0表示正北,90表示正东,180表示正南,270表示正西。注意,pvlib中的设定与我们在国内很多资料上的设定略有不同,国内一些资料将正南方向定义为0,向东偏为负角度,向西偏为正角度。 |
AOI | 入射角 | Angle of incidence,阳光照射到某个平面上时与该平面的夹角。 |
zenith | 天顶角 | 指光线入射方向和天顶方向的夹角,与高度角互余。 |
elevation | 高度角 | 指光线入射方向和地平面之间的夹角,与天顶角互余。 |
DNI | 直接辐射 | Direct Normal Irradiance,阳光从太阳盘面直接照射到与光路正交的表面时的辐射度。 |
DHI | 散射 | Direct Horizontal Irradiance,在大气中散射的直接达到地面的阳光称为散射辐射,而散射辐射的标准测量在水平面上进行,得到的值称为散射水平辐射。 |
GHI | 总辐射 | Global Horizontal Irradiance,太阳的DHI和DNI到达水平表面称为总水平辐射。 |
TMY | 典型气象年 | Typical Meteorological Year,又被译为标准气象年,是依据气候平均变动原理所统计出来作为当地典型气候的代表,所有也被称为平均气象年,是一种实际上并不存在的假想气象年,其意义在于以一年份之标准气象来代表当地之长期气候最平均的变动情况。 |
在了解了光伏发电的基本术语之后,我们来看一下在pvlib中如何实现发电量的预测。
pvlib的基本工作流程如下图所示:
ModelChain
是pvlib中定义的一个类,其作用就是将各种基础模型及其数据按照先后顺序组合成一个链条(Chain),然后执行相关的方法来进行预测。上图清晰地展示了这个过程。
对应于2.2中的流程图,我将在本章给出具体的代码实现过程。
地理位置信息的存储是通过实例化pvlib.location.Location实现的,这个类很好理解,其作用就是来指定光伏模块的安装的地理位置信息,例如常见的经纬度、海拔高度、时区等。另外,还可以对其实例指定名称。
在定义了地理位置信息之后,还可以调用Location
类的其他方法来计算对应的数据。例如,通过传入额外的时间数据来获取太阳的位置数据、计算日出日落时间、计算各种辐照度的估计值、计算气团值等。
什么是气团值?简而言之就是光通过大气的路径长度,显然,这是一个直接影响辐照度、进而影响发电量的重要因素。关于气团的更多内容,参考这里。
用于表示安装参数的类有两个:pvlib.pvsystem.FixedMount和pvlib.SingleAxisTrackerMount。
FixedMount
FixedMount
指的是固定位置安装。对于采用这种安装方式的一个光伏阵列而言,其中所有的光伏板都具有相同的倾角和方位角,另外还可以指定安装位置距底面的高度。
SingleAxisTrackerMount
这是一种可以使光伏板自动追踪太阳位置的安装方式,由于需要灵活调整光伏板的位置,相较于四角固定的FixedMount
而言,它更像是在光伏板中心位置支撑一个轴来满足转动需求,所以叫“Single Axis”。
这是我猜的,目前还没实际见过光伏板,如果实地考察后再来更新。
光伏模块配置与逆变器配置的实现都是通过pvlib.pvsystem.retrieve_sam
函数实现的。这个函数的参数非常简单,只需要传入对应的存储光伏模块配置信息或逆变器配置信息的数据库的名称即可。
当用户安装pvlib时,会将存储这些配置信息的数据——实质上就是许多csv文件——一并下载到本地,调用retrieve_sam
函数时,实际上就是从指定位置加载对应的csv文件。
这些存储配置信息的csv文件源于SAM网站,我们可以把SAM理解为一个专门为可再生能源提供技术支持的软件系统,它可以为多种可再生能源提供建模服务。在其PV Cost and Component Data标签下,提供了上述csv数据。
有人可能会问了,这些csv文件存储的光伏模块与逆变器配置信息都是固定的,如果我的信息与它们均不相同该怎么办?换言之,我能否自定义自己的配置信息呢?
答案是肯定的。
首先,这些固定的配置数据来自于加州能源委员会(California Energy Commission,CEC),你可以在这里找到如何通过SAM来添加自己的配置数据。此外,通过观察这些csv文件以及函数的源码可以发现,源csv文件每一行代表了一种配置信息,在读取的时候做了转置并通过列名进行索引,因此,我们只需要将自己的配置数据按照对应的指标组合成可以供后续函数调用的格式即可,可以参考这里的一种实现方式。
搞清楚每个指标是什么含义不是一件容易的事,起码我没有找到相关的资料,可能需要专业人士来协助。
温度之所以会对发电量造成影响,一个直观的理解就是,它会直接影响设备元件的工作情况。因此,掌握各元件的温度变化情况并对未来一段时间内的温度做出预测是十分有必要的。
需要计算温度的元件包括前文提到的光伏模块以及电池,而估算电池温度的前提就是估算模块温度。不难理解,元件温度取决于许多因素,主要包括:气温、辐照度、风速以及元件材料。桑迪亚阵列性能模型(Sandia Array Performance Model,SAPM),提供了一系列以上述影响因素为输入并输出元件温度的功能。
使用SAPM之前需要先指定一些初始参数,其实就是在不同安装场景下的一些基本系数。
调用pvlib.temperature.sapm_module
函数即可实现对模块温度的预测。
前面提到,电池温度是基于模块温度得到的,因此,pvlib提供了两个函数来计算电池温度,分别是pvlib.temperature.sapm_cell
,pvlib.temperature.sapm_cell_from_module
。
查看源码可以发现,它们其实是一样的,并且都是从模块温度计算得来。
通过组合安装参数、光伏模块配置以及温度数据,就可以通过实例化pvlib.pvsystem.Array
类来生成一个阵列对象。这个类在实例化时可选的参数很多,但并不是所有的参数都是必需的,用户在充分理解了本章前几节提到的类及函数的功能后,可以在实例化光伏阵列时灵活指定相关的参数,以使之最符合实际条件。
一个或多个光伏阵列再加上一个逆变器,就形成了一个完整的光伏系统(pvlib.pvsystem.PVSystem
)。一般来讲,它并不被单独使用,而是和Location
对象一起用于实例化ModelChain
。
根据Location
实例和PVSystem
实例,可以实例化一个ModelChain
。至此,我们已经收集到了所有的设备相关的数据,它们都被存储在ModelChain
实例中,接下来就可以调用ModelChain
的相关执行方法来运行模型并获取结果。
pvlib的设计逻辑决定了模型的执行实际上是初始化一个ModelChainResult
类,所有的结果都是作为该类的属性来存储,用户可以从其源码的注释中来查看结果类中都可以存储哪些数据。
显然,想要调用ModelChain
的执行方法来计算一些用户关系的数据(例如,想要获取发出的交流电的功率,则还需要天气数据)。以Model.Chain.run_model
方法为例,它需要传入weather
参数才能正常工作,而传入的weather
参数必须要包括DNI、DHI和GNI。
本章给出官方文档中的一个完整的示例,并添加对应的注释。
import pandas as pd
import numpy as np
import pvlib
from pvlib.pvsystem import PVSystem, FixedMount
from pvlib.location import Location
from pvlib.modelchain import ModelChain
from pvlib.temperature import TEMPERATURE_MODEL_PARAMETERS
# sapm,Sandia Array Performance Model,一种用于预测温度的模型,对应有不同的参数可以选择
temperature_model_parameters = TEMPERATURE_MODEL_PARAMETERS['sapm']['open_rack_glass_glass']
# 从SAM网站上获取SandiaMod光伏模块的配置
sandia_modules = pvlib.pvsystem.retrieve_sam('SandiaMod')
# 从SAM网站上获取cec逆变器的配置
cec_inverters = pvlib.pvsystem.retrieve_sam('cecinverter')
# 选择一个光伏模块及一个逆变器的数据
sandia_module = sandia_modules['Canadian_Solar_CS5P_220M___2009_']
cec_inverter = cec_inverters['ABB__MICRO_0_25_I_OUTD_US_208__208V_']
# 设置位置信息
location = Location(latitude=32.2, longitude=-110.9)
# 实例化一个PVSystem对象
system = PVSystem(surface_tilt=20, surface_azimuth=200,
module_parameters=sandia_module,
inverter_parameters=cec_inverter,
temperature_model_parameters=temperature_model_parameters)
# 实例化一个ModelChain对象
mc = ModelChain(system, location)
# 虚拟一些天气数据
weather = pd.DataFrame([[1050, 1000, 100, 30, 5]],
columns=['ghi', 'dni', 'dhi', 'temp_air', 'wind_speed'],
index=[pd.Timestamp('20170401 1200', tz='US/Arizona')])
# 运行模型
mc.run_model(weather)
# 获取相关结果
print(mc.results.aoi) # 入射角
print(mc.results.cell_temperature) # 电池温度
print(mc.results.dc) # 直流电功率
print(mc.results.ac) # 交流电功率
在上述示例代码中,我们拿到了一组光伏模块和逆变器数据,并虚拟了温度数据,通过模型计算,得到了在该位置上的运算结果。
通过前面的介绍,读者应该已经发现,pvlib所涉及到的模型及对应的参数很多,且其中相当一部分参数在构造ModelChain
的不同阶段都有出现。例如,一个光伏阵列对应一组安装位置信息(指定了倾角和方位角),而构建光伏系统时又可以指定对应的倾角和方位角。这就涉及到了参数的优先级问题。
一般来说,pvlib处理这些参数的逻辑是符合人类直觉的。例如,如果光伏阵列指定了倾角和方位角,那么利用此光伏阵列构造光伏系统时,不必再指定(指定了也不会生效)。
此外,对于一些不是必须的参数,pvlib会自动推算其合理值;如果用户在后面的阶段中又显示地对该参数进行了指定,则pvlib就会采用用户的指定值。
pvlib还提供了一些其他的实用功能,如:获取天气预报数据。但遗憾的是,从0.9.1版本开始,这个功能就被删除了,理由是当前的团队中缺乏维护此模块的功能的人。
无论是使用之前版本的功能,还是选择其他的天气预报系统,只要将数据处理成pvlib可以接收的格式,那么就可以调用该模块其他的功能。