pymgrid是一个开源Python库,用于模拟微型电网的三级控制,允许用户创建或自行选择的微电网。并可以使用自定义的算法或pymgrid中包含的控制算法之一来控制这些微电网(基于规则的控制和模型预测控制)。
pymgrid还提供了与OpenAI Gym API相对应的环境,提供了连续和离散动作空间环境,与强化学习算法一起使用,以训练控制算法。
pymgrid试图提供简单、直观的API,让用户能够专注于他们的特定应用程序。
1. 用于人工智能研究的开源的Python微电网模拟器pymgrid
微电网是能够与主电网断开连接的独立电网,在通过减少二氧化碳排放来缓解气候变化和通过提高基础设施弹性来适应气候变化方面都具有潜力。由于其分布性质,微电网往往是独特的;因此,对这些系统的控制是不平凡的。虽然存在微电网模拟器,但许多模拟器的范围和可模拟的微电网种类有限。我们提出了pymgrid,这是一个开源Python包,用于生成和模拟大量微电网,也是第一个可以生成600多种不同微电网的开源工具。pymgrid抽象了大部分领域专业知识,允许用户专注于控制算法。特别是,pymgrid是一个强化学习(RL)平台,它包括将微电网建模为马尔可夫决策过程的能力。pymgrid还引入了两个预先计算的微电网列表,旨在允许微电网设置中的研究再现性。
1.1. pymgrid概述
pymgrid由三个主要组件组成:包含用于“种子”微电网的负载和光伏产生时间序列的数据文件夹,名为MicrogridGenerator的微电网生成器类,以及名为Microgrid的微电网模拟器类。
1.1.1. 数据集
为了方便地生成微电网,pymgrid提供了负荷和光伏发电数据集。负荷数据来自于DOE OpenEI,基于TMY3天气数据;光伏数据也基于TMY3,由DOE/NREL/ALLIANCE提供。这些数据集包含了五个城市的负荷和光伏文件,每个城市处于美国不同的气候区域,时间序列为一年,时间步长为一小时,共8760个数据点。
1.1.2. Microgrid
该类包含一个微电网的完整实现,包括时间序列数据和一个微电网的具体规模。Microgrid实现了三类函数:控制循环、两个基准算法和实用函数。
需要使用一些函数来与Microgrid对象交互。函数run()用于前进一个时间步长,它以控制字典为参数,并返回微电网的更新状态。控制字典集中了需要传递给微电网的所有电力指令,以在每个时间步骤中操作每个发电设备。一旦微电网到达数据的最后一个时间步骤,其done参数将传递为True。函数reset()可用于将微电网重置为其初始状态,清空跟踪数据结构并重置时间步长。一旦将控制操作应用于微电网,它将通过检查函数来确保命令符合微电网约束条件。
对于强化学习基准和更普遍的机器学习,另一个额外的函数是有用的,train_test_split()允许用户将数据集分为两个部分,即训练集和测试集。用户还可以使用reset()从训练集转到测试集,在reset函数中使用testing = True参数。列表中提供了一个示例。
1.1.3. MicrogridGenerator类
MicrogridGenerator包含生成微电网列表的功能。对于每个请求的微电网,过程如下。首先,随机生成负荷的最大功率。然后随机选择一个负荷文件,并将其缩放到先前生成的值。下一步是自动随机选择微电网的架构。光伏和电池始终存在,这可能会随着我们添加更多组件而发展 - 我们随机选择是否有柴油发电机(genset)、电网、没有电网或弱电网(频繁停电的并网系统)。在弱电网的情况下,我们还实施备用发电机;如果有电网或弱电网,则随机选择电费。电力费率是由MicrogridGenerator生成的,基于加州和法国的商业费率。
选择了体系结构之后,需要对微电网进行尺寸调整。首先,需要计算光伏穿透率(由Hoke等人[2012]定义为负荷最大功率/光伏最大功率),并使用该值随机缩放所选的光伏曲线。生成的电网尺寸保证大于最大负荷,发电设备提供足够的功率满足峰值负载需求。最后,电池能够在平均负载下提供三至五个小时的电能。
一旦选择并调整了不同的组件,MicrogridGenerator将创建一个Microgrid对象。重复此过程以生成用户请求的多个微电网。
总体而言,使用五个负荷文件、五个光伏文件、两个电费、三种电网类型和二元发电机选择,该模型可以生成600多种不同的微电网-甚至没有考虑可能的不同光伏穿透率水平的数量。
1.2. 基准和讨论
除了上述功能,我们还提出了两个标准微电网列表:pymgrid10和pymgrid25,分别包含10个和25个微电网。 pymgrid10被设计为供初学者使用的第一个数据集。它包含10个具有相同架构(光伏+电池+发电机)的微电网,主要旨在获得有关仿真情况的直观感受。在pymgrid25中,可以找到所有可能的架构超过25个微电网。其中有四个微电网只有发电机,三个带有发电机和电网,九个只有电网,九个带有发电机和弱电网。由于我们提出这些微电网集合作为标准化测试集,因此我们还实现了一套控制算法作为基准比较。具体而言,我们实现了四种算法:基于规则的控制、模型预测控制(MPC)、Q学习和决策树(DT)增强的Q学习。通过检查结果,我们发现MPC具有完美预测时,可以视为几乎最优,而RBC可以视为下限,因为它给出了简单算法可达到的性能。
正如上表所看到的,算法的性能差异非常大。Q学习表现不佳;然而,增强了决策树的Q学习的表现优于RBC——RBC的平均成本约比DT增强Q学习高出44%——而大部分差异发生在边缘情况,其中RBC的表现较差,因为缺乏算法复杂性。虽然增强决策树的Q学习可能表现良好,但其必须使用离散的行动空间,这个需求会减少Q学习器能够学习的行动范围,并且很难确保在任何给定的离散行动空间中考虑到所有可能的行动。在6个微电网中,RBC的表现优于增强决策树的Q学习;这表明DT Q学习可能无法始终超过可接受的性能下限。这个问题通常出现在只有电网或带有电网和发电机组的微电网中。
虽然增强决策树的Q学习和MPC之间的差异经常看起来微不足道,但需要记住的是,这25个微电网的负载达到兆瓦级别;因此,13%的差异可以带来4000万美元的额外成本。为了应对气候变化并集成更多可再生能源,这项技术需要扩大规模,超过部署的系统数千个。提高控制器性能的几个百分点可能会大大减少运营成本,从而增加改进控制器性能的重要性。强化学习是实现这个目标的一种有前途的解决方案。
1.3. 结论和未来工作
pymgrid是一个Python软件包,允许研究人员生成和模拟大量微电网,并提供应用于强化学习研究的环境。我们为算法比较和可重复性建立了标准微电网场景,并使用经典控制算法和强化学习提供了性能基线。为了改进基于强化学习的微电网控制器,具有普适性和适应性的基准模拟器至关重要,而pymgrid正是扮演这个角色的。一个有前途的新途径是利用从多个微电网生成的数据来增加性能或适应性。
未来计划包括增加更广泛的基准算法套件,包括最新的强化学习方法。我们还计划允许增加其他微电网组件、更复杂的应用场景和更精细的时间分辨率。此外,我们希望增加实时数据获取的功能。最后,关于二氧化碳使用和数据的功能对于用户控制碳效率非常有价值,同时也允许用户考虑碳税在未来能源发电中可能扮演的角色。
2. 安装pymgrid
pip安装
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple pymgrid
安装要求与依赖
- python>=3.6
- 安装依赖包:
pandas,
numpy,
cvxpy,
statsmodels,
matplotlib,
plotly,
cufflinks,
gym,
tqdm,
pyyaml
下载源码安装
https://github.com/Total-RD/pymgrid.git
# 进入pymgrid工程根目录下:
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple .
3. 快速开始
定义一个简单的微电网,创建控制它的操作,并读取结果。微电网可以通过定义一组模块,然后将它们传递给微网格构造函数来定义,也可以通过YAML配置文件来定义。
3.1. 定义微电网
定义微电网的一些组件。我们将定义两个电池,一个快速充电,容量为100千瓦时,另一个慢充,但容量为1000千瓦时。
import numpy as np
import pandas as pd
np.random.seed(0)
from pymgrid import Microgrid
from pymgrid.modules import (
BatteryModule,
LoadModule,
RenewableModule,
GridModule)
small_battery = BatteryModule(min_capacity=10,
max_capacity=100,
max_charge=50,
max_discharge=50,
efficiency=0.9,
init_soc=0.2)
large_battery = BatteryModule(min_capacity=10,
max_capacity=1000,
max_charge=10,
max_discharge=10,
efficiency=0.7,
init_soc=0.2)
随机数据定义负载和光伏(pv)模块,例如,以小时为单位定义90天的太阳能发电数据。
load_ts = 100+100*np.random.rand(24*90) # random load data in the range [100, 200].
pv_ts = 200*np.random.rand(24*90) # random pv data in the range [0, 200].
load = LoadModule(time_series=load_ts)
pv = RenewableModule(time_series=pv_ts)
最后,我们定义了一个外部电网来填补任何能源缺口。电网时间序列必须包含三列或四列。前三个表示电网购电价、上网电价和每千瓦时二氧化碳产量。如果存在第四列,则表示电网状态(以布尔形式);如果没有,则假定网格始终处于启动和运行状态。
grid_ts = [0.2, 0.1, 0.5] * np.ones((24*90, 3))
grid = GridModule(max_import=100,
max_export=100,
time_series=grid_ts)
基于上述数据,构造微电网,并使用’pv’定义光伏发电。默认情况下,会添加一个平衡模块来跟踪任何未满足的需求或过剩的生产。(可以通过unbalanced_energy_module=False来禁用,但不建议这样做)
打印输出微电网,将告诉我们微电网中包含的模块。
modules = [
small_battery,
large_battery,
('pv', pv),
load,
grid]
microgrid = Microgrid(modules)
print(microgrid)
输出:
Microgrid([load x 1, pv x 1, balancing x 1, battery x 2, grid x 1])
我们可以通过名称或关键字(key)访问微电网中的模块:
print(microgrid.modules.pv)
print(microgrid.modules.grid is microgrid.modules['grid'])
3.2. 控制微电网
您必须通过每个可控模块的动作来控制微电网。固定模块存储在属性microgrid.controlleble中:
microgrid.controllable
{
"battery": "[BatteryModule(min_capacity=10, max_capacity=100, max_charge=50, max_discharge=50, efficiency=0.9, battery_cost_cycle=0.0, battery_transition_model=None, init_charge=None, init_soc=0.2, initial_step=0, raise_errors=False),
BatteryModule(min_capacity=10, max_capacity=1000, max_charge=10, max_discharge=10, efficiency=0.7, battery_cost_cycle=0.0, battery_transition_model=None, init_charge=None, init_soc=0.2, initial_step=0, raise_errors=False)]",
"grid": "[GridModule(max_import=100, max_export=100)]"
}
我们的“负载”、“电池”和“电网”模块是固定的。
我们还可以通过从微电网获得空动作来查看我们需要传递动作的模块。在这里,必须替换所有None值才能将此操作作为控制传递。
print(microgrid.get_empty_action())
重置微电网,然后检查其当前状态。
microgrid.reset()
microgrid.state_series()
随机运行一步。
microgrid.run(microgrid.sample_action())
microgrid.current_step
# 查看一步后的状态
# microgrid.state_series()
我们将尝试使用可用的可再生能源,然后对电池进行放电,以满足169.646919的负载需求。对于电池,我们将尝试产生较低的超额负载和最大产量。
load = -1.0 * microgrid.modules.load.item().current_load
pv = microgrid.modules.pv.item().current_renewable
net_load = load + pv # negative if load demand exceeds pv
if net_load > 0:
net_load = 0.0
battery_0_discharge = min(-1*net_load, microgrid.modules.battery[0].max_production)
net_load += battery_0_discharge
battery_1_discharge = min(-1*net_load, microgrid.modules.battery[1].max_production)
net_load += battery_1_discharge
grid_import = min(-1*net_load, microgrid.modules.grid.item().max_production)
control = {"battery" : [battery_0_discharge, battery_1_discharge],
"grid": [grid_import]}
control
{'battery': [13.68159573726988, 7.0], 'grid': [83.6066548705889]}
把这些放在一起,我们可以控制。
注意,正值表示进入微电网的电量,负值表示离开微电网的能源。
然后我们可以用这种控制来运行微电网。由于此控件未进行归一化,因此我们传递normalized=False。
obs, reward, done, info = microgrid.run(control, normalized=False)
3.3. 分析结果
将控制传递给微电网后,可以通过查看微电网或任何模块的日志来查看结果。微电网日志中的每一项操作都有一行。动作(例如满足的负载量)和状态(例如当前负载)都有值。
请注意,状态值是采取操作之前的状态值。
这些列是一个pd.MultiIndex,有三个级别:模块名称、模块名称枚举(例如,我们所在的每个模块名称的编号)和属性。例如,由于有一个加载,它的所有日志条目都将在关键字(“加载”,0)下可用。由于有两个电池,因此将同时有(电池,0)和(电池,1)。
microgrid.log.loc[:, pd.IndexSlice['load', 0, :]]
microgrid.log.loc[:, pd.IndexSlice['pv', 0, :]]
microgrid.log.loc[:, 'battery']
3.4. 绘制结果
我们还可以利用pandas绘图功能来查看结果。为了说明这一点,我们将用随机采样的动作使微电网再运行24步。
for _ in range(24):
microgrid.run(microgrid.sample_action(strict_bound=True))
microgrid.log[[('load', 0, 'load_met'),
('pv', 0, 'renewable_used'),
('balancing', 0, 'loss_load'),
('grid', 0, 'grid_import'),
('battery',0,'charge_amount'),
('battery',1,'charge_amount')]].droplevel(axis=1, level=1).plot()
3.5. 微电网日志(数据表)
microgrid.log
展开,查看电网“grid”数据:
microgrid.log[[('grid')]]
4. API概述
4.1. 微电网
Microgrid类,用于定义和模拟具有各种模块的环境。
- 方法:
方法名称 | 说明 |
---|---|
Microgrid.run(control[, normalized]) | 运行微电网一步。 |
Microgrid.reset() | 重置微电网并清除日志 |
Microgrid.sample_action([strict_bound, …]) | 在微电网的动作空间内获得随机动作。 |
Microgrid.get_log([as_frame, drop_singleton_key]) | 收集微电网的控制和响应日志。 |
Microgrid.get_forecast_horizon() | 获取微电网中包含的时间序列模块的预测范围。 |
Microgrid.get_empty_action([sample_flex_modules]) | 在没有设置值的情况下对微电网进行操作。 |
- Serialization/IO/Conversion——序列化/IO/转换:
名称 | 说明 |
---|---|
Microgrid.load(stream) | 从yaml缓冲区加载微电网。 |
Microgrid.dump([stream]) | 将微电网保存到YAML缓冲区。 |
Microgrid.from_nonmodular(nonmodular) | 从旧式老版本NonModularMicrogrid转换为Microgrid。 |
Microgrid.from_scenario([microgrid_number]) | 加载一个pymgrid25基准微电网。 |
Microgrid.to_nonmodular() | 将Microgrid转换为旧式NonModularMicrogrid。 |
4.2. 模块
pymgrid.modules.GridModule,一种电网模块。
默认情况下,GridModule是一个固定模块;它可以通过GridModule.as_flex转换为flex模块。GridModule是唯一一个既可以是固定模块又可以是柔性模块的内置模块。
pymgrid.modules.RenewableModule,可再生能源模块。
可再生能源的经典例子是光伏和风力涡轮机。
pymgrid.modules.BatteryModule,一个电池模块。
电池模块是固定的:当调用Microgrid.run时,您必须通过电池控制。
如果您定义了battery_transition_model,那么如果您计划序列化您的电池模块或包含电池的任何微电网,那么它必须是YAML可序列化的。
例如,您可以将其定义为一个具有__call__方法的类,并将yaml.YAMLObject定义为其元类。有关详细信息,请参阅PyYAML文档。
pymgrid.modules.GensetModule,发电机组/发电机模块。
该模块是一个可控源模块;当用作微电网中的模块时,必须向其发送发电生产请求。
pymgrid.modules.UnbalancedEnergyMod
4.3. 预测
Forecasting可用于时间序列预测的类,以及允许用户定义自己的预测者的类。
get_forecaster(),获取时间序列模块的预测函数。
4.4. 强化学习(RL)环境
使用OpenAI Gym API进行强化学习的环境类。
- Discrete
具有离散动作空间的环境。
DiscreteMicrogridEnv(modules[, …])
一种离散的环境,将优先级列表作为微电网上的操作来实现。
- Continuous
具有连续动作空间的环境。
ContinuousMicrogridEnv(modules[, …])
具有连续动作空间的微网格环境。
4.5. 控制算法
pymgrid中内置的控制算法,以及可以部署的外部算法的引用
- 基于规则的控制
通过优先级列表部署模块的启发式算法。
RuleBasedControl(microgrid[, priority_list, …])
在微电网上运行基于规则的(启发式)控制算法。
- 模型预测控制
依赖于未来预测以及状态转换模型来确定最佳控制的算法。
ModelPredictiveControl(microgrid[, solver])
在微电网上运行模型预测控制算法。
- 强化学习
将微电网视为马尔可夫过程的算法,并通过与环境的重复交互来训练黑箱策略。有关使用强化学习来训练此类算法的示例,请参见后续文章。
参考原文:
pymgrid documentation
Gonzague Henri (Total). pymgrid: An Open-Source Python Microgrid Simulator for Applied Artificial Intelligence Research (Papers Track). Neurips 2020