Matlab 生成任意波形wav文件

1、背景

  测试DAC/功放的性能指标的时候,常需要 1KHz 的波形来分析,主要测试参数有输出幅度,相移、失真度、频响曲线、信噪比(SNR)等常用的手段来评估设备的好坏程度,测试仪器一般选用AG,粗略测试也可以使用稍微好一点的示波器。
  曾经一开始接触这部分调试的时候,从网上找了些音频文件,发现怎么测参数都不对,后来从别人那里考来了一份常用的1K文件,才得出像样点的结果,由于此文件需要的精度高,而网上下载的文件质量参差不齐,而且没有所需要的各种格式,比如各采样率、位深、时常、特殊幅值、任意频率等的参数,所以干脆自己写一个程序来生成,所有内部的波形都能够看得出来,会比较放心地拿来测试。
  对音频这块比较专业的软件有 Adobe Audition 这一款,很适合音频录制、编辑和混合,但是作为程序员,还是喜欢通过用代码来生成想要的内容,因此选择使用 Matlab,Matlab 在信号处理上,也可以说是老大了,各种处理的算法基本都是有对应的函数库,就算有些没有,编写起来也很容易,包含了众多科学/工程领域的包及仿真工具。当然,对于本文这种比较小的需求,虽说有种牛刀杀鸡的感觉,但是未尝不是一个学习的过程,再不用一下,在学校里学的就得忘光了。

2、实现

  本文是该分栏的第一篇文章,上述废话多了点哈,后面的代码都尽量保证代码的注释多点,也欢迎大家来指正错误一起学习哦,现在开始来实现吧~~

2.1 参数定义

可以自由设置的参数如下,同学们可以根据需要来修改想要的参数,然后运行一下来生成wav文件。
在这里插入图片描述
代码片段(csdn 的 markdown 貌似对 m 文件的支持不太好,没有高亮 - -。):

 %%  参数定义  %%%%%%%%%%%
fs = 96000;             % 采样频率
bps = 16;               % 位深 bit
Tfile = 60;             % 声音片段的总时长,单位s
vol = 0;                % 声音片段的音量 0db
sinewave1_fs = 1000;    % 左声道频率,单位Hz
sinewave2_fs = 1000;    % 右声道频率
stereo = 1;             % 0:单声道,1:立体声
filename = ('96000_16b_1KHz_60s_stereo_gen_by_Matlab.wav'); %输出文件名称(自己定义,后缀是.wav)

2.2 生成时间序列

生成一个时间序列,序列里每一个点对应一个采样点。
在这里插入图片描述

代码片段:

%% 生成时间序列
Df = 1;                 % 频率间隔,默认1
T = 1/fs;               % 采样周期
N = fs/Df;              % 序列点数
time = Tfile*(N-1)*T;   % 文件总时长
t = 0:T:time;           % 生成每一个采样点对应的时间序列

2.3 生成左右声道波形

调用正弦函数来生成波形,参数为 2.1 定义的参数,照葫芦画瓢,可以将 sin 函数 替换成其他函数,生成各种你想要的波形。
在这里插入图片描述
代码片段:

%% 生成左右声道波形
y1 = sin(2*pi*sinewave1_fs*t)*(db2mag(vol));    % 生成第一个声音片段,注意需要用db2mag()函数把dB转换成magnitude。
y2 = sin(2*pi*sinewave2_fs*t)*(db2mag(vol));    % 生成第二个声音片段,若需不同赋值,可以在参数定义中增加一个 vol_2 来控制第二段的赋值。 
if stereo == 0                                  % 选择单声道输出
        y = y1';                                %   输出的 y 只使用 y1, 左声道(单声道)
        y2 = 0*sin(2*pi*sinewave2_fs*t);        %   令 y2 为 0
else                                            % 选择立体声输出
        y = [y1',y2'];                          %   合成立体声
end

2.4 播放生成的波形

生成的波形文件可以通过 sound() 函数来播放。
在这里插入图片描述

代码片段:

%% 通过电脑音频输出口,播放生成的波形
whos y              % 命令行打印 y 的信息
if fs < 192000      % 电脑不能支持大于 192K 的声音输出,但是可以正常生成。
    sound(y,fs)     % 可以播放声音的函数 sound()
end

2.5 描绘波形图像

