From 620ea3d88929a14cf5c5d42f9b40bc3ecf2609f8 Mon Sep 17 00:00:00 2001
From: Mauco03 <marco.gaibotti@skywarder.eu>
Date: Wed, 8 Jan 2025 12:15:39 +0100
Subject: [PATCH] [handle-value-conversion] Adding value classes

---
 classes/@Rocket/Rocket.m                      | 226 +++++++
 classes/@Rocket/checkGeometry.m               |  83 +++
 classes/@Rocket/interpCoeffs.m                |  63 ++
 classes/@Rocket/loadData.m                    |  40 ++
 classes/@Rocket/plot.m                        | 116 ++++
 classes/@Rocket/update.m                      |  45 ++
 classes/@Rocket/updateBay.m                   |  18 +
 classes/@Rocket/updateNoMotor.m               |  39 ++
 classes/@Rocket/updateOverridable.m           |  10 +
 classes/Bay.m                                 |  27 +-
 classes/Component.m                           | 121 ----
 classes/Config.m                              | 136 +++--
 classes/{components => }/Environment.m        |   0
 classes/Mission.m                             |  61 +-
 classes/Rocket.m                              | 558 ------------------
 classes/bays/@Motor/Motor.m                   | 137 +++++
 classes/bays/@Motor/loadData.m                |  50 ++
 classes/bays/@Motor/validateTimeDependent.m   |  14 +
 classes/bays/Airbrakes.m                      |  61 +-
 classes/bays/Electronics.m                    |  24 +-
 classes/bays/Motor.m                          | 135 -----
 classes/bays/MotorType.m                      |   8 +
 classes/bays/Parafoil.m                       |  34 +-
 classes/bays/Rear.m                           |  26 +-
 classes/bays/Recovery.m                       |  22 +-
 .../{components/Para.m => misc/ParaLoader.m}  |  36 +-
 classes/{components => misc}/Parachute.m      |  14 +-
 classes/{components => misc}/Pitot.m          |  14 +-
 classes/{components => misc}/WindCustom.m     |   0
 classes/{components => misc}/WindMatlab.m     |   0
 classes/{components => misc}/Wing.m           |  33 +-
 functions/miscellaneous/camel2UpperSnake.m    |   6 +
 .../config/rocketConfig.m                     |  24 +-
 33 files changed, 1102 insertions(+), 1079 deletions(-)
 create mode 100644 classes/@Rocket/Rocket.m
 create mode 100644 classes/@Rocket/checkGeometry.m
 create mode 100644 classes/@Rocket/interpCoeffs.m
 create mode 100644 classes/@Rocket/loadData.m
 create mode 100644 classes/@Rocket/plot.m
 create mode 100644 classes/@Rocket/update.m
 create mode 100644 classes/@Rocket/updateBay.m
 create mode 100644 classes/@Rocket/updateNoMotor.m
 create mode 100644 classes/@Rocket/updateOverridable.m
 delete mode 100644 classes/Component.m
 rename classes/{components => }/Environment.m (100%)
 delete mode 100644 classes/Rocket.m
 create mode 100644 classes/bays/@Motor/Motor.m
 create mode 100644 classes/bays/@Motor/loadData.m
 create mode 100644 classes/bays/@Motor/validateTimeDependent.m
 delete mode 100644 classes/bays/Motor.m
 create mode 100644 classes/bays/MotorType.m
 rename classes/{components/Para.m => misc/ParaLoader.m} (51%)
 rename classes/{components => misc}/Parachute.m (85%)
 rename classes/{components => misc}/Pitot.m (81%)
 rename classes/{components => misc}/WindCustom.m (100%)
 rename classes/{components => misc}/WindMatlab.m (100%)
 rename classes/{components => misc}/Wing.m (85%)
 create mode 100644 functions/miscellaneous/camel2UpperSnake.m

