Cornell University ECE4760
Digital Signal Processing
PIC32MX250F128B
DSP -- FFT, IIR filters, Direct Digital Synthesis
|amplitude|=max(|Re|,|Im|)+0.4*min(|Re|,|Im|)
. This approximation is accurate within about 4%.
Taking the log of the magnitude using a fast approximation
(Generation of Products and Quotients Using Approximate Binary Logarithms for Digital Filtering Applications, IEEE Transactions on Computers 1970 vol.19 Issue No.02) gives more resolution at lower amplitudes.
The log was only computed to a 4-bit integer, concantenated with a 4-bit fraction for display at limited TFT resolution. In the first image below, the sampling rate is 500 KHz, and the signal applied was 123 KHz sine wave. You can see the spike of the sine wave as well as the DC offset at zero frequency. (Code) You can get rid of the residual log-noise by truncating at log=0x20 (2 bits in power). The second image shows a calculation of peak frequency. (Code) |amplitude|=max(|Re|,|Im|)+0.4*min(|Re|,|Im|)
. This approximation is accurate within about 4%.butter
function). This matlab program allows you to check SOS filter response accuracy for a given bandwidth. This program uses an unfactored IIR filter design for comparision. For low-order filters (one or two samples), unfactored IIR filters will be faster, while being accurate enough. // coeff = {b2, -a2} noting that b1=b2 and a1=1 (for first order Butterworth) // history = { last_input, last_output} fix16 coeff[2], history[2], output, input ; fix16 IIR_butter_1_16(fix16 input, fix16 *coeff, fix16 *history ) { fix16 output; output = multfix16(input+history[0], coeff[0]) + multfix16(history[1], coeff[1]) ; history[0] = input ; history[1] = output ; return output ; }-- A second order Butterworth lowpass has less than 1% response error down to cutoff=0.04. At cutoff=0.1 (and Fs=100 kHz) the measured cutoff frequency is very close to 5 kHz, as predicted. The ISR takes 3.5 microSec to execute (60 MHz core clock).
DAC_value = (output>>6) + 128 ;
.1.5*0.05-0.25
) is in error by 4*10^{-5}, the 2.30 result is correct to 8 places. The macros for the 2.30 follow:
typedef signed int fix32 ; #define multfix32(a,b) ((fix32)(((( signed long long)(a))*(( signed long long)(b)))>>30)) //multiply two fixed 2:30 #define float2fix32(a) ((fix32)((a)*1073741824.0)) // 2^30 #define fix2float32(a) ((float)(a)/1073741824.0)Another fixed point system useful over a larger integer range is 16.16 format with a range of +/-32767 and a resolution of 1.5x10^{-5}. The macros for this system are
typedef signed int fix16 ; #define multfix16(a,b) ((fix16)(((( signed long long)(a))*(( signed long long)(b)))>>16)) //multiply two fixed 16:16 #define float2fix16(a) ((fix16)((a)*65536.0)) // 2^16 #define fix2float16(a) ((float)(a)/65536.0) #define divfix16(a,b) ((fix16)((((signed long long)(a)<<16)/(b)))) #define sqrtfix16(a) (float2fix16(sqrt(fix2float16(a))))The performance for operations vary. At level 1 opt, fixed multiply is about 2.4 times faster than floating point (23 cycles), and fixed add is about 8 times faster (8 cycles). However fixed divide is the same speed as float, and fixed square root is 0.6 the speed of the float operation. Test code.
References
Copyright Cornell University October 29, 2018