通过查找确定数组元素的最快方法 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
希望每个人都过得很好。我现在正在做一个四轴飞行器项目,我设计了一个基于增益调度的控制器。
我正在使用四轴飞行器的横滚角、俯仰角和偏航角来确定操作间隔。让我解释一下基本思想:
我把横滚、俯仰、偏航分成了四个操作区间。它们是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