CBuilder 教程 4- 发电机励磁控制器

目录

1 介绍

2 绘制图形并添加参数

3 添加模型代码

4 DC1型励磁器的示例“c”代码

5 数据准备和初始化

6 添加内部滑块

7 添加realpole函数的CODE

8 添加代码leadlag函数

9 添加Washout函数的代码

10 添加饱和函数的代码

11 添加代码

12 增加一个刻度盘来选择内部变量进行监控

13 添加一个通用输出

14 添加监控CODE


技术咨询、模型上机运行 请加微信号 rtdsim

1 介绍


DC1型励磁器需要来自发电机模型的实数类型输入。两个需要的输入是发电机终端标幺值形式的电压(Vpu)和发电机转速(W)。可选的实型的电力系统稳定器输入和负载补偿输入。励磁器模型产生发电机所需的励磁电压输出(Ef)。

2 绘制图形并添加参数

  • 作为起点,可以将现有的发电机控制块加载到CBuilder中。这消除了绘制图标和创建所有参数的需要。现有的发电机控制块可以在RSCAD的安装目录中找到
    > MLIB > Components > CONTROLS > GENERATOR。
  • 加载元件后,会出现一个弹出框,要求输入
    元件。选择“控制”。


图7.1:EXDC1元件图标
励磁控制器的元件图标包括5个I/O点。4个信号输入和1个信号输出,均为实数。

      • 将CBuilder图标保存到位于RTDS_USER|ULIB文件夹中的新文件名中。

3 添加模型代码

  • 选择“C File Associations”选项卡。
  • 选择“+”图标添加新关联。
  • 输入模型名称。
  • 输入和输出点(列在IO points选项卡下)和用户定义的参数(列在parameters选项卡下)会自动与模型关联,并放置在.h文件中。左键点击“View Header File”按钮,就会在编辑器中打开.h文件。该模型包括四个输入,一个输出和一些参数:
    INPUTS:
    double VPU; double VS; double Speed; double VC;
    OUTPUTS:
    double OUT;
    PARAMETERS:
    charGen[11]; intMon;
    int PSS; double Vi; double Tr; double Ka; double Ta;
    ...

4 DC1型励磁器的示例“c”代码

  • C代码是通过点击编辑图标打开文本编辑器窗口来为模型编写的。
  • DC1型励磁器的代码基于图7.2所示的框图。
    CBuilder教程:发电机控制块


