An improved virtual synchronous generator power control strategy
Deep reinforcement learning based parameter self-tuning control
基于改进型RBF神经网络的VSG转动惯量自适应控制_杨旭红
基于RBF的VSG转动惯量和阻尼系数自适应控制策略_高子轩
基于虚拟同步发电机的逆变器并网稳定性研究_姚凤军
基于S函数的BP神经网络P...制器及Simulink仿真_杨艺
想做一个把虚拟同步发动机中转动惯量J自适应调节的仿真,于是参考了姚凤君硕士的论文,在做仿真的时候遇到很多问题,主要是S函数怎么使用,网上资料很少,后来参考了csdn上一些博文,还看了杨艺的论文,摸索了一些方法,不能说完全掌握了s函数模块的使用,至少在一定程度上能复现出姚凤君论文中的效果了。
一般来说,神经网络算法是基于数据集来做预测和识别的,运用到控制系统里做参数自适应调节的例子不多,但是它是有潜力做这个工作的,毕竟其对非线性关系的拟合效果很好,能描述非线性关系。但是也有缺陷,那就是神经网络算法计算需要时间,怎么将这个时间尺度匹配好,还需要做更多优化,不能让基于t-1时刻状态得到的参数,拿来应用的时候已经是t+1时刻了,这样很有可能会导致系统的失调和震荡。
关于VSG相关的一些原理可以看我其他博文或者高子轩和姚凤军的论文,简单地说就是VSG的参数J(转动惯量)对VSG性能影响很大,主要体现在当有功功率指令变化(接入负载或负载撤去)时,产生的电网频率波动和有功功率、无功功率震荡,我们的目的是采用RBF神经网络,让它根据电网频率的偏差和变化率,取调节实时输出的转动惯量J,已达到减小电网频率波动的目的。那么输入就是两个,Δω和dω/dt,输出就是J。
下面着重来讲程序和仿真设计。

使用的版本是matlab2022a,我相信在其他版本下也可以完成这个建模。以下展示几个关键位置:


以下是转子机械方程:

设定中,有功功率在0.5秒时从5kw突增到20kw,再在0.8秒回到5kw。

detaw和dw_dt是用来观测的,删去也无所谓。

内部设置,mux模块,从上到下,是u(1),u(2),u(3)和u(4),里面前两个输入后面将作为神经网络的输入,乘以0.1是因为我想做数据归一化,尝试很多参数后发现0.1可行,大家可以自己改进这里的预处理形式,也可以把预处理封装携程代码坐进是模块中。里面的1/Z模块是延时模块Unit delay,这里表示ω(t-1),这些部分是和后面的RBF_VSG_a_4算法中联系起来的,里面使用的u(1)对应就是我外面输入进去的max第一个值。
s函数的设置就是你在外面写一个.m函数就行,保存,但是它有固定格式的。
我们怎么封装进去呢?

选择我圈出来的这个,双击,点编辑,浏览,找到你写的函数,双击

会弹出以下界面:

在编辑器中点运行-添加到路径。一定要有这一步,不然matlab找不到这个m文件的位置,你以后运行这个模型的时候,如果找不到文件位置,再进去点一下运行,报错不要紧,肯定会报错告诉你参数不足,但是一定要运行,添加到路径!

