diff --git a/classes/DataWrapper.m b/classes/DataWrapper.m index 04c827361cc842c7630607379fb4069804c775f4..d708671ae603607996576f6bacb5e147a6128a41 100644 --- a/classes/DataWrapper.m +++ b/classes/DataWrapper.m @@ -11,43 +11,40 @@ classdef DataWrapper < handle end properties(Access = private) - cache - counter int32 = 0 - dummyStrc struct - chunkSize int32 % Size of preallocated memory - dataLen int32 % Current size of cache + counter int32 + shift int32 + dummyStrc struct + chunkSize int32 % Size of preallocated memory + dataLen int32 % Current size of cache end methods - function obj = DataWrapper(dataDummy, chunkSize) + function obj = DataWrapper(dataDummy, chunkSize, shift) arguments dataDummy struct - chunkSize {mustBeInteger, mustBePositive} = 5 + chunkSize {mustBeInteger, mustBePositive} = 1000 + shift = 0 end obj.chunkSize = chunkSize; + obj.shift = shift; % Useful to preallocate initial value fields = fieldnames(dataDummy)'; fields{2, 1} = []; obj.dummyStrc = struct(fields{:}); - obj.cache = obj.dummyStrc; - obj.data = obj.dummyStrc; % Set struct dataType - obj.data(obj.chunkSize) = obj.dummyStrc; % Preallocate struct - - obj.dataLen = obj.chunkSize; + obj.reset(); end function setCache(obj, data) - obj.cache = data; + obj.data(obj.counter + 1) = data; end function setData(obj) obj.counter = obj.counter + 1; - if obj.counter > obj.dataLen + if obj.counter == obj.dataLen len = obj.dataLen + obj.chunkSize; obj.dataLen = len; obj.data(len) = obj.dummyStrc; end - obj.data(obj.counter) = obj.cache; end function out = popData(obj) @@ -55,17 +52,20 @@ classdef DataWrapper < handle obj.reset(); end - function out = getData(obj) - out = obj.data(1:obj.counter); + function out = getData(obj, startIdx) + arguments + obj + startIdx = 1 + end + out = obj.data(startIdx:obj.counter); end function obj = reset(obj) - obj.cache = obj.dummyStrc; obj.data = obj.dummyStrc; % Set struct dataType obj.data(obj.chunkSize) = obj.dummyStrc; % Preallocate struct obj.dataLen = obj.chunkSize; - obj.counter = 0; + obj.counter = obj.shift; end end @@ -85,6 +85,11 @@ classdef DataWrapper < handle if isstruct(currentValue) out.(currentField) = DataWrapper.packageData([data.(currentField)]); else + sz = size(data(1).(currentField)); + if all(sz > 1) + szIn = num2cell(sz); szIn{end+1} = []; %#ok<AGROW> + currentValue = reshape(currentValue, szIn{:}); + end out.(currentField) = currentValue; end end diff --git a/classes/components/Environment.m b/classes/components/Environment.m index bacae3c281b2ebaef29cf4b8291d0ff10887f725..cbdc0e72aaa6e71d493b60d64f6283aafeed5a6f 100644 --- a/classes/components/Environment.m +++ b/classes/components/Environment.m @@ -29,8 +29,10 @@ classdef Environment < Component properties(SetAccess = private) g0 double % [-] Gravity costant at launch latitude and altitude + local double % [-] Vector conatining inputs for atmosphereData pinDistance double % [m] Distance of the upper pin from the rail base (upper pin-boat + boat-rail base) effectiveRampLength double % [m] Total launchpad length + effectiveRampAltitude double % [m] Projection of effectiveRampLength on z axis end properties(Access = protected) @@ -56,7 +58,8 @@ classdef Environment < Component obj.updateG0; obj.updatePinDistance; - obj.updateEffectiveRampLength; + obj.updateRamp; + obj.updateLocal; end end @@ -71,8 +74,14 @@ classdef Environment < Component + obj.motor.tankLength; end - function obj = updateEffectiveRampLength(obj) + function obj = updateRamp(obj) obj.effectiveRampLength = obj.rampLength - obj.pinDistance; + obj.effectiveRampAltitude = obj.effectiveRampLength*sin(obj.omega); + end + + function obj = updateLocal(obj) + obj.local = [obj.z0, obj.temperature, ... % vector containing inputs for atmosphereData + obj.pressure, obj.rho]; end end end \ No newline at end of file diff --git a/functions/miscellaneous/recallOdeFcn.m b/functions/miscellaneous/recallOdeFcn.m index 6af4a4e27a2bef4082dbb0174f8d4c23f0b2db77..68ad613171b5483cad4529d7e7ee4e2532b07aee 100644 --- a/functions/miscellaneous/recallOdeFcn.m +++ b/functions/miscellaneous/recallOdeFcn.m @@ -1,4 +1,8 @@ -function out = recallOdeFcn(fun, t, Y, varargin) +function out = recallOdeFcn(solution, startIdx) +arguments + solution + startIdx = 1 +end % recallOdeFcn - This function allows to compute some parameters used % inside the ODE integrations. % @@ -26,14 +30,14 @@ function out = recallOdeFcn(fun, t, Y, varargin) % % SPDX-License-Identifier: GPL-3.0-or-later -wrapper = varargin{end}; -dataRaw = wrapper.getData(); +args = solution.extdata.varargin; +fun = solution.extdata.odefun; -%% Adding t = 0, Fixing t(end) +wrapper = args{end}; +data = wrapper.getData(startIdx); -[~, data0] = fun(t(1), Y(:,1), varargin{1:end-1}); -data = [data0, dataRaw]; +%% Fixing points at t = 0, t = end -[~, data(end)] = fun(t(end), Y(:,end), varargin{1:end-1}); -out = wrapper.packageData(data); -wrapper.reset(); \ No newline at end of file +[~, data(1)] = fun(solution.x(startIdx), solution.y(:,startIdx), args{1:end-1}); +[~, data(end)] = fun(solution.x(end), solution.y(:,end), args{1:end-1}); +out = wrapper.packageData(data); \ No newline at end of file diff --git a/functions/odeFunctions/ascentMultipleAB.m b/functions/odeFunctions/ascentMultipleAB.m deleted file mode 100644 index 052faafcc6f57d0c1e678ebaca85028bea8c3a39..0000000000000000000000000000000000000000 --- a/functions/odeFunctions/ascentMultipleAB.m +++ /dev/null @@ -1,336 +0,0 @@ -function [dY, parout] = ascentMultipleAB(t, Y, t0, iAB, settings) -%{ -ascentMultipleAB - ode function of the 6DOF Rigid Rocket Model with - multiple and smooth airbrakes opening configurations - -INPUTS: -- t, double [1, 1] integration time [s]; -- Y, double [13, 1] state vector [ x y z | u v w | p q r | q0 q1 q2 q3]: - - * (x y z), NED{north, east, down} horizontal frame; - * (u v w), body frame velocities; - * (p q r), body frame angular rates; - * (q0 q1 q2 q3), attitude unit quaternion; -- t0, double [1, 1] starting time for airbrakes change of configuration; -- iAB, double [1, 1] i-th airbrake configuration; -- settings, struct(motor, CoeffsE, CoeffsF, para, ode, stoch, prob, wind), rocket data structure; - -OUTPUTS: -- dY, double [16, 1] state derivatives -- parout, struct, interesting fligth quantities structure (aerodyn coefficients, forces and so on..) - - -CALLED FUNCTIONS: windMatlabGenerator, windInputGenerator, quatToDcm, interpCoeffs - -NOTE: To get the NED velocities the body-frame must be multiplied by the -conjugated of the current attitude quaternion -E.G. quatrotate(quatconj(Y(:,10:13)),Y(:,4:6)) - -REVISIONS: --#0 02/10/2021, Release, Davide Rosato - -Copyright © 2021, Skyward Experimental Rocketry, AFD department -All rights reserved - -SPDX-License-Identifier: GPL-3.0-or-later - -%} - - -% recalling the states -% x = Y(1); -% y = Y(2); -z = Y(3); -u = Y(4); -v = Y(5); -w = Y(6); -p = Y(7); -q = Y(8); -r = Y(9); -q0 = Y(10); -q1 = Y(11); -q2 = Y(12); -q3 = Y(13); - - - -%% CONSTANTS -S = settings.S; % [m^2] cross surface -C = settings.C; % [m] caliber -g = settings.g0/(1 + (-z*1e-3/6371))^2; % [N/kg] module of gravitational field -tb = settings.tb; % [s] Burning Time -local = settings.Local; % vector containing inputs for atmosphereData - -OMEGA = settings.OMEGA; -%% INERTIAS -if t < tb - if t < settings.timeEngineCut - I = interpLinear(settings.motor.expTime, settings.I, t); - Idot = interpLinear(settings.motor.expTime, settings.Idot, t); - else - I = settings.IengineCut; - Idot = zeros(3, 1); - end -else - if settings.timeEngineCut < tb - I = settings.IengineCut; - else - I = settings.I(:, end); - end - Idot = zeros(3, 1); -end -Ixx = I(1); Iyy = I(2); Izz = I(3); -Ixxdot = Idot(1); Iyydot = Idot(2); Izzdot = Idot(3); - -%% QUATERION ATTITUDE -Q = [q0 q1 q2 q3]; -Q = Q/norm(Q); - -%% ADDING WIND (supposed to be added in NED axes); -if settings.wind.model - [uw, vw, ww] = windMatlabGenerator(settings, z, t); -else - [uw, vw, ww] = computeWindVels(settings.wind, -z); -end - -dcm = quatToDcm(Q); -wind = dcm*[uw; vw; ww]; - -% Relative velocities (plus wind); -ur = u - wind(1); -vr = v - wind(2); -wr = w - wind(3); - -% Body to Inertial velocities -Vels = dcm'*[u; v; w]; -V_norm = norm([ur vr wr]); - -%% ATMOSPHERE DATA -if -z < 0 % z is directed as the gravity vector - z = 0; -end - -absoluteAltitude = -z + settings.z0; -[~, a, P, rho] = atmosphereData(absoluteAltitude, g, local); - -M = V_norm/a; -M_value = M; - -%% TIME-DEPENDENTS VARIABLES -if t < tb - if t < settings.timeEngineCut - m = interpLinear(settings.motor.expTime, settings.mTotalTime, t); - T = interpLinear(settings.motor.expTime, settings.motor.expThrust, t); - Pe = interpLinear(settings.motor.expTime, settings.motor.Pe, t); - T = T + settings.motor.Ae*(Pe - P); - else - m = settings.expMengineCut + settings.ms; - T = 0; - end - -else % for t >= tb the fligth condition is the empty one(no interpolation needed) - if settings.timeEngineCut < tb - m = settings.ms + settings.expMengineCut; - else - m = settings.ms + settings.motor.expM(end); - end - T = 0; -end - -%% AERODYNAMICS ANGLES -if not(abs(ur) < 1e-9 || V_norm < 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 -else - alpha = 0; - beta = 0; -end - -alpha_value = alpha; -beta_value = beta; - -%% CHOSING THE EMPTY CONDITION VALUE -% interpolation of the coefficients with the value in the nearest condition of the Coeffs matrix -if t0 == 0 - c = settings.control(iAB); -else - c = settings.control(iAB); - cPrev = settings.control(iAB - 1); - delay = settings.delayControl(iAB - 1); -end - -%% INTERPOLATE AERODYNAMIC COEFFICIENTS: -[coeffsValues, angle0] = interpCoeffs(t, alpha, M, beta, absoluteAltitude, c, settings); - -if t0 ~= 0 && t >= t0 && t < t0 + delay - [coeffsValuesPrev, ~] = interpCoeffs(t, alpha, M, beta, absoluteAltitude, cPrev, settings); - coeffsValues = coeffsValuesPrev + (coeffsValues - coeffsValuesPrev) * (t - t0)/delay; -end - -% Retrieve Coefficients -CA = coeffsValues(1); CYB = coeffsValues(2); CY0 = coeffsValues(3); -CNA = coeffsValues(4); CN0 = coeffsValues(5); Cl = coeffsValues(6); -Clp = coeffsValues(7); Cma = coeffsValues(8); Cm0 = coeffsValues(9); -Cmad = coeffsValues(10); Cmq = coeffsValues(11); Cnb = coeffsValues(12); -Cn0 = coeffsValues(13); Cnr = coeffsValues(14); Cnp = coeffsValues(15); -% XCP_value = coeffsValues(16); - - -% compute CN,CY,Cm,Cn (linearized with respect to alpha and beta): -alpha0 = angle0(1); beta0 = angle0(2); - -CN = (CN0 + CNA*(alpha - alpha0)); -CY = (CY0 + CYB*(beta - beta0)); -Cm = (Cm0 + Cma*(alpha - alpha0)); -Cn = (Cn0 + Cnb*(beta - beta0)); - -% XCPlon = Cm/CN; - -if abs(alpha) <= pi/180 - XCPlon = Cma/CNA; -else - XCPlon = Cm/CN; -end - -% XCPlat = Cn/CY; - - -if abs(beta) <= pi/180 - XCPlat = Cnb/CYB; -else - XCPlat = Cn/CY; -end - -% if Cn == 0 && CY == 0 -% XCPlat = -5; -% end - -%% -if -z < settings.lrampa*sin(OMEGA) % No torque on the launchpad - - Fg = m*g*sin(OMEGA); % [N] force due to the gravity - X = 0.5*rho*V_norm^2*S*CA; - F = -Fg +T -X; - du = F/m; - - dv = 0; - dw = 0; - dp = 0; - dq = 0; - dr = 0; - - alpha_value = NaN; - beta_value = NaN; - Y = 0; - Z = 0; - XCPlon = NaN; - XCPlat = NaN; - - if T < Fg % No velocity untill T = Fg - du = 0; - end - - XCPtot = NaN; -else - %% FORCES - % first computed in the body-frame reference system - qdyn = 0.5*rho*V_norm^2; % [Pa] dynamics pressure - qdynL_V = 0.5*rho*V_norm*S*C; - - X = qdyn*S*CA; % [N] x-body component of the aerodynamics force - Y = qdyn*S*CY; % [N] y-body component of the aerodynamics force - Z = qdyn*S*CN; % [N] z-body component of the aerodynamics force - Fg = dcm*[0; 0; m*g]; % [N] force due to the gravity in body frame - - F = Fg + [-X+T, Y, -Z]'; % [N] total forces vector - - %% STATE DERIVATIVES - % velocity - du = F(1)/m - q*w + r*v; - dv = F(2)/m - r*u + p*w; - dw = F(3)/m - p*v + q*u; - - % Rotation - dp = (Iyy - Izz)/Ixx*q*r + qdynL_V/Ixx*(V_norm*Cl+Clp*p*C/2) - Ixxdot*p/Ixx; - dq = (Izz - Ixx)/Iyy*p*r + qdynL_V/Iyy*(V_norm*Cm + (Cmad+Cmq)*q*C/2)... - - Iyydot*q/Iyy; - dr = (Ixx - Iyy)/Izz*p*q + qdynL_V/Izz*(V_norm*Cn + (Cnr*r+Cnp*p)*C/2)... - - Izzdot*r/Izz; - - % Compute the aerodynamici roll angle - [~, phi] = getAlphaPhi(alpha, beta); - - % Aerodynamic-force coefficient in the alpha-total plane - CFaTot = sin(phi)*CY + cos(phi)*(-CN); - % Aerodynanic-moment coefficient in the alpha-total plane - CMaTot = cos(phi)*Cm - sin(phi)*Cn; - - if CFaTot ~= 0 - XCPtot = CMaTot/CFaTot; - else - XCPtot = XCPlon; - end - -end -% Quaternions -OM = [ 0 -p -q -r ; - p 0 r -q ; - q -r 0 p ; - r q -p 0 ]; - -dQQ = 1/2*OM*Q'; - -%% FINAL DERIVATIVE STATE ASSEMBLING -dY(1:3) = Vels; -dY(4) = du; -dY(5) = dv; -dY(6) = dw; -dY(7) = dp; -dY(8) = dq; -dY(9) = dr; -dY(10:13) = dQQ; -dY = dY'; - -%% SAVING THE QUANTITIES FOR THE PLOTS -parout.integration.t = t; - -parout.interp.M = M_value; -parout.interp.alpha = alpha_value; -parout.interp.beta = beta_value; -parout.interp.alt = -z; -parout.interp.mass = m; -parout.interp.inertias = [Ixx, Iyy, Izz]; - -parout.wind.NED_wind = [uw, vw, ww]; -parout.wind.body_wind = wind; - -parout.rotations.dcm = dcm; - -parout.velocities = Vels; - -parout.forces.AeroDyn_Forces = [X, Y, Z]; -parout.forces.T = T; - -parout.air.rho = rho; -parout.air.P = P; - -parout.accelerations.body_acc = [du, dv, dw]; -parout.accelerations.ang_acc = [dp, dq, dr]; - -parout.coeff.CA = CA; -parout.coeff.CYB = CYB; -parout.coeff.CNA = CNA; -parout.coeff.Cl = Cl; -parout.coeff.Clp = Clp; -parout.coeff.Cma = Cma; -parout.coeff.Cmad = Cmad; -parout.coeff.Cmq = Cmq; -parout.coeff.Cnb = Cnb; -parout.coeff.Cnr = Cnr; -parout.coeff.Cnp = Cnp; -parout.coeff.XCPlon = XCPlon; -parout.coeff.XCPlat = XCPlat; - -parout.coeff.XCPtot = XCPtot; -end \ No newline at end of file diff --git a/functions/odeFunctions/ballistic.m b/functions/odeFunctions/ballistic.m index c4ddb8d5cb4372596c41038e0bffa0e12b819eb7..9ed6be9a77b1a6cb20d10a98da0df3a01c97bed1 100644 --- a/functions/odeFunctions/ballistic.m +++ b/functions/odeFunctions/ballistic.m @@ -61,16 +61,16 @@ q2 = Y(12); q3 = Y(13); angle = Y(14); +dY = zeros(14, 1); % if altitude < 0, altitude = 0; end -%% CONSTANTS +%% GETTING DATA S = rocket.crossSection; % [m^2] cross surface C = rocket.diameter; % [m] caliber g = environment.g0/(1 + (altitude*1e-3/6371))^2; % [N/kg] module of gravitational field tb = rocket.motor.cutoffTime; % [s] Burning Time theta = t-t0; % [s] Time shift (needed for control) -local = [environment.z0, environment.temperature, ... % vector containing inputs for atmosphereData - environment.pressure, environment.rho]; +local = environment.local; % vector containing inputs for atmosphereData omega = environment.omega; isControlActive = false; @@ -81,10 +81,11 @@ Q = [q0 q1 q2 q3]; Q = Q/norm(Q); %% ADDING WIND (supposed to be added in NED axes); -if isa(wind, 'WindMatlab') - [uw, vw, ww] = wind.getVels(altitude, theta); -else - [uw, vw, ww] = wind.getVels(altitude); +switch class(wind) + case 'WindMatlab' + [uw, vw, ww] = wind.getVels(altitude, theta); + case 'WindCustom' + [uw, vw, ww] = wind.getVels(altitude); end dcm = quatToDcm(Q); @@ -206,7 +207,7 @@ end % end %% RAMP / FREE FLIGHT -if altitude < environment.effectiveRampLength*sin(omega) % No torque on the launchpad +if altitude < environment.effectiveRampAltitude % No torque on the launchpad Fg = m*g*sin(omega); % [N] force due to the gravity fX = 0.5*rho*velsNorm^2*S*CA; F = -Fg +T -fX; @@ -316,7 +317,6 @@ dY(4:6) = [du; dv; dw]; dY(7:9) = [dp; dq; dr]; dY(10:13) = dQQ; dY(14) = dAngle; -dY = dY'; %% SAVING THE QUANTITIES FOR THE PLOTS @@ -360,5 +360,7 @@ if nargout == 2 || ~isempty(wrapper) parout.coeff.XCPlat = XCPlat; parout.coeff.XCPtot = XCPtot; - if ~isempty(wrapper), wrapper.setCache(parout); end + if ~isempty(wrapper) + wrapper.setCache(parout); + end end \ No newline at end of file diff --git a/functions/odeFunctions/descentBal.m b/functions/odeFunctions/descentBal.m deleted file mode 100644 index 3e2bb42b99c0645676bc15148b4ac7a611b6cacf..0000000000000000000000000000000000000000 --- a/functions/odeFunctions/descentBal.m +++ /dev/null @@ -1,249 +0,0 @@ -function [dY, parout] = descentBal(t, Y, settings) - -%{ -descentBal - ode function of the ballistic descent - -INPUTS: -- t, double [1, 1], integration time [s]; -- Y, double [13, 1], state vector [ x y z | u v w | p q r | q0 q1 q2 q3]: - - * (x y z), NED{north, east, down} horizontal frame; - * (u v w), body frame velocities; - * (p q r), body frame angular rates; - * (q0 q1 q2 q3), attitude unit quaternion; -- settings, struct(motor, CoeffsE, CoeffsF, para, ode, stoch, prob, wind), rocket data structure; - -OUTPUTS: -- dY , double [13, 1] state derivatives -- parout, struct, interesting fligth quantities structure (aerodyn coefficients, forces and so on..) - - -CALLED FUNCTIONS: windMatlabGenerator, windInputGenerator, quatToDcm, interpCoeffs - -NOTE: To get the NED velocities the body-frame must be multiplied by the -conjugated of the current attitude quaternion -E.G. quatrotate(quatconj(Y(:,10:13)),Y(:,4:6)) - -REVISIONS: --#0 31/12/2014, Release, Ruben Di Battista - --#1 16/04/2016, Second version, Francesco Colombi - --#2 13/01/2018, Third version, Adriano Filippo Inno - --#3 21/07/2023, update, Riccardo Cadamuro, Maria Teresa Cazzola - Bugfix when the rocket begin descent with ur < 0: - included larger aerodynamic matrix and linear - coefficients interpolation; - alpha and beta computed with atan2 - -Copyright © 2021, Skyward Experimental Rocketry, AFD department -All rights reserved - -SPDX-License-Identifier: GPL-3.0-or-later - -%} - -% recalling the state -% x = Y(1); -% y = Y(2); -z = Y(3); -u = Y(4); -v = Y(5); -w = Y(6); -p = Y(7); -q = Y(8); -r = Y(9); -q0 = Y(10); -q1 = Y(11); -q2 = Y(12); -q3 = Y(13); -m = settings.mEndAscent; -Ixx = settings.IxxEndAscent; -Iyy = settings.IyyEndAscent; -Izz = settings.IzzEndAscent; - -persistent flippedFlag; - -if isempty(flippedFlag) - flippedFlag = false; -end - -%% CONSTANTS -% Everything related to empty condition (descent-fase) -S = settings.S; % [m^2] cross surface -C = settings.C; % [m] caliber -g = settings.g0/(1 + (-z*1e-3/6371))^2; % [N/kg] module of gravitational field -T = 0; -local = settings.Local; % vector containing inputs for atmosphereData - -%% QUATERION ATTITUDE -Q = [q0 q1 q2 q3]; -Q = Q/norm(Q); - -%% ADDING WIND (supposed to be added in NED axes); -if settings.wind.model - [uw, vw, ww] = windMatlabGenerator(settings, z, t); -else - [uw, vw, ww] = computeWindVels(settings.wind, -z); -end - -dcm = quatToDcm(Q); -wind = dcm*[uw; vw; ww]; - -% Relative velocities (plus wind); -ur = u - wind(1); -vr = v - wind(2); -wr = w - wind(3); - -% Body to Inertial velocities -Vels = dcm'*[u; v; w]; -V_norm = norm([ur vr wr]); - -%% ATMOSPHERE DATA -if -z < 0 % z is directed as the gravity vector - z = 0; -end - -absoluteAltitude = -z + settings.z0; -[~, a, P, rho] = atmosphereData(absoluteAltitude, g, local); - -M = V_norm/a; -M_value = M; - -%% AERODYNAMICS ANGLES -if not(abs(ur) < 1e-9 || V_norm < 1e-9) - alpha = atan2(wr,ur); - beta = atan2(vr,ur); % beta = asin(vr/V_norm); is the classical notation, Datcom uses this one though. -else - alpha = 0; - beta = 0; -end - -alpha_value = alpha; -beta_value = beta; - -%% CHOSING THE CONDITION VALUE -% interpolation of the coefficients with the value in the nearest condition of the Coeffs matrix - -c = 1; % descent with no aerobrakes - -%% INTERPOLATE AERODYNAMIC COEFFICIENTS: - -if abs(alpha)>25*pi/180 || abs(beta)>25*pi/180 - coeffsValues = interpN( settings.highAOA.Coeffs,... - {settings.highAOA.State.Alphas, settings.highAOA.State.Machs, settings.highAOA.State.Betas, settings.highAOA.State.Altitudes}, ... - [alpha, M, beta, absoluteAltitude]); - angle0 = [alpha beta]; - flippedFlag = true; -else - if flippedFlag - coeffsValues = interpN( settings.Coeffs(:, :, :, :, :, c, end),... - {settings.State.Alphas, settings.State.Machs, settings.State.Betas, settings.State.Altitudes}, ... - [alpha, M, beta, absoluteAltitude]); - angle0 = [alpha beta]; - else - [coeffsValues, angle0] = interpCoeffs(t, alpha, M, beta, absoluteAltitude, c, settings); - end -end - -% Retrieve Coefficients -CA = coeffsValues(1); CYB = coeffsValues(2); CY0 = coeffsValues(3); -CNA = coeffsValues(4); CN0 = coeffsValues(5); Cl = coeffsValues(6); -Clp = coeffsValues(7); Cma = coeffsValues(8); Cm0 = coeffsValues(9); -Cmad = coeffsValues(10); Cmq = coeffsValues(11); Cnb = coeffsValues(12); -Cn0 = coeffsValues(13); Cnr = coeffsValues(14); Cnp = coeffsValues(15); - -% compute CN,CY,Cm,Cn (linearized with respect to alpha and beta): -alpha0 = angle0(1); beta0 = angle0(2); - -CN = (CN0 + CNA*(alpha - alpha0)); -CY = (CY0 + CYB*(beta - beta0)); -Cm = (Cm0 + Cma*(alpha - alpha0)); -Cn = (Cn0 + Cnb*(beta - beta0)); - -%% FORCES -% first computed in the body-frame reference system -qdyn = 0.5*rho*V_norm^2; % [Pa] dynamics pressure -qdynL_V = 0.5*rho*V_norm*S*C; % - -fX = qdyn*S*CA; % [N] x-body component of the aerodynamics force -fY = qdyn*S*CY; % [N] y-body component of the aerodynamics force -fZ = qdyn*S*CN; % [N] z-body component of the aerodynamics force -Fg = dcm*[0; 0; m*g]; % [N] force due to the gravity - -F = Fg +[-fX, +fY, -fZ]'; % [N] total forces vector - -%% STATE DERIVATIVES -% velocity -du = F(1)/m - q*w + r*v; -dv = F(2)/m - r*u + p*w; -dw = F(3)/m - p*v + q*u; - -% Rotation -dp = (Iyy - Izz)/Ixx*q*r + qdynL_V/Ixx*(V_norm*Cl + Clp*p*C/2); -dq = (Izz - Ixx)/Iyy*p*r + qdynL_V/Iyy*(V_norm*Cm + (Cmad + Cmq)*q*C/2); -dr = (Ixx - Iyy)/Izz*p*q + qdynL_V/Izz*(V_norm*Cn + (Cnr*r + Cnp*p)*C/2); - -% Quaternion -OM = 1/2* [ 0 -p -q -r ; - p 0 r -q ; - q -r 0 p ; - r q -p 0 ]; - -dQQ = OM*Q'; - -%% FINAL DERIVATIVE STATE ASSEMBLING -dY(1:3) = Vels; -dY(4) = du; -dY(5) = dv; -dY(6) = dw; -dY(7) = dp; -dY(8) = dq; -dY(9) = dr; -dY(10:13) = dQQ; -dY = dY'; - -%% SAVING THE QUANTITIES FOR THE PLOTS -parout.integration.t = t; - -parout.interp.M = M_value; -parout.interp.alpha = alpha_value; -parout.interp.beta = beta_value; -parout.interp.alt = -z; - -parout.wind.NED_wind = [uw, vw, ww]; -parout.wind.body_wind = wind; - -parout.rotations.dcm = dcm; - -parout.velocities = Vels; - -parout.forces.AeroDyn_Forces = [fX, fY, fZ]; -parout.forces.T = T; - -parout.air.rho = rho; -parout.air.P = P; - -parout.accelerations.body_acc = [du, dv, dw]; -parout.accelerations.ang_acc = [dp, dq, dr]; - -parout.forces.AeroDyn_Forces = [fX, fY, fZ]; -parout.forces.T = T; -parout.coeff.CA = CA; -parout.coeff.CYB = CYB; -parout.coeff.CNA = CNA; -parout.coeff.Cl = Cl; -parout.coeff.Clp = Clp; -parout.coeff.Cma = Cma; -parout.coeff.Cmad = Cmad; -parout.coeff.Cmq = Cmq; -parout.coeff.Cnb = Cnb; -parout.coeff.Cnr = Cnr; -parout.coeff.Cnp = Cnp; - -if eventLanding(t, Y, settings)<0 - clear flippedFlag; -end - -end \ No newline at end of file diff --git a/functions/odeFunctions/descentParachute.m b/functions/odeFunctions/descentParachute.m index 8d5b06f07035752aa9519d7aed68cd9eeea92939..9f1fcdd0b842ab2d363e69028fcd7191f61f2c48 100644 --- a/functions/odeFunctions/descentParachute.m +++ b/functions/odeFunctions/descentParachute.m @@ -1,12 +1,13 @@ -function [dY, parout] = descentParachute(t, Y, rocket, environment, wind, settings, descentData) +function [dY, parout] = descentParachute(~, Y, rocket, environment, wind, settings, descentData, wrapper) arguments - t + ~ Y rocket Rocket environment Environment - wind WindCustom {mustBeA(wind, {'WindCustom', 'WindMatlab'})} + wind % WindCustom {mustBeA(wind, {'WindCustom', 'WindMatlab'})} settings Settings descentData struct + wrapper = [] %DataWrapper = DataWrapper.empty end %{ descentParachute - ode function of the descent with parachute @@ -44,7 +45,9 @@ u = Y(4); v = Y(5); w = Y(6); -%% CONSTANTS +dY = zeros(6, 1); + +%% GETTING DATA if isfield(settings.simulator, 'stochNumber') para = settings.stoch.para; %!!!!!!!!!! @@ -64,10 +67,11 @@ local = [environment.z0, environment.temperature, ... % vector containing inpu environment.pressure, environment.rho]; %% ADDING WIND (supposed to be added in NED axes); -if isa(wind, 'WindMatlab') - [uw, vw, ww] = wind.getVels(altitude, t); -else - [uw, vw, ww] = wind.getVels(altitude); +switch class(wind) + case 'WindMatlab' + [uw, vw, ww] = wind.getVels(altitude, theta); + case 'WindCustom' + [uw, vw, ww] = wind.getVels(altitude); end windVels = [uw vw ww]; @@ -124,27 +128,27 @@ dv = F(2)/m; dw = F(3)/m; %% FINAL DERIVATIVE STATE ASSEMBLING -dY(1:3) = [u v w]; +dY(1:3) = [u; v; w]; dY(4) = du; dY(5) = dv; dY(6) = dw; -dY = dY'; - %% SAVING THE QUANTITIES FOR THE PLOTS -%if settings.plots -parout.integration.t = t; -parout.interp.alt = altitude; -parout.interp.mass = m; -parout.wind.body_wind = [uw, vw, ww]; -parout.wind.NED_wind = [uw, vw, ww]; - -parout.air.rho = rho; -parout.air.P = P; - -parout.accelerations.body_acc = [du, dv, dw]; - -parout.velocities = [u, v, w]; -parout.accelerometer = []; - -%end +if nargout == 2 || ~isempty(wrapper) + parout.interp.alt = altitude; + parout.interp.mass = m; + parout.wind.body = [uw, vw, ww]; + parout.wind.NED = [uw, vw, ww]; + + parout.air.rho = rho; + parout.air.P = P; + + parout.accelerations.body = [du, dv, dw]; + + parout.velocities = [u, v, w]; + parout.accelerometer = []; + + if ~isempty(wrapper) + wrapper.setCache(parout); + end +end \ No newline at end of file diff --git a/settings/odeConfig.m b/settings/odeConfig.m index 15f92ea389448bd17d66e48edb5d95950487cdbf..031e3512587a7466740006fef8ba1858497723d3 100644 --- a/settings/odeConfig.m +++ b/settings/odeConfig.m @@ -2,11 +2,9 @@ % ODE settings ode.finalTime = 2000; % [s] Final integration time -ode.optAscent = odeset('Events', @eventApogee, 'InitialStep', 1, ... - 'OutputFcn', @storeData); % ODE options for ascend +ode.optAscent = odeset('Events', @eventApogee, 'InitialStep', 1); % ODE options for ascend ode.optAscentDelayPara= odeset('InitialStep', 1); % ODE options for due to the opening delay of the parachute -ode.optParachute = odeset('Events', @eventParaCut, 'InitialStep', 1, .... - 'OutputFcn', @storeData); % ODE options for the parachutes +ode.optParachute = odeset('Events', @eventParaCut, 'InitialStep', 1); % ODE options for the parachutes ode.optDescent = odeset('Events', @eventLanding,... 'RelTol', 1e-3, 'AbsTol', 1e-3, 'OutputFcn', @storeData); % ODE options for ballistic descent ode.optLaunchpad = odeset('Events', @eventPad); % ODE options for the launchpad phase