Stabilisation thermique active#
Pourquoi#
L’oscillateur à quartz (XO, non compensé) qui cadence l’horloge du système dérive d’environ 0,1 ppm par degré Celsius. Si la température du boîtier oscille librement entre 35 et 50 °C au gré de la charge CPU, cette variation induit à elle seule environ 1,5 ppm de dérive que chrony doit compenser en continu, un bruit évitable si la température est maintenue stable. Le chapitre suivant replace ce travail dans la hiérarchie des oscillateurs (XO, TCXO, OCXO, rubidium, CSAC) et détaille comment l’ensemble des étapes de ce guide transforme ce quartz nu en pseudo-TCXO logiciel.
Comment#
Approche retenue par défaut : régulation par ventilateur#
Le chapitre Firmware a déjà mis en place un profil de ventilation PWM à 4
paliers (fan_temp0 à fan_temp3 dans config.txt), démarrant dès 40 °C.
C’est l’approche passive retenue par défaut : elle stabilise la
température sans consommation électrique permanente, contrairement à
l’alternative ci-dessous.
Alternative optionnelle : charge CPU contrôlée (ntpheat)#
Une autre approche, plus agressive, consiste à maintenir une charge CPU artificielle et contrôlée sur le cœur 0 pour stabiliser activement la température à une consigne fixe (typiquement 57 °C), quelle que soit la charge réelle du système.
Le script ci-dessous provient de
l’utilitaire ntpheat du projet
NTPsec (contrib/ntpheat, écrit par
Gary E. Miller, licence BSD-2-Clause), dans la copie diffusée par David
Taylor sur satsignal.eu, légèrement
adaptée ici :
mkdir -p /opt/ntpheat
cat > /opt/ntpheat/ntpheat.py <<'PYEOF'
#!/usr/bin/env python3
# Charge CPU contrôlée pour maintenir une consigne de température
# Origine : projet NTPsec, contrib/ntpheat (Gary E. Miller,
# licence BSD-2-Clause), via la copie satsignal.eu de David Taylor.
import argparse, hashlib, os, time
p = argparse.ArgumentParser()
p.add_argument('-c','--copies', type=int, default=1)
p.add_argument('-t','--temp', type=float, default=57.0)
p.add_argument('-w','--wait', type=float, default=0.001)
a = p.parse_args()
for _ in range(a.copies - 1):
if os.fork(): break
zone = '/sys/class/thermal/thermal_zone0/temp'
m = hashlib.md5(); cnt = 0; max_cnt = a.wait * 200000; temp = 0
while True:
delta = a.temp - temp
if delta > 0:
m.update(b'controlled load')
else:
cnt = max_cnt
s = max(0.001, a.wait * 10.0 * -delta); time.sleep(s)
cnt += 1
if cnt > max_cnt:
with open(zone) as f: temp = int(f.read())/1000.0
cnt = 0
PYEOF
chmod +x /opt/ntpheat/ntpheat.py
cat > /etc/systemd/system/ntpheat.service <<'EOF'
[Unit]
Description=Stabilisation thermique active (quartz)
[Service]
ExecStart=/usr/bin/python3 /opt/ntpheat/ntpheat.py -c 1 -t 57
Restart=on-failure
CPUAffinity=0
Nice=19
CPUSchedulingPolicy=idle
IOSchedulingClass=idle
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
systemctl enable --now ntpheat.serviceErreurs à éviter#
Ne pas activer
ntpheatpar défaut, d’abord observer. Cette section est délibérément marquée optionnelle. Le coût est réel : environ 1 W de consommation permanente, usure thermique accrue, bruit de ventilateur constant. La recommandation par défaut de ce guide est de skip cette étape et de réévaluer après 24-48h d’observation via Munin (chapitre Munin) : l’activation ne se justifie qu’en présence de variations de fréquence corrélées à la température supérieures à 1 ppm, ou d’une dispersion racine qui reste supérieure à 20 µs malgré un PPS fonctionnel.
- Confondre régulation passive et active. Le profil
fan_tempdu chapitre Firmware est une régulation réactive (le ventilateur s’active quand la température monte, redescend quand elle baisse), la température oscille toujours, mais dans une plage plus resserrée.ntpheatest une régulation active qui vise une consigne fixe en permanence, plus stable, mais avec le coût mentionné ci-dessus. - Oublier
CPUSchedulingPolicy=idle. Sans cette directive, la charge de stabilisation thermique entrerait en compétition avec les vrais services du système pour le temps CPU, au lieu de ne consommer que les cycles autrement perdus.
Vérifier#
# Température actuelle (en millidegrés Celsius)
cat /sys/class/thermal/thermal_zone0/temp
# Historique de la dérive de fréquence, à observer sur plusieurs heures
chronyc tracking | grep FrequencyLa bonne méthode de vérification pour ce chapitre n’est pas instantanée : il faut observer les graphes Munin de température et de fréquence (chapitre Munin) sur au moins 24h, en cherchant une corrélation visuelle entre les cycles jour/nuit (température ambiante) et la dérive de fréquence rapportée par chrony.