/* Bilinear Transform IIR Filter Example. Generates a low pass filter */ #include #include #include #include "GraphFunctions.h" /* Define constants */ #define SAMPLE_RATE ((SLData_t)10.0) #define PREWARP_MATCH_FREQUENCY SIGLIB_TWO #define REQUIRED_FILTER_GAIN ((SLData_t)10.0) #define NUMBER_OF_ZEROS 5L /* Can be changed for any number between 1 and 5 */ #define NUMBER_OF_POLES 5L /* Can be changed for any number between 1 and 5 */ #define IIR_FILTER_STAGES NUMBER_OF_POLES /* The greater of the number of poles or zeros */ #define NUMBER_OF_FILTER_COEFFS (SIGLIB_IIR_COEFFS_PER_BIQUAD*IIR_FILTER_STAGES) /* Total number of IIR filter coefficients */ #define IMPULSE_RESPONSE_LENGTH ((SLArrayIndex_t)1024) #define FFT_SIZE IMPULSE_RESPONSE_LENGTH #define LOG_FFT_SIZE ((SLArrayIndex_t)10) #define PLOT_LENGTH ((SLArrayIndex_t)(IMPULSE_RESPONSE_LENGTH/2)) /* Declare global variables */ /* Allocate arrays for the poles and zeros. For test pupRealDataoses, the array lengths are 1 larger than necessary, so that array lengths of 0 can be used */ SLComplexRect_s SPlaneZeros [NUMBER_OF_ZEROS+1]; SLComplexRect_s SPlanePoles [NUMBER_OF_POLES+1]; SLComplexRect_s ZPlaneZeros [NUMBER_OF_POLES+1]; /* NOTE - THIS ARRAY LENGTH IS SET TO THE SAME LENGTH AS THE NUMBER OF POLES BECAUSE WHEN A FILTER IS SPECIFIED IN THE S-DOMAIN WITH LESS ZEROS THEN POLES THE BILINEAR TRANSFORM ADDS ZEROS AT Fs/2 */ SLComplexRect_s ZPlanePoles [NUMBER_OF_POLES+1]; SLData_t pFilterState[IIR_FILTER_STAGES * SIGLIB_IIR_DELAY_SIZE]; SLData_t *pIIRCoeffs; SLData_t *pRealData, *pImagData, *pResults, *pStepData, *pFFTCoeffs; void main (void) { GraphObject *h2DGraph; /* Declare graph objects */ GraphObject *hPZGraph; SLFixData_t i; SLData_t Max; SLFixData_t NumberOfZeros = NUMBER_OF_ZEROS; /* Used for initialising correct number */ SLFixData_t NumberOfPoles = NUMBER_OF_POLES; /* of s-plane poles and zeros */ /* Allocate memory */ pIIRCoeffs = SUF_IirCoefficientAllocate (IIR_FILTER_STAGES); pImagData = SUF_VectorArrayAllocate (FFT_SIZE); pResults = SUF_VectorArrayAllocate (FFT_SIZE); pRealData = SUF_VectorArrayAllocate (IMPULSE_RESPONSE_LENGTH); pStepData = SUF_VectorArrayAllocate (IMPULSE_RESPONSE_LENGTH); pFFTCoeffs = SUF_FftCoefficientAllocate (FFT_SIZE); if ((pIIRCoeffs == NULL) || (pImagData == NULL) || (pResults == NULL) || (pRealData == NULL) || (pStepData == NULL) || (pFFTCoeffs == NULL)) { printf ("\n\nMemory allocation failure\n\n"); exit (0); } if (NumberOfZeros >= 1) SPlaneZeros[0] = SCV_Rectangular (((SLData_t)0.0), ((SLData_t)3.0)); /* Initialise s-plane zeros */ if (NumberOfZeros >= 2) SPlaneZeros[1] = SCV_Rectangular (((SLData_t)0.0), ((SLData_t)3.0)); if (NumberOfZeros >= 3) SPlaneZeros[2] = SCV_Rectangular (((SLData_t)0.0), ((SLData_t)3.0)); if (NumberOfZeros >= 4) SPlaneZeros[3] = SCV_Rectangular (((SLData_t)0.0), ((SLData_t)3.0)); if (NumberOfZeros >= 5) SPlaneZeros[4] = SCV_Rectangular (((SLData_t)0.0), ((SLData_t)3.0)); if (NumberOfPoles >= 1) SPlanePoles[0] = SCV_Rectangular (((SLData_t)-0.2), ((SLData_t)0.0)); /* Initialise s-plane poles */ if (NumberOfPoles >= 2) SPlanePoles[1] = SCV_Rectangular (((SLData_t)-0.3), ((SLData_t)0.0)); if (NumberOfPoles >= 3) SPlanePoles[2] = SCV_Rectangular (((SLData_t)-0.6), ((SLData_t)0.7)); if (NumberOfPoles >= 4) SPlanePoles[3] = SCV_Rectangular (((SLData_t)-0.8), ((SLData_t)0.6)); if (NumberOfPoles >= 5) SPlanePoles[4] = SCV_Rectangular (((SLData_t)-0.9), ((SLData_t)0.3)); printf ("\nComplex s-plane zeros\n"); /* Print s-plane poles and zeros */ for (i = 0; i < NumberOfZeros; i++) { print_rectangular (SPlaneZeros[i]); } printf ("\nComplex s-plane poles\n"); for (i = 0; i < NUMBER_OF_POLES; i++) { print_rectangular (SPlanePoles[i]); } printf ("Hit any key to continue . . ."); getchar (); /* Convert z-plane poles and zeros to s-plane */ /* using the bilinear transform */ SDA_BilinearTransform (SPlaneZeros, /* S-plane zeros */ SPlanePoles, /* S-plane poles */ ZPlaneZeros, /* Z-plane zeros */ ZPlanePoles, /* Z-plane poles */ SAMPLE_RATE, /* Sample rate */ PREWARP_MATCH_FREQUENCY, /* Pre-warp frequency */ SIGLIB_OFF, /* Pre-warp switch */ NumberOfZeros, /* Number of zeros */ NUMBER_OF_POLES); /* Number of poles */ NumberOfZeros = (SLArrayIndex_t)NUMBER_OF_POLES; /* If number of s-plane zeros < number of poles, additional zeros places at Fs/2 */ printf ("\nComplex z-plane zeros\n"); /* Print z-plane poles and zeros */ for (i = 0; i < NumberOfZeros; i++) { print_rectangular (ZPlaneZeros[i]); } printf ("\nComplex z-plane poles\n"); for (i = 0; i < NUMBER_OF_POLES; i++) { print_rectangular (ZPlanePoles[i]); } hPZGraph = /* Initialize graph */ CreatePoleZeroGraph("Pole-Zero Plot", /* Graph title */ "Real", /* X-Axis label */ "Imaginary", /* Y-Axis label */ SV_COMPLEX_ZERO, /* PZ Data type */ "localhost"); /* Graph server */ if (hPZGraph == NULL) /* Graph creation failed - e.g is server running ? */ { printf ("\nGraph creation failure. Please check that the server is running\n"); exit (1); } DisplayPZPlot(hPZGraph, /* Graph object */ "Poles", /* Title of dataset (for use on legends) */ (Complex_s *)ZPlanePoles, /* Array of complex values */ NUMBER_OF_POLES, /* Items of data */ SV_BLUE, /* Colour */ SV_GRAPH_NEW, /* Add / new mode */ SV_CONJUGATE_POLE); /* Pole-zero mode */ DisplayPZPlot(hPZGraph, /* Graph object */ "Zeros", /* Title of dataset (for use on legends) */ (Complex_s *)ZPlaneZeros, /* Array of complex values */ NumberOfZeros, /* Items of data */ SV_RED, /* Colour */ SV_GRAPH_ADD, /* Add / new mode */ SV_CONJUGATE_ZERO); /* Pole-zero mode */ printf ("Pole-zero plot\nHit any key to continue . . ."); getchar (); /* Convert poles and zeros to coefficients */ SDA_IirZplaneToCoeffs (ZPlaneZeros, /* Z-plane zeros */ ZPlanePoles, /* Z-plane zeros */ pIIRCoeffs, /* IIR filter coefficients */ NumberOfZeros, /* Number of zeros */ NUMBER_OF_POLES); /* Number of poles */ /* Apply filter gain function */ SDA_ModifyIirFilterGain (pIIRCoeffs, /* Pointer to source IIR filter coefficients */ pIIRCoeffs, /* Pointer to modified IIR filter coefficients */ SIGLIB_ZERO, /* Centre frequency normalised to 1 Hz */ REQUIRED_FILTER_GAIN, /* Desired gain */ IIR_FILTER_STAGES); /* Number of biquads */ /* Print filter coefficients */ printf ("\nIIR filter coefficients : b(0), b(1), b(2), a(1), a(2)\n\n"); for (i = 0; i < IIR_FILTER_STAGES; i++) { printf ("%le, %le, %le, %le, %le\n", *(pIIRCoeffs+(i*SIGLIB_IIR_COEFFS_PER_BIQUAD)), *(pIIRCoeffs+1+(i*SIGLIB_IIR_COEFFS_PER_BIQUAD)), *(pIIRCoeffs+2+(i*SIGLIB_IIR_COEFFS_PER_BIQUAD)), *(pIIRCoeffs+3+(i*SIGLIB_IIR_COEFFS_PER_BIQUAD)), *(pIIRCoeffs+4+(i*SIGLIB_IIR_COEFFS_PER_BIQUAD))); } printf ("Hit any key to see impulse, step and frequency response . . ."); getchar (); h2DGraph = /* Initialize graph */ Create2DGraph ("Bilinear Transform", /* Graph title */ "Time", /* X-Axis label */ "Magnitude", /* Y-Axis label */ SV_AUTO_SCALE, /* Scaling mode */ SV_SIGNED, /* Sign mode */ SV_GRAPH_LINE, /* Graph type */ "localhost"); /* Graph server */ if (h2DGraph == NULL) /* Graph creation failed - e.g is server running ? */ { printf ("\nGraph creation failure. Please check that the server is running\n"); exit (1); } /* Initialise IIR filter operation */ SIF_Iir (pFilterState, /* Pointer to filter state array */ IIR_FILTER_STAGES); /* Number of second order stages */ /* Generate impulse response */ SDA_SignalGenerate (pRealData, /* Pointer to destination array */ SIGLIB_IMPULSE, /* Signal type - Impulse function */ SIGLIB_ONE, /* Signal peak level */ SIGLIB_FILL, /* Fill (overwrite) or add to existing array contents */ SIGLIB_ZERO, /* Signal frequency - Unused */ SIGLIB_ZERO, /* D.C. Offset */ SIGLIB_ZERO, /* Unused */ SIGLIB_ZERO, /* Signal end value - Unused */ SIGLIB_NULL_DATA_PTR, /* Unused */ SIGLIB_NULL_DATA_PTR, /* Unused */ IMPULSE_RESPONSE_LENGTH) /* Output array length */; /* Apply iir filter and store filtered data */ SDA_Iir (pRealData, /* Input array to be filtered */ pRealData, /* Filtered output array */ pFilterState, /* Pointer to filter state array */ pIIRCoeffs, /* Pointer to filter coefficients array */ IIR_FILTER_STAGES, /* Number of stages */ IMPULSE_RESPONSE_LENGTH); /* Array length */ Display2DGraph (h2DGraph, /* Graph handle */ "Impulse response", /* Title of the dataset */ pRealData, /* Array of Double dataset */ PLOT_LENGTH, /* Number of data points */ SV_GRAPH_LINE, /* Graph type */ SV_MAGENTA, /* Colour */ SV_HIDE_MARKERS, /* Marker enable / disable */ SV_GRAPH_NEW); /* New graph */ printf ("\nImpulse response\nPlease hit to continue . . ."); getchar (); /* Re-initialise IIR filter operation */ SIF_Iir (pFilterState, /* Pointer to filter state array */ IIR_FILTER_STAGES); /* Number of second order stages */ /* Generate step response */ SDA_SignalGenerate (pStepData, /* Pointer to destination array */ SIGLIB_STEP, /* Signal type - Step function */ SIGLIB_ONE, /* Signal peak level */ SIGLIB_FILL, /* Fill (overwrite) or add to existing array contents */ SIGLIB_ZERO, /* Signal frequency - Unused */ SIGLIB_ZERO, /* D.C. Offset */ SIGLIB_ZERO, /* Unused */ SIGLIB_ZERO, /* Signal end value - Unused */ SIGLIB_NULL_DATA_PTR, /* Unused */ SIGLIB_NULL_DATA_PTR, /* Unused */ IMPULSE_RESPONSE_LENGTH); /* Output array length */ SDA_Iir (pStepData, /* Input array to be filtered */ pStepData, /* Filtered output array */ pFilterState, /* Pointer to filter state array */ pIIRCoeffs, /* Pointer to filter coefficients array */ IIR_FILTER_STAGES, /* Number of stages */ IMPULSE_RESPONSE_LENGTH); /* Array length */ Display2DGraph (h2DGraph, /* Graph handle */ "Step response", /* Title of the dataset */ pStepData, /* Array of Double dataset */ PLOT_LENGTH, /* Number of data points */ SV_GRAPH_LINE, /* Graph type */ SV_MAGENTA, /* Colour */ SV_HIDE_MARKERS, /* Marker enable / disable */ SV_GRAPH_NEW); /* New graph */ printf ("\nStep response\nPlease hit to continue . . ."); getchar (); /* Initialise FFT */ SIF_Fft (pFFTCoeffs, /* Pointer to FFT coefficients */ SIGLIB_NULL_ARRAY_INDEX_PTR, /* Pointer to bit reverse address table - NOT USED */ FFT_SIZE); /* FFT Size */ /* Perform real FFT */ SDA_Rfft (pRealData, /* Pointer to real array */ pImagData, /* Pointer to imaginary array */ pFFTCoeffs, /* Pointer to FFT coefficients */ SIGLIB_NULL_ARRAY_INDEX_PTR, /* Pointer to bit reverse address table - NOT USED */ FFT_SIZE, /* FFT size */ LOG_FFT_SIZE); /* log2 FFT size */ /* Calculate real power from complex */ SDA_LogMagnitude (pRealData, /* Pointer to real source array */ pImagData, /* Pointer to imaginary source array */ pResults, /* Pointer to log magnitude destination array */ PLOT_LENGTH); /* Array length */ Max = SDA_AbsMax (pResults, /* Pointer to source array */ PLOT_LENGTH); /* Array length */ SDA_Offset (pResults, /* Pointer to source array */ Max, /* D.C. offset */ pResults, /* Pointer to destination array */ PLOT_LENGTH); /* Array length */ Display2DGraph (h2DGraph, /* Graph handle */ "Frequency response", /* Title of the dataset */ pResults, /* Array of Double dataset */ PLOT_LENGTH, /* Number of data points */ SV_GRAPH_LINE, /* Graph type */ SV_MAGENTA, /* Colour */ SV_HIDE_MARKERS, /* Marker enable / disable */ SV_GRAPH_NEW); /* New graph */ printf ("\nFrequency response\nPlease hit to continue . . ."); getchar (); DeleteGraph (h2DGraph); /* Delete the graphs */ DeleteGraph (hPZGraph); SUF_MemoryFree (pRealData); /* Free memory */ SUF_MemoryFree (pIIRCoeffs); SUF_MemoryFree (pImagData); SUF_MemoryFree (pResults); SUF_MemoryFree (pFFTCoeffs); }