用SVPWM控制的三相PWM整流器仿真

好像PWM整流器又回到大家的视线了,OBC用三相PWM整流拓扑主要原因是可以双向变换,后面DC-DC再用三相CLLC就能完美配合。

以上是我开始接触这一块的背景,然后花了一些时间来学习PWM整流器的一些基础控制。

主要参考文献:张兴教授的 《PWM整流器及其控制 第二版》。

仿真环境:Plecs 4.1.2

目前PWM整流器主要的控制方法是在dq同步旋转坐标系上控制,电压外环的输出是输入电流的d轴的给定。通过前馈解耦的方法来分离dq轴的耦合量,得到控制的Vd, Vq后,再通过坐标系变换将dq变换为abc,可见图一所示。

(图一 PWM整流器的控制框架)

然后根据PWM调制方法,用SVPWM或者用三次谐波叠加的SPWM,可见图二,套路都是差不多的。

(图二 叠加三次谐波的SPWM)

我把坐标变换和控制做成了代码的方式,主要是方便移植到DSP,当然这得感谢Plecs仿真软件提供了非常完善的C代码调试环境。本文这些发出来的只是一些前期工作,后续还有很多有待完善的地方,还请各位大佬赐教指点。比如还可以优化锁相环,简化svpwm发波程序。目前只是实现了功能,做的非常粗糙。后续还要做出硬件来根据实际情况来调整代码,调试的内容将在后续的文章中更新。

               

下面是plecs环境中的仿真模型先是功率部分:

