LittleFOC工程简记——基于定点数的电流PI控制器设计

2023-11-15

LittleFOC工程简记——基于定点数的电流PI控制器设计

这里罗列了系列文章链接



前言

在FOC程序在设计的过程中,对于很多芯片而言,其缺乏浮点数运算器,因此大量的浮点数运算会给系统带来很大的计算负担。对于整个系统而言,采用定点数对整体程序进行优化,可以大幅减轻控制器的计算压力,从而实现更加理想的控制。本文针对定点数环境下的PI控制器的算法设计进行简要讨论,欢迎各位同学批评指正。


电机系统

对于大部分电机系统,其电流与电压的输入输出关系可以描述为
V ( t ) = R ∗ i ( t ) + L ∗ d i ( t ) d t V(t) = R * i(t) + L * \frac{di(t)}{dt} V(t)=Ri(t)+Ldtdi(t)
我们对其进行拉普拉斯变换
i ( s ) V ( s ) = 1 R + L s = 1 R 1 1 + L R s \frac{i(s)}{V(s)}= \frac{1}{ R + Ls} = \frac{1}{R} \frac{1}{ 1 +\frac{L}{R}s} V(s)i(s)=R+Ls1=R11+RLs1
可以观察到匹配到合适的电阻值时系统在大部分时间可以输出稳可控的电流,该方案仅在电机堵转的情况下是合理的。

但在实际电机运动的过程中,由于磁铁的旋转导致线圈内部磁通变化,引起反电动势的变化,从而导致电流发生波动,这一现象往往是不可预测的。考虑到实测电流决定线圈实际磁通大小,而磁力与磁通直接挂钩( F = ϕ S 2 2 μ 0 S F = \frac{\phi S^2}{2\mu_0S} F=2μ0SϕS2),而最终想要速度稳定需要保证扭矩与阻尼保持平衡。对于系统的电流控制显得尤为重要。

在FOC系统中通常采用PI控制器对电流进行闭环矫正,其结构图如下
在这里插入图片描述

其中并联PI控制器结构图如下图所示,在这个系统中,采用串联式PI控制器调控效果会更优,其解释参考https://zhuanlan.zhihu.com/p/454914546#:,实际上此处设定 k p = k a , k i = k a ∗ k b k_p=k_a, k_i = k_a*k_b kp=ka,ki=kakb即可

在这里插入图片描述

