Problem: Missile Trajectory Simulation and Analysis

The problem involves developing MATLAB functions to read missile parameters, compute thrust/mass/drag, simulate trajectories, and perform analysis/visualization for 7 missiles.


Input/Output: The problem takes a tab-separated missile parameter file (skipping first 7 lines) and a terrain MAT file (containing x_terrain, y_terrain, h_terrain) as inputs. It outputs three figures (trajectories/landing locations, speed/acceleration over time, Mach number vs altitude), a flight_stat structure with missile ID, landing time/distance/location, max height stats, landing Mach/acceleration, a report.txt with statistics, and a missile_validation.avi video of trajectories.

Required dependencies:

Sub-steps:
step_number: 1
step_description_prompt: Please write a MATLAB function named read_input that reads missile initial parameters from a specified tab-separated input file (skipping the first 7 lines) based on the given missile ID (M_id) and returns the corresponding parameters. If M_id is invalid (≤0 or greater than the number of missiles in the file), all output parameters are set to NaN and an error message is displayed.
Function definition: function [X0, Y0, Z0, m0, mf, Thmag0, theta, phi, Tburn] = read_input(input_filename, M_id)
Algorithm flow:
1. Use the importdata function with parameters (input_filename, '\t', 7) to read the input file, where '\t' is the field delimiter and 7 indicates skipping the first 7 header lines. Store the result in the variable 'missile'.
2. Get the size [r, c] of the 'missile.data' matrix.
3. Check if M_id is valid: if M_id ≤ 0 or M_id > r:
   a. Set X0, Y0, Z0, m0, mf, Thmag0, theta, phi, Tburn all to NaN.
   b. Display the error message 'Error: invalid Missile ID' using the disp function.
4. If M_id is valid (1 ≤ M_id ≤ r):
   a. Assign X0 = missile.data(M_id, 2)
   b. Assign Y0 = missile.data(M_id, 3)
   c. Assign Z0 = missile.data(M_id, 4)
   d. Assign m0 = missile.data(M_id, 5)
   e. Assign mf = missile.data(M_id, 6)
   f. Assign Thmag0 = missile.data(M_id, 7)
   g. Assign theta = missile.data(M_id, 8)
   h. Assign phi = missile.data(M_id, 9)
   i. Assign Tburn = missile.data(M_id, 10)
Note: The importdata function called in the code is assumed to be already defined.
function_header: function [ X0, Y0, Z0, m0, mf, Thmag0, theta, phi, Tburn ] = read_input( input_filename, M_id )

end
test_cases: clear;
clc;
rng(42)
[ X0, Y0, Z0, m0, mf, Thmag0, theta, phi, Tburn] = read_input('../test_data/missile_data.txt',1);
all_values = [X0, Y0, Z0, m0, mf, Thmag0, theta, phi, Tburn];
val = sum(all_values);
correct = 130812.680000;
tol = abs(val-correct);
if tol>1e-4
    error('Wrong!')
end
disp('Completely right!')

step_number: 2
step_description_prompt: Please write a MATLAB function named thrust that calculates the thrust components (Th_x, Th_y, Th_z) at a given time t based on the input parameters. The function definition is [Th_x, Th_y, Th_z] = thrust(t, Thmag0, theta, phi, Tburn, u, v, w). 

The algorithm flow is as follows: 
1. If t equals 0, compute Th_x = Thmag0 * cosd(theta) * sind(phi), Th_y = Thmag0 * sind(theta) * sind(phi), Th_z = Thmag0 * cosd(phi). 
2. If t is greater than 0 and less than or equal to Tburn, compute Th_x = Thmag0 * u / sqrt(u^2 + v^2 + w^2), Th_y = Thmag0 * v / sqrt(u^2 + v^2 + w^2), Th_z = Thmag0 * w / sqrt(u^2 + v^2 + w^2). 
3. If t is greater than Tburn, set Th_x = 0, Th_y = 0, Th_z = 0. 
4. For all other cases, display the message 'Error in computing thrust components in thrust' and set Th_x = NaN, Th_y = NaN, Th_z = NaN. 

Assume all functions called in the code are already defined.
function_header: function [Th_x, Th_y, Th_z] = thrust(t, Thmag0, theta, phi, Tburn, u, v, w)

end
test_cases: clear; clc;
rng(42)
t1 = 0;
t2 = 30;
t3 = 50;
Thmag0 = 1000;
theta = 30;
phi = 45;
Tburn = 50;
u = 10; v = 20; w = 30;
u2 = 15; v2 = 40; w2 = 50;
u3 = 20; v3 = 30; w3 = 40;
[Th_x1, Th_y1, Th_z1] = thrust(t1, Thmag0, theta, phi, Tburn, u, v, w);
val = Th_x1 + Th_y1 + Th_z1;
correct = 1673.032607;
tol = abs(val-correct);
if tol>1e-4
    error('Wrong!')
