测试DAC/功放的性能指标的时候,常需要 1KHz 的波形来分析,主要测试参数有输出幅度,相移、失真度、频响曲线、信噪比(SNR)等常用的手段来评估设备的好坏程度,测试仪器一般选用AG,粗略测试也可以使用稍微好一点的示波器。
曾经一开始接触这部分调试的时候,从网上找了些音频文件,发现怎么测参数都不对,后来从别人那里考来了一份常用的1K文件,才得出像样点的结果,由于此文件需要的精度高,而网上下载的文件质量参差不齐,而且没有所需要的各种格式,比如各采样率、位深、时常、特殊幅值、任意频率等的参数,所以干脆自己写一个程序来生成,所有内部的波形都能够看得出来,会比较放心地拿来测试。
对音频这块比较专业的软件有 Adobe Audition 这一款,很适合音频录制、编辑和混合,但是作为程序员,还是喜欢通过用代码来生成想要的内容,因此选择使用 Matlab,Matlab 在信号处理上,也可以说是老大了,各种处理的算法基本都是有对应的函数库,就算有些没有,编写起来也很容易,包含了众多科学/工程领域的包及仿真工具。当然,对于本文这种比较小的需求,虽说有种牛刀杀鸡的感觉,但是未尝不是一个学习的过程,再不用一下,在学校里学的就得忘光了。
本文是该分栏的第一篇文章,上述废话多了点哈,后面的代码都尽量保证代码的注释多点,也欢迎大家来指正错误一起学习哦,现在开始来实现吧~~
可以自由设置的参数如下,同学们可以根据需要来修改想要的参数,然后运行一下来生成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)
代码片段:
%% 生成时间序列
Df = 1; % 频率间隔,默认1
T = 1/fs; % 采样周期
N = fs/Df; % 序列点数
time = Tfile*(N-1)*T; % 文件总时长
t = 0:T:time; % 生成每一个采样点对应的时间序列
调用正弦函数来生成波形,参数为 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
代码片段:
%% 通过电脑音频输出口,播放生成的波形
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
OK ,到这里功能已经实现了,第一个 Matlab 分享代码注释写的算是较为详细了,方便自己也方便大家,学习的路上共勉。
代码比较简单,不需要其他配置,直接复制到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