把这个名字复制到这里,点应用,这里要注意,文件名,文件中的代码(上图),仿真s函数中的名字要是一样的,缺一不可。
再把它连接到仿真里面去,就可以了,连接完就是这小节图二的样子。
重点再算法,原理就不说太多了,这里目的是教学使用s函数写代码,具体原理可以看论文:基于虚拟同步发电机的逆变器并网稳定性研究_姚凤军
这里使用的是2-5-1的结构,径向基函数
的ci为0,bi为1,所以在代码里面我根本不定义这两个值,直接使用,需要用的可以定义,注意是向量的形式。
s函数可以识别C语言,我就用c语言编写了。代码注释很详细,不懂得可以看看,懂得劳烦多按删除键。
function [sys,x0,str,ts,simStateCompliance] = RBF_VSG_a_4(t,~,u,flag)
% 网络结构2-5-1的径向基函数,这里是定式,等号前面就这么写,等号后面是输入,输入t表示时间,~原来是x,表示中间变量,我这里没有中间变量,所以用~代替,u是输入,我们这里有4个,用u(i)表示,flag是标志位,后面细说
%u为输入矢量
%sys是系统输出
%x0是系统状态变量的初值
%str为保留参数且一直是空值
%ts是采样时间
%flag是标志位
%================================================
%flag | 调用函数 | 功能
% 0 |mdlInitializeSize |系统模型初始化函数
% 1 |mdlDerivatives |连续系统状态变量导数
% 2 |mdlUpdate |离散系统状态变量更新
% 3 |mdlOutputs |系统模型输出
% 4 |mdlGetTimeOfNextVarHit|计算下一个采样点时间
% 9 |mdlTerminate |仿真结束调用函数
%================================================
Ts = 0.005;%采样时间,每0.005秒进行一次计算,这个可以改的,大家根据需要来改
switch flag%flag可以为012349,分别的功能请参考杨艺的论文,这里用的功能3,输出值,因为我们要得到输出的J,功能0,初始化,别的功能不需要
case 0
[sys,x0,str,ts,simStateCompliance]=mdlInitializeSizes(Ts);%标准格式,这里可以定义外部封装参数,比如从外部输入隐藏层层数,我们不需要这个功能
case 3
sys=mdlOutputs(t,u);%在使用case 3的时候,需要用到t(仿真时间)和u(输入值),等号前面的sys是输出,我们后面会把J的计算结果给它,让它带到代码之外
case {1,2,4,9}
sys=[];%不需要的功能给空
otherwise
DAStudio.error('Simulink:blocks:unhandledFlag', num2str(flag));%标准格式
end
function [sys,x0,str,ts,simStateCompliance]=mdlInitializeSizes(Ts)%初始化,case 0
sizes = simsizes;
sizes.NumContStates = 0;%连续变量个数,不存在,毕竟我们的中间变量x=0
sizes.NumDiscStates = 0;%离散变量个数,不存在,理由同上
sizes.NumOutputs = 1;%输出变量是1个,就是J,在代码里面是J
sizes.NumInputs = 4;%4个输入,u1-4
sizes.DirFeedthrough = 1;%馈通,这里是1,尝试写为0,发现抱错
sizes.NumSampleTimes = 1;%默认为1
sys = simsizes(sizes);
x0 = [];%状态变量的初始值
str = [];
ts = [Ts 0];%采样时间
simStateCompliance = 'UnknownSimState';
function sys=mdlOutputs(t,u)%这里开始计算,case 3
persistent w w_1 h J_1 dw dw_1 J E_1%全局变量,我们用这种方式来代替x,保证在下一个计算时也可以使用上一次计算的结果
% RBF网络学习效率
xite = 0.5;
% RBF网络惯性系数
alfa = 0.05;
% 高斯基函数宽度
% b = 1;
if t == 0%初始化
J_1=0.05;%J_1的意思就是J(t-1)
%J的初始化
% c = 0;
h = zeros(5,1);%初始径向基函数设定值,你给个任意值就行了,反正要覆写的,我给的全0
w = rand(5,1)*(-1);%初始权值,也是随便给,我给的全为负
w_1 = w;
dw_1=0;
E_1=0;
end
RBF_input = [u(1) u(2)]';%输入层输入=隐层输入
%这里的u1和u2分别是△ω和d_ω/d_t
for j = 1:5%5个神经元
h(j) = exp(-norm(RBF_input)^2/2);%计算隐层输出,高斯基函数输出
end
ho_input=sum(h*w_1');%输出层输入,把隐层的5个结果加一起
yoout=0.5*exp(ho_input)/(exp(ho_input)+exp(-1*ho_input));%输出层激活函数,类似sigmoi
if yoout >=0.45
J = 0.450;
else if yoout <=0.035
J = 0.035;
else
J = yoout;%确保J在范围[0.035,0.45]内
end
%下面做权值更行,方法是改进的梯度下降法,具体见论文基于虚拟同步发电机的逆变器并网稳定性研究_姚凤军
end
o1=xite*u(1);%数
o2=sign((u(3)-u(4))/(yoout-J_1));%符号
o3=yoout*h;%向量,dim(5*1)
o4=alfa*dw_1;%向量,dim(5*1)
dw=o1*o2*o3+o4;
dw_1=dw;
%定义评价函数,如果上一次输入的电网频率偏差值或者这次输入的电网频率偏差值为0,就表明不需要调整权值
E=0.5*(u(1))^2;
if E_1*E == 0
w = w_1;
else
w = w_1-dw;
end
E_1=E;
w_1 = w;
J_1 = J;%下一次计算时,J(K-1)=本次输出的yoout也就是J
sys = J;
这个代码很简单,里面肯定有些漏洞,请大家看的时候多思考,但是基本功能是能实现的。
功率指令变化:
神经网络输出:转动惯量J的变化
和固定参数(J=0.3)的对比
电网频率波动

可见RBF调节下的电网频率调节时间更快,但是超调量会增加,大概增加了2.25rad/s,超调量为0.7%,远小于电网准入标准的2.5%,说明性能达标。

无功功率对比,超调量增加,调节时间变短

有功功率对比,超调量和调节时间均好于固定参数!
诚然,这次实验从实验结果来看,是令人满意的,但是能看见电网频率在RBF调节下,在有功功率指令突变的时候,会发生一个陡峭的上升,这样的冲击,对用电设备是非常不利的,说明这个方法,至少在我复现的模型中,还有改进空间,那就是J能不能不要在0.45和0.035之间跳变,而是有个上升的过程。这说明算法还是有改进空间的,我觉得也许要把阻尼系数放进来一起调节,或许有助于改善这个问题。
不过对于熟悉s函数操作编程,模型搭建的入门来说,这个实例已经足够用了,感谢大家阅读本文,希望我的分享对大家有帮助。欢迎点赞和关注!
假设我做了一个模块如下:m=Module.newdoclassCendend三个问题:除了对m的引用之外,还有什么方法可以访问C和m中的其他内容?我可以在创建匿名模块后为其命名吗(就像我输入“module...”一样)?如何在使用完匿名模块后将其删除,使其定义的常量不再存在? 最佳答案 三个答案:是的,使用ObjectSpace.此代码使c引用你的类(class)C不引用m:c=nilObjectSpace.each_object{|obj|c=objif(Class===objandobj.name=~/::C$/)}当然这取决于
作为我的Rails应用程序的一部分,我编写了一个小导入程序,它从我们的LDAP系统中吸取数据并将其塞入一个用户表中。不幸的是,与LDAP相关的代码在遍历我们的32K用户时泄漏了大量内存,我一直无法弄清楚如何解决这个问题。这个问题似乎在某种程度上与LDAP库有关,因为当我删除对LDAP内容的调用时,内存使用情况会很好地稳定下来。此外,不断增加的对象是Net::BER::BerIdentifiedString和Net::BER::BerIdentifiedArray,它们都是LDAP库的一部分。当我运行导入时,内存使用量最终达到超过1GB的峰值。如果问题存在,我需要找到一些方法来更正我的代
我有一个模型:classItem项目有一个属性“商店”基于存储的值,我希望Item对象对特定方法具有不同的行为。Rails中是否有针对此的通用设计模式?如果方法中没有大的if-else语句,这是如何干净利落地完成的? 最佳答案 通常通过Single-TableInheritance. 关于ruby-on-rails-Rails-子类化模型的设计模式是什么?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.co
我有一个包含模块的模型。我想在模块中覆盖模型的访问器方法。例如:classBlah这显然行不通。有什么想法可以实现吗? 最佳答案 您的代码看起来是正确的。我们正在毫无困难地使用这个确切的模式。如果我没记错的话,Rails使用#method_missing作为属性setter,因此您的模块将优先,阻止ActiveRecord的setter。如果您正在使用ActiveSupport::Concern(参见thisblogpost),那么您的实例方法需要进入一个特殊的模块:classBlah
我将应用程序升级到Rails4,一切正常。我可以登录并转到我的编辑页面。也更新了观点。使用标准View时,用户会更新。但是当我添加例如字段:name时,它不会在表单中更新。使用devise3.1.1和gem'protected_attributes'我需要在设备或数据库上运行某种更新命令吗?我也搜索过这个地方,找到了许多不同的解决方案,但没有一个会更新我的用户字段。我没有添加任何自定义字段。 最佳答案 如果您想允许额外的参数,您可以在ApplicationController中使用beforefilter,因为Rails4将参数
我刚刚被困在这个问题上一段时间了。以这个基地为例:moduleTopclassTestendmoduleFooendend稍后,我可以通过这样做在Foo中定义扩展Test的类:moduleTopmoduleFooclassSomeTest但是,如果我尝试通过使用::指定模块来最小化缩进:moduleTop::FooclassFailure这失败了:NameError:uninitializedconstantTop::Foo::Test这是一个错误,还是仅仅是Ruby解析变量名的方式的逻辑结果? 最佳答案 Isthisabug,or
我想获取模块中定义的所有常量的值:moduleLettersA='apple'.freezeB='boy'.freezeendconstants给了我常量的名字:Letters.constants(false)#=>[:A,:B]如何获取它们的值的数组,即["apple","boy"]? 最佳答案 为了做到这一点,请使用mapLetters.constants(false).map&Letters.method(:const_get)这将返回["a","b"]第二种方式:Letters.constants(false).map{|c
我的假设是moduleAmoduleBendend和moduleA::Bend是一样的。我能够从thisblog找到解决方案,thisSOthread和andthisSOthread.为什么以及什么时候应该更喜欢紧凑语法A::B而不是另一个,因为它显然有一个缺点?我有一种直觉,它可能与性能有关,因为在更多命名空间中查找常量需要更多计算。但是我无法通过对普通类进行基准测试来验证这一点。 最佳答案 这两种写作方法经常被混淆。首先要说的是,据我所知,没有可衡量的性能差异。(在下面的书面示例中不断查找)最明显的区别,可能也是最著名的,是你的
我想在Ruby中创建一个用于开发目的的极其简单的Web服务器(不,不想使用现成的解决方案)。代码如下:#!/usr/bin/rubyrequire'socket'server=TCPServer.new('127.0.0.1',8080)whileconnection=server.acceptheaders=[]length=0whileline=connection.getsheaders想法是从命令行运行这个脚本,提供另一个脚本,它将在其标准输入上获取请求,并在其标准输出上返回完整的响应。到目前为止一切顺利,但事实证明这真的很脆弱,因为它在第二个请求上中断并出现错误:/usr/b
我一直致力于让我们的Rails2.3.8应用程序在JRuby下正确运行。一切正常,直到我启用config.threadsafe!以实现JRuby提供的并发性。这导致lib/中的模块和类不再自动加载。使用config.threadsafe!启用:$rubyscript/runner-eproduction'pSim::Sim200Provisioner'/Users/amchale/.rvm/gems/jruby-1.5.1@web-services/gems/activesupport-2.3.8/lib/active_support/dependencies.rb:105:in`co