How to save samples before and after an event in a circular buffer?

Asked

Viewed 76 times

1

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

How I’m dealing with it these days?

First I sliced this file into 1 minute samples, after I created a C program that turns this file into one. CSV (skipping all the head of . wav and catching only the date fields).

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

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

Below the figures of my goal:

Evento de Passagem com demarcação de inicio e fim.

Here is evidenced the Window with 50ms before and after which I refer:

Janela co 50ms antes e depois do evento de passagem de 100ms

My question that I can’t solve is:

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

Some data to facilitate understanding:

130ms =  24900 valores do meu arquivo .csv
50ms  =  9600 valores 
30ms  =  5700 valores
10ms  =  1920 valores

I have searched several sources, but the great part of the bibliographies of DSP and Data structures treat these topics superficially, Just exemplifying what is a circular buffer and not how to deal with it in a useful way.

It follows my outline of code, which seems to be with a wrong approach to the problem but really I am without ideas of how to proceed, in this case I created a dataset from 1 to 100 to facilitate 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()
    {
        //Definindo variaveis.
        int buffer[buffer_size]={0}; // cria buffer com 150ms do buffer;
        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];     // vetor para armazenar os caracteres lidos como string.
        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);
        }
        // Registra os valores do rms
        LOG = fopen("RMSValues.csv", "a");
        // Cria o arquivo que registra 50ms antes e depois com a passagem.
        log_rms_final = fopen("Log_RMS.csv","a");
        //devemos ler o arquivo e processar:
        int lines = 0;
        while(!feof(fp))
        {
            fgets(str,1024,fp); //Lê o arquivo de 1024 cacacteres e armazena no vetor str.
            //buffer[write] = (atoi(str) & 0xff00) / 256; // Adiciona no buffer na posição head o caractere convertido.
            buffer[write] = atoi(str);
            write = (write + 1) % buffer_size; // faz ficar "redondo".
            counter_elements++; // Soma um na quantidade de elementos

        c = fgetc(fp);
        if(c == '\n')
        {
            lines++;
        }
        printf("%d\n", lines);
            //Se o buffer ta cheio.
            if(counter_elements == buffer_size)
            {
                // Janela da passagem
                read1 = read; // read1 carrega o primeiro valor da janela e vai somando um
                for(i = 0; i < window_size; i++)
                {
                    //Faz o quadrado e soma.
                    soma_quadrado += buffer[read1]*buffer[read1];
                    read1 = (read1 + 1) % buffer_size;
                }

                // RMS dado pela raiz da soma dos quadrados sobre o tamanho da janela;
                rms = sqrt(soma_quadrado/window_size);

                fprintf(LOG, "\n %d", rms); // Grava no arquivo

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

                    // Salva os 50ms anteriores a passagem e a janela.
                    write1 = write;
                    for(j = 0 ; j < 5; j++)
                    {
                        //Torna o preenchimento circular do vetor de pré amostragem.
                        write1 = (write1 + (buffer_size - 1)) % buffer_size;
                        //pré amostragem recebe os valores do buffer referente aos 50 ms anteriors.
                        pre_amostragem[j] = buffer[write1];
                    }

                    fprintf(log_rms_final,"%s","\n");
                    // Grava o vetor de 50ms no arquivo de log no sentido correto.
                    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");

                    //Salva os 50ms pós a passagem.

                    /*
                    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;

                //Faz a cola ficar circular, pula de 160 em 160.
                read = (read + 1) % buffer_size;

                //meu contador deve consumir mais 50ms
                counter_elements = counter_elements - 2;

            }
            soma_quadrado = 0;
            rms = 0;

        }

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

Any suggestion will be welcome. Thank you.

1 answer

1

I would initially load a 2x block the window size at a time, run the window over the buffer. Then, load 1x more window. Pseudocode, considering a window of 50 samples:

byte amostras[100]

// carrega 1 janela na primeira metade do buffer
n = fread(arquivo, &amostras[0], 50)
if n < 50:
    exit

// carrega janela na segunda metade do buffer
while fread(arquivo, &amostras[50], 50) == 50:

    // calcula a media movel para cada janela
    // de 0..49 a 49..98 (0 a 50 exclusive)
    for i in 0 to 50:
        calcula_rms(&amostras[i], 50)

    // copia a segunda metade para cima da primeira
    memcpy(&amostras[0], &amostras[50], 50)

Browser other questions tagged

You are not signed in. Login or sign up in order to post.