引
输出对称三相电的逆变器,总是要进行很多浮点运算。因此一般而言,需要使用带FPU的单片机。或者说叫DSP。
如果只使用整数运算能否实现 svpwm 的计算呢?
答案是能的,就是使用 “定点数”
所谓定点数,就是和浮点数相对的,他的整数部分和小数部分是固定的。比如按 16bit 存储整数部分, 16bit 存储小数部分。这样一个 32bit 的定点数字,能表示的数字范围其实和 16位的整数一样。只不过它能额外的携带小数部分。
而浮点数则是脱胎于科学计数法。比如使用 16bit 存储基数,另外16bit存储系数。则可以表示非常非常大的范围,只不过数字越大,误差就越大。大点的数字都没有小数部分了。所以这种数字表示法,他的小数点是浮动的。所以叫浮点数。
浮点数其实有各种格式存储,但是为了互操作性, IEEE 定义了一个cpu上普遍使用的格式。IEEE 754。 如果单片机不支持浮点数运算指令,编译器就会用软件模拟。编译器带的软件浮点运算,速度非常非常慢。 这就是“浮点算不快”的由来。
受限于成本,低端的单片机都不会搭载FPU。而中端的单片机,虽然搭载了FPU,但是 FPU 的速度不能和整数部分相提并论。只有使用较为高端的单片机,其搭载的 FPU 才算能用于 foc/svpwm 控制。
这就极大的提高了电机控制器的成本。使得廉价控制器总是使用较为简单的只需要六步换向的方波驱动。而不是使用三相对称的正弦波驱动电机。
那么有没有办法在廉价的单片机上使用 foc 呢?
定点数学库
其实是有的。不过将foc控制算法修改为定点数运算,需要修改大量的代码。而且简单的 + - * / 运算符号,统统被替换成了难看的,对定点数学库的调用。 需要修改的地方非常多。将程序改的面目全非。
这就是 C 语言的弊病。 所以,就到了安利 C++ 的时间啦!
定点数学库 - header only CPP plug and play
C++ 的优势,就是具有 “运算符重载” 功能。这个功能使得使用非编译器内置数字类型不需要改变使用方式。你仍然只需要使用正常的 + - * / 运算符。
比如在所有代码里,凡是需要支持小数运算的地方,我统统使用 float_number 这个类型。
然后在全局的一个 header 里,我用 using float_number = float;
这样,在不使用数学库的情况下,我的代码自动的就是使用的编译器提供的 float 类型。
然后,在开发的某一个阶段,我引入了定点数学库。
这时候,我只要把 using float_number = float;
修改为 using float_number = fixpoint_number_provided_by_math_lib;
然后重新编译。那么我所有用到浮点数的地方,就会全自动的转换为使用了数学库里的定点数。
这就是 c++ 带来的开发上的巨大优势。
这次 mini vfd 硬件上定点数的速度提升
使用 Cortex-M4 内核的浮点指令,我做到了 pwm 周期计算代码执行时间为 50us。这差不多相当于极限 20khz 的开关速度。更快的开关速度将会导致 cpu 来不及执行完毕 pwm 中断代码,就又要发生一次 pwm 定时器中断了。
修改为使用定点数后,同样的代码(除了添加 using float_number = myfloat 声明,未做任何其他修改)执行时间缩短到了 9us。 这差不多相当于能在这颗 cpu 上运行 100khz 开关速度的 svpwm。
这也意味着,使用主频 12Mhz 的单片机,也能跑不低于 8khz 的 pwm 频率。 8khz 的开关频率,其实已经相当程度上做到开关噪音的抑制了。
Comments