noise in DAC aoutput on Teensy 3.2 using sine sample code

Status
Not open for further replies.

jrdarrah

Well-known member
I'm stumped. I've tried everything I can think of to get rid of the 6.35 hz peak and the garbage up to the 2K peak from the sine wave sample. I lowered the teensy clock to 24 MHz in case that was the cause I also changed the cable which only has a single 100uf cap in the signal path. Previously it was a low pass filter at about 16khz. No change, I still show the large peak at 6.36hz and it tapers off in a linear fashion down to the peaks I'd expect from the sine code. I'm recording up to 0db hoping the signal would be higher than the noise. Still showing the same basic wave form. The FFT is from Adobe Audition and the sound card is built into my Lenovo M900. Does anyone have an idea where I could be getting the almost 0db peak at 6.35hz? I'm out of things to try other than a new sound card or another teensy. Thanks.

Attached is the frequency analysis screen from audition.
teensy 3.2 sine sample.jpg

Code:
#include "math.h"
//Teensy 3.2 & 3.1 have a proper analog output. You can always filter PWM, but true analog output responds rapidly. The output is created by the stable reference voltage, so it's doesn't vary if your power supply voltage changes slightly. 

// Simple DAC sine wave test on Teensy 3.1

float phase = 0.0;
float twopi = 3.14159 * 2;
elapsedMicros usec = 0;

void setup() {
    Serial.begin(57600);
  analogWriteResolution(12);
}

void loop() {
 float val = sin(phase) * 2000.0 + 2500.0;
 //   float val = sin(phase) * 2000.0;
  analogWrite(A14, val);
// Serial.println(val);
  phase = phase + 0.02;
  if (phase >= twopi) phase = 0;
  while (usec < 500) ; // wait
  usec = usec - 500;
}
 
First, use sinf(), not sin().

Try pre-computing the data into an array of integers in setup(), so in loop() you access access the array rather than calling the trig function. Access to the array will be fast and have fixed timing. The algorithm in the math library can have variable, data dependent timing.
 
can you look with a scope at just the DAC output. that sketch produces a nice 6.36 hz sine wave
315 samples @ 500us/sample, 0 to 3.3v. if you probe behind a 10uf blocking capacitor, you get -1.64 to 1.64 v

the computational overhead is about 50us/sample with T3.2@96mhz

dacsinecap.png
 
Last edited:
Thanks for the info. I'll try it tonight after I get off work.

Manitou, I didn't do the math to realize this was really a 6.36 hz sine wave. That helps what I'm seeing in the frequency analysis make sense. The 6.36 hz should and is the highest peak. I'll now need to figure out why the tall peaks are showing up on the right end of the display. I'm thinking they are aliases of the original data.

How do you figure 50 us computational overhead number you mentioned in your post. I'm working on another project that uses an interrupt called to produce 44100 samples / sec and integer tables to produce the sound that I was trying to diagnose. Lacking progress on that front I decided to go to the basics which is why I dropped back to the sine sample code. I'd like to check my other code timing. Dating myself but when I started programming on mainframes back in the mid 1970s we had to squeeze all we could out of the code to get it to run faster. To that end there were compiler run time options that would profile the code to see where it was spending the most time. That way you could optimize it and make the whole program run faster. I'm sure there are techniques for that in the teensy/arduino world. I'm still learning this platform.
 
You can use micros() to measure elapsed time of a computation, perhaps extracting the statements of interest into a small test program. With a scope or logic analyzer you can set a pin LOW/HIGH around a section of interest. At a fine level you can use systick to count cycles or look at the disassembled code with the help of the ARM architecture reference manual. The latest IDE allows you to select optimization options (FAST FASTER ...)

For the DAC sine sketch, you could remove the while-usec delay and let it run at full speed. the period with no delay is about 15.8 ms, divide that by 315 samples, and you get about 50 us computation delay. As Paul suggests, if you want to go faster you should pre-calculate the sine values. The limiting factor will then be the DAC settle time, datasheet says 15us, but Paul suggests 2us see
https://forum.pjrc.com/threads/26036-Fastest-DAC-speed-possible-for-Teensy-3-1-using-Arduino

Code:
 single sample computation time (us)
  Teensy  MHz  sin   sinf
   T3.2    96   49     29
   T3.2   120   48     28
   T3.5   120   35      7   (hardware float)
   T3.6   180   15      2   (hardware float)

Look at Paul's sound library for optimized sound management
https://github.com/PaulStoffregen/Audio
 
Last edited:
There is a huge error in your code which makes the DAC output a distorted, clipped/mirrored signal:
Code:
float val = sin(phase) * 2000.0 + 2500.0;
will output values from 500 to 4500, while the DAC range is only 0 to 4095 like every 12bit DAC.
Thus, use
Code:
float val = sin(phase) * 2000.0 + 2048.0;
!!!

Second, the code in posting #1 is prone to lots of timing problems which can lead to phase jitter, depending on the time, the loop() including all the hidden yield() stuff needs to run through. Thus, it's not a reliable test code for spectral purity. For that, you need code which uses the PDB to trigger an exact DAC (and DMA) timing, like it's done in the audio lib.
 
I've posted questions on several boards and have found this one to be the most helpful and willing to help someone like me who doesn't know enough yet ask a proper question. Thanks for your patience. The answers to this thread have given me some ideas about on how to get a better sound.
 
probably should be float val = sinf(phase) * 2048.0 + 2048.0;
btw, my little scope figure above was using 2048 values
 
Last edited:
I've posted questions on several boards and have found this one to be the most helpful and willing to help someone like me who doesn't know enough yet ask a proper question. Thanks for your patience. The answers to this thread have given me some ideas about on how to get a better sound.

Perhaps not the optimal approach... IMNSHFO, one should study electronic engineering and coding first, and only then, once you master all the stuff, start buying components and building projects....
 
The code I used was from the teensy 3.2 new features web page so it might need correcting there. I'll fix my copy and Rerun Thanks
 
Status
Not open for further replies.
Back
Top