diff --git a/tools/tune/common/tplg2_write.m b/tools/tune/common/tplg2_write.m index 9453c5d7dd7b..1bb28b05e5c6 100644 --- a/tools/tune/common/tplg2_write.m +++ b/tools/tune/common/tplg2_write.m @@ -1,4 +1,4 @@ -function tplg2_write(fn, blob8, component, comment) +function tplg2_write(fn, blob8, component, comment, howto) % SPDX-License-Identifier: BSD-3-Clause % @@ -9,6 +9,9 @@ function tplg2_write(fn, blob8, component, comment) if nargin < 4 comment = 'Exported Control Bytes'; end +if nargin < 5 + howto = []; +end %% Check that blob length is multiple of 32 bits n_blob = length(blob8); @@ -23,6 +26,9 @@ function tplg2_write(fn, blob8, component, comment) fh = fopen(fn, 'w'); nl = 8; fprintf(fh, '# %s %s\n', comment, date()); +if ~isempty(howto) + fprintf(fh, '# %s\n', howto); +end fprintf(fh, 'Object.Base.data.\"%s\" {\n', component); fprintf(fh, '\tbytes \"\n'); for i = 1:nl:n_blob diff --git a/tools/tune/common/tplg_write.m b/tools/tune/common/tplg_write.m index 079aea77fd10..15692cfab295 100644 --- a/tools/tune/common/tplg_write.m +++ b/tools/tune/common/tplg_write.m @@ -1,8 +1,11 @@ -function tplg_write(fn, blob8, name, comment) +function tplg_write(fn, blob8, name, comment, howto) if nargin < 4 comment = 'Exported Control Bytes'; end +if nargin < 5 + howto = []; +end %% Pad blob length to multiple of four bytes n_orig = length(blob8); @@ -14,6 +17,9 @@ function tplg_write(fn, blob8, name, comment) fh = fopen(fn, 'w'); nl = 8; fprintf(fh, '# %s %s\n', comment, date()); +if ~isempty(howto) + fprintf(fh, '# %s\n', howto); +end fprintf(fh, 'CONTROLBYTES_PRIV(%s_priv,\n', name); fprintf(fh, '` bytes "'); for i = 1:nl:n_new @@ -33,5 +39,6 @@ function tplg_write(fn, blob8, name, comment) end fprintf(fh, ')\n'); fclose(fh); +fprintf('Blob size %d was written to file %s\n', n_new, fn); end diff --git a/tools/tune/dcblock/example_dcblock.m b/tools/tune/dcblock/example_dcblock.m index df8500473369..6ffa179e5485 100644 --- a/tools/tune/dcblock/example_dcblock.m +++ b/tools/tune/dcblock/example_dcblock.m @@ -1,16 +1,53 @@ function example_dcblock() +% Default blob, about 150 Hz cut-off @ 48 kHz +prm.fc = []; +prm.fs = []; +prm.R_coeffs = [0.98, 0.98, 0.98, 0.98, 0.98, 0.98, 0.98, 0.98]; +prm.id = "default"; +dcblock_blob_calculate(prm) + +% Generate a set configuration blobs for 16 and 48 kHz rate +% The selected high-pass cut-off frequencies are in range 20 - 200 Hz: +% 20, 30, 40, 50, 80, 100, and 200 Hz +% +% Select for applications one that is best tradeoff between DC level +% settle time and the lowest frequency that should pass without +% much attenuation. Cut-off frequency by definition is the point where +% the attenuation is 3.01 dB. + +prm.R_coeffs = []; +for fs = [16e3 48e3] + for fc = [20 30 40 50 80 100 200] + prm.id = sprintf("%dhz_%dkhz", round(fc), round(fs / 1000)); + prm.fs = fs; + prm.fc = fc; + dcblock_blob_calculate(prm) + end +end + +end + +function dcblock_blob_calculate(prm) + % Set the parameters here -tplg1_fn = "../../topology/topology1/m4/dcblock_coef_default.m4"; % Control Bytes File -tplg2_fn = "../../topology/topology2/include/components/dcblock/default.conf"; +tplg1_fn = sprintf("../../topology/topology1/m4/dcblock_coef_%s.m4", prm.id); % Control Bytes File +tplg2_fn = sprintf("../../topology/topology2/include/components/dcblock/%s.conf", prm.id); % Use those files with sof-ctl to update the component's configuration -blob3_fn = "../../ctl/ipc3/dcblock_coef.blob"; % Blob binary file -alsa3_fn = "../../ctl/ipc3/dcblock_coef.txt"; % ALSA CSV format file -blob4_fn = "../../ctl/ipc4/dcblock_coef.blob"; % Blob binary file -alsa4_fn = "../../ctl/ipc4/dcblock_coef.txt"; % ALSA CSV format file +blob3_fn = sprintf("../../ctl/ipc3/dcblock/coef_%s.blob", prm.id); % Blob binary file +alsa3_fn = sprintf("../../ctl/ipc3/dcblock/coef_%s.txt", prm.id); % ALSA CSV format file +blob4_fn = sprintf("../../ctl/ipc4/dcblock/coef_%s.blob", prm.id); % Blob binary file +alsa4_fn = sprintf("../../ctl/ipc4/dcblock/coef_%s.txt", prm.id); % ALSA CSV format file endian = "little"; -R_coeffs = [0.98, 0.98, 0.98, 0.98, 0.98, 0.98, 0.98, 0.98]; + +if isempty(prm.fc) + R_coeffs = prm.R_coeffs; +else + channels = 8; + R = dcblock_rval_calculate(prm.fs, prm.fc); + R_coeffs = R * ones(1, channels); +end addpath ./../common @@ -18,11 +55,15 @@ function example_dcblock() blob8_ipc4 = dcblock_build_blob(R_coeffs, endian, 4); % Generate output files -tplg_write(tplg1_fn, blob8, "DCBLOCK"); +tplg_write(tplg1_fn, blob8, "DCBLOCK", ... + "Exported with script example_dcblock.m", ... + "cd tools/tune/dcblock; octave example_dcblock.m"); blob_write(blob3_fn, blob8); alsactl_write(alsa3_fn, blob8); -tplg2_write(tplg2_fn, blob8_ipc4, "dcblock_config", "Exported with script example_dcblock.m"); +tplg2_write(tplg2_fn, blob8_ipc4, "dcblock_config", ... + "Exported with script example_dcblock.m" , ... + "cd tools/tune/dcblock; octave example_dcblock.m"); blob_write(blob4_fn, blob8_ipc4); alsactl_write(alsa4_fn, blob8_ipc4); @@ -36,3 +77,52 @@ function example_dcblock() rmpath ./../common end + +% Finds with iterative search parameter R for given cutoff frequency +function R = dcblock_rval_calculate(fs, fc_target) + +if (fc_target / fs < 10 / 48e3 || fc_target / fs > 1000 / 48e3) + error("Illegal fc_target"); +end + +h_target = 1 / sqrt(2); % -3.01 dB +R = 0.5; +R_step = 0.005; +sign = 1; +w = 2 * pi * fc_target / fs; +j = sqrt(-1); +z = exp(j * w); + +% Iteration 0 +h = (1 - z^-1) / (1 - R * z^-1); +err_prev = (h_target - abs(h))^2; +R = R + sign * R_step; + +% Do more iterations +for n = 1 : 200 + h = (1 - z^-1) / (1 - R * z^-1); + err = (h_target - abs(h))^2; + if (err > err_prev) + sign = -sign; + R_step = R_step / 2; + end + R = R + sign * R_step; + err_prev = err; +end + +% Sane result? +if R < eps || R > 1 - eps + error("Calculate of R iteration failed"); +end + +% Sane high-pass function? +f = [1 fc_target fs/2]; +b = [ 1 -1 ]; a = [ 1 -R ]; +h = freqz(b, a, f, fs); +h_db = 20*log10(abs(h)); +err_hfc = abs(20*log10(1/sqrt(2)) - h_db(2)); +if err_hfc > 0.01 || h_db(1) > -10 || h_db(3) < 0 || h_db(3) > 1 + error("Failed high-pass response"); +end + +end