5.3. Théorie de l’aile#

Marc BUFFAT département mécanique, Lyon 1

%matplotlib inline
import numpy as np
import sympy as sp
import matplotlib.pyplot as plt
from metakernel import register_ipython_magics
register_ipython_magics()

5.3.1. Théorie de la portance#

portance

les différentes théories de la portance (sur internet):

  1. Appuie de l’aile sur l’air (principe de réaction de Newton)

  2. Bernoulli + égalité des temps de parcours

  3. Analyse globale: bilan de quantité de mouvement, déviation de l’écoulement

  4. Théorie de la Circulation de vitesse

  • lien vers le sondage

https://jupyterm1.mecanique.univ-lyon1.fr/SONDAGE/MGC1061M

%activity /usr/local/commun/ACTIVITY/MGC1061M/portance

5.3.2. Caractéristique aérodynamique d’un profil#

Analyse dimensionnelle:

Etude d’un profil 2D

  • étude en fonction de l’angle \(\alpha\)

  • fonction du nombre de Reynolds

  • \(C_L\) coefficiant de portance: projection suivant \(\vec{N}=[-\sin\alpha, \cos\alpha]\) \(\perp\) à \(\vec{U}_0\)

\[ C_L = \int_{C} Pr\, \vec{n}.\vec{N}\,ds \]
\[ C_L = \int_{C} Pr\, ds \mbox{ avec } ds = dx \cos{\alpha} + dy \sin{\alpha} \]
  • \(C_m\) coefficient de moment (moment pression) par rapport à un point de référence \(P=[x_{ref}=0.25, y_{ref}=0]\) , qui n’est donc pas nécessairement sur la ligne moyenne à 1/4 de corde

\[ C_m = \int_{C} Pr\, \vec{n} \land \vec{PM} \,ds \]
\[C_m = \int_{C} -Pr \left((x-x_{ref}) dx + (y-y_{ref}) dy \right)\]

on calcule alors le moment en un point Q quelconque par la relation de transport

\[ \mathcal{M}_Q = \mathcal{M}_P + \vec{QP} \land \vec{F}_p \mbox{ avec } \vec{F}_p = C_L [-\sin\alpha, \cos\alpha]\]

d’où la position du centre de poussée exacte / à \(P\) \(x,y\) (erreur)

\[ \frac{C_m}{C_L} = (x- x_{ref})\cos\alpha + (y- y_{ref})\sin\alpha\]

5.3.3. Analyse par bilan de quantité de mouvement#

Modèle simplifié des efforts exercés par un profil d’aile de longueur (de corde) \(L_c\) en incidence d’angle \(\alpha\) sur un écoulement stationnaire d’un fluide parfait incompressible de masse volumique \(\rho\) et de vitesse \(U_1\) (schéma ci-dessous)

portance

On constate expérimentalement que l’effet de l’aile sur l’écoulement, aux faibles incidences, est de dévier les lignes de courant d’un angle \(\alpha\) correspondant à l’angle d’incidence du profil, c.a.d l’angle d’inclinaison du bord de fuite.

ligne courant

d’après « How do wings work? » H. Babinsky, Physics Education 38(6) 2003

A 1-minute video released by the University of Cambridge sets the record straight on a much misunderstood concept - how wings lift. I start by giving the wrong explanation and asking who has heard it and every time 95% of the audience puts their hand up. Only a handful will know that it is wrong.Professor Holger BabinskyIt’s one of the most tenacious myths in physics and it frustrates aerodynamicists the world over. Now, …

from IPython.display import YouTubeVideo

YouTubeVideo('e0l31p6RIaY', width=600, height=400)

5.3.3.1. bilan de masse et de quantité de mouvement#

  • \[ U_1 S_1 = U_2 S_2 \]
  • \[ p_1 = p_2 = p_0 \]
  • \[ S_2 = L_c W \]

on en déduit par bilan de quantité de mouvement la force de portance et le coefficient de portance \(C_p\)

\[ Fp = \rho U_1^2 \sin\alpha W L_c \]

