通过查找确定数组元素的最快方法 Table

Fastest Method to Determine the Elements of an Array From Look-up Table

希望每个人都过得很好。我现在正在做一个四轴飞行器项目,我设计了一个基于增益调度的控制器。

我正在使用四轴飞行器的横滚角、俯仰角和偏航角来确定操作间隔。让我解释一下基本思想:

我把横滚、俯仰、偏航分成了四个操作区间。它们是0-30度、30-50度、50-70度和70-90度。因此,对于滚转控制,我有 4 个 PID 控制器增益集,用于俯仰控制的 4 个 PID 控制器增益集,以及用于偏航控制的 4 个 PID 控制器增益集。每个增益集包含 3 个元素。该方法有一个简单的查找 table(每个增益集是 3 的数组,包括比例、积分和微分增益):

此查找 table 分别针对横滚角、俯仰角和偏航角构建。正如我提到的,增益集是 3 个元素的数组。

要为横滚角、俯仰角和偏航角找到合适的增益集,我不知道在 C 中使用哪种方法最快,因为我要在微控制器上实现这种增益调度方法,而这增益调度方法将在中断函数中运行。

恐怕 if-else 结构对于我的需要来说太慢了,因此想听听您的意见。非常感谢您。

这是我写的代码片段(它只涵盖了 Roll/Phi 控制部分):

...
float Phi_Gain_Set_0_30[3] = {5.1838, 0.3882, 0};
float Phi_Gain_Set_30_50[3] = {5.1838, 0.3882, 0};
float Phi_Gain_Set_50_70[3] = {5.1838, 0.3882, 0};
float Phi_Gain_Set_70_90[3] = {5.1838, 0.3882, 0};
...

void scheduleGains(float *rollGainSet, float *pitchGainSet, float *yawGainSet, float phi_deg, float theta_deg, float psi_deg)
{
    if (phi_deg >= 0 && phi_deg < 30)
    {
        float Kp_phi = Phi_Gain_Set_0_30[0];
        float Kd_phi = Phi_Gain_Set_0_30[1];
        float Ki_phi = Phi_Gain_Set_0_30[2];
    }
    else if (phi_deg >= 30 && phi_deg < 50)
    {
        float Kp_phi = Phi_Gain_Set_30_50[0];
        float Kd_phi = Phi_Gain_Set_30_50[1];
        float Ki_phi = Phi_Gain_Set_30_50[2];
    }
    else if (phi_deg >= 50 && phi_deg < 70)
    {
        float Kp_phi = Phi_Gain_Set_50_70[0];
        float Kd_phi = Phi_Gain_Set_50_70[1];
        float Ki_phi = Phi_Gain_Set_50_70[2];
    }
    else if (phi_deg >= 70 && phi_deg < 90)
    {
        float Kp_phi = Phi_Gain_Set_70_90[0];
        float Kd_phi = Phi_Gain_Set_70_90[1];
        float Ki_phi = Phi_Gain_Set_70_90[2];
    }
    else
    {
        float Kp_phi = Phi_Gain_Set_0_30[0];
        float Kd_phi = Phi_Gain_Set_0_30[1];
        float Ki_phi = Phi_Gain_Set_0_30[2];
    }

    rollGainSet[0] = Kp_phi;
    rollGainSet[1] = Kd_phi;
    rollGainSet[2] = Ki_phi;


}

正如其他人评论的那样,它可能已经足够快了。那么何必呢?

无论如何,正如 Nick ODell 指出的那样,在一般情况下,您的比较是无用的复杂。每个 if 使用一个栅栏就足够了。此外,您可以使用 memcpy 使代码更短更清晰。

#include <stdio.h>
#include <string.h>

float Phi_Gain_Set_0_30[3] = {5.1838, 0.3882, 0};
float Phi_Gain_Set_30_50[3] = {1, 2, 3};
float Phi_Gain_Set_50_70[3] = {4, 5, 6};
float Phi_Gain_Set_70_90[3] = {7, 8, 9};

void scheduleGains(float *rollGainSet, float *pitchGainSet, float *yawGainSet, float phi_deg, float theta_deg, float psi_deg)
{
    if (phi_deg < 30) {
        memcpy(rollGainSet, Phi_Gain_Set_0_30, sizeof(float[3]));
    }
    else if (phi_deg < 50) {
        memcpy(rollGainSet, Phi_Gain_Set_30_50, sizeof(float[3]));
    }
    else if (phi_deg < 70) {
        memcpy(rollGainSet, Phi_Gain_Set_50_70, sizeof(float[3]));
    }
    else if (phi_deg < 90) {
        memcpy(rollGainSet, Phi_Gain_Set_70_90, sizeof(float[3]));
    }
    else {
        memcpy(rollGainSet, Phi_Gain_Set_0_30, sizeof(float[3]));
    }
}

int main(void) 
{
    float test_angles[] = { 17.3, 22.99, 81.398, 65.2 };
    size_t ntests = sizeof test_angles / sizeof *test_angles;
    
    for (size_t i = 0; i < ntests; ++i) {
        float rgs[3];
        scheduleGains(rgs, NULL, NULL, test_angles[i], 0, 0);
        printf("phi_deg=%g --> {%g, %g, %g}\n", test_angles[i], rgs[0], rgs[1], rgs[2]);
    }
    
    return 0;
}

下次帮我们打个Minimal, Reproducible Example,也打个main()

平均而言,通过在该范围内使用二进制搜索,您可以做得更好(如果需要):

void scheduleGains(float *rollGainSet, float *pitchGainSet, float *yawGainSet, float phi_deg, float theta_deg, float psi_deg)
{
    if (phi_deg < 50) {
        if (phi_deg < 30) {
            memcpy(rollGainSet, Phi_Gain_Set_0_30, sizeof(float[3]));
        }
        else {
            memcpy(rollGainSet, Phi_Gain_Set_30_50, sizeof(float[3]));
        }
    }
    else {
        if (phi_deg < 70) {
            memcpy(rollGainSet, Phi_Gain_Set_50_70, sizeof(float[3]));
        }
        else {
            if (phi_deg < 90) {
                memcpy(rollGainSet, Phi_Gain_Set_70_90, sizeof(float[3]));
            }
            else {
                memcpy(rollGainSet, Phi_Gain_Set_0_30, sizeof(float[3]));
            }
        }
    }
}

这为您提供了 0-30、30-50、50-70 的 2 次比较和 70-90 或更多的 3 次比较。但我不相信这会产生任何影响。此外,如果 phi_deg 值较低的概率很高,则第一个版本更好。一如既往:

It is a capital mistake to theorize before one has data. Sherlock Holmes