在设计出pi调节器后,需要对其离散化,之后存在浮点数,对于整形处理的cpu(如stm32f103)计算压力相当大,本文通过实例讲解,定标处理浮点运算,提高运算的速度。
1.问题的起因
电源开发时,一般会在一个开关周期内采样一次,闭环计算一次。
在一次开发中,选择开关频率是100k,中断时间是10us。那么所有的闭环计算需要在10us中计算完成,否则会引起中断竞争,导致cpu一直在执行中断,无法执行其他的程序,
而设计出闭环调节器后,调节器中难免会出现浮点计算,而对于目前像stm32f103来说,浮点计算压力相当大,实际测试中,也发现要闭环计算PI调节器,花费时间较长,不能在10us内计算完成。
后采用定标后,依旧超过10us,所以只能改成50khz,一个周期是20us,实际测试电压外环和电流内环总共耗时13us左右。
2.离散化
通过matlab计算出电压环的pi参数如下。
选定采样频率,采用maple使用双线性方式离散化后,如下图
T是采样频率,与开关频率一致,如果使用stm32 使用中央对齐模式,在计数器的峰值采样,可近似得到电流的平均值,本文中是锯齿波,在三角载波的顶点采样,在实际中是电流的谷点。
可得
分子上的小数需要保留一定的位数,才能保证离散化后和连续的相近性,在实际中我们尽可能保留多的小数点。
对其进行Q20定标,也就是浮点数乘以2^20.可得蓝色公式的第三行。
3.程序实例
编写离散化后的PI如下:
uv_k=(Vref-ADC_Value[1] ); //adc 是12位,
uv_k = (uv_k<<20)/113;
//0.8427429893*z-0.8240194818
//定标Q20
Yv_k = 883680*uv_k-864047*uv_k_1+Yv_k_1; //Y_k_1,有点积分的意思。//14.72 us
uv_k_1=uv_k; //当前输入赋值给前一拍,下一拍计算使用
if(Yv_k>3738339534438400) //6A 数字量是 (1700*2)的Q40定标 最大电流限制在6A中。
Yv_k= 3738339534438400;
if(Yv_k<0)
Yv_k= 0;
Yv_k_1=Yv_k;//当前输出赋值给前一拍,下一拍计算使用
ui_k=((Yv_k_1>>20)-ADC_Value[2]<<20 ); //3.78us
ui_k = (ui_k)/633; //633换算成1A
Yi_k = 28113550*ui_k-27267416*ui_k_1+Yi_k_1; //Y_k_1,有点积分的意思。//14.72 us
ui_k_1=ui_k;
if(Yi_k>985162418500000) // 500 然后Q40定标
Yi_k= 985162418500000;
if(Yi_k<10)
Yi_k= 10;
Yi_k_1=Yi_k;
tempa = Yi_k>>40;
if(tempa>896) //峰值的百分数限幅
tempa= 896;
if(tempa<10)
tempa= 10;
TIM1->CCR2 = tempa;
程序中,Vref是电压给定,ADC_Value[1]是输出电压的采样值,uv_k是当前的输入量。uv_k_1是前一排的输入量。Yv_k是当前的输出量,Yv_k_1是前一拍的输出量。
uv_k = (uv_k<<20)/113;此处是对电压的采样值进行了Q20的定标,而/133是将电压装换为真实的电压值,数字量133是电压1V,因为建模的时候,反馈是按照单位反馈。
此处uv_k的定标是为了保留电压的小数点,防止丢失电压的精度。
Yv_k = 883680*uv_k-864047*uv_k_1+Yv_k_1;此处就是递推公式的实现,离散pi的写法。
公式是,
按照这样来说,离散化后的数学公式是
而实际程序中,我们为了书写方便, Yv_k=,Yv_k_1=
这样就得到了程序写法:Yv_k = 883680*uv_k-864047*uv_k_1+Yv_k_1;此处的Yv_k_1类似积分的作用,如误差一直存在,则Yv_k_1一直朝着一个方向跑。
uv_k_1=uv_k; 是当前的输入送给前一拍,下一次计算使用。
if(Yv_k>6597069766656) //6A的Q40定标 最大电流限制在6A中。
Yv_k= 6597069766656;
此处是对电压环的输出限幅,防止积分过饱和。
此处变为Q40,是因为adc采集的量,和pi的定标都是Q20 二者相加是Q40。
ui_k=((Yv_k_1>>20)-ADC_Value[2]<<20 ); //3.78us 此处是电压环的输出,经过退标后,还原为Q20,和电流环的反馈做差,送入电流环。