c++vivadovivado-hls

Why does the loop direction of my filter change my result?


I have designed a simple dual channel filter to remove some noise at a given frequency.

#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;
    }
}

This filter produce the following output on a given test signal:

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
...

The test signal is generated with a testbench:

#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);
}

So why do I get a different output, when I change the for loop in Filter from a down counting loop into a upcounting loop?

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

What is the difference between this? The loops do count from 0 to (LENGTH - 1) in both cases and the filter is symetric. Why does the count direction has an impact on the result?


Solution

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

    When you count down i==0 evaluates to true last.

    When you count up i==0 evaluates to true first.