Heyo, so after my Teensy 3.2 randomly decided to fling off into outer space without leaving a notice as to why, I figured I'd give the 3.6 a shot.
Particularly intriguing was the speed and the support for CMSIS 4.5. I did what was mentioned in the "Excellent results with Floating Point FFT/IFFT Processing and Teensy 3.6" thread Here and Here
I however, can not get the 4096-point fft working using these new functions, I am probably doing everything wrong because I have no idea what I am doing, I'm trying though.
I simply went and modified analyze_fft1024.cpp and analyze_fft1024, and added #include "analyze_fft4096.h" to Audio.h
The code compiles and uploads without errors, but it just does nothing. Very enjoyable to troubleshoot.
Sketch:
Code:
#include <Audio.h>
#include <avr/power.h>
AudioInputAnalog adc1(A2);
AudioAnalyzeFFT4096 fft1;
AudioConnection patchCord2(adc1, fft1);
void setup() {
AudioMemory(16);
Serial.begin(9600);
fft1.averageTogether(8);
}
void loop() {
if (fft1.available()) {
for (uint16_t i = 0; i < 4096; i += 1) {
int32_t n = fft1.read(i);
Serial.print(n);
Serial.print(" ");
}
Serial.println();
}
}
analyze_fft4096.cpp:
Code:
/* Audio Library for Teensy 3.X
* Copyright (c) 2014, Paul Stoffregen, paul@pjrc.com
*
* Development of this audio library was funded by PJRC.COM, LLC by sales of
* Teensy and Audio Adaptor boards. Please support PJRC's efforts to develop
* open source software by purchasing Teensy or other PJRC products.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice, development funding notice, and this permission
* notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "analyze_fft4096.h"
#include "sqrt_integer.h"
#include "utility/dspinst.h"
// 140312 - PAH - slightly faster copy
static void copy_to_fft_buffer(void *destination, const void *source)
{
const uint32_t *src = (const uint32_t *)source;
uint32_t *dst = (uint32_t *)destination;
for (int i=0; i < AUDIO_BLOCK_SAMPLES; i++) {
*dst++ = *src++; // real sample plus a zero for imaginary
}
}
static void apply_window_to_fft_buffer(void *buffer, const void *window)
{
int32_t *buf = (int32_t *)buffer;
const int32_t *win = (int32_t *)window;;
for (int i=0; i < 4096; i++) {
int32_t val = *buf * *win++;
//*buf = signed_saturate_rshift(val, 16, 15);
*buf = val >> 15;
buf += 2;
}
}
void AudioAnalyzeFFT4096::update(void)
{
audio_block_t *block;
block = receiveReadOnly();
if (!block) return;
#if defined(KINETISK)
switch (state) {
case 0:
blocklist[0] = block;
state = 1;
break;
case 1:
blocklist[1] = block;
state = 2;
break;
case 2:
blocklist[2] = block;
state = 3;
break;
case 3:
blocklist[3] = block;
state = 4;
break;
case 4:
blocklist[4] = block;
state = 5;
break;
case 5:
blocklist[5] = block;
state = 6;
break;
case 6:
blocklist[6] = block;
state = 7;
break;
case 7:
blocklist[7] = block;
state = 8;
break;
case 8:
blocklist[8] = block;
state = 9;
break;
case 9:
blocklist[9] = block;
state = 10;
break;
case 10:
blocklist[10] = block;
state = 11;
break;
case 11:
blocklist[11] = block;
state = 12;
break;
case 12:
blocklist[12] = block;
state = 13;
break;
case 13:
blocklist[13] = block;
state = 14;
break;
case 14:
blocklist[14] = block;
state = 15;
break;
case 15:
blocklist[15] = block;
state = 16;
break;
case 16:
blocklist[16] = block;
state = 17;
break;
case 17:
blocklist[17] = block;
state = 18;
break;
case 18:
blocklist[18] = block;
state = 19;
break;
case 19:
blocklist[19] = block;
// TODO: perhaps distribute the work over multiple update() ??
// github pull requsts welcome......
copy_to_fft_buffer(buffer+0x000, blocklist[0]->data);
copy_to_fft_buffer(buffer+0x100, blocklist[1]->data);
copy_to_fft_buffer(buffer+0x200, blocklist[2]->data);
copy_to_fft_buffer(buffer+0x300, blocklist[3]->data);
copy_to_fft_buffer(buffer+0x400, blocklist[4]->data);
copy_to_fft_buffer(buffer+0x500, blocklist[5]->data);
copy_to_fft_buffer(buffer+0x600, blocklist[6]->data);
copy_to_fft_buffer(buffer+0x700, blocklist[7]->data);
copy_to_fft_buffer(buffer+0x800, blocklist[8]->data);
copy_to_fft_buffer(buffer+0x900, blocklist[9]->data);
copy_to_fft_buffer(buffer+0x1000, blocklist[10]->data);
copy_to_fft_buffer(buffer+0x1100, blocklist[11]->data);
copy_to_fft_buffer(buffer+0x1100, blocklist[12]->data);
copy_to_fft_buffer(buffer+0x1200, blocklist[12]->data);
copy_to_fft_buffer(buffer+0x1300, blocklist[13]->data);
copy_to_fft_buffer(buffer+0x1400, blocklist[14]->data);
copy_to_fft_buffer(buffer+0x1500, blocklist[15]->data);
copy_to_fft_buffer(buffer+0x1600, blocklist[16]->data);
copy_to_fft_buffer(buffer+0x1700, blocklist[17]->data);
copy_to_fft_buffer(buffer+0x1800, blocklist[18]->data);
copy_to_fft_buffer(buffer+0x1900, blocklist[19]->data);
if (window) apply_window_to_fft_buffer(buffer, window);
arm_cfft_radix4_q31(&fft_inst, buffer);
// TODO: support averaging multiple copies
for (int i=0; i < 2048; i++) {
uint32_t tmp = *((uint32_t *)buffer + i); // real & imag
uint32_t magsq = multiply_16tx16t_add_16bx16b(tmp, tmp);
output[i] = sqrt_uint32_approx(magsq);
}
outputflag = true;
release(blocklist[0]);
release(blocklist[1]);
release(blocklist[2]);
release(blocklist[3]);
release(blocklist[4]);
release(blocklist[5]);
release(blocklist[6]);
release(blocklist[7]);
release(blocklist[8]);
release(blocklist[9]);
blocklist[0] = blocklist[10];
blocklist[1] = blocklist[11];
blocklist[2] = blocklist[12];
blocklist[3] = blocklist[13];
blocklist[4] = blocklist[14];
blocklist[5] = blocklist[15];
blocklist[6] = blocklist[16];
blocklist[7] = blocklist[17];
blocklist[8] = blocklist[18];
blocklist[9] = blocklist[19];
state = 10;
break;
}
#else
release(block);
#endif
}
analyze_fft4096.h
Code:
/* Audio Library for Teensy 3.X
* Copyright (c) 2014, Paul Stoffregen, paul@pjrc.com
*
* Development of this audio library was funded by PJRC.COM, LLC by sales of
* Teensy and Audio Adaptor boards. Please support PJRC's efforts to develop
* open source software by purchasing Teensy or other PJRC products.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice, development funding notice, and this permission
* notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef analyze_fft4096_h_
#define analyze_fft4096_h_
#include "Arduino.h"
#include "AudioStream.h"
#include "arm_math.h"
// windows.c
extern "C" {
extern const int32_t AudioWindowHanning4096[];
}
class AudioAnalyzeFFT4096 : public AudioStream
{
public:
AudioAnalyzeFFT4096() : AudioStream(1, inputQueueArray),
window(AudioWindowHanning4096), state(0), outputflag(false) {
arm_cfft_radix4_init_q31(&fft_inst, 4096, 0, 1);
}
bool available() {
if (outputflag == true) {
outputflag = false;
return true;
}
return false;
}
float read(unsigned int binNumber) {
if (binNumber > 2047) return 0.0;
return (float)(output[binNumber]) * (1.0 / 16384.0);
}
float read(unsigned int binFirst, unsigned int binLast) {
if (binFirst > binLast) {
unsigned int tmp = binLast;
binLast = binFirst;
binFirst = tmp;
}
if (binFirst > 2047) return 0.0;
if (binLast > 2047) binLast = 2047;
uint32_t sum = 0;
do {
sum += output[binFirst++];
} while (binFirst <= binLast);
return (float)sum * (1.0 / 16384.0);
}
void averageTogether(uint8_t n) {
// not implemented yet (may never be, 86 Hz output rate is ok)
}
void windowFunction(const int32_t *w) {
window = w;
}
virtual void update(void);
uint32_t output[2048] __attribute__ ((aligned (4)));
private:
void init(void);
const int32_t *window;
audio_block_t *blocklist[8];
int32_t buffer[8192] __attribute__ ((aligned (4)));
//uint32_t sum[2048];
//uint8_t count;
uint8_t state;
//uint8_t naverage;
volatile bool outputflag;
audio_block_t *inputQueueArray[1];
arm_cfft_radix4_instance_q31 fft_inst;
};
#endif
I am aware there are other methods to implement this, but honestly, the audio library makes using this stuff so exceptionally convenient.