diff --git a/missions/classes/Config.m b/missions/classes/Config.m new file mode 100644 index 0000000000000000000000000000000000000000..67d688cc906a7c9dfc77fb75a59e775acaffd190 --- /dev/null +++ b/missions/classes/Config.m @@ -0,0 +1,103 @@ +classdef(Abstract) Config < handle + % An abstraction class that enables a standardized management of data + % Grants the ability to load respective config + + properties(Abstract, Access = protected) + mission Mission + end + + properties(Access = protected, Abstract) + configName {mustBeTextScalar} + end + + methods(Access = protected) + function loadConfig(obj) + fileName = obj.configName; + filePath = obj.mission.configPath; + 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); + fields = getAvailableProperties(obj); + for j = 1:length(fields), obj.(fields{j}) = configObj.(fields{j}); end + end + + function varargout = getConfig(varargin) + varargout = cell(1, nargin-1); + missionTemp = varargin{1}.mission; + + %% LOAD desired configs + for i = 2:nargin + fileName = char(varargin{i}); + if ~isfile(fullfile(varargin{1}.mission.configPath, fileName)) + error(strcat("File not found inside the config folder: ", varargin{i})); + end + + varName = strtok(fileName,'C'); + run(fileName); + configObj = eval(varName); + + varargout{i-1} = configObj; + varargout{i-1}.mission = missionTemp; + end + end + + function propertiesOut = getAvailableProperties(obj) + % This function returns "available" properties + % Available means: not Dependent, not Hidden, public + mc = metaclass(obj); + ii = 0; + nProperties = length(mc.PropertyList); + properties = cell(1,nProperties); + for c = 1:nProperties + mp = mc.PropertyList(c); + if ~(mp.Dependent || mp.Hidden) && ... + strcmp(mp.GetAccess, 'public') && ... + strcmp(mp.SetAccess, 'public') + ii = ii + 1; + properties(ii) = {mp.Name}; + end + end + propertiesOut = properties(1:ii); + 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{:}); + end + function TF = ge(varargin) + TF = ge@handle(varargin{:}); + end + end +end \ No newline at end of file diff --git a/missions/classes/Environment.m b/missions/classes/Environment.m new file mode 100644 index 0000000000000000000000000000000000000000..58c5bf218acb296d2f793f72745c1ad419eca676 --- /dev/null +++ b/missions/classes/Environment.m @@ -0,0 +1,40 @@ +classdef Environment < Config + %ENVIRONMENT Summary of this class goes here + % Detailed explanation goes here + + properties + lat0 double % [deg] Launchpad latitude + lon0 double % [deg] Launchpad longitude + z0 double % [m] Launchpad Altitude + pin1Length double % [m] Distance from the upper pin to the upper tank cap + pin2Length double % [m] Distance from the lower pin to the lower tank cap + rampLength double % [m] Total launchpad length + temperature double % [deg] Ground temperature + pressure double % [Pa] Ground pressure + rho double % [Kg/m^3] Gorund air density + end + + properties(Dependent) + g0 double + end + + properties(Access = protected) + configName = 'environmentConfig.m' + mission Mission = Mission() + end + + methods + function obj = Environment(mission) + arguments + mission Mission = Mission() + end + obj.mission = mission(); + if nargin == 0, return; end + obj.loadConfig(); + end + + function g0 = get.g0(obj) + g0 = gravitywgs84(obj.z0, obj.lat0); % Gravity costant at launch latitude and altitude + end + end +end \ No newline at end of file diff --git a/missions/classes/Geometries.m b/missions/classes/Geometries.m new file mode 100644 index 0000000000000000000000000000000000000000..e65e55cce956fb572f7af51e10ce8b4db2456fb0 --- /dev/null +++ b/missions/classes/Geometries.m @@ -0,0 +1,57 @@ +classdef(InferiorClasses = {?Boat, ?Center, ?Nose, ?Pitot, ?Fins, ?Protuberances}) ... + Geometries < Config + %GEOMETRY Summary of this class goes here + % Detailed explanation goes here + + properties + boat Boat = Boat() + center Center = Center() % Center (Excluding motor) + nose Nose = Nose() + pitot Pitot = Pitot() + fins Fins = Fins() + protuberances Protuberances = Protuberances() + nXCg {mustBePositive, mustBeInteger} + xCgNoMotor double + end + + properties(Dependent) % Center + motor length + length double + xCg (1,:) double + end + + properties(Access = protected) + configName = 'geometryConfig.m' + mission Mission + motor Motor + mass Masses + end + + methods + function obj = Geometries(mission, motor, mass) + %GEOMETRY Construct an instance of this class + % Detailed explanation goes here + %obj; + arguments (Input) + mission Mission = Mission() + motor Motor = Motor() + mass Masses = Masses() + end + obj.mission = mission; + obj.motor = motor; + obj.mass = mass; + if nargin == 0, return; end + if nargin ~= 3, error('Wrong input arguments count: only specify 2 arguments'); end + obj.loadConfig(); + end + + function xCg = get.xCg(obj) + xCg = (obj.motor.totalMass.*(obj.center.noMotorLength + obj.motor.xCg) + ... + obj.mass.noMotor*obj.xCgNoMotor)./(obj.motor.totalMass + obj.mass.noMotor); + end + + function length = get.length(obj) + length = obj.center.length + ... + obj.motor.totalLength; + end + end +end \ No newline at end of file diff --git a/missions/classes/Masses.m b/missions/classes/Masses.m new file mode 100644 index 0000000000000000000000000000000000000000..949d9e85eeec556bbb9b1057d955dcbe48093293 --- /dev/null +++ b/missions/classes/Masses.m @@ -0,0 +1,44 @@ +classdef Masses < Config + %MASS Summary of this class goes here + % Detailed explanation goes here + + properties + noseCone % [kg] Nosecone Mass + noMotor + end + + properties(Dependent) + total % Total mass (in time) + structure % [kg] Total structural Mass + end + + properties(Access = protected) + configName = 'massConfig.m' + mission Mission + motor Motor + end + + methods + function obj = Masses(mission, motor) + arguments (Input) + mission Mission = Mission() + motor Motor = Motor() + end + obj.mission = mission; + obj.motor = motor; + if nargin == 0, return; end + if nargin ~= 2, error('Wrong input arguments count: only specify 2 arguments'); end + obj.loadConfig(); + end + + function total = get.total(obj) + total = obj.noMotor + obj.noseCone + ... + obj.motor.totalMass; % [kg] Total initial Mass + end + + function structure = get.structure(obj) + structure = obj.noMotor + obj.noseCone + ... + obj.motor.structureMass; % [kg] Total structural Mass + end + end +end \ No newline at end of file diff --git a/missions/classes/Mission.m b/missions/classes/Mission.m new file mode 100644 index 0000000000000000000000000000000000000000..d0d6a5742a63c400cfc9471f16dd99aeec512804 --- /dev/null +++ b/missions/classes/Mission.m @@ -0,0 +1,80 @@ +classdef Mission < handle + % Class containing names and paths to access mission files + % This should be the first class to be created, + % when running a tool. + % + % To get an empty Mission, run "Mission()", or "Mission(false)" + % To get an initialized Mission, run "Mission(true)" + % Where the argument specifies whether to read config files or not + + properties + name % Mission name, used to access <mission> folder + currentPath + end + + properties(Dependent) + configPath + dataPath + end + + properties(Access = protected) + configName = 'missionConfig.m' + end + + methods + function obj = Mission(loadConfig) + arguments + loadConfig {islogical} = false + end + if loadConfig, obj.loadConfig; end + end + + function path = get.configPath(obj) + if (obj.name), path = fullfile(obj.currentPath, obj.name, 'config'); + else, path = ''; + end + end + + function path = get.dataPath(obj) + if (obj.name), path = fullfile(obj.currentPath, obj.name, 'data'); + else, path = ''; + end + end + end + + methods(Access = private) + function loadConfig(obj) + fileName = obj.configName; + filePath = fullfile(fileparts(mfilename("fullpath")), '..'); + if ~isfile(fullfile(filePath, fileName)) + error(strcat("File not found inside the mission folder: ", filePath)); + end + + varName = strtok(fileName,'C'); + run(fileName); + configObj = eval(varName); + fields = getAvailableProperties(configObj); + for j = 1:length(fields), obj.(fields{j}) = configObj.(fields{j}); end + obj.currentPath = filePath; + end + + function propertiesOut = getAvailableProperties(obj) + % This function returns "available" properties + % Available means: not Dependent, not Hidden, public + mc = metaclass(obj); + ii = 0; + nProperties = length(mc.PropertyList); + properties = cell(1,nProperties); + for c = 1:nProperties + mp = mc.PropertyList(c); + if ~(mp.Dependent || mp.Hidden) && ... + strcmp(mp.GetAccess, 'public') && ... + strcmp(mp.SetAccess, 'public') + ii = ii + 1; + properties(ii) = {mp.Name}; + end + end + propertiesOut = properties(1:ii); + end + end +end \ No newline at end of file diff --git a/missions/classes/Motor.m b/missions/classes/Motor.m new file mode 100644 index 0000000000000000000000000000000000000000..5ccc1a52f3c4caa771325e801dbfbb7d59447315 --- /dev/null +++ b/missions/classes/Motor.m @@ -0,0 +1,82 @@ +classdef Motor < Config + %MOTOR Summary of this class goes here + % Detailed explanation goes here + + properties + name % [-] Motor name + totalLength % [m] Motor + Tank lenght + motorLength % [m] Motor length + tankLength % [m] Tank length + ignitionTime % [s] Ignition transient duration + cutoffTime % [s] Cutoff transient duration + time % [s] Engine time vector + thrust % [N] Engine thrust vector + fuelMass % [kg] Fuel (grain) initial mass + oxidizerMass % [kg] Oxidizer initial mass + propellantMass % [Kg] Propellant Mass (in time) + structureMass % [kg] Engine Structural Mass + fuselageMass % [kg] Fuselage of the engine only + xCg % [m] Engine xcg from tank tip + pe % [Pa] Eflux pressure + ae % [Pa] Eflux Area + end + + properties(Dependent) + totalMass % [kg] Total motor mass + fuselageXCg % [m] xcg of the engine fuselage only from tank tip + end + + properties(Access = protected) + configName = 'motorConfig.m' + mission Mission + end + + methods + function obj = Motor(mission) + arguments (Input) + mission Mission = Mission() + end + obj.mission = mission; + if nargin == 0, return; end + obj.loadConfig(); + obj.loadData(); + end + + function set.name(obj, name) + obj.name = name; + obj.loadData(); + end + + function totalMass = get.totalMass(obj) + totalMass = obj.propellantMass + ... + obj.structureMass + obj.fuselageMass; + end + function fuselageXCg = get.fuselageXCg(obj) + fuselageXCg = (obj.motorLength - ... + obj.tankLength)/2 + obj.tankLength; + end + end + + methods (Access = private) + 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(chosenMotor), error(strcat('Unable to find engine: ', obj.name)); end + + obj.motorLength = chosenMotor.L; % [m] Engine length + obj.tankLength = chosenMotor.Ltank; % [m] Tank length + obj.totalLength = obj.motorLength + obj.tankLength; + obj.time = chosenMotor.t; % [s] Engine time vector + obj.thrust = chosenMotor.T; % [N] Engine thrust vector + obj.fuelMass = chosenMotor.mFu; % [kg] Fuel (grain) initial mass + obj.oxidizerMass = chosenMotor.mOx; % [kg] Oxidizer initial mass + obj.propellantMass = chosenMotor.m; % [Kg] Propellant Mass (in time) + obj.structureMass = chosenMotor.mc; % [kg] Engine Structural Mass + obj.xCg = chosenMotor.xcg; % [m] Engine xcg from tank tip + obj.pe = chosenMotor.Pe; % [Pa] Eflux pressure + obj.ae = chosenMotor.Ae; % [Pa] Eflux Area + obj.fuselageMass = chosenMotor.mFus; % [kg] Fuselage of the engine onlyp + end + end +end \ No newline at end of file diff --git a/missions/classes/components/Boat.m b/missions/classes/components/Boat.m new file mode 100644 index 0000000000000000000000000000000000000000..afb58f028e46e790a80a939309107dd2383a3f49 --- /dev/null +++ b/missions/classes/components/Boat.m @@ -0,0 +1,9 @@ +classdef Boat + %GEOMETRY Summary of this class goes here + % Detailed explanation goes here + + properties + length double + diameter double + end +end \ No newline at end of file diff --git a/missions/classes/components/Center.m b/missions/classes/components/Center.m new file mode 100644 index 0000000000000000000000000000000000000000..07b59eee25d78402a333deb77ab991be9d5ac0ee --- /dev/null +++ b/missions/classes/components/Center.m @@ -0,0 +1,19 @@ +classdef Center + %CENTER Summary of this class goes here + % Detailed explanation goes here + + properties + length double + caliber double + end + + properties(Dependent) + crossSection double + end + + methods + function crossSection = get.crossSection(obj) + crossSection = pi*obj.caliber^2/4; + end + end +end \ No newline at end of file diff --git a/missions/classes/components/Fins.m b/missions/classes/components/Fins.m new file mode 100644 index 0000000000000000000000000000000000000000..edf1f3355a81878c06ef752fc6c1576ebae09d29 --- /dev/null +++ b/missions/classes/components/Fins.m @@ -0,0 +1,16 @@ +classdef Fins + %FINS Summary of this class goes here + % Detailed explanation goes here + + properties + 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 + end +end \ No newline at end of file diff --git a/missions/classes/components/Nose.m b/missions/classes/components/Nose.m new file mode 100644 index 0000000000000000000000000000000000000000..3820eac7a350cdea211be6683c0b79a310637928 --- /dev/null +++ b/missions/classes/components/Nose.m @@ -0,0 +1,12 @@ +classdef Nose + %NOSE Summary of this class goes here + % Detailed explanation goes here + + properties + length double % [m] Nosecone Length + ogiveType {mustBeTextScalar} = '' % [-] Nosecone shape + power double % [-] Nosecone power type parameter + p double % [-] P coefficient for modified nosecone shapes + c double % [-] C coefficient for modified nosecone shapes + end +end \ No newline at end of file diff --git a/missions/classes/components/Pitot.m b/missions/classes/components/Pitot.m new file mode 100644 index 0000000000000000000000000000000000000000..dd8af42352a7af2228a4efc0ae83cd26c06f4fc5 --- /dev/null +++ b/missions/classes/components/Pitot.m @@ -0,0 +1,13 @@ +classdef Pitot + %PITOT Summary of this class goes here + % Detailed explanation goes here + + properties + length double % [m] Pitot tube length + diameter double % [m] Pitot tube diameter + initialConeLength double % [m] Pitot initial conic section length + finalConeLength double % [m] Pitot final conic section length + initialConeDiameter double % [m] Pitot initial conic section diameter + finalConeDiameter double % [m] Pitot final conic section diameter + end +end \ No newline at end of file diff --git a/missions/classes/components/Protuberances.m b/missions/classes/components/Protuberances.m new file mode 100644 index 0000000000000000000000000000000000000000..a27673e6a1a099118cde9fe23a98980bbcbd9091 --- /dev/null +++ b/missions/classes/components/Protuberances.m @@ -0,0 +1,11 @@ +classdef Protuberances + %PROTUBERANCES Summary of this class goes here + % Detailed explanation goes here + + properties + n double % [-] number of brakes + length double % [m] brakes thickness + width double % [m] brakes width (normal) + xDistance double % [m] axial position from nosecone base + end +end \ No newline at end of file