"""Programme de base pour le contrôle, l'acquisition et l'analyse avec Arduino.
Ce script permet d'envoyer des requêtes à un programme Arduino correspondant.
Les réponses reçues sont ensuite analysées et affichées en direct. Il s'agit
d'un programme de démonstration et de départ pour le cours PHS1903 à
l'automne 2025.
Le programme a été développé par `Jacques Massicotte`_ et `Émile Jetzer`_,
techniciens pour le département de génie physique de Polytechnique Montréal.
.. _Jacques Massicotte:
mailto:jacques-2.massicotte@polymtl.ca
.. _Émile Jetzer:
mailto:emile.jetzer@polymtl.ca
Les commentaires et la documentation de ce programme sont très verbeux, et vous
réfèreront souvent à des ressources externes. SVP référez-vous à ces
ressources avant de venir poser vos questions à un technicien.
"""
from logging import getLogger
logging = getLogger(__name__)
# Voir :doc:`deps` pour les détails
from matplotlib import pyplot as plt
from matplotlib.figure import Figure
from pandas import DataFrame
from serial import Serial # <https://www.pyserial.com/docs>
from serial.serialutil import SerialException
from serial.tools.list_ports import comports
from .afficher import plot
from .defs import DEBIT, DELAI, PORT
from .mesure import prendre_mesure
# ===========================
# = Fonctions structurelles =
# ===========================
[docs]
def setup(
pds: int = 2, port: str = PORT, debit: int = DEBIT, delai: int = DELAI
) -> (DataFrame, Serial, Figure):
"""Initialisation du programme.
Initialise le programme avec les paramètres transmis, et retourne les
objets configurés.
Parameters
-----------
debit
pds
Le nombre de broches/photodiodes à mesurer
port
Le port série à utiliser
delai
Le temps d'attente maximal pour une lecture de données
Returns
--------------
res
Liste des mesures, au format ``[t, pd1, pd2, ...]``
ser
Objet de communication série
fig
Figure pour l'affichage des données
derniere_mesure
Valeur initiale de 0
"""
# Initialisation des paramètres importants
logging.info('Initialisation...')
#: On utilise une expression de liste plutôt que la multiplication pour
#: ne pas créer un unique object commun répété plusieurs fois dans la liste.
#: Voir https://stackoverflow.com/q/366422 pour ce genre de problèmes.
res: DataFrame = DataFrame(
columns=['t'] + [f'A{i + 1}' for i in range(pds)], dtype='Float64'
)
logging.debug('res =\n%s', res)
try:
ser = Serial(port, baudrate=debit, timeout=delai)
ser.read()
except SerialException:
logging.error(
"Une erreur de communication série s'est produite, on réessait."
)
possibles = comports()
for i, p in enumerate(possibles):
print(f'[{i}]\t{p.device}\t{p.name}')
i = int(input('>'))
port = possibles[i].device
ser = Serial(port, baudrate=debit, timeout=delai)
ser.read()
logging.info('Connexion complétée à %r', ser)
#: Paramètres des graphiques
#: Affichage interactif, pour pouvoir suivre l'acquisition en direct
plt.ion()
#: Créer une nouvelle figure, qui contiendra nos systèmes d'axes
#: fig.axes pour voir la liste des axes dans la console
fig, (ax, ax2) = plt.subplots(1, 2, figsize=(12, 6))
fig.suptitle("Démonstration d'acquisition")
ax.set_title('Mesure')
ax.set_xlabel('Temps')
ax.set_ylabel('Unités CAN')
ax.plot([], color='black', label='A1')
ax.plot([], color='red', label='A2')
ax.legend()
ax2.set_title('Transformées de Fourier des signaux')
ax2.set_xlabel('Fréquence (GHz)')
ax2.plot([], color='black', label='F(A1)')
ax2.plot([], color='red', label='F(A2)')
ax2.set_yticks([], [])
ax2.legend()
ax.set_ylim(0, 1030)
ax.set_xlim(left=0)
ax2.set_xlim(left=0)
ax2.set_ylim(bottom=0)
fig.tight_layout()
plt.pause(1)
plt.show()
logging.debug('fig = %r', fig)
return res, ser, fig
[docs]
def loop(
res: DataFrame, ser: Serial, fig: Figure
) -> (DataFrame, Serial, Figure):
"""Prend de nouvelles mesures et les affiche.
Parameters
-----------
res
Liste des mesures prises. Structurée en ``[t, pd1, pd2, ...]``
ser
Objet de communication série avec lequel communiquer pour obtenir
les données.
fig
Figure contenant les différents graphiques
Returns
---------------
res: list[list[int]]
ser: serial.Serial
fig: matplotlib.figure.Figure
derniere_mesure: int
"""
logging.info('Itération #%s', res.index.size)
# Lecture des valeurs de chaque photodiode
res = prendre_mesure(res, ser)
# Mise à jour du graphique
plot(res, fig)
return res, ser, fig
[docs]
def setdown(res: list[list[int]], ser: Serial, fig: Figure):
"""Ferme tous les objets en ayant besoin.
Parameters
------------
res
Liste des mesures prises, à effacer
ser
Objet de communication série, à fermer
fig
Figure, à fermer via pyplot
"""
logging.info('On ferme tout...')
del res
ser.close()
plt.close(fig)
logging.info('Au revoir.')