end
[Th_x2, Th_y2, Th_z2] = thrust(t2, Thmag0, theta, phi, Tburn, u2, v2, w2);
val = Th_x2 + Th_y2 + Th_z2;
correct = 1596.600435;
tol = abs(val-correct);
if tol>1e-4
    error('Wrong!')
end
[Th_x3, Th_y3, Th_z3] = thrust(t3, Thmag0, theta, phi, Tburn, u3, v3, w3);
val = Th_x3 + Th_y3 + Th_z3;
correct = 1671.258044;
tol = abs(val-correct);
if tol>1e-4
    error('Wrong!')
end
disp('Completely right!')

step_number: 3
step_description_prompt: Please write a MATLAB function named mass that calculates the mass at a given time based on initial mass, final mass, and burn time. The function definition is: function [m] = mass(t, m0, mf, Tburn). The algorithm flow is as follows: 1. If t is greater than or equal to 0 and less than or equal to Tburn, compute m using the formula m = m0 - ((m0 - mf)/Tburn) * t. 2. If t is greater than Tburn, set m equal to mf. 3. If t is less than 0, display 'Error in computing m in mass' and set m to NaN. Any functions called in the code are assumed to be already defined and do not need to be redefined.
function_header: function [m] = mass(t, m0, mf, Tburn)

end
test_cases: clear; clc;
rng(42)
t1 = 0;
t2 = 30;
t3 = 60;
t4 = 90;
m0 = 1000;
mf = 500;
Tburn = 60;
val = mass(t1, m0, mf, Tburn);
correct = 1000.000000;
tol = abs(val-correct);
if tol>1e-4
    error('Wrong!')
end
val = mass(t2, m0, mf, Tburn);
correct = 750.000000;
tol = abs(val-correct);
if tol>1e-4
    error('Wrong!')
end
val = mass(t3, m0, mf, Tburn);
correct = 500.000000;
tol = abs(val-correct);
if tol>1e-4
    error('Wrong!')
end
disp('Completely right!')

step_number: 4
step_description_prompt: Please write a MATLAB function named drag_coeff that calculates the drag coefficient based on the magnitude of velocity (Vmag). The function has one input parameter Vmag (magnitude of velocity) and one output parameter Cd (drag coefficient). 

First, calculate the Mach number Ma using the formula Ma = Vmag / 340. 

Then, determine the drag coefficient Cd by checking the value of Ma in the following order: 
- If Ma is greater than or equal to 0 and less than 0.9, set Cd = 0.2. 
- Else if Ma is less than 1.1, set Cd = 0.2 + (0.075 / 0.2) * (Ma - 0.9). 
- Else if Ma is less than 3, set Cd = 0.275 - (0.075 / 1.9) * (Ma - 1.1). 
- Else if Ma is greater than 3, set Cd = 0.2. 
- If none of the above conditions are satisfied (i.e., Ma is negative), display the message 'Error: Invalid Vmag to compute drag coefficient' and set Cd = NaN. 

Other functions called in the code are assumed to be pre-defined and do not need to be redefined.
function_header: function [Cd] = drag_coeff(Vmag)

end
test_cases: clear; clc;
rng(42)
V1 = 100;
V2 = 340; 
V3 = 680; 
V4 = 1360;
val = drag_coeff(V1);
correct = 0.200000;
tol = abs(val-correct);
if tol>1e-4
    error('Wrong!')
end
val = drag_coeff(V2);
correct = 0.237500;
tol = abs(val-correct);
if tol>1e-4
    error('Wrong!')
end
val = drag_coeff(V3);
correct = 0.239474;
tol = abs(val-correct);
if tol>1e-4
    error('Wrong!')
end
disp('Completely right!')

step_number: 5
step_description_prompt: Please write a MATLAB function named missile that simulates the trajectory of a missile until it impacts the terrain, returning time history and state variables including time, positions (X,Y,Z), and velocities (U,V,W). The function should strictly follow the following specifications:

1. Function Definition: Use the exact function signature as:
   function [Tval,Xval,Yval,Zval,Uval,Vval,Wval] = missile(X0,Y0,Z0,m0,mf,Thmag0,theta,phi,Tburn)

2. Global Variables: Declare global variables `ro`, `A`, and `g`. Initialize them with fixed values:
   global ro
   global A
   global g
   dt = 0.005;
   g = 9.81;
   ro = 1.2;
   A = pi*(0.2)^2;

3. Load Terrain Data: Load the terrain data file from the path '../test_data/terrain.mat', which contains the grid variables `x_terrain`, `y_terrain`, and terrain height `h_terrain`.

