打印
[学习笔记]

AC7811-FOC无感控制代码详解

[复制链接]
楼主: 狗啃模拟
手机看帖
扫描二维码
随时随地手机跟帖
21
狗啃模拟|  楼主 | 2023-9-30 11:08 | 只看该作者 |只看大图 回帖奖励 |倒序浏览

使用特权

评论回复
22
狗啃模拟|  楼主 | 2023-9-30 11:08 | 只看该作者
在FOC的算法里,我们可能会用到PI控制器的地方:

电流环的Q轴(控制转子的转矩)
电流环的D轴(控制转子磁通)
速度环(控制转速)
位置环(控制位置)
电流观测器PLL(转速及角度估算)
串联PI、并联PI、位置式、增量式PI等。

使用特权

评论回复
23
狗啃模拟|  楼主 | 2023-9-30 11:08 | 只看该作者
启动方式
I/F电流/频率、V/F电压/频率、HF、DIRECT

I/F电流/频率:根据永磁同步电机负载特性,给变频器设置合适的电流-频率比,使得电机输出转矩与不同转速下的负载相匹配,以达到较高的运行效率。I/F控制策略运行在速度开环、电流闭环的状态。

使用特权

评论回复
24
狗啃模拟|  楼主 | 2023-9-30 11:08 | 只看该作者
启动波形

使用特权

评论回复
25
狗啃模拟|  楼主 | 2023-9-30 11:09 | 只看该作者
绿色线-相电流、黄色线-估计的电角度

1是初始位置识别,脉冲注入法,无抖动启动。

2开环运行,IF与VF开环运行

3开环到闭环的切换

4闭环运行

使用特权

评论回复
26
狗啃模拟|  楼主 | 2023-9-30 11:09 | 只看该作者
脉冲注入
根据定子铁芯非线性饱和效应的特征,当向定子绕组施加一系列等宽的短时检测电压矢量,可通过母线响应电流的大小来辨别转子初始位置区间。

使用特权

评论回复
27
狗啃模拟|  楼主 | 2023-9-30 11:09 | 只看该作者

使用特权

评论回复
28
狗啃模拟|  楼主 | 2023-9-30 11:09 | 只看该作者
高频注入
高频注入算法作用:用于无传感模式静止及低速情况下电机的位置识别。

高频注入算法通过向定子线圈注入特定的电压载波信号,藉由电机d-g轴电感的差异特性,进而产生与转子角度误差相关的电流信号,再依此电流信号进行估测角度的修正以达到无感测启动之目的。

高频注入算法利用电机d-g轴电感的差异特性,适合凸极特性较好的内嵌式永磁同步电机(IPMSM)使用。(因为内嵌式的PMSM两个轴电感值差距较大,而表贴式两者相近)


使用特权

评论回复
29
狗啃模拟|  楼主 | 2023-9-30 11:10 | 只看该作者
Startup
这个模块主要提供无感FOC开环启动的一些函数。

感觉启动方面特别的乱,捋一捋:

问题一:高频注入和vf,if这些启动方式的关系是啥?

问题二:FOC开环启动曲线,到底是个啥子?

使用特权

评论回复
30
狗啃模拟|  楼主 | 2023-9-30 11:10 | 只看该作者
预定位到指定角度
预定位到指定角度上 FOC的预定位不再是六步换相那样通电流,而设置iqRef。

问题是,开环阶段怎么能直接设置iqRef呢?

看不懂进行不下去了……感觉都是参数的互相传递。

使用特权

评论回复
31
狗啃模拟|  楼主 | 2023-9-30 11:10 | 只看该作者
PulseInject_api
脉冲注入的五种状态机,分别对应着不同的函数

而且发现只有PulseInject_api这个文件,却找不到PulseInject这个文件,但有PulseInject.h头文件。

使用特权