diff --git a/classes/@Rocket/Rocket.m b/classes/@Rocket/Rocket.m
new file mode 100644
index 0000000..61d7be1
--- /dev/null
+++ b/classes/@Rocket/Rocket.m
@@ -0,0 +1,226 @@
+classdef Rocket < Config
+    % Rocket: Contains and manages all bays
+    %
+    %   Constructor:
+    %       - Rocket: Creates an instance of the Rocket class.
+    %           Loaded config: rocketConfig.m > rocket (for overrides)
+    %           Loaded data: -
+    %           Arguments:
+    %               - mission: Mission, mission object
+    %               - varIn: (optional) config source. Alternative to config.m
+    %               file
+    
+    %% Derived properties
+    properties(SetAccess = private)
+        time                        double          % [s]       Timestamps vector
+        cutoffTime          (1, 1)  double          % [s]       Shutdown time
+        cutoffMass          (1, 1)  double          % [m]       Total mass at motor cutoff
+        cutoffInertia       (3, 1)  double          % [kg*m^2]  Total inertia at motor cutoff
+        inertiaDot          (3, :)  double          % [kg*m^2/s]Total inertia time derivative
+
+        stagesMass                  double          % [kg]      Mass of stage 2, 3, .. without chutes
+        crossSection        (1, 1)  double          % [m^2]     Rocket cross sectional area
+    end
+
+    properties(Dependent)
+        %% BAYS
+        parafoil                    Parafoil        % [-]       Parafoil bay
+        recovery                    Recovery        % [-]       Recovery bay
+        electronics                 Electronics     % [-]       Electronics bay
+        airbrakes                   Airbrakes       % [-]       Airbrakes bay
+        motor                       Motor           % [-]       Motor bay
+        rear                        Rear            % [-]       Rear bay
+
+        %% GEOMETRY
+        length              (1, 1)  double          % [m]       Total length
+        lengthCenter        (1, 1)  double          % [m]       Center length - no nose, boat
+        lengthCenterNoMotor (1, 1)  double          % [m]       Center length - no nose, boat, motor
+        diameter            (1, 1)  double          % [m]       Diameter
+
+        %% MASS PROPERTIES
+        mass                (1, :)  double          % [kg]      Total mass
+        massNoMotor         (1, 1)  double          % [kg]      Mass without motor
+        inertia             (3, :)  double          % [kg*m^2]  Total inertia - Axibody reference
+        inertiaNoMotor      (3, 1)  double          % [kg*m^2]  Inertia without motor
+        xcg                 (1, :)  double          % [m]       Total xCg
+        xcgNoMotor          (1, 1)  double          % [m]       xCg without motor
+    end
+
+    properties        
+        pitot                       Pitot           % [-]       Pitot component
+        parachutes                  cell            % [-]       (nParachutes, nStages) Parachutes onboard
+        
+        coefficients                struct          % [-]       Aerodynamic coefficients
+    end
+
+    properties(Access = private)
+        bays                        string          % [-]       Ordered list of bay names
+        baysNoMotor                 string          % [-]       Ordered list of bay names, without motor
+        bayStatus                   dictionary      % [-]       Dictionary containing initialisation flag for bays
+        overrides                   dictionary      % [-]       Dictionary containing overrides
+        mission                     Mission
+    end
+
+    %% Cached properties
+    properties(Access = private)
+        PARAFOIL
+        RECOVERY
+        ELECTRONICS
+        AIRBRAKES
+        MOTOR
+        REAR
+
+        LENGTH
+        LENGTH_CENTER
+        LENGTH_CENTER_NO_MOTOR
+        DIAMETER
+        
+        MASS
+        MASS_NO_MOTOR
+
+        INERTIA
+        INERTIA_NO_MOTOR
+
+        XCG
+        XCG_NO_MOTOR
+    end
+
+    %% Config implementation
+    properties(Constant, Hidden, Access = protected)
+        configName = 'rocketConfig.m'
+        variableName = ''
+    end
+    
+    methods
+        function obj = Rocket(mission, varsIn, options)
+            arguments
+                mission                     Mission = Mission()
+                varsIn                      struct  = []
+                options.loadCoefficients    logical = true
+                options.checkGeometry       logical = true
+            end
+            obj@Config(mission, varsIn);
+            if isempty(mission.name), return; end
+            
+            %% Initialize base properties
+            bayNames = camel2UpperSnake(obj.getProperties(Superclass='Bay'));
+            bayStatus = cellstr(bayNames);
+            [bayStatus{2, :}] = deal(false);
+            obj.bayStatus = dictionary(bayStatus{:});
+            obj.bays = bayNames;
+            obj.baysNoMotor = setdiff(bayNames, "MOTOR", 'stable');
+
+            % Remove bays from overridables, as they do not require override
+            overridables = camel2UpperSnake( ...
+                obj.getProperties('Dependent', true, 'SetAccess', 'public'));
+            overridables = cellstr(setdiff(overridables, bayNames));
+            [overridables{2, :}] = deal(false);
+            obj.overrides = dictionary(overridables{:});
+
+            %% Loading data
+            if isempty(varsIn)
+                varsIn = obj.getConfig(mission.configPath);
+            end
+            
+            obj.parafoil     = Parafoil(mission, varsIn);
+            obj.recovery     = Recovery(mission, varsIn);
+            obj.electronics  = Electronics(mission, varsIn);
+            obj.motor        = Motor(mission, varsIn);
+            obj.airbrakes    = Airbrakes(mission, varsIn);
+            obj.rear         = Rear(mission, varsIn);
+
+            obj.pitot        = Pitot(mission, varsIn);
+            paraLoader       = ParaLoader(mission);
+            obj.parachutes   = paraLoader.parachutes;
+            
+            if options.loadCoefficients
+                obj.loadData();
+                answer = '';
+                if isempty(obj.coefficients) || isempty(obj.coefficientsHighAOA)
+                    answer = questdlg(['Coefficient matrices not found. ' ...
+                        'Do you want to create new matrices?']);
+                elseif options.checkGeometry && ~all(obj.checkGeometry())
+                    answer = questdlg(['Coefficient matrices differ from rocket geometry. ' ...
+                        'Do you want to create new matrices?']);
+                end
+                
+                switch answer
+                    case 'Yes'
+                        parserPath = fullfile(mission.msaPath, 'autoMatricesProtub');
+                        addpath(genpath(parserPath));
+                        mainAutoMatProtub(obj);
+                        obj.loadData();
+                    case 'Cancel'
+                        error('Rocket creation aborted')
+                    otherwise
+                end
+            end
+        end
+    end
+
+    methods
+        [coeffsValues, angle0] = interpCoeffs(obj, t, alpha, mach, beta, alt, c)
+        checks = checkGeometry(obj)
+        img = plot(obj)
+    end
+
+    methods(Access = private)
+        obj = loadData(obj)
+        obj = updateBay(obj, bayName, value)
+        obj = updateNoMotor(obj);
+        obj = update(obj);
+    end
+
+    methods
+        function obj = set.parafoil(obj, value), obj = obj.updateBay('PARAFOIL', value); end
+        function obj = set.recovery(obj, value), obj = obj.updateBay('RECOVERY', value); end
+        function obj = set.electronics(obj, value), obj = obj.updateBay('ELECTRONICS', value); end
+        function obj = set.airbrakes(obj, value), obj = obj.updateBay('AIRBRAKES', value); end
+        function obj = set.motor(obj, value)
+            obj = obj.updateBay('MOTOR', value);
+            obj.time = value.time;
+            obj.cutoffTime = value.cutoffTime;
+        end
+        function obj = set.rear(obj, value), obj = obj.updateBay('REAR', value); end
+
+        
+        function obj = set.length(obj, value), obj = obj.updateOverridable('LENGTH', value); end
+        function obj = set.lengthCenter(obj, value), obj = obj.updateOverridable('LENGTH_CENTER', value); end
+        function obj = set.lengthCenterNoMotor(obj, value), obj = obj.updateOverridable('LENGTH_CENTER_NO_MOTOR', value); end
+        function obj = set.diameter(obj, value)
+            obj.DIAMETER = value;
+            obj.crossSection = 0.25*pi*value^2;
+        end
+
+        function obj = set.mass(obj, value), obj = obj.updateOverridable('MASS', value); end
+        function obj = set.massNoMotor(obj, value), obj = obj.updateOverridable('MASS_NO_MOTOR', value); end
+        function obj = set.inertia(obj, value), obj = obj.updateOverridable('INERTIA', value); end
+        function obj = set.inertiaNoMotor(obj, value), obj = obj.updateOverridable('INERTIA_NO_MOTOR', value); end
+        function obj = set.xcg(obj, value), obj = obj.updateOverridable('XCG', value); end
+        function obj = set.xcgNoMotor(obj, value), obj = obj.updateOverridable('XCG_NO_MOTOR', value); end
+    end
+
+    methods
+        function value = get.parafoil(obj), value = obj.PARAFOIL; end
+        function value = get.recovery(obj), value = obj.RECOVERY; end
+        function value = get.electronics(obj), value = obj.ELECTRONICS; end
+        function value = get.airbrakes(obj), value = obj.AIRBRAKES; end
+        function value = get.motor(obj), value = obj.MOTOR; end
+        function value = get.rear(obj), value = obj.REAR; end
+
+        function value = get.length(obj), value = obj.LENGTH; end
+        function value = get.lengthCenter(obj), value = obj.LENGTH_CENTER; end
+        function value = get.lengthCenterNoMotor(obj), value = obj.LENGTH_CENTER_NO_MOTOR; end
+        function value = get.diameter(obj), value = obj.DIAMETER; end
+
+        function value = get.mass(obj), value = obj.MASS; end
+        function value = get.massNoMotor(obj)
+            value = obj.MASS_NO_MOTOR; 
+        end
+        function value = get.inertia(obj), value = obj.INERTIA; end
+
+        function value = get.inertiaNoMotor(obj), value = obj.INERTIA_NO_MOTOR; end
+        function value = get.xcg(obj), value = obj.XCG; end
+        function value = get.xcgNoMotor(obj), value = obj.XCG_NO_MOTOR; end
+    end
+end
\ No newline at end of file
diff --git a/classes/@Rocket/checkGeometry.m b/classes/@Rocket/checkGeometry.m
new file mode 100644
index 0000000..95ce79c
--- /dev/null
+++ b/classes/@Rocket/checkGeometry.m
@@ -0,0 +1,83 @@
+function checks = checkGeometry(obj)
+    % checkGeometry     - This methods checks if the rocket geometry
+    %                     is consistent with the geometry of the
+    %                     aerodynamic matrices
+    %
+    % OUTPUTS:
+    %                   - checks (n fields of geometry, 1): boolean value of the geometry checks
+    
+    xCgRocket = round([ ...
+        obj.xCg(1); ...
+        obj.xCg(end) ...
+        ], 3);
+    
+    xCgTest = round([
+        obj.coefficients.geometry.xcg(1);
+        obj.coefficients.geometry.xcg(end);
+        ], 3);
+    
+    if (obj.parafoil.noseCMod & obj.parafoil.nosePMod) == 0 % KARMAN ogive case, no modified p and c coefficients
+        geometryRocket = round([
+            obj.diameter;
+            obj.parafoil.noseLength;
+            obj.lengthCenter;
+            obj.rear.finsRootChord;
+            obj.rear.finsFreeChord;
+            obj.rear.finsHeight;
+            obj.rear.finsDeltaXFreeChord;
+            obj.rear.nPanel;
+            obj.rear.boatLength;
+            obj.rear.boatFinalDiameter;
+            ], 3);
+        
+        geometryTest = round([
+            obj.coefficients.geometry.diameter;
+            obj.coefficients.geometry.lNose;
+            obj.coefficients.geometry.lCenter;
+            obj.coefficients.geometry.chord1;
+            obj.coefficients.geometry.chord2;
+            obj.coefficients.geometry.height;
+            obj.coefficients.geometry.deltaXLE;
+            obj.coefficients.geometry.nPanel;
+            obj.coefficients.geometry.boatL;
+            obj.coefficients.geometry.boatD;
+            ], 3);
+    else % MHAAK ogive case, modified p and c coefficients
+        geometryRocket = round([
+            obj.diameter;
+            obj.parafoil.noseLength;
+            obj.lengthCenter;
+            obj.parafoil.noseCMod;
+            obj.parafoil.nosePMod;
+            obj.rear.finsRootChord;
+            obj.rear.finsFreeChord;
+            obj.rear.finsHeight;
+            obj.rear.finsDeltaXFreeChord;
+            obj.rear.nPanel;
+            obj.rear.boatLength;
+            obj.rear.boatFinalDiameter;
+            ], 3);
+        
+        geometryTest = round([
+            obj.coefficients.geometry.diameter;
+            obj.coefficients.geometry.lNose;
+            obj.coefficients.geometry.lCenter;
+            obj.coefficients.geometry.cMod;
+            obj.coefficients.geometry.pMod;
+            obj.coefficients.geometry.chord1;
+            obj.coefficients.geometry.chord2;
+            obj.coefficients.geometry.height;
+            obj.coefficients.geometry.deltaXLE;
+            obj.coefficients.geometry.nPanel;
+            obj.coefficients.geometry.boatL;
+            obj.coefficients.geometry.boatD;
+            ], 3);
+    end
+    
+    checks = [
+        xCgRocket == xCgTest;
+        strcmp(obj.coefficients.geometry.ogType, obj.parafoil.noseType);
+        geometryRocket == geometryTest;
+        strcmp(obj.coefficients.geometry.boatType, obj.rear.boatType)
+        ];
+end
\ No newline at end of file
diff --git a/classes/@Rocket/interpCoeffs.m b/classes/@Rocket/interpCoeffs.m
new file mode 100644
index 0000000..717934a
--- /dev/null
+++ b/classes/@Rocket/interpCoeffs.m
@@ -0,0 +1,63 @@
+function [coeffsValues, angle0] = interpCoeffs(obj, t, alpha, mach, beta, alt, c)
+% interpCoeffs - interpolation of aerodynamic coefficients.
+%
+% INPUTS:
+%         - t, double [1,1], integration time, [s];
+%         - alpha, double[1,1], angle of attack, [];
+%         - mach, double[1,1], mach number, [];
+%         - beta, double[1,1], sideslip angle, [];
+%         - alt, double[1,1], altitude, [m];
+%         - c, double[1,1], aerobrakes control variable, [];
+%
+% OUTPUTS:
+%         - coeffsValues, array [16,1],  aerodynamic coefficients;
+%         - angle0, array [2,1], array of the reference aerodynamic angles.
+
+if mach > obj.airbrakes.maxMach
+    c = 0;
+end
+h = c*obj.coefficients.state.hprot(end);
+
+[nearAlpha, indexAlpha] = nearestValSorted(obj.coefficients.state.alphas*pi/180, alpha);
+[~, indexMach] = nearestValSorted(obj.coefficients.state.machs, mach);
+[nearBeta, indexBeta] = nearestValSorted(obj.coefficients.state.betas*pi/180, beta);
+[~, indexAlt] = nearestValSorted(obj.coefficients.state.altitudes, alt);
+[~, indexControl] = nearestValSorted(obj.coefficients.state.hprot, h);
+
+angle0 = [nearAlpha; nearBeta];
+
+if t >= obj.motor.cutoffTime
+    % Interpolate on airbrake control
+    % Uses end xCg, even if tCutOff < tBurnTime
+    num = length(obj.coefficients.state.hprot);
+    index1 = indexControl;
+    index2 = indexControl + 1;
+    if index2 > num
+        if num == 1
+            coeffsValues = obj.coefficients(:, indexAlpha, indexMach, indexBeta, indexAlt, 1, end);
+            return;
+        else
+            index2 = index2 - 1;
+            index1 = index1 - 1;
+        end
+    end
+    
+    VF = obj.coefficients.total(:, indexAlpha, indexMach, indexBeta, indexAlt, index1, end);
+    VE = obj.coefficients.total(:, indexAlpha, indexMach, indexBeta, indexAlt, index2, end);
+    
+    deltaH = obj.coefficients.state.hprot(index2) - obj.coefficients.state.hprot(index1);
+    coeffsValues =  ( (h - obj.coefficients.state.hprot(index1))/deltaH)*(VE - VF) + VF;
+else
+    % Interpolate on xCg, close airbrakes
+    num = 1:1:length(obj.coefficients.state.xcgTime)-1;
+    indexXcg = t >= obj.coefficients.state.xcgTime(1:end-1) & t < obj.coefficients.state.xcgTime(2:end);
+    index1 = num(indexXcg);
+    index2 = index1 + 1;
+    
+    VF = obj.coefficients.total(:, indexAlpha, indexMach, indexBeta, indexAlt, indexControl, index1);
+    VE = obj.coefficients.total(:, indexAlpha, indexMach, indexBeta, indexAlt, indexControl, index2);
+    
+    deltaT = obj.coefficients.state.xcgTime(index2) - obj.coefficients.state.xcgTime(index1);
+    coeffsValues =  ( (t - obj.coefficients.state.xcgTime(index1))/deltaT)*(VE - VF) + VF;
+end
+end
\ No newline at end of file
diff --git a/classes/@Rocket/loadData.m b/classes/@Rocket/loadData.m
new file mode 100644
index 0000000..78b4e6d
--- /dev/null
+++ b/classes/@Rocket/loadData.m
@@ -0,0 +1,40 @@
+function obj = loadData(obj)
+if isempty(obj.motor)
+    return;
+end
+
+varNames = {'total', 'geometry', 'state', 'finsCN'};
+motorName = obj.motor.name;
+aeroPath = fullfile(obj.mission.dataPath, 'aeroCoefficients.mat');
+aeroHighAOAPath = fullfile(obj.mission.dataPath, 'aeroCoefficientsHighAOA.mat');
+
+if ~(exist(aeroPath, 'file') && exist(aeroHighAOAPath,'file'))
+    return;
+end
+dataCoeffs = load(aeroPath);
+dataCoeffsHighAOA = load(aeroHighAOAPath);
+
+if isfield(dataCoeffs, motorName) && isfield(dataCoeffsHighAOA, motorName)
+    dataCoeffs = dataCoeffs.(motorName);
+    dataCoeffsHighAOA = dataCoeffsHighAOA.(motorName);
+else
+    return;
+end
+
+if isfield(dataCoeffs, "finsCN") && ...
+        isfield(dataCoeffsHighAOA, "finsCN")
+    obj.coefficients.finsCN = dataCoeffs.finsCN;
+    obj.coefficientsHighAOA.finsCN = dataCoeffsHighAOA.finsCN;
+end
+
+varNames = varNames{1:end - 1};
+if all(and(isfield(dataCoeffs, varNames), ...
+        isfield(dataCoeffsHighAOA, varNames)))
+    obj.coefficients.total = dataCoeffs.total;
+    obj.coefficientsHighAOA.total = dataCoeffsHighAOA.total;
+    obj.coefficients.geometry = dataCoeffs.geometry;
+    obj.coefficientsHighAOA.geometry = dataCoeffsHighAOA.geometry;
+    obj.coefficients.state = dataCoeffs.state;
+    obj.coefficientsHighAOA.state = dataCoeffsHighAOA.state;
+end
+end
\ No newline at end of file
diff --git a/classes/@Rocket/plot.m b/classes/@Rocket/plot.m
new file mode 100644
index 0000000..7b87f93
--- /dev/null
+++ b/classes/@Rocket/plot.m
@@ -0,0 +1,116 @@
+function img = plot(obj)
+arguments
+    obj     Rocket
+end
+
+deltaXLE = obj.rear.finsDeltaXFreeChord;
+r = obj.diameter/2;
+height = obj.rear.finsHeight;
+C1 = obj.rear.finsRootChord;
+C2 = obj.rear.finsFreeChord;
+
+Lcent = obj.lengthCenter;
+Lnos = obj.parafoil.noseLength;
+
+Xle1 = Lcent + Lnos - obj.rear.finsAxialDistance - C1;
+
+Daft = obj.rear.boatFinalDiameter;
+Laft = obj.rear.boatLength;
+
+xNos = Lnos - Lnos*cos(linspace(0, pi/2, 50));
+if strcmp(obj.parafoil.noseType, 'KARMAN')
+    theta = @(x) acos( 1 - ( (2*x)./Lnos ) );
+    Karman = @(x) ( r/sqrt(pi) ) * sqrt( theta(x) - ( sin(2*theta(x))./ 2 ) );
+    yNos = Karman(xNos);
+elseif strcmp(obj.parafoil.noseType, 'HAACK')
+    theta = @(x) acos( 1 - ( (2*x)./Lnos ) );
+    Haack = @(x) ( r/sqrt(pi) ) * sqrt( theta(x) - ( sin(2*theta(x))./ 2 ) + (1/3)*sin(theta(x)).^3 );
+    yNos = Haack(xNos);
+elseif strcmp(obj.parafoil.noseType, 'OGIVE')
+    rho = (r^2 + Lnos^2)/(2*r);
+    Ogive = @(x) sqrt(rho^2 - (Lnos - x).^2) + r - rho;
+    yNos = Ogive(xNos);
+elseif strcmp(obj.parafoil.noseType, 'POWER')
+    power = obj.parafoil.nosePower;
+    Power = @(x) r * (x/Lnos).^(power);
+    yNos = Power(xNos);
+elseif strcmp(obj.parafoil.noseType, 'MHAACK')
+    p = obj.parafoil.nosePMod;
+    c = obj.parafoil.noseCMod;
+    xMod = @(x, p) (x/Lnos).^(p)*Lnos;
+    thetaMod = @(x, p) acos( 1 - ( (2*xMod(x, p))./Lnos ) );
+    haackSeriesMod = @(x, p, C) ( r/sqrt(pi) ) * sqrt( thetaMod(x, p) ...
+        - ( sin(2*thetaMod(x, p))./ 2 ) + C*sin(thetaMod(x, p)).^3 );
+    yNos = haackSeriesMod(xNos, p, c);
+end
+
+if strcmp(obj.rear.boatType, 'OGIVE') % [-] Boat-tail shape. 0: Cone, 1: Tangent Ogive
+    [xBoat, yBoat] = computeTangentBoatPoints(2*r, Daft, Laft);
+else
+    xBoat = [0 Laft];
+    yBoat = [r Daft/2];
+end
+
+%%% figure begin
+img = figure();
+hold on
+
+%%% NOSECONE
+plot(xNos, yNos, 'k');
+plot(xNos, -yNos, 'k');
+plot([Lnos Lnos], [-r r], 'k');
+
+%%% CENTERBODY
+plot([Lnos Lnos+Lcent], [r r], 'k');
+plot([Lnos Lnos+Lcent], [-r -r], 'k');
+plot([Lnos+Lcent Lnos+Lcent], [-r r], 'k');
+
+%%% BOAT-TAIL PLOT
+plot(xBoat+Lnos+Lcent, yBoat, 'k');
+plot(xBoat+Lnos+Lcent, -yBoat, 'k');
+plot([Lnos+Lcent+Laft Lnos+Lcent+Laft], [-Daft/2 Daft/2], 'k');
+
+%%% FINS PLOT
+% top
+plot([Xle1 Xle1+deltaXLE], [r r+height],'k');
+plot([Xle1+C1 Xle1+deltaXLE+C2], [r r+height],'k');
+plot([Xle1+deltaXLE Xle1+deltaXLE+C2], [r+height r+height],'k');
+plot([Xle1 Xle1+C1], [r r], 'k');
+% bottom
+plot([Xle1 Xle1+deltaXLE], [-r -r-height],'k');
+plot([Xle1+C1 Xle1+deltaXLE+C2], [-r -r-height],'k');
+plot([Xle1+deltaXLE Xle1+deltaXLE+C2], [-r-height, -r-height],'k');
+plot([Xle1 Xle1+C1], [-r -r], 'k');
+
+% plot([Xle1 Xle1+deltaXLE], [r+height r+height], 'k--')
+% plot([Xle1+deltaXLE Xle1+deltaXLE], [r+height r],'k--')
+
+%%% BAYS
+lengths = obj.absolutePositions.values + 2*Lnos;
+baysBody = obj.absolutePositions.keys;
+iMotor = find(strcmp(obj.absolutePositions.keys,"motor"));
+xline(0,'r-.', 'Label', 'NOSE', ...
+    'LabelOrientation', 'aligned', 'LabelVerticalAlignment', 'bottom', ...
+    'LabelHorizontalAlignment', 'right');
+for i = 1:length(lengths)
+    if i == iMotor
+        line([lengths(i) lengths(i)], [-1 1], 'LineStyle', '--', 'Color', 'b'); % Draw the line
+        text(lengths(i), -1 + 0.3, baysBody(i), 'VerticalAlignment', 'top', ...
+            'HorizontalAlignment', 'right', 'Rotation', 90, 'Color', 'b');
+    else
+        line([lengths(i) lengths(i)], [-1 1], 'LineStyle', '--', 'Color', 'k'); % Draw the line
+        text(lengths(i), 1 + 0.1, baysBody(i), 'VerticalAlignment', 'top', ...
+            'HorizontalAlignment', 'right', 'Rotation', 90);
+    end
+end
+boatPlotLength = obj.length - obj.rear.boatLength;
+xline(boatPlotLength,'r-.', 'Label', 'BOAT-TAIL', ...
+    'LabelOrientation', 'aligned', 'LabelVerticalAlignment', 'bottom', ...
+    'LabelHorizontalAlignment', 'right');
+
+axis equal
+% set(gca, 'xlim', [-100, Lnos+Lcent+Laft+100]);
+
+%%% TITLE
+title(string(strrep(obj.mission.name, '_', ' ')));
+end
diff --git a/classes/@Rocket/update.m b/classes/@Rocket/update.m
new file mode 100644
index 0000000..4400d73
--- /dev/null
+++ b/classes/@Rocket/update.m
@@ -0,0 +1,45 @@
+function obj = update(obj)
+% Updates all properties without motor
+
+override = obj.overrides;
+
+%% Geometry
+if ~override('LENGTH')
+    obj.LENGTH = obj.rear.position + obj.rear.length + obj.parafoil.noseLength;
+end
+
+if ~override('LENGTH_CENTER')
+    obj.LENGTH_CENTER = obj.length - obj.parafoil.noseLength - obj.rear.boatLength;
+end
+
+%% Mass
+if ~override('MASS')
+    obj.MASS = obj.massNoMotor + obj.motor.mass;
+end
+
+if ~override('XCG')
+    obj.XCG = (obj.xcgNoMotor*obj.massNoMotor + ...
+                obj.motor.mass.*(obj.motor.xcg+obj.lengthCenterNoMotor))./ ...
+                obj.mass;
+end
+
+if ~override('INERTIA')
+    % [3xN] Ix, Iy, Iz
+    % Assumption: xCgs are close to rocket axis
+    motorInertia = obj.motor.inertia(2:3, :) + ...
+        (obj.xcg - (obj.motor.position + obj.motor.xcg)).^2 .* obj.motor.mass;
+    baysInertia = obj.inertiaNoMotor(2:3, :);
+    
+    obj.inertia = [obj.motor.inertia(1, :) + obj.inertiaNoMotor(1, :);
+        motorInertia + baysInertia];
+    
+    obj.inertiaDot = diff(obj.inertia, 1, 2)./diff(obj.motor.time);
+    obj.inertiaDot(:, end + 1) = obj.inertiaDot(:, end);
+end
+
+%% Cutoff
+obj.cutoffMass = interp1(obj.time, obj.mass, obj.cutoffTime, "linear", 'extrap');
+obj.cutoffInertia = interp1(obj.time, obj.inertia', obj.cutoffTime, "linear", 'extrap')';
+
+end
+
diff --git a/classes/@Rocket/updateBay.m b/classes/@Rocket/updateBay.m
new file mode 100644
index 0000000..4fb11c5
--- /dev/null
+++ b/classes/@Rocket/updateBay.m
@@ -0,0 +1,18 @@
+function obj = updateBay(obj, bayName, value)
+obj.(bayName) = value;
+
+obj.bayStatus(bayName) = true;
+if ~all(values(obj.bayStatus)), return; end
+bays = obj.bays;
+
+%% Update positions
+obj.(bays(1)).position = 0;
+for i = 2:length(bays)
+    bay = bays(i);
+    prevBay = bays(i-1);
+    obj.(bay).position = obj.(prevBay).position + obj.(prevBay).length + obj.(bay).offset;
+end
+
+obj = obj.updateNoMotor();
+obj = obj.update();
+end
\ No newline at end of file
diff --git a/classes/@Rocket/updateNoMotor.m b/classes/@Rocket/updateNoMotor.m
new file mode 100644
index 0000000..ae7f461
--- /dev/null
+++ b/classes/@Rocket/updateNoMotor.m
@@ -0,0 +1,39 @@
+function obj = updateNoMotor(obj)
+% Updates all properties without motor
+
+override = obj.overrides;
+bayNames = obj.baysNoMotor;
+nBays = length(bayNames);
+bays(nBays) = obj.(bayNames(end));
+
+for i = 1:nBays - 1, bays(i) = obj.(bayNames(i)); end
+
+positions = [bays.position];
+masses = [bays.mass];
+xcgs = positions + [bays.xcg];
+inertias = cat(1, bays.inertia)';
+
+massNoMotor = sum([bays.mass]);
+
+%% Geometry
+if ~override('LENGTH_CENTER_NO_MOTOR')
+    obj.LENGTH_CENTER_NO_MOTOR = obj.motor.position;
+end
+
+%% Mass
+if ~override('MASS_NO_MOTOR')
+    obj.MASS_NO_MOTOR = massNoMotor;
+end
+
+if ~override('XCG_NO_MOTOR')
+    obj.XCG_NO_MOTOR = (xcgs*masses')/massNoMotor;
+end
+
+if ~override('INERTIA_NO_MOTOR')
+    % [3x1] Ix, Iy, Iz
+    % Assumption: xCgs are close to rocket axis
+    IRaw = inertias(2:3, :) + (obj.xcgNoMotor - xcgs).^2 .* masses;
+    obj.INERTIA_NO_MOTOR = [sum(inertias(1, :)); sum(IRaw, 2)];
+end
+end
+
diff --git a/classes/@Rocket/updateOverridable.m b/classes/@Rocket/updateOverridable.m
new file mode 100644
index 0000000..7c01974
--- /dev/null
+++ b/classes/@Rocket/updateOverridable.m
@@ -0,0 +1,10 @@
+function obj = updateOverridable(obj, name, value)
+obj.(name) = value;
+obj.overrides(name) = true;
+
+if isempty(value)
+    obj.overrides(name) = false;
+    obj = obj.updateNoMotor();
+    obj = obj.update();
+end
+end
\ No newline at end of file
diff --git a/classes/Bay.m b/classes/Bay.m
index beb567f..1e143c3 100644
--- a/classes/Bay.m
+++ b/classes/Bay.m
@@ -1,19 +1,26 @@
-classdef Bay < Component & matlab.mixin.Heterogeneous
+classdef(Abstract) Bay < Config & matlab.mixin.Heterogeneous
 % Bay: Represents an abstraction layer for all bays
 %   Arrays of bay subclasses will be represented as [mxn Bay] arrays
 
+    properties
+        offset      (1, 1)  double      % [m]       Position offset relative to previous bay, default: 0
+        length              double      % [m]       Total bay length
+    end
+
     properties(Abstract)
-        position    % [m]       OVERRIDE Position, relative to previous component - 
-        length      % [m]       Total bay length
-        mass        % [kg]      Total bay mass
-        inertia     % [kg*m^2]  Total bay inertia (Body reference)
-        xCg         % [m]       Cg relative to bay upper side
+        mass        (1, :)  double      % [kg]      Total bay mass
+        inertia     (1, :)  double      % [kg*m^2]  Total bay inertia (Body reference)
+        xcg         (1, :)  double      % [m]       Xcg wrt bay top
+    end
+
+    properties(SetAccess = ?Rocket)
+        position            double      % [m]       Absolute position wrt ogive base
     end
 
-    methods (Static, Sealed, Access=protected)
-        function default = getDefaultScalarElement
-            default = Parafoil;
-        end
+    methods (Static,Sealed,Access = protected)
+       function obj = getDefaultScalarElement()
+          obj = Electronics();
+       end
     end
 end
 
diff --git a/classes/Component.m b/classes/Component.m
deleted file mode 100644
index 7407018..0000000
--- a/classes/Component.m
+++ /dev/null
@@ -1,121 +0,0 @@
-classdef Component < Config & matlab.mixin.Copyable
-% Component: Represents an abstraction layer for all components
-%   Components standardize object construction, config and data loading
-%
-%   Constructor:
-%       - Component: Creates an instance of the Component class.
-%           Arguments:
-%               - mission: Mission, mission object, used to find config
-%               files
-%               - varsIn: If present, data is read from this variable
-%               instead of config file
-%
-%           Options:
-%
-%               - elementWise: 
-%                   - if true, data is copied element-by-element
-%                       into target class
-%                   - if false, the loaded data substitutes target class
-
-    properties(Abstract, Access = protected) 
-        mission Mission
-    end
-
-    methods
-        function obj = Component(mission, varsIn, options)
-            % Component: Contains and manages all bays
-            %
-            %   Constructor:
-            %       - Rocket: Creates an instance of the Rocket class.
-            %           Loaded config: rocketConfig.m > rocket (for overrides)
-            %           Loaded data: -
-            %           Arguments:
-            %               - mission: Mission, mission object
-            %               - varIn: (optional) config source. Alternative to config.m
-            %               file
-
-            arguments (Input)
-                mission Mission = Mission()
-                varsIn = []
-                options.elementWise logical = true
-            end
-
-            if isempty(mission.name)
-                return;
-            end
-            
-            if isempty(varsIn)
-                varsIn = obj.getConfig(mission);
-            end
-
-            fileName = obj.configName;
-            varName = obj.variableName;
-            if isempty(varName)
-                varName = strtok(fileName, 'C');
-            end
-
-            if ~isfield(varsIn, varName)
-                error(['Class not found inside the config folder: %s\n' ...
-                    'With name: %s\n' ...
-                    'Check that the correct mission is set in your component ' ...
-                    'and the config file is correct'], fileName, varName);
-            end
-
-            configObj = varsIn.(varName);
-
-            if options.elementWise
-                fields = configObj.getProperties('writable');
-                for field = fields
-                    if isempty([configObj.(field)]), continue; end
-                    obj.(field) = configObj.(field);
-                end
-            else
-                obj = configObj;
-            end
-
-            [obj.mission] = deal(mission);
-        end
-    end
-    
-    methods
-        function m = getMission(obj)
-            m = obj.mission;
-        end
-    end
-
-    methods(Access = protected)
-        function cp = copyElement(obj)
-            fields = obj.getProperties('readable', NonCopyable = 0);
-            cp = copyElement@matlab.mixin.Copyable(obj); %shallow copy of all elements
-
-            for field = fields
-                if isa(obj.(field), 'matlab.mixin.Copyable')
-                    cp.(field) = copy(obj.(field));
-                end
-            end
-        end
-
-        function outputVariables = getConfig(obj, mission)
-            fileName = obj.configName;
-            filePath = mission.configPath;
-            file = fullfile(filePath, fileName);
-
-            if ~isfile(file)
-                error(['File not found inside the config folder: %s\n' ...
-                    'Check that the correct mission is set in your component ' ...
-                    'and the config file exists'], fileName); 
-            end
-
-            variables = [who(); "variables"];
-            run(file);
-            loadedVariables = who();
-            loadedVariables(ismember(loadedVariables, variables)) = [];
-
-            outputVariables = struct();
-            for i = 1:length(loadedVariables)
-                outputVariables.(loadedVariables{i}) = eval(loadedVariables{i});
-            end
-        end
-    end
-end
-
diff --git a/classes/Config.m b/classes/Config.m
index cec711a..5c7b954 100644
--- a/classes/Config.m
+++ b/classes/Config.m
@@ -1,16 +1,51 @@
-classdef(Abstract) Config < handle
+classdef(Abstract) Config
 % Config: Represents an abstraction layer for all config-dependent Classes
-%   Config standardizes property management and declares fundemental
-%   methods (see doc for more info)
+%   Config standardizes property management, and config loading and 
+%       declares fundemental methods (see doc for more info) and 
 
-
-    properties(Abstract, Access = protected)
+    properties(Abstract, Constant, Access = protected)
         configName  {mustBeTextScalar}
         variableName char
     end
 
     methods
+        function obj = Config(pathIn, varsIn)
+            % Component: Contains and manages all bays
+            %
+            %   Constructor:
+            %       - Rocket: Creates an instance of the Rocket class.
+            %           Loaded config: rocketConfig.m > rocket (for overrides)
+            %           Loaded data: -
+            %           Arguments:
+            %               - filePath: Path containing config file
+            %               - varIn: (optional) config source. Alternative to config.m
+            %               file
+
+            arguments (Input)
+                pathIn {mustBeA(pathIn, {'char', 'string', 'Mission'})} = ''
+                varsIn   = []
+            end
+
+            if isa(pathIn, 'Mission')
+                path = pathIn.configPath;
+            else
+                path = pathIn;
+            end
+
+            if isempty(path), return; end
+            if isempty(varsIn)
+                varsIn = obj.getConfig(path);
+            end
+
+            obj = obj.loadConfig(varsIn);
+        end
+
         function structOut = toStruct(obj)
+        % This function converts the object to a struct
+        %
+        %   WARNING: A struct does not posses update capabilities and only
+        %   publicly readable fields are copied. Use this method carefully
+
             structOut = struct();
             fields = obj.getProperties('readable');
             for j = 1:size(fields, 2), structOut.(fields{j}) = obj.(fields{j}); end
@@ -31,9 +66,8 @@ classdef(Abstract) Config < handle
         
         arguments
             obj
-            preset                  char {mustBeMember(preset, {'readable', 'writable', ''})}               = ''
+            preset                  char    {mustBeMember(preset, {'readable', 'writable', ''})}            = ''
             options.Superclass      char                                                                    = ''
-            options.Heterogeneous   logical                                                                 = 0
             attributes.GetAccess    char    {mustBeMember(attributes.GetAccess, {'public', 'private', ''})} = ''
             attributes.SetAccess    char    {mustBeMember(attributes.SetAccess, {'public', 'private', ''})} = ''
             attributes.Dependent    logical {mustBeMember(attributes.Dependent, [0, 1])}                    = []
@@ -53,7 +87,6 @@ classdef(Abstract) Config < handle
                         attributes.Hidden = 0;
                     case 'writable'
                         attributes.SetAccess = 'public';
-                        attributes.Dependent = 0;
                         attributes.Constant = 0;
                         attributes.Abstract = 0;
                         attributes.Hidden = 0;
@@ -87,50 +120,57 @@ classdef(Abstract) Config < handle
             propertiesOut = string(properties(1:ii));
 
             if nargout == 2
-                if isempty(options.Superclass) || ~options.Heterogeneous
-                    valuesOut = cell(1, ii);
-                    for i = 1:ii, valuesOut{i} = obj.(propertiesOut(i)); end
-                else
-                    valuesOut(ii) = obj.(propertiesOut(1));
-                    for i = 1:ii, valuesOut(i) = obj.(propertiesOut(i)); end
-                end
+                valuesOut = cell(1, ii);
+                for i = 1:ii, valuesOut{i} = obj.(propertiesOut(i)); end
             end
         end
     end
 
-    methods(Hidden)
-        function lh = addlistener(varargin)
-            lh = addlistener@handle(varargin{:});
-        end
-        function notify(varargin)
-            notify@handle(varargin{:});
-        end
-        function delete(varargin)
-            delete@handle(varargin{:});
-        end
-        function Hmatch = findobj(varargin)
-            Hmatch = findobj@handle(varargin{:});
-        end
-        function p = findprop(varargin)
-            p = findprop@handle(varargin{:});
-        end
-        function TF = eq(varargin)
-            TF = eq@handle(varargin{:});
-        end
-        function TF = ne(varargin)
-            TF = ne@handle(varargin{:});
-        end
-        function TF = lt(varargin)
-            TF = lt@handle(varargin{:});
-        end
-        function TF = le(varargin)
-            TF = le@handle(varargin{:});
-        end
-        function TF = gt(varargin)
-            TF = gt@handle(varargin{:});
+    methods(Access = protected)
+        function outputVariables = getConfig(obj, filePath)
+            fileName = obj.configName;
+            file = fullfile(filePath, fileName);
+
+            if ~isfile(file)
+                error(['File not found inside the config folder: %s\n' ...
+                    'Check that the correct mission is set in your component ' ...
+                    'and the config file exists'], fileName); 
+            end
+
+            variables = [who(); "variables"];
+            
+            % try run(file);
+            % catch ME, throwAsCaller(ME); end
+            run(file);
+            loadedVariables = who();
+            loadedVariables(ismember(loadedVariables, variables)) = [];
+
+            outputVariables = struct();
+            for i = 1:length(loadedVariables)
+                outputVariables.(loadedVariables{i}) = eval(loadedVariables{i});
+            end
         end
-        function TF = ge(varargin)
-            TF = ge@handle(varargin{:});
+
+        function obj = loadConfig(obj, varsIn)
+            fileName = obj.configName;
+            varName = obj.variableName;
+            if isempty(varName)
+                varName = strtok(fileName, 'C');
+            end
+
+            if ~isfield(varsIn, varName)
+                error(['Class not found inside the config folder: %s\n' ...
+                    'With name: %s\n' ...
+                    'Check that the correct mission is set in your component ' ...
+                    'and the config file is correct'], fileName, varName);
+            end
+
+            configObj = varsIn.(varName);
+            fields = configObj.getProperties('writable');
+            for field = fields
+                if isempty([configObj.(field)]), continue; end
+                obj.(field) = configObj.(field);
+            end
         end
-   end
+    end
 end
\ No newline at end of file
diff --git a/classes/components/Environment.m b/classes/Environment.m
similarity index 100%
rename from classes/components/Environment.m
rename to classes/Environment.m
diff --git a/classes/Mission.m b/classes/Mission.m
index 25b1eac..12cb70f 100644
--- a/classes/Mission.m
+++ b/classes/Mission.m
@@ -10,10 +10,14 @@ classdef Mission < Config
     %               - loadConfig: bool, Whether to load config file or return
     %               an empty mission
 
-    properties
+    properties(Dependent)
         name        char % Mission name, used to access <mission> folder
     end
 
+    properties(Access = private)
+        NAME        char % Mission name cache
+    end
+
     properties(SetAccess = protected)
         currentPath char
         configPath  char
@@ -21,17 +25,20 @@ classdef Mission < Config
         msaPath     char
     end
 
-    properties(Access = protected)
+    properties(Access = private)
+        changeMatlabPath (1,1)  logical
+    end
+
+    properties(Constant, Access = protected)
         configName = 'missionConfig.m'
         variableName = ''
-        changeMatlabPath (1,1)  logical
     end
 
     methods
         function obj = Mission(mission, options)
             arguments
                 mission {mustBeA(mission, {'logical', 'string', 'char'})} = false
-                options.changeMatlabPath = true;
+                options.changeMatlabPath = false;
             end
 
             if nargin == 0
@@ -41,16 +48,21 @@ classdef Mission < Config
             filePath = fullfile(fileparts(mfilename("fullpath")), '..', 'missions');
             filePath = trimPath(filePath);
 
-            obj.changeMatlabPath = options.changeMatlabPath;
             obj.currentPath = filePath;
+            obj.changeMatlabPath = options.changeMatlabPath;
             if isa(mission, 'char') || isa(mission, 'string')
                 obj.name = mission;
             else
-                obj.loadConfig();
+                vars = obj.getConfig(filePath);
+                obj.name = vars.mission.name;
             end
         end
 
-        function set.name(obj, name)
+        function name = get.name(obj)
+            name = obj.NAME;
+        end
+
+        function obj = set.name(obj, name)
             if strcmp(name,'design')
                 filePath = fullfile(fileparts(mfilename("fullpath")), '..', 'missions');
                 filePath = trimPath(filePath);
@@ -64,47 +76,34 @@ classdef Mission < Config
                     'Only one file can be selected at a time.',''}, ...
                     'SelectionMode','single','ListSize', [250,150], ...
                     'ListString',names);
-                obj.name = names{indx};
+                obj.NAME = names{indx};
             else
                 if ~isempty(obj.currentPath) && ...
-                        ~isfolder(fullfile(obj.currentPath, name)) %#ok<MCSUP>
+                        ~isfolder(fullfile(obj.currentPath, name))
                     error('Invalid mission: %s', name)
                 end
-                obj.name = name;
+                obj.NAME = name;
             end
-            obj.updatePath();
+
+            obj = obj.updatePath();
             obj.updateMatlabPath();
         end
     end
 
-    methods(Access = protected)
-        function loadConfig(obj)
-            fileName = obj.configName;
-            filePath = obj.currentPath;
-
-            if ~isfile(fullfile(filePath, fileName))
-                error(strcat("File not found inside the config folder: ", filePath));
-            end
-
-            varName = strtok(fileName,'C');
-            run(fileName);
-            configObj = eval(varName);
-            obj.name = configObj.name;
-        end
-
-        function updatePath(obj)
+    methods(Access = private)
+        function obj = updatePath(obj)
             if isempty(obj.name) || isempty(obj.currentPath), return; end
 
             obj.configPath = fullfile(obj.currentPath, obj.name, 'config');
             obj.dataPath = fullfile(obj.currentPath, obj.name, 'data');
             obj.msaPath = trimPath( ...
-                fullfile(obj.currentPath, '..', '..', '..', 'msa-toolkit') ...
-                );
+                fullfile(obj.currentPath, '..', '..', '..', 'msa-toolkit'));
         end
 
         function updateMatlabPath(obj)
             if isempty(obj.name) || isempty(obj.currentPath), return; end
             if ~obj.changeMatlabPath, return; end