soit à faible incidence une proportionnalité du coefficient de portance \(C_p\) avec l’angle d’incidence \(\alpha\)

\[ C_p = \frac{F_p}{\rho U_1^2 W L_c} \approx \alpha\]

5.3.4. Potentiel complexe#

Pour un écoulement incompressible 2D de fluide parfait irrotationnel le potentiel \(\phi(x,y)\) et la fonction de courant \(\psi(x,y)\) vérifie l’éuqtaion de Laplace:

\[ \Delta \psi = \Delta \phi = 0 \]

dont le champ de vitesse \(\vec{U} = [U_x,U_y]\) en cartésien est donné par

\[ U_x = \frac{\partial \phi}{\partial x} = \frac{\partial \psi}{\partial y} \]
\[ U_y = \frac{\partial \phi}{\partial y} = -\frac{\partial \psi}{\partial x} \]

On définit alors un potentiel complexe \(\Phi(z)\):

\[\Psi(z) = \phi(x,y) + i \psi(x,y)\]

qui est une fonction analytique en z, dont la dérivée est indépendante de dz.

Dans ce cas \(\Phi(z)\) est différentiable en z et vérifie:

(5.3)#\[\begin{eqnarray} \frac{d \Phi}{d z} &=& \frac{\partial \phi}{\partial x} + i \frac{\partial \psi}{\partial x}\\ &=& -i \frac{\partial \phi}{\partial y} + \frac{\partial \psi}{\partial y}\\ &=& U_x - i U_y \\ \end{eqnarray}\]

On le vérifie en prenant respectivement \(\delta z = \delta x \) et \(\delta z = i\delta y\) et en utilisant les relations de Cauchy-Riemann entre \(\phi\) et \(\psi\)

On en déduit le module de la vitesse:

\[\| U \| = \sqrt{U_x^2+U_y^2} = \left|\frac{d \Psi}{d z}\right|\]

et son angle \(\theta\)

\[ \theta = -arg\left(\frac{d \Psi}{d z} \right)\]

5.3.4.1. Coordonnées polaires#

En coordonnées polaires, l’équation de Laplace s’écrit:

\[ \frac{1}{r}\frac{\partial }{\partial r} \left(r \frac{\partial \Psi}{\partial r} \right) + \frac{1}{r^2}\frac{\partial^2 \Psi}{\partial r^2} = 0 \]

et le champ de vitesse en polaire

\[ U_r = \frac{\partial \Phi}{\partial r} \mbox{ et } U_\theta = \frac{1}{r} \frac{\partial \Phi}{\partial \theta} \]
\[ U_r = \frac{1}{r} \frac{\partial \Psi}{\partial \theta} \mbox{ et } U_\theta = -\frac{\partial \Psi}{\partial r} \]

soit en coordonnées cartésiennes $\( U_x = U_r \cos\theta - U_\theta \sin \theta \mbox{ et } U_y = U_r \sin\theta + U_\theta \cos \theta\)$

5.3.4.2. Potentiel complexe en polaire#

puisque \(z = r e^{i\theta}\) on a donc :

(5.4)#\[\begin{eqnarray} \frac{d \Phi}{d z} &=& \frac{\partial \phi}{\partial r} e^{-i\theta} + i \frac{\partial \psi}{\partial r} e^{-i\theta}\\ &=& -\frac{i}{r}\frac{\partial \phi}{\partial \theta}e^{-i\theta} + \frac{1}{r}\frac{\partial \psi}{\partial \theta}e^{-i\theta}\\ &=& U_x -i U_y = (U_r - i U_\theta) e^{-i\theta} \\ \end{eqnarray}\]

avec $\( U_r = U_x \cos \theta + U_y \sin \theta \mbox{ et } U_\theta = -U_x \sin \theta + U_y \cos \theta\)$

On en déduit aussi

(5.5)#\[\begin{eqnarray} \frac{\partial \Phi}{\partial r} &=& \frac{\partial \phi}{\partial r} + i \frac{\partial \psi}{\partial r}\\ &=& U_r - i U_\theta \end{eqnarray}\]

5.3.5. Potentiel complexe de l’écoulement autour d’un cylindre#

