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

Thread: Heteroskedastic discrepancy between buffers collected and system time

  1. #1
    Junior Member
    Join Date
    Apr 2019
    Posts
    3

    Heteroskedastic discrepancy between buffers collected and system time

    Hardware: Teensy 3.5 with Audio Shield SGTL5000
    OS: Windows 10

    Problem: Heteroskedastic divergence between implied audio input buffer time and system time. I'm trying to figure out how to keep exact time from the buffers that the Audio library is reading from the ADC. However, adding up the total number of read buffers produces an increasing discrepancy over time with the system time obtained by turning off interrupts and calling micros(). The picture below is the 1s rolling mean of the difference between the implied buffer time and the system time since the beginning of the program. I subtracted the first value of the difference from all subsequent differences--the system time includes all of the setup time and comes out to ~700,000 microseconds on the hardware that I'm using.

    There is also a small drift that happens every 64 buffers collected that I've added a correcting factor for, but that's not nearly as big a problem as the increasing variance between micros() and the sum of the buffer lengths as time goes on. It looks like a kind of accumulating error to me, but I have't been able to find an accumulating error in my code. I was wondering if anyone else has encountered a similar problem?
    Click image for larger version. 

Name:	image.jpg 
Views:	12 
Size:	59.3 KB 
ID:	16510

    Code:
    Code:
    #include <Audio.h>
    #include <Wire.h>
    #include <SPI.h>
    #include <SD.h>
    #include <SerialFlash.h>
    #include <math.h>
    #include "AudioSampleDutycycle.h"
    
    #define SDCARD_CS_PIN    10
    #define SDCARD_MOSI_PIN  7
    #define SDCARD_SCK_PIN   14
    #define AUDIO_BUFF_LN      128
    
    // GUI Code Begins Here
    AudioInputI2S            i2s1;
    AudioPlayMemory          playMem1;
    AudioAmplifier           amp1;
    AudioRecordQueue         queue1;
    AudioOutputI2S           i2s2;
    AudioConnection          patchCord1(i2s1, 0, queue1, 0);
    AudioConnection          patchCord2(playMem1, amp1);
    AudioConnection          patchCord3(amp1, 0, i2s2, 0);
    AudioControlSGTL5000     sgtl5000_1;
    IntervalTimer            playDutyCycle;
    
    short  availableBuffs;
    short  firstBuff = 1;
    short  audioBuff[AUDIO_BUFF_LN];
    
    volatile long mu;
    volatile long realTime;
    
    long  buffsRcvd = -1;
    long  bufferTime;
    long  sixtyFourBuffCnt;
    
    float diffRealTimeAndBuffTime;
    
    void playMemTimer() {
      if (!playMem1.isPlaying()) {
        playMem1.play(AudioSampleDutycycle);
      }
    }
    
    void processMicInput() {
    
      availableBuffs = queue1.available();
      if (availableBuffs < 1) {
        return;
      }
      buffsRcvd++;
      if ((buffsRcvd % 64) == 0) {
        sixtyFourBuffCnt++;
      }
      memcpy(audioBuff,
             queue1.readBuffer(),
             256);
      queue1.freeBuffer();
      availableBuffs--;
      bufferTime = (buffsRcvd + availableBuffs) * (2901.37588685);
      noInterrupts();
      realTime = micros();
      interrupts();
      // sixtyFourBuffCnt is a correction factor for a timing discrepancy I noticed happening every 64 buffers of 128 samples in the output. The 2.7195 number is an eyeballed estimate from watching
      // the data scroll by on the serial monitor, but as you can see from the picture, it's a slight overestimate, amounting to ~20 microseconds of difference after 10000 samples.
      diffRealTimeAndBuffTime = (realTime + 2.7195 * sixtyFourBuffCnt) - bufferTime;
      Serial.println(diffRealTimeAndBuffTime);
    }
    
    void setup() {
      // put your setup code here, to run once:
      amp1.gain(1);
      Serial.begin(9600);
      AudioMemory(52);
      sgtl5000_1.enable();
      sgtl5000_1.volume(0.5);
      sgtl5000_1.inputSelect(AUDIO_INPUT_MIC);
      queue1.begin();
      playDutyCycle.priority(128);
      playDutyCycle.begin(playMemTimer,
                          23235);
    }
    
    void loop() {
      // put your main code here, to run repeatedly:
      if (!playMem1.isPlaying()) {
        playMem1.play(AudioSampleDutycycle);
      }
      processMicInput();
    }
    Duty Cycle .wav:
    Code:
    // Audio data converted from WAV file by wav2sketch
    
    #include "AudioSampleDutycycle.h"
    
    // Converted from dutyCycle.wav, using 44100 Hz, 16 bit PCM encoding
    const unsigned int AudioSampleDutycycle[512] = {
    0x81000400,0xFCB9004E,0xE7E70CC8,0x1D790FBB,0x71C8A6A1,0x1E6FAD10,0xF8420215,0xFF74035D,
    0x00000007,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
    0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
    0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
    0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
    0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
    0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
    0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
    0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
    0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
    0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
    0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
    0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
    0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
    0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
    0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
    0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
    0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
    0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
    0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
    0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
    0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
    0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
    0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
    0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
    0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
    0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
    0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
    0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
    0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
    0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
    0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
    0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
    0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
    0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
    0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
    0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
    0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
    0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
    0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
    0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
    0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
    0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
    0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
    0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
    0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
    0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
    0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
    0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
    0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
    0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
    0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
    0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
    0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
    0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
    0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
    0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
    0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
    0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
    0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
    0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
    0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
    0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
    0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000};
    Code:
    // Audio data converted from WAV file by wav2sketch
    
    extern const unsigned int AudioSampleDutycycle[512];

  2. #2
    Junior Member
    Join Date
    Apr 2019
    Posts
    3
    I should have mentioned that this behavior is similar on the Teensy 3.1/3.2 that the Audio shield sold here comes mounted on. I had hoped upgrading the processing hardware would resolve the issue, but it did not. Similar captures of this data from the board are also uncorrelated (i.e. computing the cross-correlation between a sample collected from the first five minutes the board is on, resetting the board, then collecting the first five minutes after the reset) to a very high degree at both large and small windows. The maximum cross-correlation was ~0.05 and was mostly smaller than that.

  3. #3
    Junior Member
    Join Date
    Apr 2019
    Posts
    3
    I still get a delay of about 1/3 of a microsecond per buffer, but removing the floats entirely leaves the error constant and I'm quite able to model a way to remove that error. We can consider this topic closed!

  4. #4
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    19,929
    This is the one where we talked on the phone, right?

    One other thing might help you is the possibility to craft your analysis as an object which integrates with the audio library. Here's the page with info.

    https://www.pjrc.com/teensy/td_libs_...ewObjects.html

    If you go this route, you can create a member variable which tracks how many 128 sample updates you've processed. Your object and all others in the library will process 128 sample blocks together in perfect sync. Maybe that can help more than trying to correlate with the Arduino timing functions?

Posting Permissions

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