Почему направление цикла моего фильтра меняет мой результат?

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

#include "../include/Filter.h"

void Filter(int DataIn, int* DataOut, bool Enable)
{
    static coef_t Coefficients[] = {
            0.0076925293, -0.039817952, 0.018740745, 0.013075141, -0.052312399,
            0.052374545, 0.017044802, -0.14227364, 0.26541378, 0.68194015, 0.26541378,
            -0.14227364, 0.017044802, 0.052374545, -0.052312399, 0.013075141, 0.018740745,
            -0.039817952, 0.0076925293
    };

    static data_t ShiftRegRight[LENGTH];
    static data_t ShiftRegLeft[LENGTH];

    acc_t AccRight = 0x00;
    acc_t AccLeft = 0x00;

    if(Enable == true)
    {
        Shift_Accum_Loop: for(int i = (LENGTH - 1); i >= 0; i--)
        {
            if(i == 0)
            {
                ShiftRegRight[0] = DataIn & 0x0000FFFF;
                ShiftRegLeft[0] = (DataIn & 0xFFFF0000) >> 0x10;
            }
            else
            {
                ShiftRegRight[i] = ShiftRegRight[i - 1];
                ShiftRegLeft[i] = ShiftRegLeft[i - 1];
            }

            AccRight += ShiftRegRight[i] * Coefficients[i];
            AccLeft += ShiftRegLeft[i] * Coefficients[i];
        }

        *DataOut = ((AccLeft.range() >> 0x20) << 0x10) | (AccRight.range() >> 0x20);
    }
    else
    {
        *DataOut = DataIn;
    }
}

Этот фильтр производит следующие выходные данные для заданного тестового сигнала:

0, 0, 0
1, 28377, 218
2, 0, 64405
3, 0, 531
4, 0, 370
5, 37159, 63833
6, 0, 2616
7, 37159, 65269
8, 0, 62257
9, 0, 8484
10, 0, 17494
11, 28377, 8750
12, 0, 62919
13, 28377, 58754
14, 0, 50948
15, 0, 48035
16, 0, 52449
17, 37159, 56833
18, 0, 0
19, 37159, 8484
20, 0, 14216
21, 0, 16968
22, 0, 14216
...

Тестовый сигнал генерируется с помощью тестового стенда:

#include <math.h>
#include <stdio.h>

#include "../include/Filter.h"

#define SAMPLES                 48000
#define FREQ_RIGHT_1            8000
#define FREQ_RIGHT_2            10000
#define FREQ_LEFT_1             50

FILE* File;

int main(void)
{
    int Output;
    int StreamData;
    uint16_t RightChannel = 0x00;
    uint16_t LeftChannel = 0x00;

    File = fopen("Result.log", "w");
    for(int i = 0x00; i < SAMPLES; i++)
    {
        // Generate the input data
        RightChannel = 32767 * sin(2 * M_PI * i / (SAMPLES / FREQ_RIGHT_1)) * sin(2 * M_PI * i / (SAMPLES / FREQ_RIGHT_2));
        StreamData = (LeftChannel << 0x10) | RightChannel;

        // Execute the function with latest input
        Filter(StreamData, &Output, true);

        // Write the simulation results
        fprintf(File, "%i, %d, %d\n", i, StreamData, Output);
    }

    fclose(File);
}

Итак, почему я получаю другой результат, когда я меняю цикл for в Filter с цикла обратного счета на цикл восходящего счета?

if(Enable == true)
{
    Shift_Accum_Loop: for(int i = 0; i < (LENGTH - 1); i++)
    {
        if(i == 0)
        {
            ...

0, 0, 0
1, 28377, 27073
2, 0, 0
3, 0, 0
4, 0, 0
5, 37159, 38462
6, 0, 0
7, 37159, 38462
8, 0, 0
9, 0, 0
10, 0, 0
11, 28377, 27073

В чем разница между этим? Циклы в обоих случаях считаются от 0 до (LENGTH - 1), и фильтр является симметричным. Почему направление счета влияет на результат?


person Kampi    schedule 20.05.2020    source источник
comment
Совершенно не связано с вашей проблемой, но для чего нужен ярлык Shift_Accum_Loop? Вы планируете использовать goto? Тогда не надо. Если у вас есть это в качестве комментария к циклу, то, пожалуйста, напишите вместо этого правильный комментарий, в котором объясняется, что делает цикл и почему цикл делает это именно так.   -  person Some programmer dude    schedule 20.05.2020
comment
Что касается вашей проблемы, пытались ли вы пройти через различные реализации цикла, оператор за оператором, в отладчике? И подумайте о присваивании, таком как ShiftRegRight[i] = ShiftRegRight[i - 1];, и о том, какими могут быть начальные значения массива ShiftRegRight.   -  person Some programmer dude    schedule 20.05.2020
comment
@Someprogrammerdude метка предназначена только для директив HLS, а не для какого-то goto или чего-то в этом роде.   -  person Kampi    schedule 20.05.2020


Ответы (1)


if(i == 0)
        {
            ShiftRegRight[0] = DataIn & 0x0000FFFF;
            ShiftRegLeft[0] = (DataIn & 0xFFFF0000) >> 0x10;
        }
        else
        {
            ShiftRegRight[i] = ShiftRegRight[i - 1];
            ShiftRegLeft[i] = ShiftRegLeft[i - 1];
        }

При обратном отсчете i==0 оценивается как true последним.

Когда вы подсчитываете, i==0 сначала оценивается как true.

person Roy2511    schedule 20.05.2020