一、前言
上一篇初步介绍了Simulink的基本使用,并介绍了其中SimPowerSystem工具箱封装电气模型与信号模块搭建模型的区别与联系。初学者可以基于此方便地构建单机无穷大系统并进行相应的分析,但对于大系统的搭建、潮流计算与批量处理,还需要进一步借助Matlab的m文件辅助建模。即剩下三种建模方式:
4)以搭建的信号模块系统为模板,信号的传递是向量而不是单独的标量,进而用m文件控制slx仿真,实现任意系统下潮流计算、初始赋值、仿真运行以及相关分析;
5)在m文件中构建系统“类”,通过Matlab函数,运用面向对象的方式快速自动生成系统,进而类似(4)实现仿真运行与分析的自动化;
6)通过m文件在Simulink中自动生成大型系统,实现系统的布局、变量命名、以及自动化分析、绘图等工作。(它已经是一个长大的软件了,是应该让它自己做研究了)
二、知识说明
本文内容需要用到的知识较多,比如(5)要用到面向对象编程的思想,这种思想在不同语言中逻辑相同,只是语法上有些区别;同时还需要大家对电力系统潮流计算、基本电气发电单元建模有一定的了解。
2.1潮流计算
如果是搭建单机无穷大系统,即一个恒压源直接连着一个发电单元,比如双馈感应风机,那此时在仿真建立时,不用考虑其它因素,只要设置合理的端电压值即可让仿真正常运行。其中所有状态量甚至可以从0开始运行,待系统稳定时保存最后的运行点,即可以作为下一次仿真的初始运行点,让系统从稳态开始运行。然而,当多机系统互联时,其中电网规模逐渐增大,为了保障该仿真能够稳定运行,以及稳定时各节点电压与线路传输功率合理,我们需要依据电网参数以及发电单元的边界条件计算潮流,从而给接入系统的发电单元赋上合理的初值,让系统一开始便从稳态点附近开始运行,并保障电压、功率传输的合理性。
因此,在后续仿真搭建时,m文件中第一步往往是选取你的模型拓扑,进而进行潮流计算。如果你选择的是IEEE标准测试模型,比如IEEE14或118节点,则可以用MatPower中自带的数据进行计算;如果是自定义的拓扑结构,则需要自己拟定相关数据格式。仿真中,有关系统结构的数据最好是通过excel/csv格式进行存储,以方便阅读和修改。
2.2面向对象编程
将代码按逻辑顺序直接表达是面向过程式编程,将代码块写成函数即函数式编程,将相关功能的函数和数据集成一个整体,作为一个模板来对待,即是面向对象编程。面向对象编程是编写大型程序系统时都要使用的方法,像Python/C++/Java等语言,提供了面向对象的语法,我们可以很方便的基于此实现想要的功能。关于其具体的学习,如Python的面向对象,可以参考网站:www.itprojects.cn。
本文将在3.2中,介绍用m文件的代码形式,将系统写成一个类(因此会用到面向对象编程的相关概念),进而在Simulink中用Matlab System进行调用,从而实现Matlab与Simulink之间更为灵活的交互。
2.3基本发电单元建模
新型电力系统中,常见的基本发电单元除了同步发电机,还有以锁相环为主导的跟网型电力电子装置,以下垂控制等为控制策略的构网型电力电子变换装置,还有高压直流输电、风电光伏等。这些装置的都是以电力电子变换器为接口,通过控制策略实现并网,这和传统同步发电机有些不一样。
同时,连接这些发电单元的变压器,线路亦是电力系统的重要组成部分。在电力系统稳定性分析建模中,如果使用信号模型进行搭建,变压器可以直接用简单的电阻/电感加一个增益进行代替,线路则可以使用简单的pi型电路。
总之,掌握基本发电单元模型的共性,理解基本的工作、数学原理,是模型建立以及后续理论研究的根本,本文集后续亦将陆续展开。
三、Matlab/Simulink建模方法
3.1以Simulink信号模块系统为模板
这种建模方式在文集《数学建模》中电工杯A2023已有介绍。通过一个房间模块,让其中流动的信号为高维度的向量,从而同时实现多个房间模块的并行运算。
这种方式同样适用于电力系统多机设备模型的构建。比如用同一个同步发电机模型,用同一套参数同时仿真系统中所有的同步机台数,最后输出的向量再输到电网的系统(暂态是状态空间方程模型,稳态是节点导纳矩阵,后续将介绍)。
举例来说,我们现在想建立一个纯同步电机的IEEE39节点系统和IEEE118节点系统以供项目使用。如果按照前三种方式进行建模,则需要搭建一台同步机信号模型(或者用Simulink自带的电气模型),然后将其copy相应份数,然后将其按照拓扑进行连接,还要修改变量名,赋参数值和状态变量初值......O这个很明显是不符合实际的。
应用(4),我们可以这样做。在Simulink中建立一个同步发电机的信号模型,其模型的详细程度可由研究问题的性质来决定。同步机接入电网中,电网模型和同步机相连的地方往往会放置一个等效电容,我们将这个电容从电网模型中剥离出来,一并添加到Simulink中(当然,这时候要在m文件电网参数中将相应的电容置零)。这样一来,我们形成了一个完整的同步机模型。其余的电网模型,其输入是电容的电压,输出是电流,我们可以直接将其视为一个状态空间方程。
dq坐标系下的同步机+电容+电网模型【1】,可以发现,其中只有一个同步机模块,电容模块
其中的同步机展开为:
简化的同步机模型,其中电机部分只有3个绕组加摇摆部分,这已经能构满足大部分稳定性问题的分析研究
在Simulink中搭建骨架以后,接下来便是在m文件中添加灵魂。
第一步,既然要搭建IEEE118节点,我们则需要从MatPower中调用IEEE118潮流数据计算初始数据。当然,我们还可以针对研究的问题,对数据进行一些调整,比如将节点,线路进行排序,对参数进行检查等等。
第二步,基于IEEE中标准参数给发电机进行参数赋值。很明显,这里的赋值都是要以向量的形式进行赋值,从而用Simulink中的一个模块,同时代表很多个同步机。然后,基于潮流参数给剥离出来的端口电容赋上初值,以便让系统从稳定运行状态附近开始运行。同步机内部参数则可以通过电机的稳态分析进行反推,这在电机学课本中有较为清楚的阐述。
可见,系统越大,我们要处理的数据就越多,为了避免出错,再建立模型之前最好规划一下数据的结构形式,做好排序,规范命名的一些基本初始化工作
第三步,电网状态空间方程模型生成。电网中所有支路都可以简化为简单的pi电路,因此,由这个微分方程模型转换为状态空间可以通过函数编写实现。【1】中提供了一个dq0软件,它可以让用户手绘线路结构,然后自动转换为相应的ABCD状态空间,以便直接输入到Simulink中。
如果要搭建IEEE39节点,我们则无需做太大改动,将潮流数据换一下即可。而如果需要加入电力电子换流器为接口的新能源发电装置,我们则只需要建立新的信号模型模板,用类似的方式即可构建。而当系统出现不稳定时,比如IEEE39节点发生了振荡现象,通过这种建模方式,可以很方便分析系统的参与因子和留数等,且直接给系统中的PSS进行赋值,来稳定系统。
值得注意的是,在《电工杯A2023》中我们还采用了S函数,通过内嵌代码的方式实现了部分控制,这种方式和3.2将要介绍的以m文件代码为模板都是Simulink和代码形式相结合的方式,但原理是完全不同的。S函数本质与信号模块无异,只是形式上的差别,但是3.2将要介绍的,是基于面向对象实现的系统代码复用,是更为方便的一种交互形式。
3.2以m文件代码为模板
在Simulink中,有一种模块叫Matlab System【3】,点进去会发现,其不能设置参数,只有一个可以放置代码的地方,而这个代码和函数形式不一样,其要以Matlab对象的形式进行运行。
其实这和(4)有点相似,(4)中是以信号模块为一个模板,以向量作为流动的数据实现大型系统的仿真。而(5)中的模板则是Matlab System中的代码。因此,第一个感受是,(5)可能没有(4)那么的容易修改。因为代码一旦写好,你就不能像信号模块那样像在哪加东西就在哪加东西了。然而,以m文件代码为模板又拥有一些其它的优势。
我们仍然从甲方的要求入手,现在甲方要求搭建10机39节点,搭建所搭建的模型要将实际的电路拓扑给体现出来;有几台发电单元,就要显示几个模块;而且电网不要简单地用状态空间方程进行表示。这样一来,我们就不能使用“流动的向量”来解决问题了,只能通过copy多个信号模块,并相应赋值来实现仿真。
而(5)中copy的不是信号模块,而是通过你的模型“类”代码,生成了很多个“实例”,也就是多个同步机。
这是一个构网型器件的类代码【2】,方法往往包括:潮流赋值,平衡点计算,模型线性化等。所有发电单元所具有的共同属性和方法,也可以变成一个父类,通过继承的方式来减少代码的冗余度
这样一来,我们便可以在一处m文件中设置好模型的类代码,通过在Simulink中不断的生成实例,即可达到同样的效果,还可以避免反复的copy(4)中的信号模型提高效率。
我们将信号模型变成了代码类,其相关输入输出也可以通过信号线与Simulink模型相互连接,从而实现交互。这时候仿真环境从单一的Simulink变成了m类文件和Simulink混合的情况(上述只是发电单元变成了类,外面的电网模型还是Simulink的)。那么这时候Simulink求解整个仿真的流程(也就是计算整个系统的微分方程的数值解)是怎样的呢?
如果在Simulink中,存在“类”模型和Simulink模型混合的情况,这时“类”模型中的微分方程和Simulink模型的微分方程并不是被解释器一并求解的。
模型中“类”对象与Simulink模型共存,从信号流入到流出可以理解为propagation(传播)
由上图可见,类内部的微分方程模型和Simulink中的模型并不是一并求解的,我们需要在类内部自己编写代码来更新里面状态变量的值,从而计算输出给Simulink。比如,我可以在类内部编写简单的欧拉算法,设置仿真步长为1e-4。而外部Simulink的求解器中设置仿真步长为1e-5。这样还可以使得同一仿真下数据的步长不一样。(理论上应该是这样,但实际还是保持一样好一点,不要做奇怪的事情)。这样一来,信号流入类模型,到信号流出类模型,这样的传递过程在Simulink中称为propagation,传播方法。一般而言,这种仿真运行的方式又叫Interpreted execution,是一种中断执行仿真的方法。而不是那种在纯Simulink模型下,将模型都变为代码的仿真方法(code generation)。
因此,为了实现这样一个流程,官方在类模型中设置了几个默认会执行的方法(函数),基本是以Impl结尾的。常用的有:outputImpl, updateImpl【4】等。
【2】中模型采用前向欧拉算法进行状态更新,大家可以尝试在其中编写更为复杂的微分方程求解算法
以上讲解了利用Matlab System模块进行系统搭建以及其在仿真运行时大致的工作流程。但还需要指出的是,目前该模块并不能通过雅可比矩阵函数的形式对系统进行线性化【3】,因此,如果需要获取系统的状态空间方程,只能通过数值计算的方式,即给一个状态变量一个小干扰,计算函数值与自变量的微商。
在类文件中输入各个微分方程之后,我们则可以计算加小干扰之后的导数变化值,使其作商即可计算偏导数,从而形成A,C。B, D可以类似生成。
3.3Simulink模型的自动生成与其它自动化操作
方法(5)中通过类实现了多个发电单元实例的生成,但是对于甲方的要求,我们似乎还没有解决大型模型的电网结构问题,如果要搭建39节点系统,或者是要搭建含300台风机的风电场,人工搭建在当今快节奏的学术生活中无疑是低效率的。
Matlab提供了很多函数,可以使得我们通过编程的形式对仿真进行操控,包括通过编程实现对Simulink模型的参数命名与赋值,模型的添加与位置移动,以及仿真运行,添加输入输出口,线性化等等。常用的交互函数【5】有:
(1)set_param:设置指定模块对象的参数,是一个交互中难以避免的函数,在很多场合都有用到;
(2)get_param:提供指定模型对象的参数,往往和前者配套使用;
(3)regexprep:由于m文件访问Simulink模型中各个模块是按照路径一层一层搜索的,同时往往需要批量修改多个模型的名字,所以获取与设置参数往往需要设置路径字符串,因此regexprep便经常派上用场。
基于以上三种函数,我们可以实现模型名字的批量修改。以下代码可以将30台风机模型的名字,批量命名为DFIG1、DFIG2......从而使模型易读,便于后续的分析。
modelName = 'DFIG_origin';
open_system(modelName);
for num = 1:30
targetLevel = ['/DFIG_C_Line','/DFIG' num2str(num)];
findAndModifyBlocks(modelName, targetLevel, num2str(num));
end
% Save and close the model
save_system(modelName);
close_system(modelName);
function findAndModifyBlocks(modelName, targetLevel, suffixToAdd)
% Find blocks in the current subsystem
blocksInSubsystem = find_system([modelName, targetLevel], 'LookUnderMasks', 'all', 'BlockType', 'ToWorkspace');
% Modify blocks in the current subsystem
for i = 1:length(blocksInSubsystem)
originalVariableName = get_param(blocksInSubsystem{i}, 'VariableName');
cleanedVariableName = regexprep(originalVariableName, '\d+$', '');
newVariableName = [cleanedVariableName, suffixToAdd];
set_param(blocksInSubsystem{i}, 'VariableName', newVariableName);
end
end
而在m文件中使用add_block函数,则可以从指定模型库中往Simulink文件中添加模型,结合set_param函数即可设置模型的相对位置,最终各函数合作,可以实现大型模型的自动化生成(这一点【2】中模型是可以学习的典范)。具体而言,要建立IEEE118节点,我们可以从潮流等数据中,获取母线、发电机等元器件的信息,然后一种一种类型的向slx文件中添加。
构建完模型后,我们可以配上其它分析流程,将数据导出绘图,进行线性化,模态分析等等操作。下面提供了一套简约的绘图格式,可以在绘图之前运行。
set(groot,'defaultLineLineWidth',2)
set(0,'DefaultaxesLineWidth', 1.5)
set(0,'DefaultaxesFontSize', 14)
set(0,'DefaultaxesFontWeight', 'bold')
set(0,'DefaultTextFontSize', 14)
set(0,'DefaultaxesFontName', 'Times new Roman')
set(0,'DefaultlegendFontName', 'Times new Roman')
set(groot,'defaultLegendLocation','best')
set(groot, 'defaultFigureColor', [1, 1, 1]);
set(0,'defaultAxesXGrid','on')
set(0,'defaultAxesYGrid','on')
四、总结
本文集介绍了基于Matlab/Simulink建立电力系统模型的剩下三种方式,其相比前三种,更加侧重于大型系统的批量处理,是程序模型高自由度以及可拓展性的体现。[1], [2]中可以找到对应上述三种建模方式的典型实例,值得我们好好学习,拓展。除此之外,Simulink中还有许多cool的功能以便于我们高效便捷地实现项目的要求。同时,其还可以通过API接口与Python进行相互调用,这能够使得我们充分地发挥Simulink仿真优势与Python在数据处理方面的优势,从而实现更加cool的功能。
对于电力系统稳定性分析而言,电力系统的建模仅仅是基础中的基础。选取一个合适正确、易于拓展的建模方式,有助于学习成果的不断积累,且为以后分析理论的提出,控制的实施验证打下坚实的基础。
最后,让我们向所有科研人员们无私伟大的开源精神致敬!他们像是灯塔一样,指引着我们前进的方向。
五、参考文献
[1] yoash levron (2024). Toolbox for Modeling and Analysis of Power Networks in the DQ0 Reference Frame (https://www.mathworks.com/matlabcentral/fileexchange/58702-toolbox-for-modeling-and-analysis-of-power-networks-in-the-dq0-reference-frame), MATLAB Central File Exchange. 检索来源 2024/2/6.
[2] Simplus-Grid-Tool. online: https://github.com/Future-Power-Networks/Simplus-Grid-Tool
[3] 自定义适用于 Simulink 的 System object - MATLAB & Simulink - MathWorks 中国
[4] https://ww2.mathworks.cn/help/simulink/ug/propagate-mixins.html
[5] 设置 Simulink 参数值 - MATLAB set_param - MathWorks 中国