求其系统总体闭环传递函数,可得
G ( s ) = 1 K b s + 1 L K a K b s 2 + ( 1 K b + R K a K b ) s + 1 G(s) = \frac{\frac{1}{K_b}s+1}{\frac{L}{K_aK_b}s^2+(\frac{1}{K_b}+\frac{R}{K_aK_b})s+1} G(s)=KaKbLs2+(Kb1+KaKbR)s+1Kb1s+1
其中我们设定 1 K b ∗ R K a K b = L K a K b \frac{1}{K_b} * \frac{R}{K_aK_b} = \frac{L}{K_aK_b} Kb1KaKbR=KaKbL,以抵消一对极点和零点,可得 K b = R L K_b=\frac{R}{L} Kb=LR,传递函数将会被简化为
G ( s ) = 1 L K a s + 1 G(s) = \frac{1}{\frac{L}{K_a}s+1} G(s)=KaLs+11
其中 K a = B n a d w i d t h ∗ L K_a=Bnadwidth * L Ka=BnadwidthL,对两个参数进行离散化与归一化,可得
{ K a = B n a d w i d t h ∗ L ∗ I b a s e U b a s e ∗ T b a s e K b = R L ∗ T s \left\{ \begin{array}{l} K_a=Bnadwidth * L * \frac{I_{base}}{U_{base}*T_{base}}\\ K_b=\frac{R}{L}*Ts \end{array} \right. {Ka=BnadwidthLUbaseTbaseIbaseKb=LRTs

https://blog.csdn.net/richardgann/article/details/99704448

工程分析

对于系统中的PI控制器可以用下图进行描述

对于上图的PI控制器,可以归纳出
U o u t = k p ∗ e r r o r n + k i ∗ ∑ e r r o r n Δ U o u t = ( k p + k i ) ∗ e r r o r n − k p ∗ e r r o r n − 1 \begin{array}{c} U_{out} = k_p * error_n + k_i * \sum error_n\\ \Delta U_{out} = (k_p + k_i) * error_n - k_p * error_{n-1}\\ \end{array} Uout=kperrorn+kierrornΔUout=(kp+ki)errornkperrorn1

定义
{ k n = k p + k i k n − 1 = − k p \left\{ \begin{array}{l} k_n = k_p + k_i \\ k_{n-1} = -k_p \end{array} \right. {kn=kp+kikn1=kp

因此增量式PI控制器计算公式为
{ e r r o r n = I r e f − I n Δ U o u t = k n ∗ e r r o r n + k n − 1 ∗ e r r o r n − 1 U o u t = ∑ Δ U o u t \left\{ \begin{array}{l} error_n = I_{ref} - I_{n}\\ \Delta U_{out} = k_n * error_n + k_{n-1} * error_{n-1}\\ U_{out} = \sum \Delta U_{out} \end{array} \right. errorn=IrefInΔUout=knerrorn+kn1errorn1Uout=ΔUout

考虑输入输出内容的定义域,由于各个参量都为定点数(q15_t),因此其定义域为
{ I r e f ∈ [ − 1 , 1 ) I n ∈ [ − 1 , 1 ) U o u t ∈ [ − 1 , 1 ) \left\{ \begin{array}{l} I_{ref} \in [-1, 1)\\ I_{n} \in [-1, 1)\\ U_{out} \in [-1, 1) \end{array} \right. Iref[1,1)In[1,1)Uout[1,1)

计算过程中
{ e r r o r n ∈ ( − 2 , 2 ) Δ U o u t ∈ ( − 2 ( k n − k n − 1 ) , 2 ( k n − k n − 1 ) ) \left\{ \begin{array}{l} error_n \in (-2, 2)\\ \Delta U_{out} \in (-2(k_n-k_{n-1}), 2(k_n-k_{n-1})) \end{array} \right. {errorn(2,2)ΔUout(2(knkn1),2(knkn1))

再考虑到要保证 U o u t ∈ [ − 1 , 1 ) U_{out} \in [-1, 1) Uout[1,1),显然 k n − k n − 1 = 2 ∗ k p + k i < 0.5 k_n - k_{n-1}=2 * k_p + k_i< 0.5 knkn1=2kp+ki<0.5,因此需要控制 k p < 0.25 k_p< 0.25 kp<0.25 k i < 0.5 k_i< 0.5 ki<0.5

此外,由于 e r r o r n = I r e f − I n ∈ ( − 2 , 2 ) error_n = I_{ref} - I_{n} \in (-2, 2) errorn=IrefIn(2,2),变量 e r r o r n error_n errorn应转变为q14_t或q_30_t格式进行计算,由于笔者采用ADC精度仅在12位,因此对输入变量从q15_t降为q14_t并不会影响其精度。

对于 Δ U o u t \Delta U_{out} ΔUout仍采用q14_t格式进行计算,设定其最大值为1,最小值为-1,这同时保证了在满足 k p < 0.25 k_p< 0.25 kp<0.25 k i < 0.5 k_i< 0.5 ki<0.5 Δ U o u t \Delta U_{out} ΔUout的运算不会溢出。

变量 U o u t U_{out} Uout同样采用q14_t格式进行计算,设定其最大值为1,最小值为-1,对外输出q15_t格式。


工程代码

工程代码未经过严格测试,使用前请谨慎检查

/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __PI_CONTROLLER_H
#define __PI_CONTROLLER_H
/* =================================================================================
File name:       __PI_CONTROLLER_H
改编自https://blog.csdn.net/wind4study/article/details/45116281
===================================================================================*/

#ifdef __cplusplus
extern "C" {
#endif

/* Includes ------------------------------------------------------------------*/

#include "main.h"

typedef struct PI_Controller_ PI_Controller;

typedef void (*PICfptrInit)(PI_Controller*, q15_t, q15_t, q15_t, q15_t);
typedef q15_t (*PICfptrCalc)(PI_Controller*, q15_t);

struct PI_Controller_
{
	q14_t kp;
	q14_t ki;
	q14_t limit1;
	q14_t limit2;
	
	q14_t kn;
	q14_t kn_1;

	q14_t setValue;
	
	q14_t errorn_1;
	
	q14_t delta_Un;
	q14_t Un;
	q15_t output;
	
	PICfptrInit init;
	PICfptrCalc calc;
};
 
PI_Controller* new_PI_Controller(void);
void delete_PI_Controller(PI_Controller* const pPICObj);

void PI_controller_init(PI_Controller* const pPICObj, q15_t kp, q15_t ki, q15_t limit1, q15_t limit2);
q15_t PI_controller_calc(PI_Controller* const pPICObj, q15_t value);

#endif
/* =================================================================================
File name:       __PI_CONTROLLER_C
===================================================================================*/
#include "PI_controller.h"

PI_Controller* new_PI_Controller(void)
{
	PI_Controller* pObj = NULL;
	pObj = (PI_Controller*)malloc(sizeof(PI_Controller));
	if (pObj == NULL)
	{
		return NULL;
	}
	
	pObj->init = PI_controller_init;
	pObj->calc = PI_controller_calc;
	
	pObj->Un = 0;
	
	return pObj;			
}

void delete_PI_Controller(PI_Controller* const pPICObj)
{
	free(pPICObj);
}

void PI_controller_init(PI_Controller* const pPICObj, q15_t kp, q15_t ki, q15_t limit1, q15_t limit2)
{
	pPICObj->setValue = 0;
	pPICObj->kp = kp>>1;
	if(pPICObj->kp > 0x0fff)
	{
	 	pPICObj->kp = 0x0fff;
		printf("Warning: The value of kp is too large!\r\n");
	}
	
	pPICObj->ki = ki>>1;
	if(pPICObj->ki > 0x0fff)
	{
	 	pPICObj->ki = 0x0fff;
		printf("Warning: The value of ki is too large!\r\n");
	}
	
	pPICObj->kn = pPICObj->kp + pPICObj->ki;
	pPICObj->kn_1 = -pPICObj->kp;

	pPICObj->limit2 = limit2>>1;
	if(pPICObj->limit2 > 0x3fff)
	{
		pPICObj->limit2 = 0x3fff;
		printf("Warning: The value of limit2 is too large!\r\n");
	}
	
	pPICObj->limit1 = limit1>>1;
	if(pPICObj->limit1 < -0x3fff)
	{
		pPICObj->limit1 = -0x3fff;
		printf("Warning: The value of limit1 is too large!\r\n");
	}
	
	pPICObj->delta_Un = 0;
	pPICObj->errorn_1 = 0;
}
 
q15_t PI_controller_calc(PI_Controller* const pPICObj, q15_t value)
{
	q14_t errorn =0;
 
	errorn = pPICObj->setValue - (value>>1);

	pPICObj->delta_Un = my_mult_q14(pPICObj->kn, errorn) + my_mult_q14(pPICObj->kn_1, pPICObj->errorn_1);
	
	pPICObj->errorn_1 = errorn;
	
	if(pPICObj->delta_Un > 0x3fff)
		pPICObj->delta_Un = 0x3fff;
	else if(pPICObj->delta_Un < -0x3fff)
		pPICObj->delta_Un = -0x3fff;
 
	pPICObj->Un += pPICObj->delta_Un; 
	
	if(pPICObj->Un > pPICObj->limit2)
		pPICObj->Un = pPICObj->limit2;
	else if(pPICObj->Un < pPICObj->limit1)
		pPICObj->Un = pPICObj->limit1;
	
	pPICObj->output = pPICObj->Un << 1;
	return pPICObj->output;
}

关于定点数的计算函数

typedef int16_t q14_t;
typedef int16_t q15_t;

q14_t my_mult_q14(q14_t SrcA, q14_t SrcB)
{
	return ((int16_t)SrcA * SrcB)>>14;
}

q15_t my_mult_q15(q15_t SrcA, q15_t SrcB)
{
	return ((int16_t)SrcA * SrcB)>>15;
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

LittleFOC工程简记——基于定点数的电流PI控制器设计 的相关文章

随机推荐

  • 【信号与系统】傅里叶变换

    傅里叶变换 文章目录 傅里叶变换 傅里叶级数 基本公式 常用公式 基本性质 其他公式 卷积公式 周期信号的傅里叶变换 抽样信号的傅里叶变换 提供延时的理想滤波器 无失真传输 傅里叶级数 https blog csdn net lafea a
  • 【Flink】Flink 消费kafka报错 AMRMClientAsyncImpl Interrupted while waiting for queue InterruptedException

    1 背景 一个flink etl程序 读取一个kafka集群的数据 到两外一个集群 然后报错 2020 06 06 15 56 00 PM Thread flink akka actor default dispatcher 20 Clas
  • redis缓存一致性延时双删代码实现

    不废话 如下 1 自定义注解 author caoyue 延时双删 Retention RetentionPolicy RUNTIME Documented Target ElementType METHOD public interfac
  • shell脚本判断变量是否包含某个字符串的几种方法

    方法一 利用grep查找 strA long string strB string result echo strA grep strB if result then echo 包含 else echo 不包含 fi 先打印长字符串 然后在
  • 利用SVG滤镜实现水波倒影效果

    SVG滤镜用来增加对SVG图形的特殊效果 多种滤镜巧妙结合起来可以实现很棒的视觉效果 下面利用svg的feTurbulence滤镜和feDisplacementMap来模拟真实的水波倒影特效 效果如下图 代码并不复杂 首先设置两张图片 di
  • 数据包络分析(DEA)——CCR模型

    写在前面 博主本人大学期间参加数学建模竞赛十多余次 获奖等级均在二等奖以上 为了让更多学生在数学建模这条路上少走弯路 故将数学建模常用数学模型算法汇聚于此专栏 希望能够对要参加数学建模比赛的同学们有所帮助 目录 1 模型原理 1 1 模型介
  • 如何搭建以太坊测试链(附教程)

    在以太坊项目实际开发中 我们必须要有一个测试环境 因为产品环境是需要消耗GAS的 因此我们希望在测试环境测试无误之后再发布到产品环境以太坊链上去 本篇教程讲述如何搭建本地的测试链 1 Testnets 以太坊的测试网络环境被称为Testne
  • LeetCode 125. 验证回文串

    题目链接 https leetcode cn problems valid palindrome 思路如下 双指针 一首一尾 相向扫描 每次将两个指针分别移动到下一个字母字符或数字字符 再判断这两个指针指向的字符是否相同 C 代码如下 cl
  • Vue为数字添加逗号分隔

    1 看代码 我将这个代码作为外部js导出了 如果你没有那么多模块 就直接CTRL cv 这个方法 丢到你的 vue代码 methods中就可以用了 export const numberFilter function value cut 2
  • Java Class Version 研究

    一 要解决的问题 我们在尝鲜 JDK1 5 的时候 相信不少人遇到过 Unsupported major minor version 49 0 错误 当时定会茫然不知所措 因为刚开始那会儿 网上与此相关的中文资料还不多 现在好了 网上一找就
  • Mac平台安卓模拟器:网易MuMu mac中文免费版(支持12系统)

    网易MuMu Mac版是一款可以让Mac用户在电脑上轻松玩手游的安卓模拟器 是迄今为止国内最好最流畅的手游模拟器软件 网易mumu mac版现已支持梦幻西游 大话西游 倩女幽魂等众多经典安卓手机游戏 mumu模拟器mac版为大家提供海量免费
  • Python模块-pandas

    目录 数据读取 数据探索 数据清洗 数据清洗 类型转换 缺失值 重复值 值替换 修改表结构 新增列 删除列 删除行 修改列名 数据分组 数值变量 数据分列 分类变量 设置索引 排序 数据筛选 切片 多表拼接 数据聚合 分组运算 groupb
  • 高数:第一章:函数、极限、连续

    文章目录 一 函数 1 函数的概念 基本初等函数 初等函数 2 函数的性质 函数四性态 1 单调性 2 奇偶性 3 导函数的奇偶性 3 周期性 4 有界性 5 对称性 3 基本不等式 4 开根要带绝对值 二 极限 1 极限的概念 数列极限
  • R语言的基础语法及常用命令

    R其实对于数据分析来说只是工具而已 所以刚开始不需要学习多么深多么细 只需要能够满足当前需求就行 之后的在实践中慢慢学习 毕竟想要把R学精并不是容易的事情 正确的做法就是边做边学 不会就google翻文档 本片主要是R的基础语法及常用的命令
  • 关系运算和逻辑运算( &与&& 和

    关系运算和逻辑运算 关系运算 比较 gt gt lt lt 对象 instanceof 类 1 区分 和 区别 赋值符号 将 后面的结果 值 引用 存入 左边的变量空间内 比较符号 比较 后面的元素 值 引用 与前面的是否一致 2 比较运算
  • 外部组件发生异常怎么解决_火绒提示安全服务异常是怎么回事?三种方法帮你轻松解决此问题...

    平时我们在使用电脑的过程当中 为了保护电脑的安全 我们往往会在电脑上安装防护类的软件 比如火绒安全软件 它是一款集杀防于一体的电脑防御及杀毒类安全软件 使用这款软件来保护电脑 不仅软件的体积小巧 占用资源小 而且它的功能强大 可以对我们的电
  • 如何向这个public static void main(String[] args)中的args数组传递参数呢

    如何向这个public static void main String args 中的args数组传递参数呢 重新认识 main 方法 要向 public static void main String args 中的 args 数组传递参
  • Jquery中each的三种遍历方法

    1 选择器 遍历 div each function i i就是索引值 this 表示获取遍历每一个dom对象 2 选择器 遍历 div each function index domEle index就是索引值 domEle 表示获取遍历
  • python 蓝桥 数列排序

    题目 数列排序 问题描述 给定一个长度为n的数列 将这个数列按从小到大的顺序排列 1 lt n lt 200 原因分析 输出格式 输出一行 按从小到大的顺序输出排序后的数列 样例输入 5 8 3 6 4 9 样例输出 3 4 6 8 9 解
  • LittleFOC工程简记——基于定点数的电流PI控制器设计

    LittleFOC工程简记 基于定点数的电流PI控制器设计 这里罗列了系列文章链接 文章目录 LittleFOC工程简记 基于定点数的电流PI控制器设计 前言 电机系统 工程分析 工程代码 前言 在FOC程序在设计的过程中 对于很多芯片而言