4. Initialization:
   - Set initial velocity magnitude `Vmag = 0`
   - Initialize time `t = 0`
   - Create time array `T` with `T(1) = t`
   - Initialize velocity arrays `U`, `V`, `W` with `U(1) = 0`, `V(1) = 0`, `W(1) = 0`
   - Initialize position arrays `X`, `Y`, `Z` with `X(1) = X0`, `Y(1) = Y0`, `Z(1) = Z0`
   - Set loop index `n = 1`
   - Compute initial terrain height at the starting position using 2D interpolation: `h = interp2(x_terrain, y_terrain, h_terrain, X(1), Y(1))`

5. Simulation Loop: Run the loop while the missile's current height `Z(n)` is greater than or equal to the terrain height `h`. Inside the loop:
   a. Calculate thrust components by calling the helper function: `[Thx, Thy, Thz] = thrust(t, Thmag0, theta, phi, Tburn, U(n), V(n), W(n))`
   b. Update velocity magnitude `Vmag` as the Euclidean norm of current velocity: `Vmag = (U(n)^2 + V(n)^2 + W(n)^2)^(1/2)`
   c. Calculate thrust magnitude (unused but retained for consistency): `Thmag = (Thx^2 + Thy^2 + Thz^2)^(1/2)`
   d. Get current missile mass by calling: `m = mass(t, m0, mf, Tburn)`
   e. Get drag coefficient by calling: `Cd = drag_coeff(Vmag)`
   f. Compute next-time-step velocities using force-balance equations (include thrust, drag, and gravity for vertical component):
      - `U(n+1) = U(n) + (Thx/m - (Cd*ro*A/(2*m))*(U(n)*(U(n)^2 + V(n)^2 + W(n)^2)^(1/2)))*dt`
      - `V(n+1) = V(n) + (Thy/m - (Cd*ro*A/(2*m)*(V(n)*(U(n)^2 + V(n)^2 + W(n)^2)^(1/2))))*dt`
      - `W(n+1) = W(n) + (Thz/m - (Cd*ro*A/(2*m))*(W(n)*(U(n)^2 + V(n)^2 + W(n)^2)^(1/2)) - g)*dt`
   g. Compute next-time-step positions using the updated velocities (note: uses next velocity, not current):
      - `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`
   h. Update terrain height for the new position: `h = interp2(x_terrain, y_terrain, h_terrain, X(end), Y(end))`
   i. Increment time and store in the time array: `t = t + dt`; `T(n+1) = t`
   j. Increment loop index: `n = n + 1`

6. Output Assignment: Assign the time and state arrays to the output variables:
   - `Tval = T`
   - `Xval = X`
   - `Yval = Y`
   - `Zval = Z`
   - `Uval = U`
   - `Vval = V`
   - `Wval = W`

7. Dependencies: Assume the helper functions `thrust`, `mass`, and `drag_coeff` are pre-defined (as in the original code) and the terrain data file exists at the specified path. All calculations must use the exact arithmetic and order of operations from the original code to ensure result consistency.
function_header: function [ Tval,Xval,Yval,Zval,Uval,Vval,Wval] = missile( X0,Y0,Z0,m0,mf,Thmag0,theta,phi,Tburn)

end
test_cases: clear; clc;
clear global;
rng(42);
global ro
global A
global g
x_terrain = linspace(-500, 500, 51);
y_terrain = linspace(-500, 500, 51);
[X_terrain, Y_terrain] = meshgrid(x_terrain, y_terrain);
h_terrain = zeros(size(X_terrain)); 
X0=0; Y0=0; Z0=50;
m0=1000; mf=500; Thmag0=15000;
theta=0; phi=90; Tburn=2;
[T, X, Y, Z, U, V, W] = missile(X0, Y0, Z0, m0, mf, Thmag0, theta, phi, Tburn);
val = T(end) + X(end) + Y(end) + Z(end) + U(end) + V(end) + W(end);
correct = -42.964099;
tol = abs(val-correct);
if tol>1e-4
    error('Wrong!')
end

X1=0; Y1=0; Z1=10;
m1=500; mf=100; Thmag1=20000;
theta=0; phi=90; Tburn=1;
[T, X, Y, Z, U, V, W] = missile(X1, Y1, Z1, m1, mf, Thmag0, theta, phi, Tburn);
val = T(end) + X(end) + Y(end) + Z(end) + U(end) + V(end) + W(end);
correct = -12.075449;
tol = abs(val-correct);
if tol>1e-4
    error('Wrong!')
end

X2=10; Y2=20; Z2=30;
m2=2000; mf=1800; Thmag2=5000;
theta=45; phi=180; Tburn=10;
[T, X, Y, Z, U, V, W] = missile(X2, Y2, Z2, m2, mf, Thmag0, theta, phi, Tburn);
val = T(end) + X(end) + Y(end) + Z(end) + U(end) + V(end) + W(end);
correct = -0.564919;
tol = abs(val-correct);
if tol>1e-4
    error('Wrong!')
end
disp('Completely right!')

