The first, the ability to model a wing with a different root and tip airfoil was much more difficult than originally anticipated. The difficulty has to do with how MATLAB graphs an object. As alluded on the Background page, graphing a single airfoil is trivial, along with extending that approach out to a wing. Each airfoil has a set of coordinates that describe its shape along the X-Y axis. The wing is plotted by drawing a line from the trailing edge of the first airfoil to the trailing edge of the second airfoil. A line is then drawn along the airfoil cross-section to the next X-coordinate. Another line is then drawn from the second airfoil to the first airfoil. Finally, a line is drawn along the airfoil cross-section again to complete the face. As shown under Wing Plotting Steps this process is repeated across the entire airfoil cross-section.
Here is a snippet of the code that draws one segment of the wing.
for t = 1:airfoil_size(1)
if t <= airfoil_size(1) - 1
XWRT = [((airfoil_coords_x(t) + XW1) * c) - c, ((airfoil_coords_x(t).* tp + XW2) * c) - c,...
((airfoil_coords_x(t + 1).* tp + XW2) * c) - c, ((airfoil_coords_x(t + 1) + XW1) * c) - c];
YWRT = [(airfoil_array(1)), (airfoil_array(1) + b / 2), (airfoil_array(1) + b / 2), (airfoil_array(1))];
ZWRT = [((airfoil_coords_y(t) + ZW1) * c) - c, ((airfoil_coords_y(t).* tp + ZW2) * c) - c,...
((airfoil_coords_y(t + 1).* tp + ZW3) * c) - c, ((airfoil_coords_y(t + 1) + ZW4) * c) - c];
WRT = fill3(XWRT, YWRT, ZWRT, [0.5 0.5 0.5]);
t = t + 1;
end
end
Now all of this is simple to understand and use. You want to plot a wing, input the airfoil coordinates and you’re done. The problem is what if you want to plot a wing with a different airfoil for the root and tip? If the number of points in both airfoils are the same, then it’s no big deal, it works the same way. However, what if the tip airfoil has more points than the root airfoil, or vice versa?
Suppose we wish to create a wing with a NACA 2412 airfoil for the root and a NACA 63(1)-212 airfoil for the tip. The 2412 has 35 points along it’s cross-section, while the 63(1)-212 has 141.
The difficulty is in how an airfoil is constructed. What you need to do then is increase the size of the array of the NACA 2412 airfoil to equal the NACA 63(1)-212. The problem is ensuring that the increased array is the same geometric shape and size as a standard NACA 2412. Each point that is added to the 2412 airfoil has to be at the same X-Axis location as the 63(1)-212 airfoil for MATLAB to plot a face connecting those segments as shown in the above steps. Enlarging the 2412 is straightforward enough, just increase the size of the array and ensure the Y-Axis points correspond to the correct X-Axis points. Once you have this enlarged array, you need to fill in the X-Axis location gaps (gaps because the 2412 has X-Axis points from 0.9, 0.95, 1 while the 63(1)-212 has X-Axis points from 0.968…, 0.987…, 1) with the points from the 63(1)-212.
The tricky part is that for each of these extra filled in points, you need to calculate the corresponding Y-Axis point that still fits geometrically with the original airfoil. You can do this by calculating the slope of the corresponding segment as, m = (y2 - y1) / (x2 - x1), where m is the slope of the segment and y2 and y1 are the Y-Axis points and x2 and x1 are the X-Axis points respectively. Also knowing the slopes of each segment isn’t enough, you also need to know it’s position on the airfoil. In other words, the slope is found from the local coordinates between each segment, you also need the global coordinates of the full airfoil to understand where to place the Y-Axis point for each X-Axis point that was filled in.
Initial attempts at working the problem.
Finally, this process needs to be completed for both airfoils, to ensure that their X-Axis points line up and the Y-Axis points are in the correct location. After this is complete, the full wing can be plotted.
The following snippets of code are the MATLAB implementations of the process described above.
Code that fills in gaps after smaller airfoil is enlarged.
% Following code places all of the original airfoil Y-Axis points
% on the new combined airfoil X-Axis points. The location of each
% Y-Axis point is the same as that of the original airfoil,
% ensuring that the new combined airfoil is the same geometrically
% as the original just a larger array
% Initialize necessary arrays
comboAirfoilSize = length(comboAirfoil_coords_xRoot);
findYLocationArrayRoot = zeros(airfoil_sizeRoot,1);
rearrangedYArray = zeros(comboAirfoilSize,1);
midpointRoot = find(airfoil_coords_xRoot == min(airfoil_coords_xRoot));
midpointCombo = find(comboAirfoil_coords_xRoot == min(comboAirfoil_coords_xRoot));
% Arrange the Y-cordinate points according to the order that they
% were on the original airfoil
for iRoot = 1:airfoil_sizeRoot(end)
intermediateArrayRoot = find(comboAirfoil_coords_xRoot == airfoil_coords_xRoot(iRoot));
if length(intermediateArrayRoot) > 1
if intermediateArrayRoot(1) == iRoot == false && iRoot < midpointRoot == true ||...
intermediateArrayRoot(end) == iRoot == false && iRoot < midpointRoot == true
intermediateArrayRoot(end) = [];
findYLocationArrayRoot(iRoot) = intermediateArrayRoot;
elseif intermediateArrayRoot(1) == iRoot == false && iRoot > midpointRoot == true ||...
intermediateArrayRoot(end) == iRoot == false && iRoot > midpointRoot == true
intermediateArrayRoot(1) = [];
findYLocationArrayRoot(iRoot) = intermediateArrayRoot;
else
intermediateArrayRoot(end) = [];
findYLocationArrayRoot(iRoot) = intermediateArrayRoot;
end
else
findYLocationArrayRoot(iRoot) = intermediateArrayRoot;
end
if length(find(findYLocationArrayRoot == intermediateArrayRoot)) > 1
tempFind = find(findYLocationArrayRoot == intermediateArrayRoot);
findYLocationArrayRoot(iRoot) = tempFind(end);
else
findYLocationArrayRoot(iRoot) = find(findYLocationArrayRoot == intermediateArrayRoot);
end
if iRoot ~= 1 && iRoot < midpointRoot && length(find(comboAirfoil_coords_xRoot == airfoil_coords_xRoot(findYLocationArrayRoot(iRoot)) == 1)) > 1
findYSortedRoot = comboAirfoil_coords_xRoot(1:midpointCombo) == airfoil_coords_xRoot(findYLocationArrayRoot(iRoot));
extraZeros = false(comboAirfoilSize-length(findYSortedRoot),1);
if isempty(extraZeros) == 1
extraZeros = 0;
end
findYSortedRoot = [findYSortedRoot;extraZeros];
elseif iRoot ~= 1 && iRoot > midpointRoot && length(find(comboAirfoil_coords_xRoot == airfoil_coords_xRoot(findYLocationArrayRoot(iRoot)) == 1)) > 1
findYSortedRoot = comboAirfoil_coords_xRoot(midpointCombo:end) == airfoil_coords_xRoot(findYLocationArrayRoot(iRoot));
extraZeros = false(comboAirfoilSize-length(findYSortedRoot),1);
findYSortedRoot = [extraZeros;findYSortedRoot];
else
findYSortedRoot = comboAirfoil_coords_xRoot == airfoil_coords_xRoot(findYLocationArrayRoot(iRoot));
end
if length(find(comboAirfoil_coords_xRoot == 0)) > 1
for j = 1:airfoil_sizeRoot(end)
if findYSortedRoot(j) ~= 1
findYSortedRoot(j) = 0;
else
findYSortedRoot(j) = 1;
end
end
end
% Final array that includes all of the original Y-Axis points
% on the correct X-Axis points (includes empty spots)
rearrangedYArray(findYSortedRoot) = airfoil_coords_yRoot(findYLocationArrayRoot(iRoot));
end
Code that calculates the slope of each segment and location of each segment on airfoil.
% Next we need to determine the slope of each segment of the airfoil. This
% is accomplished by finding all of the empty spots on the rearrangedYArray
% array. The empty spots are for all of the points that are added in to
% increase the size of the array so that each array (root and tip) are the
% same size.
% Once all of the empty spots are found then need to increment above and
% below that empty spot to find the two X-Axis and Y-Axis points to input
% into the slope formula: m = (y2-y1)/(x2-x1).
% Initialize values
findEmptySpots = find(rearrangedYArray == 0);
emptySpotsSlopeRoot = zeros(length(findEmptySpots),1);
incBack = 1;
incFront = 1;
% Determine if start incrementing at the first or second value. If the
% first value in the array is a zero then start incrementing at 2 otherwise
% start at 1
iTestStart = findEmptySpots(1)-incBack;
if iTestStart == 0
iStart = 2;
else
iStart = 1;
end
% Determine if end incrementing at the last or second to last value. If the
% end value in the array is a zero then end incrementing at 1 otherwise end
% at 0
iTestEnd = findEmptySpots(end)+incFront;
if iTestEnd > length(rearrangedYArray)
iEnd = 1;
else
iEnd = 0;
end
% Grab the first and last values of the Y-Axis array
checkOriginRootStart = airfoil_coords_yRoot(1);
checkOriginRootEnd = airfoil_coords_yRoot(end);
% Determine if need to adjust increment values along the empty spots. If
% the gap between an empty spot is greater than 2, in other words if the
% above and below value of an empty spot is zero then need to adjust the
% increment to find a value that is closet to the empty spot and is
% nonzero.
for i = iStart:length(findEmptySpots)-iEnd
incBack = 1;
incFront = 1;
backValue = rearrangedYArray(findEmptySpots(i)-incBack);
frontValue = rearrangedYArray(findEmptySpots(i)+incFront);
% Find nonzero values above the empty spot
if backValue == 0
for incBack = 1:20
if findEmptySpots(i)-incBack <= 0
incBack = incBack - 1;
break
end
backValue = rearrangedYArray(findEmptySpots(i)-incBack);
if backValue ~= 0
break
elseif findEmptySpots(i)-incBack == midpointCombo
break
elseif rearrangedYArray(findEmptySpots(i)-incBack) == checkOriginRootStart && i == iStart
break
else
continue
end
end
end
% Find nonzero values below the empty spot
if frontValue == 0
for incFront = 1:20
if findEmptySpots(i)+incFront == length(rearrangedYArray)
break
elseif findEmptySpots(i)+incFront > length(rearrangedYArray)
frontValue = frontValue - 1;
break
end
frontValue = rearrangedYArray(findEmptySpots(i)+incFront);
if frontValue ~= 0
break
elseif findEmptySpots(i)+incFront == midpointCombo
break
elseif rearrangedYArray(findEmptySpots(i)+incFront) == checkOriginRootEnd && i == length(findEmptySpots)-iEnd
break
else
continue
end
end
end
% Calculates slope across the empty spot
if findEmptySpots(i) == midpointCombo
emptySpotsSlopeRoot(i) = 0;
else
emptySpotsSlopeRoot(i) = (rearrangedYArray(findEmptySpots(i) + incFront)...
- rearrangedYArray(findEmptySpots(i) - incBack)) / (comboAirfoil_coords_xRoot(findEmptySpots(i)...
+ incFront) - comboAirfoil_coords_xRoot(findEmptySpots(i) - incBack));
end
end
% Calculates the empty spot value based on the slope across the empty spot
% and the nearest nonzero value.
for i = iStart:length(findEmptySpots)-iEnd
rearrangedYArray(findEmptySpots(i)) = rearrangedYArray(findEmptySpots(i)-1) +...
emptySpotsSlopeRoot(i) .* (comboAirfoil_coords_xRoot(findEmptySpots(i)) - comboAirfoil_coords_xRoot(findEmptySpots(i)-1));
if findEmptySpots(i) == midpointCombo
rearrangedYArray(findEmptySpots(i)) = 0;
end
end
% Sets the final combined airfoil Y-Axis array to the final
% rearrangedYArray array (empty spots are filled in)
comboAirfoil_coords_yRoot = rearrangedYArray;
Here are the finished airfoils for the root and tip, the NACA 2412 and NACA 63(1)-212.
Finally, here is the code that plots the wing. Note how rather then using a FOR loop to create the wing by drawing a face connecting both segments together on the root and tip, a surface function is used which creates the wing by lofting a surface between the root and tip airfoils. The above process still holds true, where the X-Axis points need to be in the same location across the root and tip for the loft to work. A FOR loop would still work, but a surface is faster and also allows for shading the model. I showed the steps of using a FOR loop to help better understand the overall process.
% X-Coordinates
XW1 = 0;
XW2=XW1 + (b/2)*tand(LamLE);
XW3=XW2+tipChord;
XW4=XW1+rootChord;
% Z-Coordinates
ZW1=rootChord*sind(i_w);
ZW2=(XW4-XW2)*sind(i_w)+(b/2)*tand(Gam);
ZW3=(XW4-XW3)*sind(i_w)+(b/2)*tand(Gam);
XWRRoot = ((comboAirfoil_coords_xRoot).*rootChord)+XW1;
XWRTip = ((comboAirfoil_coords_xTip.*tipChord)+XW2);
YWRT = zeros(length(XWRRoot),2);
ZWRRoot = ((comboAirfoil_coords_yRoot).*rootChord)+ZW1;
ZWRTip = ((comboAirfoil_coords_yTip).*tipChord)+ZW2;
YWRT(:,1) = 0;
YWRT(:,2) = b/2-((b/2)-(b/2)*cosd(Gam));
XWRT = [XWRRoot,XWRTip];
ZWRT = [ZWRRoot,ZWRTip];
% Plot Right Wing
WRT = surface(XWRT,YWRT,ZWRT);