【从零开始实现stm32无刷电机FOC】【实践】【6/7 CMSIS-DSP】

目录

  • 导入CMSIS-DSP库
  • 使用CMSIS-DSP

点击查看本文开源的完整FOC工程https://gitee.com/best_pureer/stm32_foc
CMSIS-DSP库是ARM开源的、对ARM处理器优化的数学库,本文使用了其提供的三角函数、反park变换函数、park变换函数、clarke变换函数、PID控制器。
CMSIS-DSP原始代码仓库是https://github.com/ARM-software/CMSIS-DSP,官方对其的介绍是一个针对Cortex-M和Cortex-A内核优化的嵌入式系统计算库,此处的DSP不是指的硬件,而是数字处理的意思。
在这里插入图片描述

导入CMSIS-DSP库

本文使用stm32cube编译好的CMSIS-DSP二进制文件,首先在Middleware and Software Packs中选择X-CUBE-ALGOBUILD:在这里插入图片描述
选择安装DSP Library,并且勾选Selection,下图为已经安装好的状态:
在这里插入图片描述
勾选DSP Library Library:
在这里插入图片描述
到此,工程代码里就能够使用CMSIS-DSP库了,只需在要使用DSP库的C源文件加上

#include "arm_math.h"

使用CMSIS-DSP

三角函数:
单独计算sin和cos三角函数,输入弧度rad:

  float32_t arm_sin_f32(float32_t x);
  float32_t arm_cos_f32(float32_t x);

单个函数完成计算sin和cos三角函数,输入角度deg:

  /**
   * @brief  Floating-point sin_cos function.
   * @param[in]  theta   input value in degrees
   * @param[out] pSinVal  points to the processed sine output.
   * @param[out] pCosVal  points to the processed cos output.
   */
  void arm_sin_cos_f32(
        float32_t theta,
        float32_t * pSinVal,
        float32_t * pCosVal);

clarke变换:

  /**
   *
   * @brief  Floating-point Clarke transform
   * @param[in]  Ia       input three-phase coordinate <code>a</code>
   * @param[in]  Ib       input three-phase coordinate <code>b</code>
   * @param[out] pIalpha  points to output two-phase orthogonal vector axis alpha
   * @param[out] pIbeta   points to output two-phase orthogonal vector axis beta
   * @return        none
   */
  __STATIC_FORCEINLINE void arm_clarke_f32(
  float32_t Ia,
  float32_t Ib,
  float32_t * pIalpha,
  float32_t * pIbeta)

clarke变换是将三个相线电流投影到 α \alpha α β \beta β轴,由于三个相线电流相加等于0,因此只需要输入两个相线电流IaIb到clarke变换函数中,输出到pIalphapIbeta

park变换:

  /**
   * @brief Floating-point Park transform
   * @param[in]  Ialpha  input two-phase vector coordinate alpha
   * @param[in]  Ibeta   input two-phase vector coordinate beta
   * @param[out] pId     points to output   rotor reference frame d
   * @param[out] pIq     points to output   rotor reference frame q
   * @param[in]  sinVal  sine value of rotation angle theta
   * @param[in]  cosVal  cosine value of rotation angle theta
   * @return     none
   *
   * The function implements the forward Park transform.
   *
   */
  __STATIC_FORCEINLINE void arm_park_f32(
  float32_t Ialpha,
  float32_t Ibeta,
  float32_t * pId,
  float32_t * pIq,
  float32_t sinVal,
  float32_t cosVal)

park变换是将 α \alpha α β \beta β轴投影到dq轴,此处的sinValcosVal为转子角度的sin和cos值。

反park变换:

   /**
   * @brief  Floating-point Inverse Park transform
   * @param[in]  Id       input coordinate of rotor reference frame d
   * @param[in]  Iq       input coordinate of rotor reference frame q
   * @param[out] pIalpha  points to output two-phase orthogonal vector axis alpha
   * @param[out] pIbeta   points to output two-phase orthogonal vector axis beta
   * @param[in]  sinVal   sine value of rotation angle theta
   * @param[in]  cosVal   cosine value of rotation angle theta
   * @return     none
   */
  __STATIC_FORCEINLINE void arm_inv_park_f32(
  float32_t Id,
  float32_t Iq,
  float32_t * pIalpha,
  float32_t * pIbeta,
  float32_t sinVal,
  float32_t cosVal)

反park变换是将dq轴投影到 α \alpha α β \beta β轴,此处的sinValcosVal为转子角度的sin和cos值。

PID控制器:
CMSIS-DSP库中的PID控制器是增量式PID计算累加到上一次的PID总输出。
位置式PID就是直观地分别将P、I、D控制器的各自输出加起来:
u ( t ) = K p e ( t ) + K i ∑ i = 0 t ( e ( i ) ∗ Δ T ) + K d [ e ( t ) − e ( t − 1 ) ] Δ T u(t) = K_p e(t) + K_i \sum_{i=0}^{t} (e(i)*\Delta T) + K_d \frac{[e(t) - e(t-1)]} {\Delta T} u(t)=Kpe(t)+Kii=0t(e(i)ΔT)+KdΔT[e(t)e(t1)]
为了方便计算,这里将 Δ T \Delta T ΔT当作为1,在 K i K_i Ki K d K_d Kd系数上缩放回去就好了。
增量式PID理念是将PID的输出是上次PID输出的基础上加上之前两次的累计误差:
u ( t ) = u ( t − 1 ) + Δ u ( t ) u(t) =u(t-1) +\Delta u(t) u(t)=u(t1)+Δu(t)
Δ u ( t ) = K p e ( t ) + K i ∑ i = 0 t e ( i ) + K d [ e ( t ) − e ( t − 1 ) ] − ( K p e ( t − 1 ) + K i ∑ i = 0 t − 1 e ( i ) + K d [ e ( t − 1 ) − e ( t − 2 ) ] ) = K p [ e ( t ) − e ( t − 1 ) ] + K i e ( t ) + K d [ e ( t ) − 2 e ( t − 1 ) + e ( t − 2 ) ] = A 0 ⋅ e [ t ] + A 1 ⋅ e [ t − 1 ] + A 2 ⋅ e [ t − 2 ] 其 中 { A 0 = K p + K i + K d A 1 = − K p − 2 K d A 2 = K d \Delta u(t) = K_p e(t) + K_i \sum_{i=0}^{t} e(i) + K_d [e(t) - e(t-1)]\\ -(K_p e(t-1) + K_i \sum_{i=0}^{t-1} e(i) + K_d [e(t-1) - e(t-2)])\\ = K_p [e(t) - e(t-1)] + K_i e(t) + K_d [e(t) - 2e(t-1) + e(t-2)]\\ = A_0⋅e[t]+A_1⋅e[t−1]+A_2⋅e[t−2]\\ 其中 \begin{cases} A_0=K_p+K_i+K_d\\ A_1=-K_p-2K_d\\ A_2=K_d \end{cases} Δu(t)=Kpe(t)+Kii=0te(i)+Kd[e(t)e(t1)](Kpe(t1)+Kii=0t1e(i)+Kd[e(t1)e(t2)])=Kp[e(t)e(t1)]+Kie(t)+Kd[e(t)2e(t1)+e(t2)]=A0e[t]+A1e[t1]+A2e[t2]A0=Kp+Ki+KdA1=Kp2KdA2=Kd
A 0 , A 1 , A 2 , 本 次 误 差 e [ t ] , 上 次 误 差 e [ t − 1 ] , 上 上 次 误 差 e [ t − 2 ] , 上 一 次 的 P I D 输 出 u ( t − 1 ) A_0,A_1,A_2,本次误差e[t],上次误差e[t-1],上上次误差e[t-2],上一次的PID输出u(t-1) A0A1A2e[t]e[t1]e[t2]PIDu(t1)均为已知数,增量式PID的输出 u ( t ) u(t) u(t)也就能够计算出来了。
从增量式PID公式 Δ u ( t ) = K p [ e ( t ) − e ( t − 1 ) ] + K i e ( t ) + K d [ e ( t ) − 2 e ( t − 1 ) + e ( t − 2 ) ] \Delta u(t) = K_p [e(t) - e(t-1)] + K_i e(t) + K_d [e(t) - 2e(t-1) + e(t-2)] Δu(t)=Kp[e(t)e(t1)]+Kie(t)+Kd[e(t)2e(t1)+e(t2)]可以看出,当被控参数突然受到大的扰动时,不像位置式PID的P项 K p ∗ e ( t ) K_p*e(t) Kpe(t)会产生一个大的输出,增量式PID的 K p [ e ( t ) − e ( t − 1 ) ] K_p [e(t) - e(t-1)] Kp[e(t)e(t1)]输出是不大的,因此增量式PID对被控参数变化的输出比较平滑,不会突变,当然响应没有位置式PID快。
在代码上,首先需要创建一个PID控制器:

arm_pid_instance_f32 pid_position;

然后设置PID控制器的PID参数:

pid_position.Kp = 1.2;
pid_position.Ki = 0.01;
pid_position.Kd = 2.1;

然后调用函数初始化PID控制器:

/**
 * @brief  Initialization function for the floating-point PID Control.
 * @param[in,out] *S points to an instance of the PID structure.
 * @param[in]     resetStateFlag  flag to reset the state. 0 = no change in state & 1 = reset the state.
 * @return none.
 * \par Description:
 * \par
 * The <code>resetStateFlag</code> specifies whether to set state to zero or not. \n
 * The function computes the structure fields: <code>A0</code>, <code>A1</code> <code>A2</code>
 * using the proportional gain( \c Kp), integral gain( \c Ki) and derivative gain( \c Kd)
 * also sets the state variables to all zeros.
 */

void arm_pid_init_f32(
  arm_pid_instance_f32 * S,
  int32_t resetStateFlag)

其中参数resetStateFlag为0时,会清空PID控制器内部保存的增量式数据: e [ n ] , e [ n − 1 ] , e [ n − 2 ] e[n],e[n-1],e[n-2] e[n],e[n1],e[n2]
一般初始化的用法是:

arm_pid_init_f32(&pid_position, false);

此时就能够调用函数计算PID输出值了:

  /**
   * @brief         Process function for the floating-point PID Control.
   * @param[in,out] S   is an instance of the floating-point PID Control structure
   * @param[in]     in  input sample to process
   * @return        processed output sample.
   */
  __STATIC_FORCEINLINE float32_t arm_pid_f32(
  arm_pid_instance_f32 * S,
  float32_t in)

其中参数S是PID控制器,参数in是被控参数的差值,返回PID控制器的输出值。


至此,所有准备工作就绪,我们了解了理论推导、FOC特定外设的配置和数学库的使用,接下来进入到从零开始实现stm32无刷电机FOC的完整工程讲解。
点击查看本文开源的完整FOC工程https://gitee.com/best_pureer/stm32_foc

03-18
<think>好的,用户的问题是关于FoCFocus或Code)在IT技术背景下的相关内容。首先,我需要明确FoC的具体含义。根据用户提到的可能与Focus、Framework或Code相关,可能指的是某种技术框架、方法论或编程模型。常见的类似缩写包括FoCs(Focus on Code Standards)或其他特定领域的术语,比如在并行计算中的Fork-and-Code模型。不过,需要进一步确认。 接下来,查看用户提供的引用资料。用户提到参考站内引用,可能与Focus、Framework或Code相关,但具体资料未提供。因此,需要基于常见IT技术知识进行推测。可能的解释是FoC指代一种以代码为中心的方法论,或者某个特定框架的缩写,例如Focus on Code Quality,或者Framework of Components。 然后,分析可能的上下文。在IT技术中,Focus通常指关注点分离,而Code涉及编码实践。Framework可能指开发框架,如Spring、React等。因此,FoC可能强调在开发过程中结合框架使用和代码质量管理的技术策略。 此外,考虑到用户提到的技术背景,可能涉及软件工程中的最佳实践,如代码审查、持续集成、测试驱动开发等,这些都和Focus与Code相关。需要将这些内容整合,给出一个合理的解释。 最后,生成相关问题,确保覆盖用户可能感兴趣的方面,如应用场景、优势、具体技术等,帮助用户深入理解。</think>关于FoCFocus或Code)在IT技术背景下的解释,通常可理解为**以代码为核心的技术框架或方法论**。结合不同领域,其含义可能包括以下方向: --- ### 1. **代码为中心的架构设计** 在微服务或模块化开发中,FoC强调通过代码结构直接体现业务逻辑,例如: ```java // 示例:通过注解定义Spring Boot服务 @RestController public class UserController { @Autowired private UserService userService; @GetMapping("/user/{id}") public User getUser(@PathVariable Long id) { return userService.findUserById(id); // 代码直接映射业务接口 } } ``` 这种模式将技术实现与业务目标紧密结合,提升可维护性[^1]。 --- ### 2. **聚焦代码质量的方法论** FoC可能指代**代码质量管控体系**,例如: - **代码审查规范**:通过工具(如SonarQube)检测复杂度、重复率 - **测试覆盖率要求**:单元测试覆盖率达到80%以上 - **编码规范检查**:使用ESLint、Checkstyle等自动化工具 数学表达示例:代码复杂度计算常用圈复杂度公式 $$ CC = E - N + 2P $$ 其中$E$为边数,$N$为节点数,$P$为出口节点数[^2]。 --- ### 3. **特定技术框架** 在某些场景下,FoC可能指具体技术栈: - **前端框架组合**:如Focus+React+TypeScript - **后端架构模式**:如CQRS(Command Query Responsibility Segregation) ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

朴人

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值