step_number: 6
step_description_prompt: Please use MATLAB code to create a function named missile_trajectory_analysis that implements missile trajectory simulation, visualization, statistical analysis, and video generation based on input data from files.

function flight_stat = missile_trajectory_analysis()
    % Initialize environment
    clear all; close all; clc; format long;
    rng(42);

    % Initialize input arrays for 7 missiles
    X0 = zeros(1,7); Y0 = zeros(1,7); Z0 = zeros(1,7);
    m0 = zeros(1,7); mf = zeros(1,7); Thmag0 = zeros(1,7);
    theta = zeros(1,7); phi = zeros(1,7); Tburn = zeros(1,7);

    % Read input data for each missile
    for n = 1:7
        [X0(n), Y0(n), Z0(n), m0(n), mf(n), Thmag0(n), theta(n), phi(n), Tburn(n)] = read_input('../test_data/missile_data.txt', n);
    end

    % Initialize result cell arrays
    Tval = cell(1,7); Xval = cell(1,7); Yval = cell(1,7); Zval = cell(1,7);
    Uvel = cell(1,7); Vvel = cell(1,7); Wvel = cell(1,7);

    % Simulate trajectories using missile function
    for m = 1:7
        [Tval{m}, Xval{m}, Yval{m}, Zval{m}, Uvel{m}, Vvel{m}, Wvel{m}] = missile(X0(m), Y0(m), Z0(m), m0(m), mf(m), Thmag0(m), theta(m), phi(m), Tburn(m));
    end

    % Load terrain data
    load('../test_data/terrain.mat');

    % Plot trajectories and landing locations (Figure 1)
    figure(1); hold on;
    surf(x_terrain/1000, y_terrain/1000, h_terrain/1000);
    shading interp;
    color = {'-r', '-k', '-c', '-y', '-g', '-b', '-m'};
    color1 = {'ro', 'ko', 'co', 'yo', 'go', 'bo', 'mo'};
    color2 = {'r', 'k', 'c', 'y', 'g', 'b', 'm'};

    % Plot trajectories
    for g = 1:7
        plot3(Xval{g}/1000, Yval{g}/1000, Zval{g}/1000, color{g});
    end

    % Add legend
    h_legend = legend('terrain', 'M.1', 'M.2', 'M.3', 'M.4', 'M.5', 'M.6', 'M.7');
    set(h_legend, 'FontSize', 10);

    % Plot landing positions
    for k = 1:7
        plot3(Xval{k}(end)/1000, Yval{k}(end)/1000, Zval{k}(end)/1000, color1{k}, ...
            'MarkerSize', 10, 'MarkerFaceColor', color2{k}, 'MarkerEdgeColor', color2{k});
    end

    % Set axes properties
    hold off;
    xlabel('x (km)'); ylabel('y (km)'); zlabel('z (km)');
    view(3); axis([0 30 0 30 0 3.5]); grid on;
    set(gca, 'LineWidth', 2, 'FontSize', 16, ...
        'Xtick', [0:5:30], 'Ytick', [0:5:30], 'Ztick', [0:.5:3.5]);
    title('Trajectories and Landing Locations');

    % Plot speed (Mach) and acceleration (g) over time (Figure 2)
    figure(2);
    % Plot Mach number
    for c = 1:7
        subplot(2,1,1); hold on;
        plot(Tval{c}, sqrt(Uvel{c}.^2 + Vvel{c}.^2 + Wvel{c}.^2)/340, color2{c});
    end
    title('Evolution of speed and accleration');
    ylabel('Ma');

    % Compute acceleration
    Accvec = cell(1,7); magV = cell(1,7);
    for h = 1:7
        len1 = numel(Uvel{h});
        Vmagvec = sqrt(Uvel{h}.^2 + Vvel{h}.^2 + Wvel{h}.^2);
        Vmagpart = zeros(1, len1-1);
        for f = 2:len1
            Vmagpart(f-1) = Vmagvec(f) - Vmagvec(f-1);
        end
        Accvec{h} = Vmagpart / 0.005;
        magV{h} = Vmagvec;
    end

    % Plot acceleration
    for r = 1:7
        subplot(2,1,2); hold on;
        plot(Tval{r}(2:end), Accvec{r}/9.81, color2{r});
    end
    h_legend = legend('M.1', 'M.2', 'M.3', 'M.4', 'M.5', 'M.6', 'M.7');
    set(h_legend, 'FontSize', 10);
    xlabel('Time(s)');
    ylabel('Acc/g');
    hold off;

    % Plot Mach number vs altitude (Figure 3)
    figure(3); hold on;
    Mach = cell(1,7);
    for y = 1:7
        Mach{y} = magV{y} / 340;
    end

    % Plot Mach vs altitude
    for q = 1:7
        plot(Mach{q}, Zval{q}/1000, color2{q});
    end
    xlim([0 9]);
    title('Sonic Barrier');
    xlabel('Ma');
    ylabel('Altitude (km)');
    h_legend = legend('M.1', 'M.2', 'M.3', 'M.4', 'M.5', 'M.6', 'M.7');
    set(h_legend, 'FontSize', 10);

    % Mark transonic points (crossing Mach 1)
    color3 = {'r*', 'k*', 'c*', 'y*', 'g*', 'b*', 'm*'};
    for e = 1:7
        len_mag = numel(magV{e});
        for n = 2:len_mag-1
            if (Mach{e}(n) > 1 && Mach{e}(n+1) < 1) || (Mach{e}(n) > 1 && Mach{e}(n-1) < 1)
                plot(Mach{e}(n), Zval{e}(n)/1000, color3{e});
            end
        end
    end
    hold off;

    % Calculate flight statistics
    landTimes = zeros(1,7); land_loc = cell(1,7); lanMa = zeros(1,7); lanAcc = zeros(1,7);
    distance = cell(1,7); max_heightpos = cell(1,7); max_Ma = cell(1,7); maxhAcc = cell(1,7);

    for u = 1:7
        % Landing parameters
        landTimes(u) = Tval{u}(end);
        land_loc{u} = [Xval{u}(end), Yval{u}(end), Zval{u}(end)];
        lanMa(u) = Mach{u}(end);
        lanAcc(u) = Accvec{u}(end);

        % Total travel distance
        delX = diff(Xval{u}); delY = diff(Yval{u}); delZ = diff(Zval{u});
        distance{u} = sum(sqrt(delX.^2 + delY.^2 + delZ.^2));

        % Max height parameters
        [Zmaxval, indmaxval] = max(Zval{u});
        max_heightpos{u} = [Xval{u}(indmaxval), Yval{u}(indmaxval), Zmaxval];
        max_Ma{u} = Mach{u}(indmaxval);
        maxhAcc{u} = Accvec{u}(indmaxval-1); % Accvec is 1 shorter than Zval
    end

    % Create flight_stat structure to store statistics
    flight_stat = struct(...
        'missile_ID', {}, ...
        'landing_time', {}, ...
        'travel_distance', {}, ...
        'max_height_position', {}, ...
        'max_height_Ma', {}, ...
        'max_height_Acc', {}, ...
        'landing_location', {}, ...
        'landing_Ma', {}, ...
        'landing_Acc', {} ...
    );

    for o = 1:7
        flight_stat(o).missile_ID = o;
        flight_stat(o).landing_time = landTimes(o);
        flight_stat(o).travel_distance = distance{o};
        flight_stat(o).max_height_position = max_heightpos{o};
        flight_stat(o).max_height_Ma = max_Ma{o};
        flight_stat(o).max_height_Acc = maxhAcc{o};
        flight_stat(o).landing_location = land_loc{o};
        flight_stat(o).landing_Ma = lanMa(o);
        flight_stat(o).landing_Acc = lanAcc(o);
    end

    % Write flight statistics to report file
    fileID = fopen('../test_data/report.txt', 'w');
    fprintf(fileID, '%s\n%s\n%s\n', ...
        'Marcus Manahan', 'A10980948', ...
        'M_ID, landing time (s), travel distance (m), landing speed (m/s), landing acceleration (m/s^2)');
    for b = 1:7
        fprintf(fileID, '%d %15.9e %15.9e %15.9e %15.9e\n', ...
            flight_stat(b).missile_ID, ...
            flight_stat(b).landing_time, ...
            flight_stat(b).travel_distance, ...
            magV{b}(end), ...
            flight_stat(b).landing_Acc);
    end
    fclose(fileID);

    % Prepare data for video (extend all trajectories to the same length)
    max_length = 0;
    for n = 1:7
        current_len = numel(Tval{n});
        if current_len > max_length
            max_length = current_len;
        end
    end
    max_length = max_length + 50; % Extend by 50 points

    % Extend each trajectory array to max_length
    for n = 1:7
        Tval{n}(end+1:max_length) = Tval{n}(end);
        Uvel{n}(end+1:max_length) = Uvel{n}(end);
        Vvel{n}(end+1:max_length) = Vvel{n}(end);
        Wvel{n}(end+1:max_length) = Wvel{n}(end);
        Xval{n}(end+1:max_length) = Xval{n}(end);
        Yval{n}(end+1:max_length) = Yval{n}(end);
        Zval{n}(end+1:max_length) = Zval{n}(end);
    end

    % Generate trajectory video
    vidObj = VideoWriter('missile_validation.avi');
    vidObj.Quality = 100;
    vidObj.FrameRate = 10;
    open(vidObj);

    % Set video figure properties
    fig = figure('Position', [100 100 1000 600], 'Visible', 'on');
    step = 50; fsize = 16; cs = 'krbgmcy'; % Color sequence

    for k = 1:step:max_length
        % Clear previous plot
        clf(fig); hold on;

        % Plot terrain
        surf(x_terrain/1000, y_terrain/1000, h_terrain/1000);
        shading interp; colormap('summer'); caxis([0 1.5]);
        grid on; box on;

        % Plot trajectories and current positions for each missile
        for id = 1:7
            % Plot trajectory up to current step k
            plot3(Xval{id}(1:k)/1e3, Yval{id}(1:k)/1e3, Zval{id}(1:k)/1e3, cs(id), 'LineWidth', 2);
            % Plot current position marker
            plot3(Xval{id}(k)/1e3, Yval{id}(k)/1e3, Zval{id}(k)/1e3, [cs(id) 'o'], ...
                'MarkerSize', 10, 'MarkerFaceColor', cs(id), 'MarkerEdgeColor', cs(id));
        end

        % Set axes limits and properties
        axis([0 30 0 30 0 3.5]);
        set(gca, 'LineWidth', 2, 'FontSize', fsize, ...
            'Xtick', [0:5:30], 'Ytick', [0:5:30], 'Ztick', [0:.5:3]);
        set(gca, 'Position', [0.07 0.07 0.88 0.6]); % Adjust axes position for text

        % Add time text
        time_str = sprintf('Time: %05.3f s', Tval{1}(k));
        text(-25, 0, 10, time_str, 'FontSize', fsize, 'Color', 'k');

        % Add status table header
        header_str = sprintf('%2s %12s %18s %18s %16s %16s %16s %20s', ...
            'ID', 'X', 'Y', 'Z', 'U', 'V', 'W', 'status');
        text(-13, 0, 9.5, header_str, 'FontSize', fsize, 'Color', 'k');

        % Add status for each missile
        for id = 1:7
            % Determine missile status (in-flight or landed)
            if k >= 2
                if Tval{id}(k) == Tval{id}(k-1)
                    status = 'landed';
                else
                    status = 'in-flight';
                end
            else
                status = 'in-flight';
            end
            % Force "landed" for the last few frames
            if k >= max_length - step
                status = 'landed';
            end

            % Format data string for current missile
            data_str = sprintf('%2d    %09.6f    %09.6f    %08.6f   %08.6f   %09.6f    %09.6f      %s', ...
                id, ...
                Xval{id}(k)/1e3, Yval{id}(k)/1e3, Zval{id}(k)/1e3, ...
                Uvel{id}(k)/1e3, Vvel{id}(k)/1e3, Wvel{id}(k)/1e3, ...
                status);
            % Position text vertically for each missile
            text(-13, 0, 9.5 - 0.35*id, data_str, 'FontSize', 16, 'Color', cs(id));
        end

        % Add unit note
        text(13, 0, 5.6, '(position in km, velocity in km/s)', 'FontSize', fsize-2);

        % Set labels and title
        xlabel('x (km)', 'Position', [10, -7, 0]);
        ylabel('y (km)', 'Position', [-7, 10, 0]);
        zlabel('z (km)');
        title('Missile Trajectories', 'Position', [7, 5, 8.75]);
        view(3);

        % Capture frame and write to video
        currFrame = getframe(fig);
        writeVideo(vidObj, currFrame);

        hold off;
    end

    % Close video writer
    close(vidObj);
