Fall 2023 project as part of intro to MATLAB class. Takes intial condition of a basketball shot, plots in on a 3d grid, and checks if the shot went through. Grid and outline of process provided by the professor.
clear all; clc; close all;
format long;
num_shots = 7;
% preallocate results structure
results(num_shots) = struct('Zo', [], 'phi', [], 'status', [], 'X', [], 'Y', [], 'Z', [], 'U', [], 'V', [], 'W', [], 'T', []);
% loop over shots
for shot_num = 1:num_shots
[Xo, Yo, Zo, Umag0, theta, phi, omgX, omgY, omgZ] = read_input('test_study_parameter.txt', shot_num);
[T, X, Y, Z, U, V, W, status] = basketball(Xo, Yo, Zo, Umag0, theta, phi, omgX, omgY, omgZ);
results(shot_num).Zo = Zo;
results(shot_num).phi = phi;
results(shot_num).status = status;
results(shot_num).X = X;
results(shot_num).Y = Y;
results(shot_num).Z = Z;
results(shot_num).U = U;
results(shot_num).V = V;
results(shot_num).W = W;
T = T(end);
results(shot_num).T = T;
end
figure(1);
hold on;
load('court_geometry.mat');
figure(1); hold on;
plot3(Xcourt,Ycourt,Zcourt,'.','color',[0.5 0.2 0.3]);
plot3(Xrim,Yrim,Zrim,'-','color',[.8 0 0.8]);
plot3(Xboard,Yboard,Zboard,'.','color',[1 0.9 1]);
box on; grid on; axis tight; axis equal;
xlabel('x (m)'); ylabel('y (m)'); zlabel('z (m)');
title('Basketball Court');
view(3);
set(gca,'FontSize',16);
colors = lines(num_shots); % generate a set of distinct colors for each shot
for shot_num = 1:num_shots
plot3(results(shot_num).X, results(shot_num).Y, results(shot_num).Z, 'color', colors(shot_num,:), 'LineWidth', 1.5, 'DisplayName', ['Shot ', num2str(shot_num)]);
plot3(results(shot_num).X(1), results(shot_num).Y(1), results(shot_num).Z(1), 'o');
plot3(results(shot_num).X(end), results(shot_num).Y(end), results(shot_num).Z(end), '*');
end
title('Optimal Shooting Angles Study');
xlabel('X Position (m)');
ylabel('Y Position (m)');
zlabel('Z Position (m)');
grid on;
hold off;
%make the data strucutre
ball_stat = struct('shot_number', cell(1, num_shots), 'time', cell(1, num_shots), 'max_height_position', cell(1, num_shots), 'landing_position', cell(1, num_shots), 'landing_speed', cell(1, num_shots), 'travel_distance', cell(1, num_shots));
for shot_num = 1:num_shots
ball_stat(shot_num).shot_number = shot_num;
ball_stat(shot_num).time = results(shot_num).T;
[~, idx_max_height] = max(results(shot_num).Z);
ball_stat(shot_num).max_height_position = [results(shot_num).X(idx_max_height), results(shot_num).Y(idx_max_height), results(shot_num).Z(idx_max_height)];
ball_stat(shot_num).landing_position = [results(shot_num).X(end), results(shot_num).Y(end), results(shot_num).Z(end)];
landing_velocity = [results(shot_num).U(end), results(shot_num).V(end), results(shot_num).W(end)] ; % [Ux, Vy, Wz]
ball_stat(shot_num).landing_speed = sqrt(landing_velocity(1)^2 + landing_velocity(2)^2 + landing_velocity(3)^2);
travel_distance = 0;
for i = 2:length(results(shot_num).X)
dx = results(shot_num).X(i) - results(shot_num).X(i-1);
dy = results(shot_num).Y(i) - results(shot_num).Y(i-1);
dz = results(shot_num).Z(i) - results(shot_num).Z(i-1);
travel_distance = travel_distance + sqrt(dx^2 + dy^2 + dz^2);
end
ball_stat(shot_num).travel_distance = travel_distance;
end
%study on optimal shooting angles
num_simulations = 1200;
results5(num_simulations) = struct('Zo', [], 'phi', [], 'status', [], 'X', [], 'Y', [], 'Z', [], 'U', [], 'V', [], 'W', [], 'T', []);
for shot_num = 1:num_simulations
[Xo, Yo, Zo, Umag0, theta, phi, omgX, omgY, omgZ] = read_input('best_angle_study_parameter.txt', shot_num);
[T2, X2, Y2, Z2, U2, V2, W2, status] = basketball(Xo, Yo, Zo, Umag0, theta, phi, omgX, omgY, omgZ);
results5(shot_num).Zo = Zo;
results5(shot_num).phi = phi;
results5(shot_num).status = status;
results5(shot_num).X = X2;
results5(shot_num).Y = Y2;
results5(shot_num).Z = Z2;
results5(shot_num).U = U2;
results5(shot_num).V = V2;
results5(shot_num).W = W2;
T = T2(end);
results5(shot_num).T = T2;
end
figure(2); hold on;
for shot_num = 1:num_simulations
if results5(shot_num).status == 1
plot(results5(shot_num).Zo, results5(shot_num).phi, 'o', 'MarkerSize', 5, 'MarkerFaceColor', 'r', 'MarkerEdgeColor', 'r');
end
if results5(shot_num).status == 0
plot(results5(shot_num).Zo, results5(shot_num).phi, 'o', 'MarkerSize', 5, 'MarkerFaceColor', 'k', 'MarkerEdgeColor', 'k');
end
end
xlabel('Initial Vertical Position Z0 (m)');
ylabel('Shooting Angle \phi (degrees)');
title('Optimal Shooting Angles Study');
legend({'Successful Shot', 'Missed Shot'}, 'Location', 'best');
hold off;
good = 0;
for i = 1:1200
if results5(i).status == 1
good = good + 1;
end
end
disp(good)
function [T, X, Y, Z, U, V, W, status] = basketball(Xo, Yo, Zo, Umag0, theta, phi, omgX, omgY, omgZ)
%basketball returns a vector for time, x-positions, y-positions, z-positions,
% x-velocities, y-velocities, z-velocities, and status of shot throughout
% the ball's time in the air.
%Call format: [T, X, Y, Z, U, V, W, status] = basketball(Xo, Yo, Zo, Umag0,
%theta, phi, omgX, omgY, omgZ);
m = 0.625;
r = 0.12;
A = pi * r^2;
drim = 0.46;
rrim = drim/2;
rho = 1.2;
g = 9.81;
Cd = 0.3;
Cm = 0.13;
dt = 0.01;
load('court_geometry.mat', 'Xboard', 'Yboard', 'Zboard', 'Xrim', 'Yrim', 'Zrim');
Xrim_center = mean(Xrim); % Calculate the center
Yrim_center = mean(Yrim);
Zrim_center = mean(Zrim);
U0 = Umag0 * cosd(phi) * cosd(theta);
V0 = Umag0 * cosd(phi) * sind(theta);
W0 = Umag0 * sind(phi);
num_steps = 100000;
T = zeros(1, num_steps);
X = zeros(1, num_steps);
Y = zeros(1, num_steps);
Z = zeros(1, num_steps);
U = zeros(1, num_steps);
V = zeros(1, num_steps);
W = zeros(1, num_steps);
n = 1;
T(1) = 0;
X(1) = Xo;
Y(1) = Yo;
Z(1) = Zo;
U(1) = U0;
V(1) = V0;
W(1) = W0;
status = 0;
passed_hoop = 0;
while Z(n) >= r && X(n) >= -14.4 + r && X(n) <= -r && Y(n) >= -7.5 + r && Y(n) <= 7.5 - r
U_mag = sqrt(U(n)^2 + V(n)^2 + W(n)^2);
U(n+1) = U(n) - ( (Cd * rho * A / (2 * m) * U(n) * U_mag - Cm * rho * A * r / (2 * m) * (omgY * W(n) - omgZ * V(n))) * dt );
V(n+1) = V(n) - ( (Cd * rho * A / (2 * m) * V(n) * U_mag - Cm * rho * A * r / (2 * m) * (omgZ * U(n) - omgX * W(n))) * dt );
W(n+1) = W(n) - ( (Cd * rho * A / (2 * m) * W(n) * U_mag - Cm * rho * A * r / (2 * m) * (omgX * V(n) - omgY * U(n))) * dt + g * dt );
X(n+1) = X(n) + U(n+1) * dt;
Y(n+1) = Y(n) + V(n+1) * dt;
Z(n+1) = Z(n) + W(n+1) * dt;
T(n+1) = T(n) + dt;
dist_to_rim = sqrt((X(n) - Xrim).^2 + (Y(n) - Yrim).^2 + (Z(n) - Zrim).^2);
%passed hoop check
if abs(Z(n) - Zrim) <= 0.019
if abs(X(n)- max(Xrim)) <= drim
if abs(Y(n)- max(Yrim)) <= drim
if any(((drim/2) - dist_to_rim) > 0)
passed_hoop = 1;
end
end
end
end
%hit rim check
if any(dist_to_rim < r)
status = 0;
if passed_hoop
status = 1;
break;
end
break;
end
%hit backboard check
dist_to_backboard = sqrt((X(n+1) - Xboard).^2 + (Y(n+1) - Yboard).^2 + (Z(n+1) - Zboard).^2);
if any(dist_to_backboard <= r)
break;
end
if passed_hoop
status = 1;
end
n = n + 1;
end
T = T(1:n);
X = X(1:n);
Y = Y(1:n);
Z = Z(1:n);
U = U(1:n);
V = V(1:n);
W = W(1:n);
end