On a vu que l’écoulement potentiel autour d’un cylindre de rayon \(R\) en rotation est la somme d’un écoulement uniforme, d’un doublet et d’un vortex de circulation \(\Gamma\)

Pour une vitesse \(U_0\) d’incidence \(\alpha\) , le potentiel complexe s’écrit

\[\Psi(z) = U_0 z e^{-i\alpha} + U_0 e^{i\alpha} \frac{R^2}{z} - i \frac{\Gamma}{2\pi}\log(\frac{z e^{-i\alpha}}{R})\]

et la vitesse complexe \(W = U- i V\)

\[ W = U_0 e^{-i\alpha} - U_0 e^{i\alpha} \frac{R^2}{z^2} - i \frac{\Gamma}{2\pi z}\]
# parametres
R, U0 = sp.symbols('R U_0',real=True, positive=True)
Gamma,alpha = sp.symbols('Gamma alpha',real=True)
# variables
theta,x,y = sp.symbols('theta x y',real=True)
r         = sp.symbols('r',real=True,Positive=True)
# fonctions pour manipuler les complexes
from sympy import re,im,I

Pour une vitesse \(U_0\) d’incidence \(\alpha\) , le potentiel complexe s’écrit

\[\Psi(z) = U_0 z e^{-i\alpha} + U_0 e^{i\alpha} \frac{R^2}{z} - i \frac{\Gamma}{2\pi}\log(\frac{z e^{-i\alpha}}{R})\]
# potentiel complexe Phi
z = sp.symbols('z')
Phi = U0*z*sp.exp(-I*alpha) + U0*sp.exp(I*alpha)*R**2/z \
    - (I*Gamma/(2*sp.pi))*sp.log(z*sp.exp(-I*alpha)/R)
display("Phi(z)=",Phi)
'Phi(z)='
\[\displaystyle - \frac{i \Gamma \log{\left(\frac{z e^{- i \alpha}}{R} \right)}}{2 \pi} + \frac{R^{2} U_{0} e^{i \alpha}}{z} + U_{0} z e^{- i \alpha}\]

la vitesse complexe \(W = U- i V\) est alors donnée par $\( W = \frac{d \Phi}{d z}\)$

# calcul de la vitesse complexe W
W = 0
### BEGIN SOLUTION
W = sp.diff(Phi,z)
### END SOLUTION
display("W(z)=",W)
'W(z)='
\[\displaystyle - \frac{i \Gamma}{2 \pi z} - \frac{R^{2} U_{0} e^{i \alpha}}{z^{2}} + U_{0} e^{- i \alpha}\]
# calcul fonction de courant psi (en fonction de (x,y)
psi = 0
### BEGIN SOLUTION
psi = im(Phi.subs(z,x+sp.I*y))
### END SOLUTION
display('psi(x,y)=',psi)
'psi(x,y)='
\[\displaystyle - \frac{\Gamma \log{\left(\sqrt{\frac{x^{2}}{R^{2}} + \frac{y^{2}}{R^{2}}} \right)}}{2 \pi} + R^{2} U_{0} \operatorname{im}{\left(\frac{e^{i \alpha}}{x + i y}\right)} - U_{0} x \sin{\left(\alpha \right)} + U_{0} y \cos{\left(\alpha \right)}\]
# en déduire les composantes de vitesse dans Ux et Uy
Ux = 0
Uy = 0
### BEGIN SOLUTION
Ux =  re(W.subs(z,x+sp.I*y))
Uy = -im(W.subs(z,x+sp.I*y))
### END SOLUTION
display("Ux=",Ux)
display("Uy=",Uy)
'Ux='
\[\displaystyle - \frac{\Gamma y}{2 \pi \left(x^{2} + y^{2}\right)} - R^{2} U_{0} \operatorname{re}{\left(\frac{e^{i \alpha}}{\left(x + i y\right)^{2}}\right)} + U_{0} \cos{\left(\alpha \right)}\]
'Uy='
\[\displaystyle \frac{\Gamma x}{2 \pi \left(x^{2} + y^{2}\right)} + R^{2} U_{0} \operatorname{im}{\left(\frac{e^{i \alpha}}{\left(x + i y\right)^{2}}\right)} + U_{0} \sin{\left(\alpha \right)}\]

5.3.5.1. Visualisation des champs#

  • utilisation d’une technique de masque pour éliminer l’écoulement à l’intérieur du cercle

# parametres numeriques: choix arbitraire de Gamma et alpha ! 
R0   = 0.5
Uinf = 1.0
vals = [(Gamma,-2*np.pi*R*U0),(alpha,np.deg2rad(10)),(R,R0),(U0,Uinf)]
display("parametres:",vals)
'parametres:'
[(Gamma, -6.28318530717959*R*U_0),
 (alpha, 0.17453292519943295),
 (R, 0.5),
 (U_0, 1.0)]
# domaine de calcul et maillage (grille) pour le calcul de psi et de la vitesse
L = 3
N = 201
pas = 8 # pas pour les vitesses
# points de calcul
xg = np.linspace(-L,L,N)
yg = np.linspace(-L/2,L/2,N)
# pour les lignes de courant psi
X, Y = np.meshgrid(xg, yg)
# utilisation d'un masque
Z = X + 1j*Y
Z = np.ma.masked_where(np.absolute(Z)<0.95*R0,Z)
X = Z.real
Y = Z.imag
# et le champ de vitesse U
XX = X[::pas,::pas]
YY = Y[::pas,::pas]
# calcul des valeurs numeriques
psi1 = sp.lambdify([x,y],psi.subs(vals),'numpy')
u1   = sp.lambdify([x,y],Ux.subs(vals),'numpy')
v1   = sp.lambdify([x,y],Uy.subs(vals),'numpy')
with np.errstate(divide='ignore'):
    Psi1 = psi1(X,Y)
    Psi0 = psi1(0.5,0)
    Levs = np.linspace(Psi0-L/5,Psi0+L/5,21)
    U1   = u1(XX,YY)
    V1   = v1(XX,YY)
<lambdifygenerated-1>:2: RuntimeWarning: invalid value encountered in sqrt
  return -0.17364817766693*x + 0.984807753012208*y + 1.5707963267949*log(2.0*sqrt(x**2 + y**2))/pi + 0.25*imag(exp(0.174532925199433*1j)/(x + 1j*y))
# tracer
fig, ax = plt.subplots(figsize=(12,6))
#ax.contourf(X,Y,Psi1,levels=21)
ax.contour(X,Y, Psi1,levels=Levs,colors='r')
ax.quiver(XX,YY,U1,V1)
cercle = plt.Circle((0.,0.),R0,color='yellow')
ax.add_artist(cercle)
plt.axis('equal')
plt.axis('off')
plt.title("Ecoulement autour du cylindre");
../../_images/3262d7a733e74bc0ecb317c4dcbd71b495ec26eab30012128cba688893692fd8.png

5.3.6. Transformation conforme#

On définit une transformation conforme \(Z=F(z)\) qui préserve les angles dans le plan complexe.

5.3.6.1. Transformation de Joukovski#

\[ Z = z + \frac{C^2}{z} \]

avec \( z = x + i y \) (plan d’origine) et \(Z = X + i Y\) (plan transformé)

C = sp.symbols('C',real=True,positive=True)
F = lambda z: z + C**2/z
display("Z=F(z)",F(z))
'Z=F(z)'
\[\displaystyle \frac{C^{2}}{z} + z\]

5.3.6.2. transformation conforme#

transformation de l’écoulement autour d’un cercle de centre \(x0,y0\) de rayon \(R=R_0\)

  • \(c\) paramétre de la transformation \(0\le c\le 1\)

  • \(\beta\) angle du point centre / horizontal

# selection cas 1,2,3,4 (choix 4 par defaut)
cas  = 4
beta = 0
if cas==0:
    # cercle
    x0 = 0
    y0 = 0
    R0 = float(R.subs(vals))
    c  = float(R.subs(vals)*0.0)
elif cas==1:
    # parametres pour une ellipse
    x0 = 0
    y0 = 0
    R0 = float(R.subs(vals))
    c  = float(R.subs(vals)*0.9)
elif cas==2:
    # parametre pour une plaque
    x0 = 0
    y0 = 0
    R0 = float(R.subs(vals))
    c  = float(R.subs(vals)*1.0)
elif cas==3:
    # parametres pour un profil symetrique
    R0 = float(R.subs(vals))
    c  = float(R.subs(vals)/1.2) 
    x0 = c - R0
    y0 = 0
else:
    # parametres pour un profil cambre
    beta = np.deg2rad(8)
    R0 = float(R.subs(vals))
    c  = float(R.subs(vals)/1.2)
    x0 = c - R0*np.cos(beta)
    y0 = R0*np.sin(beta)
# calcul de la transformation en coordonnées cartésienne
xc = re(F(x+sp.I*y))
yc = im(F(x+sp.I*y))
display("xc,yc=",xc,yc)
'xc,yc='
\[\displaystyle \frac{C^{2} x}{x^{2} + y^{2}} + x\]
\[\displaystyle - \frac{C^{2} y}{x^{2} + y^{2}} + y\]
# transformation du cercle
Xc = sp.lambdify([x,y],xc.subs(C,c),'numpy')
Yc = sp.lambdify([x,y],yc.subs(C,c),'numpy')
Theta = np.linspace(0,2*np.pi,410)
XC = Xc(x0+R0*np.cos(Theta),y0+R0*np.sin(Theta))
YC = Yc(x0+R0*np.cos(Theta),y0+R0*np.sin(Theta))
plt.figure(figsize=(8,6))
plt.plot(XC,YC)
plt.title("Transformation de Joukovski")
plt.axis('equal');
../../_images/e2a009f5e919ccc4dba207ddfe14d756e762e5eb486f391c0a330d9241233d1e.png

5.3.6.3. calcul de l’écoulement par transformation de Joukovski#

  • calcul pour un profil

  • transformation numérique

def TransJ(Z,lam):
    '''transformation Joukovski (complexe)'''
    return Z + lam**2/Z
def Cercle(C0,R):
    '''pts du cercle de centre C0 (complexe) et de rayon R'''
    Theta = np.linspace(0,2*np.pi,200)
    return C0 + R*np.exp(1j*Theta)
def solutionJ(PHI,lam,C0,R,xg,yg):
    '''calcul de la solution par transformation de Joukovski PHI'''
    X,Y  = np.meshgrid(xg,yg)
    Z    = X+1j*Y
    Z    = np.ma.masked_where(np.absolute(Z-C0)<=R,Z)
    Zc   = Z - C0
    #Phiz = PHI(Z)
    # BUG numpy: calcul 
    # np.log(Z) cannot be calculated correctly due to a numpy bug np.log(MaskedArray);
    Phiz = Zc.copy()
    with np.errstate(divide='ignore'):        
        for m in range(Zc.shape[0]):
            for n in range(Zc.shape[1]):
                Phiz[m,n] = PHI(Zc[m,n])
    # Joukovski transformation 
    J  = TransJ(Z, lam)  
    cercle = Cercle(C0, R)
    airfoil= TransJ(cercle, lam) 
    return J, Phiz.imag, airfoil
#valeur des  parametres
display("parametres ",vals)
alpha0 = np.rad2deg(float(alpha.subs(vals)))
print("alpha={} deg. beta={} deg. c={} C0={}".format(alpha0,np.rad2deg(beta),c,x0+1j*y0))
'parametres '
[(Gamma, -6.28318530717959*R*U_0),
 (alpha, 0.17453292519943295),
 (R, 0.5),
 (U_0, 1.0)]
alpha=10.0 deg. beta=8.0 deg. c=0.4166666666666667 C0=(-0.0784673677041185+0.06958655048003272j)
display(Phi)
# calcul du potentiel complexe 
PhiJ = Phi.subs(vals)
display("Phi(z)=",PhiJ)
# conversion fonction python
PHI  = sp.lambdify(z,PhiJ)
\[\displaystyle - \frac{i \Gamma \log{\left(\frac{z e^{- i \alpha}}{R} \right)}}{2 \pi} + \frac{R^{2} U_{0} e^{i \alpha}}{z} + U_{0} z e^{- i \alpha}\]
'Phi(z)='
\[\displaystyle 1.0 z e^{- 0.174532925199433 i} + \frac{1.5707963267949 i \log{\left(2.0 z e^{- 0.174532925199433 i} \right)}}{\pi} + \frac{0.25 e^{0.174532925199433 i}}{z}\]
# calcul solution ! pble mauvaise valeur de la circulation 
J, Psi, airfoil = solutionJ(PHI,c,x0+1j*y0,R0,xg,yg)
# tracer
fig=plt.figure(figsize=(12,8))
ax=fig.add_subplot(111)
# this means that the flow is evaluated at Juc(z) since c_flow(Z)=C_flow(csi(Z))
cp=ax.contour(J.real, J.imag, Psi,levels=Levs, colors='blue', linewidths=1,
                linestyles='solid')
ax.plot(airfoil.real, airfoil.imag)
ax.fill(airfoil.real, airfoil.imag,color='yellow')
plt.axis('off')
plt.title("Problème: eclt au bord de fuite car circulation non correcte")
ax.set_aspect('equal');
#plt.savefig('eclt_cylindre.png')
../../_images/3214bd2015d50d1a0dc81237633b0101ed1a71cac507e9c878423bfa4ac4c590.png

5.3.6.4. circulation de Kutta-Joukovsky#

condition de Kutta au bord de fuite !

\[ \Gamma = -4 \pi U_0 R \sin{(\alpha + \beta)}\]
# valeur de Joukovski
GammaJ = -4*sp.pi*U0*R*sp.sin(alpha+beta)
display("GammaJ=",GammaJ)
# potentiel Joukovsky
PhiJ = Phi.subs(Gamma,GammaJ).subs(vals)
display("PhiJ=",PhiJ)
# conversion fonction python
PHI  = sp.lambdify(z,PhiJ)
'GammaJ='
\[\displaystyle - 4 \pi R U_{0} \sin{\left(\alpha + 0.139626340159546 \right)}\]
'PhiJ='
\[\displaystyle 1.0 z e^{- 0.174532925199433 i} + 0.309016994374947 i \log{\left(2.0 z e^{- 0.174532925199433 i} \right)} + \frac{0.25 e^{0.174532925199433 i}}{z}\]
# calcul solution
J, Psi, airfoil = solutionJ(PHI,c,x0+1j*y0,R0,xg,yg)
# tracer
fig=plt.figure(figsize=(12,8))
ax=fig.add_subplot(111)
# this means that the flow is evaluated at Juc(z) since c_flow(Z)=C_flow(csi(Z))
cp=ax.contour(J.real, J.imag, Psi,levels=Levs, colors='blue', linewidths=1,
                linestyles='solid')
ax.plot(airfoil.real, airfoil.imag)
ax.fill(airfoil.real, airfoil.imag,color='yellow')
plt.axis('off')
ax.set_aspect('equal');
../../_images/24e48b42a113ea84230640d61cbdd8d5c716348549de098caab177704d1878ca.png

5.3.7. Calcul de la Portance#

portance

5.3.7.1. Condition de Kutta - Joukovsky#

création circulation vitesse \(\Gamma\) telle que la vitesse reste parallèle au bord de fuite (pas de contournement)

condition de kutta-joukovski

  • circulation

\[\Gamma = 4 \pi U_0 R_0 \sin(\alpha + \beta)\]
  • portance

\[ F_p = \rho \Gamma U_0 \]

en faible incidence

\[ F_p \propto (\alpha + \beta)\]

5.3.7.2. Expérience de Prandtl (~1918)#

création de la circulation

prandtl_expe.png

from IPython.display import YouTubeVideo

YouTubeVideo('VcggiVSf5F8', width=600, height=400)

5.3.8. Annexe: Joukovski-airfoil#

Ce notebook est inspiré d’un notebook de calcul de l’écoulement autour d’un profil de Joukovski

5.3.9. FIN#