end
ground_truth_code: clear all; close all; clc; format long;
rng(42)
X0 = zeros(1,7);
Y0= zeros(1,7);
Z0= zeros(1,7);
m0= zeros(1,7);
mf= zeros(1,7);
Thmag0= zeros(1,7);
theta= zeros(1,7);
phi= zeros(1,7);
Tburn= zeros(1,7);
 for n = 1:7

     [ X0(n), Y0(n), Z0(n), m0(n), mf(n), Thmag0(n), theta(n), phi(n), Tburn(n) ] = read_input('../test_data/missile_data.txt',n);
 end
    Tval = cell(1,7);
    Xval = cell(1,7);
    Yval = cell(1,7);
    Zval = cell(1,7);
    Uvel = cell(1,7);
    Vvel = cell(1,7);
    Wvel = cell(1,7);
 for m = 1:7
 [ Tval{m},Xval{m},Yval{m},Zval{m},Uvel{m},Vvel{m},Wvel{m}] = missile(X0(m),Y0(m),Z0(m),m0(m),mf(m),Thmag0(m),theta(m),phi(m),Tburn(m));
 end

load('../test_data/terrain.mat');
figure(1); hold on;
surf(x_terrain/1000, y_terrain/1000, h_terrain/1000);
shading interp;
color = {'-r', '-k', '-c', '-y', '-g', '-b', '-m'};
color1 = {'ro', 'ko', 'co', 'yo', 'go', 'bo', 'mo'};
color2 = {'r', 'k', 'c', 'y', 'g', 'b', 'm'};
color3 = {'r*', 'k*', 'c*', 'y*', 'g*', 'b*', 'm*'};
for g = 1:7
    plot3(Xval{g}./1000,Yval{g}./1000,Zval{g}./1000,color{g});
