• 回复
  • 收藏
  • 点赞
  • 分享
  • 发新帖

(PSIM仿真)教你C-Block模块巧用结构体变量

我们在用C-Block进行数字电源编程的时候,最常用到的是PI控制算法,如下一个常见的电压外环PI代码:

/**********************************************************************************/

//INV电压环参数定义

double Inv_U_PID;

const double Inv_U_K1=0.205;

const double Inv_U_K2=0.2;

double Inv_U_Error_0=0;

double Inv_U_Error_1=0;

//INV电流环参数

Inv_U_Error_1 = Inv_U_Error_0;           //偏差计算(比例) 

Inv_U_Error_0 =U_bus_avg-U_bus_set;                        //偏差计算(积分)

Inv_U_PID+= Inv_U_K1 *  Inv_U_Error_0 -  Inv_U_K2 *  Inv_U_Error_1 ;                              

           //PID计算式,更改系数以获得理想的输出

if( Inv_U_PID<-40)         //限制电压环输出     

  Inv_U_PID=-40;

if( Inv_U_PID>40)    

        Inv_U_PID=40;

/**********************************************************************************/

PI算法的格式都是一样的,中间会涉及多个中间变量,如果我们的系统比较复杂,涉及多个PI环路,那这样我们的变量定义PI算法就会非常冗余,代码的可移植性就比较差;

比如下面这个三相四桥臂正负序闭环控制系统:

正序QD轴外环电压内环电流环和负序QD轴外环电压内环电流环,总共有8个PI控制环路,如果直接定义变量,以及各个环路的PI代码,这样代码量就非常大,而且相当冗余;

怎样才能将代码简洁化,以及可移植性:我们可以用C语言的结构体去定义PI中间参数变量;以及把PI控制算法写成一个函数,单要调用PI算法时,就通过结构体变量调用PI算法函数,这样就可以避免同样结构的代码结构重复性编写;

//------------------->PID.H<---------------------//
typedef struct       //定义PI变量结构体
{
double   Tag;
double   Current;
double   Error_0;
double   Error_1;
double   Kp;
double   Ki;
double   Output;
double   OutputMaxLimit;
double   OutputMinLimit;
}   stNamePID;
void pid_set_tag(stNamePID* pPid, double Tag)
{
pPid->Tag=Tag;
}
void pid_set_Kp(stNamePID* pPid, double Kp)
{
pPid->Kp=Kp;
}
void pid_set_Ki(stNamePID* pPid, double Ki)
{
pPid->Ki=Ki;
}
void pid_set_OutputLimit(stNamePID* pPid, double   OutputMaxLimit, double   OutputMinLimit)
{
pPid->OutputMaxLimit =OutputMaxLimit;
pPid->OutputMinLimit  =OutputMinLimit;
}
double pi_calc(stNamePID* pPid, double Current)
{
pPid->Current=Current;
pPid->Error_1=pPid->Error_0;
pPid->Error_0=pPid->Tag-pPid->Current;
pPid->Output+=(pPid->Kp+ pPid->Ki)*pPid->Error_0 - pPid->Kp*pPid->Error_1;
if((pPid->Output)>(pPid->OutputMaxLimit))
  pPid->Output = pPid->OutputMaxLimit;
if((pPid->Output)<(pPid->OutputMinLimit))
 pPid->Output = pPid->OutputMinLimit;
return   pPid->Output;
}

/----------------------------------------------------------------------------------/

比如我们要用到电压外环,电流内环控制架构的时候;我们只需要定义下面结构体变量:

/---------------------------------结构体变量定义--------------------------------------------/

static  stNamePID  InvVoltPid={0}; //电压环PI结构体

double VpidCalTemp=0;

static stNamePID  InvCurrPid={0}; //电流环PI结构体

double pidCalTemp=0;

/----------------------------------------------------------------------------------/

//**************电压外环*************//

 Inv_V_ref=U_out_cmd*cos(angle);

 pid_set_tag(&InvVoltPid,Inv_V_ref); 

pid_set_Kp(&InvVoltPid, 0.02); 

pid_set_Ki(&InvVoltPid, 0.01); 

pid_set_OutputLimit(&InvVoltPid,Iout_max,-Iout_max); 

VpidCalTemp=pi_calc(&InvVoltPid, U_out); 

//**************电流内环**************//

 Inv_I_ref=VpidCalTemp ;     

 pid_set_tag(&InvCurrPid, Inv_I_ref); 

pid_set_Kp(&InvCurrPid, 0.05); 

pid_set_Ki(&InvCurrPid, 0.005); 

pid_set_OutputLimit(&InvCurrPid,100,-100); 

pidCalTemp=pi_calc(&InvCurrPid, I_out_avg);

总结:在编程中学会一些小技巧,我们的代码编程就更加简洁,增强软件可移植性和可读性;

全部回复(6)
正序查看
倒序查看
yujunice
LV.5
2
2021-09-16 22:49

很不错的PI控制算法资料,收藏学习了!

0
回复
iszjt
LV.5
3
2021-09-27 11:08

C block编程就是通过ACR的输出信号来控制四个开关管导通关断。 要实现四象限运行.

0
回复
ruohan
LV.9
4
2021-11-08 11:16
@iszjt
Cblock编程就是通过ACR的输出信号来控制四个开关管导通关断。要实现四象限运行.

pPid->Output+=(pPid->Kp+ pPid->Ki)*pPid->Error_0 - pPid->Kp*pPid->Error_1;

这个PI调节是(Kp+Ki)*Error0  -  Kp*Error1吗

0
回复
ruohan
LV.9
5
2021-11-08 11:40

电流环里面Inv_I_ref=VpidCalTemp ;     ,怎么把PID的量付给电流设定值啊,

后边pidCalTemp=pi_calc(&InvCurrPid, I_out_avg);

这样可以吗,

0
回复
Richie_Li
LV.3
6
2021-11-09 08:29
@ruohan
电流环里面Inv_I_ref=VpidCalTemp;   ,怎么把PID的量付给电流设定值啊,后边pidCalTemp=pi_calc(&InvCurrPid,I_out_avg);这样可以吗,

里面有个 pid_set_tag()函数,用来给定设定值的

0
回复
Richie_Li
LV.3
7
2021-11-09 08:29
@ruohan
pPid->Output+=(pPid->Kp+pPid->Ki)*pPid->Error_0-pPid->Kp*pPid->Error_1;这个PI调节是(Kp+Ki)*Error0 - Kp*Error1吗

正确来说是这样的:

pPid->Output=pPid->Output+(pPid->Kp+ pPid->Ki)*pPid->Error_0 - pPid->Kp*pPid->Error_1;

0
回复