(图三 主功率 

采样部分:

(图四 采样信号) 

控制部分用C代码实现,所以比较简单。为了便于调试,我输出了三个PI环的输入和输出,控制dq和电角度。

(图五 控制部分 

仿真时间10秒,控制环计算周期100KHz,开关频率100KHz,功率32KW,电感量1mH,ADC采样频率100KHz,输出电压800V。

1,输出电压和输出电解电容纹波电流:

2,输入电流和电压:(备注:前面几百毫秒没发波)另外目前的锁相环还未完全调试好,在电网电压输入不平衡时,输入电流波形会变得很烂,这个问题在前言中也提到了,我后续会继续优化锁相环代码或者引入正负序电流的分别控制,提升输入不平衡时的电流thd。

3,稳态输入电流:THD还可以。

下面是前馈解耦合的三个PI环:

4,电压外环:主要用于控制输出电压稳定,另外该环的输出值决定了网侧输入电流的峰值大小。所以该环的输出一定要根据实际功率进行限制,否则等着吃炸鸡。

5,D轴电流内环:该控制环的给定就是电压外环的输出,主要控制网侧输入电流值。

6,Q轴电流内环:为了实现PFC,通常直接把给控制的给定写0。

7,经过前馈解耦后输出到PWM模块的控制DQ:

8,SPWM输出的占空比信号:

仿真代码:

code declarations

#include "math.h"

//

// PI Coefficient DEFINE

//

#define ssrf_ts             1e-5

#define ssrf_kp             1

#define sser_ki             0.002

#define sser_kd             0

#define ssrf_up_limt        10

#define ssrf_low_limt      -10



#define sqrt3      1.732

#define sqrt3div2      0.866

#define value_2pi 6.2831852

#define value_pi   3.1415926

#define value_pi6    0.3183098



#define PI 3.1415926

#define WL 2*PI*50*1e-3



#define VLOOP_TS 1e-5

#define VLOOP_KP 5

#define VLOOP_KI 20

#define VLOOP_KD        0

#define Vloop_UP   70

#define Vloop_LOW 0



#define DLOOP_TS 1e-5

#define DLOOP_KP 10

#define DLOOP_KI 25

#define DLOOP_KD        0

#define Dloop_UP   50

#define Dloop_LOW   0



#define QLOOP_TS 1e-5

#define QLOOP_KP 10

#define QLOOP_KI 25

#define QLOOP_KD        0

#define Qloop_UP     50

#define Qloop_LOW   0



//

// data struct define

//

typedef struct PI_CTRL_DATA_TAG {

double  ts;

double  kp;

double  ki;

double  kd;

double  up_limt;

double  low_limt;



double a0;

double a1;

double a2;



double  out;

double  out_1;



double  error;

double  error_1;

double  error_2;

} PI_CTRL_DATA_DEF;



typedef struct integreator_tag{

double ts;

double ki;

double out_1;

double out;

} INTER_DEF;



typedef struct ABC_ab_dq_TAG {

double A;

double B;

double C;



double alpha;

double beta;



double d;

double q;

}ABC_ab_dq_DEF;



typedef struct sinwt_coswt_tag{

double sinwt;

double coswt;

}sinwt_coswt_DEF;



typedef struct dsrf_spll_tag{

float theta;

float vd_p;

float vq_p;

float vd_n;

float vq_n;

} DSRF_SPLL_DEF;



//

// FUNCTION DES

//

double inter(INTER_DEF *inter, double input)

{

inter->out = inter->ki * inter->ts * input + inter->out_1;

inter->out_1 = inter->out;

return (inter->out);

}



double pi_func(PI_CTRL_DATA_DEF *pi, double give, double sen)

{

pi->error = give - sen;



pi->a0 = pi->kp + pi->ki * pi->ts + pi->kd / pi->ts;

pi->a1 = pi->kp + 2 * pi->kd / pi->ts;

pi->a2 = pi->kd / pi->ts;



pi->out = pi->out_1 + pi->a0 * pi->error - pi->a1 * pi->error_1 + pi->a2 * pi->error_2;



// Limt

if(pi->out > pi->up_limt) pi->out = pi->up_limt;



if(pi->out < pi->low_limt) pi->out = pi->low_limt;



pi->out_1 = pi->out;



pi->error_1 = pi->error;

pi->error_2 = pi->error_1;



return(pi->out);

}





// clark tran

void abc_to_alpha_beta_clark_tran(ABC_ab_dq_DEF *ac_data)

{

ac_data->alpha = (0.6666) * (ac_data->A - 0.5 * ac_data->B - 0.5 * ac_data->C);

ac_data->beta =  (0.6666) * (sqrt3div2 * ac_data->B - sqrt3div2 * ac_data->C);

}



// DQ

void alpha_beta_to_dq_tran(ABC_ab_dq_DEF *ac_data, sinwt_coswt_DEF *wt)

{

ac_data->d = ac_data->alpha * wt->coswt + ac_data->beta * wt->sinwt;

ac_data->q = -ac_data->alpha * wt->sinwt + ac_data->beta * wt->coswt;

}



// Inverse DQ transformation

void inverse_dq_to_alpha_beta_tran(ABC_ab_dq_DEF *ac_data, sinwt_coswt_DEF *wt)

{

ac_data->alpha = wt->coswt * ac_data->d - wt->sinwt * ac_data->q;



ac_data->beta = wt->sinwt * ac_data->d + wt->coswt * ac_data->q;

}



// Inverse clarke transformation

void inverse_clark_alpha_beta_to_abc_tran(ABC_ab_dq_DEF *ac_data)

{

ac_data->A = ac_data->beta;

ac_data->B = ac_data->beta * (-0.5) + ac_data->alpha * 0.5 * sqrt3;

ac_data->C = ac_data->beta * (-0.5) - ac_data->alpha * 0.5 * sqrt3;

}





// INIT PID coefficient

PI_CTRL_DATA_DEF ssrf_pi = {

ssrf_ts,

ssrf_kp,

sser_ki,

sser_kd,

ssrf_up_limt,

ssrf_low_limt,

0, 0, 0,

0, 0,

0, 0, 0

};



PI_CTRL_DATA_DEF vloop_pi = {

VLOOP_TS,

VLOOP_KP,

VLOOP_KI,

VLOOP_KD,

Vloop_UP,

Vloop_LOW,

0, 0, 0,

0, 0,

0, 0, 0

};



PI_CTRL_DATA_DEF d_ctrl_pi = {

DLOOP_TS,

DLOOP_KP,

DLOOP_KI,

DLOOP_KD,

Dloop_UP,

Dloop_LOW,

0, 0, 0,

0, 0,

0, 0, 0

};



PI_CTRL_DATA_DEF q_ctrl_pi = {

QLOOP_TS,

QLOOP_KP,

QLOOP_KI,

QLOOP_KD,

Qloop_UP,

Qloop_LOW,

0, 0, 0,

0, 0,

0, 0, 0

};



INTER_DEF inter_spll = {VLOOP_TS, 1, 0, 0};

ABC_ab_dq_DEF Vac = {0, 0, 0, 0, 0, 0, 0};

ABC_ab_dq_DEF Iac = {0, 0, 0, 0, 0, 0, 0};

ABC_ab_dq_DEF ctrl_ac = {0, 0, 0, 0, 0, 0, 0};

sinwt_coswt_DEF wt = {0, 0};



// DSRF SPLL

DSRF_SPLL_DEF dsrf_spll_abc = {0, 0, 0, 0};



void dsrf_spll_func(float va, float vb, float vc, DSRF_SPLL_DEF *drsf)

{

static float vd_p_ave = 0, vq_p_ave = 0, vd_n_ave = 0, vq_n_ave = 0;

static float theta = 0;





float sintheta = sin(theta);

float costheta = cos(theta);

float sintheta2 = sin(theta*2.0);

float costheta2 = cos(theta*2.0);



float ualha = 0.6666 * (va - 0.5 * vb - 0.5 * vc);

float ubeta = 0.6666 * (0.866 * vb - 0.866 * vc);



float vd_p = ualha*costheta + ubeta*sintheta;

float vq_p =-ualha*sintheta + ubeta*costheta;

float vd_n = ualha*costheta - ubeta*sintheta;

float vq_n = ualha*sintheta + ubeta*costheta;



float vd_p_o = (vd_p-vd_n_ave*costheta2)-(vq_n_ave*sintheta2);

float vq_p_o = (vq_p+vd_n_ave*sintheta2)-(vq_n_ave*costheta2);

float vd_n_o = (vd_n-vd_p_ave*costheta2)+(vq_p_ave*sintheta2);

float vq_n_o = (vq_n-vd_p_ave*sintheta2)-(vq_p_ave*costheta2);

//

vd_p_ave = vd_p_ave*0.99f + vd_p_o*0.01f;

vq_p_ave = vq_p_ave*0.99f + vq_p_o*0.01f;

vd_n_ave = vd_n_ave*0.99f + vd_n_o*0.01f;

vq_n_ave = vq_n_ave*0.99f + vq_n_o*0.01f;



float dds_kp = 1.0f, dds_ki = 0.002f, dds_vqi = 0;



float dds_vqp = -vq_p_o * dds_kp; // err = 0-vq_p_o

dds_vqi += -vq_p_o * dds_ki;



float dds_vqo = dds_vqp + dds_vqi;

theta -= dds_vqo * value_2pi * 0.0001f; // (45-65)*(1/10khz)*2pi



if(theta > value_2pi){theta -= value_2pi;}

if(theta < 0){theta += value_2pi;}



float    utheta = theta;

//   float ud, uq;

// float    itheta = theta + value_pi - value_pi6; // vab -> va: vab+pi=vba,vba-pi/6=va

// ud = ud * 0.98f + vd_p * 0.02f;

// uq = uq * 0.98f + vq_p * 0.02f;



//updata

drsf->theta = utheta;

drsf->vd_p = vd_p_ave;

drsf->vq_p = vq_p_ave;

drsf->vd_n = vd_n_ave;

drsf->vq_n = vq_n_ave;

}





//

// output function code//

#include "math.h"



// Define Input data



Vac.A = InputSignal(0, 0);

Vac.B = InputSignal(0, 1);

Vac.C = InputSignal(0, 2);



Iac.A = InputSignal(0, 3);

Iac.B = InputSignal(0, 4);

Iac.C = InputSignal(0, 5);



double vdc_sen = InputSignal(0, 6);

double vdc_set = InputSignal(0, 7);

double tsw = InputSignal(0, 8);



// Run Control function



// Run ssrf pll

dsrf_spll_func(Vac.A, Vac.B, Vac.C, &dsrf_spll_abc);

double theta = dsrf_spll_abc.theta;

OutputSignal(0, 0) = theta;



wt.sinwt = sin(theta);

wt.coswt = cos(theta);



// abc_to_alpha_beta_clark_tran

abc_to_alpha_beta_clark_tran(&Vac);

abc_to_alpha_beta_clark_tran(&Iac);



// alpha_beta_to_dq_tran

//    alpha_beta_to_dq_tran(&Vac, &wt);

Vac.d = dsrf_spll_abc.vd_p;

Vac.q = dsrf_spll_abc.vq_p;

alpha_beta_to_dq_tran(&Iac, &wt);



//

// Current inner loop D Q Control

//

double vloop_outer = pi_func(&vloop_pi, vdc_set, vdc_sen);



double d_ctrl_feed = pi_func(&d_ctrl_pi, vloop_outer, Iac.d);



ctrl_ac.d = Vac.d - d_ctrl_feed - Iac.q * WL;



// Limt the control d and q output



if(ctrl_ac.d > 400) { ctrl_ac.d = 400;}



double q_ctrl_feed = pi_func(&q_ctrl_pi, 0, Iac.q);



ctrl_ac.q = Vac.q  + Iac.d * WL - q_ctrl_feed;



//    if(ctrl_ac.q > 30) { ctrl_ac.q = 30;}

//    if(ctrl_ac.q < -30) { ctrl_ac.q = -30;}



// inverse_dq_tran

inverse_dq_to_alpha_beta_tran(&ctrl_ac, &wt);



//inverse_clark_tran

inverse_clark_alpha_beta_to_abc_tran(&ctrl_ac);



//

//svpwm

//

int A_sector = 0;

int B_sector = 0;

int C_sector = 0;



if (ctrl_ac.A > 0)

{

A_sector = 1;

}

else

{

A_sector = 0;

}



if (ctrl_ac.B > 0)

{

B_sector =  2;

}

else

{

B_sector = 0;

}



if (ctrl_ac.C > 0)

{

C_sector =  4;

}

else

{

C_sector = 0;

}



int sector = A_sector + B_sector + C_sector;



//

// VA VB VC TIMER

// Inverse clarke transformation

//

float ta = tsw * (1/vdc_sen) * ctrl_ac.beta * 1.732 ;

float tb = (ctrl_ac.alpha * 1.5 + ctrl_ac.beta * 0.866) * tsw * (1/vdc_sen);

float tc = (ctrl_ac.beta * 0.866 - 1.5 * ctrl_ac.alpha) * tsw * (1/vdc_sen);



float T1 = 0;

float T2 = 0;

switch(sector)

{

case 1:

{

T1 = tc;

T2 = tb;

}

break;



case 2:

{

T1 = tb;

T2 = -ta;

}

break;



case 3:

{

T1 = -tc;

T2 = ta;

}

break;



case 4:

{

T1 = -ta;

T2 = tc;

}

break;



case 5:

{

T1 = ta;

T2 = -tb;

}

break;



case 6:

{

T1 = -tb;

T2 = -tc;

}

break;



}



float sw_a_on = 0;

float sw_b_on = 0;

float sw_c_on = 0;



float X = (tsw - T1 - T2) * 0.25 ;

float Y = T1 * 0.5 + X;

float Z = T2 * 0.5 + Y;



switch(sector)

{

case 1:

{

sw_a_on = Y;

sw_b_on = X;

sw_c_on = Z;

}

break;



case 2:

{

sw_a_on = X;

sw_b_on = Z;

sw_c_on = Y;

}

break;



case 3:

{

sw_a_on = X;

sw_b_on = Y;

sw_c_on = Z;

}

break;



case 4:

{

sw_a_on = Z;

sw_b_on = Y;

sw_c_on = X;

}

break;



case 5:

{

sw_a_on = Z;

sw_b_on = X;

sw_c_on = Y;

}

break;



case 6:

{

sw_a_on = Y;

sw_b_on = Z;

sw_c_on = X;

}

break;

}



//

// output

//

OutputSignal(0, 1) = ctrl_ac.d;

OutputSignal(0, 2) = ctrl_ac.q;



OutputSignal(0, 3) = wt.sinwt;

OutputSignal(0, 4) = wt.coswt;



OutputSignal(0, 5) = sw_a_on;

OutputSignal(0, 6) = sw_b_on;

OutputSignal(0, 7) = sw_c_on;





//

// PI DEBUG

//

OutputSignal(0, 8) = vdc_set;

OutputSignal(0, 9) = vdc_sen;

OutputSignal(0, 10) = vloop_outer;



OutputSignal(0, 11) = vloop_outer;

OutputSignal(0, 12) = Iac.d;

OutputSignal(0, 13) = d_ctrl_feed;



OutputSignal(0, 14) = 0;

OutputSignal(0, 15) = Iac.q;

OutputSignal(0, 16) = q_ctrl_feed;



OutputSignal(0, 17) = Vac.d;

OutputSignal(0, 18) = Vac.q;
声明:本内容为作者独立观点,不代表电子星球立场。未经允许不得转载。授权事宜与稿件投诉,请联系:editor@netbroad.com
觉得内容不错的朋友,别忘了一键三连哦!
赞 2
收藏 5
关注 395
成为作者 赚取收益
全部留言
0/200
  • 空军通信兵 10-13 18:11
    先收藏
    回复