Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
main.cpp@2:7945f79d7c8e, 2019-01-29 (annotated)
- Committer:
- guicat
- Date:
- Tue Jan 29 07:20:48 2019 +0000
- Revision:
- 2:7945f79d7c8e
- Parent:
- 1:4a666bd3fef6
First commit
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
guicat | 1:4a666bd3fef6 | 1 | /* |
guicat | 1:4a666bd3fef6 | 2 | Original code from MARTIN SIMPSON : CMSIS_FFT_mbed_os_DAC |
guicat | 1:4a666bd3fef6 | 3 | https://os.mbed.com/users/martinsimpson/code/CMSIS_FFT_mbed_os_DAC/file/05e2c9ca68e2/main.cpp/ |
guicat | 1:4a666bd3fef6 | 4 | |
guicat | 1:4a666bd3fef6 | 5 | Modified by Guillaume Cathelain to generate simulation from DAC |
guicat | 1:4a666bd3fef6 | 6 | */ |
guicat | 1:4a666bd3fef6 | 7 | |
martinsimpson | 0:05e2c9ca68e2 | 8 | #include "mbed.h" |
martinsimpson | 0:05e2c9ca68e2 | 9 | /* Include arm_math.h mathematic functions */ |
martinsimpson | 0:05e2c9ca68e2 | 10 | #include "arm_math.h" |
martinsimpson | 0:05e2c9ca68e2 | 11 | /* Include mbed-dsp libraries */ |
martinsimpson | 0:05e2c9ca68e2 | 12 | #include "arm_common_tables.h" |
martinsimpson | 0:05e2c9ca68e2 | 13 | #include "arm_const_structs.h" |
martinsimpson | 0:05e2c9ca68e2 | 14 | #include "math_helper.h" |
martinsimpson | 0:05e2c9ca68e2 | 15 | |
martinsimpson | 0:05e2c9ca68e2 | 16 | /* MBED class APIs */ |
guicat | 1:4a666bd3fef6 | 17 | //DigitalOut myled(LED1); |
martinsimpson | 0:05e2c9ca68e2 | 18 | AnalogIn myADC(A1); |
martinsimpson | 0:05e2c9ca68e2 | 19 | AnalogOut myDAC(D13); |
martinsimpson | 0:05e2c9ca68e2 | 20 | Serial pc(USBTX, USBRX); |
martinsimpson | 0:05e2c9ca68e2 | 21 | Ticker timer; |
guicat | 2:7945f79d7c8e | 22 | |
guicat | 2:7945f79d7c8e | 23 | /* Global variables */ |
guicat | 2:7945f79d7c8e | 24 | #define SAMPLE_FREQUENCY_UNDEC 1024 // a ajuster selon la frequence de la porteuse |
guicat | 2:7945f79d7c8e | 25 | const float SAMPLE_TIME_UNDEC = 1.0/SAMPLE_FREQUENCY_UNDEC; |
guicat | 2:7945f79d7c8e | 26 | const int SAMPLES_UNDEC = 8*SAMPLE_FREQUENCY_UNDEC; /* 8 secondes au total */ |
guicat | 2:7945f79d7c8e | 27 | |
guicat | 2:7945f79d7c8e | 28 | /*Decimation settings*/ |
guicat | 2:7945f79d7c8e | 29 | const uint16_t numTaps = 31; // order(30) + 1 |
guicat | 2:7945f79d7c8e | 30 | const float32_t firCoeffs[numTaps] = {0.0035214853,0.004185653,0.005849378,0.008574021,0.012351584,0.017101394,0.022671906,0.028847635,0.035360847,0.041907296,0.048164908,0.053814158,0.058558714,0.06214481,0.064378045,0.065136336,0.064378045,0.06214481,0.058558714,0.053814158,0.048164908,0.041907296,0.035360847,0.028847635,0.022671906,0.017101394,0.012351584,0.008574021,0.005849378,0.004185653,0.0035214853}; |
guicat | 2:7945f79d7c8e | 31 | const uint8_t M = 32; // divise SAMPLE_FREQ_UNDEC. Limite max : M < VIBE_SAMPLES |
guicat | 2:7945f79d7c8e | 32 | const uint32_t blockSize = 64; |
guicat | 2:7945f79d7c8e | 33 | const uint32_t numBlocks = SAMPLES_UNDEC/blockSize; |
guicat | 2:7945f79d7c8e | 34 | static float32_t firState[numTaps + blockSize -1]; |
guicat | 2:7945f79d7c8e | 35 | static float32_t undecimatedSignal[SAMPLES_UNDEC]; |
guicat | 2:7945f79d7c8e | 36 | static float decimatedSignal[SAMPLES_UNDEC/M]; |
guicat | 2:7945f79d7c8e | 37 | static float32_t *pDecimatorInput, *pDecimatorOutput; |
guicat | 2:7945f79d7c8e | 38 | |
guicat | 2:7945f79d7c8e | 39 | |
guicat | 2:7945f79d7c8e | 40 | /* FFT settings */ |
guicat | 2:7945f79d7c8e | 41 | #define FFT_SIZE SAMPLES_UNDEC/M /* FFT size is always the same size as we have samples, so 1024/256 in our case */ |
guicat | 2:7945f79d7c8e | 42 | static float fftInput[FFT_SIZE*2]; // initialized with zeros |
guicat | 2:7945f79d7c8e | 43 | static float fftOutput[FFT_SIZE]; // initialized with zeros |
guicat | 2:7945f79d7c8e | 44 | static float maxValue; // Max FFT value is stored here |
guicat | 2:7945f79d7c8e | 45 | static uint32_t maxIndex; // Index in Output array where max value is |
guicat | 2:7945f79d7c8e | 46 | |
guicat | 2:7945f79d7c8e | 47 | |
guicat | 2:7945f79d7c8e | 48 | /* Define simulation settings*/ |
guicat | 2:7945f79d7c8e | 49 | #define CARRIER_FREQUENCY (256) // ATTENTION multiple de 2 pour que SAMPLE_FREQUENCY multiple de CARRIER_FREQUENCY afin que VIBE_SAMPLES soit entier |
guicat | 2:7945f79d7c8e | 50 | const int CARRIER_SIZE = SAMPLE_FREQUENCY_UNDEC/CARRIER_FREQUENCY; |
guicat | 2:7945f79d7c8e | 51 | float carrier[CARRIER_SIZE]; |
guicat | 2:7945f79d7c8e | 52 | #define MODUL_FREQUENCY 1 |
guicat | 2:7945f79d7c8e | 53 | const int VIBE_SAMPLES =(SAMPLE_FREQUENCY_UNDEC/CARRIER_FREQUENCY)*int(0.1*CARRIER_FREQUENCY); // multiple de 1/CARRIER_FREQUENCY, durée 0.01s. Durée minimale = 1/CARRIER_FREQUENCY; durée max = 1/MODUL_FREQUENCY |
guicat | 2:7945f79d7c8e | 54 | const int MODUL_SIZE = SAMPLE_FREQUENCY_UNDEC/MODUL_FREQUENCY; |
guicat | 2:7945f79d7c8e | 55 | float modul[MODUL_SIZE]; |
guicat | 2:7945f79d7c8e | 56 | const int SIM_SIZE = MODUL_SIZE; |
guicat | 2:7945f79d7c8e | 57 | float sim[SIM_SIZE]; |
guicat | 2:7945f79d7c8e | 58 | |
guicat | 2:7945f79d7c8e | 59 | // Create the carrier buffer |
guicat | 2:7945f79d7c8e | 60 | void calculate_carrier(){ |
guicat | 2:7945f79d7c8e | 61 | for (int i = 0; i < CARRIER_SIZE; i+=1) { |
guicat | 2:7945f79d7c8e | 62 | float t = i * SAMPLE_TIME_UNDEC; |
guicat | 2:7945f79d7c8e | 63 | float phase = 2* PI * CARRIER_FREQUENCY * t; |
guicat | 2:7945f79d7c8e | 64 | carrier[i] = sin(phase); |
guicat | 1:4a666bd3fef6 | 65 | } |
guicat | 1:4a666bd3fef6 | 66 | } |
guicat | 2:7945f79d7c8e | 67 | // Create the modulator buffer |
guicat | 2:7945f79d7c8e | 68 | void calculate_modulator(){ |
guicat | 2:7945f79d7c8e | 69 | for (int i = 0; i < VIBE_SAMPLES; i+=1) { |
guicat | 2:7945f79d7c8e | 70 | modul[i] = 1.0; |
guicat | 2:7945f79d7c8e | 71 | } |
guicat | 2:7945f79d7c8e | 72 | for (int i = VIBE_SAMPLES; i < MODUL_SIZE; i+=1) { |
guicat | 2:7945f79d7c8e | 73 | modul[i] = 0.0; |
guicat | 2:7945f79d7c8e | 74 | } |
guicat | 2:7945f79d7c8e | 75 | } |
guicat | 2:7945f79d7c8e | 76 | // Calculate the sim signal |
guicat | 2:7945f79d7c8e | 77 | void calculate_sim(){ |
guicat | 2:7945f79d7c8e | 78 | calculate_carrier(); |
guicat | 2:7945f79d7c8e | 79 | calculate_modulator(); |
guicat | 2:7945f79d7c8e | 80 | for (int i = 0;i<SIM_SIZE;i+=1){ |
guicat | 2:7945f79d7c8e | 81 | int i_carrier = i - CARRIER_SIZE*int(float(i)/CARRIER_SIZE); |
guicat | 2:7945f79d7c8e | 82 | sim[i] = 0.5*modul[i]*carrier[i_carrier]+0.5; |
guicat | 2:7945f79d7c8e | 83 | } |
guicat | 2:7945f79d7c8e | 84 | } |
guicat | 2:7945f79d7c8e | 85 | // Create the modulated signal |
guicat | 1:4a666bd3fef6 | 86 | int n=0; |
guicat | 1:4a666bd3fef6 | 87 | void dac_generate(){ |
guicat | 2:7945f79d7c8e | 88 | myDAC.write(sim[n]); |
guicat | 1:4a666bd3fef6 | 89 | n++; |
guicat | 2:7945f79d7c8e | 90 | if (n>=SIM_SIZE){ |
guicat | 1:4a666bd3fef6 | 91 | n=0; |
martinsimpson | 0:05e2c9ca68e2 | 92 | } |
guicat | 1:4a666bd3fef6 | 93 | } |
guicat | 1:4a666bd3fef6 | 94 | |
martinsimpson | 0:05e2c9ca68e2 | 95 | |
martinsimpson | 0:05e2c9ca68e2 | 96 | int main() { |
guicat | 2:7945f79d7c8e | 97 | /* Init serial communication*/ |
guicat | 2:7945f79d7c8e | 98 | // pc.baud(115200); //should be higher |
guicat | 2:7945f79d7c8e | 99 | pc.baud(2000000); |
guicat | 2:7945f79d7c8e | 100 | /* DAC simulation*/ |
guicat | 2:7945f79d7c8e | 101 | calculate_sim(); |
guicat | 2:7945f79d7c8e | 102 | timer.attach(&dac_generate,SAMPLE_TIME_UNDEC); |
guicat | 1:4a666bd3fef6 | 103 | |
guicat | 2:7945f79d7c8e | 104 | /* DAC record */ |
guicat | 2:7945f79d7c8e | 105 | for (int i = 0; i < SAMPLES_UNDEC; i += 1) { |
guicat | 2:7945f79d7c8e | 106 | wait(SAMPLE_TIME_UNDEC); |
guicat | 2:7945f79d7c8e | 107 | undecimatedSignal[i] = abs(myADC.read() - 0.5f); //Real part NB removing DC offset |
guicat | 2:7945f79d7c8e | 108 | } |
guicat | 2:7945f79d7c8e | 109 | |
guicat | 2:7945f79d7c8e | 110 | /* Decimation*/ |
guicat | 2:7945f79d7c8e | 111 | arm_fir_decimate_instance_f32 S; |
guicat | 2:7945f79d7c8e | 112 | arm_fir_decimate_init_f32(&S, numTaps, M,(float32_t *)&firCoeffs[0], (float32_t *)&firState[0], blockSize); |
guicat | 2:7945f79d7c8e | 113 | pDecimatorInput = &undecimatedSignal[0]; |
guicat | 2:7945f79d7c8e | 114 | pDecimatorOutput = &decimatedSignal[0]; |
guicat | 2:7945f79d7c8e | 115 | for(int i=0; i < numBlocks; i++) |
guicat | 2:7945f79d7c8e | 116 | { |
guicat | 2:7945f79d7c8e | 117 | arm_fir_decimate_f32(&S, pDecimatorInput + (i * blockSize), pDecimatorOutput + (i * blockSize/M), blockSize); |
guicat | 1:4a666bd3fef6 | 118 | } |
guicat | 2:7945f79d7c8e | 119 | |
guicat | 2:7945f79d7c8e | 120 | /* Init FFT*/ |
guicat | 2:7945f79d7c8e | 121 | float meanDecimatedSignal; |
guicat | 2:7945f79d7c8e | 122 | arm_mean_f32(decimatedSignal,SAMPLES_UNDEC/M,&meanDecimatedSignal); |
guicat | 2:7945f79d7c8e | 123 | for (int i = 0; i < 2*FFT_SIZE; i += 2) { |
guicat | 2:7945f79d7c8e | 124 | fftInput[i] = decimatedSignal[i/2] - meanDecimatedSignal; |
guicat | 2:7945f79d7c8e | 125 | fftInput[i+1] = 0; |
guicat | 1:4a666bd3fef6 | 126 | } |
martinsimpson | 0:05e2c9ca68e2 | 127 | |
guicat | 2:7945f79d7c8e | 128 | if (FFT_SIZE==1024){ |
guicat | 2:7945f79d7c8e | 129 | arm_cfft_f32(&arm_cfft_sR_f32_len1024, fftInput, 0, 1); |
guicat | 2:7945f79d7c8e | 130 | } else if (FFT_SIZE==512){ |
guicat | 2:7945f79d7c8e | 131 | arm_cfft_f32(&arm_cfft_sR_f32_len512, fftInput, 0, 1); |
guicat | 2:7945f79d7c8e | 132 | } else if (FFT_SIZE==256){ |
guicat | 2:7945f79d7c8e | 133 | arm_cfft_f32(&arm_cfft_sR_f32_len256, fftInput, 0, 1); |
guicat | 2:7945f79d7c8e | 134 | } else if (FFT_SIZE==128){ |
guicat | 2:7945f79d7c8e | 135 | arm_cfft_f32(&arm_cfft_sR_f32_len128, fftInput, 0, 1); |
guicat | 2:7945f79d7c8e | 136 | } |
guicat | 2:7945f79d7c8e | 137 | |
guicat | 2:7945f79d7c8e | 138 | /* Compute FFT and max value */ |
guicat | 2:7945f79d7c8e | 139 | arm_cmplx_mag_f32(fftInput, fftOutput, FFT_SIZE); |
guicat | 2:7945f79d7c8e | 140 | arm_max_f32(fftOutput, FFT_SIZE/2, &maxValue, &maxIndex); |
guicat | 2:7945f79d7c8e | 141 | |
guicat | 2:7945f79d7c8e | 142 | /* GRAPHS*/ |
guicat | 2:7945f79d7c8e | 143 | // /* PLOT DECIMATOR INPUT BUFFER */ |
guicat | 2:7945f79d7c8e | 144 | // for (int i = 0; i < SAMPLES_UNDEC; i += 1) { |
guicat | 2:7945f79d7c8e | 145 | // pc.printf("%f\r\n",undecimatedSignal[i]); |
guicat | 2:7945f79d7c8e | 146 | // } |
guicat | 2:7945f79d7c8e | 147 | // /* PLOT DECIMATOR OUTPUT BUFFER */ |
guicat | 2:7945f79d7c8e | 148 | // for (int i = 0; i < SAMPLES_UNDEC/M; i += 1) { |
guicat | 2:7945f79d7c8e | 149 | // pc.printf("%f\r\n",decimatedSignal[i]); |
guicat | 2:7945f79d7c8e | 150 | // } |
guicat | 2:7945f79d7c8e | 151 | // /* FFT graph, only positive frequency */ |
guicat | 1:4a666bd3fef6 | 152 | // for (int i=0; i<FFT_SIZE/2;i++){ |
guicat | 2:7945f79d7c8e | 153 | // pc.printf("%f\r\n",fftOutput[i]); |
guicat | 1:4a666bd3fef6 | 154 | // } |
guicat | 1:4a666bd3fef6 | 155 | |
guicat | 2:7945f79d7c8e | 156 | /* FFT RESULT */ |
guicat | 1:4a666bd3fef6 | 157 | // pc.printf("Maximum value is %f\r\n",maxValue); |
guicat | 1:4a666bd3fef6 | 158 | // pc.printf("Index of maximum value is %d\r\n",maxIndex); |
guicat | 2:7945f79d7c8e | 159 | float freqStep = (SAMPLE_FREQUENCY_UNDEC/float(M)) / float(FFT_SIZE); |
guicat | 1:4a666bd3fef6 | 160 | float maxFreq = maxIndex * freqStep; |
guicat | 2:7945f79d7c8e | 161 | pc.printf("Frequency of maximum value is %.3f +/- %.3f \r\n",maxFreq,freqStep); |
martinsimpson | 0:05e2c9ca68e2 | 162 | } |