You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PI控制器输出转10位无符号PWM占空比的缩放与负值处理问题

单片机PI控制器PWM占空比缩放问题解决方案

一、现有缩放逻辑的核心问题

  1. 负值处理失效:原公式duty_cycle/1023 = Stell/Max_Stell仅适用于Stell为正的场景,当Stell为负时,负数值赋值给无符号的duty_cycle会触发溢出,得到完全不符合预期的大数值。
  2. Max_Stell计算错误:原代码中Max_Stell依赖实时的Integral值,导致缩放基准动态变化,无法保证Stell到占空比的线性映射一致性。
  3. 积分饱和未处理:低设定值时积分无法补偿负误差,本质是积分环节累积了过多负向误差,导致积分饱和,PI输出被锁死在负向极值。

二、正确的缩放与负值补偿实现

1. 先给PI输出做限幅(解决积分饱和)

首先定义PI控制器输出的正负极值(根据系统实际允许的输出范围设定),并给积分项和最终输出做限幅,避免积分饱和:

// 定义PI输出的正负最大范围(示例值,需根据实际系统调整)
#define STELL_MIN (-1000)
#define STELL_MAX 1000

// 自定义限幅宏
#define CLAMP(val, min_val, max_val) ((val) < (min_val) ? (min_val) : ((val) > (max_val) ? (max_val) : (val)))

void controller(void)
{
    int32_t stell_1, stell_2, stell; 
    int32_t Integral; 
    int32_t delta_e;  // 改为int32_t,避免无符号数相减溢出
    uint32_t DZSoll, DZIst; 
    uint16_t duty_cycle; 
    int32_t temp_duty_cycle; 
    int32_t range;
    int32_t offset_stell;
     
    // 误差计算:强制转换为有符号数,避免无符号相减溢出
    delta_e = (int32_t)DZSoll - (int32_t)DZIst; 

    // PI控制器计算
    stell_1 = delta_e * Kp; 
    // 先给积分项限幅,防止积分饱和
    Integral = CLAMP(Integral, STELL_MIN / Ki, STELL_MAX / Ki);
    Integral += delta_e; 
    // 再次限幅积分项,避免累加后溢出
    Integral = CLAMP(Integral, STELL_MIN / Ki, STELL_MAX / Ki);
    stell_2 = Ki * Integral; 
    stell = stell_1 + stell_2; 
    // 限幅最终PI输出
    stell = CLAMP(stell, STELL_MIN, STELL_MAX); 

    // 负值偏移+缩放:将[-STELL_MIN, STELL_MAX]映射到[0, 1023]
    range = STELL_MAX - STELL_MIN;
    offset_stell = stell - STELL_MIN;  // 偏移后 Stell_MIN变为0,Stell_MAX变为range
    temp_duty_cycle = (offset_stell * 1023) / range;
    // 最终限幅,确保占空比在0-1023范围内
    duty_cycle = (uint16_t)CLAMP(temp_duty_cycle, 0, 1023); 

    PWMUpdate(duty_cycle); 
}

2. 映射逻辑说明

通过偏移+线性缩放实现负值到无符号占空比的转换:

  • 偏移:将Stell的最小值STELL_MIN偏移到0,此时所有Stell值都变为非负数
  • 缩放:把偏移后的数值线性映射到0-1023区间,公式为:
    duty_cycle = (偏移后Stell值) * 1023 / (PI输出总范围)

三、额外优化点

  • 积分分离:当误差绝对值超过设定阈值时,暂停积分环节,避免误差过大时积分累积过快,示例逻辑:
    if (abs(delta_e) > ERROR_THRESHOLD) {
        // 误差过大,暂停积分
        Integral = CLAMP(Integral, STELL_MIN / Ki, STELL_MAX / Ki);
    } else {
        Integral += delta_e;
        Integral = CLAMP(Integral, STELL_MIN / Ki, STELL_MAX / Ki);
    }
    
  • 定点运算优化:如果单片机性能有限,可将1023/range预先转换为定点数(比如左移16位变成整数),用移位代替除法,提高运算效率。

内容的提问来源于stack exchange,提问作者Alles Klar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.08 08:30:58