这部分比较简单,关键点是要顺便写一下验错的流程,直接上图看注释。
在这里插入图片描述
代码片段:

%% 描绘波形图像
if stereo == 0              % 如果选择单声道输出 
    subplot(2,1,1);         %     选中第一个图片位置
    plot(t,y1);             %     描绘左声道生成波形
    title('左声道生成波形'); 
    subplot(2,1,2);         %     选中第二个图片位置
    plot(y1(1:200));        %     打印左声道 1~200的值,如果下面读取成功,此值会被覆盖
    title('左声道读取失败'); %     若后面读取正常,该值会被覆盖(即读取成功的话,将看不到这句话,用于验错)

else                        % 如果选择立体声输出 
    subplot(4,1,1);         %     选中第一个图片位置
    plot(t,y1);             %     描绘左声道生成波形
    title('左声道生成波形');
    subplot(4,1,2);         %     选中第二个图片位置
    plot(t,y2);             %     描绘右声道生成波形
    title('右声道生成波形');
    subplot(4,1,3);         %     选中第三个图片位置
    plot(y1(1:200))         %     打印左声道 1~200的值,如果下面读取成功,此值会被覆盖
    title('左声道读取失败'); %     若后面读取正常,该值会被覆盖(即读取成功的话,将看不到这句话,用于验错)
    subplot(4,1,4);         %     选中第四个图片位置
    plot(y2(1:200))         %     打印右声道 1~200的值,如果下面读取成功,此值会被覆盖
    title('右声道读取失败'); %     若后面读取正常,该值会被覆盖(即读取成功的话,将看不到这句话,用于验错)
end

2.6 写入 .wav文件

在这里插入图片描述
代码片段:

%% 写入文件
audiowrite(filename,y,fs,'BitsPerSample',bps);  % 存储.wav音频文件,文件名在参数定义里设置
AudioInfo = audioinfo(filename)                 % 这里不用加分号,可以顺便在命令窗口看看写入文件的打印信息

2.7 读取生成的 wav 文件进行,并描绘波形

读取波形文件,若读取失败,则无法打印正确的波形,此时需要检查是否生成的参数设置有误
在这里插入图片描述
代码片段:

%%   读取刚才生成的 wav 文件进行,并描绘波形
[y_read,FS]=audioread(filename);    % 将 WAV 文件转换成变量
whos y_r                            % 打印一下 y_read 信息
if stereo == 0                      % 如果选择单声道 
    y_read1 = y_read(:,1);          %	提取声道
    subplot(2,1,2);                 %	选中第二个图片位置
    plot(t,y_read1);                %   描绘左声道读取波形,覆盖上一步骤的验错内容
    title('左声道读取波形');
else                                % 如果选择立体声 
    y_read1 = y_read(:,1);          %	提取左声道
    subplot(4,1,3);                 %   选中第三个图片位置
    plot(t,y_read1);                %   描绘左声道读取波形,覆盖上一步骤的验错内容
    title('左声道读取波形');
    y_read2 = y_read(:,2);          %	提取右声道
    subplot(4,1,4);                 %   选中第四个图片位置
    plot(t,y_read2);                %   描绘右声道读取波形,覆盖上一步骤的验错内容
    title('右声道读取波形');
end

OK ,到这里功能已经实现了,第一个 Matlab 分享代码注释写的算是较为详细了,方便自己也方便大家,学习的路上共勉。

3、完整代码

代码比较简单,不需要其他配置,直接复制到Matlab上即可成功运行,各位有需要用到的可以试试哦。

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%   功能:生成任意正弦波形文件(单声道 or 立体声) % 
%   作者:Mr-Ma Technology(马健维)             %
%   时间:2019.08.31                           %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

clear; 
close all; 
clc;
 %%  参数定义  %%%%%%%%%%%
fs = 96000;             % 采样频率
bps = 16;               % 位深 bit
Tfile = 60;             % 声音片段的总时长,单位s
vol = 0;                % 声音片段的音量 0db
sinewave1_fs = 1000;    % 左声道频率,单位Hz
sinewave2_fs = 1000;    % 右声道频率
stereo = 1;             % 0:单声道,1:立体声
filename = ('96000_16b_1KHz_60s_stereo_gen_by_Matlab.wav'); %输出文件名称(自己定义,后缀是.wav)

