Réseau de diffraction – python

Où l’on trace la dispersion d’une lumière polychromatique par un réseau.

Avec les modules python matplotlib (tracé de graphiques) et numpy (gestion de listes).

Ce script reproduit un document trouvé sur https://www.123couleurs.fr/ et sur dans un article (octobre 2022) du BUP (bulletin de l’union des professeurs de physique et de chimie).

On y reproduit le devenir de rayons lumineux après avoir traversé un réseau de diffraction. Les directions des différents rayons dépendent de leur longueur d’onde. Chaque segment est coloré pour rendre compte de la longueur d’onde (violet 400 nm, bleu : 450 nm, vert 550 nm, orange 650 nm).

Les rayons sont regroupés par ordres. On constate un recouvrement des ordres 2 et 3. Bien que ces ordres offrent des rayons plus efficacement dispersés, leur recouvrement empêche l’analyse du spectre. Ce document ne tient pas compte de la luminosité : pour les ordres les plus extrêmes, la luminosité baisse sensiblement. L’ordre 1 est le plus lumineux.

Un paramètre important dans la direction que prennent les rayons est le pas du réseau (sa période spatiale) : c’est la distance séparant deux lignes consécutives du réseau. Sa valeur est affichée au centre du document.

On peut apprécier l’effet de ce paramètre sur la dispersion :

Si le pas diminue, les angles augmentent. Pour l’ordre 3, certaines radiations disparaissent.


Commentaires sur la rédaction du script :

Import des modules et réglages utilisateurs :

import matplotlib.pyplot as plt
import numpy as np
import matplotlib as mpl#Normalisation des valeurs

plt.rcParams["font.family"] = "Roboto" # ou autre police installée

# rayons des arcs des ordres
R = range(5,8)

# longueurs d'onde (nm):
LO = [400, 450, 550, 650]

a = 2.0 # période du réseau, en µm

couleur_fond = 'black'
NomFichier = "diffractionReseau" + str(a)

Définitions des fonctions :


def angle(p,LO):
    """
    à partir de l'ordre p et de la longueur d'onde LO,
    renvoie l'angle de diffraction, en radians
    """
    A = p * LO*1e-9 / (a*1e-6)
    if abs(A) <= 1:
        return np.arcsin(A)
    else:
        return np.nan

def ordre(p):
    """
    trace un ordre complet.
    """
    r = R[abs(p)-1]
    for L in LO:
        theta = angle(p,L)
        if np.isnan(theta) == False:
            axe.vlines(theta, 0, r, color=cmap(norm(L)))

def signe(p): # retourne -1 si p < 0 ou 1 si p > 0
    return abs(p)/p

def arc(p):
    """
    Trace un arc pour délimiter l'ordre p.
    """
    r = R[abs(p)-1]
    Lmin=min(LO)
    Lmax=max(LO)
    angle_min = angle(p, Lmin)
    angle_max = angle(p, Lmax)
    if np.isnan(angle_max): # si le dernier rayon est hors champ
        angle_max=np.pi/2 * signe(p)
    angle_moy = (angle_min + angle_max)/2
    angles = np.arange(angle_min,angle_max,0.02 * signe(p))
    for i in angles: # tracé des pointillés
        axe.scatter(i,r+0.1,s=3,c='gray')
    axe.text(angle_moy,r+0.3,f'ordre {p}',c='gray',ha='center',va='center',rotation = -np.degrees(angle_moy))

Création du graphique et réglages :


fig = plt.figure(tight_layout=True, figsize=(8,8))

axe = plt.subplot(projection='polar',facecolor=couleur_fond)
axe.set_xlim(-np.pi/2, np.pi/2) # réduire à un demi-cercle
axe.set_theta_zero_location('N')  # Set zero to North
axe.set_xticks([])# suppression des graduations d'angle
axe.set_yticks([])# suppression des graduations de rayon
axe.set_ylim(0,R[-1]+1)
axe.set_theta_direction(-1)  # theta increasing clockwise

Création et réglages du colormap :

#Réglage du colormap :
cmap=plt.get_cmap('turbo')# colormap reproduisant les couleurs du visible
norm = mpl.colors.Normalize(vmin=400,vmax=700)#normalisation des couleurs

Un colormap est une gamme de couleurs que l’on peut associer à une gamme de valeurs. Le colormap appelé ‘turbo’ reproduit les couleurs du spectre visible. La normalisation consiste à attribuer une valeur (ici 400) à la première couleur (violet) et une autre valeur (700) à la dernière couleur (rouge). Aux valeurs de longueur d’onde intermédiaires entre 400 et 700 seront attribuées des couleurs intermédiaires du colormap.

Le script complet :

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Créé le Tue Apr  4 20:36:35 2023

@auteur: david ALBERTO
(www.astrolabe-science.fr)
"""
import matplotlib.pyplot as plt
import numpy as np
import matplotlib as mpl#Normalisation des valeurs

plt.rcParams["font.family"] = "Roboto" # ou autre police installée

# rayons des arcs des ordres
R = range(5,8)

# longueurs d'onde (nm):
LO = [400, 450, 550, 650]

a = 2.0 # période du réseau, en µm

couleur_fond = 'black'
NomFichier = "diffractionReseau" + str(a)

# fonctions : -------------------------------------

def angle(p,LO):
    """
    à partir de l'ordre p et de la longueur d'onde LO,
    renvoie l'angle de diffraction, en radians
    """
    A = p * LO*1e-9 / (a*1e-6)
    if abs(A) <= 1:
        return np.arcsin(A)
    else:
        return np.nan

def ordre(p):
    """
    trace un ordre complet.
    """
    r = R[abs(p)-1]
    for L in LO:
        theta = angle(p,L)
        if np.isnan(theta) == False:
            axe.vlines(theta, 0, r, color=cmap(norm(L)))

def signe(p): # retourne -1 si p < 0 ou 1 si p > 0
    return abs(p)/p

def arc(p):
    """
    Trace un arc pour délimiter l'ordre p.
    """
    r = R[abs(p)-1]
    Lmin=min(LO)
    Lmax=max(LO)
    angle_min = angle(p, Lmin)
    angle_max = angle(p, Lmax)
    if np.isnan(angle_max): # si le dernier rayon est hors champ
        angle_max=np.pi/2 * signe(p)
    angle_moy = (angle_min + angle_max)/2
    angles = np.arange(angle_min,angle_max,0.02 * signe(p))
    for i in angles: # tracé des pointillés
        axe.scatter(i,r+0.1,s=3,c='gray')
    axe.text(angle_moy,r+0.3,f'ordre {p}',c='gray',ha='center',va='center',rotation = -np.degrees(angle_moy))

# ------------------- propriétés du graphique

fig = plt.figure(tight_layout=True, figsize=(8,8))

axe = plt.subplot(projection='polar',facecolor=couleur_fond)
axe.set_xlim(-np.pi/2, np.pi/2) # réduire à un demi-cercle
axe.set_theta_zero_location('N')  # Set zero to North
axe.set_xticks([])# suppression des graduations d'angle
axe.set_yticks([])# suppression des graduations de rayon
axe.set_ylim(0,R[-1]+1)
axe.set_theta_direction(-1)  # theta increasing clockwise

# ------------------------------------
#Réglage du colormap :
cmap=plt.get_cmap('turbo')# colormap reproduisant les couleurs du visible
norm = mpl.colors.Normalize(vmin=400,vmax=700)#normalisation des couleurs

# ------------------------------------

# ordre 0 :
axe.vlines(0,0,R[-1],color='white')
axe.text(0,R[-1]+0.2,'ordre 0',color="white",ha='center')

# tracé des rayons :

for p in [-3,-2,-1,1,2,3]:
    ordre(p)
    arc(p)

axe.text(0.5,0.24,f'pas du réseau : {a:.2f} µm',c='firebrick',
         va='top', ha='center', fontweight='bold',
         transform=axe.transAxes)

fig.savefig(NomFichier + '.png',dpi=200)
fig.savefig(NomFichier + '.pdf')

Fichier .py à télécharger :

Une version avec 4 graphiques pour voir l’influence du pas du réseau :


Une version du schéma avec LaTeX (package TikZ) :

Soyez le premier à commenter

Laisser un commentaire