Update figures and tangle matlab code
This commit is contained in:
95
matlab/force_sensor_identification.m
Normal file
95
matlab/force_sensor_identification.m
Normal file
@@ -0,0 +1,95 @@
|
||||
%% Clear Workspace and Close figures
|
||||
clear; close all; clc;
|
||||
|
||||
%% Intialize Laplace variable
|
||||
s = zpk('s');
|
||||
|
||||
addpath('./mat/');
|
||||
|
||||
% Load Data :ignore:
|
||||
% The data are loaded:
|
||||
|
||||
load('apa95ml_5kg_2a_1s.mat', 't', 'u', 'v');
|
||||
|
||||
|
||||
|
||||
% Any offset is removed.
|
||||
|
||||
u = detrend(u, 0); % Speedgoat DAC output Voltage [V]
|
||||
v = detrend(v, 0); % Speedgoat ADC input Voltage (sensor stack) [V]
|
||||
|
||||
|
||||
|
||||
% Here, the amplifier gain is 20.
|
||||
|
||||
u = 20*u; % Actuator Stack Voltage [V]
|
||||
|
||||
% Compute TF estimate and Coherence :ignore:
|
||||
% The transfer function from the actuator voltage $V_a$ to the force sensor stack voltage $V_s$ is computed.
|
||||
|
||||
|
||||
Ts = t(end)/(length(t)-1);
|
||||
Fs = 1/Ts;
|
||||
|
||||
win = hann(ceil(5/Ts));
|
||||
|
||||
[tf_est, f] = tfestimate(u, v, win, [], [], 1/Ts);
|
||||
[coh, ~] = mscohere( u, v, win, [], [], 1/Ts);
|
||||
|
||||
|
||||
|
||||
% The coherence is shown in Figure [[fig:apa95ml_5kg_cedrat_coh]].
|
||||
|
||||
|
||||
figure;
|
||||
|
||||
hold on;
|
||||
plot(f, coh, 'k-')
|
||||
set(gca, 'Xscale', 'log'); set(gca, 'Yscale', 'lin');
|
||||
ylabel('Coherence'); xlabel('Frequency [Hz]');
|
||||
hold off;
|
||||
xlim([10, 5e3]);
|
||||
|
||||
|
||||
|
||||
% #+name: fig:apa95ml_5kg_cedrat_coh
|
||||
% #+caption: Coherence
|
||||
% #+RESULTS:
|
||||
% [[file:figs/apa95ml_5kg_cedrat_coh.png]]
|
||||
|
||||
% The Simscape model is loaded and compared with the identified dynamics in Figure [[fig:bode_plot_force_sensor_voltage_comp_fem]].
|
||||
% The non-minimum phase zero is just a side effect of the not so great identification.
|
||||
% Taking longer measurements would results in a minimum phase zero.
|
||||
|
||||
|
||||
load('mat/fem_simscape_models.mat', 'Gfm');
|
||||
|
||||
freqs = logspace(1, 4, 1000);
|
||||
|
||||
figure;
|
||||
tiledlayout(3, 1, 'TileSpacing', 'None', 'Padding', 'None');
|
||||
|
||||
ax1 = nexttile([2,1]);
|
||||
hold on;
|
||||
plot(f, abs(tf_est))
|
||||
plot(freqs, abs(squeeze(freqresp(Gfm, freqs, 'Hz'))))
|
||||
set(gca, 'Xscale', 'log'); set(gca, 'Yscale', 'log');
|
||||
ylabel('Amplitude [V/V]'); set(gca, 'XTickLabel',[]);
|
||||
hold off;
|
||||
ylim([1e-3, 1e1]);
|
||||
|
||||
ax2 = nexttile;
|
||||
hold on;
|
||||
plot(f, 180/pi*angle(tf_est), ...
|
||||
'DisplayName', 'Identification')
|
||||
plot(freqs, 180/pi*angle(squeeze(freqresp(Gfm, freqs, 'Hz'))), ...
|
||||
'DisplayName', 'FEM')
|
||||
set(gca, 'Xscale', 'log'); set(gca, 'Yscale', 'lin');
|
||||
ylabel('Phase'); xlabel('Frequency [Hz]');
|
||||
hold off;
|
||||
ylim([-180, 180]);
|
||||
yticks(-180:90:180);
|
||||
legend('location', 'northeast')
|
||||
|
||||
linkaxes([ax1,ax2], 'x');
|
||||
xlim([10, 5e3]);
|
34
matlab/huddle_test.m
Normal file
34
matlab/huddle_test.m
Normal file
@@ -0,0 +1,34 @@
|
||||
%% Clear Workspace and Close figures
|
||||
clear; close all; clc;
|
||||
|
||||
%% Intialize Laplace variable
|
||||
s = zpk('s');
|
||||
|
||||
addpath('./mat/');
|
||||
|
||||
% Load Data :noexport:
|
||||
|
||||
load('huddle_test.mat', 't', 'y');
|
||||
|
||||
y = y - mean(y(1000:end));
|
||||
|
||||
% Time Domain Data
|
||||
|
||||
figure;
|
||||
plot(t(1000:end), y(1000:end))
|
||||
ylabel('Output Displacement [m]'); xlabel('Time [s]');
|
||||
|
||||
% PSD of Measurement Noise
|
||||
|
||||
Ts = t(end)/(length(t)-1);
|
||||
Fs = 1/Ts;
|
||||
|
||||
win = hanning(ceil(1*Fs));
|
||||
|
||||
[pxx, f] = pwelch(y(1000:end), win, [], [], Fs);
|
||||
|
||||
figure;
|
||||
plot(f, sqrt(pxx));
|
||||
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
||||
xlabel('Frequency [Hz]'); ylabel('ASD [$m/\sqrt{Hz}$]');
|
||||
xlim([1, Fs/2]);
|
307
matlab/integral_force_feedback.m
Normal file
307
matlab/integral_force_feedback.m
Normal file
@@ -0,0 +1,307 @@
|
||||
%% Clear Workspace and Close figures
|
||||
clear; close all; clc;
|
||||
|
||||
%% Intialize Laplace variable
|
||||
s = zpk('s');
|
||||
|
||||
addpath('./mat/');
|
||||
|
||||
% IFF Plant
|
||||
% From the identified plant, a model of the transfer function from the actuator stack voltage to the force sensor generated voltage is developed.
|
||||
|
||||
|
||||
w_z = 2*pi*111; % Zeros frequency [rad/s]
|
||||
w_p = 2*pi*255; % Pole frequency [rad/s]
|
||||
xi_z = 0.05;
|
||||
xi_p = 0.015;
|
||||
G_inf = 0.1;
|
||||
|
||||
Gi = G_inf*(s^2 + 2*xi_z*w_z*s + w_z^2)/(s^2 + 2*xi_p*w_p*s + w_p^2);
|
||||
|
||||
|
||||
|
||||
% Its bode plot is shown in Figure [[fig:iff_plant_identification_apa95ml]].
|
||||
|
||||
|
||||
freqs = logspace(1, 4, 1000);
|
||||
|
||||
figure;
|
||||
tiledlayout(3, 1, 'TileSpacing', 'None', 'Padding', 'None');
|
||||
|
||||
ax1 = nexttile([2,1]);
|
||||
hold on;
|
||||
plot(freqs, abs(squeeze(freqresp(Gi, freqs, 'Hz'))), 'k-')
|
||||
set(gca, 'Xscale', 'log'); set(gca, 'Yscale', 'log');
|
||||
ylabel('Amplitude'); set(gca, 'XTickLabel', []);
|
||||
hold off;
|
||||
ylim([1e-3, 1e1]);
|
||||
|
||||
ax2 = nexttile;
|
||||
hold on;
|
||||
plot(freqs, 180/pi*angle(squeeze(freqresp(Gi, freqs, 'Hz'))), 'k-')
|
||||
set(gca, 'Xscale', 'log'); set(gca, 'Yscale', 'lin');
|
||||
ylabel('Phase'); xlabel('Frequency [Hz]');
|
||||
hold off;
|
||||
ylim([-180, 180]);
|
||||
yticks(-180:90:180);
|
||||
|
||||
linkaxes([ax1,ax2], 'x');
|
||||
xlim([10, 5e3]);
|
||||
|
||||
|
||||
|
||||
% #+name: fig:iff_plant_identification_apa95ml
|
||||
% #+caption: Bode plot of the IFF plant
|
||||
% #+RESULTS:
|
||||
% [[file:figs/iff_plant_identification_apa95ml.png]]
|
||||
|
||||
% The controller used in the Integral Force Feedback Architecture is:
|
||||
% \begin{equation}
|
||||
% K_{\text{IFF}}(s) = \frac{g}{s + 2\cdot 2\pi} \cdot \frac{s}{s + 0.5 \cdot 2\pi}
|
||||
% \end{equation}
|
||||
% where $g$ is a gain that can be tuned.
|
||||
|
||||
% Above 2 Hz the controller is basically an integrator, whereas an high pass filter is added at 0.5Hz to further reduce the low frequency gain.
|
||||
|
||||
% In the frequency band of interest, this controller should mostly act as a pure integrator.
|
||||
|
||||
% The Root Locus corresponding to this controller is shown in Figure [[fig:root_locus_iff_apa95ml_identification]].
|
||||
|
||||
|
||||
gains = logspace(0, 5, 1000);
|
||||
|
||||
figure;
|
||||
hold on;
|
||||
plot(real(pole(Gi)), imag(pole(Gi)), 'kx');
|
||||
plot(real(tzero(Gi)), imag(tzero(Gi)), 'ko');
|
||||
for i = 1:length(gains)
|
||||
cl_poles = pole(feedback(Gi, (gains(i)/(s + 2*2*pi)*s/(s + 0.5*2*pi))));
|
||||
plot(real(cl_poles), imag(cl_poles), 'k.');
|
||||
end
|
||||
ylim([0, 1800]);
|
||||
xlim([-1600,200]);
|
||||
xlabel('Real Part')
|
||||
ylabel('Imaginary Part')
|
||||
axis square
|
||||
|
||||
% First tests with few gains
|
||||
% The controller is now implemented in practice, and few controller gains are tested: $g = 0$, $g = 10$ and $g = 100$.
|
||||
|
||||
% For each controller gain, the identification shown in Figure [[fig:test_bench_apa_schematic_iff]] is performed.
|
||||
|
||||
iff_g10 = load('apa95ml_iff_g10_res.mat', 'u', 't', 'y', 'v');
|
||||
iff_g100 = load('apa95ml_iff_g100_res.mat', 'u', 't', 'y', 'v');
|
||||
iff_of = load('apa95ml_iff_off_res.mat', 'u', 't', 'y', 'v');
|
||||
|
||||
Ts = 1e-4;
|
||||
win = hann(ceil(10/Ts));
|
||||
|
||||
[tf_iff_g10, f] = tfestimate(iff_g10.u, iff_g10.y, win, [], [], 1/Ts);
|
||||
[co_iff_g10, ~] = mscohere( iff_g10.u, iff_g10.y, win, [], [], 1/Ts);
|
||||
|
||||
[tf_iff_g100, ~] = tfestimate(iff_g100.u, iff_g100.y, win, [], [], 1/Ts);
|
||||
[co_iff_g100, ~] = mscohere( iff_g100.u, iff_g100.y, win, [], [], 1/Ts);
|
||||
|
||||
[tf_iff_of, ~] = tfestimate(iff_of.u, iff_of.y, win, [], [], 1/Ts);
|
||||
[co_iff_of, ~] = mscohere( iff_of.u, iff_of.y, win, [], [], 1/Ts);
|
||||
|
||||
|
||||
|
||||
% The coherence between the excitation signal and the mass displacement as measured by the interferometer is shown in Figure [[fig:iff_first_test_coherence]].
|
||||
|
||||
|
||||
figure;
|
||||
|
||||
hold on;
|
||||
plot(f, co_iff_of, '-', 'DisplayName', 'g=0')
|
||||
plot(f, co_iff_g10, '-', 'DisplayName', 'g=10')
|
||||
plot(f, co_iff_g100, '-', 'DisplayName', 'g=100')
|
||||
set(gca, 'Xscale', 'log'); set(gca, 'Yscale', 'lin');
|
||||
ylabel('Coherence'); xlabel('Frequency [Hz]');
|
||||
hold off;
|
||||
legend();
|
||||
xlim([60, 600])
|
||||
|
||||
|
||||
|
||||
% #+name: fig:iff_first_test_coherence
|
||||
% #+caption: Coherence
|
||||
% #+RESULTS:
|
||||
% [[file:figs/iff_first_test_coherence.png]]
|
||||
|
||||
% The obtained transfer functions are shown in Figure [[fig:iff_first_test_bode_plot]].
|
||||
% It is clear that the IFF architecture can actively damp the main resonance of the system.
|
||||
|
||||
|
||||
figure;
|
||||
tiledlayout(3, 1, 'TileSpacing', 'None', 'Padding', 'None');
|
||||
|
||||
ax1 = nexttile([2, 1]);
|
||||
hold on;
|
||||
plot(f, abs(tf_iff_of), '-', 'DisplayName', 'g=0')
|
||||
plot(f, abs(tf_iff_g10), '-', 'DisplayName', 'g=10')
|
||||
plot(f, abs(tf_iff_g100), '-', 'DisplayName', 'g=100')
|
||||
set(gca, 'Xscale', 'log'); set(gca, 'Yscale', 'log');
|
||||
ylabel('Amplitude'); set(gca, 'XTickLabel',[]);
|
||||
hold off;
|
||||
legend();
|
||||
|
||||
ax2 = nexttile;
|
||||
hold on;
|
||||
plot(f, 180/pi*angle(-tf_iff_of), '-')
|
||||
plot(f, 180/pi*angle(-tf_iff_g10), '-')
|
||||
plot(f, 180/pi*angle(-tf_iff_g100), '-')
|
||||
set(gca, 'Xscale', 'log'); set(gca, 'Yscale', 'lin');
|
||||
ylabel('Phase'); xlabel('Frequency [Hz]');
|
||||
hold off;
|
||||
yticks(-360:90:360);
|
||||
|
||||
linkaxes([ax1,ax2], 'x');
|
||||
xlim([60, 600]);
|
||||
|
||||
% Second test with many Gains
|
||||
% Then, the same identification test is performed for many more gains.
|
||||
|
||||
load('apa95ml_iff_test.mat', 'results');
|
||||
|
||||
Ts = 1e-4;
|
||||
win = hann(ceil(10/Ts));
|
||||
|
||||
tf_iff = {zeros(1, length(results))};
|
||||
co_iff = {zeros(1, length(results))};
|
||||
g_iff = [0, 1, 5, 10, 50, 100];
|
||||
|
||||
for i=1:length(results)
|
||||
[tf_est, f] = tfestimate(results{i}.u, results{i}.y, win, [], [], 1/Ts);
|
||||
[co_est, ~] = mscohere(results{i}.u, results{i}.y, win, [], [], 1/Ts);
|
||||
|
||||
tf_iff(i) = {tf_est};
|
||||
co_iff(i) = {co_est};
|
||||
end
|
||||
|
||||
|
||||
|
||||
% The obtained dynamics are shown in Figure [[fig:iff_results_bode_plots]].
|
||||
|
||||
|
||||
figure;
|
||||
tiledlayout(3, 1, 'TileSpacing', 'None', 'Padding', 'None');
|
||||
|
||||
ax1 = nexttile([2, 1]);
|
||||
hold on;
|
||||
for i = 1:length(results)
|
||||
plot(f, abs(tf_iff{i}), '-', 'DisplayName', sprintf('g = %0.f', g_iff(i)))
|
||||
end
|
||||
set(gca, 'Xscale', 'log'); set(gca, 'Yscale', 'log');
|
||||
ylabel('Amplitude'); set(gca, 'XTickLabel',[]);
|
||||
hold off;
|
||||
legend();
|
||||
|
||||
ax2 = nexttile;
|
||||
hold on;
|
||||
for i = 1:length(results)
|
||||
plot(f, 180/pi*angle(-tf_iff{i}), '-')
|
||||
end
|
||||
set(gca, 'Xscale', 'log'); set(gca, 'Yscale', 'lin');
|
||||
ylabel('Phase'); xlabel('Frequency [Hz]');
|
||||
yticks(-360:90:360);
|
||||
axis padded 'auto x'
|
||||
|
||||
linkaxes([ax1,ax2], 'x');
|
||||
xlim([60, 600]);
|
||||
|
||||
|
||||
|
||||
% #+name: fig:iff_results_bode_plots
|
||||
% #+caption: Identified dynamics from excitation voltage to the mass displacement
|
||||
% #+RESULTS:
|
||||
% [[file:figs/iff_results_bode_plots.png]]
|
||||
|
||||
% For each gain, the parameters of a second order resonant system that best fits the data are estimated and are compared with the data in Figure [[fig:iff_results_bode_plots_identification]].
|
||||
|
||||
|
||||
G_id = {zeros(1,length(results))};
|
||||
|
||||
f_start = 70; % [Hz]
|
||||
f_end = 500; % [Hz]
|
||||
|
||||
for i = 1:length(results)
|
||||
tf_id = tf_iff{i}(sum(f<f_start):length(f)-sum(f>f_end));
|
||||
f_id = f(sum(f<f_start):length(f)-sum(f>f_end));
|
||||
|
||||
gfr = idfrd(tf_id, 2*pi*f_id, Ts);
|
||||
G_id(i) = {procest(gfr,'P2UDZ')};
|
||||
end
|
||||
|
||||
figure;
|
||||
tiledlayout(3, 1, 'TileSpacing', 'None', 'Padding', 'None');
|
||||
|
||||
ax1 = nexttile([2, 1]);
|
||||
hold on;
|
||||
for i = 1:length(results)
|
||||
set(gca,'ColorOrderIndex',i)
|
||||
plot(f, abs(tf_iff{i}), '-', 'DisplayName', sprintf('g = %0.f', g_iff(i)))
|
||||
set(gca,'ColorOrderIndex',i)
|
||||
plot(f, abs(squeeze(freqresp(G_id{i}, f, 'Hz'))), '--', 'HandleVisibility', 'off')
|
||||
end
|
||||
set(gca, 'Xscale', 'log'); set(gca, 'Yscale', 'log');
|
||||
ylabel('Amplitude'); set(gca, 'XTickLabel',[]);
|
||||
hold off;
|
||||
legend();
|
||||
|
||||
ax2 = nexttile;
|
||||
hold on;
|
||||
for i = 1:length(results)
|
||||
set(gca,'ColorOrderIndex',i)
|
||||
plot(f, 180/pi*angle(tf_iff{i}), '-')
|
||||
set(gca,'ColorOrderIndex',i)
|
||||
plot(f, 180/pi*angle(squeeze(freqresp(G_id{i}, f, 'Hz'))), '--')
|
||||
end
|
||||
set(gca, 'Xscale', 'log'); set(gca, 'Yscale', 'lin');
|
||||
ylabel('Phase'); xlabel('Frequency [Hz]');
|
||||
hold off;
|
||||
yticks(-360:90:360);
|
||||
axis padded 'auto x'
|
||||
|
||||
linkaxes([ax1,ax2], 'x');
|
||||
xlim([60, 600]);
|
||||
|
||||
|
||||
|
||||
% #+name: fig:iff_results_bode_plots_identification
|
||||
% #+caption: Comparison of the measured dynamic and the identified 2nd order resonant systems that best fits the data
|
||||
% #+RESULTS:
|
||||
% [[file:figs/iff_results_bode_plots_identification.png]]
|
||||
|
||||
% Finally, we can represent the position of the poles of the 2nd order systems on the Root Locus plot (Figure [[fig:iff_results_root_locus]]).
|
||||
|
||||
|
||||
w_z = 2*pi*111; % Zeros frequency [rad/s]
|
||||
w_p = 2*pi*255; % Pole frequency [rad/s]
|
||||
xi_z = 0.05;
|
||||
xi_p = 0.015;
|
||||
G_inf = 2;
|
||||
|
||||
Gi = G_inf*(s^2 - 2*xi_z*w_z*s + w_z^2)/(s^2 + 2*xi_p*w_p*s + w_p^2);
|
||||
|
||||
|
||||
gains = logspace(0, 5, 1000);
|
||||
|
||||
figure;
|
||||
hold on;
|
||||
plot(real(pole(Gi)), imag(pole(Gi)), 'kx', 'HandleVisibility', 'off');
|
||||
plot(real(tzero(Gi)), imag(tzero(Gi)), 'ko', 'HandleVisibility', 'off');
|
||||
for i = 1:length(results)
|
||||
set(gca,'ColorOrderIndex',i)
|
||||
plot(real(pole(G_id{i})), imag(pole(G_id{i})), 'o', 'DisplayName', sprintf('g = %0.f', g_iff(i)));
|
||||
end
|
||||
for i = 1:length(gains)
|
||||
cl_poles = pole(feedback(Gi, (gains(i)/(s + 2*pi*2))));
|
||||
plot(real(cl_poles), imag(cl_poles), 'k.', 'HandleVisibility', 'off');
|
||||
end
|
||||
ylim([0, 1800]);
|
||||
xlim([-1600,200]);
|
||||
xlabel('Real Part')
|
||||
ylabel('Imaginary Part')
|
||||
axis square
|
||||
legend('location', 'northwest');
|
Binary file not shown.
100
matlab/motion_identification.m
Normal file
100
matlab/motion_identification.m
Normal file
@@ -0,0 +1,100 @@
|
||||
%% Clear Workspace and Close figures
|
||||
clear; close all; clc;
|
||||
|
||||
%% Intialize Laplace variable
|
||||
s = zpk('s');
|
||||
|
||||
addpath('./mat/');
|
||||
|
||||
% Load Data
|
||||
% The data from the "noise test" and the identification test are loaded.
|
||||
|
||||
ht = load('huddle_test.mat', 't', 'y');
|
||||
load('apa95ml_5kg_Amp_E505.mat', 't', 'um', 'y');
|
||||
|
||||
|
||||
|
||||
% Any offset value is removed:
|
||||
|
||||
um = detrend(um, 0); % Generated DAC Voltage [V]
|
||||
y = detrend(y , 0); % Mass displacement [m]
|
||||
|
||||
ht.y = detrend(ht.y, 0);
|
||||
|
||||
|
||||
|
||||
% Now we add a factor 10 to take into account the gain of the voltage amplifier.
|
||||
|
||||
Va = 10*um;
|
||||
|
||||
% Comparison of the PSD with Huddle Test
|
||||
|
||||
Ts = t(end)/(length(t)-1);
|
||||
Fs = 1/Ts;
|
||||
|
||||
win = hanning(ceil(1*Fs));
|
||||
|
||||
[pxx, f] = pwelch(y, win, [], [], Fs);
|
||||
[pht, ~] = pwelch(ht.y, win, [], [], Fs);
|
||||
|
||||
figure;
|
||||
hold on;
|
||||
plot(f, sqrt(pxx), 'DisplayName', '5kg');
|
||||
plot(f, sqrt(pht), 'DisplayName', 'Huddle Test');
|
||||
hold off;
|
||||
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
||||
xlabel('Frequency [Hz]'); ylabel('ASD [$m/\sqrt{Hz}$]');
|
||||
legend('location', 'northeast');
|
||||
xlim([1, Fs/2]);
|
||||
|
||||
% Compute TF estimate and Coherence
|
||||
|
||||
[tf_est, f] = tfestimate(Va, -y, win, [], [], 1/Ts);
|
||||
[co_est, ~] = mscohere( Va, -y, win, [], [], 1/Ts);
|
||||
|
||||
figure;
|
||||
|
||||
hold on;
|
||||
plot(f, co_est, 'k-')
|
||||
set(gca, 'Xscale', 'log'); set(gca, 'Yscale', 'lin');
|
||||
ylabel('Coherence'); xlabel('Frequency [Hz]');
|
||||
hold off;
|
||||
xlim([10, 5e3]);
|
||||
|
||||
|
||||
|
||||
% #+name: fig:apa95ml_5kg_PI_coh
|
||||
% #+caption: Coherence
|
||||
% #+RESULTS:
|
||||
% [[file:figs/apa95ml_5kg_PI_coh.png]]
|
||||
|
||||
% Comparison with the FEM model
|
||||
|
||||
load('mat/fem_simscape_models.mat', 'Ghm');
|
||||
|
||||
freqs = logspace(0, 4, 1000);
|
||||
|
||||
figure;
|
||||
tiledlayout(3, 1, 'TileSpacing', 'None', 'Padding', 'None');
|
||||
|
||||
ax1 = nexttile([2,1]);
|
||||
hold on;
|
||||
plot(f, abs(tf_est), 'DisplayName', 'Identification')
|
||||
plot(freqs, abs(squeeze(freqresp(Ghm, freqs, 'Hz'))), 'DisplayName', 'FEM')
|
||||
set(gca, 'Xscale', 'log'); set(gca, 'Yscale', 'log');
|
||||
ylabel('Amplitude [m/V]'); set(gca, 'XTickLabel', []);
|
||||
legend('location', 'northeast')
|
||||
hold off;
|
||||
|
||||
ax2 = nexttile;
|
||||
hold on;
|
||||
plot(f, 180/pi*angle(tf_est))
|
||||
plot(freqs, 180/pi*angle(squeeze(freqresp(Ghm, freqs, 'Hz'))))
|
||||
set(gca, 'Xscale', 'log'); set(gca, 'Yscale', 'lin');
|
||||
ylabel('Phase'); xlabel('Frequency [Hz]');
|
||||
hold off;
|
||||
ylim([-180, 180]);
|
||||
yticks(-180:90:180);
|
||||
|
||||
linkaxes([ax1,ax2], 'x');
|
||||
xlim([10, 5e3]);
|
Binary file not shown.
@@ -38,7 +38,7 @@ ka = 235e6; % [N/m]
|
||||
Lmax = 20e-6; % [m]
|
||||
Vmax = 170; % [V]
|
||||
|
||||
ka*Lmax/Vmax % [N/V]
|
||||
ga = ka*Lmax/Vmax; % [N/V]
|
||||
|
||||
% Estimation from Piezoelectric parameters
|
||||
% <<sec:estimation_piezo_params>>
|
||||
|
120
matlab/simscape_model.m
Normal file
120
matlab/simscape_model.m
Normal file
@@ -0,0 +1,120 @@
|
||||
%% Clear Workspace and Close figures
|
||||
clear; close all; clc;
|
||||
|
||||
%% Intialize Laplace variable
|
||||
s = zpk('s');
|
||||
|
||||
addpath('./mat/');
|
||||
|
||||
% Import Mass Matrix, Stiffness Matrix, and Interface Nodes Coordinates
|
||||
% We first extract the stiffness and mass matrices.
|
||||
|
||||
K = readmatrix('APA95ML_K.CSV');
|
||||
M = readmatrix('APA95ML_M.CSV');
|
||||
|
||||
|
||||
|
||||
% #+caption: First 10x10 elements of the Mass matrix
|
||||
% #+RESULTS:
|
||||
% | 0.03 | 7e-08 | 2e-06 | -3e-09 | -0.0002 | -6e-08 | -0.001 | 8e-07 | 6e-07 | -8e-09 |
|
||||
% | 7e-08 | 0.02 | -1e-06 | 9e-05 | -3e-09 | -4e-09 | -1e-06 | -0.0006 | -4e-08 | 5e-06 |
|
||||
% | 2e-06 | -1e-06 | 0.02 | -3e-08 | -4e-08 | 1e-08 | 1e-07 | -2e-07 | 0.0003 | 1e-09 |
|
||||
% | -3e-09 | 9e-05 | -3e-08 | 1e-06 | -3e-11 | -3e-13 | -7e-09 | -5e-06 | -3e-10 | 3e-08 |
|
||||
% | -0.0002 | -3e-09 | -4e-08 | -3e-11 | 2e-06 | 6e-10 | 2e-06 | -7e-09 | -2e-09 | 7e-11 |
|
||||
% | -6e-08 | -4e-09 | 1e-08 | -3e-13 | 6e-10 | 1e-06 | 1e-08 | 3e-09 | -2e-09 | 2e-13 |
|
||||
% | -0.001 | -1e-06 | 1e-07 | -7e-09 | 2e-06 | 1e-08 | 0.03 | 4e-08 | -2e-06 | 8e-09 |
|
||||
% | 8e-07 | -0.0006 | -2e-07 | -5e-06 | -7e-09 | 3e-09 | 4e-08 | 0.02 | -9e-07 | -9e-05 |
|
||||
% | 6e-07 | -4e-08 | 0.0003 | -3e-10 | -2e-09 | -2e-09 | -2e-06 | -9e-07 | 0.02 | 2e-08 |
|
||||
% | -8e-09 | 5e-06 | 1e-09 | 3e-08 | 7e-11 | 2e-13 | 8e-09 | -9e-05 | 2e-08 | 1e-06 |
|
||||
|
||||
% Then, we extract the coordinates of the interface nodes.
|
||||
|
||||
[int_xyz, int_i, n_xyz, n_i, nodes] = extractNodes('APA95ML_out_nodes_3D.txt');
|
||||
|
||||
% Simscape Model
|
||||
% The flexible element is imported using the =Reduced Order Flexible Solid= Simscape block.
|
||||
|
||||
% To model the actuator, an =Internal Force= block is added between the nodes 3 and 12.
|
||||
% A =Relative Motion Sensor= block is added between the nodes 1 and 2 to measure the displacement and the amplified piezo.
|
||||
|
||||
% One mass is fixed at one end of the piezo-electric stack actuator, the other end is fixed to the world frame.
|
||||
|
||||
m = 5.5;
|
||||
|
||||
load('apa95ml_params.mat', 'ga', 'gs');
|
||||
|
||||
% Dynamics from Actuator Voltage to Vertical Mass Displacement
|
||||
% The identified dynamics is shown in Figure [[fig:dynamics_act_disp_comp_mass]].
|
||||
|
||||
|
||||
%% Name of the Simulink File
|
||||
mdl = 'piezo_amplified_3d';
|
||||
|
||||
%% Input/Output definition
|
||||
clear io; io_i = 1;
|
||||
io(io_i) = linio([mdl, '/Va'], 1, 'openinput'); io_i = io_i + 1; % Actuator Voltage [V]
|
||||
io(io_i) = linio([mdl, '/y'], 1, 'openoutput'); io_i = io_i + 1; % Vertical Displacement [m]
|
||||
|
||||
Ghm = linearize(mdl, io);
|
||||
|
||||
freqs = logspace(0, 4, 5000);
|
||||
|
||||
figure;
|
||||
tiledlayout(3, 1, 'TileSpacing', 'None', 'Padding', 'None');
|
||||
|
||||
ax1 = nexttile([2,1]);
|
||||
hold on;
|
||||
plot(freqs, abs(squeeze(freqresp(Ghm, freqs, 'Hz'))));
|
||||
hold off;
|
||||
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
||||
ylabel('Amplitude $d/V_a$ [m/V]'); set(gca, 'XTickLabel',[]);
|
||||
hold off;
|
||||
|
||||
ax2 = nexttile;
|
||||
hold on;
|
||||
plot(freqs, 180/pi*unwrap(angle(squeeze(freqresp(Ghm, freqs, 'Hz')))));
|
||||
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin');
|
||||
yticks(-360:90:360);
|
||||
xlabel('Frequency [Hz]'); ylabel('Phase [deg]');
|
||||
hold off;
|
||||
linkaxes([ax1,ax2],'x');
|
||||
xlim([freqs(1), freqs(end)]);
|
||||
|
||||
% Dynamics from Actuator Voltage to Force Sensor Voltage
|
||||
% The obtained dynamics is shown in Figure [[fig:dynamics_force_force_sensor_comp_mass]].
|
||||
|
||||
|
||||
%% Name of the Simulink File
|
||||
mdl = 'piezo_amplified_3d';
|
||||
|
||||
%% Input/Output definition
|
||||
clear io; io_i = 1;
|
||||
io(io_i) = linio([mdl, '/Va'], 1, 'openinput'); io_i = io_i + 1; % Voltage Actuator [V]
|
||||
io(io_i) = linio([mdl, '/Vs'], 1, 'openoutput'); io_i = io_i + 1; % Sensor Voltage [V]
|
||||
|
||||
Gfm = linearize(mdl, io);
|
||||
|
||||
freqs = logspace(1, 5, 1000);
|
||||
|
||||
figure;
|
||||
tiledlayout(3, 1, 'TileSpacing', 'None', 'Padding', 'None');
|
||||
|
||||
ax1 = nexttile([2,1]);
|
||||
hold on;
|
||||
plot(freqs, abs(squeeze(freqresp(Gfm, freqs, 'Hz'))));
|
||||
hold off;
|
||||
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
||||
ylabel('Amplitude $V_s/V_a$ [V/V]'); set(gca, 'XTickLabel',[]);
|
||||
hold off;
|
||||
|
||||
ax2 = nexttile;
|
||||
hold on;
|
||||
plot(freqs, 180/pi*unwrap(angle(squeeze(freqresp(Gfm, freqs, 'Hz')))));
|
||||
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin');
|
||||
yticks(-360:90:360); ylim([-360, 180]);
|
||||
xlabel('Frequency [Hz]'); ylabel('Phase [deg]');
|
||||
hold off;
|
||||
linkaxes([ax1,ax2],'x');
|
||||
xlim([freqs(1), freqs(end)]);
|
||||
|
||||
save('mat/fem_simscape_models.mat', 'Ghm', 'Gfm')
|
Reference in New Issue
Block a user