Skip to content

Commit 21a305b

Browse files
akeesteMShabarajtgrasb
authored
Control optimal gains interpolation (#96) (#106)
* modifies the optimalGainCalc for the passive case * modifies the optimalGainCalc for the reactive case * Update optimalGainCalc.m Adds semicolon to one of the lines * modified the latching control gain calc * corrects the function description * modified the declutching control gain calc * update frequency calculation * revert period * final cleanup --------- Co-authored-by: Mohamed Shabara <84589678+MShabara@users.noreply.github.com> Co-authored-by: jtgrasb <87095491+jtgrasb@users.noreply.github.com>
1 parent 9a7a98c commit 21a305b

6 files changed

Lines changed: 164 additions & 119 deletions

File tree

Controls/Declutching/optimalTimeCalc.m

Lines changed: 35 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
% This script identifies the dynamics of the float in the respective wave
22
% conditions and determines the optimal proportional gain value for a
33
% passive controller (for regular waves)
4-
54
close all; clear all; clc;
65

6+
dof = 3; % Caluclate for heave motion
77
% Inputs (from wecSimInputFile)
88
simu = simulationClass();
9-
body(1) = bodyClass('../hydroData/sphere.h5');
10-
waves.height = 1;
11-
waves.period = 3.5;
9+
body(1) = bodyClass('../../_Common_Input_Files/Sphere/hydroData/sphere.h5');
10+
waves.height = 2.5; % Wave Height [m]
11+
waves.period = 9.6664; % Wave Period [s]
1212

1313
% Load hydrodynamic data for float from BEM
1414
hydro = readBEMIOH5(body.h5File{1}, 1, body.meanDrift);
@@ -19,53 +19,62 @@
1919
T = waves.period;
2020
omega = (1/T)*(2*pi);
2121

22+
% Extend the freq vector to include the wave frequency
23+
hydro.simulation_parameters.w_extended = sort([hydro.simulation_parameters.w omega]);
24+
omegaIndex = find(hydro.simulation_parameters.w_extended == omega, 1, 'first');
25+
2226
% Define excitation force based on wave conditions
23-
ampSpect = zeros(length(hydro.simulation_parameters.w),1);
24-
[~,closestIndOmega] = min(abs(omega-hydro.simulation_parameters.w));
25-
ampSpect(closestIndOmega) = A;
26-
FeRao = squeeze(hydro.hydro_coeffs.excitation.re(3,:))'*simu.rho*simu.gravity + squeeze(hydro.hydro_coeffs.excitation.im(3,:))'*simu.rho*simu.gravity*1j;
27-
Fexc = ampSpect.*FeRao;
27+
ampSpect = zeros(length(hydro.simulation_parameters.w_extended),1);
28+
ampSpect(omegaIndex) = A;
29+
Fe_re = squeeze(hydro.hydro_coeffs.excitation.re(dof, 1, :)) * simu.rho * simu.gravity;
30+
Fe_im = squeeze(hydro.hydro_coeffs.excitation.im(dof, 1, :)) * simu.rho * simu.gravity;
31+
32+
Fe_interp = interp1(hydro.simulation_parameters.w, Fe_re + 1j * Fe_im, hydro.simulation_parameters.w_extended, 'spline', 'extrap')';
33+
Fexc = ampSpect.*Fe_interp;
2834

2935
% Define the intrinsic mechanical impedance for the device
3036
mass = simu.rho*hydro.properties.volume;
31-
addedMass = squeeze(hydro.hydro_coeffs.added_mass.all(3,3,:))*simu.rho;
32-
radiationDamping = squeeze(hydro.hydro_coeffs.radiation_damping.all(3,3,:)).*squeeze(hydro.simulation_parameters.w')*simu.rho;
33-
hydrostaticStiffness = hydro.hydro_coeffs.linear_restoring_stiffness(3,3)*simu.rho*simu.gravity;
34-
Gi = -((hydro.simulation_parameters.w)'.^2.*(mass+addedMass)) + 1j*hydro.simulation_parameters.w'.*radiationDamping + hydrostaticStiffness;
35-
Zi = Gi./(1j*hydro.simulation_parameters.w');
37+
addedMass = squeeze(hydro.hydro_coeffs.added_mass.all(dof, dof, :)) * simu.rho;
38+
addedMass = interp1(hydro.simulation_parameters.w, addedMass, hydro.simulation_parameters.w_extended, 'spline', 'extrap')';
39+
40+
radiationDamping = squeeze(hydro.hydro_coeffs.radiation_damping.all(dof,dof,:)).*squeeze(hydro.simulation_parameters.w')*simu.rho;
41+
radiationDamping = interp1(hydro.simulation_parameters.w, radiationDamping, hydro.simulation_parameters.w_extended, 'spline', 'extrap')';
42+
43+
hydrostaticStiffness = hydro.hydro_coeffs.linear_restoring_stiffness(dof, dof) * simu.rho * simu.gravity;
44+
Gi = -((hydro.simulation_parameters.w_extended)'.^2 .* (mass+addedMass)) + 1j * hydro.simulation_parameters.w_extended'.*radiationDamping + hydrostaticStiffness;
45+
Zi = Gi./(1j*hydro.simulation_parameters.w_extended');
3646

3747
% Calculate magnitude and phase for bode plot
3848
Mag = 20*log10(abs(Zi));
3949
Phase = (angle(Zi))*(180/pi);
4050

41-
% Determine natural frequency based on the phase of the impedance
42-
[~,closestIndNat] = min(abs(imag(Zi)));
43-
natFreq = hydro.simulation_parameters.w(closestIndNat);
44-
natT = (2*pi)/natFreq;
51+
% Determine resonant frequency based on the phase of the impedance
52+
resonantFreq = interp1(Phase, hydro.simulation_parameters.w_extended, 0, 'spline','extrap');
53+
resonantPeriod = (2*pi)/resonantFreq;
4554

4655
% Create bode plot for impedance
4756
figure()
4857
subplot(2,1,1)
49-
semilogx((hydro.simulation_parameters.w)/(2*pi),Mag)
58+
semilogx((hydro.simulation_parameters.w_extended)/(2*pi),Mag)
5059
xlabel('freq (hz)')
5160
ylabel('mag (dB)')
5261
grid on
53-
xline(natFreq/(2*pi))
62+
xline(resonantFreq/(2*pi))
5463
xline(1/T,'--')
55-
legend('','Natural Frequency','Wave Frequency','Location','southwest')
64+
legend('','Resonant Frequency','Wave Frequency','Location','southwest')
5665

5766
subplot(2,1,2)
58-
semilogx((hydro.simulation_parameters.w)/(2*pi),Phase)
67+
semilogx((hydro.simulation_parameters.w_extended)/(2*pi),Phase)
5968
xlabel('freq (hz)')
6069
ylabel('phase (deg)')
6170
grid on
62-
xline(natFreq/(2*pi))
71+
xline(resonantFreq/(2*pi))
6372
xline(1/T,'--')
64-
legend('','Natural Frequency','Wave Frequency','Location','northwest')
73+
legend('','Resonant Frequency','Wave Frequency','Location','northwest')
6574

6675
% Determine optimal latching time
67-
optDeclutchTime = 0.5*(natT - T)
68-
KpOpt = sqrt(radiationDamping(closestIndOmega)^2 + ((hydrostaticStiffness/omega) - omega*(mass + addedMass(closestIndOmega)))^2)
76+
optDeclutchTime = 0.5*(resonantPeriod - T)
77+
KpOpt = sqrt(radiationDamping(omegaIndex)^2 + ((hydrostaticStiffness/omega) - omega*(mass + addedMass(omegaIndex)))^2)
6978

7079
% Calculate the maximum potential power
7180
P_max = -sum(abs(Fexc).^2./(8*real(Zi)))
Lines changed: 38 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
% This script identifies the dynamics of the float in the respective wave
2-
% conditions and determines the optimal proportional gain value for a
3-
% passive controller (for regular waves)
4-
2+
% conditions and determines the optimal proportional gain and latching time
3+
% value for a regular wave
54
close all; clear all; clc;
65

6+
dof = 3; % Caluclate for heave motion
77
% Inputs (from wecSimInputFile)
88
simu = simulationClass();
9-
body(1) = bodyClass('../hydroData/sphere.h5');
9+
body(1) = bodyClass('../../_Common_Input_Files/Sphere/hydroData/sphere.h5');
1010
waves.height = 2.5;
1111
waves.period = 9.6664;
1212

@@ -19,56 +19,64 @@
1919
T = waves.period;
2020
omega = (1/T)*(2*pi);
2121

22+
% Extend the freq vector to include the wave frequency
23+
hydro.simulation_parameters.w_extended = sort([hydro.simulation_parameters.w omega]);
24+
omegaIndex = find(hydro.simulation_parameters.w_extended == omega, 1, 'first');
25+
2226
% Define excitation force based on wave conditions
23-
ampSpect = zeros(length(hydro.simulation_parameters.w),1);
24-
[~,closestIndOmega] = min(abs(omega-hydro.simulation_parameters.w));
25-
ampSpect(closestIndOmega) = A;
26-
FeRao = squeeze(hydro.hydro_coeffs.excitation.re(3,:))'*simu.rho*simu.gravity + squeeze(hydro.hydro_coeffs.excitation.im(3,:))'*simu.rho*simu.gravity*1j;
27-
Fexc = ampSpect.*FeRao;
27+
ampSpect = zeros(length(hydro.simulation_parameters.w_extended),1);
28+
[~,closestIndOmega] = min(abs(omega-hydro.simulation_parameters.w_extended));
29+
ampSpect(omegaIndex) = A;
30+
Fe_re = squeeze(hydro.hydro_coeffs.excitation.re(dof, 1, :)) * simu.rho * simu.gravity;
31+
Fe_im = squeeze(hydro.hydro_coeffs.excitation.im(dof, 1, :)) * simu.rho * simu.gravity;
32+
33+
Fe_interp = interp1(hydro.simulation_parameters.w, Fe_re + 1j * Fe_im, hydro.simulation_parameters.w_extended, 'spline', 'extrap')';
34+
Fexc = ampSpect.*Fe_interp;
2835

2936
% Define the intrinsic mechanical impedance for the device
3037
mass = simu.rho*hydro.properties.volume;
31-
addedMass = squeeze(hydro.hydro_coeffs.added_mass.all(3,3,:))*simu.rho;
32-
radiationDamping = squeeze(hydro.hydro_coeffs.radiation_damping.all(3,3,:)).*squeeze(hydro.simulation_parameters.w')*simu.rho;
33-
hydrostaticStiffness = hydro.hydro_coeffs.linear_restoring_stiffness(3,3)*simu.rho*simu.gravity;
34-
Gi = -((hydro.simulation_parameters.w)'.^2.*(mass+addedMass)) + 1j*hydro.simulation_parameters.w'.*radiationDamping + hydrostaticStiffness;
35-
Zi = Gi./(1j*hydro.simulation_parameters.w');
38+
addedMass = squeeze(hydro.hydro_coeffs.added_mass.all(dof, dof, :)) * simu.rho;
39+
addedMass = interp1(hydro.simulation_parameters.w, addedMass, hydro.simulation_parameters.w_extended, 'spline', 'extrap')';
40+
41+
radiationDamping = squeeze(hydro.hydro_coeffs.radiation_damping.all(dof,dof,:)).*squeeze(hydro.simulation_parameters.w')*simu.rho;
42+
radiationDamping = interp1(hydro.simulation_parameters.w, radiationDamping, hydro.simulation_parameters.w_extended, 'spline', 'extrap')';
43+
44+
hydrostaticStiffness = hydro.hydro_coeffs.linear_restoring_stiffness(dof, dof) * simu.rho * simu.gravity;
45+
Gi = -((hydro.simulation_parameters.w_extended)'.^2 .* (mass+addedMass)) + 1j * hydro.simulation_parameters.w_extended'.*radiationDamping + hydrostaticStiffness;
46+
Zi = Gi./(1j*hydro.simulation_parameters.w_extended');
3647

3748
% Calculate magnitude and phase for bode plot
3849
Mag = 20*log10(abs(Zi));
3950
Phase = (angle(Zi))*(180/pi);
4051

41-
% Determine natural frequency based on the phase of the impedance
42-
[~,closestIndNat] = min(abs(imag(Zi)));
43-
natFreq = hydro.simulation_parameters.w(closestIndNat);
44-
natT = (2*pi)/natFreq;
52+
% Determine resonant frequency based on the phase of the impedance
53+
resonantFreq = interp1(Phase, hydro.simulation_parameters.w_extended, 0, 'spline','extrap');
54+
resonantPeriod = (2*pi)/resonantFreq;
4555

4656
% Create bode plot for impedance
4757
figure()
4858
subplot(2,1,1)
49-
semilogx((hydro.simulation_parameters.w)/(2*pi),Mag)
59+
semilogx((hydro.simulation_parameters.w_extended)/(2*pi),Mag)
5060
xlabel('freq (hz)')
5161
ylabel('mag (dB)')
5262
grid on
53-
xline(natFreq/(2*pi))
63+
xline(resonantFreq/(2*pi))
5464
xline(1/T,'--')
55-
legend('','Natural Frequency','Wave Frequency','Location','southwest')
65+
legend('','Resonant Frequency','Wave Frequency','Location','southwest')
5666

5767
subplot(2,1,2)
58-
semilogx((hydro.simulation_parameters.w)/(2*pi),Phase)
68+
semilogx((hydro.simulation_parameters.w_extended)/(2*pi),Phase)
5969
xlabel('freq (hz)')
6070
ylabel('phase (deg)')
6171
grid on
62-
xline(natFreq/(2*pi))
72+
xline(resonantFreq/(2*pi))
6373
xline(1/T,'--')
64-
legend('','Natural Frequency','Wave Frequency','Location','northwest')
74+
legend('','Resonant Frequency','Wave Frequency','Location','northwest')
6575

6676
% Determine optimal latching time
67-
optLatchTime = 0.5*(T - natT)
68-
KpOpt = radiationDamping(closestIndOmega)
69-
force = 80*(mass+addedMass(closestIndOmega))
77+
optLatchTime = 0.5*(T - resonantPeriod)
78+
KpOpt = radiationDamping(omegaIndex)
79+
force = 80*(mass+addedMass(omegaIndex))
7080

7181
% Calculate the maximum potential power
72-
P_max = -sum(abs(Fexc).^2./(8*real(Zi)))
73-
74-
82+
P_max = -sum(abs(Fexc).^2./(8*real(Zi)))
Lines changed: 43 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
% This script identifies the dynamics of the float in the respective wave
22
% conditions and determines the optimal proportional gain value for a
33
% passive controller (for regular waves)
4-
54
close all; clear all; clc;
65

6+
dof = 3; % Caluclate for heave motion
77
% Inputs (from wecSimInputFile)
88
simu = simulationClass();
9-
body(1) = bodyClass('../hydroData/sphere.h5');
9+
body(1) = bodyClass('../../_Common_Input_Files/Sphere/hydroData/sphere.h5');
1010
waves.height = 2.5;
1111
waves.period = 9.6664; % One of periods from BEM
1212

@@ -19,57 +19,70 @@
1919
T = waves.period;
2020
omega = (1/T)*(2*pi);
2121

22+
% Extend the freq vector to include the wave frequency
23+
hydro.simulation_parameters.w_extended = sort([hydro.simulation_parameters.w omega]);
24+
omegaIndex = find(hydro.simulation_parameters.w_extended == omega, 1, 'first');
25+
2226
% Define excitation force based on wave conditions
23-
ampSpect = zeros(length(hydro.simulation_parameters.w),1);
24-
[~,closestIndOmega] = min(abs(omega-hydro.simulation_parameters.w));
25-
ampSpect(closestIndOmega) = A;
26-
FeRao = squeeze(hydro.hydro_coeffs.excitation.re(3,:))'*simu.rho*simu.gravity + squeeze(hydro.hydro_coeffs.excitation.im(3,:))'*simu.rho*simu.gravity*1j;
27-
Fexc = ampSpect.*FeRao;
27+
ampSpect = zeros(length(hydro.simulation_parameters.w_extended),1);
28+
ampSpect(omegaIndex) = A;
29+
Fe_re = squeeze(hydro.hydro_coeffs.excitation.re(dof, 1, :)) * simu.rho * simu.gravity;
30+
Fe_im = squeeze(hydro.hydro_coeffs.excitation.im(dof, 1, :)) * simu.rho * simu.gravity;
31+
32+
Fe_interp = interp1(hydro.simulation_parameters.w, Fe_re + 1j * Fe_im, hydro.simulation_parameters.w_extended, 'spline', 'extrap')';
33+
Fexc = ampSpect.*Fe_interp;
2834

2935
% Define the intrinsic mechanical impedance for the device
30-
mass = simu.rho*hydro.properties.volume;
31-
addedMass = squeeze(hydro.hydro_coeffs.added_mass.all(3,3,:))*simu.rho;
32-
radiationDamping = squeeze(hydro.hydro_coeffs.radiation_damping.all(3,3,:)).*squeeze(hydro.simulation_parameters.w')*simu.rho;
33-
hydrostaticStiffness = hydro.hydro_coeffs.linear_restoring_stiffness(3,3)*simu.rho*simu.gravity;
34-
Gi = -((hydro.simulation_parameters.w)'.^2.*(mass+addedMass)) + 1j*hydro.simulation_parameters.w'.*radiationDamping + hydrostaticStiffness;
35-
Zi = Gi./(1j*hydro.simulation_parameters.w');
36+
mass = simu.rho * hydro.properties.volume;
37+
addedMass = squeeze(hydro.hydro_coeffs.added_mass.all(dof, dof, :)) * simu.rho;
38+
addedMass = interp1(hydro.simulation_parameters.w, addedMass, hydro.simulation_parameters.w_extended, 'spline', 'extrap')';
39+
addedMass = squeeze(hydro.hydro_coeffs.added_mass.inf_freq(dof, dof, :)) * simu.rho;
40+
41+
radiationDamping = squeeze(hydro.hydro_coeffs.radiation_damping.all(dof,dof,:)).*squeeze(hydro.simulation_parameters.w')*simu.rho;
42+
radiationDamping = interp1(hydro.simulation_parameters.w, radiationDamping, hydro.simulation_parameters.w_extended, 'spline', 'extrap')';
43+
44+
hydrostaticStiffness = hydro.hydro_coeffs.linear_restoring_stiffness(dof, dof) * simu.rho * simu.gravity;
45+
Gi = -((hydro.simulation_parameters.w_extended)'.^2 .* (mass+addedMass)) + 1j * hydro.simulation_parameters.w_extended'.*radiationDamping + hydrostaticStiffness;
46+
Zi = Gi./(1j*hydro.simulation_parameters.w_extended');
3647

3748
% Calculate magnitude and phase for bode plot
3849
Mag = 20*log10(abs(Zi));
3950
Phase = (angle(Zi))*(180/pi);
4051

41-
% Determine natural frequency based on the phase of the impedance
42-
[~,closestIndNat] = min(abs(imag(Zi)));
43-
natFreq = hydro.simulation_parameters.w(closestIndNat);
44-
T0 = (2*pi)/natFreq;
52+
% Determine resonant frequency based on the phase of the impedance
53+
resonantFreq = interp1(Phase, hydro.simulation_parameters.w_extended, 0, 'spline','extrap');
54+
resonantPeriod = (2*pi)/resonantFreq;
4555

4656
% Create bode plot for impedance
4757
figure()
4858
subplot(2,1,1)
49-
semilogx((hydro.simulation_parameters.w)/(2*pi),Mag)
50-
xlabel('freq (hz)')
51-
ylabel('mag (dB)')
59+
semilogx((hydro.simulation_parameters.w_extended)/(2*pi),Mag)
60+
xlabel('freq (hz)','interpreter','latex')
61+
ylabel('mag (dB)','interpreter','latex')
5262
grid on
53-
xline(natFreq/(2*pi))
63+
xline(resonantFreq/(2*pi))
5464
xline(1/T,'--')
55-
legend('','Natural Frequency','Wave Frequency','Location','southwest')
65+
legend('','Resonant Frequency','Wave Frequency','Location','southwest','interpreter','latex')
5666

5767
subplot(2,1,2)
58-
semilogx((hydro.simulation_parameters.w)/(2*pi),Phase)
59-
xlabel('freq (hz)')
60-
ylabel('phase (deg)')
68+
semilogx((hydro.simulation_parameters.w_extended)/(2*pi),Phase)
69+
xlabel('freq (hz)','interpreter','latex')
70+
ylabel('phase (deg)','interpreter','latex')
6171
grid on
62-
xline(natFreq/(2*pi))
72+
xline(resonantFreq/(2*pi))
6373
xline(1/T,'--')
64-
legend('','Natural Frequency','Wave Frequency','Location','northwest')
74+
legend('','Resonant Frequency','Wave Frequency','Location','northwest','interpreter','latex')
6575

6676
% Calculate the maximum potential power
67-
P_max = -sum(abs(Fexc).^2./(8*real(Zi)))
77+
P_max = -sum(abs(Fexc).^2./(8*real(Zi)));
78+
fprintf('Maximum potential power P_max = %f\n', P_max);
6879

6980
% Optimal proportional gain for passive control:
70-
KpOpt = sqrt(radiationDamping(closestIndOmega)^2 + ((hydrostaticStiffness/omega) - omega*(mass + addedMass(closestIndOmega)))^2)
81+
KpOpt = sqrt(radiationDamping(omegaIndex)^2 + ((hydrostaticStiffness/omega) - omega*(mass + addedMass))^2);
7182
Ki = 0;
83+
fprintf('Optimal proportional gain for passive control KpOpt = %f\n', KpOpt);
7284

7385
% Calculate expected power with optimal passive control
7486
Zpto = KpOpt + Ki/(1j*omega);
75-
P = -sum(0.5*real(Zpto).*((abs(Fexc)).^2./(abs(Zpto+Zi)).^2))
87+
P = -sum(0.5*real(Zpto).*((abs(Fexc)).^2./(abs(Zpto+Zi)).^2));
88+
fprintf('Expected power with optimal passive control P = %f\n', P);

Controls/Passive (P)/userDefinedFunctionsMCR.m

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
mcr.maxPower(imcr) = max(controllersOutput.power(startInd:endInd,3));
1818
mcr.maxForce(imcr) = max(controllersOutput.force(startInd:endInd,3));
1919

20-
if imcr == 9
20+
if imcr == length(mcr.cases)
2121
figure()
2222
plot(mcr.cases,mcr.meanPower)
2323
title('Mean Power vs. Proportional Gain')

0 commit comments

Comments
 (0)