本帖最后由 shipeng 于 2020-7-22 11:04 编辑
使用PID控温差不多有4年了,有一个问题一直困扰我至今。曾经以为这个问题是个悖论只能寻找此消彼长的微妙平衡再无任何解决方案,但其实我错了就在前不久一个灵光乍现的清晨我在睡梦中居然找到了答案。具体问题是这样的:“有一个可调温控温装置(其实是热风拆焊台)调温范围:100~500摄氏度,要求控温精度±1℃以内。”
根据以上问题描述,由于控制温度高低的唯一办法是控制单位时间T内的平均加热功率P,假定供电电压不变加热占空比D的大小决定恒温的温度值。这就可以得到温度和加热占空比D呈一一对应关系。100~500度就需要至少400分之一的功率控制精度,但实际上由于市电的频率只有50Hz还要做到过零开关,最小功率控制精度是半个市电周期th=10ms,根据 “P=D*发热丝饱和功率/400” 得400分之一的精度对应占空比周期为:400*10ms=4秒,这对于控制热风这种比热小的介质来说是根本无法容忍的,你会发现无论你怎么调整PID的参数都始终不能实现恒温。当然如果采集温度的AD分辨率足够高你可以不需要如此高的功率分辨率,你可以在温度还在1度以内变化时提前做出功率补偿使温度始终在1度以内上下浮动这样也能满足要求。经过实验我发现功率精度最低可以降到1/50,此时的加热周期T=50*10ms=0.5秒,但此时肉眼还是可以明显的看到发热丝的红暗交替,可能是由于采温热电偶的滞后性导致实际AD却是平稳的,如用热电偶测温仪实测温度也是稳定的。以上就是我四年前的解决方案,只是发热丝的红暗交替问题让我不太舒服。
直到我看到了某大厂做的热风控温产品,在保证控温精度的前提下肉眼几乎看不出发热丝的红暗交替现象。我便知道这个问题另有出路,于是我便开始一直在寻求这个终极解决方案也就有了前文所提到的灵光乍现的瞬间。这个思路说来也简单:如下图假如占空比周期T为10个市电半周,占空比D=5,按照通常的控制思路是这样的:
每次打开5个半周后会有5个半周关闭,如果按照1/50的功率控制精度就有:250ms开加热,250ms关加热这样做当然会造成热风温度的短时波动。终极解决方案是这样的:将上图中的ON和OFF打散再让他们充分混合得到你中有我我中有你的效果:
这样整体效果还是5个市电半周开5个市电半周关,也就是占空比依然是5/10.当然5/10是个特例,如果1/50的功率精度占空比为27/50应该怎么办呢?可理解为27个开和23个关,将27/23等于1余4,即为开和关为1:1余4,也就是一次开后就有一次关但23个开关周期后还多余4个开没有打开,这应该怎么办呢?办法就是把这4个开再分散到那23个开关周期中去:也就是23/4=5余3,现在可以把余数忽略了,最后输出结果是每5个ONOFF周期多插入一个ON这样就可以得到最大限度分散的27/50的占空比了。当然口说无凭为了直观的验证这个方案特引入一个验证算法的好方法:利用微软的Visual Studio验证并打印出实验结果:
实验代码:
实现1/100功率分辨率的分散占空比控制效果:
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
int main(void)
{
for (uint8_t heat_duty = 0; heat_duty <= 100; heat_duty++)
{
uint8_t i, j, k, l, m, sub_t, pos_nag,on_cycles=0,off_cycles=0; _Bool HEAT1ON_A;
i = heat_duty;
if (i > 50) { j = 100 - i; pos_nag = 1; }
else { j = i; i = 100 - j; pos_nag = 0; }
sub_t = i == 0 || j == 0 ? 100 : i / j + 1;
l = j != 0 ? i % j : 1; if (l == 0)l = 1;
for (uint8_t period = 0; period < 100; period++)
{
k = period; m = k / (j / l * sub_t + 1);
m = j==0 ? 0 : m > l ? k - l : k - m;
HEAT1ON_A = m % sub_t == sub_t >> 1 ? !pos_nag : pos_nag;//k < j* sub_t && k % sub_t == sub_t >> 1 ? !pos_nag : pos_nag;//
if (HEAT1ON_A)on_cycles++;
else off_cycles++;
printf(HEAT1ON_A!=0?"*":"-");
}
if (heat_duty!=on_cycles || on_cycles+off_cycles!=100)printf("%d,%d/%d\n", heat_duty,on_cycles,off_cycles);
else printf("\n");
}
return 0;
}
运行结果:( ‘ * ’ 表示开,‘ - ’表示关)
占空比0~50
占空比51-100
经过以上验证后发现逻辑上是没有问题的可以实现0-100内任意占空比的分散混合开关效果,但实际控温效果却差强人意,温度居然还没有原来不分散的稳定。这个脸实在打的让人猝不及防,本着严谨的求知态度步步为营却依然被现实打脸。哪位高人过来解释一下问题究竟出在哪里?在这里我也给出一个我的解释:可能是由于我的占空比控制是实时更新的,我并不会等到整个占空比周期结束后再更新占空比值,而是每次过零我都会根据当前的温度AD值重新计算占空比,我认为这样才能保证快速的反应能力,否则加热时负载的变化就不能及时的做出反应。但是在分散开关占空比控制中由于开和关是错开的,在一个占空比周期中占空比的邻近抖动可能会得到意想不到的效果:本来是降低加热功率反而会得到更高的功率,因此就会导致温度的不稳定。
|