三相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
评论
热门推荐
  • 相关技术文库
  • 电源
  • DC
  • AC
  • 稳压
  • 开关电源常见的基本拓扑结构

    1、基本名词     常见的基本拓扑结构     ■Buck降压     ■Boost升压     ■Buck-Boost降压-升压     ■Flyback反激     ■Forward正激     ■Two-Transistor Forward双晶体管正激     ■Push-Pull推挽     ■Half Bridge半桥     ■Full Bridge全桥     ■S

    05-10
  • LLC开关电源计算过程推导

     免费申请开发板  推荐阅读: 点击下方『面包板社区』卡片关注我们, 每天学点电子技术干货 ▲ 点击关注,后台回复"关键词",领取300 G学习资料包!  内容合作 | 视频、课程合作 | 开发板合作| 转载开白  请联系小助手微信:15889572951(微信同号) 点击阅读

    05-06
  • 移相全桥电源12种工作模态

    在早期的大功率电源(输出功率大于1KW)应用中,硬开关全桥(Full-Bridge)拓扑是应用最为广泛的一种,其特点是开关频率固定,开关管承受的电压与电流应力小,便于控制,特别是适合于低压大电流,以及输出电压与电流变化较大的场合。但受制于开关器件的损耗,无

    05-07
  • 大牛总结:六种DC/DC变换电路分析比较

    基本原理 直流-直流降压变换器(BUCK变换器) 直流-直流升压变换器(BOOST变换器) 直流降压升压变换器(BUCK-BOOST变换器) 直流升压降压变换器(CUK变换器) 两象限/四象限直流-直流变换器 单端正激变换器 单端反激变换器 *本文系网络转载,版权归原作者所有,如有

    04-29
  • 肖特基二极管有什么特别之处?

    注| 文末留言有福利 提到低功耗、大电流、超高速半导体器件,很多工程师同学肯定能首先想到肖特基二极管(SBD)。 但是你真的会用肖特基二极管吗?和其他的二极管比起来,肖特基二极管又有什么特别之处呢?下面一起来 划重点 吧! 0 1 肖特基二极管的关键参数

    04-27
  • 分析实例:了解DC/DC变换器一些常见的问题

    先介绍几个应用实例从这些应用实例中,了解如何分析DC/DC变换器设计中的问题及解决方法,从常见的buck电路,在平时设计和调试过程中,从DCDC变换器性能,功能设置,控制环设计,板子布局和测试技巧,通过这些分析实例能了解DCDC电路中在试机阶段快速解决掉一

    04-26
  • 图解BUCK电路及PCB布局

    Buck架构: 当开关闭合的时候: 当开关断开的时候: 根据伏秒平衡定理可得: (Vin-Vout)*DT=Vout(1-D)T===>Vin/Vout=D<1 在实际DCDC应用中: 当Q1闭合的时候,在图1-a中,红线示出了当开关元件Q1导通时转换器中的主电流流动。CBYPASS是高频的去耦电容器,CI

    04-25
  • 开关电源公式与对应电路

    1 Buck 变换器的功率器件设计公式 (1):Buck 变换器的电路图: (2):Buck 变换器的主要稳态规格: (3):功率器件的稳态应力: -- 有源开关 S: -- 无源开关 D: 上述公式是稳态工作时,功率器件上的电压、电流应力。选择功率器件时,其电压耐量可放一个

    04-23
  • 为什么PWM驱动芯片用图腾柱?

    推挽电路的应用非常广泛,比如单片机的推挽模式输出,PWM控制器输出,桥式驱动电路等。推挽的英文单词:Push-Pull,顾名思义就是推-拉的意思。所以推挽电路又叫推拉式电路。 图1:锯木头 推挽电路有很多种,根据用法的不同有所差异,但其本质都是功率放大,增

    04-23
  • 开关电源的输入滤波器(共模、差模)

    开关电源的输入滤波器 开关电源的输入滤波器是针对共模噪声和差模噪声,分别采用适合不同噪声特性的滤波器。 差模滤波器 共模滤波器采用电容器、电感、铁氧体磁珠和电阻等。图例中是使用了LC的π型滤波器。各部件对噪声具有如下作用: 电容器:将噪声电流旁路

    04-21
  • 入门级电源工程师常遇到的问题

    先上图 一些入门级的电源工程师常遇到这样一个问题,在电路图中的Vcc接芯片的地方加入了一个12V左右稳压管。目的是为了保证芯片的电压上限,意图很明确,稳压管能够保护芯片不会因为电压过高问题而烧毁。看上去没啥毛病,但实际上很危险。 我们一起来初步分析

    04-19
  • 电源控制环路的设计计算

    引言 作为工程师,每天接触的是电源的设计工程师,发现不管是电源的老手,高手,新手,几乎对控制环路的设计一筹莫展,基本上靠实验.靠实验当然是可以的,但出问题时往往无从下手,在这里我想以反激电源为例子(在所有拓扑中环路是最难的,由于RHZ 的存在),大概说一下怎

    04-16
下载排行榜
更多
广告
X
广告