2

I am processing a dataset of 17 hours of audio .wav (16-bit PCM, 192khz), to simulate a "real-time" processing that will be embedded in an ESP32, Arduino DUE or in a RASP, depending on the results.

How am I handling with that now?

First I cut the 17 hours file in a 1 minute samples, after I created a program in C that turns this file into a .CSV (jumping the entire head of .wav and taking only the date field).

PS: I chose CSV to have the data in a better disposition in order to perform tests in Scilab to validate the algorithms.

With this generated .CSV file I run it in a second program, that opens this file and fills a circular buffer with 130ms (24900 values), when the buffer is full, the code begins to calculate the RMS (Root Mean Square) in moving window with 10ms overlap, window size is 30ms . When I get a value greater than 1000 it is considered an event.

Below you can see an illustration of the problem:

Delimiters of an Event, Inicio = Start, Fim = End

Here is shown the Window with 50 ms before and after an event which I mean:

Window os 200ms, 50ms before and after and event of 100ms

PS: Inicio, Fim and Janela means respectively, Start, End, Window.

My question is:

How should I save these 50ms before and after the event, since the event can occur anywhere in the buffer? And what should I do if the event lasts for more than one window?

Some data to help the understanding:

130ms = 24900 values ​​from my .csv file
50ms = 9600   values
30ms = 5700   values
10ms = 1920   values

I've searched for several sources, but most of the DSP bibliographies and Data Structures treat these topics superficially, just illustrating what a circular buffer is and not how to deal with it in a useful way.

Here is my code sketch, which seems to be taking a wrong approach to the problem, but I really have no idea how to proceed, in this case I created a data-set from 1 to 100 to ease of the debug:

    #include<stdio.h>
    #include<stdlib.h>
    #include<string.h>
    #include<math.h>

    // Define the size of window 50ms
    #define window_size 3 // 30ms
    #define buffer_size 13 // 130ms = 50ms + 30ms + 50ms

    int main()
    {
        //define variables.
        int buffer[buffer_size]={0}; // create the buffer with 150ms;
        int write = 0;
        int i = 0, j = 0;
        int read = 0;
        int read1 =0;
        int write1 = 0;
        int counter_elements = 0;
        int number_lines = 0;
        int save_line = 0;
        char c;
        char str[1024];     // array to hold characters in a conversion of char to int.
        int inicio = 0, fim = 0;
        //RMS
        int soma_quadrado = 0;
        int rms = 0;
        int pre_amostragem[5] = {0};

        //Define variaveis referentes a leitura do arquivo e manipulacoes do mesmo.
        FILE * fp;
        FILE * LOG;
        FILE * log_rms_final;

        // Open the file and verify is NULL.
        if((fp = fopen("generator.txt","r")) == NULL)
        { // Define o nome do csv para abrir
            printf("Error! Can't open the file.\n");
            exit(1);
        }
        // store rms values
         LOG = fopen("RMSValues.csv", "a");
        // store the 50ms after and before a event.
        log_rms_final = fopen("Log_RMS.csv","a");

        int lines = 0;
        while(!feof(fp))
        {
            fgets(str,1024,fp); //reads 1024 characters and store in str.
            buffer[write] = atoi(str);
            write = (write + 1) % buffer_size; // circular
            counter_elements++; // sum 

        c = fgetc(fp);
        if(c == '\n')
        {
            lines++;
        }
        printf("%d\n", lines);
            //if buffer is full
            if(counter_elements == buffer_size)
            {
                // window
                read1 = read; 
                for(i = 0; i < window_size; i++)
                {
                    //square and sum.
                    soma_quadrado += buffer[read1]*buffer[read1];
                    read1 = (read1 + 1) % buffer_size;
                }

                // RMS 
                rms = sqrt(soma_quadrado/window_size);

                fprintf(LOG, "\n %d", rms); // store

                if(rms > 1000)
                {
                    printf("rms: %d\n",rms);

                    // store the 50ms befor a event and the window.
                    write1 = write;
                    for(j = 0 ; j < 5; j++)
                    {

                        write1 = (write1 + (buffer_size - 1)) % buffer_size;
                        pre_amostragem[j] = buffer[write1];
                    }

                    fprintf(log_rms_final,"%s","\n");

                    for(j = 4; j >= 0; j--)
                    {
                        fprintf(log_rms_final,"%d - pre \n",pre_amostragem[j]);
                    }

                    fprintf(log_rms_final,"%s","\n");
    /*
                    for(j = 0; j < window_size; j++)
                    {

                        fprintf(log_rms_final,"%d - janela\n",buffer[read1]);
                        read1 = (read1 + 1) % buffer_size;
                    }
    */
                    fprintf(log_rms_final,"%s","\n");

                    //store the 50ms after a event.

                    /*
                    fseek(log_rms_final,save_line - 3,save_line);

                    for(j = 0; j < 5; j++){

                        fgets(str,1024,fp);
                        fprintf(log_rms_final,"%d - pós \n",atoi(str));

                    }
                    */
                }

                soma_quadrado = 0;
                rms = 0;


                read = (read + 1) % buffer_size;
                counter_elements = counter_elements - 2;

            }
            soma_quadrado = 0;
            rms = 0;

        }

    fclose(fp);
    fclose(LOG);
    fclose(log_rms_final);
    return 0;
    }