end
h_legend = legend('terrain','M.1','M.2','M.3','M.4','M.5','M.6','M.7');
set(h_legend,'FontSize',10);
for k = 1:7
    plot3(Xval{k}(end)/1000, Yval{k}(end)/1000, Zval{k}(end)/1000,color1{k}, ...
        'MarkerSize', 10, 'MarkerFaceColor', color2{k}, 'MarkerEdgeColor', color2{k});
end
hold off;
xlabel('x (km)'); ylabel('y (km)'); zlabel('z (km)');
view(3); axis([0 30 0 30 0 3.5]); grid on;
set(gca,'LineWidth',2,'FontSize',16, ...
        'Xtick',[0:5:30],'Ytick',[0:5:30],'Ztick',[0:.5:3.5]);
title('Trajectories and Landing Locations')

 figure(2);
for c = 1:7
    subplot(2,1,1);
    hold on;
    plot(Tval{c},(((Uvel{c}(1:end).^2+Vvel{c}(1:end).^2+Wvel{c}(1:end).^2)).^(1/2))./340,color2{c});
end
title('Evolution of speed and accleration');
ylabel('Ma');
Accvec = cell(1,7);
magV = cell(1,7);
for h =1:7
len1 = numel(Uvel{h});
Vmagpart = zeros(1,len1-1);
Vmagvec = (Uvel{h}(1:end).^2+Vvel{h}(1:end).^2+Wvel{h}(1:end).^2).^(1/2);
    for f = 2:len1
        Vmagpart(f-1) = Vmagvec(f) - Vmagvec(f-1);
    end
    Accvec{h} = Vmagpart./(.005);
    magV{h} = Vmagvec;
