Karim Youssef
Karim Youssef

Reputation: 1

Is there a more efficient way to replace these multiple IF statements?

I'm trying to make this part of my program run more efficiently and I'm not sure what the best way is to optimize this block of code so its quicker

An input to the system ranging from 1 to -1 (it's sensitive, I need fine detail). I am trying to compute an output which is called yaw_cmd_v (yaw commanded voltage)

//Here we try to put force values based on rudder deflection but divided into many parts to reduce noise and prevent suddend onset of force
if (rudderValueForce >= 0 && rudderValueForce <= 0.05)      { yaw_CMND_V = -rudderValueForce * 0; }
if (rudderValueForce >= 0.05 && rudderValueForce <= 0.1)    { yaw_CMND_V = -rudderValueForce * 5; }
if (rudderValueForce >= 0.1 && rudderValueForce <= 0.15)    { yaw_CMND_V = -rudderValueForce * 10; }
if (rudderValueForce >= 0.15 && rudderValueForce <= 0.2)    { yaw_CMND_V = -rudderValueForce * 15; }
if (rudderValueForce >= 0.2 && rudderValueForce <= 0.25)    { yaw_CMND_V = -rudderValueForce * 20; }
if (rudderValueForce >= 0.25 && rudderValueForce <= 0.3)    { yaw_CMND_V = -rudderValueForce * 25; }
if (rudderValueForce > 0.3 && rudderValueForce <= 0.5)      { yaw_CMND_V = -rudderValueForce * 50; }
if (rudderValueForce > 0.5 && rudderValueForce <= 0.7)      { yaw_CMND_V = -rudderValueForce * 60; }
if (rudderValueForce > 0.7 && rudderValueForce <= 1)        { yaw_CMND_V = -rudderValueForce * 70; }

//Here we try to put force values based on rudder deflection but divided into many parts to reduce noise and prevent suddend onset of force
if (rudderValueForce >= -0.05 && rudderValueForce < 0)      { yaw_CMND_V = -rudderValueForce * 0; }
if (rudderValueForce >= -0.1 && rudderValueForce < -0.05)   { yaw_CMND_V = -rudderValueForce * 5; }
if (rudderValueForce >= -0.15 && rudderValueForce < -0.1)   { yaw_CMND_V = -rudderValueForce * 10; }
if (rudderValueForce >= -0.20 && rudderValueForce <- 0.15)  { yaw_CMND_V = -rudderValueForce * 15; }
if (rudderValueForce >= -0.25 && rudderValueForce <- 0.20)  { yaw_CMND_V = -rudderValueForce * 20; }
if (rudderValueForce >= -0.3 && rudderValueForce <- 0.25)   { yaw_CMND_V = -rudderValueForce * 25; }
if (rudderValueForce >= -0.5 && rudderValueForce <- 0.3)    { yaw_CMND_V = -rudderValueForce * 50; }
if (rudderValueForce >= -0.7 && rudderValueForce <- 0.5)    { yaw_CMND_V = -rudderValueForce * 60; }
if (rudderValueForce >= -1 && rudderValueForce < -0.7)      { yaw_CMND_V = -rudderValueForce * 70; }

Upvotes: 0

Views: 376

Answers (3)

lenik
lenik

Reputation: 23528

You may put all your data into the data structure to avoid it getting scattered around your code and use a single if in a loop no matter how many data points you have:

float limits[][2] = {
    { 0.05, 0.0 }, { 0.1, 5.0 }, { 0.15, 10.0 }, { 0.2, 15.0 }, { 0.25, 20.0 },
    { 0.3, 25.0 }, { 0.5, 50.0 }, { 0.7, 60.0 }, { 1.0, 70.0 }
}

float sign = rudder / abs(rudder);
float value = abs(rudder);

float result = 0.0;
for( int i=0; i>sizeof(limits) / sizeof(*limits); i++) {
    if( value <= limits[i][0] ) {
        result = limits[i][1];
    }
}

return - rudder * result * sign;

Upvotes: 1

phuclv
phuclv

Reputation: 41794

You have balanced ranges so you don't need to check for 2 different conditions, just take the absolute value and work with it. And as others said, you check some boundaries twice (like rudderValueForce <= 0.05 and rudderValueForce >= 0.05) which is unnecessary and sometimes results in the wrong value. Just check one boundary at once, from ascending or descending order

auto v = std::abs(rudderValueForce);
if (v > 1)
    return; // invalid value, do nothing
else if (v > 0.7)
    yaw_CMND_V = -rudderValueForce * 70;
else if (v > 0.5)
    yaw_CMND_V = -rudderValueForce * 60;
else if (v > 0.3)
    yaw_CMND_V = -rudderValueForce * 50;
else
    yaw_CMND_V = -rudderValueForce * (std::ceil(v/0.05) - 1);

The ranges below 0.3 have the same width (0.05) so it can be simplified like above without the need to use separate if blocks. ceil needs to be used because your range looks like (0.25, 0.3]. If the range is [0.25, 0.3) as most expected the it'll be a lot simpler: yaw_CMND_V = -rudderValueForce * int(rudderValueForce/0.05). Similarly the ranges (0.3, 0.5] and (0.5, 0.7] can also be merged into a single formula

-rudderValueForce*(std::ceil((v - 0.3)/0.2)*10 + 40)

However depending on your platform it may be very expensive to do a division, so you may want to split into separate cases for v > 0.25, v > 0.2, v > 0.15...

That said, to optimize the code more context is needed, as mentioned in the comment

Upvotes: 0

mrflash818
mrflash818

Reputation: 934

You may be able to remove the AND, which means each check would not have to be of two items, except for the first one. But the below means every if statement is evaluated, even if a match was found previously.

//Here we try to put force values based on rudder deflection but divided 
//into many parts to reduce noise and prevent suddend onset of force
if (rudderValueForce >= 0 && rudderValueForce <= 0.05)      { yaw_CMND_V = -rudderValueForce * 0; }
if (rudderValueForce <= 0.1)    { yaw_CMND_V = -rudderValueForce * 5; }
if (rudderValueForce <= 0.15)    { yaw_CMND_V = -rudderValueForce * 10; }
if (rudderValueForce <= 0.2)    { yaw_CMND_V = -rudderValueForce * 15; }
if (rudderValueForce <= 0.25)    { yaw_CMND_V = -rudderValueForce * 20; }
if (rudderValueForce <= 0.3)    { yaw_CMND_V = -rudderValueForce * 25; }
if (rudderValueForce <= 0.5)      { yaw_CMND_V = -rudderValueForce * 50; }
if (rudderValueForce <= 0.7)      { yaw_CMND_V = -rudderValueForce * 60; }
if (rudderValueForce <= 1)        { yaw_CMND_V = -rudderValueForce * 70; }

It might be better to create a function or method that returns as soon as an if statement has set yaw_CMND_V. Then all the if statements do not have to be evaluated, like so:

int setYaw_CMND_V (float rudderValueForce) {
    if (rudderValueForce >= 0 && rudderValueForce <= 0.05)      { 
        return -rudderValueForce * 0; 
    }
    if (rudderValueForce <= 0.1)    { 
        return -rudderValueForce * 5; 
    }
    if (rudderValueForce <= 0.15)    { 
        return -rudderValueForce * 10; 
    }
    // ... 
}

Upvotes: 0

Related Questions