Skip to content

Configuration & Platforms

SignalCore needs almost no configuration. The defaults adapt to the target board on their own. The defines below exist for the cases where you want to override that behavior, or understand what the library chose for you.

Build-time defines

Set any of these before #include <SignalCore.h> to change the library's behavior.

Macro Default What it controls
SIGNALCORE_FORCE_CMSIS (off) On a non-Teensy ARM core, switch to the CMSIS-DSP FFT backend. The switch is unconditional — it does not detect support. If the core does not ship arm_math.h the build stops with a clear #error; if the core ships the header but does not link the DSP objects, expect undefined reference to arm_rfft_fast_* linker errors. Ignored on non-ARM boards.
SIGNALCORE_MAX_FFT_SIZE 256 (AVR) · 1024 (ESP8266) · 4096 (other) The largest FFT size the build will accept. The FFT<> template checks its size against this with a static_assert, so an oversized transform fails to compile instead of exhausting RAM at run time. Define it before the include to raise the cap on a larger AVR part (or lower it to guard a tight build).

The library also defines three mutually exclusive backend-selection macros that you are not expected to set: SIGNALCORE_USE_CMSIS, SIGNALCORE_USE_ESP_DSP (reserved for a future ESP-DSP wrapper), and SIGNALCORE_USE_GENERIC. Platform.h sets exactly one of them based on the target board. A sketch can test them to report which path is active:

#if defined(SIGNALCORE_USE_CMSIS)
    Serial.println("FFT backend: CMSIS-DSP");
#else
    Serial.println("FFT backend: generic C++");
#endif

Supported platforms

Board family Backend Notes
Teensy 4.x CMSIS-DSP Auto-selected via TEENSYDUINO
Other ARM (STM32, Giga, SAMD51) Generic C++ Define SIGNALCORE_FORCE_CMSIS to opt in to CMSIS if the core links it
ESP32 / ESP32-S3 Generic C++ ESP-DSP wrapper reserved for future use
RP2040 / RP2350 Generic C++
SAMD21 Generic C++
AVR (UNO, Nano, Pro Micro) Generic C++ FFT capped at 256 points by SIGNALCORE_MAX_FFT_SIZE; ATmega328 boards (2 KB SRAM) fit FFT<128> at most in practice
ESP8266 Generic C++ FFT capped at 1024 points
Any Arduino-compatible board with a C++11 compiler Generic C++

The generic backend produces the same output as the CMSIS backend, bin for bin (it matches the arm_rfft_fast_f32 packing), so spectrum-analysis sketches behave the same across all of these boards.

Memory footprint

FFT<N> reserves 2·N + N/2 floats statically. That memory is fixed at compile time and never comes from the heap. The three pieces are the input samples (N floats), the result buffer (N floats), and the half-window coefficients (N/2 floats):

FFT size Static RAM
256 ~2.5 KB
512 ~5 KB
1024 ~10 KB
2048 ~20 KB
4096 ~40 KB

At a size of 1024 that works out to 1024 + 1024 + 512 = 2560 floats, or 10 KB. On AVR the compile-time static_assert blocks any size above SIGNALCORE_MAX_FFT_SIZE (256 by default). Note that the 256 cap targets larger AVR parts such as the Mega 2560 (8 KB of SRAM): per the table above, FFT<256> alone needs ~2.5 KB, more than an ATmega328's entire 2 KB — on an UNO R3 or Nano the practical ceiling is FFT<128> (~1.3 KB plus your own sample buffer).

PeakHoldProcessor and ExponentialMovingAverage size their buffers when constructed, or when you call init(), and they take that memory from the heap rather than reserving it statically. On a RAM-tight board such as an AVR, create them once at the size you need early in setup(), rather than resizing them in the loop. Repeated resizing leaves small unusable gaps in the heap, a problem called fragmentation, that can eventually starve later allocations.


Created by VoidLoop · Founded by Gregory Kovacs · Written by Zachariah Magee