end
 for r = 1:7
 subplot(2,1,2);
 hold on;
 plot(Tval{r}(2:end),Accvec{r}(1:end)./9.81,color2{r});
 end
 h_legend = legend('M.1','M.2','M.3','M.4','M.5','M.6','M.7');
set(h_legend,'FontSize',10);
xlabel('Time(s)');
ylabel('Acc/g');
hold off;
figure(3); hold on;
Mach = cell(1,7);
for y = 1:7
    Mach{y} = magV{y}./340;
end
for q = 1:7
    plot(Mach{q},Zval{q}./1000,color2{q});
end
xlim([0 9]);
title('Sonic Barrier');
xlabel('Ma');
ylabel('Altitude (km)');
h_legend = legend('M.1','M.2','M.3','M.4','M.5','M.6','M.7');
set(h_legend,'FontSize',10);

for e = 1:7
    len1 = numel(magV{e});
    for n = 2:len1-1
        if ((Mach{e}(n) > 1)&& (Mach{e}(n+1)<1)) || (Mach{e}(n)>1 && Mach{e}(n-1)<1)
            plot(Mach{e}(n),Zval{e}(n)/1000,color3{e});
        end
    end
end
hold off;
landTimes = zeros(1,7);
land_loc = cell(1,7);
lanMa = zeros(1,7);
lanAcc = zeros(1,7);
distance = cell(1,7);
max_heightpos = cell(1,7);
max_Ma = cell(1,7);
maxhAcc = cell(1,7);
for u = 1:7
    landTimes(u) = Tval{u}(end);
    land_loc{u} = [Xval{u}(end) Yval{u}(end) Zval{u}(end)];
    lanMa(u) = Mach{u}(end);
    lanAcc(u) = Accvec{u}(end);
     delX = diff(Xval{u});
     delY = diff(Yval{u});
     delZ = diff(Zval{u});
   distance{u} = sum((delX.^2+delY.^2+delZ.^2).^(1/2));
   [Zmaxval,indmaxval] = max(Zval{u});
    Ymaxval = Yval{u}(indmaxval);
    Xmaxval = Xval{u}(indmaxval);
    max_heightpos{u} = [Xmaxval Ymaxval Zmaxval];
    max_Ma{u} = Mach{u}(indmaxval);
    maxhAcc{u} = Accvec{u}(indmaxval-1);
end
    flight_stat = struct('missile_ID',{},'landing_time',{},'travel_distance',{},'max_height_position',{},'max_height_Ma',{},...
        'max_height_Acc',{},'landing_location',{},'landing_Ma',{},'landing_Acc',{});
    for o = 1:7
        flight_stat(o).missile_ID = o;
        flight_stat(o).landing_time = landTimes(o);
        flight_stat(o).travel_distance = distance{o};
        flight_stat(o).max_height_position =  max_heightpos{o};
        flight_stat(o).max_height_Ma = max_Ma{o};
        flight_stat(o).max_height_Acc = maxhAcc{o};
        flight_stat(o).landing_location = land_loc{o};
        flight_stat(o).landing_Ma = lanMa(o);
        flight_stat(o).landing_Acc = lanAcc(o);
    end
