DAC generate irritating high frequencies when used with a 8khz sample rate

I'm trying to use a TDA1543 DAC in order to generate an analog audio signal.

The samples are generated with a bytebeat formula.

The fact is, when I set the sample rate of the DAC at 8Khz (the frequency that generate classic bytebeat melodies) I get very loud high frequencies.

But when I increase the sample rate to 24000 or 32000, the high frequencies disappear. It's great, but it is not classic bytebeat anymore. ( bytebeat need to be sampled at 8khz. With an 8-bit variable, it increases to 255 and generate an 8000/255=~31.30Hz sawtooth).

It is because the sampling rate is inside the audio range ?

Here is my code:

#include <I2S.h>

// Create the I2S port using a PIO state machine
I2S i2s(OUTPUT);

// GPIO pin numbers
#define pBCLK 1
#define pWS   2
#define pDOUT 3

const int sampleRate = 24000;

void setup() {

  Serial.begin(115200);
  Serial.println("I2S simple tone");

  i2s.setBCLK(pBCLK);
  i2s.setDATA(pDOUT);
  i2s.setBitsPerSample(16);

  if (!i2s.begin(sampleRate)) {
    Serial.println("Failed to initialize I2S!");
    while (1); // do nothing
  }

}

void loop() {
  static int t = 0;

  long value = ((t >> 10) & 42) * t;

  Serial.println(value);

  // write the same sample twice, once for left and once for the right channel
  i2s.write(value);
  i2s.write(value);

  t++;
}

It's probably due to aliasing. If you sample at 8kHz you have to put the input to the ADC through a low pass filter to remove any frequencies > 0.5 * 8kHz.
When you sample at 24kHz or 32kHz you don't hear a problem because either the original input doesn't contain much above 12 kHz or 16 kHz and / or the spurious high frequencies can't be reproduced by your speaker or heard by you.
See Nyquist frequency - Wikipedia

2 Likes

A closer look reveals a stair output, not a sawtooth. Each step introduces harmonic frequencies which have to be reduced/eliminated by a discrete low pass filter.

If you are sampling at 8 kHz, then you need a very good low pass filter for the output signal, such that any component with frequency above about 4 kHz becomes insignificant.

This site gives some background and examples of bytebeat.

In any case, this loop does NOT create samples at 8 kHz sample rate. It does not even have a fixed or well defined sample rate, because the serial print can take variable amounts of time to execute.

void loop() {
  static int t = 0;
  long value = ((t >> 10) & 42) * t;
  Serial.println(value);
  // write the same sample twice, once for left and once for the right channel
  i2s.write(value);
  i2s.write(value);
  t++;
}
1 Like

I think I don't use the correct term. I don't want to record a sample from an output source.

I want to output samples generated by bytebeat synthesis on the mcu to a DAC with I2S protocol.

If you are sampling at 8 kHz, then you need a very good low pass filter for the output signal, such that any component with frequency above about 4 kHz becomes insignificant.

Ok, so it joins what DrDiettrich says.

This site gives some background and examples of bytebeat.

I know dollchan. My aim is to get roughly the same audio quality as the website output with a DAC.

In any case, this loop does NOT create samples at 8 kHz sample rate. It does not even have a fixed or well defined sample rate, because the serial print can take variable amounts of time to execute.

Hum. The sample rate is set in the setup

if (!i2s.begin(sampleRate)) {
    Serial.println("Failed to initialize I2S!");
    while (1); // do nothing
  }

with sampleRate = 8000 for exemple
You can guess that I didn't leave the Serial.println on all my tests and I had almost the same results

So the best way I can follow is the discrete low pass filter in order to get rid of these unwanted frequencies.

That has nothing to do with how often the loop executes, unless the function I2s.write() blocks, which won't happen if the loop is slower than the sample rate.

According to the documentation, the writes call are blocking, unless a second parameter "sync" is provided

I'm on a pico btw so I think 133Mhz is fast enough for 8Khz sampleRate audio

https://arduino-pico.readthedocs.io/en/latest/i2s.html

Take out the Serial.print and test again. You are NOT thinking this through.

I removed it. It might be a little better, but it's so imperceptible that I'm not sure.
There's still a hiss in the background.
Maybe putting a low pass filter will finish the job

Maybe you are hearing the harmonics.
When sampling at 8khz probably you hear something around 16 khz.

When sampling at 24 khz, the harmonic might be ~48 khz, speaker should be unable to reproduce, and ear is unable to catch that.

Low pass filtering might help, but a simple r-c filter might not be enough. And it will interact with the speaker.

2nd order sallen key low pass filter might add too many electronic components.

Hi, @sercurio

Do you have an oscilloscope?
As you are experimenting in the audio world, it would be of a great advantage to have one.

Even a cheap microcontroller based unit that is only 500KHz bandwidth would help.
https://www.aliexpress.com/item/1005006849125772.html?spm=a2g0o.productlist.main.1.1ad252b8w8r7VO&algo_pvid=f8ca5f07-f4cf-47de-ab3b-9061778c8229&algo_exp_id=f8ca5f07-f4cf-47de-ab3b-9061778c8229-0&pdp_npi=4%40dis!AUD!63.02!31.59!!!299.10!149.91!%402103010f17250609186847652e1206!12000038508497098!sea!AU!754111335!X&curPageLogUid=H7ojfLi7xoVG&utparam-url=scene%3Asearch|query_from%3A

Or Google;

arduino oscilloscope

There are many projects out there for you to maske your own test gear.

Tom... :smiley: :+1: :coffee: :australia: