Capteur & Signaux
Ces modules regroupent les briques non thermodynamiques de la bibliothèque : un capteur qui lit une grandeur sur un port de fluide sans en modifier l’état, et un bus de signaux générique qui transporte des valeurs scalaires (données ou consignes) entre composants, en dehors des flux de fluide. Un contrôleur PID discret complète l’ensemble pour piloter un signal.
Sensor
Rôle
Capteur terminal branché sur un unique port d’entrée (Inlet). Il lit
l’état du fluide et en déduit une grandeur mesurée, sans influence sur l’état
thermodynamique observé (aucune sortie, il ne perturbe pas le circuit). La
grandeur restituée est choisie par measurement_type ; toutes les grandeurs
dérivables sont malgré tout calculées et exposées dans df.
Grandeurs mesurables
Le type de mesure measurement_type accepte l’une des clés suivantes (issues
du dictionnaire MEASUREMENTS) :
'Température'→temperature_degC[°C]'Pression'→pressure_bar[bar]'Débit massique'→mass_flow_kgs[kg/s]'Débit en m3/h'→volume_flow_m3h[m³/h]'Débit en Nm3/h'→normal_volume_flow_Nm3h[Nm³/h]'Enthalpie'→enthalpy_kJkg[kJ/kg]'Masse volumique'→density_kgm3[kg/m³]'Humidité relative'→relative_humidity_percent[%]
Note
L”humidité relative n’est calculée que si le port d’entrée est un mélange
gazeux humide (thermo_backend ou fluid valant 'humid_gas_mixture',
avec une composition contenant H2O). Pour un fluide pur, cette mesure
reste à None et la sélectionner lève une ValueError.
Le calcul dérive de l’état du port : température et masse volumique sont obtenues
par ThermoPropsSI('T'/'D', 'P', P, 'H', h, fluid), les débits volumiques
(m³/h et Nm³/h) à partir du débit massique et des masses volumiques aux
conditions réelles et normales. Les conditions normales par défaut sont
273,15 K et 101 325 Pa.
Paramètres
Attributs définis dans __init__ (Object()) :
Attribut |
Défaut |
Rôle |
|---|---|---|
|
|
Port d’entrée observé (fournit |
|
|
Grandeur restituée par |
|
|
Température de référence des conditions normales [K]. |
|
|
Pression de référence des conditions normales [Pa]. |
|
|
Horodatage recopié dans |
Après calculate(), les résultats sont exposés dans value (grandeur
choisie), unit (unité associée) et les attributs dédiés
(temperature_degC, pressure_bar, mass_flow_kgs, volume_flow_m3h,
normal_volume_flow_Nm3h, enthalpy_kJkg, density_kgm3,
normal_density_kgNm3, relative_humidity_percent), ainsi que dans le
DataFrame df.
Exemple
from ThermodynamicCycles.Source import Source
from ThermodynamicCycles.Sensor import Sensor
# Source de fluide pour alimenter le capteur
SOURCE = Source.Object()
SOURCE.Pi_bar = 1.01325
SOURCE.Ti_degC = 25
SOURCE.fluid = "air"
SOURCE.F = 1
SOURCE.calculate()
# Capteur branché sur la sortie de la source
SENSOR = Sensor.Object()
SENSOR.Inlet = SOURCE.Outlet
SENSOR.measurement_type = "Température"
valeur = SENSOR.calculate()
print(valeur, SENSOR.unit) # ~25.0 °C
print(SENSOR.df)
Signals
Rôle
Bus de signaux générique et purement logique (testable, sans IHM). Il permet qu’un composant émette n’importe quelle grandeur scalaire de son modèle (paramètre ou résultat) et qu’un autre la reçoive dans n’importe quel attribut, indépendamment des ports de fluide. C’est l’utilisateur qui choisit, à la connexion, quelle grandeur transporter et dans quel sens ; le nœud récepteur doit recalculer après injection de la consigne.
Le module fonctionne par introspection : aucun catalogue à maintenir, tout
attribut scalaire numérique (ou None = résultat non encore calculé) devient
un signal sélectionnable. Les ports et structures (df, Timestamp,
Inlet, Outlet, fluid, callback) sont exclus.
Fonctions utilitaires
Fonction |
Rôle |
|---|---|
|
Retourne |
|
Lit la valeur de l’attribut |
|
Injecte |
Classe SignalLink
Liaison de signal choisie par l’utilisateur : source.<src_attr> →
target.<tgt_attr>.
Paramètre ( |
Rôle |
|---|---|
|
Modèle émetteur (déjà calculé avant |
|
Nom de l’attribut émis sur la source. |
|
Modèle récepteur. |
|
Nom de l’attribut cible où injecter la valeur. |
La méthode propagate(recompute=False) recopie la valeur émise dans la
consigne du récepteur ; si recompute=True et que la cible expose
calculate(), elle la relance.
Exemple
from ThermodynamicCycles.Signals import Signals
# Lister les signaux disponibles sur un modèle
signaux = Signals.list_model_signals(SENSOR)
# Recopier la température lue par le capteur vers la consigne d'un autre nœud
lien = Signals.SignalLink(
source=SENSOR, src_attr="temperature_degC",
target=CIBLE, tgt_attr="Ti_degC",
)
lien.propagate(recompute=True) # injecte puis recalcule la cible
PIDController
Rôle
Contrôleur PID discret générique agissant sur des signaux scalaires. Il
compare une consigne (setpoint) à une mesure (measurement) et produit un
signal de sortie output, typiquement borné [0, 1] pour piloter une
ouverture. L’anti-emballement (anti-windup) sature l’intégrale et gèle son
accumulation quand la sortie est saturée.
Paramètres
Attribut |
Défaut |
Rôle |
|---|---|---|
|
|
Consigne (même unité que la mesure). |
|
|
Grandeur mesurée à réguler. |
|
|
Gain proportionnel. |
|
|
Gain intégral. |
|
|
Gain dérivé. |
|
|
Pas de temps par défaut [s] (sinon déduit des |
|
|
Inverse le sens de l’erreur (action inverse). |
|
|
Bornes de saturation de la sortie. |
|
|
Bornes de saturation de l’intégrale (anti-windup). |
|
|
Biais additif appliqué à la sortie. |
|
|
Horodatage ; l’écart entre deux appels sert de |
Après calculate(), les résultats sont exposés dans error, p_term,
i_term, d_term, output et le DataFrame df. La méthode
reset() réinitialise les états internes (integral, prev_error,
prev_time).
Exemple
from ThermodynamicCycles.Signals import PIDController
PID = PIDController.Object()
PID.Kp = 0.05
PID.Ki = 0.01
PID.setpoint = 20.0 # consigne, ex. 20 °C
PID.measurement = 18.5 # mesure courante
commande = PID.calculate() # signal de sortie borné [0, 1]
print(commande, PID.error)
print(PID.df)