diff --git a/classes/Config.m b/classes/Config.m index 760e923ad404a4ddfde4d3233c016dab5b19d83c..5572240a048890c4b7475fed571858683aed3baa 100644 --- a/classes/Config.m +++ b/classes/Config.m @@ -75,7 +75,7 @@ classdef(Abstract) Config < handle || ~isempty(prop.Validation) ... && ~isempty(prop.Validation.Class) ... && ~isempty(prop.Validation.Class.SuperclassList) ... - && any(strcmp(prop.Validation.Class.SuperclassList.Name, options.Superclass)); + && any(strcmp({prop.Validation.Class.SuperclassList.Name}, options.Superclass)); mc = metaclass(obj); ii = 0; diff --git a/classes/Rocket.m b/classes/Rocket.m index d42ac89f016f5cf695e783c1d1aa1ae819dacfed..4b59a325bc6934d40ed758672faac3cec251d582 100644 --- a/classes/Rocket.m +++ b/classes/Rocket.m @@ -11,24 +11,30 @@ classdef Rocket < Component % file properties - nose Nose = Nose() % [-] Nose bay - payload Payload = Payload() % [-] Payload bay - recovery Recovery = Recovery() % [-] Recovery bay - electronics Electronics = Electronics() % [-] Electronics bay - airbrakes Airbrakes = Airbrakes() % [-] Airbrakes bay - motor Motor = Motor() % [-] Motor bay - rear Rear = Rear() % [-] Rear bay - - pitot Pitot = Pitot() % [-] Pitot component - - length % [m] Total length - diameter % [m] Diameter - mass % [kg] Total mass - massNoMotor % [kg] Mass without motor - inertia % [] Total inertia - Axibody reference - inertiaNoMotor % [] Inertia without motor - xCg % [] Total xCg - xCgNoMotor % [] xCg without motor + payload Payload % [-] Payload 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 + + length double % [m] Total length + diameter double % [m] Diameter + mass double % [kg] Total mass + massNoMotor double % [kg] Mass without motor + inertia double % [] Total inertia - Axibody reference + inertiaNoMotor double % [] Inertia without motor + xCg double % [] Total xCg + xCgNoMotor double % [] xCg without motor + end + + properties(SetAccess = private) + absolutePositions % [m] Bay start positions - 0 is set at nose base + absolutePositionsNoMotor % [m] Bay start positions, no Motor - 0 is set at nose base + bays (1, :) Bay % [Bay] All bays + baysNoMotor (1, :) Bay % [Bay] All bays, except Motor end properties(Access = protected) @@ -37,20 +43,30 @@ classdef Rocket < Component mission Mission end - properties(SetAccess = private) - absolutePositions % [m] Bay start positions - 0 is set at nose base - absolutePositionsNoMotor % [m] Bay start positions, no Motor - 0 is set at nose base - bays (1, :) = Rear() % [Bay] All bays - baysNoMotor (1, :) = Rear() % [Bay] All bays, except Motor - end - methods % Updaters + function updateAbsolutePositions(obj) + b = obj.bays; + + % 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]); + + shift(overridesShift) = b(overrides).position; + shift(~overridesShift) = [b(~overridesShift).length]; + + absPositions = cumsum([-shift(1), shift(1:end-1)]); + obj.absolutePositions = absPositions; + obj.absolutePositionsNoMotor = [absPositions(1:4), absPositions(6:end)]; + end + function updateLength(obj) if ~isempty(obj.length) return; end - % Do not consider Boat length, as motor bay already covers boat - obj.length = sum([obj.bays(1:end-1).length]); + % Measures rear - tip + obj.length = (obj.absolutePositions(end) + obj.bays(end).length) - obj.absolutePositions(1); end function updateDiameter(obj) @@ -75,21 +91,6 @@ classdef Rocket < Component obj.mass = obj.massNoMotor + obj.motor.mass; end - function updateAbsolutePositions(obj) - out = zeros(1, size(obj.bays, 2)); - out(1) = -obj.bays(1).length; - for i = 2:size(obj.bays, 2) - bay = obj.bays(i); - if ~isempty(bay.position) - out(i) = sum([obj.bays(2:i-2).length, bay.position]); - continue; - end - out(i) = sum([obj.bays(2:i-1).length]); - end - obj.absolutePositions = out; - obj.absolutePositionsNoMotor = out([1:5, 7:end]); - end - function updateXCgNoMotor(obj) if ~isempty(obj.xCgNoMotor) return; @@ -113,9 +114,11 @@ classdef Rocket < Component return; end % [3x1] Ix, Iy, Iz - temp = [obj.baysNoMotor.inertia] + ... - ([obj.absolutePositionsNoMotor] + [obj.xCgNoMotor]).^2 .* obj.massNoMotor; - obj.inertiaNoMotor = sum(temp, 2); + % Assumption: xCgs are close to rocket axis + inertias = [obj.baysNoMotor.inertia]; + temp = inertias(2:3, :) + ... + (obj.xCgNoMotor - ([obj.absolutePositionsNoMotor] + [obj.baysNoMotor.xCg])).^2 .* [obj.baysNoMotor.mass]; + obj.inertiaNoMotor = [inertias(1); sum(temp, 2)]; end function updateInertia(obj) @@ -123,19 +126,23 @@ classdef Rocket < Component return; end % [3x634] Ix, Iy, Iz - obj.updateInertiaNoMotor(); - temp = [obj.motor.inertia] + ... - (obj.absolutePositions(6) + [obj.xCg]).^2 .* obj.mass; - obj.inertia = temp + obj.inertiaNoMotor; + % Assumption: xCgs are close to rocket axis + motorInertia = obj.motor.inertia(2:3, :) + ... + (obj.xCg - (obj.absolutePositions(5) + 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]; end function updateAll(obj) - % Note: properties without motor must be updated first + % Note: properties without motor must be updated first + obj.updateAbsolutePositions; obj.updateLength; obj.updateDiameter; obj.updateMassNoMotor; obj.updateMass; - obj.updateAbsolutePositions; obj.updateXCgNoMotor; obj.updateXCg; obj.updateInertiaNoMotor; @@ -157,7 +164,6 @@ classdef Rocket < Component return; end vars = obj.getConfig(); % Load config once and apply to other bays - obj.nose = Nose(mission, vars); obj.payload = Payload(mission, vars); obj.recovery = Recovery(mission, vars); obj.electronics = Electronics(mission, vars); @@ -167,9 +173,8 @@ classdef Rocket < Component obj.pitot = Pitot(mission, vars); [~, obj.bays] = obj.getProperties(Superclass='Bay', Heterogeneous=1); - obj.baysNoMotor = [obj.bays(1:5), obj.bays(7:end)]; % Take all bays except motor + obj.baysNoMotor = [obj.bays(1:4), obj.bays(6:end)]; % Take all bays except motor obj.updateAll(); end end -end - +end \ No newline at end of file diff --git a/classes/Settings.m b/classes/Settings.m index 4d2e97ddea90ecab9c9a51f93404023734c0727e..9afdc2c433dea2d28665cdf3ec6cc080e5eb0919 100644 --- a/classes/Settings.m +++ b/classes/Settings.m @@ -51,7 +51,7 @@ classdef Settings < Config & dynamicprops outputVariables = struct(); for i = 1:length(configNames) fileName = configNames{i}; - filePath = fullfile(fileparts(mfilename("fullpath")), '..', 'missions', 'settings'); + filePath = fullfile(fileparts(mfilename("fullpath")), '..', 'settings'); if ~isfile(fullfile(filePath, fileName)) % Get caller function path callers = dbstack("-completenames"); diff --git a/classes/bays/Payload.m b/classes/bays/Payload.m index 1c94ad74993995d77424fa70636ca75d5d58edfc..03111037774243be6f1725fa2a4f5a7401372304 100644 --- a/classes/bays/Payload.m +++ b/classes/bays/Payload.m @@ -1,5 +1,5 @@ classdef Payload < Bay -% Payload: Represents payload configuration for a rocket. +% Payload: Represents nose + payload configuration for a rocket. % % Constructor: % - Payload: Creates an instance of the Payload class. @@ -11,12 +11,21 @@ classdef Payload < Bay % file properties - position % [m] Absolute position, relative to nose base - length % [m] Total bay length - diameter % [m] Diameter of the bay - mass % [kg] Total bay mass - inertia % [kg*m^2] Total bay inertia (Body reference) - xCg % [m] Cg relative to bay upper side + noseLength double % [m] Nosecone length + ogiveType {mustBeMember(ogiveType, { ... + '', 'CONE', 'OGIVE', ... + 'POWER', 'HAACK', 'KARMAN', ... + 'MHAACK'})} = '' % [-] Nosecone shape + power double % [-] Nosecone power type parameter + pMod double % [-] P coefficient for modified nosecone shapes + cMod double % [-] C coefficient for modified nosecone shapes + + position % [m] Absolute position, relative to nose base + length % [m] Total bay length + diameter % [m] Diameter of the bay + mass % [kg] Total bay mass + inertia % [kg*m^2] Total bay inertia (Body reference) + xCg % [m] Cg relative to bay upper side end properties(Access = protected) diff --git a/classes/bays/Rear.m b/classes/bays/Rear.m index 6077c828c9b773ef2866b2a48a357884e28140aa..06cf64a8fb0f7d11c51310b31102335bc6ca468e 100644 --- a/classes/bays/Rear.m +++ b/classes/bays/Rear.m @@ -11,27 +11,28 @@ classdef Rear < Bay % file properties - position % [m] Absolute position, relative to nose base - length % [m] Total bay length - diameter % [m] Final diameter of the bay - mass % [kg] Total bay mass - inertia % [kg*m^2] Total bay inertia (Body reference) - xCg % [m] Cg relative to bay upper side + position % [m] Absolute position, relative to nose base + length % [m] Total bay length + diameter % [m] Final diameter of the bay + mass % [kg] Total bay mass + inertia % [kg*m^2] Total bay inertia (Body reference) + xCg % [m] Cg relative to bay upper side - type {mustBeMember(type, {'', 'CONE', 'OGIVE'})} = '' % [] Boat type - boatLength double % [m] Boat length - finalDiameter double % [m] Boat end diameter + boatType {mustBeMember(boatType, { ... + '', 'CONE', 'OGIVE'})} = '' % [] Boat type + boatLength double % [m] Boat length + boatFinalDiameter double % [m] Boat end diameter - deltaXRootChord double % [m] start of Chord 1 measured from beginning of bay - rootChord double % [m] attached chord length - freeChord double % [m] free chord length - height double % [m] fin heigth - deltaXFreeChord double % [m] start of Chord 2 measured from start of Chord 1 - nPanel double % [m] number of fins - leadingEdgeRadius double % [deg] Leading edge radius at each span station - axialDistance double % [m] distance between end of root chord and end of center body - semiThickness double % [m] fin semi-thickness - maxThicknessPosition double % [m] Fraction of chord from leading edge to max thickness + finsDeltaXRootChord double % [m] start of Chord 1 measured from beginning of bay + finsRootChord double % [m] attached chord length + finsFreeChord double % [m] free chord length + finsHeight double % [m] fin heigth + finsDeltaXFreeChord double % [m] start of Chord 2 measured from start of Chord 1 + nPanel double % [m] number of fins + finsLeadingEdgeRadius double % [deg] Leading edge radius at each span station + finsAxialDistance double % [m] distance between end of root chord and end of center body + finsSemiThickness double % [m] fin semi-thickness + finsMaxThicknessPosition double % [m] Fraction of chord from leading edge to max thickness end properties(Access = protected) diff --git a/missions/2024_Lyra_Roccaraso_September/config/rocketConfig.m b/missions/2024_Lyra_Roccaraso_September/config/rocketConfig.m index debc69977bf780c81104480da07aad0162913982..0691b5b4e6310cba8ca1a4d34db86d4905966fff 100644 --- a/missions/2024_Lyra_Roccaraso_September/config/rocketConfig.m +++ b/missions/2024_Lyra_Roccaraso_September/config/rocketConfig.m @@ -12,21 +12,7 @@ rocket.inertiaNoMotor = []; % [kg*m^2] OVERRIDE inerti rocket.xCg = []; % [m] OVERRIDE total xCg rocket.xCgNoMotor = []; % [m] OVERRIDE xCg without motor -%% NOSE -nose = Nose(); - -nose.length = 0.3; % [m] Nosecone Length -nose.diameter = 0.15; % [m] Nosecone Diameter -nose.mass = 0.50188; % [m] Nosecone Mass -nose.inertia = ... - [1182201; 219929; 2241000]*1e-9; % [kg*m^2] Nosecone Inertia - Axibody reference -nose.ogiveType = 'MHAACK'; % [-] Nosecone shape -nose.power = 3/4; % [-] Nosecone power type parameter -nose.pMod = 1.250152e+00; % [-] P coefficient for modified nosecone shapes -nose.cMod = 1.799127e-01; % [-] C coefficient for modified nosecone shapes -nose.xCg = 0.10459; % [m] Nosecone xCg - -%% PLD +%% PLD - Includes Payload + Nose payload = Payload(); payload.length = 0.32; % [m] Total bay length @@ -35,7 +21,15 @@ payload.mass = 3.38512; % [kg] Total bay mass payload.inertia = ... [1032892397; 5461775539; 5450863094]*1e-9; % [kg*m^2] Total bay inertia (Body reference) payload.xCg = 0.22734; % [m] Cg relative to bay upper side - + +payload.noseLength = 0.32; % [m] Nosecone length +payload.ogiveType = 'MHAACK'; % [-] Nosecone shape +payload.power = 3/4; % [-] Nosecone power type parameter +payload.pMod = 1.250152e+00; % [-] P coefficient for modified nosecone shapes +payload.cMod = 1.799127e-01; % [-] C coefficient for modified nosecone shapes + +payload.xCg = 0.10459; % [m] Nosecone xCg + %% RCS recovery = Recovery(); @@ -59,6 +53,13 @@ electronics.xCg = 0.22968; % [m] Cg relative to bay u %% ARB airbrakes = Airbrakes(); +airbrakes.length = 0.0548; % [m] Total bay length +airbrakes.diameter = 0.15; % [m] Diameter of the bay +airbrakes.mass = 0.99429; % [kg] Total bay mass +airbrakes.inertia = ... + [78545425; 41163849; 41163849]*1e-9; % [kg*m^2] Total bay inertia (Body reference) +airbrakes.xCg = 0.03967; % [m] Cg relative to bay upper side + airbrakes.multipleAB = false; % If true, multiple and smooth airbrakes opening will be simulated airbrakes.opening = [1 3]; % aerobrakes, 1-2-3 for 0%, 50% or 100% opened airbrakes.deltaTime = [10]; % aerobrakes, configurations usage time @@ -69,13 +70,6 @@ airbrakes.width = 0.1002754821; % [m] brakes width (normal airbrakes.thickness = 0.008; % [m] brakes thickness airbrakes.xDistance = 1.517; % [m] axial position from nosecone base -airbrakes.length = 0.0548; % [m] Total bay length -airbrakes.diameter = 0.15; % [m] Diameter of the bay -airbrakes.mass = 0.99429; % [kg] Total bay mass -airbrakes.inertia = ... - [78545425; 41163849; 41163849]*1e-9; % [kg*m^2] Total bay inertia (Body reference) -airbrakes.xCg = 0.03967; % [m] Cg relative to bay upper side - airbrakes.minTime = 0; % [s] time after which the airbrakes can be used airbrakes.maxMach = 0.8; % [-] Maximum Mach at which airbrakes can be used airbrakes.servoOmega = 150*pi/180; % [rad/s] Servo-motor angular velocity @@ -88,13 +82,13 @@ motor.cutoffTime = inf; % [s] Cutoff time motor.ignitionTransient = 0.4; % [s] Ignition transient motor.cutoffTransient = 0.3; % [s] Cut-off transient -%% REAR - FICNAN + BOAT +%% REAR - Includes Fincan + Boat rear = Rear(); -rear.position = 1.3; -rear.length = 0.5585; % [m] Total bay length -rear.diameter = 0.15; % [m] Diameter of the bay -rear.mass = 1.61926; % [kg] Total bay mass +rear.position = 1.086; +rear.length = 0.5585; % [m] Total bay length +rear.diameter = 0.15; % [m] Diameter of the bay +rear.mass = 1.61926; % [kg] Total bay mass rear.inertia = ... [13054773; 44192627; 44193468]*1e-9; % [kg*m^2] Total bay inertia (Body reference) rear.xCg = 0.25358; % [m] Cg relative to bay upper side @@ -116,7 +110,7 @@ rear.finsMaxThicknessPosition = 0.00175; % [m] Fraction of chord fr %% PITOT pitot = Pitot(); -pitot.length = 0.07452; % [m] Pitot tube length +pitot.length = 0.04777; % [m] Pitot tube length pitot.diameter = 0; % [m] Pitot tube diameter pitot.initialConeLength = 0; % [m] Pitot initial conic section length pitot.finalConeLength = 0; % [m] Pitot final conic section length diff --git a/missions/settings/odeConfig.m b/settings/odeConfig.m similarity index 100% rename from missions/settings/odeConfig.m rename to settings/odeConfig.m