评论回复
32
狗啃模拟|  楼主 | 2023-9-30 11:11 | 只看该作者
同时在PulseInject_api里面有很多函数,应该是在PulseInject里面的,也没办法具体的观察。
/*!
* [url=home.php?mod=space&uid=247401]@brief[/url] Pre_positioning motor to an expected angle.
*预定位到指定角度上  FOC的预定位不再是六步换相那样通电流,而设置iqRef
* @param[in] focVarsCtrl: pointer to FOC_VARS_CTRL structure
* @param[in] startUp: pointer to START_UP structure
* [url=home.php?mod=space&uid=266161]@return[/url] none
*/
void Angle_Prepositioning_Process(FOC_VARS_CTRL *focVarsCtrl, START_UP *startUp)
{
    static uint32_t s_timeBase = 0;

    ++s_timeBase;
    if (s_timeBase <= startUp->pStCfg->alignTime)
    {
        startUp->pStCtrl->startUpElecTheta = startUp->pStCfg->alignAngle;
        focVarsCtrl->elecAngle = startUp->pStCtrl->startUpElecTheta;
        focVarsCtrl->idRef = 0;
        if (s_timeBase <= startUp->pStCfg->slopeDuration1)
        {
            focVarsCtrl->iqRef = (startUp->pStCfg->curRamp1Init + Math_Mpy(s_timeBase, startUp->pStCtrl->curAddSlope1)) * pFocVarsCfg->motorDir;
            //iqRef,q轴参考电流
        }
        else
        {
            focVarsCtrl->iqRef = startUp->pStCfg->alignCur * pFocVarsCfg->motorDir;
        }

    }
    else
    {
#if (defined MOTOR_POLES_OBTAIN)
        startUp->pStCtrl->startUpFlag = 2;
#else
        s_timeBase = 0;
        startUp->pStCtrl->alignState = 1;
        startUp->pStCtrl->startUpFlag = 3;
#endif
    }

脉冲注入其实有两部份工作要做:1脉冲宽度的自识别(PulseInject_SelfLearn());2脉冲注入。

使用特权

评论回复
33
狗啃模拟|  楼主 | 2023-9-30 11:11 | 只看该作者
脉冲注入后,得到六向母线电流,根据电感的饱和特性,计算转子的初始位置。

PulseInject_DataHandle()该函数处理数据只需要总线电流,因此初始位置检查功能也适用于bldc控制。

void PulseInject_DataHandle(PULSE_INJECT_DATA *pulseInj);

使用特权

评论回复
34
狗啃模拟|  楼主 | 2023-9-30 11:11 | 只看该作者
hfi_api
和脉冲注入一样都是只有头文件,找不到源文件。

但通过头文件也可以简单了解到那些函数用于高频注入。



能了解到的就这么多……

使用特权

评论回复
35
狗啃模拟|  楼主 | 2023-9-30 11:11 | 只看该作者
Speed loop
speed_angle
这个模块主要提供速度斜坡与速度环的一些功能参数。

和BLDC里面的一些函数与配置很相似,但也有一些不同的点:

PI:Speedloop变量PI参数计算,它根据速度将速度环路PI参数分为三个部分,低速时使用低速PI,高速时使用高速PI,中间速度线性过渡。
/*!
* @brief Speedloop variable PI parameters calculate, it divides the speed loop PI parameters into three sections
         according to the speed, low speed PI is used at low speed, high speed PI is used at high speed, and the
         intermediate speed is linearly transitioned.
*Speedloop变量PI参数计算,它根据速度将速度环路PI参数分为三个部分,低速时使用低速PI,高速时使用高速PI,中间速度线性过渡。
* @param[in] freq: motor electrical frequency pu value in Q15
* @param[in] asrVarPI: pointer to ASR_SPEEDVARPI structure
* @param[in] asrPidCof: pointer to PID_REGULATOR_COF structure
* @return none
*/
void ASR_SpeedVarPICalc(int16_t freq, ASR_SPEEDVARPI *asrVarPI, PID_REGULATOR_COF *asrPidCof)
{
    uint16_t s_absFre = 0;
    s_absFre = Math_Qabs(freq);
    if (s_absFre > asrVarPI->frepuH)
    {
        asrPidCof->**u = asrVarPI->kpH;
        asrPidCof->kiPu = asrVarPI->kiH;
    }
    else if (s_absFre > asrVarPI->frepuL)
    {
        asrPidCof->**u = asrVarPI->kpL + Math_Mpy((s_absFre - asrVarPI->frepuL), asrVarPI->kpGain);
        asrPidCof->kiPu = asrVarPI->kiL + Math_Mpy((s_absFre - asrVarPI->frepuL), asrVarPI->kiGain);
    }
    else
    {
        asrPidCof->**u = asrVarPI->kpL;
        asrPidCof->kiPu = asrVarPI->kiL;
    }
}

使用特权

评论回复
36
狗啃模拟|  楼主 | 2023-9-30 11:11 | 只看该作者

    if (s_absFre > asrVarPI->frepuH)
    {
        asrPidCof->**u = asrVarPI->kpH;
        asrPidCof->kiPu = asrVarPI->kiH;
    }
    else if (s_absFre > asrVarPI->frepuL)
    {
        asrPidCof->**u = asrVarPI->kpL + Math_Mpy((s_absFre - asrVarPI->frepuL), asrVarPI->kpGain);
        asrPidCof->kiPu = asrVarPI->kiL + Math_Mpy((s_absFre - asrVarPI->frepuL), asrVarPI->kiGain);
    }
    else
    {
        asrPidCof->**u = asrVarPI->kpL;
        asrPidCof->kiPu = asrVarPI->kiL;
    }
}