图7.2:EXDC1图

      • DC1型励磁器的数据准备和代码如下所示。
        VERSION:
        3.001
        #include ”myEXDC1.h”
        STATIC:
        double dt,washoutG; double Vmax, Vref, tmp; double efldi,Verr,v_init;
        double mon1,mon2,mon3,mon4,mon5,mon6,mon7,mon8,mon9,mon10; int mon_array[10] = {1,2,3,4,5,6,7,8,9,10};
        #include <builtin_gcc_generatorStructures.h>
        struct realpolex realpole1; struct realpolex realpole2; struct integratorx integrator1; struct washoutx washout1; struct leadlagx leadlag1; struct satKEx satKE1;
        RAM_FUNCTIONS:
        #include ”initTransferFunctions.inc”
        RAM:
        dt= getTime-step();
        /* Parameter Validation */
        if(Vrmax <= 0.0)
        {
        if(E2< E1)
        {
        printf(”\nWarning: Vrmax is less than zero.”); printf(”\nE2 must be greater than E1”);
        printf(”\nSubsystem %d, Machine %s, exciter type ESDC1A.\n”, getSubsystem(),Gen);
        reportError(”EXDC1”,1);
        }
        Vrmax = (Se2 + Ke)*E2;
        Vrmin = −1*Vrmax;
        }
        if (Vrmax < Vrmin)
        {
        tmp = Vrmin;
        Vrmin = Vrmax;
        Vrmax = tmp;
        printf(”\nWarning: Vrmax is less than Vrmin.”);
        printf(”\nVrmin set to Vrmax and Vrmax set to Vrmin”);
        printf(”\nSubsystem %d, Machine %s, exciter type EXDC1.\n”, getSubsystem(),Gen);
        reportError(”EXDC1”,1);
        }
        /* read initial field voltage */
        efldi = get_data(Gen,”Efldi”);
        /* ComputeinitialVrefvalue */ if (Vi < 0.0 || LFInit==1)
        {
        Vi= get_data(Gen,”Vpu”);
        if (LDComp == 1)
        {
        Vi = computeInitVcomp(Gen);
        }
        }
        /* ComputeinitialSe+KE */ if (Ke == 0.0)
        {
        v_init = 0.0;
        printf(”\nWarning: Ke entered as 0.0. Calculation of Ke such that the”); printf(”\ninitial condition of Vc is zero is not supported.”);
        printf(”\nSubsystem %d, Machine %s, exciter type EXDC1.\n”, getSubsystem(),Gen);
        reportError(”EXDC1x”,1);
        }
        else
        {
        v_init = initSatKE(E1,Se1,E2,Se2,efldi,Ke,&satKE1);
        }
        printf(”The value of v_init is %f\n”,v_init);
        Verr = v_init/Ka;
        Vref = Verr + Vi;
        Vmax= 1.2;
        if (Vref > Vmax) Vmax= 1.2*Vref;
        /* the create_slider function is in the .h file in the INPUTS section */
        /* Initialize variables for real pole #1 */
        initRealPole(1.0,Tr,Vi,Vi,&realpole1);
        /* Initialize variables for lead − lag */
        initLeadLag(Tb,Tc,Verr,Verr,&leadlag1);
        /* Initialize variables for real pole #2 */
        initRealPole(Ka,Ta,Verr,v_init,&realpole2);
        /* Initialize variables for wash out */
        washoutG = Kf/Tf1; initWashout(washoutG,Tf1,efldi,&washout1);
        /* Initialize variables for integrator */
        initIntegrator(Te,0.0,efldi,&integrator1);
        /* Check initial output values are within Vrmax and Vrmin limits */
        if (v_init > Vrmax || v_init < Vrmin)
        {
        printf(”\nWarning: Initial value of mon6 is not within the entered limits.”);
        printf(”\n VRmax = %f, VRmin = %f, mon6 initial value = %f.”,Vrmax,Vrmin,v_init); printf(”\n Subsystem %d, Machine %s, exciter type EXDC1x.\n”, getSubsystem(),Gen); reportError(”EXDC1x”,1);
        }
        /*Initializeallmonitoringvariablesthataregoingtobereferencedinthecodesectionbeforetheyare assigned a value*/
        mon9 = v_init; mon10 = 0.0; CODE:
        double puSpeed;
        /* Include load compensation */
        if (LDComp==1)
        {
        mon1 = VC;
        }
        else
        {
        mon1 = VPU;
        }
        /* realpole #1*/
        mon2 = realPole(mon1, 1.0, 0, 0.0, 0.0,0,0,0.0, &realpole1);
        /* Summing junction */
        mon3 = Vref1 − mon2;
        /* Optionally include stabilizer input */
        if (PSS == 1)
        {
        mon3 = mon3 + VS;
        }
        mon4 = mon3 − mon10;
        /* lead−lag */
        mon5 = leadLag(mon4,1.0,0,0.0,0.0,0,0,0.0,&leadlag1);
        /* realpole #2 */
        mon6 = realPole(mon5,Ka,1,Vrmin,Vrmax,0,0,0.0,&realpole2);
        /* Summing Junction */
        mon7 = mon6 − mon9;
        /* Integrator */
        mon8 = integrator(mon7,0,0.0,0.0,0,0,0.0,&integrator1);
        /* Saturation Function */
        mon9 = satKE(mon8, &satKE1);
        /* Washout */
        mon10 = washOut(mon8,washoutG,0,0.0,0.0,0,0,0.0,&washout1);
        /* Efd */
        OUT = mon8;
        if (spdMult == 1)
        {
        puSpeed = Speed/wBase; OUT = mon8 * puSpeed;
        }
        /*check if monitoring is enabled, if so assign the output based on the dial position*/
        if (Mon ==1)
        {
        if (dial1 == 2)
        {
        internalV = mon2;
        }
        else if (dial1 == 3)
        {
        internalV = mon3;
        }
        else if (dial1 == 4)
        {
        internalV = mon4;
        }
        else if (dial1 == 5)
        {
        internalV = mon5;
        }
        else if (dial1 == 6)
        {
        internalV = mon6;
        }
        else if (dial1 == 7)
        {
        internalV = mon7;
        }
        else if (dial1 == 8)
        {
        internalV = mon8;
        }
        else if (dial1==9)
        {
        internalV = mon9;
        }
        else if (dial1==10)
        {
        internalV = mon10;
        }
        else
        {
        internalV = mon1;
        }
        }

