Fiche de traçabilité de la page Calculateur balistique, de son interface js/calculateur-ui.js, et des préréglages qu'elle partage avec le solveur (COMMON_BULLETS, portages JS et Julia) et avec les tables du manuel PDF. Compagne de la fiche du solveur : celle-là auditait l'arbitre ; celle-ci contrôle la vitrine — la page qui expose ses sorties aux lecteurs, et qui depuis le 22 août raconte elle-même comment elle est validée.
Pourquoi cette page passe maintenant. Un texte qui décrit un dispositif de contrôle est lui-même une série d'affirmations factuelles : un nombre de cas, un nombre de modèles, une date. Il mérite exactement le traitement que la passe applique au reste — d'autant que la page vient d'être réécrite et que personne n'avait relu son énumération contre le fichier qu'elle décrit.
La page annonce une grille nocturne de quatorze cas avec « trois modèles de traînée ». Le fichier gelé qu'elle décrit en contient deux : G7 (12 cas) et G1 (2 cas). Le décompte des cas était juste, celui des modèles était plausible et faux — les deux dans la même parenthèse.
Le mécanisme est celui des énumérations descriptives : elles se rédigent de mémoire, après coup, et rien n'obligeait celle-ci à coller au fichier. La leçon rejoint celle du départ de la passe : la description d'un dispositif de contrôle se vérifie comme un chiffre, sinon elle dérive aussi sûrement qu'e — et c'est la page la plus consultée du domaine qui disait faux sur sa propre garde-fou.
Le préréglage « .308 Win / 175 gr Sierra MK » affichait G7 = 0,259. Le tableau du wiki coefficient balistique donne 0,243 pour cette même balle, à partir du même G1 = 0,505 — et la grille de validation utilise 0,243. Pire : la table du manuel qui portait le 0,259 cite en source précisément les travaux de mesure dont la valeur mesurée est 0,243. Elle se contredisait avec sa propre référence depuis sa rédaction ; aucune relecture page par page ne pouvait le voir, car les deux supports n'appartiennent pas au même dossier.
Cinq emplacements portaient la valeur :
| Endroit | Avant | Après |
|---|---|---|
Préréglage de l'interface (calculateur-ui.js) | 0,259 | 0,243 |
Préréglages du solveur JS (COMMON_BULLETS) | 0,259 | 0,243 |
Portage Julia (CompetitionBallistics.jl) | 0,259 | 0,243 |
| Manuel, table des balles de compétition | 0,259 | 0,243 |
| Manuel, table des seuils transsoniques | 0,259 | 0,243 |
La provenance du 0,259 n'a pas pu être établie : la conversion mécanique G1 → G7 du site ne le rend pas non plus (~0,25–0,27 selon la vitesse de référence choisie). Un chiffre sans lignée — c'est le deuxième cas de ce type après le sigle développé en organisme inexistant (fiche sources).
Conséquence pratique chiffrée. Avec un CB gonflé, la ligne transsonique du manuel pour cette balle était trop optimiste. Seuils d'abord reproduits sur les lignes saines (entrée en transsonique à Mach 1,1, subsonique à Mach 1,0, atmosphère normalisée niveau mer — les six autres lignes retombent toutes au cordeau), puis la ligne corrigée recalculée :
| CB | Entre en transsonique | Subsonique |
|---|---|---|
| 0,259 (publié) | $\approx$ 830 m | $\approx$ 920 m |
| 0,243 (corrigé) | $\approx$ 780 m | $\approx$ 860 m |
Le PDF a été reconstruit ; pdftotext ne trouve plus aucune occurrence de l'ancienne valeur.
| Contrôle | Résultat |
|---|---|
| Décompte de la grille | 14 cas ; 3 atmosphères (normalisée, chaud/haut, froid) ; vent, dérive gyroscopique, Coriolis — tout sauf les modèles, conforme |
| Date du premier contrôle automatisé | commit du 2026-08-22, comme dit |
| Valeurs par défaut du formulaire | = préréglage 6,5 CM : 6,71 mm = 0,264″, 34,04 mm = 1,34″, 823 m/s = 2 700 fps, 3,8 cm = 1,5″ |
| Atmosphère revendiquée | ISA 1976 : $T_0$ = 288,15 K, $\rho_0$ = 1,2250 kg/m³ — constantes présentes dans le code |
| Convertisseur G1 ↔ G7 | $BC_{cible} = BC_{source}\cdot C_{d,cible}(M)/C_{d,source}(M)$, redérivé exact ; l'avertissement « un CB ne se convertit pas par un facteur fixe » est correct, et le code le respecte en exigeant une vitesse |
| Infobulle Coriolis | dérive horizontale ∝ sin(lat) — conforme au portage vectoriel complet |
| Infobulle azimut/Eötvös | tir vers l'est → impact plus haut : conforme au signe du code, et validé numériquement par la paire Est/Ouest de la grille |
| Règle du tireur (infobulle pente) | chute perçue en cos α — implémentée ainsi |
| Six autres préréglages | CB identiques dans l'interface, COMMON_BULLETS JS et Julia, et cohérents avec le tableau wiki quand il les porte (0,311 / 0,351 / 0,419) ou entre eux (0,275 / 0,283 / 0,350) |
| Liens | tous vivants, y compris les quatre pages wiki du bloc voir-aussi |
| Solveur tiers, confrontation ponctuelle du 2026-08-24 | cœur du vol à ≤ 0,6 %, dérive au vent à ≤ 1,3 % — voir section ci-dessus |
Les préréglages de l'interface et ceux du solveur diffèrent sur trois longueurs de balle, alors que la longueur alimente le facteur de stabilité de Miller :
| Balle | Interface | COMMON_BULLETS |
|---|---|---|
| Berger 185 Juggernaut (.308) | 1,353″ | 1,30″ |
| Berger 105 Hybrid (6 mm) | 1,292″ | 1,10″ |
| Berger 180 Hybrid (7 mm) | 1,527″ | 1,50″ |
Aucune fiche constructeur ni mesure publiée n'étant disponible dans books/libres/, on ne tranche pas aujourd'hui lequel des deux jeux est bon — mais l'un des deux l'est forcément, et ils pilotent des $S_g$ différents. À régler lors du passage sur la base de calibres.
Pourquoi une troisième avis alors que la grille nocturne existe. py-ballisticcalc et notre solveur lisent les mêmes tables BRL publiées : une erreur de lecture commune — le défaut qui nous a coûté nos tables supersoniques pendant des mois — leur échapperait à tous les deux. Un solveur proposé en ligne par un tiers, écrit d'une lignée de code différente, a été exécuté localement (son code est public dans la page) sur les deux cas nus de la grille et un cas de vent, entrées strictement identiques aux nôtres.
Ses différences de construction, identifiées à la lecture avant exécution : la traînée n'y est pas tabulée mais ajustée par loi de puissance par paliers de vitesse ; l'intégration est un Euler du point milieu à pas adaptatif, pas un RK4 à pas fixe ; l'atmosphère n'y modifie pas la densité mais écrête le CB d'un facteur calé sur une référence de 29,53 inHg — pas les 29,92 standard ; la dérive au vent y est appliquée par la règle du retard, hors intégration, là où la nôtre est intégrée.
Écart relatif à nos sorties :
| Grandeur | 300 yd | 600 yd | 900 yd |
|---|---|---|---|
| Chute, .308 175 gr G7 0,243 | 0,06 % | 0,24 % | 0,39 % |
| Vitesse, .308 175 gr | 0,14 % | 0,25 % | 0,58 % |
| Chute, 6,5 CM 140 gr G7 0,311 | 0,51 % | 0,20 % | 0,26 % |
| Vitesse, 6,5 CM 140 gr | 0,18 % | 0,16 % | 0,39 % |
| Dérive, vent 10 mph à 90° (6,5 CM) | 1,3 % | 0,9 % | 0,8 % |
Concordance de l'ordre du demi pour cent sur le cœur du vol, entre deux implémentations qui ne partagent ni leurs tables de traînée, ni leur intégrateur, ni leur traitement de l'atmosphère. L'écart résiduel est systématique — le solveur tiers retient un peu plus de vitesse à 900 yd — conforme au sens qu'on attend de son écrêtage de CB et de son ajustement continu de traînée. La dérive au vent, calculée par deux méthodes différentes (règle du retard contre intégration), tient à 1,3 % près.
Portée et limite. C'est un contrôle manuel, daté, non rejouable automatiquement — il ne remplace pas la grille nocturne et n'y entre pas : interroger un site vivant en automatique, c'est une référence révocable sans préavis. En cas de divergence future, l'arbitrage reste contre les tables publiées et la DOPE — jamais contre l'un des trois solveurs.
Jusqu'au 2026-08-25, la section « Validation & Références » de la page portait le récit complet, qui est de la traçabilité et non du service au lecteur — il a sa place ici. Ce récit, anonymisé comme le veut la méthode :
La page annonçait une validation contre un étalon public du domaine, dont les calculateurs ont été retirés en 2026 (constat porté au journal de maintenance dès le 2026-08-14 — une référence hébergée chez autrui est un emprunt, révocable sans préavis). Cette validation n'avait jamais été rejouée. La première confrontation réellement automatisée, le 22 août 2026, a montré qu'elle ne tenait pas : les tables de traînée supersoniques étaient fausses au-dessus de Mach 1,03, et un facteur correctif du solveur masquait l'erreur sur un cas particulier — une .308 de 175 gr arrivant à 1 000 yd sur une vitesse plausible, ce qui suffit à faire croire qu'un solveur est juste. Tables et facteur ont été corrigés le jour même ; la grille nocturne existe depuis. La mécanique du facteur est documentée dans la fiche du solveur et son addendum.
Deux lignes de principe restent sur la page, car elles servent directement le lecteur : « un accord entre deux calculateurs ne prouve jamais qu'ils ont raison — ils peuvent partager la même erreur », et « le meilleur contrôle reste votre propre carnet de tir ». La leçon d'époque, qui a motivé la grille, rejoint la méthode : une validation que personne ne rejoue ne vaut rien.
Le calcul de la probabilité de toucher (analyse WEZ) intègre exactement la loi de Hoyt (σx ≠ σy) sur le disque. Il a été confronté à une étude publiée : Webb (US Army Research Laboratory, ARL-MR-830, 2012, hébergé dans la bibliothèque du site) évalue par Monte-Carlo, sur 10⁸ impacts, la formule approchée du CEP de Grubbs et Patnaik, et trouve que son cercle reçoit au plus 2,17 % de coups de plus que 50 %. Le calcul du site retrouve ce maximum : 0,5108 (excès relatif de 2,15 %), vers σx/σy ≈ 4,5. Contre une quadrature adaptative indépendante (SciPy), le rayon à 50 % est exact à 0,002 % pour σx/σy = 3, 0,008 % pour 10, 0,025 % pour 30.
Ces fonctions vivent désormais dans un module partagé avec le carnet de tir (js/dispersion.js), éprouvé à chaque contrôle des artefacts par scripts/check_dispersion.js (formes fermées de Rayleigh, références SciPy, ancre de Webb, axes principaux).
Le code Matlab publié en annexe du rapport ne s'exécute pas tel quel : il appelle sigx(l) (la lettre l) au lieu de sigx(j).
calibers.json donne 0,339″ comme diamètre de balle du .338 Lapua là où solveur, préréglages et manuel utilisent 0,338″. Écart à trancher dans le dossier de la base de calibres, pas ici.
Depuis la passe ci-dessus, la page s'est dotée d'une couche d'analyse que cette fiche déclare couvrir (js/calculateur-ui.js) mais qu'elle ne mentionnait pas. Chaque outil est consigné ici avec le banc qui tient ses nombres ; les équations correspondantes sont au manuel v3.3, chapitre « Dispersion, Hit Probability and Velocity Truing ».
trajectoryTable, déjà couvert par la grille nocturne.energyJ et time. Contrôle croisé : énergie à 549 m identique à la colonne de la table au joule près (1 365 J) ; E₀ = 3 561 J, conforme à ½mv² pour 175 gr à 792 m/s.vTotal est en m/s là où Miller attend des fps — sans conversion, Sg était sous-estimé du facteur ∛(0,305) ≈ 0,67, faisant paraître instable dès 100 m un .308 sain. Banc final : bouche 2,40 (valeur redérivée à la main), 2,34 / 2,21 / 2,05 aux 100 / 300 / 549 m ; le Sg d'en-tête est reproduit exactement au premier point.trajectoryTable est le pas, pas la portée — la table se réduisait à une ligne unique (le banc initial ne l'avait pas vu : son pas égalait sa portée) ; l'angle du formulaire filtrait silencieusement des colonnes annoncées pleine valeur ; le bouton affichait le panneau sans jamais calculer. Banc final (pas 50 m) : à 550 m, 26,2 / 52,6 / 78,7 / 104,9 cm pour 5 / 10 / 15 / 20 km/h, soit 5 / 10 / 14 / 19 clics MRAD — linéarité ×4 vérifiée entre extrêmes. Contrôle croisé contre la table principale (vent 10 km/h à 45°) : rapport 1,084 au lieu de √2, qui est exactement le spin + Coriolis que la soustraction isole (≈ 9 cm à 500 m) — les deux tables se valident l'une l'autre. La grille part sur papier avec la carte de tir : les nombres ont une seule définition (ventData), l'écran et l'impression ne sont que deux rendus.calibers.json, groupées rimfire / rifle / handgun ; il remplit uniquement le diamètre, chaque cote prise dans son unité native (pas de double arrondi : 6,71 mm / 0,264 in pour le 6,5 CM). Vérifié au rendu serveur réel : JSON valide, 140/140 diamètres présents et dans les bornes de saisie ; .308 Win → 7,82 mm / 0,308 in ; l'édition manuelle du diamètre désélectionne la cartouche, comme pour les préréglages.api/ballistics.php : GET plat ou POST JSON, unités des deux systèmes acceptées et normalisées, bornes physiques validées côté serveur ; le moteur node reçoit le JSON par stdin (aucun paramètre ne traverse un shell) et sa réponse est bornée (≤ 400 points, ≤ 200 lignes). Longueur de balle et pas manquants sont estimés — relation du moteur, Greenhill — et signalés dans la réponse : un Sg estimé ne se déguise pas en donnée d'arme. Deux prises au banc avant mise en service : cinq alias écrasaient leur tableau d'alias dans le paramètre « défaut » de num() ; twist_in n'était lu nulle part et Greenhill répondait silencieusement à sa place — Sg 1,824 au lieu de 2,40, dont le ratio 0,761 est la signature exacte du pas estimé. Une démo iframe (fetch → trace) sert de modèle aux futurs clients.
Resté hors couverture de cet addendum : l'API n'a encore aucun consommateur réel dans le wiki ou le forum ; la spécification PWA est écrite mais le service worker n'existe pas. Plotly, listé ci-dessus comme non audité, a été auditée le lendemain — provenance par hachage contre l'artefact officiel de l'éditeur (identique octet pour octet), pas d'eval, sorties réseau confinées au sous-système cartographique qu'aucune trace du site n'emprunte, et intégrité des 693 fichiers vendus figée dans un manifeste vérifié chaque nuit (scripts/check_vendor_integrity.py, détails dans docs/ballistics_roadmap.md) ; la relecture ligne à ligne du minifié reste hors portée.
Trouvées en relisant le code pour répondre à une question simple : quelle notion mathématique l'estimateur explique-t-il mal ? Aucun banc ne pouvait les voir, puisque chacun rejouait les formules erronées.
1. Les facteurs ES → σ de l'outil WEZ étaient ceux d'une série à une dimension. La table ES_FACTEUR_N (1,693 ; 2,326 ; 3,078 à 3, 5 et 10 coups) est celle des constantes $d_2$, l'espérance de l'étendue d'un échantillon normal sur un axe. Or l'outil demande l'extreme spread du groupement, la plus grande distance entre deux impacts dans le plan. Son commentaire citait pourtant la page rayon moyen, qui donne la bonne valeur ($3{,}066\thinspace\sigma$ à 5 coups). Le σ de dispersion était donc surestimé de 42 % à 3 coups, 32 % à 5 coups et 24 % à 10 coups. Facteurs refaits par simulation de 2 000 000 de groupes par valeur de n (erreur-type 0,0006) : 2,408 ; 2,794 ; 3,066 ; 3,275 ; 3,443 ; 3,585 ; 3,706 ; 3,812. Ils concordent avec la page rayon moyen (400 000 groupes) à 0,003 près. Exemple travaillé (.308, 600 yd, ES 20 cm sur 5 coups) : σ passe de 8,60 à 6,52 cm ; P de toucher 6,5 % au lieu de 6,4 % (le vent domine) ; avec un vent parfaitement connu, 93 % au lieu de 78 %.
2. Le truing prenait la dispersion des coups pour l'incertitude de leur moyenne. L'a priori était le SD tir à tir du chrono. Or la grandeur recalée est la V₀ moyenne : son incertitude est l'erreur-type $s/\sqrt{n}$, composée avec l'exactitude de l'appareil (une erreur d'échelle, sans effet sur le SD mais qui déplace la moyenne). L'observation, elle, était un impact unique, avec une « incertitude de lecture » dont l'aide suggérait « la moitié du groupement ». Trois défauts en découlaient :
Le modèle refait : a priori $\sigma^2 = s^2/n + (\epsilon\thinspace\bar{v}_0)^2$, où l'exactitude annoncée est traitée comme un écart-type, ce qui la majore. L'observation est le centre d'un groupe de k coups, avec $\sigma_y = H/d_2(k)$ tiré de la hauteur du groupe et divisé par $\sqrt{k}$. Ce $\sigma_y$ contient déjà l'effet du SD de vitesse, qui n'est donc pas ajouté une seconde fois. Le verdict porte désormais sur la compatibilité des deux estimations, $z = |\hat{v}_0 - \bar{v}_0| / \sqrt{\sigma_{\mathrm{prior}}^2 + \sigma_{\mathrm{obs}}^2}$.
Banc (6,5 CM 140 gr, 800 m, formulaire par défaut sans vent ; chrono radar 823,0 m/s, SD 3 sur 10 coups, ±0,1 % ; groupe de 5, centre +14,7 cm, hauteur 6 cm) : a priori ± 1,26 m/s ; V₀ impliquée 831,9 ± 0,70 m/s ; a posteriori 829,8 ± 0,61 m/s, poids de l'observation 77 % ; z = 6,2, ce qui oriente vers le CB, le zéro ou les conditions. La même page rendue dans Chromium, en français puis en anglais, affiche ces valeurs au centième près, sans erreur JS ni débordement à 320 px. L'exemple est publié dans la pondération par la précision ; ses chiffres issus du solveur sont inscrits dans scripts/check_solver_claims.js. Le manuel passe en v3.4 avec les deux corrections.
Non vérifié : le modèle ne propage pas l'incertitude sur $\sigma_y$ lui-même (±37 % pour l'étendue de 5 coups, affiché dans les hypothèses). Il ne traite pas non plus l'exactitude annoncée comme une loi uniforme ($\epsilon/\sqrt{3}$), faute de savoir ce que les constructeurs entendent par leur borne. L'exemple WEZ gardait la sensibilité au vent du manuel (13,5 cm par km/h) : recalculée le jour même, elle était fausse (voir l'addendum suivant).
Question posée à la relecture : la loi de Rayleigh suppose le même σ sur les deux axes, alors que le SD de vitesse n'agit que sur la verticale. La réponse chiffrée a fait apparaître un défaut plus lourd que la question.
Le vent était étalé en hauteur. L'outil composait l'incertitude de vent, purement latérale, dans un σ unique qu'il appliquait aux deux axes. Sur l'exemple du manuel (σ groupement 6,52 cm, σ vent 40,5 cm, plaque de 30 cm), il annonçait 6,5 % de touches. La probabilité avec σx = 41,0 et σy = 6,52 cm vaut 25,3 %, soit presque quatre fois plus. Valeur obtenue par intégration dans la page, et confirmée par SciPy (quad) à 10⁻⁵ près.
La sensibilité au vent de cet exemple était elle-même fausse. Le manuel supposait 13,5 cm par km/h pour la .308 175 gr à 600 yd. Le solveur donne 5,23 cm par km/h (15,70 cm pour ±3 km/h, formulaire par défaut). La dérive imprimée de Litz, déjà ancre du garde-fou, va dans le même sens : 28,5 pouces par 10 mph pour une balle voisine, soit environ 4,5 cm par km/h. Le chiffre du manuel était 2,6 fois trop fort ; son origine n'a pas été retrouvée.
L'outil refait. Trois sources, chacune sur son axe :
La probabilité sur le disque s'intègre numériquement (Simpson, 400 intervalles ; erf d'Abramowitz et Stegun 7.1.26). Les rayons de 50 et 90 % s'obtiennent par dichotomie. Pour σx = σy, l'outil retrouve Rayleigh (0,929091 contre 0,929095).
Arrondi de trajectoryTable. La table arrondit chute et dérive au dixième de pouce, ce qui fausse des différences finies de 1 à 2 %. Le WEZ et le truing lisent désormais la trajectoire non arrondie. La pente du truing passe de 1,667 à 1,659 cm par m/s, et l'exemple publié devient : V₀ impliquée 831,9 ± 0,70 m/s, a posteriori 829,8 ± 0,61 m/s, z = 6,2. Le banc part de 823,0 m/s, la valeur que le formulaire affiche, et non de 2 700 fps (822,96 m/s).
Autres prises. La note de l'outil affirmait que « l'ES d'un petit groupement sous-estime σ ». C'est faux une fois l'ES divisé par son facteur d'espérance ; la note dit maintenant ce qui est vrai : un seul ES de 5 coups estime σ à ±27 % (simulation, 400 000 groupes). La liste des champs conservés au changement de langue ignorait les nouveaux champs du truing depuis sa réécriture du matin ; elle est complétée.
Banc du nouvel exemple (celui du manuel) : .308 175 gr, préréglage, 549 m ; ES 3,0 cm à 100 m sur 5 coups, vent ±3 km/h, SD 3 m/s, plaque de 30 cm. σ groupement 5,37 cm, vent 15,70 cm, vitesse 2,68 cm ; σx 16,6 cm et σy 6,0 cm ; P = 58 %, contre 97 % à vent parfaitement connu. Un σ circulaire unique aurait donné 33 %. Le 33/58 et le tableau d'anisotropie de la page de statistiques sont inscrits dans check_solver_claims.js. Page rendue dans Chromium en français et en anglais, sans erreur JS ni débordement à 320 px.
Non vérifié : les causes d'anisotropie liées au tireur (respiration, balancement) et la compensation positive ne sont pas modélisées. Le groupement tiré court est supposé proportionnel à la distance.
Question posée : les outils auxquels on se compare utilisent-ils Rayleigh ? Ceux qui valident le solveur (py-ballisticcalc, tables imprimées de Litz) ne calculent pas de probabilité de toucher. Ceux qui en calculent la tirent au hasard, source par source, trajectoire par trajectoire : l'analyse WEZ d'Applied Ballistics (Litz, Applied Ballistics for Long Range Shooting, 3ᵉ éd., ch. 16, p. 271-283, lu dans notre copie ; document ABDOC115 de 2021, consulté en ligne) et l'outil de Zima Ballistics (guide en ligne). Aucun ne suppose de groupement circulaire. Sources complètes dans la page probabilités et statistiques et dans la bibliographie du manuel.
Deux écarts de notre outil, corrigés le jour même :
L'exemple du manuel et de la page de statistiques (33 % contre 58 %) est désormais libellé avec un écart-type de 3 km/h sur le vent, ce qu'il était. La sensibilité de 0,8 cm par mètre est inscrite dans check_solver_claims.js.
Non vérifié : le fonctionnement interne des Kestrel ; l'analyse d'Applied Ballistics n'est connue que par sa description (livre et ABDOC115). Le livre Accuracy and Precision for Long Range Shooting (Litz, 2012), cité par Litz pour le traitement complet, n'a pas été consulté. Le dévers (cant) et la variation du CB, que ces outils peuvent modéliser, ne le sont pas ici.