Skip to content

Commit e5c8bb5

Browse files
singalsulgirdwood
authored andcommitted
audio: eq_iir: tune: accept multiple measurement files in sof_ucm2_eq_generate
Allow the meas_file argument to be a cell array of paths in addition to a single string. Each file is still loaded and column-averaged the same way it was before; the per-file traces are then averaged together into the single response the IIR + FIR fit consumes. All files must share the exact same frequency grid. A mismatch aborts before any fit is attempted with an error that names both the offending file and the reference (first) file, so it is obvious which measurement was captured on a different grid. The main use case is a series of measurements taken with the microphone at different positions in front of the speaker, so the tuning target is the spatial average of those positions instead of the exact frequency response at one arbitrary spot. Signed-off-by: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
1 parent 69ea9d3 commit e5c8bb5

1 file changed

Lines changed: 79 additions & 24 deletions

File tree

src/audio/eq_iir/tune/sof_ucm2_eq_generate.m

Lines changed: 79 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,13 @@ function sof_ucm2_eq_generate(sys_vendor, product_name, endpoint, meas_file)
2525
% layout with no header row, matching
2626
% sof_ucm2_eq_example.xlsx.
2727
%
28+
% A cell array of paths is also accepted, e.g.
29+
% { 'mls-a.txt', 'mls-b.txt', 'mls-c.txt' }. Each file is
30+
% loaded independently (per-file column averaging still
31+
% applies) and the per-file magnitudes are then averaged
32+
% together. All files must share the same frequency
33+
% grid; a mismatch raises an error.
34+
%
2835
% The binary IIR and FIR blobs consumed by UCM are written to
2936
% ./ucm2_blobs_sof/ipc4/eq_iir/<endpoint>_<vendor>_<product>_iir.bin
3037
% ./ucm2_blobs_sof/ipc4/eq_fir/<endpoint>_<vendor>_<product>_fir.bin
@@ -149,31 +156,79 @@ function sof_ucm2_eq_generate(sys_vendor, product_name, endpoint, meas_file)
149156
%% Measurement loading
150157
%% -----------------------------------------------------------------------
151158
function eq = load_measurement(eq, meas_file)
152-
if ~exist(meas_file, 'file')
153-
error('Measurement file not found: %s', meas_file);
154-
end
155-
[~, ~, ext] = fileparts(meas_file);
156-
switch lower(ext)
157-
case {'.xls', '.xlsx', '.xlsm', '.ods'}
158-
pkg load io;
159-
meas = xlsread(meas_file);
160-
otherwise
161-
%% dlmread with no explicit delimiter auto-detects whitespace or
162-
%% comma separation, which covers both the sof_mls_freq_resp.m
163-
%% output and legacy whitespace-delimited measurement files.
164-
meas = dlmread(meas_file);
165-
end
166-
if size(meas, 2) < 2
167-
error('%s must have at least a frequency column and one response column', ...
168-
meas_file);
169-
end
170-
eq.raw_f = meas(:,1);
171-
if size(meas, 2) == 2
172-
eq.raw_m_db = meas(:,2);
159+
%% meas_file is either a single path or a cell array of paths. Each file
160+
%% is loaded and its response columns (if more than one) are averaged
161+
%% into a single trace, then the per-file traces are averaged together.
162+
%% All files must share the exact same frequency grid; any mismatch
163+
%% aborts before any fit is attempted.
164+
if iscell(meas_file)
165+
files = meas_file;
166+
elseif ischar(meas_file)
167+
files = { meas_file };
168+
else
169+
error(['meas_file must be a char path or a cell array of ' ...
170+
'char paths (got %s)'], class(meas_file));
171+
end
172+
173+
if isempty(files)
174+
error('meas_file must not be an empty cell array');
175+
end
176+
for k = 1:numel(files)
177+
if ~ischar(files{k}) || isempty(files{k})
178+
error(['meas_file{%d} must be a non-empty char path ' ...
179+
'(got %s)'], k, class(files{k}));
180+
end
181+
end
182+
183+
f_ref = [];
184+
m_stack = [];
185+
for k = 1:numel(files)
186+
fn = files{k};
187+
if ~exist(fn, 'file')
188+
error('Measurement file not found: %s', fn);
189+
end
190+
[~, ~, ext] = fileparts(fn);
191+
switch lower(ext)
192+
case {'.xls', '.xlsx', '.xlsm', '.ods'}
193+
pkg load io;
194+
meas = xlsread(fn);
195+
otherwise
196+
%% dlmread with no explicit delimiter auto-detects whitespace or
197+
%% comma separation, which covers both the sof_mls_freq_resp.m
198+
%% output and legacy whitespace-delimited measurement files.
199+
meas = dlmread(fn);
200+
end
201+
if size(meas, 2) < 2
202+
error('%s must have at least a frequency column and one response column', ...
203+
fn);
204+
end
205+
f_k = meas(:, 1);
206+
if size(meas, 2) == 2
207+
m_k = meas(:, 2);
208+
else
209+
m_k = mean(meas(:, 2:end), 2);
210+
fprintf('Averaged %d response columns from %s\n', ...
211+
size(meas, 2) - 1, fn);
212+
end
213+
if isempty(f_ref)
214+
f_ref = f_k;
215+
m_stack = m_k;
216+
else
217+
if ~isequal(size(f_k), size(f_ref)) || any(f_k(:) ~= f_ref(:))
218+
error(['Frequency grid of %s does not match %s. ' ...
219+
'All measurement files must share the same ' ...
220+
'[freq, resp...] grid.'], fn, files{1});
221+
end
222+
m_stack = [m_stack, m_k];
223+
end
224+
end
225+
226+
eq.raw_f = f_ref;
227+
if size(m_stack, 2) == 1
228+
eq.raw_m_db = m_stack;
173229
else
174-
%% Average of the response columns
175-
eq.raw_m_db = mean(meas(:, 2:end), 2);
176-
fprintf('Averaged %d response columns from %s\n', size(meas, 2) - 1, meas_file);
230+
eq.raw_m_db = mean(m_stack, 2);
231+
fprintf('Averaged %d measurement files\n', size(m_stack, 2));
177232
end
178233
end
179234

0 commit comments

Comments
 (0)