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)')