-
Notifications
You must be signed in to change notification settings - Fork 48
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Tools: Add more robustness to check_volume_levels.m measure #985
Changes from all commits
bd3fece
46ac326
902ed6d
1cd54e2
5eec116
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,4 @@ | ||
function check_volume_levels(cmd, fn1, fn2, fn3) | ||
function check_volume_levels(cmd, fn1, fn2, fn3, do_plot) | ||
|
||
% check_volume_levels(cmd, fn1, fn2, fn3) | ||
% | ||
|
@@ -7,17 +7,20 @@ function check_volume_levels(cmd, fn1, fn2, fn3) | |
% fn1 - File name for sine wave to generate or first record file name to analyze | ||
% fn2 - File name to analyze 2nd | ||
% fn3 - File name to analyze 3rd | ||
% do_plot - Plot figure of levels if 1, defaults to 0 | ||
% | ||
% E.g. | ||
% check_volume_levels('generate','sine.wav'); | ||
% check_volume_levels('measure','rec1.wav','rec2.wav','rec3.wav'); | ||
% check_volume_levels('generate', 'sine.wav'); | ||
% check_volume_levels('measure', 'rec1.wav', 'rec2.wav', 'rec3.wav'); | ||
% check_volume_levels('measure', 'rec1.wav', 'rec2.wav', 'rec3.wav', 1); | ||
|
||
% SPDX-License-Identifier: BSD-3-Clause | ||
% Copyright(c) 2016 Intel Corporation. All rights reserved. | ||
% Author: Seppo Ingalsuo <[email protected]> | ||
|
||
addpath('../../sof/tools/test/audio/std_utils'); | ||
addpath('../../sof/tools/test/audio/test_utils'); | ||
if nargin < 5 | ||
do_plot = 0; | ||
end | ||
|
||
if exist('OCTAVE_VERSION', 'builtin') | ||
pkg load signal | ||
|
@@ -32,15 +35,15 @@ function check_volume_levels(cmd, fn1, fn2, fn3) | |
error('FAIL'); | ||
end | ||
case 'measure' | ||
pass = measure(fn1, fn2, fn3); | ||
pass = measure(fn1, fn2, fn3, do_plot); | ||
if pass | ||
fprintf(1, 'PASS\n'); | ||
else | ||
error('FAIL'); | ||
end | ||
otherwise | ||
error('Invalid cmd') | ||
endswitch | ||
end | ||
|
||
end | ||
|
||
|
@@ -52,19 +55,19 @@ function check_volume_levels(cmd, fn1, fn2, fn3) | |
fs = 48e3; | ||
f1 = 701; | ||
f2 = 1297; | ||
a = 10^(-40/20); | ||
a = 10 ^ (-40 / 20); | ||
t = 60; | ||
x1 = multitone(fs, f1, a, t); | ||
x2 = multitone(fs, f2, a, t); | ||
x = [x1'; x2']'; | ||
sx = size(x); | ||
d = (rand(sx(1), sx(2)) - 0.5)/2^15; | ||
d = (rand(sx(1), sx(2)) - 0.5) / 2 ^ 15; | ||
audiowrite(fn, x + d, fs); | ||
pass = 1; | ||
end | ||
|
||
|
||
function pass = measure(fn1, fn2, fn3) | ||
function pass = measure(fn1, fn2, fn3, do_plot) | ||
|
||
% General test defaults | ||
lm.tgrid = 5e-3; % Return level per every 5ms | ||
|
@@ -87,7 +90,7 @@ function check_volume_levels(cmd, fn1, fn2, fn3) | |
t1.vtol = 0.5; % Pass test with max +/- 0.5 dB mismatch | ||
|
||
% Check test 1 | ||
pass1 = level_vs_time_checker(fn1, t1, lm, '1/3'); | ||
pass1 = level_vs_time_checker(fn1, t1, lm, '1 / 3', do_plot); | ||
|
||
% Default gains for test 2 | ||
m1 = [vmut vnom vnom vmut]; | ||
|
@@ -100,7 +103,7 @@ function check_volume_levels(cmd, fn1, fn2, fn3) | |
t2.vtol = t1.vtol; % Same as previous | ||
|
||
% Check test 2 | ||
pass2 = level_vs_time_checker(fn2, t2, lm, '2/3'); | ||
pass2 = level_vs_time_checker(fn2, t2, lm, '2 / 3', do_plot); | ||
|
||
% Default gains for test 3 | ||
vol_ch1 = [ vmut vmut m2(1) vnom ]; | ||
|
@@ -111,7 +114,7 @@ function check_volume_levels(cmd, fn1, fn2, fn3) | |
t3.vtol = t1.vtol; % Same as previous | ||
|
||
% Check test 3 | ||
pass3 = level_vs_time_checker(fn3, t3, lm, '3/3'); | ||
pass3 = level_vs_time_checker(fn3, t3, lm, '3 / 3', do_plot); | ||
|
||
if pass1 == 1 && pass2 == 1 && pass3 == 1 | ||
pass = 1; | ||
|
@@ -121,11 +124,13 @@ function check_volume_levels(cmd, fn1, fn2, fn3) | |
|
||
end | ||
|
||
function pass = level_vs_time_checker(fn, tc, lm, id) | ||
function pass = level_vs_time_checker(fn, tc, lm, id, do_plot) | ||
fprintf(1, 'File %s:\n', fn); | ||
|
||
lev = level_vs_time(fn, lm); | ||
%plot_levels(lev, tc, lm); | ||
if do_plot | ||
plot_levels(lev, tc, lm); | ||
end | ||
pass = check_levels(lev, tc, lm, 1); | ||
if pass | ||
fprintf(1, 'pass (%s)\n', id); | ||
|
@@ -134,7 +139,7 @@ function check_volume_levels(cmd, fn1, fn2, fn3) | |
|
||
% Swapped channels? | ||
sine_freqs_orig = lm.sine_freqs; | ||
lm.sine_freqs = sine_freqs_orig(end:-1:1); | ||
lm.sine_freqs = sine_freqs_orig(end : -1 : 1); | ||
lev = level_vs_time(fn, lm); | ||
pass_test = check_levels(lev, tc, lm, 0); | ||
if pass_test | ||
|
@@ -145,7 +150,7 @@ function check_volume_levels(cmd, fn1, fn2, fn3) | |
% Swapped controls? | ||
lm.sine_freqs = sine_freqs_orig; | ||
volumes_orig = tc.volumes; | ||
tc.volumes = volumes_orig(:, end:-1:1); | ||
tc.volumes = volumes_orig(:, end : -1 : 1); | ||
lev = level_vs_time(fn, lm); | ||
pass_test = check_levels(lev, tc, lm, 0); | ||
if pass_test | ||
|
@@ -154,7 +159,7 @@ function check_volume_levels(cmd, fn1, fn2, fn3) | |
end | ||
|
||
% Swapped controls and swapped channels | ||
lm.sine_freqs = sine_freqs_orig(end:-1:1); | ||
lm.sine_freqs = sine_freqs_orig(end : -1 : 1); | ||
lev = level_vs_time(fn, lm); | ||
pass_test = check_levels(lev, tc, lm, 0); | ||
if pass_test | ||
|
@@ -170,34 +175,57 @@ function plot_levels(meas, tc, lm) | |
|
||
sv = size(tc.volumes); | ||
hold on; | ||
for j = 1:sv(2) | ||
for i = 1:sv(1) | ||
plot([tc.vctimes(i)+tc.meas(1) tc.vctimes(i)+tc.meas(2)], ... | ||
[tc.volumes(i,j)+tc.vtol tc.volumes(i,j)+tc.vtol], 'r--'); | ||
if tc.volumes(i,j) > -100 | ||
plot([tc.vctimes(i)+tc.meas(1) tc.vctimes(i)+tc.meas(2)], ... | ||
[tc.volumes(i,j)-tc.vtol tc.volumes(i,j)-tc.vtol], 'r--'); | ||
for j = 1 : sv(2) | ||
for i = 1 : sv(1) | ||
plot([tc.vctimes(i) + tc.meas(1) tc.vctimes(i) + tc.meas(2)], ... | ||
[tc.volumes(i, j) + tc.vtol tc.volumes(i, j) + tc.vtol], 'r--'); | ||
if tc.volumes(i, j) > -100 | ||
plot([tc.vctimes(i) + tc.meas(1) tc.vctimes(i) + tc.meas(2)], ... | ||
[tc.volumes(i, j) - tc.vtol tc.volumes(i, j) - tc.vtol], 'r--'); | ||
end | ||
end | ||
end | ||
hold off; | ||
xlabel('Time (s)'); | ||
ylabel('Gain (dB)'); | ||
grid on; | ||
end | ||
|
||
function pass = check_levels(meas, tc, lm, verbose) | ||
pass = 1; | ||
dg_tol = 0.1; | ||
gains = meas.levels - lm.sine_dbfs; | ||
sv = size(tc.volumes); | ||
for j = 1:sv(2) | ||
for i = 1:sv(1) | ||
ts = tc.vctimes(i)+tc.meas(1); | ||
te = tc.vctimes(i)+tc.meas(2); | ||
for j = 1 : sv(2) | ||
for i = 1 : sv(1) | ||
% Initial location to test | ||
ts = tc.vctimes(i) + tc.meas(1); | ||
te = tc.vctimes(i) + tc.meas(2); | ||
idx0 = find(meas.t < te); | ||
idx = find(meas.t(idx0) > ts); | ||
|
||
% Delay if settled gain is later in the window, | ||
% this adds more robustness to test for controls | ||
% apply delay. | ||
dg = diff(gains(idx, j)); | ||
if max(abs(dg)) > dg_tol | ||
n_idx = length(idx); | ||
dg_rev = dg(end : -1 : 1); | ||
idx_add = length(dg) - find(abs(dg_rev) > dg_tol, 1, 'first') + 1; | ||
idx = idx + idx_add; | ||
if idx(end) > size(gains, 1) | ||
idx = idx(1) : size(gains, 1); | ||
end | ||
if idx(1) > size(gains, 1) || length(idx) < 0.5 * n_idx | ||
fprintf(1, 'Channel %d controls impact is delayed too much ', j); | ||
fprintf(1, 'from %4.1f - %4.1fs\n', ts, te); | ||
pass = 0; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Variable There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I kept this as-is. The fail is done if the control has drifted too much in time from where it should have happened. |
||
return; | ||
end | ||
end | ||
avg_gain = mean(gains(idx, j)); | ||
max_gain = tc.volumes(i,j) + tc.vtol; | ||
min_gain = tc.volumes(i,j) - tc.vtol; | ||
max_gain = tc.volumes(i, j) + tc.vtol; | ||
min_gain = tc.volumes(i, j) - tc.vtol; | ||
if avg_gain > max_gain | ||
if verbose | ||
fprintf(1, 'Channel %d Failed upper gain limit at ', j); | ||
|
@@ -206,7 +234,7 @@ function plot_levels(meas, tc, lm) | |
end | ||
pass = 0; | ||
end | ||
if tc.volumes(i,j) > -100 | ||
if tc.volumes(i, j) > -100 | ||
if avg_gain < min_gain | ||
if verbose | ||
fprintf(1, 'Channel %d failed lower gain limit at ', j); | ||
|
@@ -231,23 +259,49 @@ function plot_levels(meas, tc, lm) | |
ngrid = lm.tgrid * fs; | ||
nlength = lm.tlength * fs; | ||
nmax = nlev - round(nlength / ngrid) + 1; | ||
ret.t = (0:(nmax-1)) * lm.tgrid; | ||
ret.t = (0 : (nmax - 1)) * lm.tgrid; | ||
ret.levels = zeros(nmax, nch); | ||
for i = 1:nmax | ||
for i = 1 : nmax | ||
i1 = floor((i - 1) * ngrid + 1); | ||
i2 = floor(i1 + nlength -1); | ||
ret.levels(i, :) = level_dbfs(x(i1:i2, :)); | ||
ret.levels(i, :) = level_dbfs(x(i1 : i2, :)); | ||
end | ||
ret.levels_lin = 10.^(ret.levels/20); | ||
ret.levels_lin = 10 .^ (ret.levels / 20); | ||
end | ||
|
||
function y = bandpass_filter(x, f, fs) | ||
sx = size(x); | ||
y = zeros(sx(1), sx(2)); | ||
c1 = 0.8; | ||
c2 = 1/c1; | ||
for j = 1:sx(2) | ||
[b, a] = butter(4, 2*[c1*f(j) c2*f(j)]/fs); | ||
y(:,j) = filter(b, a, x(:,j)); | ||
c2 = 1 / c1; | ||
for j = 1 : sx(2) | ||
[b, a] = butter(4, 2 *[c1 * f(j) c2 * f(j)] / fs); | ||
y(:, j) = filter(b, a, x(:, j)); | ||
end | ||
end | ||
|
||
% This function is copy of | ||
% sof/tools/test/audio/test_utils/multitone.m | ||
function x = multitone(fs, f, amp, tlength) | ||
n = round(fs * tlength); | ||
t = (0 : n - 1) / fs; | ||
nf = length(f); | ||
if nf > 1 | ||
ph = rand(nf, 1) * 2 * pi; | ||
else | ||
ph = 0; | ||
end | ||
|
||
x = zeros(n, 1); | ||
for i = 1 : length(f) | ||
x = x + amp(i) * sin(2 * pi * f(i) * t + ph(i))'; | ||
end | ||
end | ||
|
||
% This function is copy of | ||
% sof/tools/test/audio/std_utils/level_dbfs.m | ||
function dbfs = level_dbfs(x) | ||
marc-hb marked this conversation as resolved.
Show resolved
Hide resolved
|
||
%% Reference AES 17 3.12.3 | ||
level_ms = mean(x .^ 2); | ||
dbfs = 10 * log10(level_ms + 1e-20) + 20 * log10(sqrt(2)); | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
could you please add a space between
ts = tc.vctimes(i)+tc.meas(1);
asts = tc.vctimes(i) + tc.meas(1);