5 数据准备和初始化


通用发电机控制模型包括初始化其内部变量和配置设定点滑块的能力。给定初始励磁电压,初始终端电压和励磁器元件的各种增益,可以计算与DC1控制器的每个块相关的初始输入和输出。励磁控制器元件的初始终端电压和增益作为参数输入到元件中。初始励磁电压由发电机模型代码计算,并可使用get_data函数访问。get_data函数定位并返回来自另一个元件的数据。在RAM部分,初始励磁电压是使用下面的代码确定的;
efldi = get_data(Gen,”Efldi”);
getdata函数需要两个参数。第一个参数是元件的名称,第二个参数是参数名。
励磁器模型所连接的发电机的名称需要作为参数名为'Gen'。
发电机模型预计算提供所需的实功率和无功功率输出所需的励磁电压。该数据被写入.map文件,并给定变量“Efldi”。要从发电机模型中提取初始励磁电压,必须将参数名称Efldi传递给get_data函数。参数名是区分大小写的。
误差计算为饱和块' v_init '的初始输出除以增益卡。
Verr= v_init/Ka;
Vref滑动条的初始值计算如下:
Vref= Vi+Verr;
Vmax= 1.2;
if (Vref > Vmax) Vmax= 1.2*(Vref);
初始值“Vref”和最大值“Vmax”用于在下一节“ADD AN INTERNAL slider”中初始化滑块。
常用的控制函数在CBuilder中作为函数调用可用。在这种情况下,使用realPole, leadLag, washOut和Integrator函数。要在CODE节中使用这些函数,必须首先在RAM节中初始化历史项。计算出来的历史项然后存储在一个结构中,以供CODE部分使用。初始化函数存储在名为“initTransferFunctions.inc”的文件中。这个include语句必须出现在RAM_FUNCTIONS部分中。可选的是,初始化函数可以直接出现在RAM_FUNCTIONS部分中,而不是包含文件中。有关传递函数初始化的完整细节,请参阅CBuilder用户手册的附录E。
RAM_FUNCTIONS:
#include "initTransferFunctions.inc"
initTransferFunctions中的函数。. inc .文件可以从RAM部分调用。
/*初始化饱和函数的变量*/
if (Ke <= 0.0)
{
v_init= initSatKE0(E1,Se1,E2,Se2,efldi,Vrmax,Cal,&satKE1);
}
else
{
v_init = initSatKE(E1,Se1,E2,Se2,efldi,Ke,Cal,&satKE1);
}
/* Initialize variables for real pole #1 */
initRealPole(1.0,Tr,Vi,Vi,&realpole1);
/* Initialize variables for lead − lag */
initLeadLag(Tb,Tc,Verr,Verr,&leadlag1);
/* Initialize variables for real pole #2 */
initRealPole(Ka,Ta,Verr,v_init,&realpole2);
/* Initialize variables for wash out */ washoutG = Kf/Tf1; initWashout(washoutG,Tf1,efldi,&washout1);
/* Initialize variables for integrator */
initIntegrator(Te,0.0,efldi,&integrator1);
例如,要初始化第一个realpole,增益、时间常数、初始输入、初始输出和realpole结构作为参数传递。realpole的初始输入和输出设置为发电机的初始p.u.电压。接下来初始化超前滞后(leadLag),传递预先计算的Verr值作为超前滞后的初始输入和输出。