而且还提到了一个新的控制对象:S curve .

我推测应该是速度曲线的意思,有很多的函数是围绕它来写的。

Protector
电机保护策略功能函数,相比于BLDC控制多了很多功能。

使用特权

评论回复
37
狗啃模拟|  楼主 | 2023-9-30 11:12 | 只看该作者
Phase_Over_Current_Check 相电流过流保护
电机相电流超过设定阈值,且连续达到设定次数(防误报)时,上报相电流过流故障
/*!
* @brief Phase over current protection. When the amplitude of the phase current
*        synthesis vector exceeds the threshold value, phase over current fault is reported.
*
* @param[in] focVars: pointer to FOC_VARS_CTRL structure
* @return status: fault diagnosis status, 0 OK; 1 fault; 2 unknown
*/
int16_t Phase_Over_Current_Check(FOC_VARS_CTRL *focVars)
{
    static int16_t cnta = 0;
    int16_t status = DIAGNOSTIC_OK;
    uint16_t statusTemp = 0;

    if (focVars->idq > MAX_IPHASE_THRESHOLD)
    {
        statusTemp |= 0x1;
        if (cnta < IPHASE_DBC)
        {
            cnta++;
        }
        else
        {
            cnta = 0;
            Fault_Report(OVER_CURRENT_PHASE_FAILURE);
        }
    }
    else
    {
        cnta = 0;
    }

    if (statusTemp != 0)
    {
        status = DIAGNOSTIC_FAIL;
    }

    return status;
}

使用特权

评论回复
38
狗啃模拟|  楼主 | 2023-9-30 11:12 | 只看该作者
Bus_Over_Current_Check 母线电流过流保护
Vbus_OverVoltage_Check 过压保护
Vbus_UnderVoltage_Check 欠压保护
LoseSpeed_Check 失速保护
失速,指的就是速度控制不住了,忽然加速

使用特权

评论回复
39
狗啃模拟|  楼主 | 2023-9-30 11:12 | 只看该作者
/*!
* @brief Motor Lose Speed protection.
*
* @param[in] speed: speed feedback pu value
* @return none
*/
void LoseSpeed_Check(int16_t speed)
{
    static int16_t oldSpeed = 0;
    static uint16_t cntLoseSpeed = 0;

    if (g_startUpCtrl.startUpFlag > 3)
    {
        if ((Math_Qabs(speed) > LOSE_SPEED_THRESHOLD) || ((int16_t)Math_Mpy(pFocVarsCfg->motorDir, speed) < 0) || (Math_Qabs(speed - oldSpeed) > LOSE_SPEED_ERR_THRESHOLD))
        //转速超过设定阈值或当前转速与上一次转速差值大于设定阈值,且连续达到 10 次时上报失速故障(LOSE_SPEED_FAILURE)。
        {
            if (cntLoseSpeed < LOSE_SPEED_DBC)
            {
                cntLoseSpeed++;
            }
            else
            {
                cntLoseSpeed = 0;
                oldSpeed = 0;
                g_protector.loseSpeedProFlag = 1;
                #if (defined STARTUP_CHECK_RESTART_ENABLE)
                #else
                Fault_Report(LOSE_SPEED_FAILURE);//上报失速错误
                #endif
            }
        }
        else
        {
            cntLoseSpeed = 0;
//            Fault_Clear(LOSE_SPEED_FAILURE);
        }
        oldSpeed = speed;
    }
}

使用特权

评论回复
40
狗啃模拟|  楼主 | 2023-9-30 11:12 | 只看该作者
ZeroSpeed_Check 零速保护
/*!
* @brief Motor Zero Speed protection.
*转速低于设定阈值,且连续达到 2 次时上报零速故障(ZERO_SPEED_FAILURE)。
* @param[in] none
* @return none
*/
void ZeroSpeed_Check(int16_t speed)
{
    static uint16_t s_zeroSpeedCnt = 0;

    if (g_startUpCtrl.startUpFlag >= 6)
    {
        if (Math_Qabs(speed) < ZERO_SPEED_THRESHOLD)
        {
            if (s_zeroSpeedCnt < ZERO_SPEED_DBC)
            {
                s_zeroSpeedCnt++;
            }
            else
            {
                s_zeroSpeedCnt = 0;
                g_protector.zeroSpeedProFlag = 1;
                #if (defined STARTUP_CHECK_RESTART_ENABLE)
                #else
                Fault_Report(ZERO_SPEED_FAILURE);
                #endif
            }
        }
        else
        {
            s_zeroSpeedCnt = 0;
//            Fault_Clear(ZERO_SPEED_FAILURE);
        }
    }

}

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则