Slow FFT on Pico

Posted on
  • I'm trying to experiment with audio analysis on the Pico and am running into slower than expected performance.

    I've specifically picked this board because it runs on the Cortex M4 MCU with accelerated DSP via CMSIS. (It is unclear if it has an FPU, but I'm not using it here, so...) I've run some timings and am getting ~44ms to run E.FFT() on a 128 16-bit data:

    var w = new Waveform(128, {doubleBuffer:true, bits:16});
    var a = new Uint16Array(128);
    w.on("buffer", function(buf) {
        var l = buf.length;
        var start =;
        console.log( - start);
    w.startInput(B1, 44100, {repeat:true});

    At best, this is 1000/44 = 22.72 FFTs per second.
    According to benchmarks done in­nchmarking-fft-speed.html, Arduino M0, which has a slower chip with no DSP unit does 639 FFTs per second, while a Teensy 3.2, which runs a similarly specced NXP chip manages 7156 FFTs per second when not using accelerated DSP and 14286 when doing so.

    So, what's going on? Am I reading it wrong or calling it wrong?
    I get that their benchmark is in C while Pico is running interpreted JS, but E.FFT() just calls into the C library function, so there shouldn't be much overhead there. Looking at the GitHub sources, I do see that on the Pico, E.FFT() supposedly calls into CMSIS, so this should be really fast.

  • I'm pretty sure E.FFT doesn't call into CMSIS... The issue is that it has to deal with all different kinds of input data, and JavaScript's default number type is float64 so that's what the FFT uses - however the floating point hardware can't handle float64 at all. It means everything is happening in software - plus there's the format conversion too.

    I'm honestly not sure if anyone would notice if it changed to Float32 though - and that would be possible to accelerate and would be pretty fast.

    One option is to use the inline C code with an integer FFT:

    I'm not sure how realistic using CMSIS would be but even a normal integer FFT should be pretty speedy.

    However, I think ultimately you're going to end up a bit disappointed trying to do audio in JavaScript with Espruino. As noted on the Waveform page ( you're limited to around 10k samples/sec for input - the Waveform's trying to prioritise flexibility over outright performance (eg allowing polyphonic sound and multiple concurrent inputs).

    You could use the hardware directly with DMA buffers though - either with C code or by poking registers with JavaScript - but it's not going to be super easy.

  • I see... that's a bummer. I really like the Waveform's ease of use and was hoping that it would provide me with the best of both worlds - a convenient JS code for doing some light post-processing and output, coupled with an efficient internal implementation.

  • The same software has to handle waveform play, record, wakeups, and things like digitalPulse (sometimes all at once) - and has to work on 40+ different boards. While it'd be nice to use DMA and different timers automatically, it's just too much of an ask.

    ... even when you get 44kHz data into JS-land, there are going to be some severe limits on what changes you can make to it with JS since it's just not that fast. Personally I'd look at compiling your own Espruino, then setting up DMA record and playback as well as most of the audio processing you require in C code on interrupts - and then you could use JS to control the audio processing (adding envelopes/etc).

  • Post a reply
    • Bold
    • Italics
    • Link
    • Image
    • List
    • Quote
    • code
    • Preview

Slow FFT on Pico

Posted by Avatar for mleibman @mleibman