Forum Rule: Always post complete source code & details to reproduce any issue!
Results 1 to 4 of 4

Thread: Test Tone Generator, log frequency sweep, Grid Generator 250 kHz sample frequency

  1. #1

    Test Tone Generator, log frequency sweep, Grid Generator 250 kHz sample frequency

    Hi,
    this might perhaps be interesting for some guys working on audio projects.

    It is a testtone-generator which can do logarithmic frequency sweeps. If you have a 2-channel oscilloscope, then the second channel ist used for trigger and to display a logarithmic frequency grid, which is very handy to see the frequency response. See attachment for an example 80Hz to 10kHz.

    In addition to a constant tone and two different sweeps there is a mode to test for compression. The volume of a 400Hz signal is modulated: low-high-low. This is interesting for Guitar Amps or effects.

    It took me a while to get a high sample rate for good looking 20kHz. There is some compromise: At low frequency, the precision of the frequencies is not so good and there are some stops of the output between bursts of clear signal.

    /*Potentiometer at A0 for selection of 4 different functions:
    1. 400Hz constant Test Tone
    2. Sweep for Guitar 80…10000Hz
    3. Compresstest 400Hz; 1/4=>1=>1/4 Amplitude
    4. Sweep for general use 20Hz … 20kHz

    NF Output at A14, 12 bit
    Grid Output with 2bit-Dac using digital outputs at 15 and 16 Trigger full 3.3V, Grid 0…1,65V
    LED Pin 13 indicates Poti Mode
    */

    Code:
    #define VERSION "TeensyDac_J"
    // for Teensy 3.2 09.05.2019 CWE
    /*Potentiometer at A0 for selection of functions:
      1. 400Hz constant Test Tone
      2. Sweep for Guitar 80…10000Hz
      3. Compresstest 400Hz; 1/4=>1=>1/4 Amplitude
      4. Sweep for general use 20Hz … 20kHz
    
    NF Output at A14, 12 bit
    Grid Output with 2bit-Dac using digital outputs at 15 and 16 Trigger full 3.3V, Grid 0…1,65V
    LED Pin 13 indicates Poti Mode
    */
    
    
    #include <math.h>
    
    float phase = 0.0;
    float twopi = 3.14159 * 2;
    elapsedMicros usec = 0;
    const int ledPin = 13;
    // #define gridPin A22
    #define gridP1 15
    #define gridP2 16
    #define dacPin A14 //A21 for 3.5
    #define potiPin A0 // For selection of modes
    
    # define BUFLEN 16384
    
    
    void startblink(int n)
    {
      int i;
      for(i=0; i<n; i++)
      {
        digitalWrite(ledPin, HIGH);   // set the LED on
        delay(150);                  // wait for a second
        digitalWrite(ledPin, LOW);    // set the LED off
        delay(150);                  // wait for a second
      }
    }
    
    int bufmax;
    short int buffer[BUFLEN+1];
    void fillbuffer()
    {
      int i=0;
      while(phase < twopi)
      {
          float val = sin(phase) * 2047.0; //+ 2050.0; // 0.1/1.17 f. 1000mV RMS
          //float val = 100.0/950.0*sin(phase) * 2000.0 + 2050.0; // f. 100mV RMS      
          buffer[i]= (int)val;
          phase = phase + twopi/(BUFLEN);
          i++;
      }
      float val = sin(phase) * 2047.0; //+ 2050.0;
      buffer[i]= (int)val;
    }
    
    
    unsigned long timeu;
    float freq= 200.0;
    float tcyc= 2.0;
    float fsteps[30]= {10.0, 20.0, 30.0, 40.0, 50.0, 60.0, 70.0, 80.0, 90.0, 100.0, \
                       200.0, 300.0, 400.0, 500.0, 600.0, 700.0, 800.0, 900.0, 1000.0, \
                       2000.0, 3000.0, 4000.0, 5000.0, 6000.0, 7000.0, 8000.0, 9000.0, 10000.0,20000.0};
    
    
    
    void setup() {
      pinMode(ledPin, OUTPUT);
      pinMode(gridP1, OUTPUT);
      pinMode(gridP2, OUTPUT);    
      // pinMode(gridPin, OUTPUT);  
      digitalWrite(gridP1, 0);
      digitalWrite(gridP2, 0);  
      analogWriteResolution(12);
      //analogWrite(gridPin, 0);
      analogWrite(dacPin, 2048);      
      startblink(10);
      Serial.begin(115200);  
     
      fillbuffer();
      Serial.println(VERSION);
      Serial.println("Buffer gefuellt.");
      //startblink();
    }
    
    
    
    float frmin;
    float frmax;
    float twidth; //us
    
    void loop() {
      int poti= analogRead(potiPin)*5/1024 + 1;
      Serial.println(poti);
      startblink(poti);
      
      if(poti==1) // Constant 400Hz
      {
        frmin= 400.0;
        frmax= 400.1;
        twidth= 2000000.0; //us
        sweep_C();    
      } 
      
      if(poti==2) // Spweep for Guitar
      {
        frmin= 80.0;
        frmax= 10000.0;
        twidth= 2000000.0; //us
        sweep_C();    
      }
    
      if(poti==3) // Compresstest 400Hz
      {
        comp_B();    
      } 
    
     
      if(poti==4) // Spweep for Audio
      {
        frmin= 20.0;
        frmax= 20000.0;
        twidth= 2000000.0; //us
        sweep_C();    
      }  
    
      //while(1);
    }
    
    int iold=0, iakt, ifrequenz, imode=1, ifakt, irepeats=100, ideltat;
    unsigned long oldu, aktu;
    float frfaktor;
    
    void fastsample(void)
    {
      // ifrequenz=20000;
      ifakt= ifrequenz*BUFLEN/(1000000/4);
      iakt=0;
      oldu=micros()/4;
      for(int i=0; i<irepeats; i++)
      {  
        do
        {
          if(imode==1) analogWrite(dacPin, 2048 + buffer[iakt]);
          else analogWrite(dacPin, 2048 + buffer[iakt]/4);
          aktu=micros()/4;
          iakt+=(aktu-oldu)*ifakt;
          oldu=aktu;
        } while(iakt<BUFLEN);
        iakt-=BUFLEN;
      }
      analogWrite(dacPin, 2048);
    }
    
    
    void comp_B() // Compressortest
    {
      ifrequenz=400;
      imode = 0; 
      irepeats= 266;
      fastsample();
      imode=1;
      //analogWrite(gridPin, 4095);  //Trigger
      digitalWrite(gridP1, 1);
      digitalWrite(gridP2, 1);   
      fastsample();
      imode=0;
      //analogWrite(gridPin, 0);  //Trigger
      digitalWrite(gridP2, 0);
      digitalWrite(gridP1, 0);  
      fastsample();  
    }
    
    void sweep_C()
    {
      int fstep=0;
    
      unsigned long int tistart;
      int gridstat;
      
      float ffaktor= (log10(frmax)-log10(frmin))/twidth;
      float log10frmin= log10(frmin);
      freq= frmin;
      
      
      //analogWrite(gridPin, 4095);  //Trigger
      digitalWrite(gridP1, 1);
      digitalWrite(gridP2, 1);  
      gridstat=1;
      
      tistart= micros();
      oldu= tistart;
      imode=1;
      iakt=0;
      iold=0;
      
      
      while(freq<frmax)
      {
        //frfaktor= freq*BUFLEN/1000000.0;    
        //Serial.println(freq);
        ifrequenz=freq;
       
        while(freq>=fsteps[fstep]) // Next grid line
        {
          if(gridstat<1)
          {
              //analogWrite(gridPin, 2048);
              digitalWrite(gridP1, 1);
              digitalWrite(gridP2, 0);            
              gridstat=1;
          }
          else
          {
              //analogWrite(gridPin, 0); 
              digitalWrite(gridP1, 0);
              digitalWrite(gridP2, 0); 
              gridstat=0;        
          }
          //Serial.println("Grid");
          fstep++;
        }
    
        // fastsample();
        
        if(freq<100.0) irepeats= 1;
        else if(freq<1000.0) irepeats= 5;
        else if(freq<5000.0) irepeats= 10;   
        else if(freq<10000.0) irepeats= 30;
        else irepeats=100; 
    
        fastsample();
    
        float fhelp= ffaktor*(micros()-tistart);
        fhelp += log10frmin;
        freq= pow(10,fhelp); 
      }
      //analogWrite(gridPin, 0);  
      digitalWrite(gridP1, 0);
      digitalWrite(gridP2, 0);
      gridstat=0;
      imode=0;
      analogWrite(dacPin,2048);
      delay(1000);
    }
    The hardware is pretty simple.

    Suggestions for additional modes?

    Enjoy!
    Christof
    Attached Thumbnails Attached Thumbnails Click image for larger version. 

