Tangle Matlab scripts
This commit is contained in:
1 parent
6826e2b049
commit
8f5334da31
36 files changed
+9508
-4265
No files matched your search
@@ -15,6 +15,6 @@ function [W] = generateWeight(args)
|
||||
|
||||
s = zpk('s');
|
||||
|
||||
W = (((1/args.wc)*sqrt((1-(args.G0/args.Gc)^(2/args.n))/(1-(args.Gc/args.G1)^(2/args.n)))*s + (args.G0/args.Gc)^(1/args.n))/((1/args.G1)^(1/args.n)*(1/args.wc)*sqrt((1-(args.G0/args.Gc)^(2/args.n))/(1-(args.Gc/args.G1)^(2/args.n)))*s + (1/args.Gc)^(1/args.n)))^args.n;
|
||||
W = (((1/args.wc) * sqrt((1-(args.G0/args.Gc)^(2/args.n))/(1-(args.Gc/args.G1)^(2/args.n)))*s + (args.G0/args.Gc)^(1/args.n)) / ((1/args.G1)^(1/args.n) * (1/args.wc) * sqrt((1-(args.G0/args.Gc)^(2/args.n))/(1-(args.Gc/args.G1)^(2/args.n)))*s + (1/args.Gc)^(1/args.n)))^args.n;
|
||||
|
||||
end
|
||||
@@ -0,0 +1,204 @@
|
||||
%% Clear Workspace and Close figures
|
||||
clear; close all; clc;
|
||||
|
||||
%% Intialize Laplace variable
|
||||
s = zpk('s');
|
||||
|
||||
|
||||
|
||||
% Let's define the system parameters on Matlab.
|
||||
|
||||
k = 1e6; % Stiffness [N/m]
|
||||
c = 4e2; % Damping [N/(m/s)]
|
||||
m = 10; % Mass [kg]
|
||||
|
||||
|
||||
|
||||
% And now the system dynamics $G(s)$ and $G_d(s)$.
|
||||
|
||||
G = 1/(m*s^2 + c*s + k); % Plant
|
||||
Gd = (c*s + k)/(m*s^2 + c*s + k); % Disturbance
|
||||
|
||||
|
||||
|
||||
% #+HTML: <details><summary>Hint</summary>
|
||||
% #+LATEX: \tcbsubtitle{Hint}
|
||||
% You can follow this procedure:
|
||||
% 1. In order to have good disturbance rejection at low frequency, add a simple or double *integrator*
|
||||
% 2. In terms of the loop gain, the *bandwidth* can be defined at the frequency $\omega_c$ where $|l(j\omega_c)|$ first crosses 1 from above.
|
||||
% Therefore, adjust the *gain* such that $L(j\omega)$ crosses 1 at around 10Hz
|
||||
% 3. The roll-off at high frequency for noise attenuation should already be good enough.
|
||||
% If not, add a *low pass filter*
|
||||
% 4. Add a *Lead* centered around the crossover frequency (10 Hz) and tune it such that sufficient phase margin is added.
|
||||
% Verify that the gain margin is good enough.
|
||||
% #+HTML: </details>
|
||||
% #+end_exercice
|
||||
|
||||
% Let's say we came up with the following controller.
|
||||
|
||||
K = 14e8 * ... % Gain
|
||||
1/(s^2) * ... % Double Integrator
|
||||
1/(1 + s/2/pi/40) * ... % Low Pass Filter
|
||||
(1 + s/(2*pi*10/sqrt(8)))/(1 + s/(2*pi*10*sqrt(8))); % Lead
|
||||
|
||||
|
||||
|
||||
% The bode plot of the Loop Gain is shown in Figure [[fig:loop_gain_manual_afm]] and we can verify that we have the wanted stability margins using the =margin= command:
|
||||
|
||||
[Gm, Pm, ~, Wc] = margin(G*K);
|
||||
|
||||
|
||||
|
||||
% #+RESULTS:
|
||||
% | Requirements | Manual Method |
|
||||
% |-----------------------------+---------------|
|
||||
% | Gain Margin $> 3$ [dB] | 3.1 |
|
||||
% | Phase Margin $> 30$ [deg] | 35.4 |
|
||||
% | Crossover $\approx 10$ [Hz] | 10.1 |
|
||||
|
||||
|
||||
freqs = logspace(0, 3, 1000);
|
||||
|
||||
figure;
|
||||
tiledlayout(3, 1, 'TileSpacing', 'None', 'Padding', 'None');
|
||||
|
||||
ax1 = nexttile([2,1]);
|
||||
hold on;
|
||||
plot(freqs, abs(squeeze(freqresp(G*K, freqs, 'Hz'))));
|
||||
hold off;
|
||||
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
||||
ylabel('Magnitude'); set(gca, 'XTickLabel',[]);
|
||||
hold off;
|
||||
ylim([1e-4, 1e1])
|
||||
|
||||
ax2 = nexttile;
|
||||
hold on;
|
||||
plot(freqs, 180/pi*unwrap(angle(squeeze(freqresp(G*K, freqs, 'Hz')))));
|
||||
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin');
|
||||
yticks(-360:90:360); ylim([-360, 0]);
|
||||
xlabel('Frequency [Hz]'); ylabel('Phase [deg]');
|
||||
hold off;
|
||||
|
||||
linkaxes([ax1,ax2],'x');
|
||||
xlim([freqs(1), freqs(end)]);
|
||||
|
||||
% Example of the $\mathcal{H}_\infty$ Loop Shaping Synthesis
|
||||
% <<sec:h_infinity_open_loop_shaping_example>>
|
||||
|
||||
% To apply the $\mathcal{H}_\infty$ Loop Shaping Synthesis, the wanted shape of the loop gain should be determined from the specifications.
|
||||
% This is summarized in Table [[tab:open_loop_shaping_specifications]].
|
||||
|
||||
% Such shape corresponds to the typical wanted Loop gain Shape shown in Figure [[fig:open_loop_shaping_shape]].
|
||||
|
||||
% #+name: tab:open_loop_shaping_specifications
|
||||
% #+caption: Wanted Loop Shape corresponding to each specification
|
||||
% #+attr_latex: :environment tabularx :width \linewidth :align lXX
|
||||
% | | *Specification* | *Corresponding Loop Shape* |
|
||||
% |--------------+----------------------------------------+------------------------------------------|
|
||||
% | *Dist. Rej.* | Highest possible rejection below 1Hz | Slope of -40dB/dec at low frequency |
|
||||
% | *Pos. Speed* | Bandwidth of approximately 10Hz | $L$ crosses 1 at 10Hz |
|
||||
% | *Noise Att.* | Roll-off of -40dB/decade past 30Hz | Roll-off of -40dB/decade past 30Hz |
|
||||
% | *Robustness* | $\Delta G > 3dB$, $\Delta \phi > 30^o$ | Slope of -20dB/decade near the crossover |
|
||||
|
||||
% Then, a (stable, minimum phase) transfer function $L_w(s)$ should be created that has the same gain as the wanted shape of the Loop gain.
|
||||
% For this example, a double integrator and a lead centered on 10Hz are used.
|
||||
% Then the gain is adjusted such that the $|L_w(j2 \pi 10)| = 1$.
|
||||
|
||||
% Using Matlab, we have:
|
||||
|
||||
Lw = 2.3e3 * ...
|
||||
1/(s^2) * ... % Double Integrator
|
||||
(1 + s/(2*pi*10/sqrt(3)))/(1 + s/(2*pi*10*sqrt(3))); % Lead
|
||||
|
||||
|
||||
|
||||
% The $\mathcal{H}_\infty$ open loop shaping synthesis is then performed using the =loopsyn= command:
|
||||
|
||||
[K, ~, GAM] = loopsyn(G, Lw);
|
||||
|
||||
|
||||
|
||||
% The obtained Loop Gain is shown in Figure [[fig:open_loop_shaping_hinf_L]] and matches the specified one by a factor $\gamma \approx 2$.
|
||||
|
||||
|
||||
freqs = logspace(0, 3, 1000);
|
||||
|
||||
figure;
|
||||
tiledlayout(3, 1, 'TileSpacing', 'None', 'Padding', 'None');
|
||||
|
||||
ax1 = nexttile([2,1]);
|
||||
hold on;
|
||||
plot(freqs, abs(squeeze(freqresp(G*K, freqs, 'Hz'))), 'DisplayName', '$L(s)$');
|
||||
plot(freqs, abs(squeeze(freqresp(Lw, freqs, 'Hz'))), 'k--', 'DisplayName', '$L_w(s)$');
|
||||
plot(freqs, abs(squeeze(freqresp(Lw, freqs, 'Hz')))*GAM, 'k-.', 'DisplayName', '$L_w(s) / \gamma$, $L_w(s) \cdot \gamma$');
|
||||
plot(freqs, abs(squeeze(freqresp(Lw, freqs, 'Hz')))/GAM, 'k-.', 'HandleVisibility', 'off');
|
||||
hold off;
|
||||
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
||||
ylabel('Magnitude'); set(gca, 'XTickLabel',[]);
|
||||
hold off;
|
||||
legend('location', 'northeast');
|
||||
ylim([1e-4, 1e2]);
|
||||
|
||||
ax2 = nexttile;
|
||||
hold on;
|
||||
plot(freqs, 180/pi*unwrap(angle(squeeze(freqresp(G*K, freqs, 'Hz')))));
|
||||
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin');
|
||||
yticks(-360:90:360); ylim([-360, 0]);
|
||||
xlabel('Frequency [Hz]'); ylabel('Phase [deg]');
|
||||
hold off;
|
||||
|
||||
linkaxes([ax1,ax2],'x');
|
||||
xlim([freqs(1), freqs(end)]);
|
||||
|
||||
|
||||
|
||||
% #+name: fig:open_loop_shaping_hinf_L
|
||||
% #+caption: Obtained Open Loop Gain $L(s) = G(s) K(s)$ and comparison with the wanted Loop gain $L_w$
|
||||
% #+RESULTS:
|
||||
% [[file:figs/open_loop_shaping_hinf_L.png]]
|
||||
|
||||
|
||||
% #+begin_important
|
||||
% When using the $\mathcal{H}_\infty$ Synthesis, it is usually recommended to analyze the obtained controller.
|
||||
|
||||
% This is usually done by breaking down the controller into simple elements such as low pass filters, high pass filters, notches, leads, etc.
|
||||
% #+end_important
|
||||
|
||||
% Let's briefly analyze the obtained controller which bode plot is shown in Figure [[fig:open_loop_shaping_hinf_K]]:
|
||||
% - two integrators are used at low frequency to have the wanted low frequency high gain
|
||||
% - a lead is added centered with the crossover frequency to increase the phase margin
|
||||
% - a notch is added at the resonance of the plant to increase the gain margin (this is very typical of $\mathcal{H}_\infty$ controllers, and can be an issue, more info on that latter)
|
||||
|
||||
|
||||
freqs = logspace(0, 3, 1000);
|
||||
|
||||
figure;
|
||||
tiledlayout(3, 1, 'TileSpacing', 'None', 'Padding', 'None');
|
||||
|
||||
ax1 = nexttile([2,1]);
|
||||
plot(freqs, abs(squeeze(freqresp(K, freqs, 'Hz'))));
|
||||
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
||||
ylabel('Magnitude'); set(gca, 'XTickLabel',[]);
|
||||
hold off;
|
||||
|
||||
ax2 = nexttile;
|
||||
plot(freqs, 180/pi*angle(squeeze(freqresp(K, freqs, 'Hz'))));
|
||||
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin');
|
||||
yticks(-360:90:360); ylim([-180, 90]);
|
||||
xlabel('Frequency [Hz]'); ylabel('Phase [deg]');
|
||||
|
||||
linkaxes([ax1,ax2],'x');
|
||||
xlim([freqs(1), freqs(end)]);
|
||||
|
||||
|
||||
|
||||
% #+name: fig:open_loop_shaping_hinf_K
|
||||
% #+caption: Obtained controller $K$ using the open-loop $\mathcal{H}_\infty$ shaping
|
||||
% #+RESULTS:
|
||||
% [[file:figs/open_loop_shaping_hinf_K.png]]
|
||||
|
||||
|
||||
% Let's finally compare the obtained stability margins of the $\mathcal{H}_\infty$ controller and of the manually developed controller in Table [[tab:open_loop_shaping_compare]].
|
||||
|
||||
|
||||
[Gm_2, Pm_2, ~, Wc_2] = margin(G*K);
|
||||
@@ -0,0 +1,308 @@
|
||||
%% Clear Workspace and Close figures
|
||||
clear; close all; clc;
|
||||
|
||||
%% Intialize Laplace variable
|
||||
s = zpk('s');
|
||||
|
||||
|
||||
|
||||
% Let's define the system parameters on Matlab.
|
||||
|
||||
k = 1e6; % Stiffness [N/m]
|
||||
c = 4e2; % Damping [N/(m/s)]
|
||||
m = 10; % Mass [kg]
|
||||
|
||||
|
||||
|
||||
% And now the system dynamics $G(s)$ and $G_d(s)$.
|
||||
|
||||
G = 1/(m*s^2 + c*s + k); % Plant
|
||||
Gd = (c*s + k)/(m*s^2 + c*s + k); % Disturbance
|
||||
|
||||
% The Sensitivity Function
|
||||
% <<sec:sensitivity_transfer_functions>>
|
||||
|
||||
% The sensitivity function is indisputably the most important closed-loop transfer function of a feedback system.
|
||||
% In this section, we will see how the shape of the sensitivity function will impact the performances of the closed-loop system.
|
||||
|
||||
|
||||
% Suppose we have developed a "/reference/" controller $K_r(s)$ and made three small changes to obtained three controllers $K_1(s)$, $K_2(s)$ and $K_3(s)$.
|
||||
% The obtained sensitivity functions for these four controllers are shown in Figure [[fig:sensitivity_shape_effect]] and the corresponding step responses are shown in Figure [[fig:sensitivity_shape_effect_step]].
|
||||
|
||||
% The comparison of the sensitivity functions shapes and their effect on the step response is summarized in Table [[tab:compare_sensitivity_shapes]].
|
||||
|
||||
% #+name: tab:compare_sensitivity_shapes
|
||||
% #+caption: Comparison of the sensitivity function shape and the corresponding step response for the three controller variations
|
||||
% #+attr_latex: :environment tabularx :width 0.9\linewidth :align lXX
|
||||
% | *Controller* | *Sensitivity Function Shape* | *Change of the Step Response* |
|
||||
% |--------------+----------------------------------------------------+----------------------------------|
|
||||
% | $K_1(s)$ | Larger bandwidth $\omega_b$ | Faster rise time |
|
||||
% | $K_2(s)$ | Larger peak value $\Vert S\Vert_\infty$ | Large overshoot and oscillations |
|
||||
% | $K_3(s)$ | Larger low frequency gain $\vert S(j\cdot 0)\vert$ | Larger static error |
|
||||
|
||||
|
||||
wc = 2*pi*1; L_w = 8; wi = 2*pi*0.02;
|
||||
Kr = 1/((s + wi)^2) * ... % Double Integrator
|
||||
(1 + s/(wc/sqrt(L_w)))/(1 + s/(wc*sqrt(L_w))); % Lead
|
||||
Kr = Kr/abs(evalfr(Kr*G, 1j*wc));
|
||||
|
||||
wc = 2*pi*2; L_w = 8; wi = 2*pi*0.045;
|
||||
K1 = 1/((s + wi)^2) * ... % Double Integrator
|
||||
(1 + s/(wc/sqrt(L_w)))/(1 + s/(wc*sqrt(L_w))); % Lead
|
||||
K1 = K1/abs(evalfr(K1*G, 1j*wc));
|
||||
|
||||
wc = 2*pi*1; L_w = 2; wi = 2*pi*0.03;
|
||||
K2 = 1/((s + wi)^2) * ... % Double Integrator
|
||||
(1 + s/(wc/sqrt(L_w)))/(1 + s/(wc*sqrt(L_w))); % Lead
|
||||
K2 = K2/abs(evalfr(K2*G, 1j*wc));
|
||||
|
||||
wc = 2*pi*1; L_w = 8; wi = 2*pi*0.2;
|
||||
K3 = 1/((s + wi)^2) * ... % Double Integrator
|
||||
(1 + s/(wc/sqrt(L_w)))/(1 + s/(wc*sqrt(L_w))); % Lead
|
||||
K3 = K3/abs(evalfr(K3*G, 1j*wc));
|
||||
|
||||
|
||||
Sr = 1/(1 + Kr*G);
|
||||
S1 = 1/(1 + K1*G);
|
||||
S2 = 1/(1 + K2*G);
|
||||
S3 = 1/(1 + K3*G);
|
||||
|
||||
Tr = Kr*G/(1 + Kr*G);
|
||||
T1 = K1*G/(1 + K1*G);
|
||||
T2 = K2*G/(1 + K2*G);
|
||||
T3 = K3*G/(1 + K3*G);
|
||||
|
||||
freqs = logspace(-2, 2, 1000);
|
||||
|
||||
figure;
|
||||
hold on;
|
||||
plot(freqs, abs(squeeze(freqresp(S1, freqs, 'Hz'))), 'DisplayName', '$K_1(s)$');
|
||||
plot(freqs, abs(squeeze(freqresp(S2, freqs, 'Hz'))), 'DisplayName', '$K_2(s)$');
|
||||
plot(freqs, abs(squeeze(freqresp(S3, freqs, 'Hz'))), 'DisplayName', '$K_3(s)$');
|
||||
plot(freqs, abs(squeeze(freqresp(Sr, freqs, 'Hz'))), 'k-', 'DisplayName', '$K_r(s)$');
|
||||
hold off;
|
||||
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
||||
xlabel('Frequency [Hz]'); ylabel('Sensitivity Magnitude');
|
||||
hold off;
|
||||
legend('location', 'southeast');
|
||||
ylim([1e-3, 3]);
|
||||
|
||||
|
||||
|
||||
% #+name: fig:sensitivity_shape_effect
|
||||
% #+caption: Sensitivity function magnitude $|S(j\omega)|$ corresponding to the reference controller $K_r(s)$ and the three modified controllers $K_i(s)$
|
||||
% #+RESULTS:
|
||||
% [[file:figs/sensitivity_shape_effect.png]]
|
||||
|
||||
|
||||
t = linspace(0, 5, 1000);
|
||||
|
||||
figure;
|
||||
hold on;
|
||||
plot(t, step(T1, t), 'DisplayName', '$K_1(s)$')
|
||||
plot(t, step(T2, t), 'DisplayName', '$K_2(s)$')
|
||||
plot(t, step(T3, t), 'DisplayName', '$K_3(s)$')
|
||||
plot(t, step(Tr, t), 'k-', 'DisplayName', '$K_r(s)$')
|
||||
hold off
|
||||
xlabel('Time [s]'); ylabel('Step Response');
|
||||
legend('location', 'northeast');
|
||||
ylim([0, 1.7])
|
||||
|
||||
% Robustness: Module Margin
|
||||
% <<sec:module_margin>>
|
||||
|
||||
% Let's start this section by an example demonstrating why the phase and gain margins might not be good indicators of robustness.
|
||||
% Will follow a discussion about the module margin, a robustness indicator that can be linked to the $\mathcal{H}_\infty$ norm of $S$ and that will prove to be very useful.
|
||||
|
||||
% #+begin_exampl
|
||||
% Consider the following plant $G_t(s)$:
|
||||
|
||||
w0 = 2*pi*100;
|
||||
xi = 0.1;
|
||||
k = 1e7;
|
||||
|
||||
Gt = 1/k*(s/w0/4 + 1)/(s^2/w0^2 + 2*xi*s/w0 + 1);
|
||||
|
||||
|
||||
|
||||
% Let's say we have designed a controller $K_t(s)$ that gives the loop gain shown in Figure [[fig:phase_gain_margin_model_plant]].
|
||||
|
||||
|
||||
Kt = 1.2e6*(s + w0)/s;
|
||||
|
||||
|
||||
|
||||
% The following characteristics can be determined from the Loop gain in Figure [[fig:phase_gain_margin_model_plant]]:
|
||||
% - Control bandwidth of $\approx 10\, \text{Hz}$
|
||||
% - Infinite gain margin (the phase of the loop-gain never reaches $-180^o$)
|
||||
% - More than $90^o$ of phase margin
|
||||
|
||||
% This clearly indicate very good robustness of the closed-loop system!
|
||||
% Or does it? Let's find out.
|
||||
|
||||
|
||||
freqs = logspace(0, 3, 1000);
|
||||
|
||||
figure;
|
||||
tiledlayout(3, 1, 'TileSpacing', 'None', 'Padding', 'None');
|
||||
|
||||
ax1 = nexttile([2,1]);
|
||||
hold on;
|
||||
plot(freqs, abs(squeeze(freqresp(Gt*Kt, freqs, 'Hz'))), 'DisplayName', '$L(s)$');
|
||||
hold off;
|
||||
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
||||
ylabel('Magnitude'); set(gca, 'XTickLabel',[]);
|
||||
hold off;
|
||||
legend('location', 'northeast');
|
||||
|
||||
ax2 = nexttile;
|
||||
hold on;
|
||||
plot(freqs, 180/pi*unwrap(angle(squeeze(freqresp(Gt*Kt, freqs, 'Hz')))));
|
||||
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin');
|
||||
yticks(-360:90:360); ylim([-200, 0]);
|
||||
xlabel('Frequency [Hz]'); ylabel('Phase [deg]');
|
||||
hold off;
|
||||
|
||||
linkaxes([ax1,ax2],'x');
|
||||
xlim([freqs(1), freqs(end)]);
|
||||
|
||||
|
||||
|
||||
% #+name: fig:phase_gain_margin_model_plant
|
||||
% #+caption: Bode plot of the obtained Loop Gain $L(s)$
|
||||
% #+attr_latex: :float nil
|
||||
% #+RESULTS:
|
||||
% [[file:figs/phase_gain_margin_model_plant.png]]
|
||||
|
||||
% Now let's suppose the controller is implemented in practice, and the "real" plant $G_r(s)$ as a slightly lower damping factor than the one estimated for the model:
|
||||
|
||||
xi = 0.03;
|
||||
|
||||
Gr = 1/k*(s/w0/4 + 1)/(s^2/w0^2 + 2*xi*s/w0 + 1);
|
||||
|
||||
|
||||
|
||||
% The obtained "real" loop gain is shown in Figure [[fig:phase_gain_margin_real_plant]].
|
||||
% At a frequency little bit above 100Hz, the phase of the loop gain reaches -180 degrees while its magnitude is more than one which indicates instability.
|
||||
|
||||
% It is confirmed by checking the stability of the closed loop system:
|
||||
|
||||
isstable(feedback(Gr,Kt))
|
||||
|
||||
|
||||
|
||||
% #+RESULTS:
|
||||
% : 0
|
||||
|
||||
|
||||
freqs = logspace(0, 3, 1000);
|
||||
|
||||
figure;
|
||||
tiledlayout(3, 1, 'TileSpacing', 'None', 'Padding', 'None');
|
||||
|
||||
ax1 = nexttile([2,1]);
|
||||
hold on;
|
||||
plot(freqs, abs(squeeze(freqresp(Gt*Kt, freqs, 'Hz'))), 'DisplayName', '$L(s)$');
|
||||
plot(freqs, abs(squeeze(freqresp(Gr*Kt, freqs, 'Hz'))), 'DisplayName', '$L_r(s)$');
|
||||
hold off;
|
||||
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
||||
ylabel('Magnitude'); set(gca, 'XTickLabel',[]);
|
||||
hold off;
|
||||
legend('location', 'northeast');
|
||||
|
||||
ax2 = nexttile;
|
||||
hold on;
|
||||
plot(freqs, 180/pi*unwrap(angle(squeeze(freqresp(Gt*Kt, freqs, 'Hz')))));
|
||||
plot(freqs, 180/pi*unwrap(angle(squeeze(freqresp(Gr*Kt, freqs, 'Hz')))));
|
||||
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin');
|
||||
yticks(-360:90:360); ylim([-200, 0]);
|
||||
xlabel('Frequency [Hz]'); ylabel('Phase [deg]');
|
||||
hold off;
|
||||
|
||||
linkaxes([ax1,ax2],'x');
|
||||
xlim([freqs(1), freqs(end)]);
|
||||
|
||||
|
||||
|
||||
% #+name: fig:phase_gain_margin_real_plant
|
||||
% #+caption: Bode plots of $L(s)$ (loop gain corresponding the nominal plant) and $L_r(s)$ (loop gain corresponding to the real plant)
|
||||
% #+attr_latex: :float nil
|
||||
% #+RESULTS:
|
||||
% [[file:figs/phase_gain_margin_real_plant.png]]
|
||||
|
||||
% Therefore, even a small change of the plant parameter renders the system unstable even though both the gain margin and the phase margin for the nominal plant are excellent.
|
||||
|
||||
% This is due to the fact that the gain and phase margin are robustness indicators corresponding a *pure* change or gain or a *pure* change of phase but not a combination of both.
|
||||
% #+end_exampl
|
||||
|
||||
% Let's now determine a new robustness indicator based on the Nyquist Stability Criteria.
|
||||
|
||||
% #+begin_definition
|
||||
% - Nyquist Stability Criteria (for stable systems) ::
|
||||
% If the open-loop transfer function $L(s)$ is stable, then the closed-loop system will be unstable for any encirclement of the point $-1$ on the Nyquist plot.
|
||||
|
||||
% - Nyquist Plot ::
|
||||
% The Nyquist plot shows the evolution of $L(j\omega)$ in the complex plane from $\omega = 0 \to \infty$.
|
||||
% #+end_definition
|
||||
|
||||
% #+begin_seealso
|
||||
% For more information about the /general/ Nyquist Stability Criteria, you may want to look at [[https://www.youtube.com/watch?v=sof3meN96MA][this]] video.
|
||||
% #+end_seealso
|
||||
|
||||
% From the Nyquist stability criteria, it is clear that we want $L(j\omega)$ to be as far as possible from the $-1$ point (called the /unstable point/) in the complex plane.
|
||||
% This minimum distance is called the *module margin*.
|
||||
|
||||
% #+begin_definition
|
||||
% - Module Margin ::
|
||||
% The Module Margin $\Delta M$ is defined as the *minimum distance* between the point $-1$ and the loop gain $L(j\omega)$ in the complex plane.
|
||||
% #+end_definition
|
||||
|
||||
% #+begin_exampl
|
||||
% A typical Nyquist plot is shown in Figure [[fig:module_margin_example]].
|
||||
% The gain, phase and module margins are graphically shown to have an idea of what they represent.
|
||||
|
||||
|
||||
% Example Plant
|
||||
k = 1e6; % Stiffness [N/m]
|
||||
c = 4e2; % Damping [N/(m/s)]
|
||||
m = 10; % Mass [kg]
|
||||
G = 1/(m*s^2 + c*s + k); % Plant
|
||||
|
||||
% Example Controller
|
||||
K = 14e8 * ... % Gain
|
||||
1/(s^2) * ... % Double Integrator
|
||||
(1 + s/(2*pi*10/sqrt(8)))/(1 + s/(2*pi*10*sqrt(8))); % Lead
|
||||
|
||||
L = G*K;
|
||||
L_resp = squeeze(freqresp(L, freqs, 'Hz'));
|
||||
|
||||
% Module Margin
|
||||
Dm = min(abs(1 + L_resp));
|
||||
|
||||
% Phase Gain Margin
|
||||
[Gm, Pm, Wcg, Wcp] = margin(L);
|
||||
|
||||
freqs = logspace(0, 3, 1000);
|
||||
figure;
|
||||
hold on;
|
||||
% Gain Margin
|
||||
plot([-1, -1/Gm], [0, 0], '-', 'DisplayName', sprintf('$\\Delta G = %.1f$', Gm))
|
||||
|
||||
% Phase Margin
|
||||
theta = -pi:0.01:-pi+Pm*pi/180;
|
||||
plot(cos(theta), sin(theta), '-', 'DisplayName', sprintf('$\\Delta \\phi = %.1f^o$', Pm));
|
||||
|
||||
% Module Margin
|
||||
theta = 0 : 0.01 : 2*pi;
|
||||
plot(Dm*cos(theta)-1, Dm*sin(theta), '-', 'DisplayName', sprintf('$\\Delta M = %.1f$', Dm));
|
||||
|
||||
% Nyquist Plot
|
||||
plot(real(L_resp), imag(L_resp), 'k-', 'DisplayName', '$L(j\omega)$')
|
||||
|
||||
plot(-1, 0, 'k*', 'HandleVisibility', 'off');
|
||||
|
||||
hold off;
|
||||
xlabel('Real Axis'); ylabel('Imaginary Axis');
|
||||
xlim([-1.5, 0.5]); ylim([-1, 1]);
|
||||
axis equal;
|
||||
legend('location', 'southeast');
|
||||
@@ -0,0 +1,138 @@
|
||||
%% Clear Workspace and Close figures
|
||||
clear; close all; clc;
|
||||
|
||||
%% Intialize Laplace variable
|
||||
s = zpk('s');
|
||||
|
||||
|
||||
|
||||
% Let's define the system parameters on Matlab.
|
||||
|
||||
k = 1e6; % Stiffness [N/m]
|
||||
c = 4e2; % Damping [N/(m/s)]
|
||||
m = 10; % Mass [kg]
|
||||
|
||||
|
||||
|
||||
% And now the system dynamics $G(s)$ and $G_d(s)$.
|
||||
|
||||
G = 1/(m*s^2 + c*s + k); % Plant
|
||||
Gd = (c*s + k)/(m*s^2 + c*s + k); % Disturbance
|
||||
|
||||
|
||||
% with:
|
||||
% - =dcgain=: low frequency gain
|
||||
% - =[freq,mag]=: frequency =freq= at which the gain is =mag=
|
||||
% - =hfgain=: high frequency gain
|
||||
|
||||
% #+begin_exampl
|
||||
% The Matlab code below produces a weighting function with the following characteristics (Figure [[fig:first_order_weight]]):
|
||||
% - Low frequency gain of 100
|
||||
% - Gain of 1 at 10Hz
|
||||
% - High frequency gain of 0.5
|
||||
|
||||
|
||||
Ws = makeweight(1e2, [2*pi*10, 1], 1/2);
|
||||
|
||||
freqs = logspace(-2, 2, 1000);
|
||||
|
||||
figure;
|
||||
hold on;
|
||||
plot(freqs, abs(squeeze(freqresp(Ws, freqs, 'Hz'))), 'k-');
|
||||
hold off;
|
||||
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
||||
xlabel('Frequency [Hz]'); ylabel('Magnitude');
|
||||
hold off;
|
||||
|
||||
|
||||
|
||||
% Let's use this function to generate three weights with the same high and low frequency gains, but but different slopes.
|
||||
|
||||
|
||||
W1 = generateWeight('G0', 1e2, 'G1', 1/2, 'Gc', 1, 'wc', 2*pi*10, 'n', 1);
|
||||
W2 = generateWeight('G0', 1e2, 'G1', 1/2, 'Gc', 1, 'wc', 2*pi*10, 'n', 2);
|
||||
W3 = generateWeight('G0', 1e2, 'G1', 1/2, 'Gc', 1, 'wc', 2*pi*10, 'n', 3);
|
||||
|
||||
|
||||
|
||||
% The obtained shapes are shown in Figure [[fig:high_order_weight]].
|
||||
|
||||
|
||||
freqs = logspace(-2, 2, 1000);
|
||||
|
||||
figure;
|
||||
hold on;
|
||||
plot(freqs, abs(squeeze(freqresp(W1, freqs, 'Hz'))), ...
|
||||
'DisplayName', '$n = 1$');
|
||||
plot(freqs, abs(squeeze(freqresp(W2, freqs, 'Hz'))), ...
|
||||
'DisplayName', '$n = 2$');
|
||||
plot(freqs, abs(squeeze(freqresp(W3, freqs, 'Hz'))), ...
|
||||
'DisplayName', '$n = 3$');
|
||||
hold off;
|
||||
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
||||
xlabel('Frequency [Hz]'); ylabel('Magnitude');
|
||||
legend('location', 'northeast');
|
||||
|
||||
|
||||
% #+HTML: </details>
|
||||
% #+end_exercice
|
||||
|
||||
% Let's say we came up with the following weighting function:
|
||||
|
||||
Ws = generateWeight('G0', 1e3, ...
|
||||
'G1', 1/2, ...
|
||||
'Gc', sqrt(2), 'wc', 2*pi*10, ...
|
||||
'n', 2);
|
||||
|
||||
|
||||
|
||||
% The weighting function is then added to the generalized plant.
|
||||
|
||||
P = [1 -G;
|
||||
1 -G];
|
||||
Pw = blkdiag(Ws, 1)*P;
|
||||
|
||||
|
||||
|
||||
% And the $\mathcal{H}_\infty$ synthesis is performed on the /weighted/ generalized plant.
|
||||
|
||||
K = hinfsyn(Pw, 1, 1, 'Display', 'on');
|
||||
|
||||
|
||||
|
||||
% #+RESULTS:
|
||||
% #+begin_example
|
||||
% Test bounds: 0.5 <= gamma <= 0.51
|
||||
|
||||
% gamma X>=0 Y>=0 rho(XY)<1 p/f
|
||||
% 5.05e-01 0.0e+00 0.0e+00 3.000e-16 p
|
||||
% Limiting gains...
|
||||
% 5.05e-01 0.0e+00 0.0e+00 3.461e-16 p
|
||||
% 5.05e-01 -3.5e+01 # -4.9e-14 1.732e-26 f
|
||||
|
||||
% Best performance (actual): 0.503
|
||||
% #+end_example
|
||||
|
||||
% $\gamma \approx 0.5$ means that the $\mathcal{H}_\infty$ synthesis generated a controller $K(s)$ that stabilizes the closed-loop system, and such that the $\mathcal{H}_\infty$ norm of the closed-loop transfer function from $w$ to $z$ is less than $\gamma$:
|
||||
% \begin{align*}
|
||||
% & \| W_s(s) S(s) \|_\infty \approx 0.5 \\
|
||||
% & \Leftrightarrow |S(j\omega)| < \frac{0.5}{|W_s(j\omega)|} \quad \forall \omega
|
||||
% \end{align*}
|
||||
|
||||
% This is indeed what we can see by comparing $|S|$ and $|W_S|$ in Figure [[fig:results_sensitivity_hinf]].
|
||||
|
||||
% #+begin_important
|
||||
% Obtaining $\gamma < 1$ means that the $\mathcal{H}_\infty$ synthesis found a controller such that the specified closed-loop transfer functions are bellow the specified upper bounds.
|
||||
|
||||
% Yet, obtaining a $\gamma$ slightly above one does not necessary means the synthesis is unsuccessful.
|
||||
% It just means that at some frequency, one of the closed-loop transfer functions is above the specified upper bound by a factor $\gamma$.
|
||||
% #+end_important
|
||||
|
||||
|
||||
figure;
|
||||
hold on;
|
||||
plot(freqs, 1./abs(squeeze(freqresp(Ws, freqs, 'Hz'))), 'k--', 'DisplayName', '$|W_s|^{-1}$');
|
||||
plot(freqs, abs(squeeze(freqresp(1/(1 + K*G), freqs, 'Hz'))), 'k-', 'DisplayName', '$|S|$');
|
||||
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
||||
xlabel('Frequency [Hz]'); ylabel('Magnitude');
|
||||
legend('location', 'southeast', 'FontSize', 8);
|
||||
@@ -0,0 +1,605 @@
|
||||
%% Clear Workspace and Close figures
|
||||
clear; close all; clc;
|
||||
|
||||
%% Intialize Laplace variable
|
||||
s = zpk('s');
|
||||
|
||||
|
||||
|
||||
% #+name: fig:classical_feedback_test_system_bis
|
||||
% #+caption: Block diagram corresponding to the example system
|
||||
% #+RESULTS:
|
||||
% [[file:figs/ex_test_system_feedback.png]]
|
||||
|
||||
% The two transfer functions present in the system are derived and defined below:
|
||||
|
||||
k = 1e6; % Stiffness [N/m]
|
||||
c = 4e2; % Damping [N/(m/s)]
|
||||
m = 10; % Mass [kg]
|
||||
|
||||
% Control Plant
|
||||
G = 1/(m*s^2 + c*s + k);
|
||||
% Disturbance dynamics
|
||||
Gd = (c*s + k)/(m*s^2 + c*s + k);
|
||||
|
||||
|
||||
|
||||
% We also define the inputs signals that will be used for time domain simulations.
|
||||
% They are graphically shown in Figure [[fig:ex_inputs_signals]].
|
||||
|
||||
% Time Vector
|
||||
t = 0:1e-4:0.5;
|
||||
|
||||
% Reference Input
|
||||
r = zeros(size(t));
|
||||
r(t>0.05 & t<=0.25) = 1e-4*(t(t>0.05 & t<=0.25)-0.05);
|
||||
r(t>0.25) = 2e-5;
|
||||
|
||||
% Measurement Noise
|
||||
Fs = 1e3; % Sampling Frequency [Hz]
|
||||
Ts = 1/Fs; % Sampling Time [s]
|
||||
n = sqrt(Fs/2)*randn(1, length(t)); % Signal with an ASD equal to one
|
||||
n = lsim(1e-6*(s + 2*pi*1e2)^2/(s + 2*pi*1e3)^2/(1+s/2/pi/500), n, t)'; % Shaped noise
|
||||
|
||||
% Disturbance
|
||||
d = zeros(size(t));
|
||||
d(t>0.3) = 5e-6;
|
||||
|
||||
figure;
|
||||
tiledlayout(2, 2, 'TileSpacing', 'None', 'Padding', 'None');
|
||||
|
||||
nexttile;
|
||||
plot(t, 1e6*r, 'k-')
|
||||
xlabel('Time [s]');
|
||||
ylabel('Reference Signal $[\mu m]$');
|
||||
|
||||
nexttile;
|
||||
plot(t, 1e6*n, 'k-')
|
||||
xlabel('Time [s]');
|
||||
ylabel('Measurement Noise $[\mu m]$');
|
||||
|
||||
nexttile;
|
||||
plot(t, 1e6*d, 'k-')
|
||||
xlabel('Time [s]');
|
||||
ylabel('Disturbance Motion $[\mu m]$');
|
||||
|
||||
|
||||
|
||||
% #+name: fig:ex_general_plant_sim
|
||||
% #+caption: Generalized plant that will be used for simulations
|
||||
% #+RESULTS:
|
||||
% [[file:figs/ex_general_plant_sim.png]]
|
||||
|
||||
% The Generalized plant of Figure [[fig:ex_general_plant_sim]] is defined on Matlab as follows:
|
||||
|
||||
Psim = [0 0 Gd G
|
||||
0 0 0 1
|
||||
1 -1 -Gd -G];
|
||||
|
||||
Psim.InputName = {'r', 'n', 'd', 'u'};
|
||||
Psim.OutputName = {'y', 'u', 'e'};
|
||||
|
||||
% Modern Interpretation of control specifications
|
||||
% <<sec:ex_specification_interpretation>>
|
||||
|
||||
% #+begin_exercice
|
||||
% 1. Translate the control specifications into wanted shape of closed-loop transfer functions
|
||||
% 2. Conclude and the closed-loop transfer functions to be shaped
|
||||
% 3. Chose a general configuration architecture that allows to shape these transfer function
|
||||
% 4. Using Matlab, define the generalized plant
|
||||
|
||||
% #+HTML: <details><summary>Hint</summary>
|
||||
% #+LATEX: \tcbsubtitle{Hint}
|
||||
% 1. Make use of Table [[tab:usual_shaping_gang_four]]
|
||||
% 2. Make use of Table [[tab:usual_shaping_gang_four]]
|
||||
% 3. See Section [[sec:shaping_multiple_tf]]
|
||||
% 4. See Section [[sec:shaping_multiple_tf]]
|
||||
% #+HTML: </details>
|
||||
% #+end_exercice
|
||||
|
||||
% After converting the control specifications into wanted shape of closed-loop transfer functions, we might come up with the Table [[tab:ex_specification_shapes]].
|
||||
|
||||
% In such case, we want to shape $S$, $GS$ and $T$.
|
||||
|
||||
% #+name: tab:ex_specification_shapes
|
||||
% #+caption: Control Specifications and associated wanted shape of the closed-loop transfer functions
|
||||
% #+attr_latex: :environment tabularx :width 0.7\linewidth :align llX
|
||||
% | <l> | <c> | <l> |
|
||||
% | *Specification* | *TF* | *Wanted Shape* |
|
||||
% |--------------------------+-----------+------------------------------------|
|
||||
% | Follow Step Reference | $S$ | +40dB of slope at low frequency |
|
||||
% | Reject Disturbances | $S$, $GS$ | Small gain |
|
||||
% | Reject measurement noise | $T$ | Small high frequency (>100Hz) gain |
|
||||
% | Robust System | $S$ | Small $\Vert S \Vert_\infty$ |
|
||||
|
||||
% To do so, we use to generalized plant shown in Figure [[fig:ex_general_plant]] for the synthesis where the three closed-loop tranfert functions from $w$ to $[z_1\,,z_2\,,z_3]$ are respectively $S$, $GS$ and $T$.
|
||||
|
||||
% This generalized plant is defined on Matlab as follows:
|
||||
|
||||
P = [1 -1
|
||||
G -G
|
||||
0 1
|
||||
G -G];
|
||||
|
||||
% Step 1 - Shaping of $S$
|
||||
% <<sec:ex_shaping_S>>
|
||||
|
||||
% Let's first shape the Sensitivity function as it is usually the most important of the /Gang of four/ closed-loop transfer functions.
|
||||
% To do so, we have to create a weight $W_1(s)$ that defines the wanted upper bound on $|S(j\omega)|$:
|
||||
% - small low frequency gain: $|S(j\cdot 0)| = 10^{-3}$
|
||||
% - minimum crossover frequency of $\approx 10Hz$: $|S(j2\pi 10)| < \frac{1}{\sqrt{2}}$
|
||||
% - small maximum peak magnitude for robustness properties: $\|S\|_\infty < 2$
|
||||
|
||||
% The weighting function is design using the =generateWeigh= function and its inverse shape can be seen in Figure
|
||||
|
||||
W1 = generateWeight('G0', 1e3, ...
|
||||
'G1', 1/2, ...
|
||||
'Gc', sqrt(2), 'wc', 2*pi*10, ...
|
||||
'n', 1);
|
||||
|
||||
|
||||
|
||||
% To not constrain $GS$ and $T$ for the shaping of $S$, $W_2$ and $W_3$ are first taken as very small gains:
|
||||
|
||||
W2 = tf(1e-8);
|
||||
W3 = tf(1e-8);
|
||||
|
||||
|
||||
|
||||
% The $\mathcal{H}_\infty$ synthesis is performed and the obtained closed-loop transfer functions $S$, $GS$, and $T$ and compared with the upper bounds set by the weighting functions in Figure [[fig:ex_results_1]].
|
||||
|
||||
|
||||
Pw = blkdiag(W1, W2, W3, 1)*P;
|
||||
K1 = hinfsyn(Pw, 1, 1, 'Display', 'on');
|
||||
|
||||
|
||||
|
||||
% #+RESULTS:
|
||||
% #+begin_example
|
||||
% Test bounds: 0.5 <= gamma <= 0.51
|
||||
|
||||
% gamma X>=0 Y>=0 rho(XY)<1 p/f
|
||||
% 5.05e-01 0.0e+00 0.0e+00 5.511e-14 p
|
||||
% Limiting gains...
|
||||
% 5.05e-01 0.0e+00 0.0e+00 1.867e-14 p
|
||||
|
||||
% Best performance (actual): 0.502
|
||||
% #+end_example
|
||||
|
||||
|
||||
% Closed-loop tranfer functions are computed
|
||||
Z1 = lft(P, K1);
|
||||
|
||||
freqs = logspace(-1, 3, 1000);
|
||||
|
||||
figure;
|
||||
tiledlayout(2, 2, 'TileSpacing', 'Tight', 'Padding', 'None');
|
||||
|
||||
ax1 = nexttile;
|
||||
hold on;
|
||||
plot(freqs, abs(squeeze(freqresp(Z1(1,1), freqs, 'Hz'))), 'DisplayName', 'Step 1');
|
||||
plot(freqs, 1./abs(squeeze(freqresp(W1, freqs, 'Hz'))), 'k--', 'DisplayName', '$|W|^{-1}$');
|
||||
hold off;
|
||||
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
||||
xlabel('Frequency [Hz]'); ylabel('Magnitude');
|
||||
title('S');
|
||||
legend('location', 'southeast');
|
||||
|
||||
ax2 = nexttile;
|
||||
hold on;
|
||||
plot(freqs, abs(squeeze(freqresp(Z1(2,1), freqs, 'Hz'))));
|
||||
hold off;
|
||||
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
||||
xlabel('Frequency [Hz]'); ylabel('Magnitude');
|
||||
title('GS');
|
||||
|
||||
ax3 = nexttile;
|
||||
hold on;
|
||||
plot(freqs, abs(squeeze(freqresp(Z1(3,1), freqs, 'Hz'))));
|
||||
hold off;
|
||||
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
||||
xlabel('Frequency [Hz]'); ylabel('Magnitude');
|
||||
title('T');
|
||||
|
||||
ax4 = nexttile;
|
||||
hold on;
|
||||
plot(freqs, abs(squeeze(freqresp(K1, freqs, 'Hz'))));
|
||||
hold off;
|
||||
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
||||
xlabel('Frequency [Hz]'); ylabel('Magnitude');
|
||||
title('K');
|
||||
|
||||
linkaxes([ax1, ax2, ax3, ax4], 'x')
|
||||
xlim([freqs(1), freqs(end)]);
|
||||
|
||||
|
||||
|
||||
% #+name: fig:ex_results_1
|
||||
% #+caption: Obtained Shape Closed-Loop transfer functions (dashed black lines indicate inverse magnitude of the weighting functions)
|
||||
% #+RESULTS:
|
||||
% [[file:figs/ex_results_1.png]]
|
||||
|
||||
% Time domain simulation is then performed and the obtained output displacement and control inputs are shown in Figure [[fig:ex_time_domain_1]].
|
||||
|
||||
% We can see:
|
||||
% - we are not able to follow the ramp input. This have to be solved by modifying the weighting function $W_1(s)$
|
||||
% - we have poor rejection of disturbances. This we be solve by shaping $GS$ in Section [[sec:ex_shaping_GS]]
|
||||
% - we have quite large effect of the measurement noise. This will be solved by shaping $T$ in Section [[sec:ex_shaping_T]]
|
||||
|
||||
|
||||
% Closed-loop simulation
|
||||
Z1sim = lft(Psim, K1);
|
||||
z = lsim(Z1sim, [r;n;d], t);
|
||||
y1 = z(:,1);
|
||||
u1 = z(:,2);
|
||||
|
||||
figure;
|
||||
tiledlayout(1, 1, 'TileSpacing', 'None', 'Padding', 'None');
|
||||
|
||||
nexttile;
|
||||
hold on;
|
||||
plot(t, 1e6*y1, 'DisplayName', 'Step 1');
|
||||
plot(t, 1e6*r, 'k--', 'DisplayName', '$r$');
|
||||
hold off;
|
||||
xlabel('Time [s]'); ylabel('Output $y$ [$\mu m$]');
|
||||
legend('location', 'southeast');
|
||||
|
||||
|
||||
|
||||
% #+name: fig:ex_time_domain_1
|
||||
% #+caption: Time domain simulation results
|
||||
% #+RESULTS:
|
||||
% [[file:figs/ex_time_domain_1.png]]
|
||||
|
||||
% Remember that in order to follow ramp inputs, the sensitivity function should have a slope of +40dB/dec at low frequency (Table [[tab:usual_shaping_gang_four]]).
|
||||
|
||||
% To do so, let's modify $W_1$ to impose a slope of +40dB/dec at low frequency.
|
||||
% This can simple be done by using a second order weight:
|
||||
|
||||
W1 = generateWeight('G0', 1e3, ...
|
||||
'G1', 1/2, ...
|
||||
'Gc', sqrt(2), 'wc', 2*pi*15, ...
|
||||
'n', 2);
|
||||
|
||||
|
||||
|
||||
% The $\mathcal{H}_\infty$ synthesis is performed using the new weights and the obtained closed-loop shaped are shown in figure [[fig:ex_results_1b]].
|
||||
|
||||
% The time domain signals are shown in Figure [[fig:ex_time_domain_1b]] and it is confirmed that the ramps are now follows without static errors.
|
||||
|
||||
|
||||
Pw = blkdiag(W1, W2, W3, 1)*P;
|
||||
K1b = hinfsyn(Pw, 1, 1, 'Display', 'on');
|
||||
|
||||
% Compute the closed-loop transfer function
|
||||
Z1b = lft(P, K1b);
|
||||
|
||||
freqs = logspace(-1, 3, 1000);
|
||||
|
||||
figure;
|
||||
tiledlayout(2, 2, 'TileSpacing', 'Tight', 'Padding', 'None');
|
||||
|
||||
ax1 = nexttile;
|
||||
hold on;
|
||||
plot(freqs, abs(squeeze(freqresp(Z1(1,1), freqs, 'Hz'))), 'DisplayName', 'Step 1');
|
||||
plot(freqs, abs(squeeze(freqresp(Z1b(1,1), freqs, 'Hz'))), 'DisplayName', 'Step 1b');
|
||||
plot(freqs, 1./abs(squeeze(freqresp(W1, freqs, 'Hz'))), 'k--', 'DisplayName', '$|W^{-1}|$');
|
||||
hold off;
|
||||
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
||||
xlabel('Frequency [Hz]'); ylabel('Magnitude');
|
||||
title('S');
|
||||
legend('location', 'southeast');
|
||||
|
||||
ax2 = nexttile;
|
||||
hold on;
|
||||
plot(freqs, abs(squeeze(freqresp(Z1(2,1), freqs, 'Hz'))));
|
||||
plot(freqs, abs(squeeze(freqresp(Z1b(2,1), freqs, 'Hz'))));
|
||||
hold off;
|
||||
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
||||
xlabel('Frequency [Hz]'); ylabel('Magnitude');
|
||||
title('GS');
|
||||
|
||||
ax3 = nexttile;
|
||||
hold on;
|
||||
plot(freqs, abs(squeeze(freqresp(Z1(3,1), freqs, 'Hz'))));
|
||||
plot(freqs, abs(squeeze(freqresp(Z1b(3,1), freqs, 'Hz'))));
|
||||
hold off;
|
||||
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
||||
xlabel('Frequency [Hz]'); ylabel('Magnitude');
|
||||
title('T');
|
||||
|
||||
ax4 = nexttile;
|
||||
hold on;
|
||||
plot(freqs, abs(squeeze(freqresp(K1, freqs, 'Hz'))));
|
||||
plot(freqs, abs(squeeze(freqresp(K1b, freqs, 'Hz'))));
|
||||
hold off;
|
||||
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
||||
xlabel('Frequency [Hz]'); ylabel('Magnitude');
|
||||
title('K');
|
||||
|
||||
linkaxes([ax1, ax2, ax3, ax4], 'x')
|
||||
xlim([freqs(1), freqs(end)]);
|
||||
|
||||
|
||||
|
||||
% #+name: fig:ex_results_1b
|
||||
% #+caption: Obtained Shape Closed-Loop transfer functions
|
||||
% #+RESULTS:
|
||||
% [[file:figs/ex_results_1b.png]]
|
||||
|
||||
|
||||
% Closed-loop simulations
|
||||
Z1bsim = lft(Psim, K1b);
|
||||
z = lsim(Z1bsim, [r;n;d], t);
|
||||
y1b = z(:,1);
|
||||
u1b = z(:,2);
|
||||
|
||||
figure;
|
||||
tiledlayout(1, 1, 'TileSpacing', 'None', 'Padding', 'None');
|
||||
hold on;
|
||||
plot(t, 1e6*y1, 'DisplayName', 'Step 1');
|
||||
plot(t, 1e6*y1b, 'DisplayName', 'Step 1b');
|
||||
plot(t, 1e6*r, 'k--', 'DisplayName', '$r$');
|
||||
hold off;
|
||||
xlabel('Time [s]'); ylabel('Output $y$ [$\mu m$]');
|
||||
legend('location', 'southeast');
|
||||
|
||||
% Step 2 - Shaping of $GS$
|
||||
% <<sec:ex_shaping_GS>>
|
||||
|
||||
% Looking at Figure [[fig:ex_results_2]], it is clear that the rejection of disturbances is not satisfactory.
|
||||
% This can also be seen by the large peak of $GS$ in Figure [[fig:ex_results_1b]].
|
||||
|
||||
% This poor rejection of disturbances is actually due to the fact that the obtain controller has at notch at the resonance frequency of the plant.
|
||||
|
||||
|
||||
% To overcome this issue, we can simply increase the magnitude of $W_2$ to limit the peak magnitude of $GS$
|
||||
% Let's take $W_2$ as a simple constant gain:
|
||||
|
||||
W2 = tf(4e5);
|
||||
|
||||
|
||||
|
||||
% The $\mathcal{H}_\infty$ Synthesis is performed and the obtained closed-loop transfer functions are shown in Figure [[fig:ex_results_2]].
|
||||
|
||||
Pw = blkdiag(W1, W2, W3, 1)*P;
|
||||
K2 = hinfsyn(Pw, 1, 1, 'Display', 'on');
|
||||
|
||||
Z2 = lft(P, K2);
|
||||
|
||||
freqs = logspace(-1, 3, 1000);
|
||||
|
||||
figure;
|
||||
tiledlayout(2, 2, 'TileSpacing', 'Tight', 'Padding', 'None');
|
||||
|
||||
ax1 = nexttile;
|
||||
hold on;
|
||||
plot(freqs, abs(squeeze(freqresp(Z1(1,1), freqs, 'Hz'))), 'DisplayName', 'Step 1');
|
||||
plot(freqs, abs(squeeze(freqresp(Z1b(1,1), freqs, 'Hz'))), 'DisplayName', 'Step 1b');
|
||||
plot(freqs, abs(squeeze(freqresp(Z2(1,1), freqs, 'Hz'))), 'DisplayName', 'Step 2');
|
||||
plot(freqs, 1./abs(squeeze(freqresp(W1, freqs, 'Hz'))), 'k--', 'DisplayName', '$|W^{-1}|$');
|
||||
hold off;
|
||||
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
||||
xlabel('Frequency [Hz]'); ylabel('Magnitude');
|
||||
title('S');
|
||||
legend('location', 'southeast');
|
||||
|
||||
ax2 = nexttile;
|
||||
hold on;
|
||||
plot(freqs, abs(squeeze(freqresp(Z1(2,1), freqs, 'Hz'))));
|
||||
plot(freqs, abs(squeeze(freqresp(Z1b(2,1), freqs, 'Hz'))));
|
||||
plot(freqs, abs(squeeze(freqresp(Z2(2,1), freqs, 'Hz'))));
|
||||
plot(freqs, 1./abs(squeeze(freqresp(W2, freqs, 'Hz'))), 'k--');
|
||||
hold off;
|
||||
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
||||
xlabel('Frequency [Hz]'); ylabel('Magnitude');
|
||||
title('GS');
|
||||
|
||||
ax3 = nexttile;
|
||||
hold on;
|
||||
plot(freqs, abs(squeeze(freqresp(Z1(3,1), freqs, 'Hz'))));
|
||||
plot(freqs, abs(squeeze(freqresp(Z1b(3,1), freqs, 'Hz'))));
|
||||
plot(freqs, abs(squeeze(freqresp(Z2(3,1), freqs, 'Hz'))));
|
||||
hold off;
|
||||
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
||||
xlabel('Frequency [Hz]'); ylabel('Magnitude');
|
||||
title('T');
|
||||
|
||||
ax4 = nexttile;
|
||||
hold on;
|
||||
plot(freqs, abs(squeeze(freqresp(K1, freqs, 'Hz'))));
|
||||
plot(freqs, abs(squeeze(freqresp(K1b, freqs, 'Hz'))));
|
||||
plot(freqs, abs(squeeze(freqresp(K2, freqs, 'Hz'))));
|
||||
hold off;
|
||||
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
||||
xlabel('Frequency [Hz]'); ylabel('Magnitude');
|
||||
title('K');
|
||||
|
||||
linkaxes([ax1, ax2, ax3, ax4], 'x')
|
||||
xlim([freqs(1), freqs(end)]);
|
||||
|
||||
|
||||
|
||||
% #+name: fig:ex_results_2
|
||||
% #+caption: Obtained Shape Closed-Loop transfer functions
|
||||
% #+RESULTS:
|
||||
% [[file:figs/ex_results_2.png]]
|
||||
|
||||
% Time domain simulation results are shown in Figure [[fig:ex_time_domain_2]].
|
||||
% If is shown that indeed, the disturbance rejection performance are much better and only very small oscillation is obtained.
|
||||
|
||||
|
||||
Z2sim = lft(Psim, K2);
|
||||
|
||||
z = lsim(Z2sim, [r;n;d], t);
|
||||
y2 = z(:,1);
|
||||
u2 = z(:,2);
|
||||
|
||||
figure;
|
||||
tiledlayout(1, 2, 'TileSpacing', 'None', 'Padding', 'None');
|
||||
|
||||
hold on;
|
||||
plot(t, 1e6*y1, 'DisplayName', 'Step 1');
|
||||
plot(t, 1e6*y1b, 'DisplayName', 'Step 1b');
|
||||
plot(t, 1e6*y2, 'DisplayName', 'Step 2');
|
||||
plot(t, 1e6*r, 'k--', 'DisplayName', '$r$');
|
||||
hold off;
|
||||
xlabel('Time [s]'); ylabel('Output $y$ [$\mu m$]');
|
||||
legend('location', 'southeast');
|
||||
|
||||
% Step 3 - Shaping of $T$
|
||||
% <<sec:ex_shaping_T>>
|
||||
|
||||
% Finally, we want to limit the effect of the noise on the displacement output.
|
||||
|
||||
% To do so, $T$ is shaped such that its high frequency gain is reduced.
|
||||
|
||||
% This is done by increasing the high frequency gain of the weighting function $W_3$ until the $\mathcal{H}_\infty$ synthesis gives $\gamma \approx 1$.
|
||||
|
||||
% The final weighting function $W_3$ is defined as follows:
|
||||
|
||||
W3 = generateWeight('G0', 1e-1, ...
|
||||
'G1', 1e4, ...
|
||||
'Gc', 1, 'wc', 2*pi*70, ...
|
||||
'n', 2);
|
||||
|
||||
|
||||
|
||||
% The $\mathcal{H}_\infty$ synthesis is performed and $\gamma$ is closed to one.
|
||||
|
||||
Pw = blkdiag(W1, W2, W3, 1)*P;
|
||||
|
||||
K3 = hinfsyn(Pw, 1, 1, 'Display', 'on');
|
||||
|
||||
|
||||
|
||||
% #+RESULTS:
|
||||
% #+begin_example
|
||||
% Test bounds: 0.622 <= gamma <= 1.62
|
||||
|
||||
% gamma X>=0 Y>=0 rho(XY)<1 p/f
|
||||
% 1.01e+00 -1.3e+07 # -6.4e-18 3.459e-04 f
|
||||
% 1.28e+00 0.0e+00 0.0e+00 5.369e-02 p
|
||||
% 1.13e+00 3.8e-15 0.0e+00 1.695e-01 p
|
||||
% 1.07e+00 -5.0e-08 -1.2e-19 1.622e+00 # f
|
||||
% 1.10e+00 0.0e+00 0.0e+00 3.147e-01 p
|
||||
% 1.08e+00 0.0e+00 0.0e+00 5.327e-01 p
|
||||
% 1.08e+00 3.4e-15 0.0e+00 8.052e-01 p
|
||||
|
||||
% Best performance (actual): 1.08
|
||||
% #+end_example
|
||||
|
||||
% The obtained closed-loop transfer functions are shown in Figure [[fig:ex_results_3]] and we can obverse that:
|
||||
% - The high frequency gain of $T$ is indeed reduced
|
||||
% - This comes as the expense of a large magnitude both $GS$ and $S$.
|
||||
% This means we will probably have slightly less good disturbance rejection and tracking performances.
|
||||
|
||||
|
||||
Z3 = lft(P, K3);
|
||||
|
||||
freqs = logspace(-1, 3, 1000);
|
||||
|
||||
figure;
|
||||
tiledlayout(2, 2, 'TileSpacing', 'Tight', 'Padding', 'None');
|
||||
|
||||
ax1 = nexttile;
|
||||
hold on;
|
||||
plot(freqs, abs(squeeze(freqresp(Z1(1,1), freqs, 'Hz'))), 'DisplayName', 'Step 1');
|
||||
plot(freqs, abs(squeeze(freqresp(Z1b(1,1), freqs, 'Hz'))), 'DisplayName', 'Step 1b');
|
||||
plot(freqs, abs(squeeze(freqresp(Z2(1,1), freqs, 'Hz'))), 'DisplayName', 'Step 2');
|
||||
plot(freqs, abs(squeeze(freqresp(Z3(1,1), freqs, 'Hz'))), 'DisplayName', 'Step 3');
|
||||
plot(freqs, 1./abs(squeeze(freqresp(W1, freqs, 'Hz'))), 'k--', 'DisplayName', '$|W^{-1}|$');
|
||||
hold off;
|
||||
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
||||
xlabel('Frequency [Hz]'); ylabel('Magnitude');
|
||||
title('S');
|
||||
legend('location', 'southeast');
|
||||
|
||||
ax2 = nexttile;
|
||||
hold on;
|
||||
plot(freqs, abs(squeeze(freqresp(Z1(2,1), freqs, 'Hz'))));
|
||||
plot(freqs, abs(squeeze(freqresp(Z1b(2,1), freqs, 'Hz'))));
|
||||
plot(freqs, abs(squeeze(freqresp(Z2(2,1), freqs, 'Hz'))));
|
||||
plot(freqs, abs(squeeze(freqresp(Z3(2,1), freqs, 'Hz'))));
|
||||
plot(freqs, 1./abs(squeeze(freqresp(W2, freqs, 'Hz'))), 'k--');
|
||||
hold off;
|
||||
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
||||
xlabel('Frequency [Hz]'); ylabel('Magnitude');
|
||||
title('GS');
|
||||
|
||||
ax3 = nexttile;
|
||||
hold on;
|
||||
plot(freqs, abs(squeeze(freqresp(Z1(3,1), freqs, 'Hz'))));
|
||||
plot(freqs, abs(squeeze(freqresp(Z1b(3,1), freqs, 'Hz'))));
|
||||
plot(freqs, abs(squeeze(freqresp(Z2(3,1), freqs, 'Hz'))));
|
||||
plot(freqs, abs(squeeze(freqresp(Z3(3,1), freqs, 'Hz'))));
|
||||
plot(freqs, 1./abs(squeeze(freqresp(W3, freqs, 'Hz'))), 'k--');
|
||||
hold off;
|
||||
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
||||
xlabel('Frequency [Hz]'); ylabel('Magnitude');
|
||||
title('T');
|
||||
|
||||
ax4 = nexttile;
|
||||
hold on;
|
||||
plot(freqs, abs(squeeze(freqresp(K1, freqs, 'Hz'))));
|
||||
plot(freqs, abs(squeeze(freqresp(K1b, freqs, 'Hz'))));
|
||||
plot(freqs, abs(squeeze(freqresp(K2, freqs, 'Hz'))));
|
||||
plot(freqs, abs(squeeze(freqresp(K3, freqs, 'Hz'))));
|
||||
hold off;
|
||||
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
||||
xlabel('Frequency [Hz]'); ylabel('Magnitude');
|
||||
title('K');
|
||||
|
||||
linkaxes([ax1, ax2, ax3, ax4], 'x')
|
||||
xlim([freqs(1), freqs(end)]);
|
||||
|
||||
|
||||
|
||||
% #+name: fig:ex_results_3
|
||||
% #+caption: Obtained Shape Closed-Loop transfer functions
|
||||
% #+RESULTS:
|
||||
% [[file:figs/ex_results_3.png]]
|
||||
|
||||
% The time domain simulation signals are shown in Figure [[fig:ex_time_domain_3]].
|
||||
% We can indeed see a slightly less good disturbance rejection.
|
||||
% However, the vibrations induced by the sensor noise is well reduced.
|
||||
% This can be seen when zooming on the output signal in Figure [[fig:ex_time_domaim_3_zoom]].
|
||||
|
||||
|
||||
Z3sim = lft(Psim, K3);
|
||||
|
||||
z = lsim(Z3sim, [r;n;d], t);
|
||||
y3 = z(:,1);
|
||||
u3 = z(:,2);
|
||||
|
||||
figure;
|
||||
tiledlayout(1, 1, 'TileSpacing', 'None', 'Padding', 'None');
|
||||
hold on;
|
||||
plot(t, 1e6*y1, 'DisplayName', 'Step 1');
|
||||
plot(t, 1e6*y1b, 'DisplayName', 'Step 1b');
|
||||
plot(t, 1e6*y2, 'DisplayName', 'Step 2');
|
||||
plot(t, 1e6*y3, 'DisplayName', 'Step 3');
|
||||
plot(t, 1e6*r, 'k--', 'DisplayName', '$r$');
|
||||
hold off;
|
||||
xlabel('Time [s]'); ylabel('Output $y$ [$\mu m$]');
|
||||
legend('location', 'southeast');
|
||||
|
||||
|
||||
|
||||
% #+name: fig:ex_time_domain_3
|
||||
% #+caption: Time domain simulation results
|
||||
% #+RESULTS:
|
||||
% [[file:figs/ex_time_domain_3.png]]
|
||||
|
||||
|
||||
figure;
|
||||
hold on;
|
||||
plot(t, 1e6*y1, 'DisplayName', 'Step 1');
|
||||
plot(t, 1e6*y1b, 'DisplayName', 'Step 1b');
|
||||
plot(t, 1e6*y2, 'DisplayName', 'Step 2');
|
||||
plot(t, 1e6*y3, 'DisplayName', 'Step 3');
|
||||
plot(t, 1e6*r, 'k--', 'DisplayName', '$r$');
|
||||
hold off;
|
||||
xlabel('Time [s]'); ylabel('Output $y$ [$\mu m$]');
|
||||
legend('location', 'southeast');
|
||||
xlim([0.4, 0.5])
|
||||
Reference in new issue
Block a user