Close

Added a 1st order Butterworth High-pass IIR filter!

A project log for PIC32MX music box with FM synthesis and I2S DAC

Six-channel FM synthesis music box using PIC32MX250F128B microcontroller with envelope generator.

nyh-workshopNYH-workshop 01/14/2018 at 06:150 Comments

Man, the first and the second week of this year is rough as the weather isn't looking good!

However, after for so many experimentation, I have squeezed out an IIR filter. To try the code, I have used the book "Real time Digital Signal Processing from Matlab to C with the TMS320Cx DSPs", Matlab/Octave and an online C compiler before putting this into the microcontroller:

/******************************************************************************

                            Online C Compiler.
                Code, Compile, Run and Debug C program online.
Write your code in this editor and press "Run" button to compile and execute it.

*******************************************************************************/

#include <stdio.h>

float b[2] = {0.9980, -0.9980};
float a[2] = {1.0000, -0.9961};
float array1[8+1] = {0.000 ,0.000, 0.7071, 0.8660, 1.000, 0.8660, 0.7071, 0.000, -0.7071};
float array2[8+1] = {0.000 ,-0.8660, -1, -0.8660, -0.7071, 0.0000, 0.7071, 0.8660, 1.000};
float x[8];
float y1[9] = { 0 };
float y2[9] = { 0 };

int main()
{
    for(int i = 1; i <= 8; i++) {
        array1[i] = array1[i] + 2.0;
        //printf("%f\n", array1[i]);
    }
    
    for(int i = 1; i <= 8; i++) {
        array2[i] = array2[i] + 2.0;
        //printf("%f\n", array1[i]);
    }


    printf("IIR first order Butterworth, high-pass, cutoff 20Hz:\n");
    for(int n = 1; n <= 8; n++) {
        y1[n] = -1.000*a[1]*y1[n-1] + b[0]*array1[n] + b[1]*array1[n-1];
    }
    
    y2[0]     = y1[8];
    array2[0] = array1[8];
    
    for(int n = 1; n <= 8; n++) {
        y2[n] = -1.000*a[1]*y2[n-1] + b[0]*array2[n] + b[1]*array2[n-1];
    }
    
    printf("Array1 and Array2:\n");
    for(int i = 1; i <= 8; i++) {
        printf("%f, ", y1[i]);
    }
    
    for(int i = 1; i <= 8; i++) {
        printf("%f, ", y2[i]);
    }
    

    return 0;
}

 I tested the code with a small float input and output array with 8 + 1 elements (the one (1) is for saving the previous output) and the coefficients are generated using Matlab/Octave:

Fc = 20;        % cutoff.
Fs = 32000;  % sampling rate.
[b,a] = butter(1, Fc/(Fs/2), 'high');

After confirming the output, I pasted and modified the code to fit into the microcontroller project. Using the mentioned book as a reference [Chapter 6: Frame Based DSP], the resulting code is this in the XC32 and Bruce Land's DSP routines for the 16.16 fixed point ones:

outputData_fix16[0] = prev_output_value_fix16[0];
inputData[0]        = prev_input_value[0];

for (i = 1; i <= BUFFER_LENGTH/2; i++) {

    outputData_fix16[i] = multfix16(-1 * coeff_a_fp[1], outputData_fix16[i - 1]) + multfix16(coeff_b_fp[0], short2fix16(inputData[i])) + multfix16(coeff_b_fp[0], short2fix16(inputData[i]));
            
}

prev_output_value_fix16[0] = outputData_fix16[BUFFER_LENGTH/2];
prev_input_value[0]        = inputData[BUFFER_LENGTH/2];

Coefficients:

// Fixed point coefficients for 20hz cutoff 1st order high pass Butterworth filter:
// (in 16.16 format)
fix16 coeff_b_fp[2] = { 65405, -65405 };
fix16 coeff_a_fp[2] = { 65536, -65280 };

// The same coefficients, but in floating point.    
float coeff_b[2] = {0.9980, -0.9980};
float coeff_a[2] = {1.0000, -0.9961};

It works... but I gotta need to tune down the amplitude for whatever it is from the input or else the thing wraps around and make awful noises. If I have the saturate algorithm inside, it would sound less unpleasent, but I prefer to keep the audio amplitude in range.

On top of that, I have added class functionality on that filter, but it refuses to work in MPLAB Harmony. Instead, I put aside that class thingy (might be useful for anything 32-bits Arduino-related) and work on the limitations on this platform first! 

Discussions