Name:	Teensy DAC Testtone Generator.JPG 
Views:	4 
Size:	111.1 KB 
ID:	16581   Click image for larger version. 

Name:	NewFile14.jpg 
Views:	5 
Size:	91.0 KB 
ID:	16582  

    Last edited by cebersp; 05-09-2019 at 03:56 PM.

  2. #2
    Junior Member
    Join Date
    May 2019
    Posts
    7
    Linear sweep! Itvs very convinient for calculating spectra since the energy per unit bandwidth is constant, contrarry to log sweep.

  3. #3
    Junior Member
    Join Date
    May 2019
    Posts
    7
    and the analog output of the 3.6 can go beyond 1MHz.. for audio thats to much, but for ultrasonic ranging or sonar it might be interesting. Even for extended amplifier testing it might be fun to be able to test a few octaves above 20k

  4. #4
    Hi tschrama,

    thanks for the replies! Linear sweep would be very easy to implement.

    As the sample frequency is 250kHz, you could go well over 20kHz. This high frequency signal would not look very much like a sine.
    Along the signal path of a guitar effect (not at the output) I found that high frequencies have a high gain factor. This led to the effect, that the high frequency content of a signal, which was not a nice looking clear sine, got amplified very much. So I decided, that a "good clean" sine is important.


    For higher sample rate there seem to be limits using the easy Arduino environment. Calling function seems to have a very large overhead which consumes a lot of cycles. But I did not investigate this in more depth. I did not even block interrupts.


    Christof

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •