Pour ceux qui ne seraient pas familier avec le language python, vous pouvez consulter le Notebook Introduction au Python.
Ce notebook constitue une introduction à l'aérodynamique des profils d'ailes. Il vous permettra de vous familiariser avec les différents profils et leurs construction ainsi qu'avec les grands principes de l'aérodynamique d'une aile.
import numpy as np
import matplotlib.pyplot as plt
import math
import copy
%matplotlib widget
import ipywidgets as widgets
#%matplotlib inline
fs=15
plt.rc('xtick',labelsize=fs)
plt.rc('ytick',labelsize=fs)
Dans le cadre des profils symétriques, les profils NACA sont définis à l'aide d'un polynôme d'ordre 4 donnant l'ordonnée du profil en fonction de l'abcisse. On normalise en général les coordonnées par la corde $c$. On a ainsi:
$$ \dfrac{y_s}{c}=a_0\left(\dfrac{x}{c}\right)^{1/2}+a_1\left(\dfrac{x}{c}\right)+a_2\left(\dfrac{x}{c}\right)^{2}+a_3\left(\dfrac{x}{c}\right)^{3}+a_4\left(\dfrac{x}{c}\right)^{4} $$Les 5 coefficients de ce polynôme sont calculés en imposant les 5 conditions suivantes dans le cas ou l'on souhaite une épaisseur de 20% de la corde (T/c=0.2):
Après résolution du système linéaire on trouve:
Ainsi on peut définir une fonction calculant les coordonées d'un profil d'aile symétrique d'épaisseur $T$ (Thickness en anglais):
A=np.array([[0.3**0.5,0.3,0.3**2,0.3**3,0.3**4],
[0.5*0.3**-0.5,1,2*0.3,3*0.3**2,4*0.3**3],
[1,1,1,1,1],
[0.5,1,2,3,4],
[0.1**0.5,0.1,0.1**2,0.1**3,0.1**4]])
B=np.array([0.1,0,0.0021/2,-0.234,0.0078])
np.linalg.solve(A,B)
array([-1.01600029, 4.06808007, -8.62300818, 8.83597717, -3.26399877])
def naca_00TT(x,T):
return T*(0.2969*x**0.5-0.1260*x-0.3516*x**2+0.2843*x**3-0.1015*x**4)/0.2
Pour choisir les abscisses où sont calculé les points du profil, on choisi en général une distribution non uniforme pour pouvoir représenter correctement le bord d'attaque.
N=50
db=np.pi/N
beta=np.arange(0,np.pi+db,db)
x=0.5*(1-np.cos(beta))
plt.figure(figsize=(8,3))
plt.plot(x,np.ones(len(x)),'o')
plt.grid()
plt.figure(figsize=(8,3))
plt.plot(x,naca_00TT(x,0.08),'-+k',label='NACA0008');plt.plot(x,-naca_00TT(x,0.08),'-+k')
plt.plot(x,naca_00TT(x,0.12),'-+b',label='NACA0012');plt.plot(x,-naca_00TT(x,0.12),'-+b')
plt.plot(x,naca_00TT(x,0.15),'-+r',label='NACA0015');plt.plot(x,-naca_00TT(x,0.15),'-+r')
plt.axis('equal')
plt.grid();plt.legend(fontsize=fs)
<matplotlib.legend.Legend at 0x7f23adc20d60>
Pour pouvoir générer de la portance à incidence nulle, il est nécessaire de briser la symétrie du profil en ajoutant une légère cambrure pour augmenter la dépression à l'extrados.
On introduit alors deux nouveaux paramètres:
Le profil est alors découpé en 4 parties:
Pour la ligne de cambrure on défini: $$ 0<\left[\dfrac{x}{c}\right]<P ~ : ~ \dfrac{y_c}{c}=\dfrac{M}{P^2}\left(2P\left[\dfrac{x}{c}\right]-\left[\dfrac{x}{c}\right]^2\right) $$
$$ 1>\left[\dfrac{x}{c}\right]>P ~ : ~ \dfrac{y_c}{c}=\dfrac{M}{1-P^2}\left(1-2P+2P\left[\dfrac{x}{c}\right]-\left[\dfrac{x}{c}\right]^2\right) $$def camb_line(x,M,P):
yc=np.zeros(len(x))
dyc=np.zeros(len(x))
x1=x[x<P]
x2=x[x>=P]
if P>0:
yc[x<P]=(M/P**2)*(2*P*x1-x1**2)
dyc[x<P]=(2*M/P**2)*(P-x1)
yc[x>=P]=(M/(1-P)**2)*(1-2*P+2*P*x2-x2**2)
dyc[x>=P]=(2*M/(1-P)**2)*(P-x2)
return yc,dyc
yc,dyc=camb_line(x,0.02,0.4)
plt.figure(figsize=(8,3))
plt.plot(x,yc,'-k')
plt.axis('equal')
plt.grid();
On peut alors définir le profil complet en partant d'un profil symétrique et en retranchant l'apaisseur à la ligne de cambrure. On aurra donc:
Pour l'extrados: $$ \left.\dfrac{y}{c}\right|_{extrados}=\dfrac{y_c}{c}+\dfrac{y_s}{c}\cos(\theta) $$
Pour l'intrados: $$ \left.\dfrac{y}{c}\right|_{intrados}=\dfrac{y_c}{c}-\dfrac{y_s}{c}\cos(\theta) $$
Avec $\theta=arctan\left(\dfrac{dy_c}{dx}\right)$
def naca_MPTT_extra(x,M,P,T):
ys=naca_00TT(x,T)
yc,dyc=camb_line(x,M,P)
y=yc+ys*np.cos(np.arctan(dyc))
return y
def naca_MPTT_intra(x,M,P,T):
ys=naca_00TT(x,T)
yc,dyc=camb_line(x,M,P)
y=yc-ys*np.cos(np.arctan(dyc))
return y
def plot_NACA(x,M,P,T,col='k'):
yc,dyc=camb_line(x,M,P)
ye=naca_MPTT_extra(x,M,P,T)
yi=naca_MPTT_intra(x,M,P,T)
return yc,ye,yi
Les profils NACA sont ainsi désignés par un nombre à 4 chiffres NACAMPXX ou M est la cambrure max multiplié par 100, P la position de la cambrure max multiplié par 10 et XX l'épaisseur multiplié par 100.
Ainis le profil NACA2415 sera défini par une épaisseur de 15% de la corde, une cambrure de 2% de la corde positionée à 40% de la corde.
# set up plot
fig, ax = plt.subplots(figsize=(8, 4))
ax.set_ylim([-0.5, 0.5])
ax.grid(True)
@widgets.interact(camb=(0, 0.2, 0.01), pos=(0.1, 0.9, .1), ep=(0.05, 0.5, 0.01))
def update(camb = 0., pos=0.1, ep=0.12):
"""Remove old lines from plot and plot new one"""
[l.remove() for l in ax.lines]
[l.remove() for l in ax.lines]
name='NACA'+str(int(100*camb))+str(int(10*pos))+str(int(100*ep))
plt.title(name,fontsize=fs)
yc,ye,yi=plot_NACA(x,camb,pos,ep)
ax.plot(x, yc, '--k')
ax.plot(x,ye,'-+r')
ax.plot(x,yi,'-+r')
interactive(children=(FloatSlider(value=0.0, description='camb', max=0.2, step=0.01), FloatSlider(value=0.1, d…
Afin d'utiliser les données aéro, il faut d'abord les télécharger en executant la cellule suivante (Attention il faut décommenter les 2 lignes avant -> supprimer le #
# ! wget https://hpp.education/Lessons/Aerodynamique/Files/NACA0015_polair.dat
# ! wget https://hpp.education/Lessons/Aerodynamique/Files/NACA2415_polair.dat
Airfoiltools est un site permettant de comparer les performances aérodynamique des profils d'ailes. Il permet d'obtenir des fichiers de données en colonnes sous la forme:
$\alpha$ | $C_L$ | $C_D$ | $C_{Dp}$ | $C_M$ | $X_{tr}^t$ | $X_{tr}^b$ |
---|
Les colonnes corespondent à:
On peut alors charger les données, on comparera ici le NACA0015 et le NACA2415:
NACA1=np.loadtxt('NACA0015_polair.dat')
NACA2=np.loadtxt('NACA2415_polair.dat')
On peut commencer par tracer l'évolution des coefficients aérodynamique $C_D$ et $C_L$ en fonction de l'incidence:
fig=plt.figure(figsize=(8,4),dpi=120)
fig.add_subplot(121)
plt.plot(NACA1[:,0],NACA1[:,1],linewidth=3,label='NACA0015')
plt.plot(NACA2[:,0],NACA2[:,1],linewidth=3,label='NACA2415')
plt.xlabel(r'Incidence (°)',fontsize=fs)
plt.ylabel(r'CL',fontsize=fs)
plt.grid(True)
plt.legend(fontsize=fs)
fig.add_subplot(122)
plt.plot(NACA1[:,0],NACA1[:,2],linewidth=3,label='NACA0015')
plt.plot(NACA2[:,0],NACA2[:,2],linewidth=3,label='NACA2415')
plt.xlabel(r'Incidence (°)',fontsize=fs)
plt.ylabel(r'CD',fontsize=fs)
plt.grid(True)
plt.legend(fontsize=fs)
<matplotlib.legend.Legend at 0x7f593ae64640>
La polaire d'un profil est la courbe représentant le coefficient de portance en fonction du coefficient de trainée pour différentes incidences.
On peut comparer directement les polaires des deux profils:
fig=plt.figure(figsize=(7,3),dpi=120)
plt.plot(NACA1[:,2],NACA1[:,1],linewidth=3,label='NACA0015');plt.plot(np.arange(0,0.02,0.001),77.8*np.arange(0,0.02,0.001),'--b')
plt.plot(NACA2[:,2],NACA2[:,1],linewidth=3,label='NACA2415');plt.plot(np.arange(0,0.02,0.001),103*np.arange(0,0.02,0.001),'--r')
plt.xlabel(r'CD',fontsize=fs)
plt.ylabel(r'CL',fontsize=fs)
plt.grid(True)
plt.legend(fontsize=fs)
<matplotlib.legend.Legend at 0x7f594113e2e0>
La finesse d'une aile représente le rapport entre son coefficient de portance et son coefficient de trainée. Elle exprime donc une efficacité aérodynamique entre portance et trainée. La finesse maximum est obtenue pour une incidence donnée qu'il sera important de connaitre pour l'utilisation du profil.
On peut donc connaitre la finesse max en faisant simplement ici:
print('Finesse max NACA0015',np.max(NACA1[:,1]/NACA1[:,2]))
print('Finesse max NACA2415',np.max(NACA2[:,1]/NACA2[:,2]))
Finesse max NACA0015 77.87696924231058 Finesse max NACA2415 103.04444444444445
On peut également représenter l'évolution de la finesse en fonction de l'incidence:
fig=plt.figure(figsize=(7,3),dpi=120)
plt.plot(NACA1[:,0],NACA1[:,1]/NACA1[:,2],linewidth=3,label='NACA0015');plt.plot(NACA1[:,0],77.8*np.ones(len(NACA1[:,0])),'--b')
plt.plot(NACA2[:,0],NACA2[:,1]/NACA2[:,2],linewidth=3,label='NACA2415');plt.plot(NACA2[:,0],103*np.ones(len(NACA2[:,0])),'--r')
plt.ylabel(r'f=CL/CD',fontsize=fs)
plt.xlabel(r'incidence',fontsize=fs)
plt.grid(True)
plt.legend(fontsize=fs)
<matplotlib.legend.Legend at 0x7f5940092a30>
fig=plt.figure(figsize=(7,3),dpi=120)
plt.plot(NACA1[:,0],100*NACA1[:,3]/NACA1[:,2],linewidth=3,label='NACA0015')
plt.plot(NACA2[:,0],100*NACA2[:,3]/NACA2[:,2],linewidth=3,label='NACA2415')
plt.xlabel(r'indicence',fontsize=fs)
plt.ylabel(r'\% $CD_p/CD$',fontsize=fs)
plt.title(r'Contribution de la trainée de pression à la trainée totale',fontsize=fs)
plt.grid(True)
plt.legend(fontsize=fs)
<matplotlib.legend.Legend at 0x7f593acfc5b0>
fig=plt.figure(figsize=(7,3),dpi=120)
plt.plot(NACA1[:,0],NACA1[:,5],linewidth=3,label='Top NACA0015')
plt.plot(NACA1[:,0],NACA1[:,6],linewidth=3,label='Bottom NACA0015')
plt.plot(NACA2[:,0],NACA2[:,5],linewidth=3,label='Top NACA2415')
plt.plot(NACA2[:,0],NACA2[:,6],linewidth=3,label='Bottom NACA2415')
plt.title(r'Position du point de transition par rapport à la corde',fontsize=fs)
plt.xlabel(r'indicence',fontsize=fs)
plt.ylabel(r'Xtr',fontsize=fs)
plt.grid(True)
plt.legend(fontsize=fs)
<matplotlib.legend.Legend at 0x7f593a8b6eb0>
Dans ce TN, nous avons apris a représenter la géométrie d'un profil d'ail à partir de ses 4 chiffres. Nous avons ensuite pu comparer les performances aérodynamique de quelques profil à partir d'informations issues d'une base de données aérodynamique Airfoiltools.
Pour aller plus loin, on pourra consulter les documents suivant:
from IPython.core.display import HTML
style=open('notebooks.css', "r").read()
HTML(style)