views:

68

answers:

2

I have many (~100 or so) filter coefficients calculated with the aid of some Matlab and Excel that I want to dump into a C header file for general use, but I'm not sure what the best way to do this would be. I was starting out as so:

#define BUTTER 1
#define BESSEL 2
#define CHEBY 3
#if FILT_TYPE == BUTTER
    #if FILT_ROLLOFF == 0.010
        #define B0 256
        #define B1 512
        #define B2 256
        #define A1 467
        #define A2 -214
    #elif FILT_ROLLOFF == 0.015
        #define B0 256
        #define B1 512
// and so on...

However, if I do that and shove them all into a header, I need to set the conditionals (FILT_TYPE, FILT_ROLLOFF) in my source before including it, which seems kinda nasty. What's more, if I have 2+ different filters that want different roll-offs/filter types it won't work. I could #undef my 5 coefficients (A1-2, B0-2) in that coefficients file, but it still seems wrong to have to insert an #include buried in code.

Edit: This is for an embedded 8-bit processor with very small (2-4K) code space. I cannot seem to accomplish this by storing them into an array of structs because the space it consumes is unacceptable. Even declaring them all constant, my compiler will not 'optimize them away' so I'm left with a shade over 1.2K of extra binary data.

The below does not work.

typedef struct { 
    int16_t b0, b1, b2, a1, a2;
} filtCoeff;

const filtCoeff butter[41] = {
    {256,512,256,467,-214},
    {256,512,256,444,-196},
    {255,512,255,422,-179},
    // ...
};
const filtCoeff bessel[41]  // ...
+3  A: 

Put the filter coefficients in an array of structs. Instead of worrying about header files, I would just put the declaration of the array pointer in the .h files and define them in a specific .c file that you link in.

clahey
although that rules out some possible optimizations, it definitely is a much cleaner solution.
xtofl
Forgot to mention that this is for small 8-bit embedded targets, so the 40 rolloffs * 3 types * 5 coeffs * 2 bytes = 1200 bytes of data that consumes blows away a huge part of my Flash.
Nick T
+2  A: 

You could use token concatenation to get these to be parameters to a macro.

#define BUTTER 1
#define BESSEL 2
#define CHEBY 3

#define ROLLOFF_0_010 1
#define ROLLOFF_0_015 2

// BUTTER, ROLLOFF_0_010
#define B0_11 256
#define B1_11 512
#define B2_11 256
#define A1_11 467
#define A2_11 -214

// BUTTER, ROLLOFF_0_015
#define B0_12 256
#define B1_12 512
// ...

#define B0_(type, rolloff) (BO_##type##rolloff)
#define B1_(type, rolloff) (B1_##type##rolloff)
#define B2_(type, rolloff) (B2_##type##rolloff)
#define A1_(type, rolloff) (A1_##type##rolloff)
#define A2_(type, rolloff) (A2_##type##rolloff)

/*
 * This two level define is so that the parameters to these macros
 * get run through the macro process.   That is, B1_(BUTTER, ROLLOFF_0_010) 
 * evaluates as B1_BUTTERROLLOFF_0_010, while B1(BUTTER, ROLLOFF_0_010)
 * evaluates as B1_11 and thus as 256.
 */

#define B0(type, rolloff) B0_(type, rolloff)
#define B1(type, rolloff) B1_(type, rolloff)
#define B2(type, rolloff) B2_(type, rolloff)
#define A1(type, rolloff) A1_(type, rolloff)
#define A2(type, rolloff) A2_(type, rolloff)

B1(BUTTER, ROLLOFF_0_015) is now equivalent to 512. Then you can build any more complicated things as macros. E.g.:

#define CROSSPRODUCT(type, rolloff, values) \
    B0(type, rolloff) * ((values)[0]) + \
    B1(type, rolloff) * ((values)[1]) + \
    ...

You could also put your code in another file and use TYPE and ROLLOFF. Then just #define TYPE and ROLLOFF and include the other file. I think I prefer using a macro though.

clahey