三相PWM整流拓扑(仿真代码)
2021-08-09
 好像PWM整流器又回到大家的视线了,OBC用三相PWM整流拓扑主要原因是可以双向变换,后面DCDC再用三相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输出的占空比信号:


备注: 

1,回复:”PWM整流器“,我将送出该仿真模型,开袋即食,下载即玩。

2,仿真代码:

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;


本文源自微信公众号:开关电源仿真与实用设计,不代表用户或本站观点,如有侵权,请联系nick.zong@aspencore.com 删除!

声明: 本文转载自其它媒体或授权刊载,目的在于信息传递,并不代表本站赞同其观点和对其真实性负责,如有新闻稿件和图片作品的内容、版权以及其它问题的,请联系我们及时删除。(联系我们,邮箱:evan.li@aspencore.com )
0
评论
  • 【7.24 深圳】2025国际AI+IoT生态发展大会/2025全球 MCU及嵌入式技术论坛


  • 相关技术文库
  • 电源
  • DC
  • AC
  • 稳压
  • 什么是整流器?整流器的工作原理是什么?

    整流器是常用设备之一,通过整流器,我们能够对电流类型加以转换。为增进大家对整流器的认识,本文将对整流器、整流器的工作原理予以介绍。如果你对整流器或者整流器的相关知识具有兴趣,不妨和小编继续往下阅读哦...

    昨天
  • 干式变压器有何优缺点?干式变压器的应用+保护方式介绍

    干式变压器具备很强的应用意义,为增进大家对干式变压器的认识,本文将基于三点介绍干式变压器:1.干式变压器的优缺点,2.干式变压器的应用领域,3.干式变压器的保护方式。如果你对干式变压器具有兴趣,不妨继续往...

    昨天
  • 你了解干式变压器的冷却结构吗?干式变压器如何冷却?

    干式变压器在工业中具有很多的应用场景,对于干式变压器,我们有必要对它有所认识。为增进大家对干式变压器的了解程度,本文将基于两点介绍干式变压器:1.干式变压器的冷却结构,2.干式变压器的冷却方式介绍。如果...

    昨天
  • 干式变压器正常温度是多少?干式变压器有何安装规范?

    干式变压器是变压器类型之一,任何一款器件都有它的适用范围,干式变压器也不例外。为保证干式变压器的正常适用,本文将对干式变压器的正常温度予以介绍。此外,本文还将介绍干式变压器的安装规范。如果你对干式变...

    昨天
  • 为何要发展电源管理芯片?如何选择电源管理芯片?

    芯片的重要性不言而喻,我国目前在芯片方面的成就还未达到世界巅峰。但是,小编相信中国的芯片水平将会领先世界。为增进大家对芯片的了解,本文将对电源管理芯片予以解读。本文中,你将对电源管理芯片的发展必要性...

    前天
  • 全方位了解存储,你知道的存储介质有哪些?

    存储是非常重要的技术,基于存储技术,我们可以将数据存储在存储设备上。那么对于存储设备而言,有哪些因素对它而言是十分重要的呢?其中一个,便是存储介质。为增进大家对存储的认识,本文将对存储介质予以介绍。如...

    07-07
  • 了解过分布式光伏逆变器吗?不同光伏逆变器有何优缺点?

    逆变器,已是一个老生常谈的话题。因此,就机械等相关专业的朋友,对于逆变器通常都较为了解。为增进大家对逆变器的认识,本文将对光伏逆变器、组串式逆变器、分布式逆变器等内容予以介绍。如果你对逆变器相关内容...

    07-07
  • 一步步了解检测技术,什么是声发射检测?

    检测的重要性不言而喻,我们通过检测,可以对很多电子器件进行检测,以判断电子器件是否存在一些缺陷。为增进大家对检测的认识,本文将对声发射检测技术予以介绍。如果你对检测技术具有兴趣,不妨同小编一起来阅读...

    07-07
  • 变压器规格型号容量

    一般常用变压器的型号可归纳如下 : 1、按相数分: (1)单相变压器:用于单相负荷和三相变压器组。 (2)三相变压器:用于三相系统的升、降电压。 2、按冷却方式分: (1)干式变压器:依靠空气对流进行自然冷却或增加风机冷却...

    07-04
  • 干式变压器有哪些分类?干式变压器性能特点介绍

    干式变压器是变压器类型之一,但是,很多朋友对干式变压器却并非十分了解。为增进大家对干式变压器的认识,本文将对干式变压器的分类、干式变压器的性能特点、干式变压器的应用领域予以介绍。如果你对干式变压器具...

    07-03
  • UPS电源内部结构解析,大佬带你看UPS电源防雷误区

    UPS电源,也就是我们常说的不间断电源。通常情况下,UPS电源都带有保护作用。为增加大家对UPS电源的认识,本文将对UPS电源的内部结构以及UPS电源的防雷误区予以介绍。如果你对UPS电源具有兴趣,不妨和小编一同往下...

    07-03
下载排行榜
更多
评测报告
更多
广告