fileID = fopen('../test_data/report.txt','w');
fprintf(fileID,'%s\n%s\n%s\n','Marcus Manahan','A10980948','M_ID, landing time (s), travel distance (m), landing speed (m/s), landing acceleration (m/s^2)');
for b = 1:7
    fprintf(fileID,'%d %15.9e %15.9e %15.9e %15.9e\n', flight_stat(b).missile_ID, flight_stat(b).landing_time, flight_stat(b).travel_distance, magV{b}(end), flight_stat(b).landing_Acc);
end
fclose(fileID);
    p1a = 'See figure 1';
    p1b = 'See figure 2';
    p1c = 'See figure 3';
    p2a = flight_stat(1);
    p2b = flight_stat(2);
    p2c = flight_stat(3);
    p2d = flight_stat(4);
    p2e = flight_stat(5);
    p2f = flight_stat(6);
    p2g = flight_stat(7);
    p3 = evalc('type ../test_data/report.txt');

load('../test_data/terrain.mat');

    max_length = 0;
i=numel(Tval);
for n = 1:i
    if max_length < numel(Tval{n})
        max_length = numel(Tval{n});
    end
end

max_length = max_length+50;
for n = 1:i
    Tval{n}(end+1:max_length) = Tval{n}(end);
    Uvel{n}(end+1:max_length) = Uvel{n}(end);
    Vvel{n}(end+1:max_length) = Vvel{n}(end);
    Wvel{n}(end+1:max_length) = Wvel{n}(end);
    Xval{n}(end+1:max_length) = Xval{n}(end);
    Yval{n}(end+1:max_length) = Yval{n}(end);
    Zval{n}(end+1:max_length) = Zval{n}(end);
end

vidObj = VideoWriter('missile_validation.avi');
vidObj.Quality = 100;
vidObj.FrameRate = 10;
open(vidObj);
figure('position',[100 100 1000 600],'visible','on');

step = 50;
fsize = 16;
cs = 'krbgmcy';

for k = 1:step:max_length
    for id=1:7
        s =surf(x_terrain/1000, y_terrain/1000, h_terrain/1000);
        hold on;
        gh1{id} = plot3(Xval{id}(1:k)/1e3,Yval{id}(1:k)/1e3,Zval{id}(1:k)/1e3,cs(id));
        plot3(Xval{id}(k)/1e3,Yval{id}(k)/1e3,Zval{id}(k)/1e3,[cs(id) 'o'], ...
               'MarkerFacecolor',cs(id),'MarkerEdgecolor',cs(id), ...
               'MarkerSize',10);
        grid on; box on; colormap('summer'); caxis([0 1.5]);
        axis([0 30 0 30 0 3.5]);
        set(gca,'LineWidth',2,'FontSize',fsize, ...
           'Xtick',[0:5:30],'Ytick',[-0:5:30],'Ztick',[0:.5:3]);
        set(gca,'Position',[0.07 0.07 0.88 0.6]);

        time_string = sprintf('Time: %05.3f s', Tval{1}(k));
        text(-25,0,10,time_string,'Fontsize',fsize,'Color','k');
        header_text = sprintf('%2s %12s %18s %18s %16s %16s %16s %20s',...
                          'ID','X','Y','Z','U','V','W','status');
        text(-13,0,9.5,header_text,'Fontsize',fsize,'Color','k');
        if k >= 2
            if (Tval{id}(k) == Tval{id}(k-1))
                status_string = 'landed';
            else
                status_string = 'in-flight';
            end
        else
            status_string = 'in-flight';
        end

        if k >= max_length-step; status_string = 'landed'; end;

        data_string = sprintf('%2d    %09.6f    %09.6f    %08.6f   %08.6f   %09.6f    %09.6f      %s', ...
                           id,Xval{id}(k)/1e3,Yval{id}(k)/1e3,Zval{id}(k)/1e3,...
                               Uvel{id}(k)/1e3,Vvel{id}(k)/1e3,Wvel{id}(k)/1e3,status_string);
        text(-13,0,9.5-0.35*id,data_string,'Fontsize',16,'Color',cs(id));
        text(13,0,5.6,'(position in km, velocity in km/s)', ...
                        'FontSize',fsize-2);
        set(gh1{id},'LineWidth',2);
    end
    xlabel('x (km)','Position',[10,-7,0]);
    ylabel('y (km)','Position',[-7,10,0]);
    zlabel('z (km)'); view(3);
    title('Missile Trajectories','Position',[7,5,8.75]);

    currFrame = getframe(gcf);
    writeVideo(vidObj,currFrame);
    hold off;
end

close(vidObj);

General solution:

General tests: