diff --git a/classes/misc/Coefficient.m b/classes/misc/Coefficient.m index f48b71dcd01d42776ebc62529a411bb3ff7e902a..a230fbf0de742df8a62fb259c4f39aa61a4f6601 100644 --- a/classes/misc/Coefficient.m +++ b/classes/misc/Coefficient.m @@ -55,6 +55,11 @@ classdef Coefficient finsCN double % Fins-only CN 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 + end + properties(Access = private) STATIC % Cached variable for static coefficients DYNAMIC % Cached variable for dynamic derivatives @@ -63,8 +68,6 @@ classdef Coefficient end properties(Access = private) - loadDynamic (1, 1) logical % Whether to load dynamic derivatives. Adds XCG dependece - staticInterpolant (1, 1) griddedInterpolant dynamicInterpolant (1, 1) griddedInterpolant end @@ -77,6 +80,8 @@ classdef Coefficient end obj = obj.loadData(filePath, name); + obj.isReady = obj.checkProperties(); + obj = obj.updateInterpolants(); end function coefficients = get(obj, alpha, mach, beta, altitude, airbakes, xcg) @@ -102,6 +107,8 @@ classdef Coefficient % the specified xcg. Dynamic derivatives are included only if % loadDynamic is true. + if ~obj.isReady, error('Canno interpolate coefficients: check that all dimensions match'); end + coefficients = zeros(11, 1); coefficients(1:6) = obj.staticInterpolant(alpha, mach, beta, altitude, airbakes); % Transporting static coefficients to new xcg @@ -115,7 +122,7 @@ classdef Coefficient coefficients(4:6) = coefficients(4:6) + d/l * forceCoeffs; - if ~obj.loadDynamic, return; end + if ~obj.isDynamic, return; end coefficients(7:11) = obj.dynamicInterpolant(alpha, mach, beta, altitude, airbakes, xcg); end end @@ -140,23 +147,27 @@ classdef Coefficient methods % Setters function obj = set.static(obj, value) - obj.STATIC = value(:, :, :, :, :, :, 1); - obj = obj.updateInterpolants(); + obj.STATIC = value(:, :, :, :, :, :, 1); + obj.isReady = obj.checkProperties(); + obj = obj.updateInterpolants(); end function obj = set.dynamic(obj, value) obj.DYNAMIC = value(:, :, :, :, :, :, :); - obj = obj.updateInterpolants(); + obj.isReady = obj.checkProperties(); + obj = obj.updateInterpolants(); end function obj = set.geometry(obj, value) obj.GEOMETRY = value; - obj = obj.updateInterpolants(); + obj.isReady = obj.checkProperties(); + obj = obj.updateInterpolants(); end function obj = set.state(obj, value) - obj.STATE = value; - obj = obj.updateInterpolants(); + obj.STATE = value; + obj.isReady = obj.checkProperties(); + obj = obj.updateInterpolants(); end end @@ -179,17 +190,17 @@ classdef Coefficient if ~isfield(dataCoeffs, name), return; end dataCoeffs = dataCoeffs.(name); - obj.loadDynamic = ~strcmp(name, 'generic'); + obj.isDynamic = ~strcmp(name, 'generic'); obj.finsCN = dataCoeffs.finsCN; - obj.geometry = dataCoeffs.geometry; - obj.state = dataCoeffs.state; + obj.GEOMETRY = dataCoeffs.geometry; + obj.STATE = dataCoeffs.state; % Load CA, CY, CN, Cl, Cm, Cn - obj.static = dataCoeffs.total([1, 3, 5, 6, 9, 13], :, :, :, :, :, :); + obj.STATIC = dataCoeffs.total([1, 3, 5, 6, 9, 13], :, :, :, :, :, :); - if obj.loadDynamic + if obj.isDynamic % Load Clp, Cmad, Cmq, Cnr, Cnp - obj.dynamic = dataCoeffs.total([7, 10, 11, 14, 15], :, :, :, :, :, :); + obj.DYNAMIC = dataCoeffs.total([7, 10, 11, 14, 15], :, :, :, :, :, :); end end @@ -197,39 +208,70 @@ classdef Coefficient % Check if STATIC, DYNAMIC, GEOMETRY, and STATE are non-empty ready = ~isempty(obj.STATIC) && ... ~isempty(obj.GEOMETRY) && ~isempty(obj.STATE) && ... - ~(isempty(obj.DYNAMIC) && obj.loadDynamic); + ~(isempty(obj.DYNAMIC) && obj.isDynamic); + + if ~ready, return; end + + 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}; + dims = cellfun(@(x) length(x), gridVecs); + dims(dims == 0) = 1; % Empty case is the same as scalar case + + staticDimsReady = all(size(obj.STATIC, 2:6) == dims(1:end-1)); + dynamicDimsReady = true; + + if obj.isDynamic + dynamicDimsReady = all(size(obj.DYNAMIC, 2:7) == dims); + end + + ready = ready && staticDimsReady && dynamicDimsReady; end function obj = updateInterpolants(obj) % Update static and dynamic interpolants - if ~obj.checkProperties(), return; end + if ~obj.isReady, return; end %% 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; - airbakes = obj.state.hprot/obj.state.hprot(end); % Normalizing on height + 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 + + gridVecs = {alpha, mach, beta, 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 = permute(obj.STATIC, [2, 3, 4, 5, 6, 1]); + staticCoeffs = repmat(staticCoeffs, singletonDims(1:end-1) + 1); % Exclude xcg for static coefficients - gridVecs = {alpha, mach, beta, altitude, airbakes}; - obj.staticInterpolant = griddedInterpolant(gridVecs, staticCoeffs, 'linear', 'nearest'); + obj.staticInterpolant = griddedInterpolant(gridVecs(1:end-1), staticCoeffs, 'linear', 'nearest'); - if ~obj.loadDynamic, return; end + if ~obj.isDynamic, return; end - xcg = obj.geometry.xcg; - dynamicCoeffs = permute(obj.dynamic, [2, 3, 4, 5, 6, 7, 1]); + %% Handle dynamic derivatives + dynamicCoeffs = permute(obj.DYNAMIC, [2, 3, 4, 5, 6, 7, 1]); - if xcg(2) < xcg(1) % Flip xcg in case of descending order - xcg = flip(xcg); + % Flip xcg in case of descending order + if ~isscalar(xcg) && xcg(2) < xcg(1) + gridVecs{end} = flip(xcg); dynamicCoeffs = flip(dynamicCoeffs, 7); end - gridVecs = {alpha, mach, beta, altitude, airbakes, xcg}; obj.dynamicInterpolant = griddedInterpolant(gridVecs, dynamicCoeffs, 'linear', 'nearest'); end end -end - +end \ No newline at end of file