gnuplot - 轴上的物理尺寸

时间:2017-08-09 15:46:33

标签: c audio gnuplot

我写了一个代码,据说应该读取一个音频文件作为输入,以便编写包含每个样本的csv文件。这是代码:

FILE *pipein;
          pipein = popen("ffmpeg -i test1.wav -f s16le -ac 1 -", "r");
          fread(buf, 2, sample_number, pipein);
          pclose(pipein);

          // Print the sample values in the buffer to a CSV file
          FILE *csvfile;
          csvfile = fopen("samples.csv", "w");

          while (n<=sample_number) {

            //if (buf[n]!=0) {

                    fprintf(csvfile, "%d %f\n", buf[cont], Sam_freq*cont);
                    cont++;

         //  }

             n++;

          }

          fclose(csvfile);

这是运行代码后csv文件的样子:

10 43.150544
-36 43.150567
11 43.150590
30 43.150612
-29 43.150635
61 43.150658
13 43.150680
46 43.150703
121 43.150726
61 43.150748
144 43.150771
128 43.150794
130 43.150816
131 43.150839

我尝试使用gnuplot绘制samples.csv的数据,但我不明白在y轴上表示了哪个物理尺寸。

waveform plot 我在其他文章中读到,y轴上的值表示麦克风中膜的变形。有没有人知道数学关系,以便从这些值中提取我需要的物理维度?

1 个答案:

答案 0 :(得分:4)

的问题:

  1. 这不是CSV文件,只是一个文本文件。

  2. 您的代码看起来不像那样。它远非可编辑,你犯了错误,将“相关部分”复制到这个问题上。

    特别是,您使用n作为循环变量,但cont访问缓冲区。如果您的代码实际上是这样,那么您只会在输出中看到一对重复的值。

  3. 您没有定义采样率。

  4. 考虑以下反例:

    #include <stdlib.h>
    #include <stdint.h>
    #include <limits.h>
    #include <string.h>
    #include <endian.h>
    #include <stdio.h>
    
    #ifndef   SAMPLE_RATE
    #define   SAMPLE_RATE  48000
    #endif
    
    #define  NO_SAMPLE  INT_MIN
    
    #if (__BYTE_ORDER-0 == __BIG_ENDIAN-0)
    
    /* Use big-endian samples */
    
    #define  SAMPLE_FORMAT  "s16be"
    static inline int read_sample(FILE *source)
    {
        int16_t sample;
    
        if (fread(&sample, sizeof sample, 1, source) == 1)
            return (int)sample;
        else
            return NO_SAMPLE;
    }
    
    #elif (__BYTE_ORDER-0 == __LITTLE_ENDIAN-0) || (__BYTE_ORDER-0 == __PDP_ENDIAN-0)
    
    /* Use little-endian samples */
    
    #define  SAMPLE_FORMAT  "s16le"
    static inline int read_sample(FILE *source)
    {
        int16_t sample;
    
        if (fread(&sample, sizeof sample, 1, source) == 1)
            return (int)sample;
        else
            return NO_SAMPLE;
    }
    
    #else
    
    /* Use little-endian (two's complement) samples, but
       read them byte-by-byte. */
    
    #define  SAMPLE_FORMAT  "s16le"
    static inline int16_t read_sample(FILE *source)
    {
        unsigned char  bytes[2];
        int            sample;
        if (fread(bytes, 2, 1, source) != 2)
            return NO_SAMPLE;
    
        sample = bytes[0] + 256*bytes[1];
        if (sample > 32767)
            return sample - 65536;
        else
            return sample;
    }
    #endif
    
    int main(void)
    {
        const double   sample_rate = SAMPLE_RATE;
        FILE          *in;
        unsigned long  i;
        int            sample;
    
        in = popen("ffmpeg -i test1.wav -v -8 -nostats -f " SAMPLE_FORMAT " -ac 1 -", "r");
        if (!in)
            return EXIT_FAILURE;
    
        i = 0u;
        while ((sample = read_sample(in)) != NO_SAMPLE) {
            printf("%.6f %9.6f\n", (double)i / sample_rate, (double)sample / 32768.0);
            i++;
        }
    
        pclose(in);
    
        return EXIT_SUCCESS;
    }
    

    假设采样率为每秒48,000个样本(您可以先使用ffmpeg查找采样率),然后打印出每个样本,每行一个样本,第一列中的时间,以及第二列中的样本值(-1.0到恰好低于+1.0)。

    在物理意义上,第一列反映了样本的时间维度,第二列反映了传感器当时的相对压力变化 - 但是,压力变化的符号或线性都不是真正已知的当然,这取决于所使用的麦克风,放大器和ADC。

    假设您编译并运行上述内容,将输出重定向到test1.out

    gcc -Wall -O2 example.c -o example
    ./example > test1.out
    

    您可以轻松地在Gnuplot中绘制它。开始gnuplot,并告诉它

    set xlabel "Time [seconds]"
    set ylabel "Relative pressure change [f((P-P0)/Pmax)]"
    plot "test1.out" u 1:2 notitle w lines
    

    对于垂直轴,P是水平轴上指示的压力,P0是环境压力,Pmax是麦克风可以检测到的最大压力变化, f()与使用的麦克风,麦克风放大器和模数转换器电路的非线性相反。 (f()Pmax都可能取决于环境压力P0。)