■■■■■■■■■■ FFT_samle_01 ■■■■■■■■■■ #include "mbed.h" #include "N5110.h" extern "C" void fftR4(short *y, short *x, int N); float magnitude(short y1, short y2); void updateSamples(); void doFFT(); void printSpectrum(); void printSamples(); void ledBarGraph(); void rgbDance(); void lcdEqualiser(); int calcPeakFrequency(); AnalogIn audio(p17); // ADC pin must be biased at Vcc/2 using coupling capacitor and potential divider BusOut leds(LED1,LED2,LED3,LED4); LocalFileSystem local("local"); // Create the local filesystem under the name "local" Serial serial(USBTX,USBRX); // VCC,SCE,RST,D/C,MOSI,SCLK,LED N5110 lcd(p7,p8,p9,p10,p11,p13,p21); PwmOut red(p23); // RGB LEDs (same connections as app board) PwmOut green(p24); PwmOut blue(p25); #define BUF_LEN 1024 #define SAMP_FREQ 10000 short samples[BUF_LEN]; // store the values read from ADC short mx[BUF_LEN*2]; // input data 16 bit, 4 byte aligned x0r,x0i,x1r,x1i,.... short my[BUF_LEN*2]; // output data 16 bit,4 byte aligned y0r,y0i,y1r,y1i,.... float spectrum[BUF_LEN/2]; // frequency spectrum char buffer[14]; // screen buffer int tone; int main() { // initialise LCD and display welcomes message lcd.init(); lcd.printString("Audio FFT",14,0); lcd.printString("Analyser",20,1); lcd.printString("Craig A. Evans",0,4); serial.baud(115200); red.period(1e-4); // 10 kHz period for starters // setting one PWM channel sets them all as they share the same frequency leds = 15; wait(2.0); // short pause to allow coupling capacitor to charge leds = 0; lcd.clear(); while(1) { //red = 1.0,green=1.0,blue=1.0; updateSamples(); // read in new analog values doFFT(); // calc FFT ledBarGraph(); // display amplitude bar graph on LEDs from sample values lcdEqualiser(); // plot spectrum on LCD rgbDance(); //printSpectrum(); //printSamples(); tone = calcPeakFrequency(); // calculate peak frequcny and send over serial for debug wait_ms(10); // update display 100 ms } } void ledBarGraph() { float rms = 0.0; // initialse array for (int i = 0; i < BUF_LEN; i++) { rms+= samples[i]*samples[i]; } // calc the sum of the squares rms/=BUF_LEN; // get the mean rms = sqrt(rms); // and root to get the RMS rms/= 16384.0; // scale according to 16-bit signed maximum value // check value and update LEDs to show amplitude if (rms > 0.8) { leds = 15; } else if (rms > 0.6) { leds = 7; } else if (rms > 0.4) { leds = 3; } else if (rms > 0.2) { leds = 1; } else { leds = 0; } //serial.printf("RMS = %f\n",rms); } float magnitude(short y1, short y2) { return sqrt(float(y1*y1+y2*y2)); // pythagoras } void updateSamples() { for (int i = 0; i < BUF_LEN; i++) { samples[i] = (short) (audio.read_u16() - 0x8000); // read unsigned 16-bit and convert to signed 16-bit (subtract 32768) wait_us(1e6/SAMP_FREQ); // wait for sampling frequency, should really implement with tickers } } void doFFT() { // clear buffers for (int i=0; i<2*BUF_LEN; i++) { my[i] = 0; mx[i] = 0; } for (int i=0; i<BUF_LEN; i++) { // load samples in array (skip imaginary input values) mx[i*2]=samples[i]; } fftR4(my, mx, BUF_LEN); // call FFT routine int j = 0; for (int i = 0; i < BUF_LEN; i+=2) { spectrum[j] = magnitude(my[i],my[i+1]); // get magnitude of FFT output to get spectrum data j++; } } void printSpectrum() { FILE *fp = fopen("/local/fft.csv","w"); //now write a CSV file to filesytem of frequency vs amplitude int j = 0; for (int i = 0; i < BUF_LEN; i+=2) { int frequency = int(SAMP_FREQ/BUF_LEN/2*i); // calculate value of frequency bin fprintf(fp, "%d,%f\n", frequency, spectrum[j]); j++; } fclose(fp); } void printSamples() { FILE *fp = fopen("/local/samples.csv","w"); //now write a CSV file to filesytem of frequency vs amplitude for (int i = 0; i < BUF_LEN; i++) { fprintf(fp, "%d\n", samples[i]); } fclose(fp); } int calcPeakFrequency() { float max = 0.0; int frequency = 0; int j = 0; for (int i=0; i<BUF_LEN; i+=2) { // loop through spectrum and look for maximum value if (spectrum[j] > max) { max = spectrum[j]; frequency = int(SAMP_FREQ/BUF_LEN/2*i); } j++; } //serial.printf("Max = %f\n",max); return frequency; } void lcdEqualiser() { // spectrum has BUF_LEN/2 values = 512 // screen has 84 pixel, giving 6 spectrum points per pixel float max = 0.0; // used for normalisation later float pixelValue[84]; for (int i=0; i<84; i++) { // loop through array pixelValue[i] = 0.0; for (int y=0; y<6; y++) { pixelValue[i] += spectrum[i*6+y]; // sum the 6 values in the spectrum } pixelValue[i]/=6; // calc. average for that pixel if (pixelValue[i] > max) // check for biggest value max = pixelValue[i]; } for (int i=0; i<84; i++) { // loop through array pixelValue[i]/=max; // normalise to 1.0 } lcd.clear(); for (int i=0; i<84; i++) { // loop through array for (int j=0; j<= 47 - int(pixelValue[i]*47.0); j++) { // loop through array lcd.setPixel(i,j); // draw bar graphs for spectrum bins } } sprintf(buffer,"%4u Hz",tone); lcd.printString(buffer,40,0); lcd.refresh(); } void rgbDance() { // spectrum has BUF_LEN/2 values = 512 // split into 3 bins for R, G and B gives 170 bins per colour float ledColour[3]; float total = 0.0; for (int i=0; i<60; i++) { ledColour[0] += spectrum[i]; // sum the 6 values in the spectrum } total += ledColour[0]; for (int i=60; i<200; i++) { ledColour[1] += spectrum[i]; // sum the 6 values in the spectrum } total += ledColour[1]; for (int i=200; i<512; i++) { ledColour[2] += spectrum[i]; // sum the 6 values in the spectrum } total += ledColour[2]; float r = ledColour[0]/total; float g = ledColour[1]/total; float b = ledColour[2]/total; serial.printf("RGB = %f , %f , %f (%f)\n",r,g,b,r+g+b); r = 1.0 - r; // common anode, smaller value is brighter g = 1.0 - g; // bigger value is duller b = 1.0 - b; if (r > 1.0) r = 1.0; else if (r < 0.0) r = 0.0; if (g > 1.0) g = 1.0; else if (g < 0.0) g = 0.0; if (b > 1.0) b = 1.0; else if (b < 0.0) b = 0.0; red.write(r); // set duty cycles green.write(g); blue.write(b); } ■■■■■■■■■■ FFT_samle_02 ■■■■■■■■■■ // Audio Spectrum Display // Copyright 2013 Tony DiCola (tony@tonydicola.com) // Code ported from the guide at http://learn.adafruit.com/fft-fun-with-fourier-transforms?view=all #include "mbed.h" #include "NVIC_set_all_priorities.h" #include <ctype.h> #include "arm_math.h" #include "arm_const_structs.h" #include "hsi2rgbw_pwm.h" #include "FastAnalogIn.h" Serial pc(USBTX, USBRX); FastAnalogIn Audio(PTC2); //#define RGBW_ext // Disable this line when you want to use the KL25Z on-board RGB LED. #ifndef RGBW_ext // HSI to RGB conversion with direct output to PWM channels - on-board RGB LED hsi2rgbw_pwm led(LED_RED, LED_GREEN, LED_BLUE); #else // HSI to RGBW conversion with direct output to external PWM channels - RGBW LED hsi2rgbw_pwm led(PTD4, PTA12, PTA4, PTA5); //Red, Green, Blue, White #endif // Dummy ISR for disabling NMI on PTA4 - !! DO NOT REMOVE THIS !! // More info at https://mbed.org/questions/1387/How-can-I-access-the-FTFA_FOPT-register-/ extern "C" void NMI_Handler() { DigitalIn test(PTA4); } //////////////////////////////////////////////////////////////////////////////// // CONFIGURATION // These values can be changed to alter the behavior of the spectrum display. // KL25Z limitations // ----------------- // - When used with the Spectrogram python script : // There is a substantial time lag between the music and the screen output. // Max allowed SAMPLE_RATE_HZ is 40000 // Max allowed FFT_SIZE is 64 //////////////////////////////////////////////////////////////////////////////// int SLOWDOWN = 4; // Create an optical delay in spectrumLoop - useful when only one RGB led is used. // Only active when nonzero. // A value >= 1000 and <= 1000 + PIXEL_COUNT fixes the output to a single frequency // window = a single color. int SAMPLE_RATE_HZ = 40000; // Sample rate of the audio in hertz. float SPECTRUM_MIN_DB = 30.0; // Audio intensity (in decibels) that maps to low LED brightness. float SPECTRUM_MAX_DB = 80.0; // Audio intensity (in decibels) that maps to high LED brightness. int LEDS_ENABLED = 1; // Control if the LED's should display the spectrum or not. 1 is true, 0 is false. // Useful for turning the LED display on and off with commands from the serial port. const int FFT_SIZE = 64; // Size of the FFT. const int PIXEL_COUNT = 32; // Number of pixels. You should be able to increase this without // any other changes to the program. const int MAX_CHARS = 65; // Max size of the input command buffer //////////////////////////////////////////////////////////////////////////////// // INTERNAL STATE // These shouldn't be modified unless you know what you're doing. //////////////////////////////////////////////////////////////////////////////// const static arm_cfft_instance_f32 *S; Ticker samplingTimer; float samples[FFT_SIZE*2]; float magnitudes[FFT_SIZE]; int sampleCounter = 0; char commandBuffer[MAX_CHARS]; float frequencyWindow[PIXEL_COUNT+1]; float hues[PIXEL_COUNT]; bool commandRecv = 0; //////////////////////////////////////////////////////////////////////////////// // UTILITY FUNCTIONS //////////////////////////////////////////////////////////////////////////////// void rxisr() { char c = pc.getc(); // Add any characters that aren't the end of a command (semicolon) to the input buffer. if (c != ';') { c = toupper(c); strncat(commandBuffer, &c, 1); } else { // Parse the command because an end of command token was encountered. commandRecv = 1; } } // Compute the average magnitude of a target frequency window vs. all other frequencies. void windowMean(float* magnitudes, int lowBin, int highBin, float* windowMean, float* otherMean) { *windowMean = 0; *otherMean = 0; // Notice the first magnitude bin is skipped because it represents the // average power of the signal. for (int i = 1; i < FFT_SIZE/2; ++i) { if (i >= lowBin && i <= highBin) { *windowMean += magnitudes[i]; } else { *otherMean += magnitudes[i]; } } *windowMean /= (highBin - lowBin) + 1; *otherMean /= (FFT_SIZE / 2 - (highBin - lowBin)); } // Convert a frequency to the appropriate FFT bin it will fall within. int frequencyToBin(float frequency) { float binFrequency = float(SAMPLE_RATE_HZ) / float(FFT_SIZE); return int(frequency / binFrequency); } //////////////////////////////////////////////////////////////////////////////// // SPECTRUM DISPLAY FUNCTIONS /////////////////////////////////////////////////////////////////////////////// void spectrumSetup() { // Set the frequency window values by evenly dividing the possible frequency // spectrum across the number of neo pixels. float windowSize = (SAMPLE_RATE_HZ / 2.0) / float(PIXEL_COUNT); for (int i = 0; i < PIXEL_COUNT+1; ++i) { frequencyWindow[i] = i*windowSize; } // Evenly spread hues across all pixels. for (int i = 0; i < PIXEL_COUNT; ++i) { hues[i] = 360.0*(float(i)/float(PIXEL_COUNT-1)); } } void spectrumLoop() { // Update each LED based on the intensity of the audio // in the associated frequency window. static int SLrpt = 0, SLpixcnt = 0; int SLpixend = 0; float intensity, otherMean; if(SLOWDOWN != 0) { if(SLOWDOWN >= 1000) { if(SLOWDOWN <= (1000 + PIXEL_COUNT-1)) { SLpixcnt = SLOWDOWN - 1000; SLrpt = 0; SLpixend = SLpixcnt + 1; } else SLOWDOWN = 0; } else { SLrpt++; if (SLrpt >= SLOWDOWN) { SLrpt = 0; SLpixcnt = SLpixcnt < PIXEL_COUNT-1 ? ++SLpixcnt : 0; } SLpixend = SLpixcnt + 1; } } else { SLpixcnt = 0; SLrpt = 0; SLpixend = PIXEL_COUNT; } for (int i = SLpixcnt; i < SLpixend; ++i) { windowMean(magnitudes, frequencyToBin(frequencyWindow[i]), frequencyToBin(frequencyWindow[i+1]), &intensity, &otherMean); // Convert intensity to decibels. intensity = 20.0*log10(intensity); // Scale the intensity and clamp between 0 and 1.0. intensity -= SPECTRUM_MIN_DB; intensity = intensity < 0.0 ? 0.0 : intensity; intensity /= (SPECTRUM_MAX_DB-SPECTRUM_MIN_DB); intensity = intensity > 1.0 ? 1.0 : intensity; led.hsi2rgbw(hues[i], 1.0, intensity); } } //////////////////////////////////////////////////////////////////////////////// // SAMPLING FUNCTIONS //////////////////////////////////////////////////////////////////////////////// void samplingCallback() { // Read from the ADC and store the sample data samples[sampleCounter] = (1023 * Audio) - 511.0f; // Complex FFT functions require a coefficient for the imaginary part of the input. // Since we only have real data, set this coefficient to zero. samples[sampleCounter+1] = 0.0; // Update sample buffer position and stop after the buffer is filled sampleCounter += 2; if (sampleCounter >= FFT_SIZE*2) { samplingTimer.detach(); } } void samplingBegin() { // Reset sample buffer position and start callback at necessary rate. sampleCounter = 0; samplingTimer.attach_us(&samplingCallback, 1000000/SAMPLE_RATE_HZ); } bool samplingIsDone() { return sampleCounter >= FFT_SIZE*2; } //////////////////////////////////////////////////////////////////////////////// // COMMAND PARSING FUNCTIONS // These functions allow parsing simple commands input on the serial port. // Commands allow reading and writing variables that control the device. // // All commands must end with a semicolon character. // // Example commands are: // GET SAMPLE_RATE_HZ; // - Get the sample rate of the device. // SET SAMPLE_RATE_HZ 400; // - Set the sample rate of the device to 400 hertz. // //////////////////////////////////////////////////////////////////////////////// void parseCommand(char* command) { if (strcmp(command, "GET MAGNITUDES") == 0) { for (int i = 0; i < FFT_SIZE; ++i) { printf("%f\r\n", magnitudes[i]); } } else if (strcmp(command, "GET SAMPLES") == 0) { for (int i = 0; i < FFT_SIZE*2; i+=2) { printf("%f\r\n", samples[i]); } } else if (strcmp(command, "GET FFT_SIZE") == 0) { printf("%d\r\n", FFT_SIZE); } else if (strcmp(command, "GET SAMPLE_RATE_HZ") == 0) { printf("%d\r\n", SAMPLE_RATE_HZ); } else if (strstr(command, "SET SAMPLE_RATE_HZ") != NULL) { SAMPLE_RATE_HZ = (typeof(SAMPLE_RATE_HZ)) atof(command+(sizeof("SET SAMPLE_RATE_HZ")-1)); } else if (strcmp(command, "GET LEDS_ENABLED") == 0) { printf("%d\r\n", LEDS_ENABLED); } else if (strstr(command, "SET LEDS_ENABLED") != NULL) { LEDS_ENABLED = (typeof(LEDS_ENABLED)) atof(command+(sizeof("SET LEDS_ENABLED")-1)); } else if (strcmp(command, "GET SPECTRUM_MIN_DB") == 0) { printf("%f\r\n", SPECTRUM_MIN_DB); } else if (strstr(command, "SET SPECTRUM_MIN_DB") != NULL) { SPECTRUM_MIN_DB = (typeof(SPECTRUM_MIN_DB)) atof(command+(sizeof("SET SPECTRUM_MIN_DB")-1)); } else if (strcmp(command, "GET SPECTRUM_MAX_DB") == 0) { printf("%f\r\n", SPECTRUM_MAX_DB); } else if (strstr(command, "SET SPECTRUM_MAX_DB") != NULL) { SPECTRUM_MAX_DB = (typeof(SPECTRUM_MAX_DB)) atof(command+(sizeof("SET SPECTRUM_MAX_DB")-1)); } else if (strcmp(command, "GET SLOWDOWN") == 0) { printf("%d\r\n", SLOWDOWN); } else if (strstr(command, "SET SLOWDOWN") != NULL) { SLOWDOWN = (typeof(SLOWDOWN)) atoi(command+(sizeof("SET SLOWDOWN")-1)); } // Update spectrum display values if sample rate was changed. if (strstr(command, "SET SAMPLE_RATE_HZ ") != NULL) { spectrumSetup(); } // Turn off the LEDs if the state changed. if (LEDS_ENABLED == 0) { } } void parserLoop() { // Process any incoming characters from the serial port while (pc.readable()) { char c = pc.getc(); // Add any characters that aren't the end of a command (semicolon) to the input buffer. if (c != ';') { c = toupper(c); strncat(commandBuffer, &c, 1); } else { // Parse the command because an end of command token was encountered. parseCommand(commandBuffer); // Clear the input buffer memset(commandBuffer, 0, sizeof(commandBuffer)); } } } //////////////////////////////////////////////////////////////////////////////// // MAIN FUNCTION //////////////////////////////////////////////////////////////////////////////// int main() { NVIC_set_all_irq_priorities(1); NVIC_SetPriority(UART0_IRQn, 0); // Set up serial port. pc.baud (38400); pc.attach(&rxisr); #ifndef RGBW_ext led.invertpwm(1); //On-board KL25Z RGB LED uses common anode. #endif // Clear the input command buffer memset(commandBuffer, 0, sizeof(commandBuffer)); // Initialize spectrum display spectrumSetup(); // Begin sampling audio samplingBegin(); // Init arm_ccft_32 switch (FFT_SIZE) { case 16: S = & arm_cfft_sR_f32_len16; break; case 32: S = & arm_cfft_sR_f32_len32; break; case 64: S = & arm_cfft_sR_f32_len64; break; case 128: S = & arm_cfft_sR_f32_len128; break; case 256: S = & arm_cfft_sR_f32_len256; break; case 512: S = & arm_cfft_sR_f32_len512; break; case 1024: S = & arm_cfft_sR_f32_len1024; break; case 2048: S = & arm_cfft_sR_f32_len2048; break; case 4096: S = & arm_cfft_sR_f32_len4096; break; } while(1) { // Calculate FFT if a full sample is available. if (samplingIsDone()) { // Run FFT on sample data. // Run FFT on sample data. arm_cfft_f32(S, samples, 0, 1); // Calculate magnitude of complex numbers output by the FFT. arm_cmplx_mag_f32(samples, magnitudes, FFT_SIZE); if (LEDS_ENABLED == 1) { spectrumLoop(); } // Restart audio sampling. samplingBegin(); } // Parse any pending commands. if(commandRecv) { // pc.attach(NULL); parseCommand(commandBuffer); commandRecv = 0; // Clear the input buffer memset(commandBuffer, 0, sizeof(commandBuffer)); // pc.attach(&rxisr); } } } ■■■■■■■■■■ FFT_samle_03 ■■■■■■■■■■ #include "mbed.h" #include <limits.h> DigitalOut myled(LED1); LocalFileSystem local("local"); // code from FFTCM3.s by Ivan Mellen // http://www.luminarymicro.com/component/option,com_joomlaboard/Itemid,92/func,view/id,1636/catid,6/ extern "C" void fftR4(short *y, short *x, int N); extern "C" void ifftR4(short *y, short *x, int N); // code from STM32 DSP Library /* 64 points*/ extern "C" void cr4_fft_64_stm32(void *pssOUT, void *pssIN, uint16_t Nbin); /* 256 points */ extern "C" void cr4_fft_256_stm32(void *pssOUT, void *pssIN, uint16_t Nbin); /* 1024 points */ extern "C" void cr4_fft_1024_stm32(void *pssOUT, void *pssIN, uint16_t Nbin); void test_stm32() { #define N 64 /*Number of points*/ uint32_t x[N], y[N]; /* input and output arrays */ int16_t real[N], imag[N]; /* real and imaginary arrays */ memset(real, 0, sizeof(real)); memset(imag, 0, sizeof(imag)); real[1]=SHRT_MAX; /* Fill the input array */ for (int i=0; i<N; i++) { x[i] = (((uint16_t)(real[i])) | ((uint32_t)(imag[i]<<16))); } cr4_fft_64_stm32(y, x, N); /*computes the FFT of the x[N] samples*/ FILE* log = fopen("/local/stm32.txt","w"); for (int i=0; i<N; i++) { fprintf(log, "%d: %d, %d -> %d, %d\n", i, real[i], imag[i], int16_t(y[i] & 0xFFFF), int16_t(y[i] >> 16)); } fclose(log); } void test_mellen() { short x[512]; // input data 16 bit, 4 byte aligned x0r,x0i,x1r,x1i,.... short y[512]; // output data 16 bit,4 byte aligned y0r,y0i,y1r,y1i,.... short z[512]; // same format... for (int i=0;i<512;i++) x[i]=0; for (int i=0;i<512;i=i+8) { x[i+0]=16384; x[i+2]=16384; x[i+4]=-16384; x[i+6]=-16384;} // x = [ 16384,16384,-16384,-16384,16384,...] 1/4 Fsampling //call functions fftR4(y, x, 256); // y is in frequency domain y[128]= printf("fftR4 ok\n"); ifftR4(z, y, 256); // z should be x/N + noise introduced by 16 bit truncating printf("ifftR4 ok\n"); FILE* log = fopen("/local/mellen.txt","w"); for (int i=0; i<256; i++) { fprintf(log, "%d: %d -> %d -> %d\n", i, x[i], y[i], z[i]); } fclose(log); } int main() { printf("Testing Mellen\n"); test_mellen(); printf("Testing STM32\n"); test_stm32(); printf("Done\n"); } ■■■■■■■■■■ FFT_samle_04 ■■■■■■■■■■ // Audio Spectrum Display // Copyright 2013 Tony DiCola (tony@tonydicola.com) // Code ported from the guide at http://learn.adafruit.com/fft-fun-with-fourier-transforms?view=all // mods by Tony Abbey to simplify code to drive tri-colour LED as a "colour organ" #include "mbed.h" #include "NVIC_set_all_priorities.h" #include <ctype.h> #include "arm_math.h" #include "arm_const_structs.h" #include "FastAnalogIn.h" Serial pc(USBTX, USBRX); FastAnalogIn Audio(PTC2); //#define RGBW_ext // Disable this line when you want to use the KL25Z on-board RGB LED. #ifndef RGBW_ext // RGB direct output to PWM channels - on-board RGB LED PwmOut gled(LED_GREEN); PwmOut rled(LED_RED); PwmOut bled(LED_BLUE); #else // HSI to RGBW conversion with direct output to external PWM channels - RGBW LED // hsi2rgbw_pwm led(PTD4, PTA12, PTA4, PTA5); //Red, Green, Blue, White #endif // Dummy ISR for disabling NMI on PTA4 - !! DO NOT REMOVE THIS !! // More info at https://mbed.org/questions/1387/How-can-I-access-the-FTFA_FOPT-register-/ extern "C" void NMI_Handler() { DigitalIn test(PTA4); } //////////////////////////////////////////////////////////////////////////////// // CONFIGURATION // These values can be changed to alter the behavior of the spectrum display. // KL25Z limitations // ----------------- // - When used with the Spectrogram python script : // There is a substantial time lag between the music and the screen output. // Max allowed SAMPLE_RATE_HZ is 40000 // Max allowed FFT_SIZE is 64 //////////////////////////////////////////////////////////////////////////////// int SLOWDOWN = 4; // Create an optical delay in spectrumLoop - useful when only one RGB led is used. // Only active when nonzero. // A value >= 1000 and <= 1000 + PIXEL_COUNT fixes the output to a single frequency // window = a single color. int SAMPLE_RATE_HZ = 20000; // Sample rate of the audio in hertz. float SPECTRUM_MIN_DB = 20.0; // Audio intensity (in decibels) that maps to low LED brightness. float SPECTRUM_MAX_DB = 80.0; // Audio intensity (in decibels) that maps to high LED brightness. int LEDS_ENABLED = 1; // Control if the LED's should display the spectrum or not. 1 is true, 0 is false. // Useful for turning the LED display on and off with commands from the serial port. const int FFT_SIZE = 64; // Size of the FFT. const int PIXEL_COUNT = 3; // Number of pixels (RGB LED). You should be able to increase this without // any other changes to the program. const int MAX_CHARS = 65; // Max size of the input command buffer //////////////////////////////////////////////////////////////////////////////// // INTERNAL STATE // These shouldn't be modified unless you know what you're doing. //////////////////////////////////////////////////////////////////////////////// const static arm_cfft_instance_f32 *S; Ticker samplingTimer; float samples[FFT_SIZE*2]; float magnitudes[FFT_SIZE]; int sampleCounter = 0; char commandBuffer[MAX_CHARS]; float frequencyWindow[PIXEL_COUNT+1]; float hues[PIXEL_COUNT]; bool commandRecv = 0; //////////////////////////////////////////////////////////////////////////////// // UTILITY FUNCTIONS //////////////////////////////////////////////////////////////////////////////// void rxisr() { char c = pc.getc(); // Add any characters that aren't the end of a command (semicolon) to the input buffer. if (c != ';') { c = toupper(c); strncat(commandBuffer, &c, 1); } else { // Parse the command because an end of command token was encountered. commandRecv = 1; } } // Compute the average magnitude of a target frequency window vs. all other frequencies. void windowMean(float* magnitudes, int lowBin, int highBin, float* windowMean, float* otherMean) { *windowMean = 0; *otherMean = 0; // Notice the first magnitude bin is skipped because it represents the // average power of the signal. for (int i = 1; i < FFT_SIZE/2; ++i) { if (i >= lowBin && i <= highBin) { *windowMean += magnitudes[i]; } else { *otherMean += magnitudes[i]; } } *windowMean /= (highBin - lowBin) + 1; *otherMean /= (FFT_SIZE / 2 - (highBin - lowBin)); } // Convert a frequency to the appropriate FFT bin it will fall within. int frequencyToBin(float frequency) { float binFrequency = float(SAMPLE_RATE_HZ) / float(FFT_SIZE); return int(frequency / binFrequency); } //////////////////////////////////////////////////////////////////////////////// // SPECTRUM DISPLAY FUNCTIONS /////////////////////////////////////////////////////////////////////////////// void spectrumSetup() { // Set the frequency window values by evenly dividing the possible frequency // spectrum across the number of neo pixels. float windowSize = (SAMPLE_RATE_HZ / 2.0) / float(PIXEL_COUNT); for (int i = 0; i < PIXEL_COUNT+1; ++i) { frequencyWindow[i] = i*windowSize; } } void spectrumLoop() { // Update each LED based on the intensity of the audio // in the associated frequency window. static int SLrpt = 0, SLpixcnt = 0; int SLpixend = 0; float intensity, otherMean; if(SLOWDOWN != 0) { if(SLOWDOWN >= 1000) { if(SLOWDOWN <= (1000 + PIXEL_COUNT-1)) { SLpixcnt = SLOWDOWN - 1000; SLrpt = 0; SLpixend = SLpixcnt + 1; } else SLOWDOWN = 0; } else { SLrpt++; if (SLrpt >= SLOWDOWN) { SLrpt = 0; SLpixcnt = SLpixcnt < PIXEL_COUNT-1 ? ++SLpixcnt : 0; } SLpixend = SLpixcnt + 1; } } else { SLpixcnt = 0; SLrpt = 0; SLpixend = PIXEL_COUNT; } for (int i = SLpixcnt; i < SLpixend; ++i) { windowMean(magnitudes, frequencyToBin(frequencyWindow[i]), frequencyToBin(frequencyWindow[i+1]), &intensity, &otherMean); // Convert intensity to decibels. intensity = 20.0*log10(intensity); // Scale the intensity and clamp between 0 and 1.0. intensity -= SPECTRUM_MIN_DB; intensity = intensity < 0.0 ? 0.0 : intensity; intensity /= (SPECTRUM_MAX_DB-SPECTRUM_MIN_DB); intensity = intensity > 1.0 ? 1.0 : intensity; hues[i]=intensity; } rled=1.0-hues[0] ; // onboard LED is common anode so inversion needed gled=1.0-hues[1]; bled=1.0-hues[2]; } //////////////////////////////////////////////////////////////////////////////// // SAMPLING FUNCTIONS //////////////////////////////////////////////////////////////////////////////// void samplingCallback() { // Read from the ADC and store the sample data samples[sampleCounter] = (1023 * Audio) - 511.0f; // Complex FFT functions require a coefficient for the imaginary part of the input. // Since we only have real data, set this coefficient to zero. samples[sampleCounter+1] = 0.0; // Update sample buffer position and stop after the buffer is filled sampleCounter += 2; if (sampleCounter >= FFT_SIZE*2) { samplingTimer.detach(); } } void samplingBegin() { // Reset sample buffer position and start callback at necessary rate. sampleCounter = 0; samplingTimer.attach_us(&samplingCallback, 1000000/SAMPLE_RATE_HZ); } bool samplingIsDone() { return sampleCounter >= FFT_SIZE*2; } //////////////////////////////////////////////////////////////////////////////// // COMMAND PARSING FUNCTIONS // These functions allow parsing simple commands input on the serial port. // Commands allow reading and writing variables that control the device. // // All commands must end with a semicolon character. // // Example commands are: // GET SAMPLE_RATE_HZ; // - Get the sample rate of the device. // SET SAMPLE_RATE_HZ 400; // - Set the sample rate of the device to 400 hertz. // //////////////////////////////////////////////////////////////////////////////// void parseCommand(char* command) { if (strcmp(command, "GET MAGNITUDES") == 0) { for (int i = 0; i < FFT_SIZE; ++i) { printf("%f\r\n", magnitudes[i]); } } else if (strcmp(command, "GET SAMPLES") == 0) { for (int i = 0; i < FFT_SIZE*2; i+=2) { printf("%f\r\n", samples[i]); } } else if (strcmp(command, "GET FFT_SIZE") == 0) { printf("%d\r\n", FFT_SIZE); } else if (strcmp(command, "GET SAMPLE_RATE_HZ") == 0) { printf("%d\r\n", SAMPLE_RATE_HZ); } else if (strstr(command, "SET SAMPLE_RATE_HZ") != NULL) { SAMPLE_RATE_HZ = (typeof(SAMPLE_RATE_HZ)) atof(command+(sizeof("SET SAMPLE_RATE_HZ")-1)); } else if (strcmp(command, "GET LEDS_ENABLED") == 0) { printf("%d\r\n", LEDS_ENABLED); } else if (strstr(command, "SET LEDS_ENABLED") != NULL) { LEDS_ENABLED = (typeof(LEDS_ENABLED)) atof(command+(sizeof("SET LEDS_ENABLED")-1)); } else if (strcmp(command, "GET SPECTRUM_MIN_DB") == 0) { printf("%f\r\n", SPECTRUM_MIN_DB); } else if (strstr(command, "SET SPECTRUM_MIN_DB") != NULL) { SPECTRUM_MIN_DB = (typeof(SPECTRUM_MIN_DB)) atof(command+(sizeof("SET SPECTRUM_MIN_DB")-1)); } else if (strcmp(command, "GET SPECTRUM_MAX_DB") == 0) { printf("%f\r\n", SPECTRUM_MAX_DB); } else if (strstr(command, "SET SPECTRUM_MAX_DB") != NULL) { SPECTRUM_MAX_DB = (typeof(SPECTRUM_MAX_DB)) atof(command+(sizeof("SET SPECTRUM_MAX_DB")-1)); } else if (strcmp(command, "GET SLOWDOWN") == 0) { printf("%d\r\n", SLOWDOWN); } else if (strstr(command, "SET SLOWDOWN") != NULL) { SLOWDOWN = (typeof(SLOWDOWN)) atoi(command+(sizeof("SET SLOWDOWN")-1)); } // Update spectrum display values if sample rate was changed. if (strstr(command, "SET SAMPLE_RATE_HZ ") != NULL) { spectrumSetup(); } else if (strcmp(command, "GET HUES") == 0) { for (int i = 0; i < PIXEL_COUNT; ++i) { printf("%f\r\n", hues[i]); } } // Turn off the LEDs if the state changed. if (LEDS_ENABLED == 0) { } } void parserLoop() { // Process any incoming characters from the serial port while (pc.readable()) { char c = pc.getc(); // (doesnt work!) printf("%c",c); // echo characters typed // Add any characters that aren't the end of a command (semicolon) to the input buffer. if (c != ';') { c = toupper(c); strncat(commandBuffer, &c, 1); } else { // Parse the command because an end of command token was encountered. parseCommand(commandBuffer); // Clear the input buffer memset(commandBuffer, 0, sizeof(commandBuffer)); } } } //////////////////////////////////////////////////////////////////////////////// // MAIN FUNCTION //////////////////////////////////////////////////////////////////////////////// int main() { NVIC_set_all_irq_priorities(1); NVIC_SetPriority(UART0_IRQn, 0); // Set up serial port. pc.baud (38400); pc.attach(&rxisr); // Clear the input command buffer memset(commandBuffer, 0, sizeof(commandBuffer)); // Initialize spectrum display spectrumSetup(); // Begin sampling audio samplingBegin(); // Init arm_ccft_32 switch (FFT_SIZE) { case 16: S = & arm_cfft_sR_f32_len16; break; case 32: S = & arm_cfft_sR_f32_len32; break; case 64: S = & arm_cfft_sR_f32_len64; break; case 128: S = & arm_cfft_sR_f32_len128; break; case 256: S = & arm_cfft_sR_f32_len256; break; case 512: S = & arm_cfft_sR_f32_len512; break; case 1024: S = & arm_cfft_sR_f32_len1024; break; case 2048: S = & arm_cfft_sR_f32_len2048; break; case 4096: S = & arm_cfft_sR_f32_len4096; break; } while(1) { // Calculate FFT if a full sample is available. if (samplingIsDone()) { // Run FFT on sample data. arm_cfft_f32(S, samples, 0, 1); // Calculate magnitude of complex numbers output by the FFT. arm_cmplx_mag_f32(samples, magnitudes, FFT_SIZE); if (LEDS_ENABLED == 1) { spectrumLoop(); } // Restart audio sampling. samplingBegin(); printf("this will make it work "); } // Parse any pending commands. if(commandRecv) { // pc.attach(NULL); parseCommand(commandBuffer); commandRecv = 0; // Clear the input buffer memset(commandBuffer, 0, sizeof(commandBuffer)); // pc.attach(&rxisr); } } } ■■■■■■■■■■ FFT_samle_05 ■■■■■■■■■■ #include "mbed.h" DigitalOut myled(LED1); DigitalOut led(LED2); DigitalOut led2(LED3); DigitalOut led3(LED4); const int N=1024; // Sample number struct TWIDDLE { // Structure factor for calculate fft float cosval [N/2]; float sinval [N/2]; }; void FFT(float datos[N], int n, TWIDDLE &w); //Declaration of functions void enviodatos(float datos[N], int n); Serial pc(USBTX, USBRX); //Declaration Serial port int main() { //Main program myled.write(0); led.write(0); led2.write(0); led3.write(0); int i; //Parameters to calculate the values of a sine function. DATOS[N]=Amp*sin(w0*t) float arg; arg=2*3.1416/N; //argument of the structure TWIDDLE float tm,t,w0,T, Amp; tm=0.1; // increments of time (0,1seg) t=0; //initial time T=2*3.1416; //Period of signal w0=(2*3.1416/T); // angular frequency Amp=3; //Amplitude struct TWIDDLE W; //Declarate of a type structure for (i=0; i<N/2; i++) { //Calculate all the TWIDDLE factors W.cosval[i]= cos(i*arg); W.sinval[i]= -sin(i*arg); } float DATOS[N]; //array to save the sinus values for (i=0; i<N; i++) { //calculate the sinus values DATOS[i]=Amp*sin(w0*t); t+=tm; } led.write(1); //Execution of the program to here OK FFT(DATOS,N,W); //Function to calculate FFT enviodatos(DATOS,N); //Function to send values to serial port led3.write(1); //Execution of the program to here OK while (1); // } void FFT(float datos[N], int n,TWIDDLE &w) { float temp1, temp2, temp3,temp4; //variables needed to calculate FFT int i,j,k,p; int upper_leg, lower_leg; int leg_diff; int num_stages=0; int index, step; float datos_real[n], datos_imag[n]; //real and imaginary values for (p=0; p<n; p++) { datos_real[p]=datos[p]; datos_imag[p]=0; } led2.write(1); // Execution of the program to here break it if N=>2048, else OK. i=1; do { num_stages+=1; i=i*2; } while (i!=n); leg_diff=n/2; step=1; for (i=0; i<num_stages; i++) { index=0; for (j=0; j<leg_diff; j++) { for (upper_leg=j; upper_leg<n; upper_leg+=(2*leg_diff)) { lower_leg=upper_leg+leg_diff; temp1= (datos_real[upper_leg]+ datos_real[lower_leg]); temp2= (datos_real[upper_leg]- datos_real[lower_leg]); temp3= (datos_imag[upper_leg]+ datos_imag[lower_leg]); temp4= (datos_imag[upper_leg]- datos_imag[lower_leg]); datos_real[lower_leg]= (temp2*w.cosval[index])-(temp4*w.sinval[index]); datos_imag[lower_leg]= (temp2*w.sinval[index]+temp4*w.cosval[index]); datos_real[upper_leg]= temp1; datos_imag[upper_leg]= temp3; } index+=step; } leg_diff=leg_diff/2; step*=2; } //bit reversal j=0; for (i=1; i<(N-2); i++) { k=n/2; while (k<=j) { j=j-k; k=k/2; } j=j+k; if (i<j) { temp1= datos_real[j]; temp2= datos_imag[j]; datos_real[j]=datos_real[i]; datos_imag[j]=datos_imag[i]; datos_real[i]=temp1; datos_imag[i]=temp2; } } for (i=0; i<n; i++) { datos[i]= pow(sqrt(pow(datos_real[i],2)+pow(datos_imag[i],2)),2); //Calculate the power fft }; } void enviodatos(float datos[N],int n) { int i=0,j=0,k=0,aux=0; //send to serial port the values correctly. unsigned char bytes[4]; float dato; for (i=0; i<n; i++) { dato=datos[i]; aux=dato; for (j=0; j<4; j++) { switch (j) { case 0: bytes[j]=aux; aux=aux>>8; break; case 1: bytes[j]=aux; aux=aux>>8; break; case 2: bytes[j]=aux; aux=aux>>8; break; case 3: bytes[j]=aux; aux=aux>>8; break; } } for (k=3; k>=0; k--) { while (pc.writeable()==0); pc.putc(bytes[k]); } } } ■■■■■■■■■■ FFT_samle_06 ■■■■■■■■■■ // Nothing special, an example for using the library of FFT, Audio Spectrum Analyzer with LCD #include "mbed.h" #include "FFT.h" #include "LCD_Serial.h" // ********************************************************************************************** #define N 32 float Data[N*2]; unsigned char PowerInt[N/2]; volatile int kbhit; float Average; AnalogIn ChannelR(p16); AnalogIn ChannelL(p17); AnalogIn ChannelC(p18); LCDSerial myLcd(p21,p22,p23,p24); // Data, Clock, Enable, Back // ********************************************************************************************** void vUpdateDataAnalogs(float Analogs[]); void vGraphicDisplay(unsigned char *Data); // ********************************************************************************************** int main() { myLcd.vSetBacklight(1); myLcd.printf("\f FFT with mbed!!!"); wait(2.0); myLcd.printf("\f"); Average=0; for(int k=0;k<64;k++){ Average+=ChannelC.read_u16(); wait_us(100); } Average/=64; while(1){ vUpdateDataAnalogs(Data); vFFT(Data-1,N); vCalPowerInt(Data,PowerInt,N/2); vGraphicDisplay(PowerInt); wait_ms(30); } } // ********************************************************************************************** void vUpdate(void){ kbhit=1; } void vUpdateDataAnalogs(float Analogs[]){ unsigned short TempReadR[32],TempReadL[32]; Ticker Period; kbhit=0; Period.attach_us(&vUpdate,25); // 25 us, 40.000 Hz for(int k=0;k<32;k++){ while(kbhit==0); kbhit=0; TempReadR[k]=ChannelR.read_u16(); } for(int k=0;k<32;k++){ while(kbhit==0); kbhit=0; TempReadL[k]=ChannelL.read_u16(); } Period.detach(); for(int k=0,j=0;k<32;k++,j++){ Analogs[j]=(TempReadR[k]+TempReadL[k])/2; // Promedio (x1[n]+x2[n]=X1[k]+X2[k]) Analogs[j]=((float)(Analogs[j]-Average)/10); // Desplazo y aplico escala.- Analogs[++j]=0; } return; } // ********************************************************************************************** void vGraphicDisplay(unsigned char *Data){ unsigned char k; myLcd.vGotoxy(3,1); for(k=0;k<16;k++,Data++){ if(*Data>192){myLcd.vPutc((*Data-193)/8);}else{myLcd.vPutc(' ');} } myLcd.vGotoxy(3,2); Data-=16; for(k=0;k<16;k++,Data++){ if((*Data>128)&&(*Data<193)){myLcd.vPutc((*Data-129)/8);}else if(*Data>192){myLcd.vPutc(0x07);}else{myLcd.vPutc(' ');} } myLcd.vGotoxy(3,3); Data-=16; for(k=0;k<16;k++,Data++){ if((*Data>64)&&(*Data<129)){myLcd.vPutc((*Data-65)/8);}else if(*Data>128){myLcd.vPutc(0x07);}else{myLcd.vPutc(' ');} } myLcd.vGotoxy(3,4); Data-=16; for(k=0;k<16;k++,Data++){ if((*Data>0)&&(*Data<65)){myLcd.vPutc((*Data-1)/8);}else if(*Data>64){myLcd.vPutc(0x07);}else{myLcd.vPutc(' ');} } } ■■■■■■■■■■ FFT_samle_07 ■■■■■■■■■■ #define SAMPLE_RATE 48000 #include "mbed.h" #include "adc.h" #include "PololuLedStrip.h" PololuLedStrip ledStrip(p8); #define LED_COUNT 60 rgb_color colors[LED_COUNT]; Serial pc(USBTX,USBRX); //extern "C" void cr4_fft_256_stm32(void *pssOUT, void *pssIN, uint16_t Nbin); extern "C" void fftR4(short *y, short *x, int N); //use the LED as a bargraph DigitalOut l1(LED1); DigitalOut l2(LED2); DigitalOut l3(LED3); DigitalOut l4(LED4); //set up a timer for timing FFT's Timer timer; //Used to change colour of LED strips //int testX = 0; //Set up filesystem so we can write some useful files LocalFileSystem local("local"); FILE *fp; //Set up a global buffer for audio data so interrupt can access it int Counter = 0; int16_t Buffer[5000]; int16_t VoltageBuffer[5000]; //Initialise ADC to maximum SAMPLE_RATE and cclk divide set to 1 ADC adc(SAMPLE_RATE, 1); int colourVoltage=0; //Our interrupt handler for audio sampling void sample_ADC(int chan, uint32_t value) { float s; s = adc.read(p20); int16_t b = (s -2048)*16; Buffer[Counter] = b; Counter += 1; /* bar graph */ int g = abs(s-2048); l1 = g > 0.1f*2048; l2 = g > 0.3f*2048; l3 = g > 0.6f*2048; l4 = g > 0.8f*2048; } int main() { while (1){ //Prepare for burst mode on all ADC pins and set up interrupt handler (using ADC library from Simon Blandford adc.append(sample_ADC); adc.startmode(0,0); adc.burst(1); adc.setup(p20,1); //introduce a delay as initial waveform has bias whilst decoupling cap charges wait(0.05); //start the interrupt and wait for about 4096 samples adc.interrupt_state(p20,1); wait(0.05); //Finsh up - Unset pin 20 adc.interrupt_state(p20,0); adc.setup(p20,0); int actual_rate = adc.actual_sample_rate(); //now lets try mellen fft------------------------- timer.reset(); timer.start(); #define MN 1024 /*Number of points*/ short mx[MN*2]; // input data 16 bit, 4 byte aligned x0r,x0i,x1r,x1i,.... short my[MN*2]; // output data 16 bit,4 byte aligned y0r,y0i,y1r,y1i,.... float mz[MN*2]; // to store the final result for (int i=0;i<MN*2;i++) mx[i]=0; for (int i=0;i<MN*2;i++) mz[i]=0; for (int i=0;i<MN;i=i+1) { mx[i*2]=Buffer[i];} //printf("Mellen set up took %i\n",timer.read_us()); //call functions timer.reset(); timer.start(); fftR4(my, mx, MN); //printf("Mellen fft took %i\n",timer.read_us()); //FILE* mlog = fopen("/local/mellen.csv","w"); //now write a CSV file to filesytem of frequency vs amplitude for (int i=0; i<MN; i=i+2) { // fprintf(mlog, "%d: %d -> %d\n", i, mx[i], my[i]); //fprintf(mlog, "%d,%f\n", int(actual_rate/MN/2*i),sqrt(float( (my[i]*my[i]) +(my[i+1]*my[i+1]) ) ) ); mz[i]=sqrt(float( (my[i]*my[i]) +(my[i+1]*my[i+1]) ) ) ; //fprintf(mlog, "%f\n", mz[i] ); } // detect the change of input frequency ****************************** float maxFreq=0; float max=0; for (int i=2;i<512;i=i+1){ if(mz[i]>max){ max = mz[i]; maxFreq=i; }//end if }//end for //fprintf(mlog, "%d\n",maxFreq ); int maxVoltage=0; for (int i=0;i<512;i=i+1){ if(mx[i]>maxVoltage){ maxVoltage = mx[i]; }//end if }//end for pc.printf(" the max = %f\n",max ); pc.printf(" the maxFreq = %f\n",maxFreq ); pc.printf(" the colourValtage = %d\n", maxVoltage ); /*for (int i = 0; i < LED_COUNT; i++){ colors[i] = (rgb_color){ 0, 0, 0 }; } if (maxFreq>60) maxFreq=60; // Limiting Length for (int i = 0; i < maxFreq; i++){ colors[i] = (rgb_color){ abs(maxVoltage/11),abs(255-(maxVoltage/11)) ,abs(255-(maxVoltage/11)+50) }; } ledStrip.write(colors, LED_COUNT);*/ int actualFreq= (actual_rate/MN/2*maxFreq); pc.printf(" actualFreq = %d\n", actualFreq ); //wait_ms(10); /*if (maxFreq>30){ //testX=200; for (int i = 0; i < LED_COUNT; i++){ colors[i] = (rgb_color){ 0, 20, 200 }; } } if ((maxFreq>22)&&(maxFreq<30)){// if frequency bigger than 966Hz //testX= 10; for (int i = 0; i < LED_COUNT; i++){ colors[i] = (rgb_color){ 250, 0, 0 }; } } if (maxFreq<22){ //testX=200; for (int i = 0; i < LED_COUNT; i++){ colors[i] = (rgb_color){ 0, 250, 0 }; } }*/ //----------- //fclose(mlog); Counter = 0; }// end while (1) } ■■■■■■■■■■ FFT_samle_08 ■■■■■■■■■■ #define SAMPLE_RATE 48000 #include "mbed.h" #include "adc.h" //Going to use the Mellen FFT rather than STM, as the STM (port by Igor) won't compile //extern "C" void cr4_fft_256_stm32(void *pssOUT, void *pssIN, uint16_t Nbin); extern "C" void fftR4(short *y, short *x, int N); //use the LED as a bargraph DigitalOut l1(LED1); DigitalOut l2(LED2); DigitalOut l3(LED3); DigitalOut l4(LED4); //set up a timer for timing FFT's Timer timer; //Set up filesystem so we can write some useful files LocalFileSystem local("local"); FILE *fp; //Set up a global buffer for audio data so interrupt can access it int Counter = 0; int16_t Buffer[5000]; //Initialise ADC to maximum SAMPLE_RATE and cclk divide set to 1 ADC adc(SAMPLE_RATE, 1); //Functions to write 16 bit audio data and 32 bit headers to files in au format (cf sndRecorder Cookbook) void fwrite16(uint16_t v) { uint8_t *b = (uint8_t *)&v; fprintf(fp,"%c%c", b[1], b[0]); } void fwrite32(uint32_t v) { uint8_t *b = (uint8_t *)&v; fprintf(fp,"%c%c%c%c", b[3], b[2], b[1], b[0]); } //Our interrupt handler for audio sampling void sample_ADC(int chan, uint32_t value) { float s; s = adc.read(p20); int16_t b = (s -2048)*16; Buffer[Counter] = b; Counter += 1; /* bar graph */ int g = abs(s-2048); l1 = g > 0.1f*2048; l2 = g > 0.3f*2048; l3 = g > 0.6f*2048; l4 = g > 0.8f*2048; } int main() { //Prepare for burst mode on all ADC pins and set up interrupt handler (using ADC library from Simon Blandford adc.append(sample_ADC); adc.startmode(0,0); adc.burst(1); adc.setup(p20,1); //introduce a delay as initial waveform has bias whilst decoupling cap charges wait(1); //start the interrupt and wait for about 4096 samples adc.interrupt_state(p20,1); wait(0.1); //Finsh up - Unset pin 20 adc.interrupt_state(p20,0); adc.setup(p20,0); int actual_rate = adc.actual_sample_rate(); //for debugging tell the terminal sample rate and how many samples we took printf("Requested max sample rate is %u, actual max sample rate is %u.\n", SAMPLE_RATE, actual_rate); printf("We did %i samples\n",Counter); //write original audio file to filesytem so we can load on PC and see what's there (cf sndRecorder Cookbook) fp = fopen("/local/out.au", "w"); fprintf(fp,".snd"); fwrite32(24); fwrite32(-1); fwrite32(3); fwrite32(48000); fwrite32(1); int writeCount = 0; while(writeCount <=Counter) { fwrite16(Buffer[writeCount]); writeCount+=1; } //Not using the STM FFT, but leave code here for the moment /* //now do a fft of the initial 1024 samples #define N 256 //Number of points uint32_t x[N], y[N]; // input and output arrays int16_t real[N], imag[N]; // real and imaginary arrays memset(real, 0, sizeof(real)); memset(imag, 0, sizeof(imag)); // real[1]=SHRT_MAX; // Fill the input array for (int i=0; i<N; i++) { x[i] = (((uint16_t)(Buffer[i])) | ((uint32_t)(0<<16))); } timer.reset(); timer.start(); cr4_fft_256_stm32(y, x, N); //computes the FFT of the x[N] samples printf("ST32 fft up took %i\n",timer.read_us()); FILE* log = fopen("/local/stm32.txt","w"); for (int i=0; i<N; i++) { fprintf(log, "%d: %d, %d -> %d, %d\n", i, Buffer[i], 0 , int16_t(y[i] & 0xFFFF), int16_t(y[i] >> 16)); } fclose(log); //compute frequencies and magnitudes of result FILE* spectrum = fopen("/local/stm32Spec.txt","w"); for (int i=0; i<N/2; i++) { float real = int16_t(y[i] & 0xFFFF)* int16_t(y[i] & 0xFFFF); float imag = int16_t(y[i] >> 16)* int16_t(y[i] >> 16); fprintf(spectrum, "%d -> %f\n", int(SAMPLE_RATE/N*i),sqrt(imag+real)); } fclose(spectrum); */ //now lets try mellen fft timer.reset(); timer.start(); #define MN 1024 /*Number of points*/ short mx[MN*2]; // input data 16 bit, 4 byte aligned x0r,x0i,x1r,x1i,.... short my[MN*2]; // output data 16 bit,4 byte aligned y0r,y0i,y1r,y1i,.... for (int i=0;i<MN*2;i++) mx[i]=0; for (int i=0;i<MN;i=i+1) { mx[i*2]=Buffer[i];} printf("Mellen set up took %i\n",timer.read_us()); //call functions timer.reset(); timer.start(); fftR4(my, mx, MN); printf("Mellen fft took %i\n",timer.read_us()); FILE* mlog = fopen("/local/mellen.csv","w"); //now write a CSV file to filesytem of frequency vs amplitude for (int i=0; i<MN; i=i+2) { // fprintf(mlog, "%d: %d -> %d\n", i, mx[i], my[i]); fprintf(mlog, "%d,%f\n", int(actual_rate/MN/2*i),sqrt(float( (my[i]*my[i]) +(my[i+1]*my[i+1]) ) ) ); } fclose(mlog); } ■■■■■■■■■■ FFT_samle_09 ■■■■■■■■■■ /* * This is my code. It takes 16 samples of the analog in pins and writes the values back to the serial port. * Nathan Lasseter 2010 */ #include "mbed.h" #include "TextLCD.h" extern void fft(float inarr[16], float outarr[16]); //look for fft at link not compile time //Serial pc(USBTX,USBRX); ///dev/ttyACM0 is locked on university pc's Serial pc(p9,p10); //So I use /dev/ttyS0 instead BusOut bargraph(p21,p22,p23,p24,p25,p26,p27,p28,p29,p30); //Dot matrix bargraphs horizontal bus BusOut graphs(p11,p12,p13,p14,p15,p16,p17,p18); //Dot matrix bargraphs vertical bus AnalogIn left(p19); //Left channel input AnalogIn right(p20); //Right channel input void outputmatrix(float avg, int which) { //This is the simple dot matrix driver. switch (which) { //Select a bargraph case 8: graphs = 0xFF; //8: off case 0: graphs = 0xFE; //0-7 are right to left. They turn on a bargraph by going low. case 1: graphs = 0xFC; case 2: graphs = 0xF8; case 3: graphs = 0xF0; case 4: graphs = 0xE0; case 5: graphs = 0xC0; case 6: graphs = 0x80; case 7: graphs = 0x00; } if (avg > 0.9) { bargraph=0x3FF; return; } //Same principle, but set a value on the graph. if (avg > 0.8) { bargraph=0x1FF; return; } if (avg > 0.7) { bargraph=0x0FF; return; } if (avg > 0.6) { bargraph=0x07F; return; } if (avg > 0.5) { bargraph=0x03F; return; } if (avg > 0.4) { bargraph=0x01F; return; } if (avg > 0.3) { bargraph=0x00F; return; } if (avg > 0.2) { bargraph=0x007; return; } if (avg > 0.1) { bargraph=0x003; return; } if (avg > 0.0) { bargraph=0x001; return; } bargraph=0x000; //Default to all off } int main() { //Main code while(1) { int i; /* float leftin[16], leftout[16]; //While technically it can support 16 bands over each of 2 channels... float rightin[16], rightout[16]; for(i=0;i<16;i++) leftin[i] = left; for(i=0;i<16;i++) rightin[i] = right; fft(leftin, leftout); fft(rightin, rightout); */ float in[16], out[16], avg[8]; //I only use 8 on one channel for(i=0;i<16;i++) in[i] = (left + right) / 2; //So I average the two fft(in, out); for(i=0;i<8;i++) avg[i] = (out[2*i] + out[(2*i)+1]) / 2; //And then average pairs of bands /* pc.printf("%f %f %f %f %f %f %f %f\t%f %f %f %f %f %f %f %f\n", leftout[0], leftout[1], leftout[2], leftout[3], leftout[4], leftout[5], leftout[6], leftout[7], leftout[8], leftout[9], leftout[10], leftout[11], leftout[12], leftout[13], leftout[14], leftout[15]); pc.printf("%f %f %f %f %f %f %f %f\t%f %f %f %f %f %f %f %f\n\n", rightout[0], rightout[1], rightout[2], rightout[3], rightout[4], rightout[5], rightout[6], rightout[7], rightout[8], rightout[9], rightout[10], rightout[11], rightout[12], rightout[13], rightout[14], rightout[15]); */ pc.printf("%f %f %f %f\t%f %f %f %f\r\n", //Then print the values to the uart avg[0], avg[1], avg[2], avg[3], avg[4], avg[5], avg[6], avg[7]); for(i=0;i<8;i++) outputmatrix(avg[i], i); //And display on the bargrpahs } } ■■■■■■■■■■ FFT_samle_10 ■■■■■■■■■■ /* Novo projeto MBED_Tempo Criado para: - calcular ValorMedio - Calcular Casos de OverFlow (Valores maiores que 4095 do AD) - Calcular Casos de UnderFlow (Valores menores que 0 do AD) - Calcular o tempo em ms de uma fuga. */ #include <stdio.h> #include "mbed.h" #include "rtos.h" #include "cmsis_os.h" //#include "EthernetIf.h" #include "EthernetInterface.h" #include "Settings.h" #include "Capture.h" #include "Http_post.h" //#include "CommTCP.h" #include "SignalProcessor.h" #include "EventDetector.h" #include "limites.h" //#include "TelnetServer.h" //__attribute((section("AHBSRAM0"),aligned)) char LargeBuffer[1024]; EthernetInterface eth; void thread1(void const *args) { DigitalOut led1(LED1); int n = 0; //int tatual, tnovo; float rms[NUMBER_OF_CHANNELS], mv2[NUMBER_OF_CHANNELS]; int under[NUMBER_OF_CHANNELS], over[NUMBER_OF_CHANNELS]; Capture::Initialize(); //Timer t; //t.start(); //tatual = 0; while(1) { Capture::Wait(); // Calcula o RMS dos 6 canais SignalProcessor::CalculateRMSBulk(rms, mv2, under, over); //printf("Tempo ms %d\n", t.read_ms()); //t.reset(); //rms[0] = 2050; //rms[1]=rms[2]=rms[3]=rms[4]=rms[5]=2000; for(int i=0;i<6;i++){ //printf("Main %d\n", i); EventDetector::get_Detector(i).ProcessEvent(rms[i], mv2[i], under[i], over[i]); //wait_ms(2); } //Thread::yield(); /* for(int i =0; i < 6; i++) printf("%5.2f\t", rms[i]); printf("\n"); wait(5); */ n++; if(n==60) { printf("%.2f %.0f %.2f %.0f\t%.2f %.0f %.2f %.0f\t%.2f %.0f %.2f %.0f\n",rms[0], mv2[0],rms[1],mv2[1],rms[2],mv2[2],rms[3],mv2[3],rms[4],mv2[4],rms[5],mv2[5]); led1 = !led1; n=0; //t.stop(); /* tnovo = t.read_us(); printf("MAIN: The time XXX taken loop %d\n", tnovo - tatual); tatual = tnovo; t.reset(); */ //Thread::wait(1000); //1000 wait(1); } } } /* void InitializeEthernetLink() { if(Settings::get_Dhcp()) eth.init(); //Use DHCP else eth.init(Settings::get_IpAddress(),Settings::get_Netmask(),Settings::get_Gateway()); eth.connect(); printf("IP Address is %s\n", eth.getIPAddress()); } */ void InitializeEthernetLink() { if(Settings::get_Dhcp()) //EthernetIf::Initialize(); //Use DHCP eth.init(); //Use DHCP else //EthernetIf::Initialize(Settings::get_IpAddress(),Settings::get_Netmask(),Settings::get_Gateway()); eth.init(Settings::get_IpAddress(),Settings::get_Netmask(),Settings::get_Gateway()); //EthernetIf::Connect(); eth.connect(); //printf("IP Address is %s\n", EthernetIf::get_IpAddress()); printf("IP Address is NEW %s\n", eth.getIPAddress()); } int main() { FILE *f; //Set Highest Priority //osThreadSetPriority(osThreadGetId(),osPriorityHigh); Settings::ReadFile(); //printf("Passou Settings, carregou arquivo\n"); //Settings::ShowValues(); InitializeEthernetLink(); //printf("Inicializou link Ethernet\n"); //Start HTTP POST service Thread http_post(HttpPost::HttpPost_Thread); DisplayRAMBanks(); //Start TCP daemon service //Thread TcpService(CommTCP::CommTCP_Thread); //Start Telnet Service //Thread telnetserver(TelnetServer::TelnetServer_Thread); //Start TFTP Service /* unsigned short vet[256] = {2105,2105,2113,2127,2127,2125,2112,2113,2130,2130,2123,2112,2112,2128,2128,2123,2112,2113,2136,2136,2374,2551,2671,2869,2887,3036,2964,2964,2964,3145,3145,3206,3209,3298,3298,3264,3261,3208,3239,3239,3197,3197,3113,3032,3065,3065,3000,2901,2943,2943,2900,2852,2844,2863,2863,2838,2764,2791,2724,2724,2668,2710,2636,2658,2658,2606,2527,2443,2434,2434,2258,2066,2061,2080,2080,2063,2055,2055,2070,2070,2064,2051,2054,2069,2069,2062,2054,2058,2066,2309,2062,2052,2054,2067,2067,2063,2051,2049,2068,2068,2060,2053,2050,2067,2066,2069,2051,2053,2070,2070,2064,2050,2053,2070,2070,2062,2052,2055,2068,2068,2065,2052,2057,2072,2072,2064,2054,2054,2072,2072,2064,2053,2052,2069,2069,2064,2052,2053,2064,2064,2062,2049,2051,2067,2067,2059,2051,2050,2068,2068,2058,2046,2050,2068,2068,2061,2052,2058,2068,2068,2059,2052,2053,2067,2067,1744,1526,1471,1289,1289,1137,1142,1055,1120,1120,997,967,894,941,941,928,887,1001,949,949,1028,1105,1079,1191,1191,1223,1211,1223,1267,1267,1325,1267,1356,1327,1327,1369,1439,1381,1498,1498,1503,1503,1527,1545,1545,1635,1650,1778,1792,1792,1971,2108,2109,2126,2126,2124,2117,2118,2131,2131,2126,2118,2118,2138,2138,2134,2124,2114,2135,2135,2129,2121,2120,2136,2136,2128,2122,2122,2143,2120,2130,2120,2121,2139,2139,2130,2119,2121,2136,2136,2129}; float sen[12],cos[12],vm; SignalProcessor::CalculateFFT(vet,sen,cos,&vm,1); printf("VM = %f\n",vm); for(int i=0;i<12;i++) { printf("SEN%d = %f, COS%d = %f\n",i,sen[i],i,cos[i]); } */ printf("Nova versao [8]\n\n"); //printf("0x%lx\n", LargeBuffer); //Jump to the capture routine(will run on this thread) thread1(NULL); while(1){//never reaches here printf("Reset\n"); f = fopen(FILENAMERESET, "a"); if (f == NULL) f = fopen(FILENAMERESET, "w"); fprintf(f, "Laco Errado\n"); fclose(f); Thread::yield(); } } ■■■■■■■■■■ FFT_samle_11 ■■■■■■■■■■ #include "mbed.h" #include "adc.h" #include "NokiaLCD.h" #define MN 256 /*Number of points*/ #define SAMPLE_RATE 48000 NokiaLCD lcd(p5, p7, p8, p9, NokiaLCD::LCD6610); // mosi, sclk, cs, rst, type //Going to use the Mellen FFT rather than STM, as the STM (port by Igor) won't compile //extern "C" void cr4_fft_256_stm32(void *pssOUT, void *pssIN, uint16_t Nbin); extern "C" void fftR4(short *y, short *x, int N); //use the LED as a bargraph DigitalOut l1(LED1); DigitalOut l2(LED2); DigitalOut l3(LED3); DigitalOut l4(LED4); //set up a timer for timing FFT's Timer timer; Ticker ticker; //Set up filesystem so we can write some useful files LocalFileSystem local("local"); FILE *fp; //Set up a global buffer for audio data so interrupt can access it int Counter = 0; int16_t Buffer[5000]; //Initialise ADC to maximum SAMPLE_RATE and cclk divide set to 1 ADC adc(SAMPLE_RATE, 1); //Functions to write 16 bit audio data and 32 bit headers to files in au format (cf sndRecorder Cookbook) void fwrite16(uint16_t v) { uint8_t *b = (uint8_t *)&v; fprintf(fp,"%c%c", b[1], b[0]); } void fwrite32(uint32_t v) { uint8_t *b = (uint8_t *)&v; fprintf(fp,"%c%c%c%c", b[3], b[2], b[1], b[0]); } //Our interrupt handler for audio sampling void sample_ADC(int chan, uint32_t value) { float s; s = adc.read(p20); int16_t b = (s -2048)*16; Buffer[Counter] = b; Counter += 1; /* bar graph */ int g = abs(s-2048); l1 = g > 0.1f*2048; l2 = g > 0.3f*2048; l3 = g > 0.6f*2048; l4 = g > 0.8f*2048; } int main() { while (1) { //Prepare for burst mode on all ADC pins and set up interrupt handler (using ADC library from Simon Blandford adc.append(sample_ADC); adc.startmode(0,0); adc.burst(1); adc.setup(p20,1); //introduce a delay as initial waveform has bias whilst decoupling cap charges wait(.4); //start the interrupt and wait for about 4096 samples adc.interrupt_state(p20,1); wait(0.1); //Finsh up - Unset pin 20 adc.interrupt_state(p20,0); adc.setup(p20,0); int actual_rate = adc.actual_sample_rate(); //now lets try mellen fft lcd.background(0x0000FF); short mx[MN*2]; // input data 16 bit, 4 byte aligned x0r,x0i,x1r,x1i,.... short my[MN*2]; // output data 16 bit,4 byte aligned y0r,y0i,y1r,y1i,.... float data2[512]; for (int i=0;i<MN*2;i++) mx[i]=0; for (int i=0;i<MN;i=i+1) { mx[i*2]=Buffer[i]; } //FILE* mlog = fopen("/local/mellen.csv","w"); //call functions; fftR4(my, mx, MN); for (int i=0; i<MN; i=i+2) { data2[i]= sqrt(float( (my[i]*my[i]) +(my[i+1]*my[i+1]))); //fprintf(mlog, "%d,%f\n", int(actual_rate/MN/2*i),sqrt(float( (my[i]*my[i]) +(my[i+1]*my[i+1])) ) ); } //fclose(mlog); //Display amplitude on Nokia LCD lcd.cls(); for (int i=0; i<128; i++) { data2[i+1] = 20*log10(data2[i+1]); lcd.fill(i, 0, 2, data2[i+1], 0x00FF00); } Counter = 0; } }