helmi_mjd
Member level 2
Hi guys,
I have one question related to FFT computation in dsPIC30F4013. Below is the code I used (basically from example CE018 C30 compiler) but with input signal from ADC pin. However, i got incorrect result. Please anybody could help me resolve this issue and check whether i make mistake in my code. I'm using MPLAB IDE and C30 comipiler.
Thanks in advance.
I have one question related to FFT computation in dsPIC30F4013. Below is the code I used (basically from example CE018 C30 compiler) but with input signal from ADC pin. However, i got incorrect result. Please anybody could help me resolve this issue and check whether i make mistake in my code. I'm using MPLAB IDE and C30 comipiler.
Thanks in advance.
Code C - [expand] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 // Include the neccesary header files #include <p30F4013.h> #include <dsp.h> #include <stdio.h> #include <math.h> #include "system.h" #include "lcd.h" #include "delay.h" #include "uart.h" #include "adc.h" /******************************************************************************* * DEVICE CONFIGURATION WORDS * *******************************************************************************/ _FOSC(CSW_FSCM_OFF & XT_PLL8); // Primary Oscillator Mode = XT with PLL 8x. // Clock Switching and Monitor = Off. _FWDT(WDT_OFF); // Watchdog Timer = Off. _FBORPOR(PBOR_OFF & PWRT_64 & MCLR_EN); // Brown Out Reset = Off. POR Timer Value = 64ms. // Master Clear = Enabled. _FGS(CODE_PROT_ON); // Code Protection = On. /******************************************************************************* * PRIVATE FUNCTION PROTOTYPES * *******************************************************************************/ void lcd_1stline_msg(const char* csz_string); void lcd_2ndline_msg(const char* csz_string); void alert_lamp (void); void test_uart1 (void); void test_uart2 (void); void test_uart1a (void); //Extern definition extern fractcomplex sigCmpx[FFT_BLOCK_LENGTH] // Typically, the input signal to an FFT __attribute__ ((section (".ydata, data, ymemory"), // routine is a complex array containing samples aligned (FFT_BLOCK_LENGTH * 2 *2))); // of an input signal. For this example, // we will provide the input signal in an // array declared in Y-data space. /******************************************************************************* * Global Variables * *******************************************************************************/ unsigned char c_received_data = 0; // data received through UART int peakFrequencyBin = 0; // Declare post-FFT variables to compute the unsigned long peakFrequency = 0; // frequency of the largest spectral component // Global Definitions #ifndef FFTTWIDCOEFFS_IN_PROGMEM fractcomplex twiddleFactors[FFT_BLOCK_LENGTH/2] // Declare Twiddle Factor array in X-space __attribute__ ((section (".xbss, bss, xmemory"), aligned (FFT_BLOCK_LENGTH*2))); #else extern const fractcomplex twiddleFactors[FFT_BLOCK_LENGTH/2] // Twiddle Factor array in Program memory __attribute__ ((space(auto_psv), aligned (FFT_BLOCK_LENGTH*2))); #endif fractcomplex sigCmpx[FFT_BLOCK_LENGTH] __attribute__ ((section (".ydata, data, ymemory"), aligned (FFT_BLOCK_LENGTH * 2 *2))) ={0}; /******************************************************************************* * MAIN FUNCTION * *******************************************************************************/ int main(void) { int i = 0; // FFT size index unsigned int ADC_val[]={0}; // Clear all ports. LATA = 0; LATB = 0; LATC = 0; LATD = 0; LATF = 0; // Initialize I/O directions. TRISA = 0; // PORTA TRISAbits.TRISA11 = 1; // SW1 is connected at RA11 TRISB = 0; TRISC = 0; TRISD = 0; TRISDbits.TRISD8 = 1; // SW2 is connected at RD8 TRISF = 0; TRISBbits.TRISB12 = 1; // ADC input PIN as B12 [AN12] lcd_initialize(); // initialize LCD lcd_clear(); // clear LCD config_module_adc(); // configure ADC module change_channel_adc(12); // AN12 channel [1100=12] // Acquire signal from ADC pin for (i=0;i<FFT_BLOCK_LENGTH;i++){ ADC_val[i] = sampling_and_conversion_adc(); // get ADC value sigCmpx[i].real = Float2Fract(ADC_val[i]); // replace real part with ADC value sigCmpx[i].imag = 0; // set imiginary part with 0 } // the ADC value in float format. So we need to change to fractional format for // library compatibality // FFT computation fractional *p_real = &sigCmpx[0].real ; // initialize real pointer fractcomplex *p_cmpx = &sigCmpx[0] ; // initialize imaginary pointer #ifndef FFTTWIDCOEFFS_IN_PROGMEM // Generate TwiddleFactor Coefficients TwidFactorInit (LOG2_BLOCK_LENGTH, &twiddleFactors[0], 0); // We need to do this only once at start-up #endif for ( i = 0; i < FFT_BLOCK_LENGTH; i++ ) // The FFT function requires input data { // to be in the fractional fixed-point range [-0.5, +0.5] *p_real = *p_real >>1 ; // So, we shift all data samples by 1 bit to the right. *p_real++; // Should you desire to optimize this process, perform } // data scaling when first obtaining the time samples // Or within the BitReverseComplex function source code p_real = &sigCmpx[(FFT_BLOCK_LENGTH/2)-1].real ; // Set up pointers to convert real array p_cmpx = &sigCmpx[FFT_BLOCK_LENGTH-1] ; // to a complex array. The input array initially has all // the real input samples followed by a series of zeros for ( i = FFT_BLOCK_LENGTH; i > 0; i-- ) // Convert the Real input sample array { // to a Complex input sample array (*p_cmpx).real = (*p_real--); // We will simpy zero out the imaginary (*p_cmpx--).imag = 0x0000; // part of each data sample } // Perform FFT operation #ifndef FFTTWIDCOEFFS_IN_PROGMEM FFTComplexIP (LOG2_BLOCK_LENGTH, &sigCmpx[0], &twiddleFactors[0], COEFFS_IN_DATA); #else FFTComplexIP (LOG2_BLOCK_LENGTH, &sigCmpx[0], (fractcomplex *) __builtin_psvoffset(&twiddleFactors[0]), (int) __builtin_psvpage(&twiddleFactors[0])); #endif // Store output samples in bit-reversed order of their addresses BitReverseComplex (LOG2_BLOCK_LENGTH, &sigCmpx[0]); // Compute the square magnitude of the complex FFT output array so we have a Real output vetor SquareMagnitudeCplx(FFT_BLOCK_LENGTH, &sigCmpx[0], &sigCmpx[0].real); // Find the frequency Bin ( = index into the SigCmpx[] array) that has the largest energy // i.e., the largest spectral component VectorMax(FFT_BLOCK_LENGTH/2, &sigCmpx[0].real, &peakFrequencyBin); // Compute the frequency (in Hz) of the largest spectral component peakFrequency = peakFrequencyBin*(SAMPLING_RATE/FFT_BLOCK_LENGTH); for (i=0; i<FFT_BLOCK_LENGTH;i++) { lcd_1stline_msg("FFT num : "); // display the adc value lcd_2ndline_msg("ADC val : "); // display the decibel value lcd_goto(0x80+10); // jump to the desired position on lcd lcd_bcd(4, sigCmpx[i].real); // write adc value to lcd lcd_goto(0xC0+10); // jump to the desired position on lcd lcd_bcd(4, peakFrequency); // write dB value to lcd delay_ms(500); lcd_clear(); } while (1); // Place a breakpoint here and observe the watch window variables }
Last edited by a moderator: