From 7b110d6d9c82162c10a2985cbd9ff72832fce6f3 Mon Sep 17 00:00:00 2001 From: Mauco03 <marco.gaibotti@skywarder.eu> Date: Mon, 21 Apr 2025 21:03:58 +0200 Subject: [PATCH 1/8] [alpha-phi] Moved enums to dedicated folder --- classes/enums/CoeffType.m | 7 +++++++ classes/{bays => enums}/MotorType.m | 0 2 files changed, 7 insertions(+) create mode 100644 classes/enums/CoeffType.m rename classes/{bays => enums}/MotorType.m (100%) diff --git a/classes/enums/CoeffType.m b/classes/enums/CoeffType.m new file mode 100644 index 0000000..85e051c --- /dev/null +++ b/classes/enums/CoeffType.m @@ -0,0 +1,7 @@ +classdef CoeffType + enumeration + AlphaTotPhi + AlphaBeta + end +end + diff --git a/classes/bays/MotorType.m b/classes/enums/MotorType.m similarity index 100% rename from classes/bays/MotorType.m rename to classes/enums/MotorType.m -- GitLab From cae902b74bd55cde455880b0d101301de1cada57 Mon Sep 17 00:00:00 2001 From: Mauco03 <marco.gaibotti@skywarder.eu> Date: Mon, 21 Apr 2025 21:04:40 +0200 Subject: [PATCH 2/8] [alpha-phi] Implementing coefficient type enum and symmetry flag --- classes/misc/Coefficient.m | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/classes/misc/Coefficient.m b/classes/misc/Coefficient.m index 02f721d..b41b341 100644 --- a/classes/misc/Coefficient.m +++ b/classes/misc/Coefficient.m @@ -59,10 +59,12 @@ classdef Coefficient < Structured dynamic double % Dynamic derivatives: [Clp, Cmad, Cmq, Cnr, Cnp] end - properties(SetAccess = private) - isReady (1, 1) logical % Whether all coefficients are loaded and of the right size - isDynamic (1, 1) logical % Whether to load dynamic derivatives. Adds XCG dependece + type CoeffType % Wheter based on alphaTot-phi or alpha-beta + symmetry (1, 1) logical % Apply axial simmetry: valid for alphaTot-phi + + isReady (1, 1) logical % Whether all coefficients are loaded and of the right size + isDynamic (1, 1) logical % Whether to load dynamic derivatives. Adds XCG dependece end properties(Access = private) @@ -197,6 +199,14 @@ classdef Coefficient < Structured end function obj = set.state(obj, value) + if isfield(value, 'phis') && ~isempty(value.phis) + if ~isempty(value.betas), error('Cannot set both alpha, beta and phi'); end + obj.type = CoeffType.AlphaTotPhi; + obj.symmetry = (360/obj.STATE.phis(end) == obj.GEOMETRY.nPanel); + else + obj.type = CoeffType.AlphaBeta; + end + obj.STATE = value; obj.isReady = obj.checkProperties(); obj = obj.updateChad(); -- GitLab From 6efc8ebd2113b58b28abf31cdd4de986ec897f24 Mon Sep 17 00:00:00 2001 From: Mauco03 <marco.gaibotti@skywarder.eu> Date: Tue, 22 Apr 2025 11:05:32 +0200 Subject: [PATCH 3/8] [alpha-phi] Improved checks --- classes/misc/Coefficient.m | 30 ++++++++++++++++---- functions/miscellaneous/createDissileInput.m | 9 +++--- 2 files changed, 29 insertions(+), 10 deletions(-) diff --git a/classes/misc/Coefficient.m b/classes/misc/Coefficient.m index b41b341..01e508e 100644 --- a/classes/misc/Coefficient.m +++ b/classes/misc/Coefficient.m @@ -192,6 +192,10 @@ classdef Coefficient < Structured end function obj = set.geometry(obj, value) + if ~isempty(obj.STATE) && isfield(obj.STATE, 'phis') && ~isempty(obj.STATE.phis) + obj.symmetry = (360/obj.STATE.phis(end) == value.nPanel); + end + obj.GEOMETRY = value; obj.isReady = obj.checkProperties(); obj = obj.updateChad(); @@ -200,9 +204,13 @@ classdef Coefficient < Structured function obj = set.state(obj, value) if isfield(value, 'phis') && ~isempty(value.phis) - if ~isempty(value.betas), error('Cannot set both alpha, beta and phi'); end + if ~isempty(value.betas) + error('Cannot set both alpha, beta and phi'); + end + if ~isempty(obj.GEOMETRY) + obj.symmetry = (360/value.phis(end) == obj.GEOMETRY.nPanel); + end obj.type = CoeffType.AlphaTotPhi; - obj.symmetry = (360/obj.STATE.phis(end) == obj.GEOMETRY.nPanel); else obj.type = CoeffType.AlphaBeta; end @@ -251,12 +259,17 @@ classdef Coefficient < Structured alpha = obj.STATE.alphas; mach = obj.STATE.machs; - beta = obj.STATE.betas; altitude = obj.STATE.altitudes; airbakes = obj.STATE.hprot; xcg = obj.GEOMETRY.xcg; - gridVecs = {alpha, mach, beta, altitude, airbakes, xcg}; + if obj.type == CoeffType.AlphaBeta + theta = obj.STATE.betas; % Converting to rad + else + theta = obj.STATE.phis; % Converting to rad + end + + gridVecs = {alpha, mach, theta, altitude, airbakes, xcg}; dims = cellfun(@(x) length(x), gridVecs); dims(dims == 0) = 1; % Empty case is the same as scalar case @@ -270,15 +283,20 @@ classdef Coefficient < Structured %% Retrieve flight conditions alpha = obj.STATE.alphas*pi/180; % Converting to rad mach = obj.STATE.machs; - beta = obj.STATE.betas*pi/180; % Converting to rad altitude = obj.STATE.altitudes; xcg = obj.GEOMETRY.xcg; if isempty(obj.STATE.hprot), airbakes = 0; else, airbakes = obj.STATE.hprot/obj.STATE.hprot(end); % Normalizing on height end + + if obj.type == CoeffType.AlphaBeta + theta = obj.STATE.betas*pi/180; % Converting to rad + else + theta = obj.STATE.phis*pi/180; % Converting to rad + end - gridVecs = {alpha, mach, beta, altitude, airbakes, xcg}; + gridVecs = {alpha, mach, theta, altitude, airbakes, xcg}; % Find singleton dims (last dimension is coefficients and will not be of length 1) singletonDims = cellfun(@(x) isscalar(x) || isempty(x), gridVecs); diff --git a/functions/miscellaneous/createDissileInput.m b/functions/miscellaneous/createDissileInput.m index 39bc2b0..1c3f5ee 100644 --- a/functions/miscellaneous/createDissileInput.m +++ b/functions/miscellaneous/createDissileInput.m @@ -49,12 +49,12 @@ if not(any(vars.alpha == 1)) error('vars.alpha does not contains 1'); end -if not(any(vars.alpha == -1)) - error('vars.alpha does not contains -1'); +if isempty(vars.phi) && not(any(vars.alpha == -1)) + error('vars.alpha does not contain -1 in alpha-beta configuration'); end -if not(isequal(vars.alpha, -fliplr(vars.alpha))) - error('vars.alpha is not symmetric'); +if isempty(vars.phi) && not(isequal(vars.alpha, -fliplr(vars.alpha))) + error('vars.alpha is not symmetric in alpha-beta configuration'); end % if any(vars.abk > 1) @@ -69,6 +69,7 @@ input.fltcon.about = 'Flight conditions quantities'; input.fltcon.MACH = vars.mach; input.fltcon.ALPHA = vars.alpha; input.fltcon.BETA = vars.beta; +input.fltcon.PHI = vars.phi; input.fltcon.ALT = vars.alt; %% REFQ -- GitLab From b1293f6c2a187cb6a29837668ecc05b8b85e717a Mon Sep 17 00:00:00 2001 From: Mauco03 <marco.gaibotti@skywarder.eu> Date: Sat, 26 Apr 2025 22:48:52 +0200 Subject: [PATCH 4/8] [alpha-phi][Coefficient] Implemented coefficient transport --- classes/misc/Coefficient.m | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/classes/misc/Coefficient.m b/classes/misc/Coefficient.m index 01e508e..14ab717 100644 --- a/classes/misc/Coefficient.m +++ b/classes/misc/Coefficient.m @@ -93,7 +93,7 @@ classdef Coefficient < Structured obj = obj.updateInterpolants(); end - function coefficients = get(obj, alpha, mach, beta, altitude, airbakes, xcg) + function [coefficients] = get(obj, alpha, mach, beta, altitude, airbakes, xcg) % GET: Retrieve aerodynamic coefficients for specified flight conditions % % This method interpolates the aerodynamic coefficients based on @@ -118,10 +118,31 @@ classdef Coefficient < Structured if ~obj.isReady, error('Cannot interpolate coefficients: check that all dimensions match'); end + % Interpolating coefficients coefficients = zeros(11, 1); - coefficients(1:6) = obj.staticInterpolant(alpha, mach, beta, altitude, airbakes); - % Transporting static coefficients to new xcg + if obj.type == CoeffType.AlphaBeta + coefficients(1:6) = obj.staticInterpolant(alpha, mach, beta, altitude, airbakes); + else + [alphaTot, phi] = getAlphaPhi(alpha, beta); + phi = wrapTo2Pi(phi); + + finAngle = 2*pi / obj.GEOMETRY.nPanel; % Angle between two fin panels + n = floor(phi / finAngle); + deltaPhi = n*finAngle; + psi = phi - deltaPhi; % Angle wrapped to finAngle + + coefficients(1:6) = obj.staticInterpolant(alphaTot, mach, psi, altitude, airbakes); % Get coeffs in limited range + + if n > 1 % If necessary, perform rotation on different frame + R = [cos(deltaPhi), -sin(deltaPhi); + sin(deltaPhi), cos(deltaPhi)]; + + coefficients([2, 3]) = R * coefficients([2, 3]); + coefficients([5, 6]) = R' * coefficients([5, 6]); + end + end + % Transporting static coefficients to new xcg % C_B = C_A + d / c * [0; -CN; CY]_A <- NOTE: Non torna il meno su CN d = xcg - obj.GEOMETRY.xcg(1); l = obj.GEOMETRY.diameter; @@ -132,6 +153,9 @@ classdef Coefficient < Structured coefficients(4:6) = coefficients(4:6) + d/l * forceCoeffs; if ~obj.isDynamic, return; end + if obj.type == CoeffType.AlphaTotPhi + error('Alpha-Phi coefficients do not support dynamic derivatives yet') + end coefficients(7:11) = obj.dynamicInterpolant(alpha, mach, beta, altitude, airbakes, xcg); end -- GitLab From ba45c68e00961cd4a520fd0d00585dcc485f6d86 Mon Sep 17 00:00:00 2001 From: Mauco03 <marco.gaibotti@skywarder.eu> Date: Sun, 27 Apr 2025 00:28:43 +0200 Subject: [PATCH 5/8] [alpha-phi][Rocket] Added option to not load highAOA matrices --- classes/@Rocket/Rocket.m | 16 ++++++++++------ .../config/rocketConfig.m | 1 + .../config/rocketConfig.m | 1 + .../config/rocketConfig.m | 1 + .../config/rocketConfig.m | 1 + .../config/rocketConfig.m | 2 +- .../config/rocketConfig.m | 1 + .../config/rocketConfig.m | 1 + .../config/rocketConfig.m | 1 + .../config/rocketConfig.m | 3 ++- 10 files changed, 20 insertions(+), 8 deletions(-) diff --git a/classes/@Rocket/Rocket.m b/classes/@Rocket/Rocket.m index a7796d4..f050235 100644 --- a/classes/@Rocket/Rocket.m +++ b/classes/@Rocket/Rocket.m @@ -52,7 +52,8 @@ classdef Rocket < Config parachutes Para % [-] (nParachutes, nStages) Parachutes onboard dynamicDerivatives (1, 1) logical % [-] True if dynamic derivatives will be loaded - + highAOACoefficients (1, 1) logical % [-] True if highAOACoefficients are loaded + coefficients Coefficient % [-] Aerodynamic coefficients coefficientsHighAOA Coefficient % [-] Aerodynamic coefficients at high angle of attack end @@ -149,13 +150,16 @@ classdef Rocket < Config fullfile(mission.dataPath, 'aeroCoefficients.mat'), ... coeffName); - obj.coefficientsHighAOA = Coefficient( ... - fullfile(mission.dataPath, 'aeroCoefficientsHighAOA.mat'), ... - coeffName); + if obj.highAOACoefficients + obj.coefficientsHighAOA = Coefficient( ... + fullfile(mission.dataPath, 'aeroCoefficientsHighAOA.mat'), ... + coeffName); + end answer = ''; - if isempty(obj.coefficients.static) || isempty(obj.coefficientsHighAOA.static) + if isempty(obj.coefficients.static) || ... + (obj.highAOACoefficients && isempty(obj.coefficientsHighAOA.static)) answer = questdlg(['Coefficient matrices not found. ' ... 'Do you want to create new matrices?']); elseif options.checkGeometry @@ -194,7 +198,7 @@ classdef Rocket < Config parserPath = fullfile(mission.msaPath, 'autoMatricesProtub'); addpath(genpath(parserPath)); [obj.coefficients, obj.coefficientsHighAOA] = ... - mainAutoMatProtub(obj); + mainAutoMatProtub(obj, 'computeHighAOA', obj.highAOACoefficients); case 'Cancel' error('Rocket creation aborted') otherwise diff --git a/missions/2021_Lynx_Portugal_October/config/rocketConfig.m b/missions/2021_Lynx_Portugal_October/config/rocketConfig.m index 160c5b0..cb26401 100644 --- a/missions/2021_Lynx_Portugal_October/config/rocketConfig.m +++ b/missions/2021_Lynx_Portugal_October/config/rocketConfig.m @@ -20,6 +20,7 @@ rocket.lengthCenterNoMot = 1.7640; % [m] % When false, coefficients are saved with current motor's name % When true, coefficients are saved as 'generic' rocket.dynamicDerivatives = false; % [-] True if dynamic derivatives will be loaded +rocket.highAOACoefficients = false; % [-] True if separate matrix for high AOA will be loaded %% PLD - Includes Parafoil + Nose parafoil = Parafoil(); diff --git a/missions/2021_Lynx_Roccaraso_September/config/rocketConfig.m b/missions/2021_Lynx_Roccaraso_September/config/rocketConfig.m index d0dc3df..0851f94 100644 --- a/missions/2021_Lynx_Roccaraso_September/config/rocketConfig.m +++ b/missions/2021_Lynx_Roccaraso_September/config/rocketConfig.m @@ -20,6 +20,7 @@ rocket.lengthCenterNoMot = 1.7840; % [m] % When false, coefficients are saved with current motor's name % When true, coefficients are saved as 'generic' rocket.dynamicDerivatives = false; % [-] True if dynamic derivatives will be loaded +rocket.highAOACoefficients = false; % [-] True if separate matrix for high AOA will be loaded %% PLD - Includes Parafoil + Nose parafoil = Parafoil(); diff --git a/missions/2022_Pyxis_Portugal_October/config/rocketConfig.m b/missions/2022_Pyxis_Portugal_October/config/rocketConfig.m index 2f949bf..17d63ca 100644 --- a/missions/2022_Pyxis_Portugal_October/config/rocketConfig.m +++ b/missions/2022_Pyxis_Portugal_October/config/rocketConfig.m @@ -20,6 +20,7 @@ rocket.lengthCenterNoMot = 1.4470; % [m] % When false, coefficients are saved with current motor's name % When true, coefficients are saved as 'generic' rocket.dynamicDerivatives = false; % [-] True if dynamic derivatives will be loaded +rocket.highAOACoefficients = false; % [-] True if separate matrix for high AOA will be loaded %% PLD - Includes Parafoil + Nose parafoil = Parafoil(); diff --git a/missions/2022_Pyxis_Roccaraso_September/config/rocketConfig.m b/missions/2022_Pyxis_Roccaraso_September/config/rocketConfig.m index ee3a3c7..5b7406a 100644 --- a/missions/2022_Pyxis_Roccaraso_September/config/rocketConfig.m +++ b/missions/2022_Pyxis_Roccaraso_September/config/rocketConfig.m @@ -22,6 +22,7 @@ rocket.lengthCenterNoMot = 1.61; % [m] % When false, coefficients are saved with current motor's name % When true, coefficients are saved as 'generic' rocket.dynamicDerivatives = false; % [-] True if dynamic derivatives will be loaded +rocket.highAOACoefficients = false; % [-] True if separate matrix for high AOA will be loaded %% PLD - Includes Parafoil + Nose parafoil = Parafoil(); diff --git a/missions/2023_Gemini_Portugal_October/config/rocketConfig.m b/missions/2023_Gemini_Portugal_October/config/rocketConfig.m index 401c415..f9d6d4c 100644 --- a/missions/2023_Gemini_Portugal_October/config/rocketConfig.m +++ b/missions/2023_Gemini_Portugal_October/config/rocketConfig.m @@ -19,7 +19,7 @@ rocket.lengthCenterNoMot = 1.517; % [m] % When false, coefficients are saved with current motor's name % When true, coefficients are saved as 'generic' rocket.dynamicDerivatives = false; % [-] True if dynamic derivatives will be loaded - +rocket.highAOACoefficients = false; % [-] True if separate matrix for high AOA will be loaded %% PLD - Includes Parafoil + Nose parafoil = Parafoil(); diff --git a/missions/2023_Gemini_Roccaraso_September/config/rocketConfig.m b/missions/2023_Gemini_Roccaraso_September/config/rocketConfig.m index fc2715b..cadbc7e 100644 --- a/missions/2023_Gemini_Roccaraso_September/config/rocketConfig.m +++ b/missions/2023_Gemini_Roccaraso_September/config/rocketConfig.m @@ -19,6 +19,7 @@ rocket.lengthCenterNoMot = 1.517; % [m] % When false, coefficients are saved with current motor's name % When true, coefficients are saved as 'generic' rocket.dynamicDerivatives = false; % [-] True if dynamic derivatives will be loaded +rocket.highAOACoefficients = false; % [-] True if separate matrix for high AOA will be loaded %% PLD - Includes Parafoil + Nose parafoil = Parafoil(); diff --git a/missions/2024_Lyra_Portugal_October/config/rocketConfig.m b/missions/2024_Lyra_Portugal_October/config/rocketConfig.m index f87640c..1d90d15 100644 --- a/missions/2024_Lyra_Portugal_October/config/rocketConfig.m +++ b/missions/2024_Lyra_Portugal_October/config/rocketConfig.m @@ -13,6 +13,7 @@ rocket.lengthCenterNoMot = []; % [m] % When false, coefficients are saved with current motor's name % When true, coefficients are saved as 'generic' rocket.dynamicDerivatives = false; % [-] True if dynamic derivatives will be loaded +rocket.highAOACoefficients = false; % [-] True if separate matrix for high AOA will be loaded %% PLD - Includes Parafoil + Nose parafoil = Parafoil(); diff --git a/missions/2024_Lyra_Roccaraso_September/config/rocketConfig.m b/missions/2024_Lyra_Roccaraso_September/config/rocketConfig.m index 2939db0..133be74 100644 --- a/missions/2024_Lyra_Roccaraso_September/config/rocketConfig.m +++ b/missions/2024_Lyra_Roccaraso_September/config/rocketConfig.m @@ -19,6 +19,7 @@ rocket.lengthCenterNoMot = []; % [m] % When false, coefficients are saved with current motor's name % When true, coefficients are saved as 'generic' rocket.dynamicDerivatives = false; % [-] True if dynamic derivatives will be loaded +rocket.highAOACoefficients = false; % [-] True if separate matrix for high AOA will be loaded %% PLD - Includes Parafoil + Nose parafoil = Parafoil(); diff --git a/missions/2025_Orion_Portugal_October/config/rocketConfig.m b/missions/2025_Orion_Portugal_October/config/rocketConfig.m index e73d2a2..6e2c6c6 100644 --- a/missions/2025_Orion_Portugal_October/config/rocketConfig.m +++ b/missions/2025_Orion_Portugal_October/config/rocketConfig.m @@ -12,7 +12,8 @@ rocket.diameter = 0.15; % [m] % If dynamic derivatives are loaded, coefficient will depend on rocket xcg % When false, coefficients are saved with current motor's name % When true, coefficients are saved as 'generic' -rocket.dynamicDerivatives = false; % [-] True if dynamic derivatives will be loaded +rocket.dynamicDerivatives = false; % [-] True if dynamic derivatives will be loaded +rocket.highAOACoefficients = false; % [-] True if separate matrix for high AOA will be loaded %% PRF - Includes Parafoil + Nose parafoil = Parafoil(); -- GitLab From 84fc310802e9a6bc13b6a642335fac70fb4bd1d6 Mon Sep 17 00:00:00 2001 From: Mauco03 <marco.gaibotti@skywarder.eu> Date: Sun, 27 Apr 2025 00:29:28 +0200 Subject: [PATCH 6/8] [alpha-phi] Updated aerodynamic matrices --- .../2025_Orion_Portugal_October/data/aeroCoefficients.mat | 4 ++-- .../data/aeroCoefficientsHighAOA.mat | 4 ++-- missions/2025_Orion_Roccaraso_September/config/rocketConfig.m | 1 + 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/missions/2025_Orion_Portugal_October/data/aeroCoefficients.mat b/missions/2025_Orion_Portugal_October/data/aeroCoefficients.mat index 1df1179..3aa85db 100644 --- a/missions/2025_Orion_Portugal_October/data/aeroCoefficients.mat +++ b/missions/2025_Orion_Portugal_October/data/aeroCoefficients.mat @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:fb0ccbfea51866683e3cdaf1b7aa21c42ca3d387575aaa40df3694557c009fd4 -size 14789031 +oid sha256:f4ad48c4d016c33811361e5823e3fb0c87ae64679ff148293e2fcbb48c52f056 +size 300753532 diff --git a/missions/2025_Orion_Portugal_October/data/aeroCoefficientsHighAOA.mat b/missions/2025_Orion_Portugal_October/data/aeroCoefficientsHighAOA.mat index 965f46e..00d9ce5 100644 --- a/missions/2025_Orion_Portugal_October/data/aeroCoefficientsHighAOA.mat +++ b/missions/2025_Orion_Portugal_October/data/aeroCoefficientsHighAOA.mat @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f6f664625606e3fdfcbf0de0d8a45b8f49a43be69d8a879104f1315d4d9f5e53 -size 5776386 +oid sha256:1659d1dc6b19ea13c3cdd75b8f9627d42123c4cb6dff535d93618247a17ab9d1 +size 46224320 diff --git a/missions/2025_Orion_Roccaraso_September/config/rocketConfig.m b/missions/2025_Orion_Roccaraso_September/config/rocketConfig.m index c4e1ffc..e320c15 100644 --- a/missions/2025_Orion_Roccaraso_September/config/rocketConfig.m +++ b/missions/2025_Orion_Roccaraso_September/config/rocketConfig.m @@ -19,6 +19,7 @@ rocket.lengthCenterNoMot = []; % [m] % When false, coefficients are saved with current motor's name % When true, coefficients are saved as 'generic' rocket.dynamicDerivatives = false; % [-] True if dynamic derivatives will be loaded +rocket.highAOACoefficients = false; % [-] True if separate matrix for high AOA will be loaded %% PLD - Includes Parafoil + Nose parafoil = Parafoil(); -- GitLab From 2f5958ac270dae5b45547995421233a82bfbbad5 Mon Sep 17 00:00:00 2001 From: Lorenzo Bettonte <lorenzo.bettonte@skywarder.edu> Date: Sun, 18 May 2025 22:41:23 +0200 Subject: [PATCH 7/8] [alpha-phi] fixed a bug where n would in the wrong range (in Coefficient's class) and Handle AoA matrix usage in alphaTotPhi cases (in ballistic) --- classes/misc/Coefficient.m | 2 +- functions/odeFunctions/ballistic.m | 13 ++++++++----- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/classes/misc/Coefficient.m b/classes/misc/Coefficient.m index 14ab717..4b6d685 100644 --- a/classes/misc/Coefficient.m +++ b/classes/misc/Coefficient.m @@ -133,7 +133,7 @@ classdef Coefficient < Structured coefficients(1:6) = obj.staticInterpolant(alphaTot, mach, psi, altitude, airbakes); % Get coeffs in limited range - if n > 1 % If necessary, perform rotation on different frame + if n > 0 % If necessary, perform rotation on different frame R = [cos(deltaPhi), -sin(deltaPhi); sin(deltaPhi), cos(deltaPhi)]; diff --git a/functions/odeFunctions/ballistic.m b/functions/odeFunctions/ballistic.m index d08b306..fed5600 100644 --- a/functions/odeFunctions/ballistic.m +++ b/functions/odeFunctions/ballistic.m @@ -134,7 +134,7 @@ end if not(abs(ur) < 1e-9 || velsNorm < 1e-9) alpha = atan(wr/ur); beta = atan(vr/ur); % beta = asin(vr/V_norm) is the classical notation, Datcom uses this one though. - % alpha_tot = atan(sqrt(wr^2 + vr^2)/ur); % datcom 97' definition + alphaTot = atan(sqrt(wr^2 + vr^2)/ur); % datcom 97' definition else alpha = 0; beta = 0; @@ -144,14 +144,17 @@ alphaOut = alpha; betaOut = beta; %% INTERPOLATE AERODYNAMIC COEFFICIENTS: - -if abs(alpha) > rocket.coefficients.state.alphas(end)*pi/180 || ... - abs(beta) > rocket.coefficients.state.betas(end)*pi/180 - coeffsValues = rocket.coefficientsHighAOA.get(alpha, mach, beta, absoluteAltitude, extension, xcg); +if rocket.coefficients.type == CoeffType.AlphaBeta + if abs(alpha) > rocket.coefficients.state.alphas(end)*pi/180 || abs(beta) > rocket.coefficients.state.betas(end)*pi/180 + coeffsValues = rocket.coefficientsHighAOA.get(alpha, mach, beta, absoluteAltitude, extension, xcg); + end +elseif abs(alphaTot) > rocket.coefficients.state.alphas(end)*pi/180 + coeffsValues = rocket.coefficientsHighAOA.get(alpha, mach, beta, absoluteAltitude, extension, xcg); else coeffsValues = rocket.coefficients.get(alpha, mach, beta, absoluteAltitude, extension, xcg); end + % Retrieve Coefficients CA = coeffsValues(1); CY = coeffsValues(2); CN = coeffsValues(3); Cl = coeffsValues(4); Cm = coeffsValues(5); Cn = coeffsValues(6); -- GitLab From 7b9fa1e8d56c9b239181122f55996d47bce19f63 Mon Sep 17 00:00:00 2001 From: Lorenzo Bettonte <lorenzo.bettonte@skywarder.edu> Date: Tue, 24 Jun 2025 12:45:39 +0200 Subject: [PATCH 8/8] [alpha-phi] created new coefficient's matrices and removed a comment --- classes/misc/Coefficient.asv | 322 ++++++++++++++++++ classes/misc/Coefficient.m | 2 +- .../data/aeroCoefficients.mat | 4 +- 3 files changed, 325 insertions(+), 3 deletions(-) create mode 100644 classes/misc/Coefficient.asv diff --git a/classes/misc/Coefficient.asv b/classes/misc/Coefficient.asv new file mode 100644 index 0000000..924dc07 --- /dev/null +++ b/classes/misc/Coefficient.asv @@ -0,0 +1,322 @@ +classdef Coefficient + % Coefficient: Manages the coefficients associated with a rocket + % + % Constructor: + % - Coefficient: Creates an instance of the Coefficient class. + % Loaded config: - + % Loaded data: aeroCoefficients.mat + % Arguments: + % - filePath: char, path to coefficient file to load + % - name: (optional) coefficient name. Used when dynamic + % derivatives are also needed + % + % Coefficients are retrieved from DATCOM in the following format: + % Coefficient matrix: double (15, nAlpha, nMach, nBeta, nAlt, nAbk, nXcg) + % Where the 15 coefficients are + % - CA Axial force + % - CYB Side force derivative wrt beta + % - CY0 Side force + % - CNA Normal force derivative wrt alpha + % - CN0 Normal force + % - Cl Rolling moment + % - Clp Rolling moment derivative wrt roll rate + % - Cma Pitching moment derivative wrt alpha + % - Cm0 Pitching moment + % - Cmad Pitching moment derivative wrt alpha dot + % - Cmq Pitching moment derivative wrt pitch rate + % - Cnb Yawing moment derivative wrt beta + % - Cn0 Yawing moment + % - Cnr Yawing moment derivative wrt yaw rate + % - Cnp Yawing moment derivative wrt roll rate + % + % Coefficients are then stored in the following format: + % static: double (6, nAlpha, nMach, nBeta, nAlt, nAbk) + % Where the 6 coefficients are: + % - [CA, CY, CN, Cl, Cm, Cn] + % dynamic: double (5, nAlpha, nMach, nBeta, nAlt, nAbk, nXcg) + % - [Clp, Cmad, Cmq, Cnr, Cnp] + % + % NOTE: When dynamic derivatives are not loaded, the matrix will be + % 6-D, as there will be no need to interpolate wrt to the xcg: moment + % transport formulas will be used instead + % + % NOTE: Coefficients in an interpolants are stored on the last + % dimension, instead of the first, to improve performance + + properties(Dependent) + total double % Coefficients stored in DATCOM format + geometry struct % Reference geometry + state struct % Flight envelope + end + + properties + finsCN double % Fins-only CN + end + + properties(Dependent, SetAccess = private) + static double % Static coefficients: [CA, CY, CN, Cl, Cm, Cn] + dynamic double % Dynamic derivatives: [Clp, Cmad, Cmq, Cnr, Cnp] + end + + properties(SetAccess = private) + type CoeffType % Wheter based on alphaTot-phi or alpha-beta + symmetry (1, 1) logical % Apply axial simmetry: valid for alphaTot-phi + + isReady (1, 1) logical % Whether all coefficients are loaded and of the right size + isDynamic (1, 1) logical % Whether to load dynamic derivatives. Adds XCG dependece + end + + properties(Access = private) + TOTAL % Cached variable for total + GEOMETRY % Cached variable for geometry + STATE % Cached variable for state + end + + properties(Access = private) + staticInterpolant (1, 1) griddedInterpolant + dynamicInterpolant (1, 1) griddedInterpolant + end + + methods + function obj = Coefficient(filePath, name) + arguments + filePath (1, :) char = '' + name (1, :) char = 'generic' + end + + if isempty(filePath), return; end + + obj = obj.loadData(filePath, name); + obj.isReady = obj.checkProperties(); + obj = obj.updateInterpolants(); + end + + function [coefficients] = get(obj, alpha, mach, beta, altitude, airbakes, xcg) + % GET: Retrieve aerodynamic coefficients for specified flight conditions + % + % This method interpolates the aerodynamic coefficients based on + % the provided flight conditions and adjusts them for the given + % center of gravity (xcg). + % + % Arguments: + % - alpha double, angle of attack [rad] + % - mach double, Mach number [-] + % - beta double, sideslip angle [rad] + % - altitude double, altitude [m] + % - airbakes double, airbrake deployment [-] + % - xcg double, center of gravity position [m] + % + % Returns: + % - coefficients: double (11, 1), aerodynamic coefficients + % [CA, CY, CN, Cl, Cm, Cn, Clp, Cmad, Cmq, Cnr, Cnp] + % + % NOTE: Static coefficients are interpolated and adjusted for + % the specified xcg. Dynamic derivatives are included only if + % loadDynamic is true. + + if ~obj.isReady, error('Cannot interpolate coefficients: check that all dimensions match'); end + + % Interpolating coefficients + coefficients = zeros(11, 1); + if obj.type == CoeffType.AlphaBeta + coefficients(1:6) = obj.staticInterpolant(alpha, mach, beta, altitude, airbakes); + else + [alphaTot, phi] = getAlphaPhi(alpha, beta); + phi = wrapTo2Pi(phi); + + finAngle = 2*pi / obj.GEOMETRY.nPanel; % Angle between two fin panels + n = floor(phi / finAngle); + deltaPhi = n*finAngle; + psi = phi - deltaPhi; % Angle wrapped to finAngle + + coefficients(1:6) = obj.staticInterpolant(alphaTot, mach, psi, altitude, airbakes); % Get coeffs in limited range + + if n > 0 % If necessary, perform rotation on different frame + R = [cos(deltaPhi), -sin(deltaPhi); + sin(deltaPhi), cos(deltaPhi)]; + + coefficients([2, 3]) = R * coefficients([2, 3]); + coefficients([5, 6]) = R' * coefficients([5, 6]); + end + end + + % Transporting static coefficients to new xcg + % C_B = C_A + d / c * [0; -CN; CY]_A + d = xcg - obj.GEOMETRY.xcg(1); + l = obj.GEOMETRY.diameter; + + CY = coefficients(2); CN = coefficients(3); + forceCoeffs = [0; CN; CY]; + + coefficients(4:6) = coefficients(4:6) + d/l * forceCoeffs; + + if ~obj.isDynamic, return; end + if obj.type == CoeffType.AlphaTotPhi + error('Alpha-Phi coefficients do not support dynamic derivatives yet') + end + coefficients(7:11) = obj.dynamicInterpolant(alpha, mach, beta, altitude, airbakes, xcg); + end + end + + methods % Getters + function value = get.total(obj) + value = obj.TOTAL; + end + + function value = get.static(obj) + if isempty(obj.TOTAL), value = []; return; end + value = obj.TOTAL([1, 3, 5, 6, 9, 13], :, :, :, :, :, 1); + end + + function value = get.dynamic(obj) + if ~obj.isDynamic || isempty(obj.TOTAL), value = []; return; end + value = obj.TOTAL([7, 10, 11, 14, 15], :, :, :, :, :, :); + end + + function value = get.geometry(obj) + value = obj.GEOMETRY; + end + + function value = get.state(obj) + value = obj.STATE; + end + end + + methods % Setters + function obj = set.total(obj, value) + obj.TOTAL = value; + obj.isDynamic = size(value, 7) ~= 1; + obj.isReady = obj.checkProperties(); + obj = obj.updateInterpolants(); + end + + function obj = set.geometry(obj, value) + if ~isempty(obj.STATE) && isfield(obj.STATE, 'phis') && ~isempty(obj.STATE.phis) + obj.symmetry = (360/obj.STATE.phis(end) == value.nPanel); + end + + obj.GEOMETRY = value; + obj.isReady = obj.checkProperties(); + obj = obj.updateInterpolants(); + end + + function obj = set.state(obj, value) + if isfield(value, 'phis') && ~isempty(value.phis) + if ~isempty(value.betas) + error('Cannot set both alpha, beta and phi'); + end + if ~isempty(obj.GEOMETRY) + obj.symmetry = (360/value.phis(end) == obj.GEOMETRY.nPanel); + end + obj.type = CoeffType.AlphaTotPhi; + else + obj.type = CoeffType.AlphaBeta; + end + + obj.STATE = value; + obj.isReady = obj.checkProperties(); + obj = obj.updateInterpolants(); + end + end + + methods(Access = private) + function obj = loadData(obj, filePath, name) + % Load the coefficients from the specified file + % filePath: char, path to coefficient file to load + % name: (optional) coefficient name. Used when dynamic + % derivatives are also needed + % + % NOTE: Coefficient alpha and beta derivatives are not loaded + % as coefficients are already interpolated linearly + + + if ~exist(filePath, 'file'), return; end + warning('off'); % Disable warning in case coefficients are not present + dataCoeffs = load(filePath, name); + warning('on'); + + if ~isfield(dataCoeffs, name), return; end + dataCoeffs = dataCoeffs.(name); + + obj.finsCN = dataCoeffs.finsCN; + obj.GEOMETRY = dataCoeffs.geometry; + obj.state = dataCoeffs.state; + + % Load coefficients + obj.total = dataCoeffs.total; + end + + function ready = checkProperties(obj) + % Check if STATIC, DYNAMIC, GEOMETRY, and STATE are non-empty + ready = ~isempty(obj.static) && ... + ~isempty(obj.GEOMETRY) && ~isempty(obj.STATE) && ... + ~(isempty(obj.dynamic) && obj.isDynamic); + + if ~ready, return; end + + alpha = obj.STATE.alphas; + mach = obj.STATE.machs; + altitude = obj.STATE.altitudes; + airbakes = obj.STATE.hprot; + xcg = obj.GEOMETRY.xcg; + + if obj.type == CoeffType.AlphaBeta + theta = obj.STATE.betas; % Converting to rad + else + theta = obj.STATE.phis; % Converting to rad + end + + gridVecs = {alpha, mach, theta, altitude, airbakes, xcg}; + dims = cellfun(@(x) length(x), gridVecs); + dims(dims == 0) = 1; % Empty case is the same as scalar case + + ready = all(size(obj.total, 2:7) == dims); + end + + function obj = updateInterpolants(obj) + % Update static and dynamic interpolants + if ~obj.isReady, return; end + + %% Retrieve flight conditions + alpha = obj.STATE.alphas*pi/180; % Converting to rad + mach = obj.STATE.machs; + altitude = obj.STATE.altitudes; + xcg = obj.GEOMETRY.xcg; + + if isempty(obj.STATE.hprot), airbakes = 0; + else, airbakes = obj.STATE.hprot/obj.STATE.hprot(end); % Normalizing on height + end + + if obj.type == CoeffType.AlphaBeta + theta = obj.STATE.betas*pi/180; % Converting to rad + else + theta = obj.STATE.phis*pi/180; % Converting to rad + end + + gridVecs = {alpha, mach, theta, altitude, airbakes, xcg}; + + % Find singleton dims (last dimension is coefficients and will not be of length 1) + singletonDims = cellfun(@(x) isscalar(x) || isempty(x), gridVecs); + gridVecs(singletonDims) = deal({[0, 1]}); + + %% Create interpolants + staticCoeffs = permute(obj.static, [2, 3, 4, 5, 6, 1]); + staticCoeffs = repmat(staticCoeffs, singletonDims(1:end-1) + 1); % Exclude xcg for static coefficients + + obj.staticInterpolant = griddedInterpolant(gridVecs(1:end-1), staticCoeffs, 'linear', 'nearest'); + + if ~obj.isDynamic, return; end + + %% Handle dynamic derivatives + dynamicCoeffs = permute(obj.dynamic, [2, 3, 4, 5, 6, 7, 1]); + + % Flip xcg in case of descending order + if ~isscalar(xcg) && xcg(2) < xcg(1) + gridVecs{end} = flip(xcg); + dynamicCoeffs = flip(dynamicCoeffs, 7); + end + + obj.dynamicInterpolant = griddedInterpolant(gridVecs, dynamicCoeffs, 'linear', 'nearest'); + end + end +end \ No newline at end of file diff --git a/classes/misc/Coefficient.m b/classes/misc/Coefficient.m index 4b6d685..2573c6d 100644 --- a/classes/misc/Coefficient.m +++ b/classes/misc/Coefficient.m @@ -143,7 +143,7 @@ classdef Coefficient < Structured end % Transporting static coefficients to new xcg - % C_B = C_A + d / c * [0; -CN; CY]_A <- NOTE: Non torna il meno su CN + % C_B = C_A + d / c * [0; -CN; CY]_A d = xcg - obj.GEOMETRY.xcg(1); l = obj.GEOMETRY.diameter; diff --git a/missions/2025_Orion_Portugal_October/data/aeroCoefficients.mat b/missions/2025_Orion_Portugal_October/data/aeroCoefficients.mat index 3aa85db..e7019e8 100644 --- a/missions/2025_Orion_Portugal_October/data/aeroCoefficients.mat +++ b/missions/2025_Orion_Portugal_October/data/aeroCoefficients.mat @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f4ad48c4d016c33811361e5823e3fb0c87ae64679ff148293e2fcbb48c52f056 -size 300753532 +oid sha256:f544fdb75b3dcc7180915ef4b0263969a17444b7609cb7e8947fc482d5cffa14 +size 300751768 -- GitLab