mirror of https://github.com/ArduPilot/ardupilot
160 lines
5.8 KiB
Matlab
160 lines
5.8 KiB
Matlab
clc
|
|
clear all
|
|
close all
|
|
|
|
%{
|
|
Very basic Velocity Prediction Program, this duplicates the physics used in the sailboat SITL model. It can be used to generate polar plots to check
|
|
STIL physics is sensible.
|
|
|
|
In the future it is hoped this program can be used as a comparison for a built in polar generator that is yet to be added to the ArduRover code.
|
|
Alternatively a drag polar generated here can be used directly in the code to select optimal sailing angles.
|
|
|
|
Sail lift, drag and Hull drag not considered properly, boat heel not considered. The polar generated is however realistic for a 'generic' sailboat.
|
|
%}
|
|
|
|
sail_aoa_in = [0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120, 130, 140, 150, 160, 170, 179.9]; % deg
|
|
lift_curve_in = [0.00, 0.50, 1.00, 1.10, 0.95, 0.75, 0.60, 0.40, 0.20, 0.00, -0.20, -0.40, -0.60, -0.75, -0.95, -1.10, -1.00, -0.50, 0];
|
|
drag_curve_in = [0.10, 0.10, 0.20, 0.40, 0.80, 1.20, 1.50, 1.70, 1.90, 1.95, 1.90, 1.70, 1.50, 1.20, 0.80, 0.40, 0.20, 0.10, 0.10];
|
|
|
|
|
|
min_sail_angle = 0; % deg
|
|
max_sail_angle = 90; % deg
|
|
|
|
% intpolate to more detailed curves
|
|
sail_aoa = sail_aoa_in(1):0.1:sail_aoa_in(end)-0.1;
|
|
lift_curve = interp1(sail_aoa_in, lift_curve_in, sail_aoa);
|
|
drag_curve = interp1(sail_aoa_in, drag_curve_in, sail_aoa);
|
|
|
|
% Plot lift curve
|
|
figure
|
|
subplot(2,1,1)
|
|
hold all
|
|
title('Lift and Drag Curves')
|
|
scatter(sail_aoa_in,lift_curve_in,'*','r')
|
|
plot(sail_aoa,lift_curve,'r')
|
|
ylabel('Cl')
|
|
|
|
subplot(2,1,2)
|
|
hold all
|
|
scatter(sail_aoa_in,drag_curve_in,'*','b')
|
|
plot(sail_aoa,drag_curve,'b')
|
|
xlabel('AoA (deg)')
|
|
ylabel('Cd')
|
|
|
|
%% VPP
|
|
% Do for range of sailing angles and wind speeds, increse speed until foward force equals zero
|
|
wind_speed = 3:2:15; % m/s
|
|
heading = 0:1:179; % deg
|
|
speed_step = 0.01; % m/s
|
|
|
|
for n = 1:length(wind_speed)
|
|
for m = 1:length(heading)
|
|
|
|
thrust = 1;
|
|
boat_speed{n,m}(1) = 0;
|
|
j = 0;
|
|
while thrust > 0 && boat_speed{n,m}(end) < 10
|
|
j = j + 1;
|
|
if j == 1
|
|
boat_speed{n,m}(j) = speed_step;
|
|
else
|
|
boat_speed{n,m}(j) = boat_speed{n,m}(j-1) + speed_step;
|
|
end
|
|
|
|
% calculate apparent wind in earth-frame (this is the direction the wind is coming from)
|
|
wind_apparent_speed{n,m}(j) = sqrt(wind_speed(n)^2 + boat_speed{n,m}(j)^2 + 2 * wind_speed(n) * boat_speed{n,m}(j) * cosd(heading(m)));
|
|
|
|
% Aparent wind angle in body frame
|
|
wind_apparent_dir_bf{n,m}(j) = acosd((wind_speed(n) * cosd(heading(m)) + boat_speed{n,m}(j))/wind_apparent_speed{n,m}(j));
|
|
|
|
% calculate lift at all angles-of-attack from wind to mainsail
|
|
% calculate Lift force (perpendicular to wind direction) and Drag force (parallel to wind direction)
|
|
lift = lift_curve * wind_apparent_speed{n,m}(j);
|
|
drag = drag_curve * wind_apparent_speed{n,m}(j);
|
|
|
|
% rotate lift and drag from wind frame into body frame
|
|
sin_rot = sind(wind_apparent_dir_bf{n,m}(j));
|
|
cos_rot = cosd(wind_apparent_dir_bf{n,m}(j));
|
|
force_fwd = (lift * sin_rot) - (drag * cos_rot);
|
|
|
|
% accel in body frame due acceleration from sail and deceleration from hull friction
|
|
hull_drag = 0.5 * boat_speed{n,m}(j)^2;
|
|
thrust_range = force_fwd - hull_drag;
|
|
|
|
% angle of sail to boat
|
|
sail_boat_angle = wind_apparent_dir_bf{n,m}(j) - sail_aoa;
|
|
% discard imposible sail angles
|
|
index = find(sail_boat_angle > max_sail_angle | sail_boat_angle < min_sail_angle);
|
|
thrust_range(index) = NaN;
|
|
|
|
% select sail angle that gives best thrust
|
|
index = find(thrust_range == max(thrust_range),1);
|
|
|
|
if ~isempty(index)
|
|
thrust = thrust_range(index);
|
|
sail_force{n,m}(j) = force_fwd(index);
|
|
sail_angle_trim{n,m}(j) = sail_boat_angle(index);
|
|
hull_drag_trim{n,m}(j) = hull_drag;
|
|
else
|
|
thrust = 0;
|
|
end
|
|
end
|
|
|
|
max_boat_speed(n,m) = boat_speed{n,m}(j);
|
|
% Set minumum values to NaN to make plot neater
|
|
if max_boat_speed(n,m) == speed_step
|
|
max_boat_speed(n,m) = NaN;
|
|
end
|
|
end
|
|
end
|
|
|
|
|
|
%% Polar plot
|
|
figure
|
|
for n = 1:length(wind_speed)
|
|
polarplot(deg2rad(heading),max_boat_speed(n,:))
|
|
hold on
|
|
legend_val{n} = sprintf('%g m/s',wind_speed(n));
|
|
end
|
|
ax = gca;
|
|
d = ax.ThetaDir;
|
|
ax.ThetaDir = 'clockwise';
|
|
ax.ThetaZeroLocation = 'top';
|
|
legend(legend_val)
|
|
title('Polar Plot, boat speed (m/s) vs heading (deg)')
|
|
|
|
|
|
%% Plot sail thrust and hull drag for a given heading
|
|
plot_heading = 50;
|
|
plot_wind_speed = 5;
|
|
|
|
% convet from values to indexs
|
|
plot_heading = find(heading == plot_heading);
|
|
plot_wind_speed = find(wind_speed == plot_wind_speed);
|
|
|
|
if isempty(plot_heading) || isempty(plot_wind_speed)
|
|
fprintf('Plot headings and or windspeed not within the range caulated')
|
|
return
|
|
end
|
|
|
|
figure
|
|
subplot(2,1,1)
|
|
hold all
|
|
title(sprintf('Thrust vs drag for heading of %g deg and wind speed of %g m/s',heading(plot_heading),wind_speed(plot_wind_speed)))
|
|
yyaxis left
|
|
plot(boat_speed{plot_wind_speed,plot_heading},wind_apparent_speed{plot_wind_speed,plot_heading})
|
|
ylabel('Apparent wind speed (m/s)')
|
|
yyaxis right
|
|
plot(boat_speed{plot_wind_speed,plot_heading},wind_apparent_dir_bf{plot_wind_speed,plot_heading})
|
|
ylabel('Apparent wind direction (deg)')
|
|
|
|
|
|
subplot(2,1,2)
|
|
hold all
|
|
plot(boat_speed{plot_wind_speed,plot_heading},sail_force{plot_wind_speed,plot_heading})
|
|
plot(boat_speed{plot_wind_speed,plot_heading},hull_drag_trim{plot_wind_speed,plot_heading})
|
|
|
|
legend('Sail Forwards force','Hull drag','Location','northwest')
|
|
ylabel('Force (N)')
|
|
xlabel('Boat speed (m/s)')
|