Teensy Floating Point Audio Library: Sample Rates Changes

Here are a few thoughts on setting audio sample rates, in particular for the Teensy OpenAudio_ArduinoLibrary floating point processing. Bob W7PUA

First, looking back at the roots of the Teensy use, the interger version of the library has no direct provision for changing samplerate---it runs with 44.1 kilo sample per second (ksps). It is also 16-bit integer stereo. A bit of confusion could come because of the really good work of Frank B. to change the clock rate of the I2s processor of Teensy 3.x. See the forum post for lots of details. What this does is to change the hardware clock rate for the CODEC and the I2S interface. It does not alter the software parameters of the audio library.

Note that changing the I2S hardware clock rate leaves a number of I16 library objects running at the wrong rate, as they are ignorant of the rate change. Fixing these is up to the user of the I16 library. For instance, with waveform generators, you must call the frequency() function with an adjusted frequency. In some cases, such as with frequency domain filters, it is more difficult than this simple adjustment.

Next, we move to the Chip Audette OpenAudio_ArduinoLibrary which does most things in floating point, but more importantly for this discussion, adds a formal way to communicate the sample rate at startup. This sets the hardware I2S clock rate and for many, but not all, library objects, can be used to properly correct the computation of the data. An example of this is the sine wave generator, AudioSynthWaveformSine_F32 which will assume the default 44.1 ksps sample rate if it is instantiated as

  AudioSynthWaveformSine_F32 sine1;
but will run at a faster audio sample rate if it is instantiated with
  AudioSettings_F32           audio_settings(48000.0f, 128);
  AudioSynthWaveformSine_F32  sine1(audio_settings);

The next level of sample rate setting complexity is to make changes while the process is running. Elements of this are included in the floating point OpenAudio_ArduinoLibrary. But, it is not a complete organized capability. An example of using this with the Teensy 3.6 is the Audio Vector Network Analyzer. Dynamic sample rate with the Teensy 4 series will involve changing the I2S clock and using functions for library classes to adjust the computations. An example of the latter for the library class AudioSynthSineCosine_F32 is the function setSampleRate_Hz(float32_t fs_Hz). At this point though, implementing dynamic changes requires some familiarity with the Teensy Audio workings. Organizing this is on the list!

Setting sample rate at startup - Chip added a formal way to communicate the sample rate at object instantation, which, for the Teensy, is most often at startup. This ends up with code, such as,

  const float sample_rate_Hz = 48000.0f ;
  const int   audio_block_samples = 32;
  AudioSettings_F32 audio_settings(sample_rate_Hz, audio_block_samples);
  AudioInputI2S_F32           i2sIn(audio_settings);
  AudioAnalyzePeak_F32        peakL(audio_settings);
  AudioOutputI2S_F32          i2sOut(audio_settings);
  AudioConnection_F32         patchCord0(i2sIn,   0, peakL,  0);
  AudioConnection_F32         patchCord2(i2sIn,   0, i2sOut, 0);
  AudioControlSGTL5000        codec1;
  void setup() {
    AudioMemory_F32(20, audio_settings);
    // ... more code
  }

The class, AudioSettings_F32, has an object "audio_settings." This takes two parameters, the sample rate in Hz and the number of samples processed at once. We will ignore that second parameter here, and most often it is just left as 128. The first parameter is a floating point number, such as 48000.0f. In terms of sample rates, the AudioSettings_F32 class is simply communicating the desired rate.

Teensy Audio Board - PJRC has produced their SGTL5000 based audio board from the beginning and they are widely used for all sorts of applications, including SDR's. There is a separate version for Teensy 4.0 and 4.1, but the difference is only with pin connections. They all use the SGTL5000 CODEC. This is a good basic stereo ADC/DAC. In terms of sample rates, it is an interesting part. It is rated to be operated at sample rates from 8 to 96 ksps. We know that many people run these at 192 ksps and even higher. As a designer, I don't like to use thee higher rates, as they can be problems waiting to happen. I would reccomend that no design depend on the operation at rates like 192 ksps. There are other devices available that are designed for the higher rates, if that is needed.

To be aware of - Both the I16 and F32 audio libraries use time interrupts to initiate the processing of "audio" data (the DSP part of things). This processing occurs every 128 sample periods which at 48 ksps is 2.67 milliseconds (2670 microseconds) but at 96 ksps is half of that or 1.33 milliseconds. Data is coming in faster at 96 ksps than at 48 ksps, so it must be processed faster! Not having enough time to process the audio data results in severe waveform problems and must be prevented. To aid with this, many of the OpenAudio_ArduinoLibrary F32 classes have timing information that has been measured. This is often included in the ".h" include file for the class. As an example, the class, RadioFMDetector_F32, in the file RadioFMDetector_F32.h tells us

  * Time: For T3.6, an update of a 128 sample block, 430 microseconds, or
  *             3.4 microseconds per data point.
  *       For T4.0, 97 microseconds, or 0.76 microseconds per data point.
This means that performing this DSP function requires, for the Teensy 4, about 97/1333=0.073 or about 7.3% of available interrupt time. We have other processing to consider, such as band-pass filtering, so those numbers need to be added in as well. The sum total needs to be well below 1333 uSec (100%). How much below depends on how many other tasks, such as display updates, we have that require non-interrupt time, but need to happen without too much delay.

An additional factor is that functions such as frequency domain filters need greater complexity when the sample rate is increased. In some cases, the design of the library class can include "decimation and interpolation" to reduce this complexity. In other cases, such as full-band FFT's, tradeoffs between FFT resolution and compute time are inevitable. The important point is that higher sample rates require more processing than lower ones! This must be considered as part of the overall DSP design.

Software radios (SDR's) benefit from higher sampling rates by being able to view the spectrum around the receiving frequency. Increasing the sample rate increases the visible spectrum. That is a plus. But really, the most useful is the 10 or 20 kHz above and below. Looking across 100's of kHz is sometimes useful, but not usually. This suggests sample rates around 48 or 96 ksps may be a good rate to use.

p>

Back to W7PUA Home Page

Issued 1 Jan 2022 - All Copyright © Robert Larkin 2022