some comments are in Portuguese but they aren't relevant for the understanding of the problem.

Stoogy
  • 1,307
  • 3
  • 16
  • 34
  • 2
    C or C++? Pick one. – klutt May 20 '19 at 16:16
  • 1
    You know the frequency + number of channels. You know number of the sample you're currently looking at for your window. If your event happens - you can establish the frame # of 50ms previous. When your event stops you can save the frame # 50ms later. – UKMonkey May 20 '19 at 16:16
  • 1
    Personally i'd keep the 'window' size of data in my buffer. If i don't find the start of an event, drop all but the last 50mS and it to the beginning of the buffer, then fill the rest of the buffer with new data. Rinse, repeat. Yes, you go over some data twice, but it prevents you from missing a start of an event or having your event go off the end of the buffer. – Russ Schultz May 20 '19 at 16:30
  • @broman C, i've included c++ because i don't find much content in c about that. – Gabriel Lavoura May 20 '19 at 16:32
  • In your "sketch", your buffer size needs to be _t / sample-rate_ in length, your "window" has far more than 13 samples in. The question of what to do is an event lasts more than one "window" requires information on your system constraints, but you actually only need a "window" for the 50ms event start monitoring, after that the data can be streamed to a buffer of arbitrary length or to storage media until the event end is detected. – Clifford May 21 '19 at 09:10

1 Answers1

2

I am giving you an algorithm for the solution here.

  1. Always record 50ms (or even 60ms) data in a circular buffer.
  2. If you detect a start event,
    • Copy previous 50 ms from circular buffer to final buffer
    • Continue writing received data into final buffer at 50ms location.
  3. If you detect an end event.
    • Continue writing into final buffer for 50 ms more.
    • Start writing into circular buffer again.
  4. If you have multiple events, you need to have multiple final buffers and can repeat the process.

As mentioned below in the comments, this solution will work for a window size > 50 ms also. You need to select the size of the final buffer accordingly.

Rishikesh Raje
  • 8,556
  • 2
  • 16
  • 31
  • Good answer, however the question includes "_And what should I do if the event lasts for more than one window?_" which is not addressed here. I am not sure there is a good answer other than a bigger "worst case" window. Storing the data directly to a mass storage device with ample capacity rather then a finite and necessarily short "window" buffer would be my approach. If there is no mass storage, then you have to pick a buffer size and accept that it may fail and handle the failure perhaps. – Clifford May 21 '19 at 08:41
  • By more than 1 window, i understand that the event size to be more than 50ms. The solution given here will allow for any event size. Only the final buffer size needs to be increased. The circular buffer can remain unchanged. – Rishikesh Raje May 21 '19 at 08:51
  • I agree, but the question refers to the "window" as covering the entire event (200ms in the example). An event lasting longer requires a larger buffer "final" buffer, but if the maximum event length is non-deterministic, you have to either choose some "worst-case" length _a priori_ and consume resources that you may not have, for relatively rare occurrences, or as I suggest use some sort of streaming media. My point was simply that the answer does not directly address the issue; without more specific information on system constraints it is not possible to give a specific solution. – Clifford May 21 '19 at 08:59
  • If the event length is _indefinite_, no specific arbitrary buffer length will suffice. I don't think it is answerable without more information, but the issues can perhaps be addressed (or perhaps they have been adequately covered in these comments). – Clifford May 21 '19 at 09:02
  • My take on the question is that the required "final" size is small (of the order of ms or few seconds) out of a very large recording (few hrs) of all the events. Since the OP is using microcontrollers, he may not have use of `malloc` so window size and no of windows supported needs to be determined in advance. – Rishikesh Raje May 21 '19 at 09:08