6 添加内部滑块


参考框图,需要一个滑块Vref作为控制块的输入。滑块是元件的内部输入,这意味着元件上不存在物理输入连接。


图7.3:添加一个内部滑动条
当这个参数被选中时,编辑菜单出现在右边的窗口,如图7.4所示。


图7.4:滑块菜单编辑选项

      • 为滑块指定一个变量名,以便在代码部分中引用它。在本例中使用Vref1。
      • 滑块名称是必需的。这是滚动条的名称,因为它将出现在运行时。为了复制现有的通用发电机控制模型,Vref滑块位于ctl |Inputs组下,并命名为V_generator name。要将两个字符串连接在一起,可以使用strcat2函数来创建滑块名称。滑块的初始值已在RAM部分中计算并分配给变量Vref。滑块的最大值也已在RAM部分中计算并分配给变量Vmax。变量“Vref”和“Vmax”分别作为“初始值”和“最大值”输入。
      • 保存CBuilder元件。
        保存元件后,.h文件的INPUTS:部分会出现一个create_slider函数。滑块名称' Vref1 '可以在.c文件的CODE部分中使用。

7 添加realpole函数的CODE

  1. 函数realPole实现的传递函数如式7-1所示。


在代码部分,realPole函数调用如下:
/* realpole */
out=realPole(Input, Gain, Limit, minLim, maxLim,RST,RSTSIG,RVAL, &realpole1);
realPole函数需要9个参数。有关参数的完整描述,请参阅CBuilder用户手册的附录E。该函数返回realpole传递函数的输出Y(s)。

添加代码leadlag函数

  1. 函数leadLag实现的传递函数如式7-2所示。


在代码部分,leadLag函数调用如下:
/* leadLag */
out=leadLag(Input, Gain, Limit, minLim, maxLim,RST,RSTSIG,RVAL, &leadlag1);
leadLag函数需要9个参数。有关参数的完整描述,请参阅CBuilder用户手册的附录E。该函数返回leadLag传递函数的输出Y(s)。

添加Washout函数的代码

  1. 函数washOut实现了如式7-3所示的传递函数。


在代码部分,washOut函数调用如下:
/* washOut*/
out=washOut(Input, Gain, Limit, minLim, maxLim,RST,RSTSIG,RVAL, &washout1);
washOut函数需要9个参数。有关参数的完整描述,请参阅CBuilder用户手册的附录E。该函数返回washOut传递函数的输出Y(s)。

10 添加饱和函数的代码

  1. 饱和函数satKE实现了饱和曲线。


图7.5:饱和曲线
在代码部分,satKE函数调用如下:
/* saturation */
out= satke(Input,&satKE1);

11 添加代码

  • 读取电源电压并检查负载补偿。
    if (LDComp==1)
    {
    mon1 = VC;
    }
    else
    {
    mon1 = VPU
    }
  • 为第一个realpole函数添加函数调用。
    mon2 = realPole(VPU, 1.0, 0,0.0, 0.0,0, 0.0, &realpole1);
    realpole函数需要9个参数。第一个参数是输入。第一个实极块的输入是来自发电机模型的p.u.电压。这个输入是
    元件上的一个I/O点,并在.h文件中声明为VPU。第二个参数是增益。增益固定为1.0。
    第三、第四和第五个参数表示限制。limit不包括在这个块中,因此设置为0。
    第六个、第七个和第八个参数用于重置。Reset不包含在此块中,因此设置为0。
    第九个参数是realpole结构。结构体中的变量在RAM部分被初始化。
    realpole的输出被赋值为变量名' mon2 '框图。
  • 为求和结点添加代码。
    /* Summing junction */
    mon3 = Vref1 − mon2;
    /* Optionally include stabilizer input */ if (PSS == 1)
    {
    mon3 = mon3 + VS;
    }
    求和结从Vref滑块中减去realpole ' mon2 '的输出。一个可选的第三个输入可以存在于求和结点。如果元件中的参数PSS设置为YES,则可提供稳定器输入信号输入,并将其添加到上述。将求和结的输出赋给变量名mon3。
  • 添加求和结点的代码。
    Mon4 = mon3−mon10;
    冲洗块(mon10)的输出根据方框图从前一个求和结的输出中减去。
  • 为leadlag函数增加函数调用。
    mon5 = leadLag(mon4,1.0,0,0.0,0.0,0, 0.0,&leadlag1);
    leadLag函数需要9个参数。第一个参数是输入。leadLag函数的输入是前一个求和结(mon4)的输出。
    第二个参数是增益。增益固定为1.0。第三、第四和第五个参数表示限制。limit不包括在这个块中,因此设置为0。
    第六个、第七个和第八个参数用于重置。Reset不包含在这个块中,因此被设置为0。
    第九个参数是leadlag结构。结构中的变量在RAM部分中初始化。
    将前置滞后的输出赋给变量名' mon5 '框图。
  • 为第二个realpole函数添加函数调用。
    mon6 = realPole(mon5,Ka,1,Vrmin,Vrmax,0,0,0.0,&realpole2);第二个realPole函数的输入是前置滞后(mon5)的输出。第二个参数是增益。增益' Ka '作为参数输入。
    限制包含在第二个realPole中,因此第三个参数被设置为1。
    第四个和第五个参数是最小和最大限制Vrmin和Vrmax。“Vrmin”和“Vrmax”为用户自行填写的参数。
    第六个、第七个和第八个参数用于重置。Reset不包含在这个块中,因此被设置为0。
    第九个参数是realpole#2结构。结构中的变量在RAM部分中初始化。
    realpole的输出根据方框图被分配变量名mon6。
  • 添加求和结点代码。
    Mon7 = mon6−mon9;
    饱和块(mon9)的输出从realpole#2 (mon6)的输出中减去。
  • 为积分器函数添加函数调用。
    Mon8 = integrator(mon7,0,0.0,0.0,0, 0.0,&integrator1);
    integrator函数调用中的第一个参数是输入。积分器函数的输入是前一个求和结点(mon7)的输出。
    第二个、第三个和第四个参数用于极限。limit不包括在这个块中,因此设置为0。
    第5、第6和第7个参数用于重置。Reset不包含在这个块中,因此被设置为0。
    第八个参数是积分器结构。结构中的变量在RAM部分中初始化。
    将积分器的输出赋给变量名“mon8”框图。
  • 为饱和度函数增加函数调用。
    mon9 = satke(mon8,&satKE1);
    satKE函数调用中的第一个参数是输入。satKE函数的输入是前一个积分器(mon8)的输出。
    第二个参数是饱和结构。结构中的变量在RAM部分中初始化。
  • 增加washout函数的函数调用。
    mon10 = washOut(mon8,washoutG,0.0,0.0,0, 0.0,&integrator1);
    washOut函数调用中的第一个参数是输入。washOut的输入是积分器(mon8)的输出。
    第二个参数是增益。增益计算为Kf/Tf1。
    第三、第四和第五个参数表示极限。limit不包括在这个块中,因此设置为0。
    第六个、第七个和第八个参数用于重置。Reset不包含在这个块中,因此被设置为0。
    第九个参数是washout结构。该结构体中的变量在RAM段中被初始化。
    水洗的输出被赋给变量名' mon10 '框图。
  • 加乘法器,计算输出励磁电压。
    if (spdMult == 1){
    puSpeed = Speed/wBase; OUT = mon8 * puSpeed; }
    p.u速度由发电机速度除以基准值(wBase)确定。wBase是用户输入的一个参数,Speed是元件上的一个I/O点,在.h文件中声明为Speed。
    积分器(mon8)的输出乘以机器的p.u.速度以产生励磁电压(OUT)。信号OUT是元件上的一个I/O点,在.h文件中声明为OUT。

12 增加一个刻度盘来选择内部变量进行监控

  1. 内部变量显示在DC1控制器的方框图上,用mon#线标签标识。为了保持与现有发电机控件类似的操作,在运行时中一次只能监视一个内部变量。表盘的位置指示在运行时中显示的是哪个内部变量。
  • 添加内部表盘。点击添加变量按钮(见图7.6中的1),然后在“添加变量”窗口的Section下拉菜单中选择dial(见图7.6中的2)。


图7.6:添加刻度盘

      • 为刻度盘指定一个变量名,以便在代码部分中引用它。在本例中使用了dial1。
      • 使用编辑拨号窗口输入拨号的初始值。
      • 拨盘名称是必需的。这是表盘的名称,因为它将出现在运行时中。为了复制现有的通用发电机控制模型,将表盘命名为“exc_mon”,并位于Machines|generatorname组下,将两个字符串连接在一起,可以使用strcat2函数创建组名。内部监控变量的数量为10,因此表盘上可用的位置数已设置为10。表盘的初始位置设置为1。表盘值存储在一个名为mon_array的数组中。这个数组必须在.c文件的static部分中声明。dial的创建是有条件的。如果参数Mon
        (监视器内部变量)切换为Yes,则创建表盘。
      • 保存CBuilder元件。
        保存元件后,的INPUTS:部分会出现一个create_dial函数
        .h文件。拨号名称' dial1 '可以在.c文件的CODE部分中使用。

13 添加一个通用输出

  1. 必须添加输出信号以在运行时中显示被监视的内部变量。
  • 添加一个通用输出变量(Generic Output)。


图7.7:添加泛型输出

      • 为通用输出变量(Generic Output)指定一个变量名,以便在Code部分中引用它。在这个例子中使用了internalV。
      • 使用edit选项输入通用输出变量的初始值。
        在运行时中显示内部变量需要通用输出。输出名称是必需的,这是信号的名称,因为它将在运行时中出现。输入变量名称“ivName”。' ivName '是一个参数。因此,作为参数' ivName '输入的信号名称被用作输出名称。要复制现有的通用发电机控制模型,信号名称位于Machines|generatorname组下。要将两个字符串连接在一起,可以使用strcat2函数来创建Group名称。通用输出的创建是有条件的。如果参数Mon(监视器内部变量)切换为Yes,则创建输出信号。

14 添加监控CODE

  1. 名为mon#的内部变量可以在运行时中绘制。要监视的信号是基于的
    在表盘位置上。
  • 增加内部变量的监控代码。

if (Mon == 1)

{

if (dial1 == 2)

{

internalV = mon2;

}

else if (dial1 == 3)

{

internalV = mon3;

}

else if (dial1 == 4)

{

internalV = mon4;

}

else if (dial1 == 5)

{

internalV = mon5;

}

else if (dial1== 6)

{

internalV = mon6;

}

else if (dial1 == 7)

{

internalV = mon7;

}

else if (dial1 == 8)

{

internalV = mon8;

}

else if (dial1==9)

{

internalV = mon9;

}

else if (dial1==10)

{

internalV = mon10;

}

else

{

internalV = mon1;

}

}

如果元件中Mon参数被切换为Yes,则开启监控。如果拨号盘位置为2,则将通用输出信号‘exc_mon1’赋给内部变量mon2。如果表盘位置为3,则通用输出信号' exc_mon1 '被分配内部变量mon3等。这段代码一直持续,直到所有9个表盘位置都与一个输出相关联。注意:.h文件中声明的表盘变量名是dial1。运行时中的拨号名称将显示为exc_dial。类中声明的通用输出的变量名.h文件是exc_mon1。通用输出变量(Generic Output)的名称将在运行时中显示为exc_mon。

技术咨询、模型免费上机运行 请加微信号 rtdsim

  • 24
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值