Эффективное среднее из трех значений в C


Мы считываем некоторые сигналы с контактов и устанавливаем еще несколько событий, основанных на этом чтении.

Чтобы быть в безопасности, я хочу попробовать булавки 3 раза, сравнить три значения и использовать наиболее распространенное значение (т. е. образец A равен 1, B равен 3 и C равен 1, я хочу использовать 1, Если A B и C все 2, то используйте 2, но если A равен 1, B равен 2 и C равен 3, я хочу снова захватить три образца).

В настоящее время я использую:

int getCAPValues (void)
{
//  Get three samples to check CAP signals are stable:  

        uint32_t x = (PORT->Group[IN_PORT_CAP].IN.reg & IN_PORT_CAP_MASK) >> IN_PORT_CAP_PIN;           // First set of CAP values
        for (uint32_t i = 0; i < 7; i++) dummy = i;                                                     // Pause
        uint32_t y = (PORT->Group[IN_PORT_CAP].IN.reg & IN_PORT_CAP_MASK) >> IN_PORT_CAP_PIN;           // second set
        for (uint32_t i = 0; i < 7; i++) dummy = i;                                                     // Pause
        uint32_t z = (PORT->Group[IN_PORT_CAP].IN.reg & IN_PORT_CAP_MASK) >> IN_PORT_CAP_PIN;           // third set

        if (x == y) || (x == z)
        {
            //use the x value
        }
        else if (y == z)
        {
            // use the y value
            x = y;
        }
        else
        {           
            x = -1;
        }

    return x;
}

Но это не кажется мне очень эффективным, есть ли лучший способ чтобы сделать это?

Это на доске развития SAMD21 Xplained Pro В C.

Правка:

Я изменил код в соответствии с ответами, только читая значение "z", если оно будет использоваться, и используя delay_us () вместо фиктивных циклов:

int getCAPValues (void)
{
//  Get three samples to check CAP signals are stable:  

        uint32_t x = (PORT->Group[IN_PORT_CAP].IN.reg & IN_PORT_CAP_MASK) >> IN_PORT_CAP_PIN;           // First set of CAP values
        delay_us(1);
        //for (uint32_t i = 0; i < 7; i++) dummy = i;                                                   // Pause
        uint32_t y = (PORT->Group[IN_PORT_CAP].IN.reg & IN_PORT_CAP_MASK) >> IN_PORT_CAP_PIN;           // second set
        // Using most common value, or error code of -1 if all different

        if (!(x == y))
        {
            delay_us(1);
            //for (uint32_t i = 0; i < 7; i++) dummy = i;                                               // Pause
            uint32_t z = (PORT->Group[IN_PORT_CAP].IN.reg & IN_PORT_CAP_MASK) >> IN_PORT_CAP_PIN;       // third set
            if (x == z)
            {
                // use the x/z value
                return x;
            }
            else if (y == z)
            {
                // use the y/z value
                return y;
            }
            else
            {           
                return -1;
            }
        }
    return x;
}
2 7

2 ответа:

Если x==y вы собираетесь использовать значение x. Так что в этом случае вы можете уклониться от третьего чтения.

Я не знаю, насколько изменчивы ваши значения, но это может эффективно почти удвоить производительность, чтобы избежать этой второй задержки, если спорные значения на самом деле редки.

Действительно, если они не редки, то все обоснование может быть недействительным.

int getCAPValues (void)
{
//  Get three samples to check CAP signals are stable:  

        uint32_t x = (PORT->Group[IN_PORT_CAP].IN.reg & IN_PORT_CAP_MASK) >> IN_PORT_CAP_PIN;           // First set of CAP values
        for (uint32_t i = 0; i < 7; i++) dummy = i;                                                     // Pause
        uint32_t y = (PORT->Group[IN_PORT_CAP].IN.reg & IN_PORT_CAP_MASK) >> IN_PORT_CAP_PIN;           // second set
        if(x!=y){
            //x & y are different. Get a tie-breaker...
            for (uint32_t i = 0; i < 7; i++) dummy = i;                                                     // Pause
            uint32_t z = (PORT->Group[IN_PORT_CAP].IN.reg & IN_PORT_CAP_MASK) >> IN_PORT_CAP_PIN;           // third set
            if (y == z) {
                // use the y value
                x = y;
            } else if(x!=z){
                //tie-breaking failed...
                x=-1;
            }
        }
        return x;
}
PS: Я также думаю, что вы должны использовать ' usleep ()', а не фиктивные циклы. Это зависит от того, что доступно на вашей платформе.

Если вы можете предположить, что x, y а z - это либо 0, либо 1. Тогда вы можете просто использовать x+y+z>1 (если большинство из них 1 , то сумма больше, чем 1, и сравнение оценивается в 1, а в противном случае оно оценивается в 0).

В противном случае ваше (второе) решение, вероятно, является наиболее эффективным. По крайней мере, если вы не знаете вероятностей исходов. Кроме того, засыпание на одну микросекунду будет самой трудоемкой операцией.

Что вы следует учитывать, однако, что, поскольку считывания, вероятно, энергонезависимы, это может отличаться, если вы действительно делаете третье чтение или нет. Кроме того, вы должны, возможно, рассмотреть, если вам нужно сделать полное перечитывание. Если вы, например, считаете, что если первые три чтения из портов все разные, а четвертое чтение равно второму или третьему, вы можете пойти на это, вы можете использовать это в качестве оптимизации. Например:

 x = read_port();
 y = read_port();

 if( x == y )
    return x;

 for(;;) {
    z = read_port();
    if( z == x || z == y )
        return z;
    x = y;
    y = z;
 }