взвешенное среднее с целыми числами - PullRequest
1 голос
/ 13 апреля 2011

Ситуация: у нас есть целочисленный микроконтроллер, и нам нужно вычислить средневзвешенное значение (например, вес 32, например, 31-1) и сохранить его в массиве.

Окончательный код будет в C.

(И, чтобы быть уверенным, это не домашняя работа :))

Мы думали сохранить результат деления модуля на вес на результате (avg calc) и использовать его в следующем раунде в качестве дополнительных данных.

Если бы у нас был float, это было бы так:

avg[i] = ( avg[i-1] * (WEIGHT-1) + measured ) / WEIGHT;

Поскольку мы этого не делаем, я подумал:

pt = (mod == 0) ? WEIGHT-1 : WEIGHT-2;
tmp = avg[i-1] * pt + mod + measured;
avg[i] = tmp / WEIGHT;
mod = tmp % WEIGHT;

Но это, кажется, дает мне ложные результаты, и я действительно застрял с реализацией.

У кого-нибудь есть идеи?


EDIT

Большое спасибо за быстрые ответы, хотя, возможно, я не задал вопрос достаточно ясно: у нас есть коэффициент необходимого веса от предыдущего среднего значения и текущей выборки.

Ответы [ 4 ]

4 голосов
/ 29 ноября 2012

Если вы попали на эту страницу с помощью поиска Google и ищете более простую реализацию приведенного выше кода, то вам может понравиться это.

Эта реализация предлагает меньше параметров конфигурации, так как имеет только 1 определение.Это может быть преимуществом или недостатком в вашем конкретном случае.

#define COEFFICIENT 32

static int sample_weighted = 0;
int output = 0;

sample_weighted *= COEFFICIENT - 1;
sample_weighted += raw_value * COEFFICIENT;
sample_weighted /= COEFFICIENT;

output = (sample_weighted + (COEFFICIENT/2) - 1) / COEFFICIENT;

Разница с обычным взвешенным фильтром заключается в том, что значение sample_weighted сохраняется, умноженное на COEFFICIENT.Таким образом, целочисленное вычисление может использоваться без ошибок округления, в результате чего вычисление «залипает» при неправильных значениях.При извлечении выходного значения целочисленное значение округляется и компенсируется для этого умножения.

Я думаю, что эта реализация более читаема, но у нее есть недостаток, заключающийся в том, что она использует деление вместо сдвига битов.Большинство компиляторов будут достаточно умны, чтобы использовать сдвиг битов, при условии, что КОЭФФИЦИЕНТ имеет степень 2.

0 голосов
/ 13 апреля 2011

Если вы хотите вычислить взвешенное среднее для двух наборов целых чисел, вы можете постепенно записать сумму каждой серии по мере поступления данных и увеличить количество записанных значений.

По мере поступления данных вы добавляете их к промежуточному итогу для этой серии.

int weighted_mean( int count_a, int sum_a, int count_b, int sum_b ){
  return = ((count_a * sum_a) + ( count_b * sum_b )) / ( sum_a + sum_b );
}

void recv_data( int a, int b )
{
  global_sum_a += a;
  global_count_a++;

  global_sum_b += b;
  global_count_b++;

  int weighted_mean_so_far = weighted_mean( global_count_a, global_sum_a, global_count_b, global_sub_b );

}
0 голосов
/ 02 мая 2011

ОК, мы нашли решение, сдвинув значения для наших нужд.

  #define TOTAL_WEIGHT 128
  #define SAMPLE_WEIGHT 24
  #define SHIFT 8
  #define SHIFT_VAL 256
  #define SHIFT_WEIGHT 7

  static int sample_weighted = 0;
  int output = 0;
  int sample_tmp = 0U;

    sample_tmp = sample_tmp << SHIFT;
    sample_tmp = sample_tmp * SAMPLE_WEIGHT;
    sample_weighted = sample_weighted * ( TOTAL_WEIGHT - SAMPLE_WEIGHT );
    sample_weighted = sample_weighted + sample_tmp;
    sample_weighted = sample_weighted >> SHIFT_WEIGHT;
    output  = (sample_weighted + (SHIFT_VAL/2) -1 ) >> SHIFT;
0 голосов
/ 13 апреля 2011
for (i = 0; i < num_elements; i++)
{
    sum_data += data[i] * weight[i];
    sum_weights += weight[i];
    average[i] = sum_data / sum_weights;
}

Очевидно, sum_data должен быть достаточно большого типа данных;Обойти это невозможно.

...