From afa7806ade96b763eca8c94e4d618d0bb5600c3a Mon Sep 17 00:00:00 2001 From: Thomas Lambert <dev@tlambert.be> Date: Tue, 12 Mar 2024 16:46:45 +0100 Subject: [PATCH] feat(Airfoil): add airfoil interpolation --- +af_tools/@Airfoil/Airfoil.m | 5 ++ +af_tools/@Airfoil/interpairfoil.m | 123 +++++++++++++++++++++++++++++ CHANGELOG.md | 10 ++- 3 files changed, 137 insertions(+), 1 deletion(-) create mode 100644 +af_tools/@Airfoil/interpairfoil.m diff --git a/+af_tools/@Airfoil/Airfoil.m b/+af_tools/@Airfoil/Airfoil.m index a03c17c..6eb3a67 100644 --- a/+af_tools/@Airfoil/Airfoil.m +++ b/+af_tools/@Airfoil/Airfoil.m @@ -99,4 +99,9 @@ classdef Airfoil < handle end end + + methods (Static) + % Create an airfoil by interpolating between two different Airofil objects + self = interpairfoil(Airfoil1, Airfoil2, weightAirfoil2) + end end diff --git a/+af_tools/@Airfoil/interpairfoil.m b/+af_tools/@Airfoil/interpairfoil.m new file mode 100644 index 0000000..58fe57e --- /dev/null +++ b/+af_tools/@Airfoil/interpairfoil.m @@ -0,0 +1,123 @@ +function self = interpairfoil(Airfoil1, Airfoil2, weightAirfoil2) + % INTERPAIRFOIL Create a new Airfoil object by interpolation of two other Airfoils. + % This static method can be used in place of a normal constructor for the Airfoil class. + % This method can be used when the user wants to create a non-standard airfoil made from + % the interpolation bewteen two known airfoils. + % Consider that the airfoil at x=0 is a NACA 0012, and the one at x=1 is a CLARY-Y. + % Rather than assuming that all segments in [0,1] are NACA 0012 and all segments after 1 are + % CLARK-Y, this function allows to create polars for the [0,1] interval that are a mix between + % the two bounds. If we are at 0.1, the newly created Airfoil object, will then be 90% of NACA + % 0012 and 10% of CLARK-Y. + % Note: + % The two input Airfoils should contain Polars of similar structure + % (same Reynolds, Mach and nCrit). + % ----- + % + % Usage: + % MixedAirfoil = Airfoil.INTERPPOLAR(Airfoil1, Airfoil2, weightAirfoil2) create an new Airofil + % object that is a linear interpolation between Airfoil1 and Airfoil2, with a given weight for + % Airfoil2. + % + % Inputs: + % Airfoil1 : Airfoil object for one part of the interpolation. + % Airfoil2 : Airfoil object for the second part of the interpolation. + % Airfoil2.Polar must have the same Re, Mach and nCrit values as + % Airfoil1.Polar. + % weightAirfoil2 : Scalar in [0-1] to skew the interpolation properly between Airfoil1 and + % Airfoil2. + % + % Output: + % self : Airfoil object that results from the interpolation. + % + % Example: + % MixedAirfoil = af_tools.interpairfoil(AfNACA0012, AfClarkY, 0.6); Creates an interpolated + % Airfoil object MixedAirfoil that results from the interpolation of AfNACA0012 + % and AfClarkY, asssuming that the MixedPolar is made of 60% ClarkY and 40% + % NACA0012. + % + % See also: af_tools.Airfoil, af_tools.Polar. + % + % ----- + % <a href="https://gitlab.uliege.be/am-dept/matlab_airfoil_toolbox">Documentation (online)</a> + + % ---------------------------------------------------------------------------------------------- + % (c) Copyright 2022-2024 University of Liege + % Author: Thomas Lambert <t.lambert@uliege.be> + % ULiege - Aeroelasticity and Experimental Aerodynamics + % MIT License + % Repo: https://gitlab.uliege.be/am-dept/matlab_airfoil_toolbox + % Issues: https://gitlab.uliege.be/am-dept/matlab_airfoil_toolbox/-/issues + % ---------------------------------------------------------------------------------------------- + + % --- Defaults and constants + DEBUG = false; + + % --- Input checks + % Check if both Airfoils are Airfoil objects and weightAirfoil2 is in [0,1] + validateattributes(Airfoil1, {'af_tools.Airfoil'}, {'scalar'}, mfilename(), 'Airfoil1', 1); + validateattributes(Airfoil2, {'af_tools.Airfoil'}, {'scalar'}, mfilename(), 'Airfoil2', 2); + validateattributes(weightAirfoil2, {'double'}, {'scalar', 'nonnegative', '<=', 1}, ... + mfilename(), 'weightAirfoil2', 3); + + % --- Interpolate the Airfoils + + self = af_tools.Airfoil; + + if Airfoil1 == Airfoil2 + self.name = Airfoil1.name; + self.coord = Airfoil1.Polar; + self.upper = Airfoil1.upper; + self.lower = Airfoil1.lower; + self.Polar = Airfoil1.Polar; + return + end + + % Private properties to prevent accidental re-assignment + wAf2 = weightAirfoil2; + wAf1 = 1 - wAf2; + + % Set base Airfoil information + self.name = sprintf('MIX-%d%%%s-%d%%%s', round(wAf1 * 100), Airfoil1.name, ... + round(wAf2 * 100), Airfoil2.name); + + % Interpolate coordinates and Polars + self.upper = interpsurf(wAf1, Airfoil1.upper, wAf2, Airfoil2.upper); + self.lower = interpsurf(wAf1, Airfoil1.lower, wAf2, Airfoil2.lower); + self.coord = [flipud(self.upper); self.lower(2:end, :)]; + + self.Polar = af_tools.Polar.interppolar(Airfoil1.Polar, Airfoil2.Polar, wAf2); + + % --- DEBUGGING + if DEBUG + % Plot the original Airfoil Coordinates as well as the interpolated one + figure('Name', 'Interpolated Airfoil'); + hold on; + plot(Airfoil1.coord(:, 1), Airfoil1.coord(:, 2)); + plot(Airfoil2.coord(:, 1), Airfoil2.coord(:, 2)); + plot(self.coord(:, 1), self.coord(:, 2)); + hold off; + legend(Airfoil1.name, Airfoil2.name, self.name, 'Location', 'NorthWest'); + grid on; + pause; + end + +end + +function newSurf = interpsurf(weight1, surfCoords1, weight2, surfCoords2) + % INTERPSURF Interpolate airfoil surfaces (ONE SURFACE AT A TIME, NOT FULL COORDS) + + % Reinterpolate original data based on the longest chord vector + if numel(surfCoords1(:, 1)) > numel(surfCoords2(:, 1)) + newX = surfCoords1(:, 1); + newY1 = surfCoords1(:, 2); + newY2 = interp1(surfCoords2(:, 1), surfCoords2(:, 2), newX); + else + newX = surfCoords2(:, 1); + newY1 = interp1(surfCoords1(:, 1), surfCoords1(:, 2), newX); + newY2 = surfCoords2(:, 2); + end + + newY = weight1 * newY1 + weight2 * newY2; + newSurf = [newX, newY]; + +end diff --git a/CHANGELOG.md b/CHANGELOG.md index 81b1f34..70f8f80 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed +## [4.4.0] - 2024-03-13 + +### Added + +- Creation of interpolated Polar between two reference Polars +- Creation of interpolated Airfoil between two reference Airfoils + ## [4.3.0] - 2023-12-14 ### Changed @@ -145,7 +152,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Initial release -[Unreleased]: https://gitlab.uliege.be/am-dept/matlab_airfoil_toolbox/-/compare/v4.3.0...master +[Unreleased]: https://gitlab.uliege.be/am-dept/matlab_airfoil_toolbox/-/compare/v4.4.0...master +[4.4.0]: https://gitlab.uliege.be/am-dept/matlab_airfoil_toolbox/-/compare/4.3.0...v4.4.0 [4.3.0]: https://gitlab.uliege.be/am-dept/matlab_airfoil_toolbox/-/compare/4.2.1...v4.3.0 [4.2.1]: https://gitlab.uliege.be/am-dept/matlab_airfoil_toolbox/-/compare/4.2.0...v4.2.1 [4.2.0]: https://gitlab.uliege.be/am-dept/matlab_airfoil_toolbox/-/compare/4.1.0...v4.2.0 -- GitLab