function make_paper_figures(target) %MAKE_PAPER_FIGURES Journal figures for Paper 2 Sections 2 and 3.2. % Writes to writing/figures of the main checkout (white background). if nargin < 1, target = 0.4; end here = fileparts(mfilename('fullpath')); main = fileparts(here); out = fullfile(main, '..', '..', '..', 'figures'); % worktree -> writing/figures if ~isfolder(out), mkdir(out), end set(groot, 'defaultAxesFontName', 'Times New Roman', 'defaultTextFontName', 'Times New Roman', ... 'defaultAxesFontSize', 8, 'defaultAxesTickDir', 'out', 'defaultAxesBox', 'off', ... 'defaultAxesTickLabelInterpreter', 'tex') copper = '#AC6420'; blue = '#007CA8'; green = '#39BF5E'; red = '#901500'; gray = [0.55 0.55 0.55]; %% open- and closed-loop frequency responses (Section 2.4) dt = 1/2048; E0 = load(fullfile(main, 'saved_results', 'exp_tf', 'tf_sp1_7000_20260627_210411.mat')); Ed = load(fullfile(main, 'saved_results', 'exp_tf', 'tf_sp1_5000_20260627_233333.mat')); pv = Ed.pid_values; C = pid(pv.P, pv.I, pv.D, 1/pv.derivative_filter_N, dt, 'IFormula', 'ForwardEuler', 'DFormula', 'ForwardEuler'); f = logspace(0, 2, 600)'; L = [squeeze(freqresp(C*c2d(E0.H_dc_dm, dt, 'zoh'), 2*pi*f)), squeeze(freqresp(C*c2d(Ed.H_dc_dm, dt, 'zoh'), 2*pi*f))]; T = L./(1 + L); chord = @(l) abs(1 + l)./sqrt(2*(1 + abs(l).^2)); kap = chord(L); X = {E0.H_dc_dm_xfunc, Ed.H_dc_dm_xfunc}; fm = cell(1, 2); Lm = cell(1, 2); % measured points (>= 1 Hz) for j = 1:2, k = X{j}.freq_hz >= 1; fm{j} = X{j}.freq_hz(k); Lm{j} = squeeze(freqresp(C, 2*pi*fm{j})).*X{j}.points(k); end st = {'-', '--'}; col = {'k', red}; mk = {'o', 's'}; nm = {'Initial, k_0', 'Damaged, 0.75k_0'}; fig = newFig(3.5, 4.2); tl = tiledlayout(fig, 3, 1, 'TileSpacing', 'compact', 'Padding', 'compact'); ax = nexttile(tl); hold on for j = 1:2, plot(fm{j}, 20*log10(abs(Lm{j})), mk{j}, 'Color', col{j}, 'MarkerSize', 1.5, 'HandleVisibility', 'off'); end for j = 1:2, semilogx(f, 20*log10(abs(L(:, j))), st{j}, 'Color', col{j}, 'LineWidth', 1); end set(ax, 'XScale', 'log', 'XTickLabel', []); ylabel('|L| (dB)'); grid on legend(nm, 'Location', 'southwest', 'Box', 'off') ax = nexttile(tl); hold on for j = 1:2 ph = unwrap(angle(L(:, j)))*180/pi; phm = angle(Lm{j})*180/pi; phm = phm + 360*round((interp1(f, ph, fm{j}) - phm)/360); plot(fm{j}, phm, mk{j}, 'Color', col{j}, 'MarkerSize', 1.5); semilogx(f, ph, st{j}, 'Color', col{j}, 'LineWidth', 1); end set(ax, 'XScale', 'log', 'XTickLabel', []); ylabel('\angleL (deg)'); grid on ax = nexttile(tl); hold on for j = 1:2, plot(fm{j}, chord(Lm{j}), mk{j}, 'Color', col{j}, 'MarkerSize', 1.5, 'HandleVisibility', 'off'); semilogx(f, kap(:, j), st{j}, 'Color', col{j}, 'LineWidth', 1, 'HandleVisibility', 'off'); end yline(0.4, ':', 'Color', gray, 'LineWidth', 1, 'HandleVisibility', 'off') set(ax, 'XScale', 'log'); ylim([0.2 0.8]); ylabel('\chi'); xlabel('Frequency (Hz)'); grid on [m, i] = min(kap); plot(f(i), m, 'o', 'MarkerFaceColor', blue, 'MarkerEdgeColor', 'w', 'MarkerSize', 5) legend('NCF margin', 'Location', 'southwest', 'Box', 'off') print(fig, fullfile(out, 'fig_open_loop.svg'), '-dsvg'); print(fig, fullfile(out, 'fig_open_loop.png'), '-dpng', '-r300'); close(fig) fig = newFig(3.5, 3.0); tl = tiledlayout(fig, 2, 1, 'TileSpacing', 'compact', 'Padding', 'compact'); ax = nexttile(tl); hold on for j = 1:2, semilogx(f, 20*log10(abs(T(:, j))), st{j}, 'Color', col{j}, 'LineWidth', 1); end set(ax, 'XScale', 'log', 'XTickLabel', []); ylabel('|T| (dB)'); grid on legend(nm, 'Location', 'southwest', 'Box', 'off') ax = nexttile(tl); hold on for j = 1:2, semilogx(f, unwrap(angle(T(:, j)))*180/pi, st{j}, 'Color', col{j}, 'LineWidth', 1); end set(ax, 'XScale', 'log'); ylabel('\angleT (deg)'); xlabel('Frequency (Hz)'); grid on close(fig) %% calibration cases (Section 3.2) S = load(fullfile(here, sprintf('paper_benchmark_target_%03d.mat', round(100*target)))); R = S.R; for g = 1:2 ids = (1:4) + 4*(g - 1); fig = newFig(7.0, 4.6); tl = tiledlayout(fig, 3, 4, 'TileSpacing', 'compact', 'Padding', 'compact'); for k = 1:4 c = R.cases(ids(k)); ax = nexttile(tl, k); hold on h1 = plot(c.t, c.dc, '-', 'Color', copper, 'LineWidth', 0.4); h2 = plot(c.t, c.dm, '-', 'Color', blue, 'LineWidth', 0.4); title(sprintf('Case %d: %s, %s', c.id, lower(c.history), lower(c.band)), 'FontWeight', 'normal') xlim([0 120]); ylim([-0.6 0.6]); set(ax, 'XTickLabel', []); grid on if k == 1, ylabel('Displacement (mm)'); end ax = nexttile(tl, k + 4); plot(c.tc, c.delta, 'k-', 'LineWidth', 1) xlim([0 120]); ylim([-0.05 1.1]); set(ax, 'XTickLabel', []); grid on if k == 1, ylabel('\delta'); end ax = nexttile(tl, k + 8); hold on if c.adaptive, yyaxis(ax, 'left'), end h3 = plot(c.tc, c.b_true, 'k-', 'LineWidth', 1); h4 = plot(c.tc, c.b_est, '-', 'Color', green, 'LineWidth', 1); h5 = plot([0 120], [target target], '--', 'Color', gray, 'LineWidth', 0.8); ylim([0.15 0.75]); ax.YColor = 'k'; if k == 1, ylabel('NCF margin'); end if c.adaptive yyaxis(ax, 'right') h6 = plot(c.tc, c.lambda, '-', 'Color', red, 'LineWidth', 1); ylim([0 1.1]); ax.YColor = red; if k == 4, ylabel('\lambda'); end end xlim([0 120]); xlabel('Time (s)'); grid on end hs = [h1 h2 h3 h4 h5]; nm = {'Command', 'Measured', 'True margin b_{NCF}', 'Estimate b_{OSI}', 'Target b_{tar}'}; if g == 2, hs(end+1) = h6; nm{end+1} = 'Adaptive factor \lambda'; end lg = legend(hs, nm, 'Orientation', 'horizontal', 'Box', 'off'); lg.Layout.Tile = 'north'; tag = {'fixed', 'adaptive'}; print(fig, fullfile(out, ['fig_calibration_' tag{g} '.png']), '-dpng', '-r300'); close(fig) end end function fig = newFig(w, h) fig = figure('Color', 'w', 'Units', 'inches', 'Position', [1 1 w h], 'Visible', 'off', ... 'PaperUnits', 'inches', 'PaperSize', [w h], 'PaperPosition', [0 0 w h], 'InvertHardcopy', 'off'); end