%% 生成时间序列
Df = 1;                 % 频率间隔,默认1
T = 1/fs;               % 采样周期
N = fs/Df;              % 序列点数
time = Tfile*(N-1)*T;   % 文件总时长
t = 0:T:time;           % 生成每一个采样点对应的时间序列

%% 生成左右声道波形
y1 = sin(2*pi*sinewave1_fs*t)*(db2mag(vol));    % 生成第一个声音片段,注意需要用db2mag()函数把dB转换成magnitude。
y2 = sin(2*pi*sinewave2_fs*t)*(db2mag(vol));    % 生成第二个声音片段,若需不同赋值,可以在参数定义中增加一个 vol_2 来控制第二段的赋值。 
if stereo == 0                                  % 选择单声道输出
        y = y1';                                %   输出的 y 只使用 y1, 左声道(单声道)
        y2 = 0*sin(2*pi*sinewave2_fs*t);        %   令 y2 为 0
else                                            % 选择立体声输出
        y = [y1',y2'];                          %   合成立体声
end

%% 通过电脑音频输出口,播放生成的波形
whos y              % 命令行打印 y 的信息
if fs < 192000      % 电脑不能支持大于 192K 的声音输出,但是可以正常生成。
    sound(y,fs)     % 可以播放声音的函数 sound()
end

%% 描绘波形图像
if stereo == 0              % 如果选择单声道输出 
    subplot(2,1,1);         %     选中第一个图片位置
    plot(t,y1);             %     描绘左声道生成波形
    title('左声道生成波形'); 
    subplot(2,1,2);         %     选中第二个图片位置
    plot(y1(1:200));        %     打印左声道 1~200的值,如果下面读取成功,此值会被覆盖
    title('左声道读取失败'); %     若后面读取正常,该值会被覆盖(即读取成功的话,将看不到这句话,用于验错)

else                        % 如果选择立体声输出 
    subplot(4,1,1);         %     选中第一个图片位置
    plot(t,y1);             %     描绘左声道生成波形
    title('左声道生成波形');
    subplot(4,1,2);         %     选中第二个图片位置
    plot(t,y2);             %     描绘右声道生成波形
    title('右声道生成波形');
    subplot(4,1,3);         %     选中第三个图片位置
    plot(y1(1:200))         %     打印左声道 1~200的值,如果下面读取成功,此值会被覆盖
    title('左声道读取失败'); %     若后面读取正常,该值会被覆盖(即读取成功的话,将看不到这句话,用于验错)
    subplot(4,1,4);         %     选中第四个图片位置
    plot(y2(1:200))         %     打印右声道 1~200的值,如果下面读取成功,此值会被覆盖
    title('右声道读取失败'); %     若后面读取正常,该值会被覆盖(即读取成功的话,将看不到这句话,用于验错)
end

%% 写入文件
audiowrite(filename,y,fs,'BitsPerSample',bps);  % 存储.wav音频文件,文件名在参数定义里设置
AudioInfo = audioinfo(filename)                 % 这里不用加分号,可以顺便在命令窗口看看写入文件的打印信息

%%   读取刚才生成的 wav 文件进行,并描绘波形
[y_read,FS]=audioread(filename);    % 将 WAV 文件转换成变量
whos y_r                            % 打印一下 y_read 信息
if stereo == 0                      % 如果选择单声道 
    y_read1 = y_read(:,1);          %	提取声道
    subplot(2,1,2);                 %	选中第二个图片位置
    plot(t,y_read1);                %   描绘左声道读取波形,覆盖上一步骤的验错内容
    title('左声道读取波形');
else                                % 如果选择立体声 
    y_read1 = y_read(:,1);          %	提取左声道
    subplot(4,1,3);                 %   选中第三个图片位置
    plot(t,y_read1);                %   描绘左声道读取波形,覆盖上一步骤的验错内容
    title('左声道读取波形');
    y_read2 = y_read(:,2);          %	提取右声道
    subplot(4,1,4);                 %   选中第四个图片位置
    plot(t,y_read2);                %   描绘右声道读取波形,覆盖上一步骤的验错内容
    title('右声道读取波形');
end

4、运行图片

为了让图片看出正弦波形,修改文件时长为 0.1s。
在这里插入图片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章