+            
             matlabPath = path;
             % Checking if other missions are in path
             pattern = 'missions\\[^\\/]*;'; % Matches any config folder under mission in path
@@ -125,8 +124,4 @@ classdef Mission < Config
             end
         end
     end
-
-    methods(Static, Access = protected)
-        function loadData(), end
-    end
 end
\ No newline at end of file
diff --git a/classes/Rocket.m b/classes/Rocket.m
deleted file mode 100644
index 3a18b22..0000000
--- a/classes/Rocket.m
+++ /dev/null
@@ -1,558 +0,0 @@
-classdef Rocket < Component
-    % Rocket: Contains and manages all bays
-    %
-    %   Constructor:
-    %       - Rocket: Creates an instance of the Rocket class.
-    %           Loaded config: rocketConfig.m > rocket (for overrides)
-    %           Loaded data: -
-    %           Arguments:
-    %               - mission: Mission, mission object
-    %               - varIn: (optional) config source. Alternative to config.m
-    %               file
-    
-    properties
-        parafoil            Parafoil         % [-]       Parafoil bay
-        recovery            Recovery        % [-]       Recovery bay
-        electronics         Electronics     % [-]       Electronics bay
-        airbrakes           Airbrakes       % [-]       Airbrakes bay
-        motor               Motor           % [-]       Motor bay
-        rear                Rear            % [-]       Rear bay
-        
-        pitot               Pitot           % [-]       Pitot component
-        parachutes          Para            % [-]       (nParachutes, nStages) Parachutes onboard
-        
-        length              double          % [m]       Total length
-        lengthCenter        double          % [m]       Center length - no nose, boat
-        lengthCenterNoMot   double          % [m]       Center length - no nose, no motor
-        diameter            double          % [m]       Diameter
-        mass                double          % [kg]      Total mass
-        massNoMotor         double          % [kg]      Mass without motor
-        inertia             double          % [kg*m^2]  Total inertia - Axibody reference
-        inertiaNoMotor      double          % [kg*m^2]  Inertia without motor
-        xCg                 double          % [m]       Total xCg
-        xCgNoMotor          double          % [m]       xCg without motor
-        
-        stagesMass          double          % [kg]      Mass of stage 2, 3, .. without chutes
-        
-        coefficients                        % [-]       Aerodynamic coefficients
-        coefficientsHighAOA                 % [-]       Aerodynamic coefficients for high angle of attacks
-    end
-    
-    properties(SetAccess = protected)
-        crossSection                        % [m^2]     Rocket cross sectional area
-        inertiaDot          double          % [kg*m^2/s]Total inertia time derivative
-        cutoffInertia       double          % [kg*m^2]  Total inertia at motor cutoff
-        cutoffMass          double          % [m]       Total mass at motor cutoff
-        absolutePositions   dictionary ...  % [m]       Bay start positions - 0 is set at nose base
-            = dictionary()
-        bays                dictionary ...  % [Bay]     All bays
-            = dictionary()
-    end
-    
-    properties(Access = protected, Hidden)
-        configName = 'rocketConfig.m'
-        variableName = ''
-        mission Mission
-    end
-    
-    methods % Updaters
-        function updateAbsolutePositions(obj)
-            bDictionay = obj.bays;
-            b = values(bDictionay);
-            
-            if ~isempty(obj.lengthCenterNoMot)
-                obj.absolutePositions = dictionary(["motor", "rear"], ...
-                    [obj.lengthCenterNoMot, obj.lengthCenterNoMot + obj.rear.position]);
-                return
-            end
-            % Populate shift vectors (how much each bay shifts the next one back)
-            % Shift overrides are applyed to the previous bay
-            shift = zeros(size(b));
-            overrides = ~cellfun(@isempty, {b.position});
-            overridesShift = logical([overrides(2:end), 0]);
-            
-            if any(overrides)
-                shift(overridesShift) = b(overrides).position;
-            end
-
-            if any(~overrides)
-                shift(~overridesShift) = [b(~overridesShift).length];
-            end
-            
-            absPositions = cumsum([-shift(1); shift(1:end-1)]);
-            absPositions = absPositions + ...
-                (obj.parafoil.length - obj.parafoil.noseLength);
-            obj.absolutePositions = dictionary(keys(bDictionay), absPositions);
-            
-        end
-        function updateGeometry(obj)
-            if ~isempty(obj.lengthCenterNoMot)
-                obj.length = obj.lengthCenterNoMot + obj.motor.length + obj.parafoil.noseLength;
-            else
-                obj.length = (obj.absolutePositions("rear") + obj.bays("rear").length) + ...
-                    obj.bays("parafoil").noseLength;
-                obj.lengthCenterNoMot = obj.absolutePositions("motor");
-            end
-            if isempty(obj.crossSection)
-                obj.crossSection = 0.25*pi*obj.diameter^2;
-            end
-            obj.lengthCenter = obj.length - obj.parafoil.noseLength - obj.rear.boatLength;
-        end
-        
-        function updateMassNoMotor(obj)
-            if ~isempty(obj.massNoMotor)
-                return;
-            end
-            bNoMotor = values(remove(obj.bays, 'motor'));
-            obj.massNoMotor = sum([bNoMotor.mass]);
-        end
-        
-        function updateMass(obj)
-            obj.mass = obj.massNoMotor + obj.motor.mass;
-        end
-        
-        function updateXCgNoMotor(obj)
-            if ~isempty(obj.xCgNoMotor)
-                return;
-            end
-            bNoMotor = values(remove(obj.bays, 'motor'))';
-            aPosNoMotor = values(remove(obj.absolutePositions, 'motor'))';
-            obj.xCgNoMotor = ((aPosNoMotor + [bNoMotor.xCg])* ...
-                [bNoMotor.mass]')/obj.massNoMotor;
-        end
-        
-        function updateXCg(obj)
-            obj.xCg = (obj.xCgNoMotor*obj.massNoMotor + ...
-                obj.motor.mass.*(obj.motor.xCg+obj.lengthCenterNoMot))./ ...
-                obj.mass;
-        end
-        
-        function updateInertiaNoMotor(obj)
-            if ~isempty(obj.inertiaNoMotor)
-                return;
-            end
-            bNoMotor = values(remove(obj.bays, 'motor'))';
-            aPosNoMotor = values(remove(obj.absolutePositions, 'motor'))';
-            % [3x1] Ix, Iy, Iz
-            % Assumption: xCgs are close to rocket axis
-            inertias = [bNoMotor.inertia];
-            temp = inertias(2:3, :) + ...
-                (obj.xCgNoMotor' - (aPosNoMotor + [bNoMotor.xCg])).^2 .* [bNoMotor.mass];
-            obj.inertiaNoMotor = [sum(inertias(1, :)); sum(temp, 2)];
-        end
-        
-        function updateInertia(obj)
-            % [3xN] Ix, Iy, Iz
-            % Assumption: xCgs are close to rocket axis
-            motorInertia = obj.motor.inertia(2:3, :) + ...
-                (obj.xCg - (obj.absolutePositions('motor') + obj.motor.xCg)).^2 .* obj.motor.mass;
-            baysInertia = obj.inertiaNoMotor(2:3, :) + ...
-                (obj.xCg - obj.xCgNoMotor).^2 .* obj.massNoMotor;
-            
-            obj.inertia = [obj.motor.inertia(1, :) + obj.inertiaNoMotor(1, :);
-                motorInertia + baysInertia];
-            
-            obj.inertiaDot = diff(obj.inertia, 1, 2)./diff(obj.motor.time);
-            obj.inertiaDot(:, end + 1) = obj.inertiaDot(:, end);
-        end
-        
-        function updateCutoff(obj)
-            obj.cutoffInertia = interpLinear(obj.motor.time, obj.inertia, obj.motor.cutoffTime);
-            obj.cutoffMass = interpLinear(obj.motor.time, obj.mass, obj.motor.cutoffTime);
-        end
-        
-        function updateStagesMass(obj)
-            stage1 = obj.cutoffMass - (obj.parachutes(1,2).mass + obj.parachutes(2,2).mass + obj.parafoil.mass);
-            % Everything at cut off without parafoil, parafoil drogue and
-            % parafoil airfoil
-            stage2 = obj.cutoffMass - stage1;
-            % only parafoil: parafoil, parafoil drogue and parafoil airfoil
-            obj.stagesMass = [stage1 stage2];
-        end
-        
-        function updateAll(obj)
-            % Note: properties without motor must be updated first
-            % if obj.motor.isHRE
-            obj.updateAbsolutePositions;
-            obj.updateGeometry;
-            obj.updateMassNoMotor;
-            obj.updateMass;
-            obj.updateXCgNoMotor;
-            obj.updateXCg;
-            obj.updateInertiaNoMotor;
-            obj.updateInertia;
-            obj.updateCutoff;
-            obj.updateStagesMass;
-            % end
-            %     obj.updateAbsolutePositions;
-            %     obj.updateGeometry;
-            %     obj.updateMassNoMotor;
-            %     obj.updateMass;
-            %     obj.updateXCgNoMotor;
-            %     obj.updateInertiaNoMotor;
-            %     obj.updateStagesMass;
-        end
-    end
-    
-    methods(Access = protected) % Loaders
-        function obj = loadData(obj)
-            if isempty(obj.motor)
-                return;
-            end
-            varNames = {'total', 'geometry', 'state', 'finsCN'};
-            motorName = obj.motor.name;
-            aeroPath = fullfile(obj.mission.dataPath, 'aeroCoefficients.mat');
-            aeroHighAOAPath = fullfile(obj.mission.dataPath, 'aeroCoefficientsHighAOA.mat');
-            
-            if ~(exist(aeroPath, 'file') && exist(aeroHighAOAPath,'file'))
-                return;
-            end
-            dataCoeffs = load(aeroPath);
-            dataCoeffsHighAOA = load(aeroHighAOAPath);
-            
-            if isfield(dataCoeffs, motorName) && isfield(dataCoeffsHighAOA, motorName)
-                dataCoeffs = dataCoeffs.(motorName);
-                dataCoeffsHighAOA = dataCoeffsHighAOA.(motorName);
-            else
-                return;
-            end
-            
-            if isfield(dataCoeffs, "finsCN") && ...
-                    isfield(dataCoeffsHighAOA, "finsCN")
-                obj.coefficients.finsCN = dataCoeffs.finsCN;
-                obj.coefficientsHighAOA.finsCN = dataCoeffsHighAOA.finsCN;
-            end
-            
-            varNames = varNames{1:end - 1};
-            if all(and(isfield(dataCoeffs, varNames), ...
-                    isfield(dataCoeffsHighAOA, varNames)))
-                obj.coefficients.total = dataCoeffs.total;
-                obj.coefficientsHighAOA.total = dataCoeffsHighAOA.total;
-                obj.coefficients.geometry = dataCoeffs.geometry;
-                obj.coefficientsHighAOA.geometry = dataCoeffsHighAOA.geometry;
-                obj.coefficients.state = dataCoeffs.state;
-                obj.coefficientsHighAOA.state = dataCoeffsHighAOA.state;
-            end
-        end
-    end
-    
-    methods
-        function obj = Rocket(mission, varIn, options)
-            arguments
-                mission                     Mission = Mission()
-                varIn                       struct  = []
-                options.loadCoefficients    logical = true
-                options.checkGeometry       logical = true
-            end
-            obj@Component(mission, varIn);
-            
-            %% Loading data
-            if isempty(mission.name)
-                return;
-            end
-            
-            vars             = obj.getConfig(mission); % Load config once and apply to other bays
-            obj.parafoil      = Parafoil(mission, vars);
-            obj.recovery     = Recovery(mission, vars);
-            obj.electronics  = Electronics(mission, vars);
-            obj.motor        = Motor(mission, vars);
-            obj.airbrakes    = Airbrakes(mission, obj.motor, vars);
-            obj.rear         = Rear(mission, vars);
-            obj.pitot        = Pitot(mission, vars);
-            paras            = Para(mission);
-            obj.parachutes    = paras(:, :, 1);
-            
-            [bayNames, bayValues] = obj.getProperties(Superclass='Bay', Heterogeneous=1);
-            obj.bays = dictionary(bayNames, bayValues);
-            obj.updateAll();
-            
-            if options.loadCoefficients
-                obj.loadData();
-                answer = '';
-                if isempty(obj.coefficients) || isempty(obj.coefficientsHighAOA)
-                    answer = questdlg(['Coefficient matrices not found. ' ...
-                        'Do you want to create new matrices?']);
-                elseif options.checkGeometry && ~all(obj.checkGeometry())
-                    answer = questdlg(['Coefficient matrices differ from rocket geometry. ' ...
-                        'Do you want to create new matrices?']);
-                end
-                
-                switch answer
-                    case 'Yes'
-                        parserPath = fullfile(mission.msaPath, 'autoMatricesProtub');
-                        addpath(genpath(parserPath));
-                        mainAutoMatProtub(obj);
-                        obj.loadData();
-                    case 'Cancel'
-                        error('Rocket creation aborted')
-                    otherwise
-                end
-            end
-        end
-        
-        function [coeffsValues, angle0] = interpCoeffs(obj, t, alpha, mach, beta, alt, c)
-            % interpCoeffs - interpolation of aerodynamic coefficients.
-            %
-            % INPUTS:
-            %         - t, double [1,1], integration time, [s];
-            %         - alpha, double[1,1], angle of attack, [];
-            %         - mach, double[1,1], mach number, [];
-            %         - beta, double[1,1], sideslip angle, [];
-            %         - alt, double[1,1], altitude, [m];
-            %         - c, double[1,1], aerobrakes control variable, [];
-            %
-            % OUTPUTS:
-            %         - coeffsValues, array [16,1],  aerodynamic coefficients;
-            %         - angle0, array [2,1], array of the reference aerodynamic angles.
-            
-            if mach > obj.airbrakes.maxMach
-                c = 0;
-            end
-            h = c*obj.coefficients.state.hprot(end);
-            
-            [nearAlpha, indexAlpha] = nearestValSorted(obj.coefficients.state.alphas*pi/180, alpha);
-            [~, indexMach] = nearestValSorted(obj.coefficients.state.machs, mach);
-            [nearBeta, indexBeta] = nearestValSorted(obj.coefficients.state.betas*pi/180, beta);
-            [~, indexAlt] = nearestValSorted(obj.coefficients.state.altitudes, alt);
-            [~, indexControl] = nearestValSorted(obj.coefficients.state.hprot, h);
-            
-            angle0 = [nearAlpha; nearBeta];
-            
-            if t >= obj.motor.cutoffTime
-                % Interpolate on airbrake control
-                % Uses end xCg, even if tCutOff < tBurnTime
-                num = length(obj.coefficients.state.hprot); %#ok<CPROPLC>
-                index1 = indexControl;
-                index2 = indexControl + 1;
-                if index2 > num
-                    if num == 1
-                        coeffsValues = obj.coefficients(:, indexAlpha, indexMach, indexBeta, indexAlt, 1, end);
-                        return;
-                    else
-                        index2 = index2 - 1;
-                        index1 = index1 - 1;
-                    end
-                end
-                
-                VF = obj.coefficients.total(:, indexAlpha, indexMach, indexBeta, indexAlt, index1, end);
-                VE = obj.coefficients.total(:, indexAlpha, indexMach, indexBeta, indexAlt, index2, end);
-                
-                deltaH = obj.coefficients.state.hprot(index2) - obj.coefficients.state.hprot(index1);
-                coeffsValues =  ( (h - obj.coefficients.state.hprot(index1))/deltaH)*(VE - VF) + VF;
-            else
-                % Interpolate on xCg, close airbrakes
-                num = 1:1:length(obj.coefficients.state.xcgTime)-1; %#ok<CPROPLC>
-                indexXcg = t >= obj.coefficients.state.xcgTime(1:end-1) & t < obj.coefficients.state.xcgTime(2:end);
-                index1 = num(indexXcg);
-                index2 = index1 + 1;
-                
-                VF = obj.coefficients.total(:, indexAlpha, indexMach, indexBeta, indexAlt, indexControl, index1);
-                VE = obj.coefficients.total(:, indexAlpha, indexMach, indexBeta, indexAlt, indexControl, index2);
-                
-                deltaT = obj.coefficients.state.xcgTime(index2) - obj.coefficients.state.xcgTime(index1);
-                coeffsValues =  ( (t - obj.coefficients.state.xcgTime(index1))/deltaT)*(VE - VF) + VF;
-            end
-        end
-        
-        function img = plot(obj)
-            arguments
-                obj     Rocket
-            end
-            deltaXLE = obj.rear.finsDeltaXFreeChord;
-            r = obj.diameter/2;
-            height = obj.rear.finsHeight;
-            C1 = obj.rear.finsRootChord;
-            C2 = obj.rear.finsFreeChord;
-            
-            Lcent = obj.lengthCenter;
-            Lnos = obj.parafoil.noseLength;
-            
-            Xle1 = Lcent + Lnos - obj.rear.finsAxialDistance - C1;
-            
-            Daft = obj.rear.boatFinalDiameter;
-            Laft = obj.rear.boatLength;
-            
-            xNos = Lnos - Lnos*cos(linspace(0, pi/2, 50));
-            if strcmp(obj.parafoil.noseType, 'KARMAN')
-                theta = @(x) acos( 1 - ( (2*x)./Lnos ) );
-                Karman = @(x) ( r/sqrt(pi) ) * sqrt( theta(x) - ( sin(2*theta(x))./ 2 ) );
-                yNos = Karman(xNos);
-            elseif strcmp(obj.parafoil.noseType, 'HAACK')
-                theta = @(x) acos( 1 - ( (2*x)./Lnos ) );
-                Haack = @(x) ( r/sqrt(pi) ) * sqrt( theta(x) - ( sin(2*theta(x))./ 2 ) + (1/3)*sin(theta(x)).^3 );
-                yNos = Haack(xNos);
-            elseif strcmp(obj.parafoil.noseType, 'OGIVE')
-                rho = (r^2 + Lnos^2)/(2*r);
-                Ogive = @(x) sqrt(rho^2 - (Lnos - x).^2) + r - rho;
-                yNos = Ogive(xNos);
-            elseif strcmp(obj.parafoil.noseType, 'POWER')
-                power = obj.parafoil.nosePower;
-                Power = @(x) r * (x/Lnos).^(power);
-                yNos = Power(xNos);
-            elseif strcmp(obj.parafoil.noseType, 'MHAACK')
-                p = obj.parafoil.nosePMod;
-                c = obj.parafoil.noseCMod;
-                xMod = @(x, p) (x/Lnos).^(p)*Lnos;
-                thetaMod = @(x, p) acos( 1 - ( (2*xMod(x, p))./Lnos ) );
-                haackSeriesMod = @(x, p, C) ( r/sqrt(pi) ) * sqrt( thetaMod(x, p) ...
-                    - ( sin(2*thetaMod(x, p))./ 2 ) + C*sin(thetaMod(x, p)).^3 );
-                yNos = haackSeriesMod(xNos, p, c);
-            end
-            
-            if strcmp(obj.rear.boatType, 'OGIVE') % [-] Boat-tail shape. 0: Cone, 1: Tangent Ogive
-                [xBoat, yBoat] = computeTangentBoatPoints(2*r, Daft, Laft);
-            else
-                xBoat = [0 Laft];
-                yBoat = [r Daft/2];
-            end
-            
-            %%% figure begin
-            img = figure();
-            hold on
-            
-            %%% NOSECONE
-            plot(xNos, yNos, 'k');
-            plot(xNos, -yNos, 'k');
-            plot([Lnos Lnos], [-r r], 'k');
-            
-            %%% CENTERBODY
-            plot([Lnos Lnos+Lcent], [r r], 'k');
-            plot([Lnos Lnos+Lcent], [-r -r], 'k');
-            plot([Lnos+Lcent Lnos+Lcent], [-r r], 'k');
-            
-            %%% BOAT-TAIL PLOT
-            plot(xBoat+Lnos+Lcent, yBoat, 'k');
-            plot(xBoat+Lnos+Lcent, -yBoat, 'k');
-            plot([Lnos+Lcent+Laft Lnos+Lcent+Laft], [-Daft/2 Daft/2], 'k');
-            
-            %%% FINS PLOT
-            % top
-            plot([Xle1 Xle1+deltaXLE], [r r+height],'k');
-            plot([Xle1+C1 Xle1+deltaXLE+C2], [r r+height],'k');
-            plot([Xle1+deltaXLE Xle1+deltaXLE+C2], [r+height r+height],'k');
-            plot([Xle1 Xle1+C1], [r r], 'k');
-            % bottom
-            plot([Xle1 Xle1+deltaXLE], [-r -r-height],'k');
-            plot([Xle1+C1 Xle1+deltaXLE+C2], [-r -r-height],'k');
-            plot([Xle1+deltaXLE Xle1+deltaXLE+C2], [-r-height, -r-height],'k');
-            plot([Xle1 Xle1+C1], [-r -r], 'k');
-            
-            % plot([Xle1 Xle1+deltaXLE], [r+height r+height], 'k--')
-            % plot([Xle1+deltaXLE Xle1+deltaXLE], [r+height r],'k--')
-            
-            %%% BAYS
-            lengths = obj.absolutePositions.values + 2*Lnos;
-            baysBody = obj.absolutePositions.keys;
-            iMotor = find(strcmp(obj.absolutePositions.keys,"motor"));
-            xline(0,'r-.', 'Label', 'NOSE', ...
-                'LabelOrientation', 'aligned', 'LabelVerticalAlignment', 'bottom', ...
-                'LabelHorizontalAlignment', 'right');
-            for i = 1:length(lengths)
-                if i == iMotor
-                    line([lengths(i) lengths(i)], [-1 1], 'LineStyle', '--', 'Color', 'b'); % Draw the line
-                    text(lengths(i), -1 + 0.3, baysBody(i), 'VerticalAlignment', 'top', ...
-                        'HorizontalAlignment', 'right', 'Rotation', 90, 'Color', 'b');
-                else
-                    line([lengths(i) lengths(i)], [-1 1], 'LineStyle', '--', 'Color', 'k'); % Draw the line
-                    text(lengths(i), 1 + 0.1, baysBody(i), 'VerticalAlignment', 'top', ...
-                        'HorizontalAlignment', 'right', 'Rotation', 90);
-                end
-            end
-            boatPlotLength = obj.length - obj.rear.boatLength;
-            xline(boatPlotLength,'r-.', 'Label', 'BOAT-TAIL', ...
-                'LabelOrientation', 'aligned', 'LabelVerticalAlignment', 'bottom', ...
-                'LabelHorizontalAlignment', 'right');
-            
-            axis equal
-            % set(gca, 'xlim', [-100, Lnos+Lcent+Laft+100]);
-            
-            %%% TITLE
-            title(string(strrep(obj.mission.name, '_', ' ')));
-        end
-        
-        
-        function checks = checkGeometry(obj)
-            % checkGeometry     - This methods checks if the rocket geometry
-            %                     is consistent with the geometry of the
-            %                     aerodynamic matrices
-            %
-            % OUTPUTS:
-            %                   - checks (n fields of geometry, 1): boolean value of the geometry checks
-            
-            xCgRocket = round([ ...
-                obj.xCg(1); ...
-                obj.xCg(end) ...
-                ], 3);
-            
-            xCgTest = round([
-                obj.coefficients.geometry.xcg(1);
-                obj.coefficients.geometry.xcg(end);
-                ], 3);
-            
-            if (obj.parafoil.noseCMod & obj.parafoil.nosePMod) == 0 % KARMAN ogive case, no modified p and c coefficients
-                geometryRocket = round([
-                    obj.diameter;
-                    obj.parafoil.noseLength;
-                    obj.lengthCenter;
-                    obj.rear.finsRootChord;
-                    obj.rear.finsFreeChord;
-                    obj.rear.finsHeight;
-                    obj.rear.finsDeltaXFreeChord;
-                    obj.rear.nPanel;
-                    obj.rear.boatLength;
-                    obj.rear.boatFinalDiameter;
-                    ], 3);
-                
-                geometryTest = round([
-                    obj.coefficients.geometry.diameter;
-                    obj.coefficients.geometry.lNose;
-                    obj.coefficients.geometry.lCenter;
-                    obj.coefficients.geometry.chord1;
-                    obj.coefficients.geometry.chord2;
-                    obj.coefficients.geometry.height;
-                    obj.coefficients.geometry.deltaXLE;
-                    obj.coefficients.geometry.nPanel;
-                    obj.coefficients.geometry.boatL;
-                    obj.coefficients.geometry.boatD;
-                    ], 3);
-            else % MHAAK ogive case, modified p and c coefficients
-                geometryRocket = round([
-                    obj.diameter;
-                    obj.parafoil.noseLength;
-                    obj.lengthCenter;
-                    obj.parafoil.noseCMod;
-                    obj.parafoil.nosePMod;
-                    obj.rear.finsRootChord;
-                    obj.rear.finsFreeChord;
-                    obj.rear.finsHeight;
-                    obj.rear.finsDeltaXFreeChord;
-                    obj.rear.nPanel;
-                    obj.rear.boatLength;
-                    obj.rear.boatFinalDiameter;
-                    ], 3);
-                
-                geometryTest = round([
-                    obj.coefficients.geometry.diameter;
-                    obj.coefficients.geometry.lNose;
-                    obj.coefficients.geometry.lCenter;
-                    obj.coefficients.geometry.cMod;
-                    obj.coefficients.geometry.pMod;
-                    obj.coefficients.geometry.chord1;
-                    obj.coefficients.geometry.chord2;
-                    obj.coefficients.geometry.height;
-                    obj.coefficients.geometry.deltaXLE;
-                    obj.coefficients.geometry.nPanel;
-                    obj.coefficients.geometry.boatL;
-                    obj.coefficients.geometry.boatD;
-                    ], 3);
-            end
-            
-            checks = [
-                xCgRocket == xCgTest;
-                strcmp(obj.coefficients.geometry.ogType, obj.parafoil.noseType);
-                geometryRocket == geometryTest;
-                strcmp(obj.coefficients.geometry.boatType, obj.rear.boatType)
-                ];
-        end
-    end
-end
\ No newline at end of file
diff --git a/classes/bays/@Motor/Motor.m b/classes/bays/@Motor/Motor.m
new file mode 100644
index 0000000..e49fe4e
--- /dev/null
+++ b/classes/bays/@Motor/Motor.m
@@ -0,0 +1,137 @@
+classdef Motor < Bay
+    % Motor: Represents the motor configuration for a rocket.
+    %
+    %   Constructor:
+    %       - Motor: Creates an instance of the Motor class.
+    %           Loaded config: rocketConfig.m > motor
+    %           Loaded data: motors.mat
+    %           Arguments:
+    %               - mission: Mission, mission object
+    %               - varIn: (optional) config source. Alternative to config.m file
+
+    %% Bay Implementation
+    properties(Dependent)
+        name                char                    % [-]  Motor name
+        mass                                        % [kg]      Total bay mass
+        inertia                                     % [kg*m^2]  Total bay inertia (Body reference)
+        xcg                                         % [m]       Xcg wrt bay top
+    end
+
+    properties(Access = private)
+        NAME                                        % [-]  Motor name
+        MASS                                        % [kg]      Total bay mass
+        INERTIA                                     % [kg*m^2]  Total bay inertia (Body reference)
+        XCG                                         % [m]       Xcg wrt bay top
+    end
+
+    %% Motor properties
+    properties(SetAccess = private)
+        type                (1, 1)  MotorType       % [-]  Motor type - Solid, Hybrid, Liquid
+        thrust              (1, :)  double          % [N]  Engine thrust vector
+        propellantMass      (1, :)  double          % [Kg] Propellant Mass in time
+        chamberPressure     (1, :)  double          % [Pa] Pressure inside combustion chamber
+        pe                  (1, :)  double          % [Pa] Eflux pressure
+    end
+
+    properties
+        time                double                  % [s]  Engine time vector
+        cutoffTime          double                  % [s]  Shutdown time
+        ignitionTransient   double                  % [s]  Ignition transient duration
+        cutoffTransient     double                  % [s]  Cutoff transient duration
+        tankLength          double                  % [m]  Tank length
+        fuelMass            double                  % [kg] Fuel grain initial mass
+        oxidizerMass        double                  % [kg] Oxidizer initial mass
+        structureMass       double                  % [kg] Engine Structural Mass
+        fuselageMass        double                  % [kg] Fuselage of the engine only
+        ae                  double                  % [Pa] Eflux Area
+    end
+
+    properties(Constant, Access = protected)
+        configName = 'rocketConfig.m'
+        variableName = 'motor'
+    end
+
+    properties(Access = private)
+        mission Mission = Mission()
+    end
+
+    methods
+        function obj = Motor(mission, varIn)
+            arguments(Input)
+                mission Mission = Mission()
+                varIn = []
+            end
+            obj@Bay(mission, varIn);
+            obj.mission = mission;
+            obj = obj.loadData();
+        end
+    end
+
+    methods (Access = private)
+        obj = loadData(obj)
+        out = validateTimeDependent(obj, value)
+    end
+
+    %% Bay implementation
+    % Getters
+    methods
+        function value = get.name(obj)
+            value = obj.NAME;
+        end
+
+        function value = get.mass(obj)
+            value = obj.MASS;
+        end
+
+        function value = get.inertia(obj)
+            value = obj.INERTIA;
+        end
+
+        function value = get.xcg(obj)
+            value = obj.XCG;
+        end
+    end
+
+    % Setters
+    methods
+        function obj = set.name(obj, name)
+            obj.NAME = name;
+            obj = obj.loadData();
+        end
+
+        function obj = set.mass(obj, mass)
+            value = obj.validateTimeDependent(mass);
+            obj.MASS = value;
+        end
+
+        function obj = set.inertia(obj, inertia)
+            value = obj.validateTimeDependent(inertia);
+            obj.INERTIA = value;
+        end
+
+        function obj = set.xcg(obj, xcg)
+            value = obj.validateTimeDependent(xcg);
+            obj.XCG = value;
+        end
+
+        function obj = set.thrust(obj, thrust)
+            value = obj.validateTimeDependent(thrust);
+            obj.thrust = value;
+        end
+
+        function obj = set.propellantMass(obj, propellantMass)
+            value = obj.validateTimeDependent(propellantMass);
+            obj.propellantMass = value;
+        end
+
+        function obj = set.chamberPressure(obj, chamberPressure)
+            value = obj.validateTimeDependent(chamberPressure);
+            obj.chamberPressure = value;
+        end
+
+        function obj = set.pe(obj, pe)
+            value = obj.validateTimeDependent(pe);
+            obj.pe = value;
+        end
+    end
+end
\ No newline at end of file
diff --git a/classes/bays/@Motor/loadData.m b/classes/bays/@Motor/loadData.m
new file mode 100644
index 0000000..460082b
--- /dev/null
+++ b/classes/bays/@Motor/loadData.m
@@ -0,0 +1,50 @@
+function obj = loadData(obj)
+
+if isempty(obj.name) || isempty(obj.mission.name)
+    return;
+end
+load(fullfile(obj.mission.dataPath, 'motors.mat'), 'motors');
+chosenMotor = motors(strcmp({motors.MotorName}, obj.name));
+
+if ~(isempty(obj.name) || isvarname(obj.name))
+    error('Motor name is not a valid MATLAB variable name')
+end
+
+if isempty(chosenMotor)
+    error(strcat('Unable to find engine: ', obj.name));
+end
+
+[obj.time, iUniqueTime] = unique(chosenMotor.t); 
+obj.thrust              = chosenMotor.T(iUniqueTime); 
+obj.propellantMass      = chosenMotor.m(iUniqueTime);
+obj.structureMass       = chosenMotor.mc;
+
+if contains(obj.name, 'HRE')
+    obj.type = "Hybrid";
+else 
+    obj.type = "Solid";
+end
+
+if obj.type == "Hybrid"
+    obj.length          = chosenMotor.L;
+    obj.tankLength      = chosenMotor.Ltank;      
+    obj.fuelMass        = chosenMotor.mFu;  
+    obj.oxidizerMass    = chosenMotor.mOx;        
+    inertiaRaw          = [chosenMotor.Ixx;chosenMotor.Iyy;chosenMotor.Izz];
+    obj.INERTIA         = inertiaRaw(:, iUniqueTime);
+    obj.XCG             = chosenMotor.xcg(iUniqueTime);  
+    obj.pe              = chosenMotor.Pe(iUniqueTime);   
+    obj.ae              = chosenMotor.Ae;   
+    obj.fuselageMass    = chosenMotor.mFus; 
+    obj.chamberPressure = chosenMotor.Pc;
+    obj.MASS            = obj.propellantMass + obj.structureMass;
+else
+    obj.length              = chosenMotor.L/1000; % lengths are saved in mm for solid motors
+    obj.xcg = obj.length/2 * ones(1, size(obj.time, 2));
+end
+
+if isempty(obj.cutoffTime) || obj.cutoffTime > obj.time(end)
+    obj.cutoffTime = obj.time(end);
+end
+
+end
\ No newline at end of file
diff --git a/classes/bays/@Motor/validateTimeDependent.m b/classes/bays/@Motor/validateTimeDependent.m
new file mode 100644
index 0000000..4583509
--- /dev/null
+++ b/classes/bays/@Motor/validateTimeDependent.m
@@ -0,0 +1,14 @@
+function out = validateTimeDependent(obj, value)
+len = length(obj.time);
+
+if isempty(obj.time), out = value; return; end
+if size(value, 2) == 1, out = repmat(value, 1, len); return; end
+if length(value) ~= length(obj.time)
+    error = MException( ...
+        'MSA:badInput', ...
+        'Incorrect dimensions: %s and time vector must be the same size', ...
+        property);
+    throwAsCaller(error);
+end
+out = value;
+end
\ No newline at end of file
diff --git a/classes/bays/Airbrakes.m b/classes/bays/Airbrakes.m
index dbb8478..73495d5 100644
--- a/classes/bays/Airbrakes.m
+++ b/classes/bays/Airbrakes.m
@@ -10,6 +10,13 @@ classdef Airbrakes < Bay
 %               - varIn: (optional) config source. Alternative to config.m
 %               file
     
+    %% Bay Implementation
+    properties
+        mass        % [kg]      Total bay mass
+        inertia     % [kg*m^2]  Total bay inertia (Body reference)
+        xcg         % [m]       Xcg wrt bay top
+    end
+
     properties
         enabled         logical         % If false, airbrakes will be kept closed during flight
         identification  logical         % If false, 
@@ -24,52 +31,44 @@ classdef Airbrakes < Bay
         servoTau        double
         servoOmega      double          % [rad/s] Servo-motor angular velocity
 
-        extension       double          % aerobrakes, 1-2-3 for 0%, 50% or 100% opened
+        extension       double          % aerobrakes, 0-1 for 0-100% opened
         deltaTime       double          % aerobrakes, configurations usage time
         maxMach         double          % [-] Maximum Mach at which airbrakes can be used
         height          double          % [m] Block airbrakes opening coordinate ( First entry must be 0! )
         angleFunction   function_handle % [-] Relation between angle and extension height
+    end 
 
-        position                        % [m] Offset with respect to other bays (negative -> shift forward)
-        length                          % [m] Total bay length
-        mass                            % [kg] Total bay mass
-        inertia                         % [kg*m^2] Total bay inertia (Body reference)
-        xCg                             % [m] Cg relative to bay upper side
+    properties(SetAccess = ?Rocket, GetAccess = private)
+        minTime                         % [s] Minimum time since engine fire at which airbrakes can open
     end
-    
-    properties(Access = protected)
-        configName = 'rocketConfig.m'
-        variableName = 'airbrakes'
-        mission Mission = Mission()
-        motor Motor = Motor()
-    end    
 
-    properties(Access = public)
+    properties(SetAccess = private)
         time        double
     end
 
-    methods
-        function obj = Airbrakes(mission, motor, varIn)
-            arguments(Input)
-                mission Mission = Mission()
-                motor   Motor   = Motor()
-                varIn = []
-            end
-            obj@Bay(mission, varIn);
-            obj.motor = motor;
+    properties(Constant, Access = protected)
+        configName = 'rocketConfig.m'
+        variableName = 'airbrakes'
+    end   
+
+    methods    
+        function obj = set.minTime(obj, minTime)
+            obj.minTime = minTime;
+            obj = obj.updateTime();
         end
-    
-        function set.motor(obj, motor)
-            obj.motor = motor;
-            obj.updateTime;
+
+        function obj = set.deltaTime(obj, deltaTime)
+            obj.deltaTime = deltaTime;
+            obj = obj.updateTime();
         end
-    end
 
-    methods
-        function updateTime(obj)
-            obj.time = cumsum(obj.deltaTime) + obj.motor.cutoffTime;
+        function obj = updateTime(obj)
+            if isempty(obj.deltaTime) || isempty(obj.minTime), return; end
+            obj.time = cumsum(obj.deltaTime) + obj.minTime;
         end
+    end
 
+    methods
         function extension = angle2Extension(obj, angle)
             extension = obj.angleFunction(angle) / obj.height(end);
         end
diff --git a/classes/bays/Electronics.m b/classes/bays/Electronics.m
index a9448aa..7f87a98 100644
--- a/classes/bays/Electronics.m
+++ b/classes/bays/Electronics.m
@@ -9,28 +9,16 @@ classdef Electronics < Bay
 %               - mission: Mission, mission object
 %               - varIn: (optional) config source. Alternative to config.m
 %               file
+
+    %% Bay Implementation
     properties
-        offset = 0
-        position    % [m] Absolute position, relative to nose base
-        length      % [m] Total bay length
-        mass        % [kg] Total bay mass
-        inertia     % [kg*m^2] Total bay inertia (Body reference)
-        xCg         % [m] Cg relative to bay upper side
+        mass        % [kg]      Total bay mass
+        inertia     % [kg*m^2]  Total bay inertia (Body reference)
+        xcg         % [m]       Xcg wrt bay top
     end
 
-    properties(Access = protected)
+    properties(Constant, Access = protected)
         configName = 'rocketConfig.m'
         variableName = 'electronics'
-        mission Mission = Mission()
-    end
-
-    methods
-        function obj = Electronics(mission, varIn)
-            arguments(Input)
-                mission Mission = Mission()
-                varIn = []
-            end
-            obj@Bay(mission, varIn);
-        end
     end
 end
\ No newline at end of file
diff --git a/classes/bays/Motor.m b/classes/bays/Motor.m
deleted file mode 100644
index 39f6ed2..0000000
--- a/classes/bays/Motor.m
+++ /dev/null
@@ -1,135 +0,0 @@
-classdef Motor < Bay
-    % Motor: Represents the motor configuration for a rocket.
-    %
-    %   Constructor:
-    %       - Motor: Creates an instance of the Motor class.
-    %           Loaded config: rocketConfig.m > motor
-    %           Loaded data: motors.mat
-    %           Arguments:
-    %               - mission: Mission, mission object
-    %               - varIn: (optional) config source. Alternative to config.m file
-
-    properties
-        name                {mustBeTextScalar} = '' % [-]  Motor name
-        position                                    % [m] Absolute position, relative to nose base
-        length                                      % [m]  Total length (motor + tank)
-        inertia                                     % [kg*m^2] Total Motor inertia (Body reference)
-        cutoffTime          double                  % [s]  Shutdown time
-        tankLength          double                  % [m]  Tank length
-        ignitionTransient   double                  % [s]  Ignition transient duration
-        cutoffTransient     double                  % [s]  Cutoff transient duration
-        time                double                  % [s]  Engine time vector
-        thrust              double                  % [N]  Engine thrust vector
-        fuelMass            double                  % [kg] Fuel (grain) initial mass
-        oxidizerMass        double                  % [kg] Oxidizer initial mass
-        propellantMass      double                  % [Kg] Propellant Mass (in time)
-        structureMass       double                  % [kg] Engine Structural Mass
-        fuselageMass        double                  % [kg] Fuselage of the engine only
-        chamberPressure     double                  % [Pa]  Pressure inside combustion chamber
-        xCg                                         % [m]  Engine xcg from tank tip
-        pe                  double                  % [Pa] Eflux pressure
-        ae                  double                  % [Pa] Eflux Area
-    end
-
-    properties
-        mass                                        % [kg] Total Motor mass
-        fuselageXCg         double                  % [m]  xcg of the engine fuselage only from tank tip
-    end
-
-    properties(Access = protected)
-        configName = 'rocketConfig.m'
-        variableName = 'motor'
-        mission Mission = Mission()
-    end
-
-    properties(SetAccess = protected)
-        isHRE             logical                   % [-] Flag relateed to the type of motor: true if HRE
-    end
-
-    properties(Access = private)
-        isBeingUpdated    logical  = false          % [-] Flag used internally when some properties are being updated
-    end
-    
-    methods
-        function obj = Motor(mission, varIn)
-            arguments(Input)
-                mission Mission = Mission()
-                varIn = []
-            end
-            obj@Bay(mission, varIn);
-            obj.loadData();
-            obj.updateAll();
-        end
-
-        function set.name(obj, name)
-            obj.name = name;
-            obj.changeState();
-            obj.loadData();
-            obj.updateAll();
-            obj.changeState();
-        end
-
-        function updateAll(obj)
-            obj.updateMass();
-        end
-
-        function changeState(obj)
-            obj.isBeingUpdated = not(obj.isBeingUpdated);
-        end
-
-        function updateMass(obj)
-            obj.fuselageXCg = (obj.length - ...
-                obj.tankLength)/2 + obj.tankLength;
-            obj.mass = obj.propellantMass + obj.structureMass;
-        end
-    end
-
-    methods (Access = protected)
-        function obj = loadData(obj)
-            if isempty(obj.mission.name) || isempty(obj.name)
-                return;
-            end
-            load(fullfile(obj.mission.dataPath, 'motors.mat'), 'motors');
-            chosenMotor = motors(strcmp({motors.MotorName}, obj.name));
-            
-            if ~(isempty(obj.name) || isvarname(obj.name))
-                error('Motor name is not a valid MATLAB variable name')
-            end
-
-            if isempty(chosenMotor)
-                error(strcat('Unable to find engine: ', obj.name));
-            end
-
-            [obj.time, iUniqueTime] = unique(chosenMotor.t); 
-            obj.thrust              = chosenMotor.T(iUniqueTime); 
-            obj.propellantMass      = chosenMotor.m(iUniqueTime);
-            obj.structureMass       = chosenMotor.mc;
-
-            obj.isHRE = contains(obj.name, 'HRE');
-
-            if obj.isHRE
-                obj.length          = chosenMotor.L;
-                obj.tankLength      = chosenMotor.Ltank;
-                if isempty(obj.tankLength)
-                    obj.tankLength = chosenMotor.LtankPr + chosenMotor.LtankOx;
-                end
-                obj.fuelMass        = chosenMotor.mFu;  
-                obj.oxidizerMass    = chosenMotor.mOx;        
-                inertiaRaw          = [chosenMotor.Ixx;chosenMotor.Iyy;chosenMotor.Izz];
-                obj.inertia         = inertiaRaw(:, iUniqueTime);
-                obj.xCg             = chosenMotor.xcg(iUniqueTime);  
-                obj.pe              = chosenMotor.Pe(iUniqueTime);   
-                obj.ae              = chosenMotor.Ae;   
-                obj.fuselageMass    = chosenMotor.mFus; 
-                obj.chamberPressure = chosenMotor.Pc;
-            else
-                obj.length              = chosenMotor.L/1000; % lengths are saved in mm for solid motors
-                obj.xCg = obj.length/2 * ones(1, size(obj.time, 2));
-            end
-
-            if isempty(obj.cutoffTime) || obj.cutoffTime > obj.time(end) || obj.isBeingUpdated
-                obj.cutoffTime = obj.time(end);
-            end
-        end
-    end
-end
\ No newline at end of file
diff --git a/classes/bays/MotorType.m b/classes/bays/MotorType.m
new file mode 100644
index 0000000..56cce1c
--- /dev/null
+++ b/classes/bays/MotorType.m
@@ -0,0 +1,8 @@
+classdef MotorType
+    enumeration
+        Solid
+        Hybrid
+        Liquid
+    end
+end
+
diff --git a/classes/bays/Parafoil.m b/classes/bays/Parafoil.m
index 378fb88..f87d709 100644
--- a/classes/bays/Parafoil.m
+++ b/classes/bays/Parafoil.m
@@ -9,7 +9,14 @@ classdef Parafoil < Bay
     %               - mission: Mission, mission object
     %               - varIn: (optional) config source. Alternative to config.m
     %               file
-    
+
+    %% Bay Implementation
+    properties
+        mass        % [kg]      Total bay mass
+        inertia     % [kg*m^2]  Total bay inertia (Body reference)
+        xcg         % [m]       Xcg wrt bay top
+    end
+
     properties
         noseLength  double                                       % [m] Nosecone length
         noseType   {mustBeMember(noseType, { ...
@@ -19,22 +26,15 @@ classdef Parafoil < Bay
         nosePower       double                                   % [-] Nosecone power type parameter
         nosePMod        double                                   % [-] P coefficient for modified nosecone shapes
         noseCMod        double                                   % [-] C coefficient for modified nosecone shapes
-        
-        position                                                 % [m] Absolute position, relative to nose base
-        length                                                   % [m] Total bay length
-        mass                                                     % [kg] Total bay mass
-        inertia                                                  % [kg*m^2] Total bay inertia (Body reference)
-        xCg                                                      % [m] Cg relative to bay upper side
     end
     
-    properties (Dependent)
-        inverseInertia  double
-    end
+    % properties (Dependent)
+    %     inverseInertia  double
+    % end
     
-    properties(Access = protected)
+    properties(Constant, Access = protected)
         configName = 'rocketConfig.m'
         variableName = 'parafoil'
-        mission Mission = Mission()
     end
     
     methods
@@ -47,9 +47,9 @@ classdef Parafoil < Bay
         end
     end
     
-    methods
-        function inverseInertia = get.inverseInertia(obj)
-            inverseInertia = inv(obj.inertiaMatrix);
-        end
-    end
+    % methods
+    %     function inverseInertia = get.inverseInertia(obj)
+    %         inverseInertia = inv(obj.inertiaMatrix);
+    %     end
+    % end
 end
\ No newline at end of file
diff --git a/classes/bays/Rear.m b/classes/bays/Rear.m
index 65d561d..2e713d5 100644
--- a/classes/bays/Rear.m
+++ b/classes/bays/Rear.m
@@ -10,13 +10,14 @@ classdef Rear < Bay
 %               - varIn: (optional) config source. Alternative to config.m
 %               file
 
+    %% Bay Implementation
+    properties
+        mass        % [kg]      Total bay mass
+        inertia     % [kg*m^2]  Total bay inertia (Body reference)
+        xcg         % [m]       Xcg wrt bay top
+    end
+    
     properties
-        position                                                            % [m] Absolute position, relative to nose base
-        length                                                              % [m] Total bay length
-        mass                                                                % [kg] Total bay mass
-        inertia                                                             % [kg*m^2] Total bay inertia (Body reference)
-        xCg                                                                 % [m] Cg relative to bay upper side
-
         boatType                    {mustBeMember(boatType, { ...
                                         '', 'CONE', 'OGIVE'})} = ''         % [] Boat type 
         boatLength                  double                                  % [m] Boat length
@@ -34,20 +35,9 @@ classdef Rear < Bay
         finsMaxThicknessPosition    double                                  % [m] Fraction of chord from leading edge to max thickness
     end
     
-    properties(Access = protected)
+    properties(Constant, Access = protected)
         configName = 'rocketConfig.m'
         variableName = 'rear'
-        mission Mission = Mission()
-    end
-
-    methods
-        function obj = Rear(mission, varIn)
-            arguments(Input)
-                mission Mission = Mission()
-                varIn = []
-            end
-            obj@Bay(mission, varIn);
-        end
     end
 end
 
diff --git a/classes/bays/Recovery.m b/classes/bays/Recovery.m
index b5d10de..40c7147 100644
--- a/classes/bays/Recovery.m
+++ b/classes/bays/Recovery.m
@@ -10,27 +10,15 @@ classdef Recovery < Bay
 %               - varIn: (optional) config source. Alternative to config.m
 %               file
 
+    %% Bay Implementation
     properties
-        position    % [m] Absolute position, relative to nose base
-        length      % [m] Total bay length
-        mass        % [kg] Total bay mass
-        inertia     % [kg*m^2] Total bay inertia (Body reference)
-        xCg         % [m] Cg relative to bay upper side
+        mass        % [kg]      Total bay mass
+        inertia     % [kg*m^2]  Total bay inertia (Body reference)
+        xcg         % [m]       Xcg wrt bay top
     end
 
-    properties(Access = protected)
+    properties(Constant, Access = protected)
         configName = 'rocketConfig.m'
         variableName = 'recovery'
-        mission Mission = Mission()
-    end
-
-    methods
-        function obj = Recovery(mission, varIn)
-            arguments(Input)
-                mission Mission = Mission()
-                varIn = []
-            end
-            obj@Bay(mission, varIn);
-        end
     end
 end
\ No newline at end of file
diff --git a/classes/components/Para.m b/classes/misc/ParaLoader.m
similarity index 51%
rename from classes/components/Para.m
rename to classes/misc/ParaLoader.m
index fb7388e..0046722 100644
--- a/classes/components/Para.m
+++ b/classes/misc/ParaLoader.m
@@ -1,4 +1,4 @@
-classdef Para < matlab.mixin.Heterogeneous & Component
+classdef ParaLoader < Config
     % Parachute: Represents a parachute component.
     %
     %   Constructor:
@@ -15,38 +15,28 @@ classdef Para < matlab.mixin.Heterogeneous & Component
     %   the third dimension can be trimmed away. 
     %   Do NOT consider the third dimension as valid
 
-    properties(Access = protected)
+    properties
+        parachutes
+    end
+
+    properties(Constant, Access = protected)
         configName = 'paraConfig.m'
         variableName = 'para'
-        mission Mission
     end
 
     methods
-        function obj = Para(mission, varIn)
+        function obj = ParaLoader(mission, varsIn)
             arguments(Input)
                 mission Mission = Mission()
-                varIn = []
+                varsIn = []
             end
-            obj@Component(mission, varIn, "elementWise", false);
-            
-            %% Forcing creation of heterogeneous array
-            if any(size(obj) > 1)
-                switch class(obj) 
-                    % In case of homogeneous type, forces conversion to
-                    % heterogeneous Para array
-                    case 'Parachute'
-                        obj(1, 1, 2) = Wing();
-                    case 'Wing'
-                        obj(1, 1, 2) = Parachute();
-                    otherwise
-                end
+
+            if isempty(mission.configPath), return; end
+            if isempty(varsIn)
+                varsIn = obj.getConfig(mission.configPath);
             end
-        end
-    end
 
-    methods (Static,Sealed,Access=protected)
-        function default = getDefaultScalarElement
-            default = Parachute;
+            obj.parachutes = varsIn.para;
         end
     end
 end
\ No newline at end of file
diff --git a/classes/components/Parachute.m b/classes/misc/Parachute.m
similarity index 85%
rename from classes/components/Parachute.m
rename to classes/misc/Parachute.m
index e16eb69..c706a1f 100644
--- a/classes/components/Parachute.m
+++ b/classes/misc/Parachute.m
@@ -1,4 +1,4 @@
-classdef Parachute < Para
+classdef Parachute
 % Parachute: Represents a parachute component.
 %
 %   Constructor:
@@ -28,17 +28,5 @@ classdef Parachute < Para
         nf               double                  % [-]      Adimensional Opening Time
         forceCoefficient double                  % [-]      Empirical coefficient to obtain correct peak force at deployment
     end
-
-    methods
-        function obj = Parachute(mission, varIn)
-            arguments(Input)
-                mission Mission = Mission()
-                varIn = []
-            end
-
-            obj@Para(mission, varIn);
-            obj = obj(:, :, 1);
-        end
-    end
 end
 
diff --git a/classes/components/Pitot.m b/classes/misc/Pitot.m
similarity index 81%
rename from classes/components/Pitot.m
rename to classes/misc/Pitot.m
index 1d8cd48..dd2d023 100644
--- a/classes/components/Pitot.m
+++ b/classes/misc/Pitot.m
@@ -1,4 +1,4 @@
-classdef Pitot < Component
+classdef Pitot < Config
 % Pitot: Represents a pitot tube.
 %
 %   Constructor:
@@ -19,19 +19,19 @@ classdef Pitot < Component
         finalConeDiameter       double      % [m] Pitot final conic section diameter
     end
 
-    properties(Access = protected)
+    properties(Constant, Access = protected)
         configName = 'rocketConfig.m'
         variableName = 'pitot'
-        mission Mission = Mission()
     end
 
     methods
-        function obj = Pitot(mission, varIn)
-            arguments(Input)
+        function obj = Pitot(mission, varsIn)
+            arguments (Input)
                 mission Mission = Mission()
-                varIn = []
+                varsIn          = []
             end
-            obj@Component(mission, varIn);
+
+            obj@Config(mission.configPath, varsIn);
         end
     end
 end
\ No newline at end of file
diff --git a/classes/components/WindCustom.m b/classes/misc/WindCustom.m
similarity index 100%
rename from classes/components/WindCustom.m
rename to classes/misc/WindCustom.m
diff --git a/classes/components/WindMatlab.m b/classes/misc/WindMatlab.m
similarity index 100%
rename from classes/components/WindMatlab.m
rename to classes/misc/WindMatlab.m
diff --git a/classes/components/Wing.m b/classes/misc/Wing.m
similarity index 85%
rename from classes/components/Wing.m
rename to classes/misc/Wing.m
index 4e47f9e..abab7f9 100644
--- a/classes/components/Wing.m
+++ b/classes/misc/Wing.m
@@ -1,4 +1,4 @@
-classdef Wing < Para
+classdef Wing
 % Parachute: Represents a parachute component.
 %
 %   Constructor:
@@ -18,7 +18,6 @@ classdef Wing < Para
         mass            double          % [kg]     Wing Mass
         openingTime     double          % [s]      Wing opening time (delay + time to get fully open)
 
-        inertia                         % [kg*m^2] 3x3 Inertia Matrix (the diagonal is made of the inertia vector values)
         finalAltitude   double          % [m]      Final altitude of the parafoil
         semiWingSpan    double          % [m]      Wing semiwingspan
         MAC             double          % [m]      Wing mean aero chord
@@ -45,29 +44,27 @@ classdef Wing < Para
         controlParams = []              % Struct containing all the control parameters
     end
 
+    properties(Dependent)
+        inertia                         % [kg*m^2] 3x3 Inertia Matrix (the diagonal is made of the inertia vector values)
+    end
+
     properties(SetAccess = private)
         inverseInertia
     end
 
-    methods
-        function obj = Wing(mission, varIn)
-            arguments(Input)
-                mission Mission = Mission()
-                varIn = []
-            end
-
-            obj@Para(mission, varIn);
-            obj = obj(:, :, 1);
-        end
+    properties(Access = private)
+        INERTIA
+    end
 
-        function set.inertia(obj, inertia)
-            obj.inertia = inertia;
-            obj.updateAll();
+    methods
+        function obj = set.inertia(obj, inertia)
+            obj.INERTIA = inertia;
+            if isempty(obj.inertia), return; end
+            obj.inverseInertia = obj.INERTIA\eye(3);
         end
 
-        function updateAll(obj)
-            if isempty(obj.inertia), return; end
-            obj.inverseInertia = obj.inertia\eye(3);
+        function inertia = get.inertia(obj)
+            inertia = obj.INERTIA;
         end
     end
 end
\ No newline at end of file
diff --git a/functions/miscellaneous/camel2UpperSnake.m b/functions/miscellaneous/camel2UpperSnake.m
new file mode 100644
index 0000000..a1d852b
--- /dev/null
+++ b/functions/miscellaneous/camel2UpperSnake.m
@@ -0,0 +1,6 @@
+function result = camel2UpperSnake(camelStr)
+    % Convert a camelCase string to UPPER_SNAKE_CASE
+    modifiedStr = regexprep(camelStr, '([A-Z])', '_$1');
+    upperStr = upper(modifiedStr);
+    result = regexprep(upperStr, '^_', ''); % Remove leading underscore if present
+end
\ No newline at end of file
diff --git a/missions/2025_Orion_Portugal_October/config/rocketConfig.m b/missions/2025_Orion_Portugal_October/config/rocketConfig.m
index 71e89f1..70935bb 100644
--- a/missions/2025_Orion_Portugal_October/config/rocketConfig.m
+++ b/missions/2025_Orion_Portugal_October/config/rocketConfig.m
@@ -1,13 +1,13 @@
 % CONFIG - This script sets up rocket's parameters
 
 %% ROCKET - OVERRIDES BAYS CONFIG
-rocket = Rocket();
-
-rocket.diameter = 0.15;                                                 % [m]      Rocket diameter
-rocket.massNoMotor = [];                                                % [kg]     OVERRIDE mass without motor
-rocket.inertiaNoMotor = [];                                             % [kg*m^2] OVERRIDE inertia without motor - body axes reference
-rocket.xCgNoMotor = [];                                                 % [m]      OVERRIDE xCg without motor
-rocket.lengthCenterNoMot = [];                                          % [m]      OVERRIDE Center length - no nose, no motor
+% rocket = Rocket();
+% 
+% rocket.diameter = 0.15;                                                 % [m]      Rocket diameter
+% rocket.massNoMotor = [];                                                % [kg]     OVERRIDE mass without motor
+% rocket.inertiaNoMotor = [];                                             % [kg*m^2] OVERRIDE inertia without motor - body axes reference
+% rocket.xCgNoMotor = [];                                                 % [m]      OVERRIDE xCg without motor
+% rocket.lengthCenterNoMot = [];                                          % [m]      OVERRIDE Center length - no nose, no motor
 
 %% PRF - Includes Parafoil + Nose
 parafoil = Parafoil();
@@ -15,7 +15,7 @@ parafoil = Parafoil();
 parafoil.length = 646.2 * 1e-3;                                         % [m] Total bay length
 parafoil.mass = 5;                                                   % [kg] Total bay mass
 parafoil.inertia = 1e-9*[10514313; 92235828; 92322682];                % [kg*m^2] Total bay inertia (Body reference)
-parafoil.xCg = 453.55 * 1e-3;                                            % [m] Cg relative to bay upper side
+parafoil.xcg = 453.55 * 1e-3;                                            % [m] Cg relative to bay upper side
 
 parafoil.noseLength = 0.327;                                              % [m] Nosecone length
 parafoil.noseType = 'MHAACK';                                            % [-] Nosecone shape
@@ -29,7 +29,7 @@ recovery = Recovery();
 recovery.length = 826 * 1e-3;                                        % [m] Total bay length
 recovery.mass = 4.452;                                               % [kg] Total bay mass
 recovery.inertia = 1e-9*[11889636; 274548189; 275245205];            % [kg*m^2] Total bay inertia (Body reference)
-recovery.xCg = 459 * 1e-3;                                        % [m] Cg relative to bay upper side
+recovery.xcg = 459 * 1e-3;                                        % [m] Cg relative to bay upper side
 
 %% ELC
 electronics = Electronics();
@@ -37,7 +37,7 @@ electronics = Electronics();
 electronics.length = 422.5 * 1e-3;                                   % [m] Total bay length
 electronics.mass = 3.3271;                                            % [kg] Total bay mass
 electronics.inertia = 1e-9*[10041478; 49742634; 50292878];            % [kg*m^2] Total bay inertia (Body reference)
-electronics.xCg = 221.11 * 1e-3;                                     % [m] Cg relative to bay upper side
+electronics.xcg = 221.11 * 1e-3;                                     % [m] Cg relative to bay upper side
 
 %% ARB
 airbrakes = Airbrakes();
@@ -47,7 +47,7 @@ airbrakes.identification = false;                           % Control parameter
 airbrakes.length = 54.8 * 1e-3;                                      % [m] Total bay length
 airbrakes.mass = 0.96;                                              % [kg] Total bay mass
 airbrakes.inertia = 1e-9*[1886729; 1931082; 3088968];                % [kg*m^2] Total bay inertia (Body reference)
-airbrakes.xCg = 35.2 * 1e-3;                                        % [m] Cg relative to bay upper side
+airbrakes.xcg = 35.2 * 1e-3;                                        % [m] Cg relative to bay upper side
 
 airbrakes.enabled = false;                                  % If true, multiple and smooth airbrakes opening will be simulated
 airbrakes.extension = [1];                                 % aerobrakes, 1-2-3 for 0%, 50% or 100% opened
@@ -82,7 +82,7 @@ rear.position = [];                                                  % [m] offse
 rear.length = 477 * 1e-3;                                         % [m] Total bay length
 rear.mass = 1736.32 *1e-3;                                           % [kg] Total bay mass
 rear.inertia = 1e-9*[13662070; 47529495; 47528846];                  % [kg*m^2] Total bay inertia (Body reference)
-rear.xCg = 236.82 * 1e-3;                                                                                               % [m] Cg relative to bay upper side
+rear.xcg = 236.82 * 1e-3;                                                                                               % [m] Cg relative to bay upper side
 
 rear.boatType = 'OGIVE';                                             % [-] Boat type
 rear.boatLength = 0.240;                                             % [m] Boat length
-- 
GitLab