├── airfoils
├── coord_flat_plate_10.dat
├── coord_parabolic_10.dat
├── coord_parabolic_20.dat
├── coord_parabolic_50.dat
├── coord_flat_plate_100.dat
└── coord_parabolic_100.dat
├── coord_parabolic_front_20.dat
├── coord_parabolic_rear_30.dat
├── main.py
├── utils.py
└── README.md
/airfoils/coord_flat_plate_10.dat:
--------------------------------------------------------------------------------
1 | 0.000 0.000
2 | 0.100 0.000
3 | 0.200 0.000
4 | 0.300 0.000
5 | 0.400 0.000
6 | 0.500 0.000
7 | 0.600 0.000
8 | 0.700 0.000
9 | 0.800 0.000
10 | 0.900 0.000
11 | 1.000 0.000
12 |
--------------------------------------------------------------------------------
/airfoils/coord_parabolic_10.dat:
--------------------------------------------------------------------------------
1 | 0.000 0.000
2 | 0.100 0.036
3 | 0.200 0.064
4 | 0.300 0.084
5 | 0.400 0.096
6 | 0.500 0.100
7 | 0.600 0.096
8 | 0.700 0.084
9 | 0.800 0.064
10 | 0.900 0.036
11 | 1.000 0.000
12 |
--------------------------------------------------------------------------------
/coord_parabolic_front_20.dat:
--------------------------------------------------------------------------------
1 | 0.000 0.000
2 | 0.050 0.019
3 | 0.100 0.036
4 | 0.150 0.051
5 | 0.200 0.064
6 | 0.250 0.075
7 | 0.300 0.084
8 | 0.350 0.091
9 | 0.400 0.096
10 | 0.450 0.099
11 | 0.500 0.100
12 | 0.550 0.099
13 | 0.600 0.096
14 | 0.650 0.091
15 | 0.700 0.084
16 | 0.750 0.075
17 | 0.800 0.064
18 | 0.850 0.051
19 | 0.900 0.036
20 | 0.950 0.019
21 | 1.000 0.000
22 |
--------------------------------------------------------------------------------
/airfoils/coord_parabolic_20.dat:
--------------------------------------------------------------------------------
1 | 0.000 0.000
2 | 0.050 0.019
3 | 0.100 0.036
4 | 0.150 0.051
5 | 0.200 0.064
6 | 0.250 0.075
7 | 0.300 0.084
8 | 0.350 0.091
9 | 0.400 0.096
10 | 0.450 0.099
11 | 0.500 0.100
12 | 0.550 0.099
13 | 0.600 0.096
14 | 0.650 0.091
15 | 0.700 0.084
16 | 0.750 0.075
17 | 0.800 0.064
18 | 0.850 0.051
19 | 0.900 0.036
20 | 0.950 0.019
21 | 1.000 0.000
22 |
--------------------------------------------------------------------------------
/coord_parabolic_rear_30.dat:
--------------------------------------------------------------------------------
1 | 2.000 0.000
2 | 2.025 0.008
3 | 2.050 0.015
4 | 2.075 0.022
5 | 2.100 0.028
6 | 2.125 0.033
7 | 2.150 0.038
8 | 2.175 0.043
9 | 2.200 0.047
10 | 2.225 0.050
11 | 2.250 0.053
12 | 2.275 0.056
13 | 2.300 0.058
14 | 2.325 0.059
15 | 2.350 0.060
16 | 2.375 0.060
17 | 2.400 0.060
18 | 2.425 0.059
19 | 2.450 0.058
20 | 2.475 0.056
21 | 2.500 0.053
22 | 2.525 0.050
23 | 2.550 0.047
24 | 2.575 0.043
25 | 2.600 0.038
26 | 2.625 0.033
27 | 2.650 0.028
28 | 2.675 0.022
29 | 2.700 0.015
30 | 2.725 0.008
31 | 2.750 -0.000
32 |
--------------------------------------------------------------------------------
/airfoils/coord_parabolic_50.dat:
--------------------------------------------------------------------------------
1 | 0.000 0.000
2 | 0.020 0.008
3 | 0.040 0.015
4 | 0.060 0.023
5 | 0.080 0.029
6 | 0.100 0.036
7 | 0.120 0.042
8 | 0.140 0.048
9 | 0.160 0.054
10 | 0.180 0.059
11 | 0.200 0.064
12 | 0.220 0.069
13 | 0.240 0.073
14 | 0.260 0.077
15 | 0.280 0.081
16 | 0.300 0.084
17 | 0.320 0.087
18 | 0.340 0.090
19 | 0.360 0.092
20 | 0.380 0.094
21 | 0.400 0.096
22 | 0.420 0.097
23 | 0.440 0.099
24 | 0.460 0.099
25 | 0.480 0.100
26 | 0.500 0.100
27 | 0.520 0.100
28 | 0.540 0.099
29 | 0.560 0.099
30 | 0.580 0.097
31 | 0.600 0.096
32 | 0.620 0.094
33 | 0.640 0.092
34 | 0.660 0.090
35 | 0.680 0.087
36 | 0.700 0.084
37 | 0.720 0.081
38 | 0.740 0.077
39 | 0.760 0.073
40 | 0.780 0.069
41 | 0.800 0.064
42 | 0.820 0.059
43 | 0.840 0.054
44 | 0.860 0.048
45 | 0.880 0.042
46 | 0.900 0.036
47 | 0.920 0.029
48 | 0.940 0.023
49 | 0.960 0.015
50 | 0.980 0.008
51 | 1.000 0.000
52 |
--------------------------------------------------------------------------------
/airfoils/coord_flat_plate_100.dat:
--------------------------------------------------------------------------------
1 | 0.000 0.000
2 | 0.010 0.000
3 | 0.020 0.000
4 | 0.030 0.000
5 | 0.040 0.000
6 | 0.050 0.000
7 | 0.060 0.000
8 | 0.070 0.000
9 | 0.080 0.000
10 | 0.090 0.000
11 | 0.100 0.000
12 | 0.110 0.000
13 | 0.120 0.000
14 | 0.130 0.000
15 | 0.140 0.000
16 | 0.150 0.000
17 | 0.160 0.000
18 | 0.170 0.000
19 | 0.180 0.000
20 | 0.190 0.000
21 | 0.200 0.000
22 | 0.210 0.000
23 | 0.220 0.000
24 | 0.230 0.000
25 | 0.240 0.000
26 | 0.250 0.000
27 | 0.260 0.000
28 | 0.270 0.000
29 | 0.280 0.000
30 | 0.290 0.000
31 | 0.300 0.000
32 | 0.310 0.000
33 | 0.320 0.000
34 | 0.330 0.000
35 | 0.340 0.000
36 | 0.350 0.000
37 | 0.360 0.000
38 | 0.370 0.000
39 | 0.380 0.000
40 | 0.390 0.000
41 | 0.400 0.000
42 | 0.410 0.000
43 | 0.420 0.000
44 | 0.430 0.000
45 | 0.440 0.000
46 | 0.450 0.000
47 | 0.460 0.000
48 | 0.470 0.000
49 | 0.480 0.000
50 | 0.490 0.000
51 | 0.500 0.000
52 | 0.510 0.000
53 | 0.520 0.000
54 | 0.530 0.000
55 | 0.540 0.000
56 | 0.550 0.000
57 | 0.560 0.000
58 | 0.570 0.000
59 | 0.580 0.000
60 | 0.590 0.000
61 | 0.600 0.000
62 | 0.610 0.000
63 | 0.620 0.000
64 | 0.630 0.000
65 | 0.640 0.000
66 | 0.650 0.000
67 | 0.660 0.000
68 | 0.670 0.000
69 | 0.680 0.000
70 | 0.690 0.000
71 | 0.700 0.000
72 | 0.710 0.000
73 | 0.720 0.000
74 | 0.730 0.000
75 | 0.740 0.000
76 | 0.750 0.000
77 | 0.760 0.000
78 | 0.770 0.000
79 | 0.780 0.000
80 | 0.790 0.000
81 | 0.800 0.000
82 | 0.810 0.000
83 | 0.820 0.000
84 | 0.830 0.000
85 | 0.840 0.000
86 | 0.850 0.000
87 | 0.860 0.000
88 | 0.870 0.000
89 | 0.880 0.000
90 | 0.890 0.000
91 | 0.900 0.000
92 | 0.910 0.000
93 | 0.920 0.000
94 | 0.930 0.000
95 | 0.940 0.000
96 | 0.950 0.000
97 | 0.960 0.000
98 | 0.970 0.000
99 | 0.980 0.000
100 | 0.990 0.000
101 | 1.000 0.000
102 |
--------------------------------------------------------------------------------
/airfoils/coord_parabolic_100.dat:
--------------------------------------------------------------------------------
1 | 0.000 0.000
2 | 0.010 0.004
3 | 0.020 0.008
4 | 0.030 0.012
5 | 0.040 0.015
6 | 0.050 0.019
7 | 0.060 0.023
8 | 0.070 0.026
9 | 0.080 0.029
10 | 0.090 0.033
11 | 0.100 0.036
12 | 0.110 0.039
13 | 0.120 0.042
14 | 0.130 0.045
15 | 0.140 0.048
16 | 0.150 0.051
17 | 0.160 0.054
18 | 0.170 0.056
19 | 0.180 0.059
20 | 0.190 0.062
21 | 0.200 0.064
22 | 0.210 0.066
23 | 0.220 0.069
24 | 0.230 0.071
25 | 0.240 0.073
26 | 0.250 0.075
27 | 0.260 0.077
28 | 0.270 0.079
29 | 0.280 0.081
30 | 0.290 0.082
31 | 0.300 0.084
32 | 0.310 0.086
33 | 0.320 0.087
34 | 0.330 0.088
35 | 0.340 0.090
36 | 0.350 0.091
37 | 0.360 0.092
38 | 0.370 0.093
39 | 0.380 0.094
40 | 0.390 0.095
41 | 0.400 0.096
42 | 0.410 0.097
43 | 0.420 0.097
44 | 0.430 0.098
45 | 0.440 0.099
46 | 0.450 0.099
47 | 0.460 0.099
48 | 0.470 0.100
49 | 0.480 0.100
50 | 0.490 0.100
51 | 0.500 0.100
52 | 0.510 0.100
53 | 0.520 0.100
54 | 0.530 0.100
55 | 0.540 0.099
56 | 0.550 0.099
57 | 0.560 0.099
58 | 0.570 0.098
59 | 0.580 0.097
60 | 0.590 0.097
61 | 0.600 0.096
62 | 0.610 0.095
63 | 0.620 0.094
64 | 0.630 0.093
65 | 0.640 0.092
66 | 0.650 0.091
67 | 0.660 0.090
68 | 0.670 0.088
69 | 0.680 0.087
70 | 0.690 0.086
71 | 0.700 0.084
72 | 0.710 0.082
73 | 0.720 0.081
74 | 0.730 0.079
75 | 0.740 0.077
76 | 0.750 0.075
77 | 0.760 0.073
78 | 0.770 0.071
79 | 0.780 0.069
80 | 0.790 0.066
81 | 0.800 0.064
82 | 0.810 0.062
83 | 0.820 0.059
84 | 0.830 0.056
85 | 0.840 0.054
86 | 0.850 0.051
87 | 0.860 0.048
88 | 0.870 0.045
89 | 0.880 0.042
90 | 0.890 0.039
91 | 0.900 0.036
92 | 0.910 0.033
93 | 0.920 0.029
94 | 0.930 0.026
95 | 0.940 0.023
96 | 0.950 0.019
97 | 0.960 0.015
98 | 0.970 0.012
99 | 0.980 0.008
100 | 0.990 0.004
101 | 1.000 0.000
102 |
--------------------------------------------------------------------------------
/main.py:
--------------------------------------------------------------------------------
1 | ###########################################
2 | # coded by Pablo N. Zitelli
3 | # https://www.linkedin.com/in/pablozitelli
4 | ###########################################
5 |
6 | import sys
7 | import numpy as np
8 | import matplotlib.pyplot as plt
9 | from utils import *
10 |
11 | # aerodynamic parameters
12 | alphaDeg = 10.0
13 | vInf = 1.0
14 |
15 | # actual code
16 |
17 | # airfoils initialization
18 | airfoils = []
19 |
20 | airfoils.append(Airfoil('Front', 'coord_parabolic_front_20.dat'))
21 | airfoils.append(Airfoil('Rear', 'coord_parabolic_rear_30.dat'))
22 | #airfoils.append(Airfoil('Flat plate', 'coord_flat_plate_10.dat'))
23 |
24 | # induced velocity on panel i collocation point due to unit vortex on panel j (all airfoils)
25 | for am in airfoils:
26 | for pi in am.panels:
27 | for an in airfoils:
28 | for pj in an.panels:
29 | pi.unitVelIndCalc(pj.qPoint)
30 |
31 | # RHS (independent vector) definition
32 | N = 0
33 | for a in airfoils:
34 | N = N + a.panelNum
35 |
36 | b = np.zeros(N)
37 | vectorInf = np.array([vInf*np.cos(alphaDeg*np.pi/180.0), vInf*np.sin(alphaDeg*np.pi/180.0), 0.0])
38 |
39 | i = 0
40 | for a in airfoils:
41 | for p in a.panels:
42 | b[i] = -np.dot(vectorInf, p.n)
43 | i = i + 1
44 |
45 | # influence coefficients matrix definition
46 | A = np.zeros((N, N))
47 |
48 | i = 0
49 | for a in airfoils:
50 | for pi in a.panels:
51 | for j in range(N):
52 | A[i,j] = np.dot(pi.unitVelInd[j], pi.n)
53 |
54 | i = i + 1
55 |
56 | # linear system solution
57 | gamma = np.linalg.solve(A, b)
58 |
59 | # results
60 | i = 0
61 | for a in airfoils:
62 | for p in a.panels:
63 | p.setGamma(gamma[i])
64 | p.dCpCalc(vInf)
65 | i = i + 1
66 |
67 | # total quantity of panels in system
68 | totalPanels = []
69 | for a in airfoils:
70 | totalPanels = totalPanels + a.panels
71 |
72 | # airfoil lift
73 | for a in airfoils:
74 | for p in a.panels:
75 | p.totalIndVelCalc(totalPanels)
76 | p.liftCalc(vectorInf)
77 |
78 | a.liftCalc(vInf)
79 |
80 | writeResults(airfoils)
81 |
82 | # plot airfoils
83 | airfoilsNameList = []
84 | fig, ax = plt.subplots()
85 | for a in airfoils:
86 | airfoilsNameList.append(a.name)
87 | x = [p.nodes[0].coord[0] for p in a.panels]
88 | x.append(a.panels[-1].nodes[1].coord[0])
89 | y = [p.nodes[0].coord[1] for p in a.panels]
90 | y.append(a.panels[-1].nodes[1].coord[1])
91 | ax.plot(x, y, label=a.name)
92 |
93 | plt.axis('equal')
94 | plt.title('airfoils setup')
95 | plt.xlabel('x [m]')
96 | plt.ylabel('y [m]')
97 | plt.legend(airfoilsNameList)
98 | plt.grid()
99 |
100 | # delta Cp along airfoils
101 | f = 2
102 | for a in airfoils:
103 | # chord vector
104 | cVec = a.panels[-1].nodes[1].coord - a.panels[0].nodes[0].coord
105 |
106 | sC = [np.dot(p.mPoint-a.panels[0].nodes[0].coord, cVec)/a.c for p in a.panels]
107 | dCpPlot = [p.dCp for p in a.panels]
108 |
109 | plt.figure(f)
110 | plt.title(a.name)
111 | plt.plot(sC, dCpPlot, 'k')
112 | plt.xlabel('x/c')
113 | plt.ylabel('dCp')
114 | f = f + 1
115 |
116 | plt.show()
117 |
--------------------------------------------------------------------------------
/utils.py:
--------------------------------------------------------------------------------
1 | ###########################################
2 | # coded by Pablo N. Zitelli
3 | # https://www.linkedin.com/in/pablozitelli
4 | ###########################################
5 |
6 | import numpy as np
7 |
8 | # node class definition
9 | class Node:
10 | def __init__(self, coord, name):
11 | self.coord = coord
12 | self.id = name
13 |
14 | # panel class definition
15 | class Panel:
16 | def __init__(self, nodes, name):
17 | self.unitVelInd = []
18 | self.nodes = nodes
19 | self.id = name
20 | self.lift = 0.0
21 |
22 | # tangent unit vector and panel length
23 | tVec = self.nodes[1].coord - self.nodes[0].coord
24 | self.len = np.linalg.norm(tVec)
25 | self.t = tVec/self.len
26 |
27 | # normal unit vector
28 | kVersor = np.array([0.0, 0.0, 1.0])
29 | nVec = np.cross(kVersor, self.t)
30 | nMag = np.linalg.norm(nVec)
31 | self.n = nVec/nMag
32 |
33 | # quarter chord point coordinates
34 | self.qPoint = self.nodes[0].coord + 0.25*tVec
35 |
36 | # collocation point coordinates
37 | self.cPoint = self.nodes[0].coord + 0.75*tVec
38 |
39 | # midpoint coordinates
40 | self.mPoint = self.nodes[0].coord + 0.5*tVec
41 |
42 | # calculation of induced velocity produced by unit vortex
43 | def unitVelIndCalc(self, quarterPoint):
44 | vector = self.cPoint - quarterPoint
45 | r = np.linalg.norm(vector)
46 | u = (0.5/(np.pi*r**2))*vector[1]
47 | v = - (0.5/(np.pi*r**2))*vector[0]
48 | self.unitVelInd.append(np.array([u, v, 0.0]))
49 |
50 | def setGamma(self, gamma):
51 | self.gamma = gamma
52 |
53 | # delta Cp calculation across panel
54 | def dCpCalc(self, velInf):
55 | self.dCp = 2*self.gamma/(velInf*self.len)
56 |
57 | # total velocity induced by all vortices except itself
58 | def totalIndVelCalc(self, panels):
59 | self.totalVelInd = np.array([0.0, 0.0, 0.0])
60 | for p in panels:
61 | if self != p:
62 | distVec = self.qPoint - p.qPoint
63 | r = np.linalg.norm(distVec)
64 | u = p.gamma*(0.5/(np.pi*r**2))*distVec[1]
65 | v = - p.gamma*(0.5/(np.pi*r**2))*distVec[0]
66 | self.totalVelInd = self.totalVelInd + np.array([u, v, 0.0])
67 |
68 | # panel lift calculation (generalized Kutta-Joukowski)
69 | def liftCalc(self, velInf):
70 | vInf = np.linalg.norm(velInf)
71 | self.lift = 1.2*vInf*self.gamma*(1 + np.dot(velInf, self.totalVelInd)/vInf**2)
72 |
73 | # airfoil class definition
74 | class Airfoil:
75 | def __init__(self, name, coordFile):
76 | self.name = name
77 | self.panels = []
78 |
79 | # nodes coordinates reading
80 | nodesFile = np.loadtxt(coordFile)
81 |
82 | # nodes creation
83 | nodes = []
84 | count = 1
85 | for i in nodesFile:
86 | nodes.append(Node(np.array([i[0], i[1], 0.0]), count))
87 | count = count + 1
88 |
89 | # panels creation
90 | for i in range(len(nodes)-1):
91 | self.panels.append(Panel([nodes[i], nodes[i+1]], i+1))
92 |
93 | self.panelNum = len(self.panels)
94 |
95 | # chord calculation
96 | cVec = self.panels[-1].nodes[1].coord - self.panels[0].nodes[0].coord
97 | self.c = np.linalg.norm(cVec)
98 |
99 | # aerodynamic characteristics: Gamma, L and Cl
100 | def liftCalc(self, vInf):
101 | self.Gamma = 0.0
102 | self.L = 0.0
103 |
104 | for p in self.panels:
105 | self.Gamma = self.Gamma + p.gamma
106 | self.L = self.L + p.lift
107 |
108 | self.Cl = 2.0*self.L/(1.2*vInf**2*self.c)
109 |
110 | # domain (grid) class definition for streamlines
111 | class Domain:
112 | def __init__(self, nx, ny, xMin, xMax, yMin, yMax):
113 |
114 | self.grid = []
115 |
116 | x = np.linspace(xMin, xMax, nx)
117 | y = np.linspace(yMin, yMax, ny)
118 |
119 | # grid point class definition
120 | class Point:
121 | def __init__(self, x, y):
122 | self.coord = np.array([x, y, 0.0])
123 |
124 | # write results to file and terminal
125 | def writeResults(airfoils):
126 | with open('results.dat', 'w') as out:
127 | print(40*'=' + '\n')
128 | out.write(40*'=' + '\n')
129 |
130 | for a in airfoils:
131 | print('Airfoil {0:s} aerodynamic characteristics:'.format(a.name))
132 | print('Gamma = {0:.4f} m2/s'.format(a.Gamma))
133 | print('L = {0:.4f} N/m'.format(a.L))
134 | print('Cl = {0:.4f}\n'.format(a.Cl))
135 | print(40*'=' + '\n')
136 |
137 | out.write('Airfoil {0:s} aerodynamic characteristics:\n'.format(a.name))
138 | out.write('Gamma = {0:.4f} m2/s\n'.format(a.Gamma))
139 | out.write('L = {0:.4f} N/m\n'.format(a.L))
140 | out.write('Cl = {0:.4f}\n'.format(a.Cl))
141 | out.write(40*'=' + '\n')
142 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Lumped-vortex panel method
2 |
3 | ## Introduction
4 | This is the simplest model which can be found under the panel method category. Lumped (or _discrete_) vortex means that every panel has a discrete vortex located at the panel quarter chord point. This model is suited to analyze thin airfoils, since the mean curvature line is discretized in panels. The present code is designed in order to handle the multi-element problem.
5 |
6 | This project is useful for students and curious of aerodynamics, since despite being very simple from the theory point of view, one can:
7 | - Achieve strong insight on how to apply the fundamentals of aerodynamics.
8 | - Understand how the panels and/or airfoils interact with each others.
9 | - Take the first steps in programming (the code is written as much as possible as OOP).
10 | - Investigate some numerical issues which arise when discretizing in a large number of panels.
11 | - Have useful and estimated results for validation with other more sofisticated methods.
12 |
13 | ## Using the script
14 | Once downloaded, you can try running `main.py` and the following will happen:
15 | - Three windows showing:
16 | - Plot of two parabolic airfoils in tandem, called _Front_ and _Rear_ in the domain.
17 | - Plot of delta Cp (difference between lower and upper Cp) along relative chord (x/c) for _Front_ airfoil.
18 | - Plot of delta Cp along relative chord for _Rear_ airfoil.
19 | - Airfoils aerodynamic characteristics shown in terminal window:
20 | - Gamma: circulation associated to the specific airfoil.
21 | - L: lift (per unit span) generated by the specific airfoil.
22 | - CL: lift coefficient generated by the specific airfoil.
23 | - A file called `results.dat` with the same results listed above.
24 |
25 | ### Setting an analysis
26 | 1. In line 7 of file `main.py` declare the incidence angle (in degrees) of the free stream velocity respect th _x_ axis, this angle is called _alpha_ as can be seen in the following image (from _Low-Speed Aerodynamics_ by Katz & Plotkin).
27 | 2. The freestream velocity magnitude is declared in line 8.
28 | 3. Airfoils are declared appending objects initialized with `Airfoil('name', 'coordinates_file.dat')` to `airfoils` array, as seen in lines 15 and 16 of file `main.py`.
29 | 4. Finally, run `main.py`.
30 |
31 | 
32 |
33 | ### Defining airfoils
34 | Each airfoil used in the problem must be defined separately in a file containing ordered nodes (rows), which columns represent the _x_ and _y_ coordinates. The files must be in the same directory as `main.py`. Take for instance `coord_parabolic_front_20.dat`, where you can see how coordinates are defined. The order of nodes must follow the orientarion shown in te above image, i.e.: each panel is defined with the frst node upstream and the second downstream.
35 |
36 | When creating an object instance of `Airfoil` class, two parameters must be passed:
37 | - A string which defines its name for identification purposes.
38 | - A second string with the nodes coordinates file name.
39 |
40 | Several coordinate files can be found inside `airfoils` directory, in their names the type of airfoil is described as well as the number of panels used. It is importan to remark that the nodes coordinates are measured in the global reference system, so when having a multi-element configuration, the location of every airfoil is taken from the nodes coordinates file.
41 |
42 | ### `main.py` overview
43 | This is the skeleton of the script, where instructions to solve the problem are found. It uses methods defined in `utils.py`. The logics of the step-by-step can be followed straight forward and it is recommended not to modify the structure.
44 |
45 | ### `utils.py` overview
46 | All the class definitions, functions and calculations are written in this file. The code is commented so the user can quickly understand what is being done by the script. This is fundamental when comparing the code to the math found in the theory.
47 |
48 | ## Theory background
49 | As was mentioned in the introduction, this approach is the simplest one which can be found under the vast variety of panel methods flavours. Due to its simplicity, it is very easy to be coded. Since there is not any distribution of vorticity along the panel length but a discrete vortex attached to it, the formulation of the flow tangency boundary condition is found straight forward.
50 |
51 | The induced velocities are found on every control point (located at the three-quarter panel length) pplying the Biot-Savart Law. Then, the dot product of the induced velocities times the unit normal vector of each panel is equated to zero. A linear algebraic equation system is obtained, where the vortex strengths of each panel are the unknowns.
52 |
53 | Once the system is solved, the vortex strengths are used to calculate the Cp difference along the airfoils, their individual lift using the Generalized Kutta-Joukowski Theorem as well as the individual CL.
54 |
55 | ### Numerical issues
56 | An interesting issue with this type of methods is that, contrary to intuition, oscillations on the Cp difference along the airfoils chord are observed when the airfoil is discretized in a larger number of panels. The reader is encouraged to investigate this phenomenon typically found in methods with discrete unknowns values instead of distributed ones. Katz & Plotkin give some insight on this.
57 |
58 | ### Recommended bibliography
59 | For a broader and detailed explanation, the reader is recommended to study from:
60 | - Low-Speed Aerodynamics, J. Katz & A. Plotkin.
61 | - An Introduction to Theoretical and Computational Aerodynamics, J. Moran.
62 | - Theoretical and Computational Aerodynamics, T. Sengupta.
63 |
64 | ## Future improvements
65 | - Streamline plots.
66 |
--------------------------------------------------------------------------------