<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
	<title>Monorailcat</title>
	<link href="https://monorailc.at/cms/rss.xml" rel="self" type="application/rss+xml" />
	<updated>2026-01-16T15:30:00+00:00</updated>
	<author>
		<name>Xavier</name>
	</author>
	<id>https://monorailc.at/</id>

	<entry>
		<title>Lampe à LEDs : Teardown (2)</title>
		<link href="/cms/2026-01-16-lampe---leds---teardown--2-.html" />
		<updated>2026-01-16T15:30:00+00:00</updated>
		<id>https://monorailc.atoutput/cms/2026-01-16-lampe---leds---teardown--2-.html</id>
		<summary type="html"><![CDATA[<p>J’ai eu deux lampes non-fonctionnelles :</p>
<ul>
<li>Müller-Licht 42850<a href="#fn1" class="footnote-ref" id="fnref1"
role="doc-noteref"><sup>1</sup></a>, défectueuse après un choc
mécanique</li>
<li>Osram AC01190<a href="#fn2" class="footnote-ref" id="fnref2"
role="doc-noteref"><sup>2</sup></a>, avec un clignotement aléatoire
après quelques années</li>
</ul>
<p>Autant les ouvrir pour voir ce qu’il y a dedans.</p>
<h1 id="spécifications">Spécifications</h1>
<p>Comme chaque lampe est fournie avec une datasheet, on va pouvoir les
comparer avant de les démonter.</p>
<table>
<thead>
<tr class="header">
<th style="text-align: left;">Donnée</th>
<th style="text-align: center;">Müller 42850<a href="#fn3"
class="footnote-ref" id="fnref3"
role="doc-noteref"><sup>3</sup></a></th>
<th style="text-align: center;">Osram AC01190<a href="#fn4"
class="footnote-ref" id="fnref4"
role="doc-noteref"><sup>4</sup></a></th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td style="text-align: left;">Puissance nominale</td>
<td style="text-align: center;">3 W</td>
<td style="text-align: center;">4.3 W</td>
</tr>
<tr class="even">
<td style="text-align: left;">Température de couleur</td>
<td style="text-align: center;">2’700 K</td>
<td style="text-align: center;">2’700 K</td>
</tr>
<tr class="odd">
<td style="text-align: left;">Couleur</td>
<td style="text-align: center;">Blanc chaud</td>
<td style="text-align: center;">Blanc chaud</td>
</tr>
<tr class="even">
<td style="text-align: left;">CRI</td>
<td style="text-align: center;">&gt;90</td>
<td style="text-align: center;">80</td>
</tr>
<tr class="odd">
<td style="text-align: left;">Intensité du faisceau</td>
<td style="text-align: center;">250 lm</td>
<td style="text-align: center;">350 lm</td>
</tr>
<tr class="even">
<td style="text-align: left;">Socket</td>
<td style="text-align: center;">GU10</td>
<td style="text-align: center;">GU10</td>
</tr>
<tr class="odd">
<td style="text-align: left;">Angle de projection</td>
<td style="text-align: center;">NA (~180°)</td>
<td style="text-align: center;">36 °</td>
</tr>
<tr class="even">
<td style="text-align: left;">Durée de vie</td>
<td style="text-align: center;">25’000 h</td>
<td style="text-align: center;">10’000 h</td>
</tr>
<tr class="odd">
<td style="text-align: left;">Tension de service</td>
<td style="text-align: center;">220-240 V AC</td>
<td style="text-align: center;">220-240 V AC</td>
</tr>
<tr class="even">
<td style="text-align: left;">Facteur de puissance</td>
<td style="text-align: center;">0.91</td>
<td style="text-align: center;">&gt;0.4</td>
</tr>
<tr class="odd">
<td style="text-align: left;">Durée de démarrage</td>
<td style="text-align: center;">&lt;1 s</td>
<td style="text-align: center;">&lt;0.5 s</td>
</tr>
<tr class="even">
<td style="text-align: left;">Classe d’énergie</td>
<td style="text-align: center;">A++ (G)</td>
<td style="text-align: center;">F</td>
</tr>
<tr class="odd">
<td style="text-align: left;">Efficacité lumineuse</td>
<td style="text-align: center;">83.33 lm/W</td>
<td style="text-align: center;">81 lm/W</td>
</tr>
<tr class="even">
<td style="text-align: left;">Dimmable</td>
<td style="text-align: center;">Non</td>
<td style="text-align: center;">Non</td>
</tr>
</tbody>
</table>
<p>Les spécifications des deux lampes sont assez comparables, regardons
ce qui est remarquable :</p>
<ul>
<li>La puissance nominale et l’intensité lumineuse sont légèrement
différentes par construction</li>
<li>Le coefficient de rendu des couleurs diffère, mais le spectre de
chaque lampe est très similaire. Il est possible que les conditions des
spécifications diffèrent</li>
<li>L’angle de projection de la lampe Müller est quasiment plat
(estimé), parce que la lampe contient plusieurs LEDs à plat derrière un
diffuseur. Celui de la lampe Osram est plus directif, avec une ou
plusieurs LEDs derrière une lentille, pour imiter le comportement de
lampes à incandescence à réflecteur parabolique (PAR)</li>
<li>La différence de durée de vie est surprenante. Il est possible que
les conditions des spécifications diffèrent</li>
<li>Le facteur de puissance de la lampe Osram est très faible, ça
suppose la présence d’une capacité directement derrière le redresseur.
La lampe Müller a probablement une architecture différente, ou un
filtre</li>
<li>Le fait qu’aucune des lampes ne soit dimmable suppose la présence
d’une capacité d’assez forte valeur pour lisser la tension du
secteur</li>
</ul>
<h1 id="osram-ac01190">Osram AC01190</h1>
<p>Le boitier s’ouvre en séparant la lentille du corps de la lampe, sans
outil. Les fils sertis dans le connecteur GU10 et sur le PCB
cassent.</p>
<p>De façon surprenante, le corps de la lampe est en verre partiellement
recouvert d’aluminium, comme sur les lampes à incandescence PAR, alors
que le traitement de surface n’est pas utile.</p>
<figure>
<img src="/data/diy/mueller_osram_gu10_leds/osram_ac01190_par_lens.jpg"
title="Osram AC01190 - Lentille" alt="Osram AC01190 - Lentille" />
<figcaption aria-hidden="true">Osram AC01190 - Lentille</figcaption>
</figure>
<p>Il faut casser 3 pions pour séparer le PCB de la lentille en
plastique et du radiateur en aluminium.</p>
<p>On y découvre une seule LED et un dissipateur thermique derrière la
lentille.</p>
<figure>
<img
src="/data/diy/mueller_osram_gu10_leds/osram_ac01190_led_heatsink.jpg"
title="Osram AC01190 - LED" alt="Osram AC01190 - LED" />
<figcaption aria-hidden="true">Osram AC01190 - LED</figcaption>
</figure>
<h2 id="inspection-visuelle">Inspection visuelle</h2>
<p>Aucun composant n’est visuellememt abimé, et l’assemblage semble de
bonne qualité, avec la présence d’une plaque d’aluminium qui sert de
dissipateur thermique.</p>
<p>Il y a quelques traces de chauffe :</p>
<ul>
<li>Les residus de flux autour de chaque soudure sont marron au lieu de
transparent à jaune clair</li>
<li>Quelques soudures sont sèches et possiblement fissurées (C2,
F1)</li>
<li>R4 est oxydée avec de reflets violets</li>
</ul>
<figure>
<img src="/data/diy/mueller_osram_gu10_leds/osram_ac01190_heat.jpg"
title="Osram AC01190 - Usure" alt="Osram AC01190 - Usure" />
<figcaption aria-hidden="true">Osram AC01190 - Usure</figcaption>
</figure>
<h2 id="marquages">Marquages</h2>
<p>Le PCB a les marquages suivants :</p>
<table>
<thead>
<tr class="header">
<th style="text-align: left;">Marquage</th>
<th style="text-align: left;">Signification</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td style="text-align: left;">UL GF201</td>
<td style="text-align: left;">Identification du substrat</td>
</tr>
<tr class="even">
<td style="text-align: left;">94V-0</td>
<td style="text-align: left;">Grade d’inflammabilité</td>
</tr>
<tr class="odd">
<td style="text-align: left;">1018</td>
<td style="text-align: left;">Code de date, semaine 10 2018</td>
</tr>
<tr class="even">
<td style="text-align: left;">&lt;RoHS&gt;</td>
<td style="text-align: left;">RoHS</td>
</tr>
<tr class="odd">
<td style="text-align: left;">1Q1-3416437-03</td>
<td style="text-align: left;">Référence de PCB</td>
</tr>
</tbody>
</table>
<h2 id="bom">BOM</h2>
<table style="width:100%;">
<colgroup>
<col style="width: 17%" />
<col style="width: 17%" />
<col style="width: 21%" />
<col style="width: 21%" />
<col style="width: 21%" />
</colgroup>
<thead>
<tr class="header">
<th style="text-align: left;">Composant</th>
<th style="text-align: left;">Composant</th>
<th style="text-align: center;">Boitier</th>
<th style="text-align: center;">Marque</th>
<th style="text-align: center;">Valeur/Référence</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td style="text-align: left;">F1</td>
<td style="text-align: left;">Résistance fusible</td>
<td style="text-align: center;">THT</td>
<td style="text-align: center;">-</td>
<td style="text-align: center;">47 Ohm</td>
</tr>
<tr class="even">
<td style="text-align: left;">L1</td>
<td style="text-align: left;">Inductance</td>
<td style="text-align: center;">THT</td>
<td style="text-align: center;">-</td>
<td style="text-align: center;">4.7 mH</td>
</tr>
<tr class="odd">
<td style="text-align: left;">R1</td>
<td style="text-align: left;">Résistance</td>
<td style="text-align: center;">1206</td>
<td style="text-align: center;">-</td>
<td style="text-align: center;">1 kOhm</td>
</tr>
<tr class="even">
<td style="text-align: left;">D1</td>
<td style="text-align: left;">Redresseur</td>
<td style="text-align: center;"></td>
<td style="text-align: center;">?</td>
<td style="text-align: center;">MB10S</td>
</tr>
<tr class="odd">
<td style="text-align: left;">C2</td>
<td style="text-align: left;">Capacité chimique</td>
<td style="text-align: center;"></td>
<td style="text-align: center;">Samxon</td>
<td style="text-align: center;">2.2 uF, 400V</td>
</tr>
<tr class="even">
<td style="text-align: left;">C4</td>
<td style="text-align: left;">Capacité céramique</td>
<td style="text-align: center;"></td>
<td style="text-align: center;">-</td>
<td style="text-align: center;">?</td>
</tr>
<tr class="odd">
<td style="text-align: left;">R4</td>
<td style="text-align: left;">Résistance</td>
<td style="text-align: center;">0805</td>
<td style="text-align: center;">-</td>
<td style="text-align: center;">5.6 kOhm</td>
</tr>
<tr class="even">
<td style="text-align: left;">D2</td>
<td style="text-align: left;">Diode Si</td>
<td style="text-align: center;">SMA</td>
<td style="text-align: center;">?</td>
<td style="text-align: center;">HSJ1</td>
</tr>
<tr class="odd">
<td style="text-align: left;">L1</td>
<td style="text-align: left;">Inductance</td>
<td style="text-align: center;"></td>
<td style="text-align: center;">-</td>
<td style="text-align: center;">?</td>
</tr>
<tr class="even">
<td style="text-align: left;">LED</td>
<td style="text-align: left;">LED</td>
<td style="text-align: center;"></td>
<td style="text-align: center;">Everlight</td>
<td style="text-align: center;"><em>67-23ST KKE 2700K</em><a href="#fn5"
class="footnote-ref" id="fnref5"
role="doc-noteref"><sup>5</sup></a></td>
</tr>
<tr class="odd">
<td style="text-align: left;">U1</td>
<td style="text-align: left;">Contrôleur buck</td>
<td style="text-align: center;">SOIC-8</td>
<td style="text-align: center;">Maxic</td>
<td style="text-align: center;">MT7828B<a href="#fn6"
class="footnote-ref" id="fnref6"
role="doc-noteref"><sup>6</sup></a></td>
</tr>
<tr class="even">
<td style="text-align: left;">R2</td>
<td style="text-align: left;">Résistance</td>
<td style="text-align: center;">0805</td>
<td style="text-align: center;">-</td>
<td style="text-align: center;">3 Ohm</td>
</tr>
<tr class="odd">
<td style="text-align: left;">R3</td>
<td style="text-align: left;">Résistance</td>
<td style="text-align: center;">0805</td>
<td style="text-align: center;">-</td>
<td style="text-align: center;">6.8 Ohm</td>
</tr>
<tr class="even">
<td style="text-align: left;">C3</td>
<td style="text-align: left;">Capacité céramique</td>
<td style="text-align: center;">0805</td>
<td style="text-align: center;">-</td>
<td style="text-align: center;"></td>
</tr>
</tbody>
</table>
<p>La datasheet du contrôleur indique le courant dans la LED en fonction
de la valeur des résistances de shunt, ici, avec R2 et R3 en
parallèle.</p>
<p><math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>I</mi><mrow><mi>L</mi><mi>E</mi><mi>D</mi></mrow></msub><mo>=</mo><mfrac><mrow><mn>600</mn><mi>m</mi><mi>V</mi></mrow><mrow><mn>2</mn><mo>⋅</mo><msub><mi>R</mi><mrow><mi>C</mi><mi>S</mi></mrow></msub></mrow></mfrac><mo>=</mo><mfrac><mrow><mn>600</mn><mi>m</mi><mi>V</mi></mrow><mrow><mn>2</mn><mo>⋅</mo><mn>2.08</mn><mi>Ω</mi></mrow></mfrac><mo>=</mo><mn>144</mn><mi>m</mi><mi>A</mi></mrow><annotation encoding="application/x-tex">I_{LED} = \frac{600 mV}{2 \cdot R_{CS}} = \frac{600 mV}{2 \cdot 2.08 \Omega} = 144 mA </annotation></semantics></math></p>
<h2 id="schéma">Schéma</h2>
<p>Le schéma est très proche de celui donné en exemple de la datasheet
du contrôleur.</p>
<figure>
<img
src="/data/diy/mueller_osram_gu10_leds/osram_ac01190_schematics.png"
title="Osram AC01190 - Schéma" alt="Osram AC01190 - Schéma" />
<figcaption aria-hidden="true">Osram AC01190 - Schéma</figcaption>
</figure>
<h2 id="test">Test</h2>
<h3 id="lampe">Lampe</h3>
<p>L’alimentation buck est simple, et la datasheet ne mentionne pas de
tension minimale autre que pour le régulateur de tension interne.</p>
<p>On peut brancher une alimentation de labo sur les pins L et N, et
augmenter progressivement la tension. La LED commence à éclairer
faiblement vers 20V, puis éclaire de façon nominale à partir de 28V.</p>
<figure>
<img src="/data/diy/mueller_osram_gu10_leds/osram_ac01190_psu_test.jpg"
title="Osram AC01190 - Test" alt="Osram AC01190 - Test" />
<figcaption aria-hidden="true">Osram AC01190 - Test</figcaption>
</figure>
<h3 id="led">LED</h3>
<p>On peut aussi alimenter directement la LED avec une alimentation
limitée en courant, pour caractériser la LED.</p>
<p>En observant la LED et en l’alimentant avec une très faible tension,
on distingue plusieurs dies dans un seul package, on peut s’attendre à
une tension de seuil largement plus élevée que 3V. On mesure
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>V</mi><mi>f</mi></msub><mo>=</mo><mn>20</mn><mi>V</mi></mrow><annotation encoding="application/x-tex">V_f = 20V</annotation></semantics></math>
en pratique.</p>
<p>Or, la datasheet de la LED indique
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>V</mi><mi>f</mi></msub><mo>=</mo><mn>9.6</mn><mi>V</mi></mrow><annotation encoding="application/x-tex">V_f = 9.6V</annotation></semantics></math>.
Il est possible qu’il y ait eu plusieurs révisions de lampe et de
datasheet qui ne correspondent pas.</p>
<h1 id="müller-licht-42850">Müller-Licht 42850</h1>
<p>Le boitier s’ouvre en séparant la lentille du corps de la lampe, puis
en séparant un premier PCB sur lequel sont montées 8 LEDs, et donne
accès à un autre PCB d’alimentation qui est serti dans le boitier.</p>
<figure>
<img src="/data/diy/mueller_osram_gu10_leds/mueller_42850_teardown.jpg"
title="Müller 42850 - Démontage" alt="Müller 42850 - Démontage" />
<figcaption aria-hidden="true">Müller 42850 - Démontage</figcaption>
</figure>
<p>Il peut-être nécessaire d’utiliser une lame pour enlever la colle de
la lentille et du premier PCB. Il faut faire attention à ne pas casser
le connecteur blanc en soulevant le premier PCB, mais il n’y a pas
d’alternative autre que de casser les fils sertis dans le connecteur
GU10 pour démonter le second PCB.</p>
<p>Sans surprise, le boitier est en plastique, mais la lentille est
aussi en plastique, et le PCB sur lequel les LEDs sont assemblées
utilise un substrat en aluminium pour améliorer la dissipation
thermique.</p>
<p>L’assemblage semble de qualité moyenne, il reste des traces de colle
et même des traces d’étain laissées lors de la soudure par vague.</p>
<figure>
<img src="/data/diy/mueller_osram_gu10_leds/mueller_42850_pcb.jpg"
title="Müller 42850 - PCB" alt="Müller 42850 - PCB" />
<figcaption aria-hidden="true">Müller 42850 - PCB</figcaption>
</figure>
<h2 id="marquages-1">Marquages</h2>
<p>Le boitier et l’emballage ont des logos CE, TÜV et GS conformes, on
peut s’attendre à un niveau de sécurité minimal.</p>
<p>Le PCB contenant les LEDs a les marquages suivants :</p>
<table>
<thead>
<tr class="header">
<th style="text-align: left;">Marquage</th>
<th style="text-align: left;">Signification</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td style="text-align: left;">MK-GU10-8SMD2835-V0.2</td>
<td style="text-align: left;">Référence de PCB</td>
</tr>
<tr class="even">
<td style="text-align: left;">(HY)</td>
<td style="text-align: left;">Hongyi, fabricant de PCB</td>
</tr>
<tr class="odd">
<td style="text-align: left;">2015-12-3</td>
<td style="text-align: left;">Date de conception</td>
</tr>
</tbody>
</table>
<p>Le PCB de l’alimentation a les marquages suivants :</p>
<table>
<thead>
<tr class="header">
<th style="text-align: left;">Marquage</th>
<th style="text-align: left;">Signification</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td style="text-align: left;">UL HY-1</td>
<td style="text-align: left;">Hongyi, fabricant de PCB</td>
</tr>
<tr class="even">
<td style="text-align: left;">E348413 94V-0</td>
<td style="text-align: left;">Code UL du fabricant de PCB</td>
</tr>
<tr class="odd">
<td style="text-align: left;">MK-GU10-6W-V0.8A</td>
<td style="text-align: left;">Grade d’inflammabilité</td>
</tr>
<tr class="even">
<td style="text-align: left;">(HY)</td>
<td style="text-align: left;">Hongyi, fabricant de PCB</td>
</tr>
<tr class="odd">
<td style="text-align: left;">2016-4-25</td>
<td style="text-align: left;">Date de conception</td>
</tr>
</tbody>
</table>
<h2 id="bom-1">BOM</h2>
<table style="width:100%;">
<colgroup>
<col style="width: 17%" />
<col style="width: 17%" />
<col style="width: 21%" />
<col style="width: 21%" />
<col style="width: 21%" />
</colgroup>
<thead>
<tr class="header">
<th style="text-align: left;">Composant</th>
<th style="text-align: left;">Composant</th>
<th style="text-align: center;">Boitier</th>
<th style="text-align: center;">Marque</th>
<th style="text-align: center;">Valeur/Référence</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td style="text-align: left;">F1</td>
<td style="text-align: left;">Fusible</td>
<td style="text-align: center;">THT</td>
<td style="text-align: center;">-</td>
<td style="text-align: center;">10 Ohm</td>
</tr>
<tr class="even">
<td style="text-align: left;">L1</td>
<td style="text-align: left;">Inductance</td>
<td style="text-align: center;">THT</td>
<td style="text-align: center;">-</td>
<td style="text-align: center;">1.2 mH</td>
</tr>
<tr class="odd">
<td style="text-align: left;">BD1</td>
<td style="text-align: left;">Redresseur</td>
<td style="text-align: center;"></td>
<td style="text-align: center;">?</td>
<td style="text-align: center;">TL10F<a href="#fn7" class="footnote-ref"
id="fnref7" role="doc-noteref"><sup>7</sup></a></td>
</tr>
<tr class="even">
<td style="text-align: left;">C1</td>
<td style="text-align: left;">Capacité chimique</td>
<td style="text-align: center;">THT</td>
<td style="text-align: center;">Aishi</td>
<td style="text-align: center;">3.3 uF, 400V</td>
</tr>
<tr class="odd">
<td style="text-align: left;">C2</td>
<td style="text-align: left;">Capacité céramique</td>
<td style="text-align: center;">THT</td>
<td style="text-align: center;">-</td>
<td style="text-align: center;">100 nF, 400V</td>
</tr>
<tr class="even">
<td style="text-align: left;">C3</td>
<td style="text-align: left;">Capacité céramique</td>
<td style="text-align: center;">0805</td>
<td style="text-align: center;">-</td>
<td style="text-align: center;"></td>
</tr>
<tr class="odd">
<td style="text-align: left;">D1</td>
<td style="text-align: left;">Diode Si</td>
<td style="text-align: center;">SMA</td>
<td style="text-align: center;">?</td>
<td style="text-align: center;">?</td>
</tr>
<tr class="even">
<td style="text-align: left;">L2</td>
<td style="text-align: left;">Inductance</td>
<td style="text-align: center;">THT</td>
<td style="text-align: center;">-</td>
<td style="text-align: center;">?</td>
</tr>
<tr class="odd">
<td style="text-align: left;">R1</td>
<td style="text-align: left;">Résistance</td>
<td style="text-align: center;">1206</td>
<td style="text-align: center;">-</td>
<td style="text-align: center;">510 kOhm</td>
</tr>
<tr class="even">
<td style="text-align: left;">U1</td>
<td style="text-align: left;">Contrôleur buck</td>
<td style="text-align: center;">SOT-23</td>
<td style="text-align: center;">BPSemi</td>
<td style="text-align: center;">BP9918S<a href="#fn8"
class="footnote-ref" id="fnref8"
role="doc-noteref"><sup>8</sup></a></td>
</tr>
<tr class="odd">
<td style="text-align: left;">RS1</td>
<td style="text-align: left;">Résistance</td>
<td style="text-align: center;">0805</td>
<td style="text-align: center;">-</td>
<td style="text-align: center;">6.8 Ohm</td>
</tr>
<tr class="even">
<td style="text-align: left;">RS2</td>
<td style="text-align: left;">Résistance</td>
<td style="text-align: center;">0805</td>
<td style="text-align: center;">-</td>
<td style="text-align: center;">22 Ohm</td>
</tr>
</tbody>
</table>
<h2 id="schéma-1">Schéma</h2>
<p>Le schéma est très proche de celui donné en exemple de la datasheet
du contrôleur, et utilise une structure inhabituelle.</p>
<figure>
<img
src="/data/diy/mueller_osram_gu10_leds/mueller_42850_schematics.png"
title="Müller 42850 - Schéma" alt="Müller 42850 - Schéma" />
<figcaption aria-hidden="true">Müller 42850 - Schéma</figcaption>
</figure>
<h2 id="test-1">Test</h2>
<h3 id="lampe-1">Lampe</h3>
<p>L’alimentation à l’air simple et ne devrait pas avoir de chute de
tension de plus de quelques volts. On devrait pouvoir l’alimenter avec
une tension proche de celle des LEDs.</p>
<p>On peut brancher une alimentation de labo sur les pins L et N, et
augmenter progressivement la tension. Les LEDs commencent à éclairer
vers 48V, puis éclairent encore faiblement à 50V, la tension maximale de
mon alimentation.</p>
<figure>
<img src="/data/diy/mueller_osram_gu10_leds/mueller_42850_psu_test.jpg"
title="Müller 42850 - Test" alt="Müller 42850 - Test" />
<figcaption aria-hidden="true">Müller 42850 - Test</figcaption>
</figure>
<h3 id="led-1">LED</h3>
<p>On peut aussi alimenter directement le PCB de LEDs avec une
alimentation limitée en courant, pour caractériser les LEDs.</p>
<p>J’ai mesuré un
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><msub><mi>V</mi><mi>f</mi></msub><annotation encoding="application/x-tex">V_f</annotation></semantics></math>
total supérieur à 45 V, ce qui suppose qu’il y a deux LEDs par package,
soit 16 LEDs au total.</p>
<h1 id="résultats">Résultats</h1>
<p>Les spécifications de la lampe Müller semblent optimistes pour la
qualité des composants et leur assemblage, et la lampe Osram à l’air
d’avoir été construite avec des <em>restes</em> de lampes halogènes.
L’échantillon de test ne permet pas de conclure sur la durée de vie
réelle, décevante dans les deux cas.</p>
<h1 id="références">Références</h1>
<section class="footnotes footnotes-end-of-document"
role="doc-endnotes">
<hr />
<ol>
<li id="fn1" role="doc-endnote"><p><a
href="http://m.mueller-licht.net/93864_de/">Müller-Licht 93864_de</a><a
href="#fnref1" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn2" role="doc-endnote"><p><a
href="https://shop.ledvance.com/products/osram-4058075818392-a-led-base-par16-led-reflektorlampe-mit-gu10-sockel-glas-4-3-w-warmweiss-5-5-x-5-09-x-5-09-cm">OSRAM
LED BASE Spot PAR16 50 36° 4.3 W/2700K GU10 - Ledvance shop</a><a
href="#fnref2" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn3" role="doc-endnote"><p><a
href="https://tool.mueller-licht.net/web/pdf/?42850.pdf">Müller-Licht
42850 - Datasheet</a><a href="#fnref3" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
<li id="fn4" role="doc-endnote"><p><a
href="https://www.ledvance.com/de/product-datasheet/6847/44601">Osram
LED Base PAR16 50 36° 4.3W 827 GU10 - Datasheet</a><a href="#fnref4"
class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn5" role="doc-endnote"><p><a
href="https://www.everlight.com/wp-content/uploads/2021/02/DSE-0020826-67-23ST-KKE-NXXXXX96Z10-SZM-2T_V7.pdf">Everlight
67-23ST KKE 2700K - Datasheet</a><a href="#fnref5" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
<li id="fn6" role="doc-endnote"><p><a
href="https://datasheet4u.com/pdf-down/M/T/7/MT7828-MaxicTechnology.pdf">MT7828
- Datasheet</a><a href="#fnref6" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
<li id="fn7" role="doc-endnote"><p><a
href="https://www.alldatasheet.com/datasheet-pdf/view/1772849/CHINADIODES/TL10F.html">TL10F
- Datasheet</a><a href="#fnref7" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
<li id="fn8" role="doc-endnote"><p><a
href="https://www.alldatasheet.com/datasheet-pdf/download/1140991/BPS/BP9918C.html">BP9918C
- Datasheet</a><a href="#fnref8" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
</ol>
</section>
]]>
		</summary>
	</entry>

	<entry>
		<title>Lectures 2025</title>
		<link href="/cms/2026-01-01-lectures-2025.html" />
		<updated>2026-01-01T21:00:00+00:00</updated>
		<id>https://monorailc.atoutput/cms/2026-01-01-lectures-2025.html</id>
		<summary type="html"><![CDATA[<p>Comme <a href="/cms/livres.html">les années précédentes</a>, voici
les livres de divertissement technique et scientifique que j’ai lus en
2025, et que je considère intéressants à partager.</p>
<table>
<colgroup>
<col style="width: 33%" />
<col style="width: 33%" />
<col style="width: 33%" />
</colgroup>
<thead>
<tr class="header">
<th style="text-align: left;">Titre</th>
<th style="text-align: left;">Auteurs</th>
<th style="text-align: left;">ISBN/ISSN</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td style="text-align: left;">Six Easy Pieces</td>
<td style="text-align: left;">R. Feynman</td>
<td style="text-align: left;">978-0-465-02527-5</td>
</tr>
<tr class="even">
<td style="text-align: left;">Autmotive Handbook</td>
<td style="text-align: left;">Bosch</td>
<td style="text-align: left;">978-1-119-91190-6</td>
</tr>
<tr class="odd">
<td style="text-align: left;">Lumière et luminescence</td>
<td style="text-align: left;">B. Valeur</td>
<td style="text-align: left;">978-2-7011-3603-5</td>
</tr>
<tr class="even">
<td style="text-align: left;">Sciences et Vie - 389, Février 1950</td>
<td style="text-align: left;">-</td>
<td style="text-align: left;">-</td>
</tr>
<tr class="odd">
<td style="text-align: left;">Sciences et Vie - 391, Avril 1950</td>
<td style="text-align: left;">-</td>
<td style="text-align: left;">-</td>
</tr>
<tr class="even">
<td style="text-align: left;">Approche thermomécanique de la tribologie
à grande vitesse - Application au freinage</td>
<td style="text-align: left;">D. Méresse</td>
<td style="text-align: left;"><a
href="https://theses.hal.science/tel-00629413">tel-00629413</a></td>
</tr>
</tbody>
</table>
<h1 id="six-easy-pieces">Six Easy Pieces</h1>
<p>J’avais lu plusieurs livres de <a
href="https://en.wikipedia.org/wiki/Richard_Feynman#Popular_works">Richard
Feynman</a> l’an dernier, et je me suis dit que ça serait intéressant de
continuer.</p>
<p>Ici, ce n’est plus de la vulgarisation, mais des chapitres extraits
cours de sciences physiques destinés à des élèves en première et
deuxième année d’études en sciences physiques à <a
href="https://en.wikipedia.org/wiki/California_Institute_of_Technology">Caltech</a>.</p>
<figure>
<img src="/data/diy/books_2025/six_easy_pieces_feynman.png"
title="Six Easy Pieces" alt="Six Easy Pieces" />
<figcaption aria-hidden="true">Six Easy Pieces</figcaption>
</figure>
<p>À mon avis, il faut quelques bases en sciences pour comprendre les
explications, même si les calculs simplifiés et les schémas permettent
d’éviter les maths complexes en se limitant aux ordres de grandeurs. Les
sujets sont expliqués de façon simple, puis développés en systèmes
complexes avec une approche <em>bottom-up</em>.</p>
<p><a href="https://ejaadnama.substack.com/">Asif</a> m’avait aussi
conseillé le cours <em>Quantum Physics I</em> du MIT<a href="#fn1"
class="footnote-ref" id="fnref1" role="doc-noteref"><sup>1</sup></a>,
comme complément à ce livre, que je recommande à mon tour.</p>
<h1 id="automotive-handbook">Automotive Handbook</h1>
<p>J’ai souvent feuilleté ce livre que j’avais vu dans plusieurs
entreprises où j’ai travaillé, y-compris éloignées de l’automobile, et
que beaucoup de gens du domaine considèrent comme une <em>bible</em> de
la science et de l’ingéniérie appliquée à l’automobile.</p>
<p>Le livre commence par des définitions, principes et règles physiques
et mathématiques, puis continue avec de l’ingéniérie de base :
matériaux, usinage, accouplements. Ensuite, il est possible d’expliquer
la physique appliquée à un véhicule, puis toute l’ingéniérie embarquée
dans une voiture : châssis, transmission, types de moteurs, fluides,
dépollution, électrification, électronique embarquée, sécurité,
assistances.</p>
<figure>
<img src="/data/diy/books_2025/bosch_automotive_handbook.png"
title="Bosch Automotive Handbook" alt="Bosch Automotive Handbook" />
<figcaption aria-hidden="true">Bosch Automotive Handbook</figcaption>
</figure>
<p>C’est un livre destiné à n’importe quelle personne avec des besoins
précis ou généraux à propos d’ingéniérie, et qui n’est pas restreint à
l’automobile. Le livre est très complet et mérite sa réputation.</p>
<h1 id="lumière-et-luminescence">Lumière et Luminescence</h1>
<p>C’est un livre de vulgarisation scientifique dont le contenu est, à
mon avis, intéressant et présenté de façon intéressante.</p>
<p>Une caractéristique inhabituelle est que le sujet soit présentée de
plusieurs façons différentes pour attirer le lecteur en fonction de ses
intérêts. Par exemple, la lumière y est abordée par l’optique avec les
approches des particules et des rayonnements, mais aussi par la chimie,
la biologie, et aussi l’histoire des découvertes/inventions et les
langues.</p>
<figure>
<img src="/data/diy/books_2025/lumiere_et_luminescence_valeur.jpg"
title="Lumière et Luminescence" alt="Lumière et Luminescence" />
<figcaption aria-hidden="true">Lumière et Luminescence</figcaption>
</figure>
<p>Les explications sont assez claires avec des schémas en plus du texte
et ressemblent beaucoup à celles présentes dans les livres de sciences
physique des années 2000. Le fait que l’auteur soit à la fois chercheur
et impliqué dans l’enseignement n’est probablement pas un hasard.</p>
<p>À mon avis, les explications sont abordables avec un niveau de lycée,
vu que tout est expliqué de façon qualitative. Et si le lecteur a
quelques bases en sciences, il est possible de comprendre quelques
explications quantitatives dans des parties encadrées.</p>
<h1 id="sciences-et-vie">Sciences et Vie</h1>
<p>J’ai trouvé des magazines Sciences et Vie datant de 1950.</p>
<figure>
<img src="/data/diy/books_2025/science_et_vie_1950.jpg"
title="Science et Vie 1950" alt="Science et Vie 1950" />
<figcaption aria-hidden="true">Science et Vie 1950</figcaption>
</figure>
<p>C’est un magazine encore publié, et réputé pour vulgariser la science
et la technologie, avec des sujets souvent futuristes.</p>
<p>C’est l’occasion de voir comment certaines technologies futuristes
des années 50 ont vieilli. Beaucoup d’articles n’ont pas eu les
applications présentées, par exemple, l’énergie nucléaire nécessite des
contraintes de sécurité, et les éoliennes actuelles ont des
caractéristiques mécaniques et électriques totalement différentes des
suppositions de l’époque.</p>
<p>D’autres articles présentent des technologies expérimentales qui se
sont développées de la même façon qu’elles ont été présentées dans les
articles, plusieurs décennies après, comme les réacteurs d’avions
(post-combustion, injection d’eau/MW50, “high-bypass”).</p>
<p>Il reste des articles que j’ai trouvés remarquables :</p>
<h2 id="de-havillant-comet">De Havillant Comet</h2>
<p>Un article décrit l’avion <a
href="https://en.wikipedia.org/wiki/De_Havilland_Comet">De Havilland
Comet</a>, qui était le premier avion de passagers moderne, avec des
moteurs à réaction et une cabine pressurisée, sans différence majeure
avec les avions actuels. Une des caractéristiques remarquables
mentionnées dans l’article est la présence de grands hublots.</p>
<figure>
<img src="/data/diy/books_2025/science_et_vie_389_comet.jpg"
title="Science et Vie 389 : Comet" alt="Science et Vie 389 : Comet" />
<figcaption aria-hidden="true">Science et Vie 389 : Comet</figcaption>
</figure>
<p>Or plusieurs années après la publication du magazine, cet avion a
causé des dizaines d’accidents mortels dus à sa structure fragile<a
href="#fn2" class="footnote-ref" id="fnref2"
role="doc-noteref"><sup>2</sup></a> :</p>
<ul>
<li>Les larges hublots concentrent les efforts dans certaines zones de
la structure</li>
<li>L’alumimium utilisé pour la structure est sensible à la <a
href="https://en.wikipedia.org/wiki/Fatigue_(material)">fatigue</a></li>
<li>La cabine de l’avion étant pressurisée, une fissure peut déclencher
une décompression explosive et détruire l’avion en vol</li>
</ul>
<h2 id="photographie">Photographie</h2>
<p>L’article y présente plusieurs améliorations techniques concernant la
photographie :</p>
<ul>
<li>Photographie sous-marine : éclairage artificiel, papier/film/filtres
corrigeant l’absorption du spectre lumineux par l’eau, mise-au-point
affectée par l’indice de réfraction de l’eau, appareils photo résistants
à la pression</li>
<li>Lampes flash :
<ul>
<li>Lampes à décharge ou éclateurs à air</li>
<li>Plusieurs lampes synchronisées</li>
<li>Impulsion la plus puissante possible pour des expositions courtes
(30MW pendant 1us, soit 30J)</li>
<li>Possibilité de photographier une balle de pistolet à 300m/s</li>
</ul></li>
<li>Fluographie : ajout d’une poudre fluorescente à un objet éclairée
uniquement par de la lumière UV, pour en photographier son relief, et
potentiellement le superposer à une photo en couleur</li>
<li>Photographie monochrome : permet d’utiliser du papier et du film
plus simple, sans distortion, et d’utiliser un éclairage puissant et
efficace sans être dérangé par leur mauvais rendu de couleurs</li>
<li>Améliorations de la partie optique des appareils photo :
<ul>
<li>Verres à l’épaisseur et au stigmatisme contrôlés par
interférences</li>
<li>Précision de mesure de l’ordre de 1um, précision d’assemblage de
l’ordre de 10um</li>
<li>Ajout d’un télémètre à mire pour ajuster la mise-au-point, l’ancêtre
de l’autofocus</li>
</ul></li>
</ul>
<figure>
<img src="/data/diy/books_2025/science_et_vie_391_photographie.jpg"
title="Science et Vie 391 : Photographie"
alt="Science et Vie 391 : Photographie" />
<figcaption aria-hidden="true">Science et Vie 391 :
Photographie</figcaption>
</figure>
<p>Les systèmes actuels à capteurs numériques sont différents, mais
partagent des contraintes : lentilles précises, surface photosensible,
compromis éclairage/durée-d’exposition/sensibilité, zoom, mise-au-point
précise. Il est aussi intéressant de voir que des systèmes similaires
servent à la lithographie de circuits intégrés.</p>
<h1
id="approche-thermomécanique-de-la-tribologie-à-grande-vitesse---application-au-freinage">Approche
thermomécanique de la tribologie à grande vitesse - Application au
freinage</h1>
<p>Je me suis longtemps posé des questions sur le rodage des freins à
disques de vélo et de voiture.</p>
<p>L’approche qualitative est simple : il faut que le disque et les
plaquettes se <em>pré-usent</em> pour que chaque objet prenne la forme
de l’autre, pour que toute la surface de la plaquette soit en friction
sur le disque. Mais on entend aussi parler de procédures de rodage plus
complexes, incluant notamment des cycles thermiques.</p>
<p>Ces procédures de rodage fonctionnent mais manquent d’explications :
comment est-ce que ça fonctionne et pourquoi un rodage relativement
complexe est-il nécessaire ?</p>
<p>La thèse présente différentes explications :</p>
<ul>
<li>Modélisations des différents éléments de freinage</li>
<li>Approche tribologique :
<ul>
<li>Friction</li>
<li>Adhésion</li>
<li>Dépôts de matière des plaquettes vers le disque, permettant
l’adhésion</li>
</ul></li>
<li>Approche thermique :
<ul>
<li>Rayonnement</li>
<li>Transferts thermique dans la matière et sur la surface de
contact</li>
<li>Points-chauds</li>
</ul></li>
<li>Approche combinée :
<ul>
<li>Coefficient de frottement dépendant de la température, et aussi
légèrement de la pression</li>
<li>Usure croissante avec la température</li>
<li>Validation du comportement de différents matériaux de frictions</li>
<li>Caractérisation de matériaux de friction</li>
</ul></li>
</ul>
<figure>
<img src="/data/diy/books_2025/tribologie_freinage_meresse.png"
title="Tribologie appliquée au freinage"
alt="Tribologie appliquée au freinage" />
<figcaption aria-hidden="true">Tribologie appliquée au
freinage</figcaption>
</figure>
<p>La thèse permet de comprendre la procédure de rodage :</p>
<ol type="1">
<li>Usure abrasive à vitesse réduite et faible température :
<ul>
<li>Usure de la couche d’oxyde/peinture du disque</li>
<li>Usure de la surface des plaquettes à la forme de la surface du
disque, pour éviter l’apparition de points-chauds plus tard</li>
</ul></li>
<li>Usure et adhésion avec des cycles thermiques progressifs, à vitesse
plus élevée et sans arrêt complet :
<ul>
<li>Fin progressive de la pré-usure</li>
<li>Mise-en-place des plaquettes à chaud</li>
<li>Transfert de matériau de friction des plaquettes vers le disque</li>
<li>Refroidissement progressif, évitant de déformer le disque et de
coller les plaquettes</li>
</ul></li>
</ol>
<p>Elle permet aussi de comprendre ce qu’il ne faut pas faire en
utilisation normale :</p>
<ul>
<li>Une température trop élevée lorsque le rodage est incomplet
<em>glace</em> les plaquettes par l’apparition de points-chauds</li>
<li>Un rodage partiel empêche le transfert de matériau de friction, et
rend les freins peu efficaces</li>
<li>Une température de fonctionnement trop élevée dégrade le coefficient
de friction mais use extrémement vite les matériaux organiques, et peut
les dégrader de façon irréversible</li>
<li>Un refroidissement non-uniforme déforme les matériaux et peut
éventuellement les fissurer</li>
</ul>
<section class="footnotes footnotes-end-of-document"
role="doc-endnotes">
<hr />
<ol>
<li id="fn1" role="doc-endnote"><p><a
href="https://ocw.mit.edu/courses/8-04-quantum-physics-i-spring-2013/">Quantum
Physics I | Physics | MIT OpenCourseWare</a> Les notes et videos de
cours valent le coup d’oeil<a href="#fnref1" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
<li id="fn2" role="doc-endnote"><p><a
href="https://www.faa.gov/lessons_learned/transport_airplane/accidents/G-ALYV">De
Havilland DH-106 Comet 1 - FAA</a> et en particulier le <a
href="https://www.faa.gov/sites/faa.gov/files/2022-10/G-ALYR_Report_0.pdf">rapport
de test de structure</a> expliquent les contraintes sur la structure et
les causes des fissures entraînant la destruction de l’avion<a
href="#fnref2" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
</ol>
</section>
]]>
		</summary>
	</entry>

	<entry>
		<title>Philips AD906WA Wireless receiver</title>
		<link href="/cms/2025-11-18-philips-ad906wa-wireless-receiver.html" />
		<updated>2025-11-18T08:00:00+00:00</updated>
		<id>https://monorailc.atoutput/cms/2025-11-18-philips-ad906wa-wireless-receiver.html</id>
		<summary type="html"><![CDATA[<h1 id="overview">Overview</h1>
<p>This AD906WA/01 wireless receiver came with a LX3950W/01 <em>home
theater</em> system and was paired to an AD906WT/01 transmitter<a
href="#fn1" class="footnote-ref" id="fnref1"
role="doc-noteref"><sup>1</sup></a>.</p>
<figure>
<img src="/data/diy/philips_wireless/ad906wa_overview.jpg"
title="Philips AD906WA" alt="Philips AD906WA" />
<figcaption aria-hidden="true">Philips AD906WA</figcaption>
</figure>
<p>Around the mid-2000s, wireless transmitters were offered for <em>home
theater</em> systems, as a way to connect the rear speakers without long
cables going across a room<a href="#fn2" class="footnote-ref"
id="fnref2" role="doc-noteref"><sup>2</sup></a>.</p>
<p>The wireless transmitter was connected to a specific output on the
audio player or amplifier, and it was paired to a matching wireless
receiver + amplifier that could power two speakers.</p>
<figure>
<img src="/data/diy/philips_wireless/lx3950w_setup.png"
title="Philips LX3950 setup" alt="Philips LX3950 setup" />
<figcaption aria-hidden="true">Philips LX3950 setup</figcaption>
</figure>
<p>PCB markings are included for SEO, in case someone else might find
this while playing with their Philips wireless systems.</p>
<h1 id="inside-view">Inside view</h1>
<figure>
<img src="/data/diy/philips_wireless/ad906wa_teardown.jpg"
title="Philips AD906WA teardown" alt="Philips AD906WA teardown" />
<figcaption aria-hidden="true">Philips AD906WA teardown</figcaption>
</figure>
<p>There are 3 PCBs :</p>
<ul>
<li>Switching PSU</li>
<li>Power amplifier</li>
<li>RF receiver</li>
</ul>
<h1 id="psu">PSU</h1>
<p>This is a 150mm*75mm, single-layer PCB. It looks like there are 2
<em>flyback</em> supplies, one with a small transformer, likely for a
low-power output, and one with a larger transformer and two outputs,
likely for the power amplifier.</p>
<p>Interestingly, there’s no monolithic IC. The control-side only has
semiconductors in SOT-23 package.</p>
<figure>
<img src="/data/diy/philips_wireless/ad906wa_psu.jpg" title="PSU board"
alt="PSU board" />
<figcaption aria-hidden="true">PSU board</figcaption>
</figure>
<h2 id="specifications">Specifications</h2>
<p>The sticker specifies the following data:</p>
<ul>
<li>Model: AC6121</li>
<li>Input 100~240V 50-60Hz 0.34A</li>
<li>Output:
<ul>
<li>+29.5V/0.16A</li>
<li>-29.5V/0.16A</li>
<li>10V/0.2A</li>
</ul></li>
</ul>
<h2 id="connectors">Connectors</h2>
<p>There are 3 connectors on the PCB:</p>
<ul>
<li>J1: AC input, unearthed</li>
<li>J2: Power output</li>
<li>J3: Standby output</li>
</ul>
<h3 id="j2-pinout">J2 pinout</h3>
<table>
<thead>
<tr class="header">
<th style="text-align: center;">Pin</th>
<th style="text-align: center;">Wire color</th>
<th style="text-align: center;">Signal</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td style="text-align: center;">J2.1</td>
<td style="text-align: center;">Yellow</td>
<td style="text-align: center;">-29.5V</td>
</tr>
<tr class="even">
<td style="text-align: center;">J2.2</td>
<td style="text-align: center;">Black</td>
<td style="text-align: center;">GND</td>
</tr>
<tr class="odd">
<td style="text-align: center;">J2.3</td>
<td style="text-align: center;">Black</td>
<td style="text-align: center;">GND</td>
</tr>
<tr class="even">
<td style="text-align: center;">J2.4</td>
<td style="text-align: center;">Red</td>
<td style="text-align: center;">+29.5V</td>
</tr>
</tbody>
</table>
<h3 id="j3-pinout">J3 pinout</h3>
<table>
<thead>
<tr class="header">
<th style="text-align: center;">Pin</th>
<th style="text-align: center;">Wire color</th>
<th style="text-align: center;">Signal</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td style="text-align: center;">J3.1</td>
<td style="text-align: center;">Yellow</td>
<td style="text-align: center;">PG?</td>
</tr>
<tr class="even">
<td style="text-align: center;">J3.2</td>
<td style="text-align: center;">Black</td>
<td style="text-align: center;">GND</td>
</tr>
<tr class="odd">
<td style="text-align: center;">J3.3</td>
<td style="text-align: center;">Red</td>
<td style="text-align: center;">10.0V</td>
</tr>
</tbody>
</table>
<p>The signal on the pin 1 seems to act as a <em>power good</em> signal.
This would need to be confirmed.</p>
<h2 id="pcb-markings">PCB markings</h2>
<ul>
<li>Sticker:
<ul>
<li>AC6121</li>
<li>P42859578</li>
</ul></li>
<li>Top side:
<ul>
<li>TF-03</li>
<li>94V0 UL</li>
<li>SIDE A</li>
<li>855D-016K</li>
<li>PI ELECTRONICS</li>
</ul></li>
<li>Bottom side:
<ul>
<li>SIDEB</li>
<li>U.S. PAT 5,986,905</li>
</ul></li>
</ul>
<h1 id="amplifier">Amplifier</h1>
<p>This is a 100mm*90mm, dual-layer PCB with a heatsink.</p>
<figure>
<img src="/data/diy/philips_wireless/ad906wa_amp.jpg" title="Amplifier"
alt="Amplifier" />
<figcaption aria-hidden="true">Amplifier</figcaption>
</figure>
<h2 id="connectors-1">Connectors</h2>
<h3 id="pinout">1100 pinout</h3>
<ol type="1">
<li>Power output L</li>
<li>GND</li>
<li>GND</li>
<li>Power output R</li>
</ol>
<h3 id="pinout-1">1104 pinout</h3>
<p><strong>Warning</strong> the markings are reversed compared to the
PSU.</p>
<ol type="1">
<li>+29.5V</li>
<li>GND</li>
<li>GND</li>
<li>-29.5V</li>
</ol>
<h3 id="pinout-2">1106 pinout</h3>
<ol type="1">
<li>Audio input R</li>
<li>GND</li>
<li>Audio input L</li>
<li>10V output</li>
<li>GND</li>
<li>?</li>
<li>Red LED input</li>
</ol>
<h3 id="pinout-3">1107 pinout</h3>
<ol type="1">
<li>10V input</li>
<li>GND</li>
<li>PG input?</li>
</ol>
<h2 id="bom-identification">BOM identification</h2>
<table>
<thead>
<tr class="header">
<th style="text-align: center;">Item</th>
<th style="text-align: center;">Type</th>
<th style="text-align: center;">Manufacturer, PN</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td style="text-align: center;">7100</td>
<td style="text-align: center;">Quad opamp</td>
<td style="text-align: center;">Natsemi LM837<a href="#fn3"
class="footnote-ref" id="fnref3"
role="doc-noteref"><sup>3</sup></a></td>
</tr>
<tr class="even">
<td style="text-align: center;">7101</td>
<td style="text-align: center;">Dual power amplifier</td>
<td style="text-align: center;">Philips TDA8920TH<a href="#fn4"
class="footnote-ref" id="fnref4"
role="doc-noteref"><sup>4</sup></a></td>
</tr>
</tbody>
</table>
<h2 id="leds">LEDs</h2>
<ul>
<li>6109: Green, Power-on</li>
<li>6110: Red, receiver paired</li>
</ul>
<h2 id="pcb-markings-1">PCB markings</h2>
<ul>
<li>Top side:
<ul>
<li>PS 2002</li>
<li>94V-0 UL (PCB substrate flammability rating)</li>
<li>2004 (datecode)</li>
</ul></li>
<li>Bottom side:
<ul>
<li>3104 123 4365. 2</li>
</ul></li>
</ul>
<h1 id="receiver-board">Receiver Board</h1>
<p>This is a 90mm*68mm, 4-layer PCB that has one JST connector, one
antenna, one RF ASIC in a metal shield, one opamps, one MCU, two analog
ASICs, and one unknown chip.</p>
<figure>
<img src="/data/diy/philips_wireless/ad906wa_receiver_top.jpg"
title="Receiver board" alt="Receiver board" />
<figcaption aria-hidden="true">Receiver board</figcaption>
</figure>
<figure>
<img src="/data/diy/philips_wireless/ad906wa_receiver_bottom.jpg"
title="Receiver board" alt="Receiver board" />
<figcaption aria-hidden="true">Receiver board</figcaption>
</figure>
<h2 id="connector-pinout">1790 connector pinout</h2>
<ol type="1">
<li>Audio output R</li>
<li>GND</li>
<li>Audio output L</li>
<li>10V input</li>
<li>GND</li>
<li>? (3V when powered-on)</li>
<li>Red LED output</li>
</ol>
<h2 id="bom-identification-1">BOM identification</h2>
<table>
<colgroup>
<col style="width: 25%" />
<col style="width: 25%" />
<col style="width: 25%" />
<col style="width: 25%" />
</colgroup>
<thead>
<tr class="header">
<th style="text-align: center;">Item</th>
<th style="text-align: center;">Type</th>
<th style="text-align: center;">Manufacturer, PN</th>
<th style="text-align: center;">Note</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td style="text-align: center;">7710</td>
<td style="text-align: center;">PLL, IF demuxer</td>
<td style="text-align: center;">Sanyo LA1836<a href="#fn5"
class="footnote-ref" id="fnref5"
role="doc-noteref"><sup>5</sup></a></td>
<td style="text-align: center;"></td>
</tr>
<tr class="even">
<td style="text-align: center;">7750</td>
<td style="text-align: center;">8-bit MCU</td>
<td style="text-align: center;">PIC12C508<a href="#fn6"
class="footnote-ref" id="fnref6"
role="doc-noteref"><sup>6</sup></a></td>
<td style="text-align: center;"></td>
</tr>
<tr class="odd">
<td style="text-align: center;">?</td>
<td style="text-align: center;">I²C-programmable PLL</td>
<td style="text-align: center;">NXP TSA5060ATS<a href="#fn7"
class="footnote-ref" id="fnref7"
role="doc-noteref"><sup>7</sup></a></td>
<td style="text-align: center;">4MHz crystal</td>
</tr>
<tr class="even">
<td style="text-align: center;">7770</td>
<td style="text-align: center;">Audio decompressor, AGC</td>
<td style="text-align: center;">Onsemi SA572D<a href="#fn8"
class="footnote-ref" id="fnref8"
role="doc-noteref"><sup>8</sup></a></td>
<td style="text-align: center;"></td>
</tr>
<tr class="odd">
<td style="text-align: center;">7780</td>
<td style="text-align: center;">Dual opamp</td>
<td style="text-align: center;">JRC 4065<a href="#fn9"
class="footnote-ref" id="fnref9"
role="doc-noteref"><sup>9</sup></a></td>
<td style="text-align: center;"></td>
</tr>
<tr class="even">
<td style="text-align: center;">7790</td>
<td style="text-align: center;">Unreadable</td>
<td style="text-align: center;">ST ??C80</td>
<td style="text-align: center;"></td>
</tr>
</tbody>
</table>
<h2 id="pcb-markings-2">PCB markings</h2>
<ul>
<li>Sticker:
<ul>
<li>864MHz</li>
<li>07520</li>
<li>SV0430</li>
<li>04091554</li>
</ul></li>
<li>Top side:
<ul>
<li>3522 2</li>
<li>2002-12-09</li>
<li>2</li>
</ul></li>
<li>Bottom side:
<ul>
<li>94V-0 UL, PCB substrate flammability rating</li>
<li>ELEC-5</li>
<li>E3330BM</li>
</ul></li>
</ul>
<h1 id="usability">Usability</h1>
<p>The transmitter isn’t designed to operate without its Philips
<em>LX3950W/01</em><a href="#fn10" class="footnote-ref" id="fnref10"
role="doc-noteref"><sup>10</sup></a>, which I don’t have, so using the
receiver as intended looks compromised.</p>
<p>However, the amplifier works without the RF part, by connecting
analog audio signals on the connector 1106: L-R signals on pins 1 and 3,
and GND on pin 2.</p>
<p>Funnily, the specsheet gives the “Output power (RMS): 5 x 45 W”<a
href="#fn11" class="footnote-ref" id="fnref11"
role="doc-noteref"><sup>11</sup></a> and the amplifier’s datasheed
specifies a maximum power of 70W for each channel, when the receiver can
only draw 25W from the power outlet and its PSU delivers 9.44W on its
+/- 29.5V rails. That looks questionable.</p>
<p>This is a Class D amplifier, which explains why there’s a low-pass
filter on the output, and why the heatsink is rather small for the
advertised power.</p>
<h1 id="references">References</h1>
<section class="footnotes footnotes-end-of-document"
role="doc-endnotes">
<hr />
<ol>
<li id="fn1" role="doc-endnote"><p><a
href="https://www.documents.philips.com/assets/20231209/603c01e7ed88455b9ad7b0d3004b54fd.pdf">Philips
LX3950W/01 specsheet</a><a href="#fnref1" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
<li id="fn2" role="doc-endnote"><p><a
href="https://www.documents.philips.com/assets/20231117/401b26d526bf4370a38ab0bd00c877d9.pdf">Philips
LX3950W/01 manual</a><a href="#fnref2" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
<li id="fn3" role="doc-endnote"><p><a
href="https://www.ti.com/lit/ds/symlink/lm837.pdf">National
Semiconductor LM837 datasheet</a><a href="#fnref3" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
<li id="fn4" role="doc-endnote"><p><a
href="https://www.nxp.com/docs/en/data-sheet/TDA8920B.pdf">TDA8920B
datasheet</a><a href="#fnref4" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
<li id="fn5" role="doc-endnote"><p><a
href="https://www.alldatasheet.com/datasheet-pdf/download/40006/SANYO/LA1836.html">Sanyo
LA1836 datasheet</a><a href="#fnref5" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
<li id="fn6" role="doc-endnote"><p><a
href="https://ww1.microchip.com/downloads/en/DeviceDoc/41236E.pdf">Microchip
PIC12C508 datasheet</a><a href="#fnref6" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
<li id="fn7" role="doc-endnote"><p><a
href="https://www.alldatasheet.com/datasheet-pdf/download/19769/PHILIPS/TSA5060ATS.html">NXP
TSA5060ATS datasheet</a><a href="#fnref7" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
<li id="fn8" role="doc-endnote"><p><a
href="https://www.alldatasheet.com/datasheet-pdf/download/105866/PHILIPS/SA572D.html">NXP
SA572D datasheet</a><a href="#fnref8" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
<li id="fn9" role="doc-endnote"><p><a
href="https://www.mouser.com/datasheet/2/294/NJM4565_E-1917662.pdf">JRC
4565 datasheet</a><a href="#fnref9" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
<li id="fn10" role="doc-endnote"><p><a
href="https://www.documents.philips.com/assets/20231117/401b26d526bf4370a38ab0bd00c877d9.pdf">Philips
LX3950W/01 manual</a><a href="#fnref10" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
<li id="fn11" role="doc-endnote"><p><a
href="https://www.documents.philips.com/assets/20231209/603c01e7ed88455b9ad7b0d3004b54fd.pdf">Philips
LX3950W/01 specsheet</a><a href="#fnref11" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
</ol>
</section>
]]>
		</summary>
	</entry>

	<entry>
		<title>Philips AD906WT Wireless transmitter</title>
		<link href="/cms/2025-11-17-philips-ad906wt-wireless-transmitter.html" />
		<updated>2025-11-17T19:00:00+00:00</updated>
		<id>https://monorailc.atoutput/cms/2025-11-17-philips-ad906wt-wireless-transmitter.html</id>
		<summary type="html"><![CDATA[<h1 id="overview">Overview</h1>
<p>This AD906WT/01 wireless transmitter came with a LX3950W/01 <em>home
theater</em> system and was paired to an AD906WA/01 receiver<a
href="#fn1" class="footnote-ref" id="fnref1"
role="doc-noteref"><sup>1</sup></a>.</p>
<figure>
<img src="/data/diy/philips_wireless/ad906wt_overview.jpg"
title="Philips AD906WT" alt="Philips AD906WT" />
<figcaption aria-hidden="true">Philips AD906WT</figcaption>
</figure>
<p>Around the mid-2000s, wireless transmitters were offered for <em>home
theater</em> systems, as a way to connect the rear speakers without long
cables going across a room<a href="#fn2" class="footnote-ref"
id="fnref2" role="doc-noteref"><sup>2</sup></a>.</p>
<p>The wireless transmitter was connected to a specific output on the
audio player or amplifier, and it was paired to a matching wireless
receiver + amplifier that could power two speakers.</p>
<figure>
<img src="/data/diy/philips_wireless/lx3950w_setup.png"
title="Philips LX3950 setup" alt="Philips LX3950 setup" />
<figcaption aria-hidden="true">Philips LX3950 setup</figcaption>
</figure>
<p>PCB markings are included for SEO, in case someone else might find
this while playing with their Philips wireless systems.</p>
<h1 id="inside-view">Inside view</h1>
<p>This looks like analog RF, pre-dating digital protocols. Stickers
specifies that the transmitter operates at 864MHz.</p>
<figure>
<img src="/data/diy/philips_wireless/ad906wt_teardown.jpg"
title="Philips AD906WT teardown" alt="Philips AD906WT teardown" />
<figcaption aria-hidden="true">Philips AD906WT teardown</figcaption>
</figure>
<p>There are 2 PCBs, a complex one connected to the antenna, and a
simpler one that seems to be here for interconnection with the RJ45
cable.</p>
<h1 id="interface-board">Interface board</h1>
<p>This is a 95mm*35mm, dual layer PCB that has 4 JST connectors, and
only a few analog components around an dual opamp. Many components are
unpopulated.</p>
<figure>
<img src="/data/diy/philips_wireless/ad906wt_interface_board.jpg"
title="Interface board" alt="Interface board" />
<figcaption aria-hidden="true">Interface board</figcaption>
</figure>
<h2 id="bom-identification">BOM Identification</h2>
<table>
<thead>
<tr class="header">
<th style="text-align: center;">Item</th>
<th style="text-align: center;">Type</th>
<th style="text-align: center;">Manufacturer, PN</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td style="text-align: center;">7115</td>
<td style="text-align: center;">Dual opamp</td>
<td style="text-align: center;">JRC 4560<a href="#fn3"
class="footnote-ref" id="fnref3"
role="doc-noteref"><sup>3</sup></a></td>
</tr>
<tr class="even">
<td style="text-align: center;">1100</td>
<td style="text-align: center;">Connector</td>
<td style="text-align: center;">JST, 2-pin</td>
</tr>
<tr class="odd">
<td style="text-align: center;">1130</td>
<td style="text-align: center;">Connector</td>
<td style="text-align: center;">JST, 4-pin</td>
</tr>
<tr class="even">
<td style="text-align: center;">1120</td>
<td style="text-align: center;">Connector</td>
<td style="text-align: center;">JST, 8-pin</td>
</tr>
<tr class="odd">
<td style="text-align: center;">1121</td>
<td style="text-align: center;">Connector</td>
<td style="text-align: center;">JST, 2-pin</td>
</tr>
</tbody>
</table>
<h2 id="connectors-pinouts">Connectors pinouts</h2>
<h3 id="pinout">1100 pinout</h3>
<ol type="1">
<li>+12V input</li>
<li>GND</li>
</ol>
<h3 id="pinout-1">1110 pinout</h3>
<ol type="1">
<li>ACH1</li>
<li>AGND1</li>
<li>ACH2</li>
<li>AGND2</li>
</ol>
<h3 id="pinout-2">1120 pinout</h3>
<ol type="1">
<li>ACH1</li>
<li>GND</li>
<li>ACH2</li>
<li>+12V output</li>
<li>GND</li>
<li>GND</li>
<li>SCL</li>
<li>SDA</li>
</ol>
<h3 id="pinout-3">1121 pinout</h3>
<ol type="1">
<li>SCL</li>
<li>SDA</li>
</ol>
<h2 id="testpoints">Testpoints</h2>
<table>
<thead>
<tr class="header">
<th style="text-align: center;">TP</th>
<th style="text-align: center;">Signal</th>
<th style="text-align: center;">Connection</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td style="text-align: center;">F001</td>
<td style="text-align: center;">+12V</td>
<td style="text-align: center;">1100.1</td>
</tr>
<tr class="even">
<td style="text-align: center;">F002</td>
<td style="text-align: center;">GND</td>
<td style="text-align: center;">1100.2</td>
</tr>
<tr class="odd">
<td style="text-align: center;">F003</td>
<td style="text-align: center;">AGND2</td>
<td style="text-align: center;">1130.4</td>
</tr>
<tr class="even">
<td style="text-align: center;">F004</td>
<td style="text-align: center;">ACH2</td>
<td style="text-align: center;">1130.3</td>
</tr>
<tr class="odd">
<td style="text-align: center;">F005</td>
<td style="text-align: center;">AGND1</td>
<td style="text-align: center;">1130.2</td>
</tr>
<tr class="even">
<td style="text-align: center;">F006</td>
<td style="text-align: center;">ACH1</td>
<td style="text-align: center;">1130.1</td>
</tr>
<tr class="odd">
<td style="text-align: center;">F007</td>
<td style="text-align: center;">?</td>
<td style="text-align: center;">Unpopulated</td>
</tr>
<tr class="even">
<td style="text-align: center;">F008</td>
<td style="text-align: center;">?</td>
<td style="text-align: center;">Unpopulated</td>
</tr>
<tr class="odd">
<td style="text-align: center;">F009</td>
<td style="text-align: center;">ACH2</td>
<td style="text-align: center;">7115.7 -&gt; Opamp output</td>
</tr>
<tr class="even">
<td style="text-align: center;">F010</td>
<td style="text-align: center;">ACH1</td>
<td style="text-align: center;">7115.1 -&gt; Opamp output</td>
</tr>
<tr class="odd">
<td style="text-align: center;">F011</td>
<td style="text-align: center;">ACH1</td>
<td style="text-align: center;">1120.1 -&gt; inductors output</td>
</tr>
<tr class="even">
<td style="text-align: center;">F012</td>
<td style="text-align: center;">ACH2</td>
<td style="text-align: center;">1120.3 -&gt; inductors output</td>
</tr>
<tr class="odd">
<td style="text-align: center;">F013</td>
<td style="text-align: center;">GND</td>
<td style="text-align: center;">1120.2</td>
</tr>
<tr class="even">
<td style="text-align: center;">F014</td>
<td style="text-align: center;">+12V</td>
<td style="text-align: center;">1120.4</td>
</tr>
<tr class="odd">
<td style="text-align: center;">F015</td>
<td style="text-align: center;">NC</td>
<td style="text-align: center;">Unpopulated area</td>
</tr>
<tr class="even">
<td style="text-align: center;">F016</td>
<td style="text-align: center;">NC</td>
<td style="text-align: center;">1130, unpopulated</td>
</tr>
<tr class="odd">
<td style="text-align: center;">F017</td>
<td style="text-align: center;">NC</td>
<td style="text-align: center;">1130, unpopulated</td>
</tr>
<tr class="even">
<td style="text-align: center;">F018</td>
<td style="text-align: center;">NC</td>
<td style="text-align: center;">Unpopulated area</td>
</tr>
<tr class="odd">
<td style="text-align: center;">F019</td>
<td style="text-align: center;">NC</td>
<td style="text-align: center;">Unpopulated area</td>
</tr>
<tr class="even">
<td style="text-align: center;">F020</td>
<td style="text-align: center;">NC</td>
<td style="text-align: center;">Unpopulated area</td>
</tr>
<tr class="odd">
<td style="text-align: center;">F021</td>
<td style="text-align: center;">NC</td>
<td style="text-align: center;">Unpopulated area</td>
</tr>
<tr class="even">
<td style="text-align: center;">F021</td>
<td style="text-align: center;">NC</td>
<td style="text-align: center;">Unpopulated area</td>
</tr>
</tbody>
</table>
<h2 id="board-overview">Board overview</h2>
<ul>
<li>ACH1: 1130.1 -&gt; filters -&gt; Opamp -&gt; filters -&gt;
1120.1</li>
<li>ACH2: 1130.3 -&gt; filters -&gt; Opamp -&gt; filters -&gt;
1120.3</li>
</ul>
<p>All other signals are directly connected from the RJ45 to the 1120
connector. It looks like this board was intended to be used in similar
standalone products, looking at the unpopulated components that include
footprints for a power jack, a switch and RCA inputs.</p>
<p>There’s an unusual amount of filters, including signal transformers.
This rather simple board seems to have been designed with EMC
considerations.</p>
<h2 id="pcb-markings">PCB markings</h2>
<p>Bottom side:</p>
<ul>
<li>3104 133 3001.2</li>
<li>3104 137 3003.1</li>
<li>3104 137 3004.1</li>
<li>3104 137 3010.1</li>
<li>2104 (datecode)</li>
<li>1 94V-0 UL (PCB substrate flammability rating)</li>
</ul>
<h1 id="transmitter-board">Transmitter board</h1>
<p>This is a 80mm*65mm, 4-layer PCB that has one JST connector, one
antenna, one RF ASIC in a metal shield, 2 opamps, one analog ASIC, one
analog multiplexer and one clock generator.</p>
<p>All components seem to be populated.</p>
<figure>
<img src="/data/diy/philips_wireless/ad906wt_transmitter_top.jpg"
title="Transmitter board" alt="Transmitter board" />
<figcaption aria-hidden="true">Transmitter board</figcaption>
</figure>
<figure>
<img src="/data/diy/philips_wireless/ad906wt_transmitter_bottom.jpg"
title="Transmitter board" alt="Transmitter board" />
<figcaption aria-hidden="true">Transmitter board</figcaption>
</figure>
<h2 id="bom-identification-1">BOM Identification</h2>
<table>
<colgroup>
<col style="width: 25%" />
<col style="width: 25%" />
<col style="width: 25%" />
<col style="width: 25%" />
</colgroup>
<thead>
<tr class="header">
<th style="text-align: center;">Item</th>
<th style="text-align: center;">Type</th>
<th style="text-align: center;">Manufacturer, PN</th>
<th style="text-align: center;">Note</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td style="text-align: center;">7101</td>
<td style="text-align: center;">I²C-programmable PLL</td>
<td style="text-align: center;">NXP TSA5060ATS<a href="#fn4"
class="footnote-ref" id="fnref4"
role="doc-noteref"><sup>4</sup></a></td>
<td style="text-align: center;">4MHz crystal</td>
</tr>
<tr class="even">
<td style="text-align: center;">7110</td>
<td style="text-align: center;">Oscillator and divider</td>
<td style="text-align: center;">NXP 74HC4060D<a href="#fn5"
class="footnote-ref" id="fnref5"
role="doc-noteref"><sup>5</sup></a></td>
<td style="text-align: center;">12MHz crystal</td>
</tr>
<tr class="odd">
<td style="text-align: center;">7111</td>
<td style="text-align: center;">8-channel analog switch</td>
<td style="text-align: center;">NXP 74HC4053D<a href="#fn6"
class="footnote-ref" id="fnref6"
role="doc-noteref"><sup>6</sup></a></td>
<td style="text-align: center;"></td>
</tr>
<tr class="even">
<td style="text-align: center;">7112</td>
<td style="text-align: center;">Audio compressor, AGC</td>
<td style="text-align: center;">Onsemi SA572D<a href="#fn7"
class="footnote-ref" id="fnref7"
role="doc-noteref"><sup>7</sup></a></td>
<td style="text-align: center;"></td>
</tr>
<tr class="odd">
<td style="text-align: center;">7113</td>
<td style="text-align: center;">Dual opamp</td>
<td style="text-align: center;">JRC 4065<a href="#fn8"
class="footnote-ref" id="fnref8"
role="doc-noteref"><sup>8</sup></a></td>
<td style="text-align: center;"></td>
</tr>
<tr class="even">
<td style="text-align: center;">7116</td>
<td style="text-align: center;">Dual opamp</td>
<td style="text-align: center;">JRC 4065<a href="#fn9"
class="footnote-ref" id="fnref9"
role="doc-noteref"><sup>9</sup></a></td>
<td style="text-align: center;"></td>
</tr>
<tr class="odd">
<td style="text-align: center;">7117</td>
<td style="text-align: center;">LDO voltage regulator</td>
<td style="text-align: center;">ST L1117</td>
<td style="text-align: center;"></td>
</tr>
</tbody>
</table>
<h2 id="connector-pinout">1101 connector pinout</h2>
<ol type="1">
<li>ACH1</li>
<li>GND</li>
<li>ACH2</li>
<li>+12V input</li>
<li>GND</li>
<li>GND</li>
<li>SCL</li>
<li>SDA</li>
</ol>
<h2 id="pcb-markings-1">PCB markings</h2>
<ul>
<li>Sticker:
<ul>
<li>864MHz</li>
<li>07890</li>
<li>SV0429</li>
<li>04087553</li>
</ul></li>
<li>Top side:
<ul>
<li>PHILIPS</li>
<li>2003-01-17</li>
<li>3521 4</li>
<li>Transmitter</li>
<li>Closed side</li>
<li>6</li>
<li>3104 213 3521.4</li>
</ul></li>
<li>Bottom side:
<ul>
<li>94V-0 UL (PCB substrate flammability rating)</li>
<li>ELEC-5</li>
<li>E3330E</li>
<li>3104 217-07110-07120-07130</li>
<li>3104 217-07210-07220-07230</li>
<li>Philips</li>
</ul></li>
</ul>
<h1 id="rj45-cable">RJ45 Cable</h1>
<ol type="1">
<li>ACH2</li>
<li>AGND</li>
<li>ACH1</li>
<li>+12V</li>
<li>GND</li>
<li>GND-shield</li>
<li>SCL</li>
<li>SDA</li>
</ol>
<h1 id="conclusion">Conclusion</h1>
<p>This doesn’t seem to be usable without its original equipment or
without deeper reverse-engineering, due to the fact the PLL needs I²C
data to operate.</p>
<h1 id="references">References</h1>
<section class="footnotes footnotes-end-of-document"
role="doc-endnotes">
<hr />
<ol>
<li id="fn1" role="doc-endnote"><p><a
href="https://www.documents.philips.com/assets/20231209/603c01e7ed88455b9ad7b0d3004b54fd.pdf">Philips
LX3950W/01 specsheet</a><a href="#fnref1" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
<li id="fn2" role="doc-endnote"><p><a
href="https://www.documents.philips.com/assets/20231117/401b26d526bf4370a38ab0bd00c877d9.pdf">Philips
LX3950W/01 manual</a><a href="#fnref2" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
<li id="fn3" role="doc-endnote"><p><a
href="https://www.mouser.com/datasheet/2/294/NJM4565_E-1917662.pdf">JRC
4565 datasheet</a><a href="#fnref3" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
<li id="fn4" role="doc-endnote"><p><a
href="https://www.alldatasheet.com/datasheet-pdf/download/19769/PHILIPS/TSA5060ATS.html">NXP
TSA5060ATS datasheet</a><a href="#fnref4" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
<li id="fn5" role="doc-endnote"><p><a
href="https://assets.nexperia.com/documents/data-sheet/74HC_HCT4060.pdf">Generic
CMOS 4060 datasheet</a><a href="#fnref5" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
<li id="fn6" role="doc-endnote"><p><a
href="https://assets.nexperia.com/documents/data-sheet/74HC_HCT4053.pdf">Generic
CMOS 4053 datasheet</a><a href="#fnref6" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
<li id="fn7" role="doc-endnote"><p><a
href="https://www.alldatasheet.com/datasheet-pdf/download/105866/PHILIPS/SA572D.html">NXP
SA572D datasheet</a><a href="#fnref7" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
<li id="fn8" role="doc-endnote"><p><a
href="https://www.mouser.com/datasheet/2/294/NJM4565_E-1917662.pdf">JRC
4565 datasheet</a><a href="#fnref8" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
<li id="fn9" role="doc-endnote"><p><a
href="https://www.mouser.com/datasheet/2/294/NJM4565_E-1917662.pdf">JRC
4565 datasheet</a><a href="#fnref9" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
</ol>
</section>
]]>
		</summary>
	</entry>

	<entry>
		<title>Nuuo NVRmini NV-4080S/Promise NS4600 (3)</title>
		<link href="/cms/2025-11-16-nuuo-nvrmini-nv-4080s-promise-ns4600--3-.html" />
		<updated>2025-11-16T18:00:00+00:00</updated>
		<id>https://monorailc.atoutput/cms/2025-11-16-nuuo-nvrmini-nv-4080s-promise-ns4600--3-.html</id>
		<summary type="html"><![CDATA[<p>Mon NAS <em>Nuuo NVRmini</em><a href="#fn1" class="footnote-ref"
id="fnref1" role="doc-noteref"><sup>1</sup></a> de récupération n’est
pas utilisable <em>out of the box</em>, je me suis dit qu’il serait
intéressant d’arriver à l’utiliser, quitte à bricoler un peu.</p>
<p>Le firmware original n’est pas utilisable ni modifiable, il va
falloir le remplacer par une distribution de Linux, avec quelques
contraintes :</p>
<ul>
<li>Mémoire flash limitée à 128MiB, de nombreux cas de mémoire corrompue
sont rapportés avec d’autres NAS qui utilisent les mêmes puces</li>
<li>U-Boot non-modifiable : les sources originales sont modifiées par
Nuuo/Promise, et ne sont pas disponibles, ni adaptables pour autre-chose
que le firmware original</li>
</ul>
<h1 id="installation-de-debian">Installation de Debian</h1>
<p>J’ai suivi le guide de <em>Alexei Colin</em><a href="#fn2"
class="footnote-ref" id="fnref2" role="doc-noteref"><sup>2</sup></a> qui
correspond au même système hardware, mais avec un firmware et un
environnement différents :</p>
<ul>
<li>Mon NAS a un firmware Nuuo avec un kernel compilé sans NFS,
contrairement au firmware <em>Patriot Javelin S4</em> et sûrement au
<em>Promise NS4600p</em></li>
<li>Mon réseau local était assez simpliste, sans serveur NFS au moment
où j’ai installé Debian</li>
</ul>
<p>On peut commencer avec le matériel suivant :</p>
<ul>
<li>NAS Nuuo/Patriot/Promise</li>
<li>UART USB 3.3V (FTDI 232 ou similaire)</li>
<li>Clé USB &gt;=1GiB</li>
<li>PC utilisant Linux avec l’adresse 192.168.3.250</li>
<li>Routeur avec l’adresse 192.168.3.1 (optionnel)</li>
</ul>
<h2 id="installation-du-système-debian-de-base">Installation du système
Debian de base</h2>
<p>On va installer un système de base Debian avec <em>debootstrap</em><a
href="#fn3" class="footnote-ref" id="fnref3"
role="doc-noteref"><sup>3</sup></a>, avec une machine Linux, de la même
façon que proposée par le guide<a href="#fn4" class="footnote-ref"
id="fnref4" role="doc-noteref"><sup>4</sup></a>, avec quelques
différences :</p>
<pre><code>apt-get install debootstrap
mkdir nuuo-rootfs
debootstrap --arch=powerpc --foreign --keyring=/usr/share/keyrings/debian-archive-removed-keys.gpg wheezy nuuo-rootfs/ http://archive.debian.org/debian/</code></pre>
<p>La dernière version de Debian disponible avec l’architecture
<em>powerpc</em> est <em>Jessie</em> 8.0, mais j’ai rencontré des soucis
de compatibilité avec des noyaux plus récents que le 2.6.32, alors j’ai
installé <em>Wheezy</em> 7.0.</p>
<p>Comme il s’agit d’une architecture <em>powerpc</em>, on ne pourra pas
utiliser chroot sur la machine hôte, qui est un PC avec une architecture
<em>amd64</em>.</p>
<p>Pour continuer, on crée les fichiers de périphériques pour la console
série, nécessaires pour la suite de l’installation :</p>
<pre><code>mknod nuuo-rootfs/dev/ttyS0 c 4 64</code></pre>
<p>On utilise l’init par défaut :</p>
<pre><code>cp nuuo-rootfs/usr/share/sysvinit/inittab nuuo-rootfs/etc/inittab</code></pre>
<p>Que l’on modifie pour utililiser la console série, en commentant les
lignes concernant les consoles clavier/écran et en décommentant la
lignes concernant une console série vt100, avec un baudrate configuré à
115200 bit/s :
<code>T0:2345:respawn:/sbin/getty -L ttyS0 115200 vt100</code>.</p>
<p>On choisit le hostname :</p>
<pre><code>echo &quot;nuuo&quot; &gt; nuuo-rootfs/etc/hostname</code></pre>
<p>On configure les systèmes de fichiers en éditant le fichier
<code>nuuo-root/etc/fstab</code></p>
<pre><code>echo &quot;LABEL=tmp / ext3 defaults 1 1&quot; &gt;&gt; nuuo-rootfs/etc/fstab
echo &quot;proc /proc proc defaults 0 0&quot; &gt;&gt; nuuo-rootfs/etc/fstab</code></pre>
<p>Ensuite, on ne suit pas le reste du tutoriel de <em>Alexei Colin</em>
puisqu’on ne va pas utiliser NFS.</p>
<h3 id="spécificité-de-devuan">Spécificité de Devuan</h3>
<p>Si le système hôte utilise Devuan au lieu de Debian, il est possible
que la commande <em>debootstrap</em> échoue et retourne une erreur à
propos de clés introuvables
<code>E: Couldn't find these debs: devuan-keyring</code>.</p>
<p>Il est possible de modifier le fichier d’installation du dossier
<code>/usr/share/debootstrap/scripts/</code> correspondant à la
distribution, pour y remplacer les clés de <em>Devuan</em> par celles de
<em>Debian</em> et corriger l’erreur. On peut par exemple utiliser les
regex suivantes avec <em>vi</em> :
<code>:%s/devuan-keyring/debian-keyring/g</code> et
<code>:%s/devuan-archive-keyring/debian-archive-keyring/g</code>.</p>
<h2 id="préparation-de-clé-usb">Préparation de clé USB</h2>
<h3 id="partitionnement">Partitionnement</h3>
<p>On choisit arbitrairement une partition de 200 MB en FAT, pour y
stocker les images de boot, et une partition de &gt;800MB pour le
système temporaire.</p>
<p>Dans mon cas, la clé USB est partitionnée de façon suivante, le
<em>boot flag</em> n’est pas nécessaire :</p>
<pre><code>Device     Boot  Start      End  Sectors  Size Id Type
/dev/sdb1  *      2048   411647   409600  200M  6 FAT16
/dev/sdb2       411648 15728639 15316992  7.3G 83 Linux</code></pre>
<h3 id="partition-boot">Partition boot</h3>
<p>On va formater la partition en FAT, utilisable par U-Boot, puis
copier les fichiers que l’on a récupérés précédemment<a href="#fn5"
class="footnote-ref" id="fnref5" role="doc-noteref"><sup>5</sup></a> en
copiant le contenu de la mémoire flash originale :</p>
<pre><code>mkfs.vfat -a /dev/sdb1
mount /dev/sdb1 /mnt
cp nuuo_mtd/mtd{0,1,2,3,4,5} /mnt/
umount /mnt</code></pre>
<h3 id="partition-root">Partition root</h3>
<p>On va formater la partition en <em>ext3</em>, utilisable par Linux,
puis copier l’installation temporaire <em>debootstrap</em> :</p>
<pre><code>mkfs.ext3 -L tmp /dev/sdb2
mount /dev/sdb2 /mnt
cp -a nuuo-rootfs/* /mnt/
umount /mnt</code></pre>
<h3 id="syncronisation">Syncronisation</h3>
<p>Il est probable de rencontrer des erreurs qui nécessitent de modifier
le contenu de la clé USB, ou le système pré-installé sur le système
hôte. <em>Rsync</em> permet de ne copier que les fichiers qui ont été
modifiés.</p>
<p>Pour copier du système hôte vers la clé usb, on utilise la commande
suivante :</p>
<pre><code>rsync -av --delete-after nuuo-rootfs/ /mnt/</code></pre>
<p>Et pour syncroniser de la clé USB vers le système hôte, on utilise la
commande suivante :</p>
<pre><code>rsync -av --delete-after /mnt/ nuuo-rootfs/</code></pre>
<p>Attention à ne pas se tromper de sens, au risque d’écraser des
modifications.</p>
<h2 id="premier-démarrage">Premier démarrage</h2>
<p>On connecte la console série au connecteur <em>J1</em><a href="#fn6"
class="footnote-ref" id="fnref6" role="doc-noteref"><sup>6</sup></a>, on
alimente le NAS, et on appuie sur Ctrl-C quand U-Boot le propose.</p>
<p>On peut connecter la clé USB sur le port USB du NAS<a href="#fn7"
class="footnote-ref" id="fnref7" role="doc-noteref"><sup>7</sup></a>, et
taper la commande <code>usb start</code> :</p>
<blockquote>
<p>(Re)start USB…</p>
<p>USB: scanning bus for devices… 2 USB Device(s) found</p>
<p>scanning bus for storage devices… 1 Storage Device(s) found</p>
</blockquote>
<p>On va ensuite définir les variables d’environnement de U-Boot
nécessaires au démarrage, puis charger les images en mémoire et booter
:</p>
<pre><code>setenv bootargs root=LABEL=tmp rw console=ttyS0,115200
fatload usb 0:1 0x1200000 mtd4; fatload usb 0:1 0x1b00000 mtd5; fatload usb 0:1 0x1a00000 mtd1
bootm 1200000 1b00000 1a00000</code></pre>
<h3 id="difficultés">Difficultés</h3>
<p>Le fonctionnement est aléatoire, j’ai essayé différentes clés USB,
différentes tailles/alignements de partitions et différentes options de
FAT. Il est possible que ça ne soit pas assez fiable.</p>
<p>J’ai aussi testé les images de <em>Patriot Javelin</em> et une image
compilée par <em>Alexei Colin</em><a href="#fn8" class="footnote-ref"
id="fnref8" role="doc-noteref"><sup>8</sup></a>, cette dernière a le
plus de fonctionalités.</p>
<h3 id="seconde-tentative">Seconde tentative</h3>
<p>U-boot permet de récupérer des fichiers avec le protocole TFTP. J’ai
déjà le serveur <em>tdtpd-hpa</em> installé sur ma machine avec
l’adresse <em>192.168.3.250</em>, à la racine <em>/srv/tftp/</em>.</p>
<p>Il reste à copier les images :</p>
<pre><code>cp nuuo_mtd/mtd{0,1,2,3,4,5} /srv/tftp/
cp javelin-alexeicolin/*.img /srv/tftp/</code></pre>
<p>Il peut être nécessaire de définir les variables suivantes pour
pré-configurer le réseau si on n’utilise pas le protocole DHCP :</p>
<pre><code>setenv ipaddr 192.168.3.181
setenv serverip 192.168.3.250
setenv bootargs root=LABEL=tmp rw console=ttyS0,115200 init=/bin/sh</code></pre>
<p>On peut ensuite charger les fichiers dans la RAM du NAS et démarrer
:</p>
<pre><code>tftpboot 0x1200000 192.168.3.250:kernel.img; tftpboot 0x1b00000 192.168.3.250:ramdisk.img; tftpboot 0x1a00000 192.168.3.250:dtb.img
bootm 1200000 1b00000 1a00000</code></pre>
<p>Si tout fonctionne correctement, la machine doit démarrer et
retourner un shell root.</p>
<h2 id="suite-de-linstallation">Suite de l’installation</h2>
<p>On va poursuivre l’installation et choisir un mot-de-passe
<em>root</em> :</p>
<pre><code>mount -o remount,rw /
debootstrap/debootstrap --second-stage
passwd</code></pre>
<p>On redémarre pour continuer l’installation avec une init normale
:</p>
<pre><code>setenv ipaddr 192.168.3.181
setenv serverip 192.168.3.250
setenv bootargs root=LABEL=tmp rw console=ttyS0,115200
tftpboot 0x1200000 192.168.3.250:kernel.stock.img; tftpboot 0x1b00000 192.168.3.250:ramdisk.stock.img; tftpboot 0x1a00000 192.168.3.250:dtb.img
bootm 1200000 1b00000 1a00000</code></pre>
<p>On peut se logguer en tant que root, avec le mot-de-passe choisi
précédemment, et commencer par régler la date :</p>
<blockquote>
<p># date 111614302025</p>
<p>Sun Nov 16 14:30:00 UTC 2025</p>
</blockquote>
<p>La pile de l’horloge RTC semble défectueuse, on va installer
<code>ntp</code> et la remplacer à la prochaine occasion.</p>
<p>Puis on va configurer le réseau :</p>
<pre><code>echo &quot;nameserver 192.168.3.1&quot; &gt;&gt; /etc/resolv.conf
ifconfig eth0 192.168.3.4
route add default gw 192.168.3.1</code></pre>
<p>On va rajouter les informations correspondantes dans le fichier
<code>/etc/network/interfaces</code>, pour rendre la configuration
permanente. Ensuite, on va s’assurer que les paquets
<code>net-tools ifupdown udev util-linux mtd-utils</code> soient bien
installés, et on va installer les paquets <code>ssh screen</code>.</p>
<p><em>SSH</em> permet d’utiliser le réseau plutôt que la console série,
le débit y est plus rapide, et <em>screen</em> permet d’utiliser
plusieurs terminaux.</p>
<h2 id="installation-sur-un-disque-dur">Installation sur un
disque-dur</h2>
<p>On arrête le NAS, puis on connecte la clé USB sur le système hôte,
pour la monter, copier et ensuite archiver son contenu :</p>
<pre><code>mount /dev/sdb2 /mnt
rsync -av --delete-after /mnt/ nuuo-rootfs/
tar cf nuuo-rootfs.tar nuuo-rootfs/
cp nuuo-rootfs.tar /mnt/
umount /mnt/</code></pre>
<p>On peut ensuite reconnecter la clé USB sur le NAS, en s’assurant que
le disque dur est bien branché, et ajoutant la commande
<code>scsi init</code> en plus des commandes du démarrage précédent
:</p>
<pre><code>setenv ipaddr 192.168.3.181
setenv serverip 192.168.3.250
setenv bootargs root=LABEL=tmp rw console=ttyS0,115200
scsi init
tftpboot 0x1200000 192.168.3.250:kernel.img; tftpboot 0x1b00000 192.168.3.250:ramdisk.img; tftpboot 0x1a00000 192.168.3.250:dtb.img
bootm 1200000 1b00000 1a00000</code></pre>
<p>On peut ensuite se logguer en tant que root et s’intéresser aux
périphériques de stockage avec la commande <code>blkid</code>.</p>
<blockquote>
<p># blkid</p>
<p>/dev/sda1: LABEL=“qwerty-123”
UUID=“55b5f9b0-8b69-4ae3-ba6d-e88e97298a06” TYPE=“ext4”</p>
<p>/dev/sda3: LABEL=“qwertz-456”
UUID=“ee406156-dd46-4d0c-a867-ce8179e49ac5” TYPE=“ext4”</p>
<p>/dev/sdb1: SEC_TYPE=“msdos” LABEL=“BOOT” UUID=“65FB-66D9”
TYPE=“vfat”</p>
<p>/dev/sdb2: LABEL=“sys” UUID=“70e37124-f816-4da0-b41c-09a51ea9c273”
TYPE=“ext3”</p>
</blockquote>
<p>On va effacer la table de partitions et le début du disque dur avec
la commande suivante :</p>
<pre><code>dd if=/dev/zero of=/dev/sda bs=1k count=1k</code></pre>
<p><strong>Attention</strong> à bien identifier le disque dur et à
s’assurer qu’il ne contienne pas de données utiles. Cette commande est
destructrice.</p>
<p>On va utiliser <code>parted</code> pour partitionner le disque dur
:</p>
<pre><code>parted /dev/sda --align optimal mktable gpt
parted /dev/sda --align optimal mkpart primary 0% 200MB     # boot
parted /dev/sda --align optimal mkpart primary 200MB 20GB   # sys
parted /dev/sda --align optimal mkpart primary 20GB 22GB    # swap
parted /dev/sda --align optimal mkpart primary 22GB 100%    # storage

mkfs.ext3 /dev/sda2 -L sys
mkfs.ext3 /dev/sda4 -L storage
mkswap /dev/sda3 -L swap
mkfs.vfat /dev/sda1 -L boot</code></pre>
<p>Il reste à vérifier que le disque est correctement partitionné avec
<code>blkid</code>:</p>
<blockquote>
<p># blkid |grep sda</p>
<p>/dev/sda1: LABEL=“boot” UUID=“9EA9-6FD2” SEC_TYPE=“msdos”
TYPE=“vfat”</p>
<p>/dev/sda2: LABEL=“sys” UUID=“7553bf9a-f2ca-48b2-ba04-336a2d49984e”
SEC_TYPE=“ext2” TYPE=“ext3”</p>
<p>/dev/sda3: LABEL=“swap” UUID=“30a216ca-b0fa-4ec0-901f-326c3fe0d8cb”
TYPE=“swap”</p>
<p>/dev/sda4: LABEL=“storage”
UUID=“938d68d2-c0e9-44e5-a2e6-eb0c0a9f31f3” SEC_TYPE=“ext2”
TYPE=“ext3”</p>
</blockquote>
<p>C’est correct, il reste à monter la partition <em>sda2</em> et
extraire l’archive que l’on avait préparée :</p>
<pre><code>mount /dev/sda2 /mnt/
cp /nuuo-rootfs.tar /mnt/
cd /mnt; tar xf nuuo-rootfs.tar
mv /mnt/nuuo-rootfs/* /mnt/
rm /mnt/nuuo-rootfs* -r</code></pre>
<p>Il reste à configurer une subtilité : le fichier
<code>/mnt/etc/fstab</code> :</p>
<blockquote>
<p>LABEL=sys / ext3 defaults 1 1</p>
<p>LABEL=boot /boot vfat defaults 1 2</p>
<p>LABEL=swap none swap sw 0 0</p>
<p>LABEL=storage /media/stuff ext3 defaults 1 2</p>
<p>proc /proc proc defaults 0 0</p>
</blockquote>
<p>Et on peut redémarrer le système et débrancher la clé USB en adaptant
le nom de partition racine :</p>
<pre><code>setenv bootargs root=LABEL=sys rw console=ttyS0,115200
setenv ipaddr 192.168.3.181
setenv serverip 192.168.3.250
scsi init
tftpboot 0x1200000 192.168.3.250:kernel.img; tftpboot 0x1b00000 192.168.3.250:ramdisk.img; tftpboot 0x1a00000 192.168.3.250:dtb.img
bootm 1200000 1b00000 1a00000</code></pre>
<p>On peut se logguer en tant que root et vérifier que la machine
fonctionne.</p>
<h1 id="configuration-de-u-boot">Configuration de U-Boot</h1>
<p>Maintenant, on va configurer <em>U-Boot</em> pour se passer de
serveur <em>TFTP</em> et de clé USB.</p>
<pre><code>setenv bootargs root=LABEL=sys mtdparts=nand0:1024K(u-boot),512K(dtb),3072K(safe-k),8192K(safe-r),3072K(kernel),8192K(rootfs),16384K(usr),2048K(data),1024K(oem),87552K(app) console=ttyS0,115200

setenv newnandboot &quot;run bootargs; scsi init; nand read.e 1200000 kernel 300000; nand read.e 1b00000 rootfs 800000; nand read.e 1a00000 dtb 3000; bootm 1200000 1b00000 1a00000&quot;

setenv newscsiboot &quot;run bootargs; scsi init; fatload scsi 0:1 0x1200000 kernel.img; fatload scsi 0:1 0x1b00000 ramdisk.img; fatload scsi 0:1 0x1a00000 dtb.img; bootm 1200000 1b00000 1a00000&quot;

setenv bootcmd run newnandboot
saveenv</code></pre>
<p>On a défini la commande <em>newnandboot</em> qui va initialiser les
disques durs, puis charger les images de noyau et de ramdisk dans la
mémoire flash, et on a défini cette commande de démarrage par défaut. La
dernière commande permet de sauvegarde la configuration de
<em>U-Boot</em>.</p>
<p>Maintenant, on va démarrer une dernière fois avec <em>TFTP</em> :</p>
<pre><code>setenv ipaddr 192.168.3.181
setenv serverip 192.168.3.250
scsi init
tftpboot 0x1200000 192.168.3.250:kernel.img; tftpboot 0x1b00000 192.168.3.250:ramdisk.img; tftpboot 0x1a00000 192.168.3.250:dtb.img
bootm 1200000 1b00000 1a00000</code></pre>
<p>On va se logguer en tant que root, et on va copier les images de
<em>Alexei Colin</em><a href="#fn9" class="footnote-ref" id="fnref9"
role="doc-noteref"><sup>9</sup></a> que l’on avait copiées sur la clé
USB :</p>
<pre><code>mount /dev/sdb1 /mnt
cp /mnt/{kernel, ramdisk}.img /root/</code></pre>
<p>Puis on va les écrire dans la mémoire flash.
<strong>Attention</strong>, il faut s’assurer de ne rien écraser et
d’écrire dans la bonne section.</p>
<pre><code>nandwrite -p -m /dev/mtd4 /root/kernel.img
nandwrite -p -m /dev/mtd5 /root/ramdisk.img</code></pre>
<p>Les redémarrages suivants fontionnent automatiquement, en tapant
simplement la commande <code>boot</code>, sans qu’une clé USB ni qu’une
connexion réseau ne soit nécessaire.</p>
<h2 id="alternative">Alternative</h2>
<p>Comme la mémoire flash n’est pas réputée fiable et n’est pas aussi
facile à modifier qu’une partition de disque dur, on a crée une
partition <em>/boot</em> formatée en <em>FAT</em>, et on a défini la
commande <em>newscsiboot</em> précédent, qui charge les images depuis le
disque dur.</p>
<p>Il suffit de copier les fichiers <code>kernel.img</code>,
<code>ramdisk.img</code> et <code>dtb.img</code> dans
<code>/boot/</code>, et de taper les deux commandes <em>U-Boot</em>
:</p>
<pre><code>setenv bootcmd run newscsiboot
saveenv</code></pre>
<h1 id="suite-de-linstallation-1">Suite de l’installation</h1>
<p>Le NAS Nuuo est utilisable comme n’importe quel NAS ou serveur. Il
peut-être utile de regarder l’article précédent<a href="#fn10"
class="footnote-ref" id="fnref10" role="doc-noteref"><sup>10</sup></a>
pour corriger les problèmes de <em>U-Boot</em>.</p>
<p>Il est possible de suivre les articles suivants pour ajouter des
fonctionalités :</p>
<ul>
<li><a href="/cms/2025-03-15-migration-de-serveur.html">Serveur hébergé
- 2025</a></li>
<li><a href="/cms/2016-09-05-serveur.html">Serveur DIY - 2016</a></li>
<li><a href="/cms/2013-01-19-serveur-home.html">Serveur DIY -
2007</a></li>
</ul>
<p>Comme la distribution Debian <em>Wheezy</em> est ancienne et n’a plus
de mises-à-jour de sécurité, il est recommandé de ne pas trop l’exposer
à internet. L’utilisation de <em>chroot</em> avec des programmes plus
récents et cloisonnés peut convenir.</p>
<h1 id="références">Références</h1>
<p>J’ai aussi lu ces autres guides. Ils ne sont pas applicables
directement à mon cas, mais ils confirment des informations utiles :</p>
<ul>
<li><a
href="https://saturn.ffzg.hr/rot13/index.cgi?promise_smartstor">Promise
SmartStor - Dobrica Pavlinušić’s random unstructured stuff</a></li>
<li><a href="https://github.com/yop0382/ns4600p">yop0382/ns4600p -
Github</a></li>
<li><a
href="http://web.archive.org/web/20130202084740/http://www.patriotmemory.com/forums/showthread.php?6980-Heavy-duty-Javelin-hacking">Heavy
duty Javelin hacking - Patriot Memory</a></li>
</ul>
<section class="footnotes footnotes-end-of-document"
role="doc-endnotes">
<hr />
<ol>
<li id="fn1" role="doc-endnote"><p><a
href="/cms/2017-05-06-nuuo-nvrmini-nv-4080s-promise-ns4600.html">Nuuo
NVRmini NV-4080S/Promise NS4600 - Monorailc.at</a><a href="#fnref1"
class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn2" role="doc-endnote"><p><a
href="https://github.com/alexeicolin/javelin">Alexei Colin</a><a
href="#fnref2" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn3" role="doc-endnote"><p><a
href="https://www.debian.org/releases/stable/amd64/apds03.en.html">D.3.
Installing Debian GNU/Linux from a Unix/Linux System - Debian</a><a
href="#fnref3" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn4" role="doc-endnote"><p><a
href="https://github.com/alexeicolin/javelin">Alexei Colin</a><a
href="#fnref4" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn5" role="doc-endnote"><p><a
href="/cms/2017-05-06-nuuo-nvrmini-nv-4080s-promise-ns4600.html">Nuuo
NVRmini NV-4080S/Promise NS4600 - Monorailc.at</a><a href="#fnref5"
class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn6" role="doc-endnote"><p><a
href="/cms/2017-05-06-nuuo-nvrmini-nv-4080s-promise-ns4600.html">Nuuo
NVRmini NV-4080S/Promise NS4600 - Monorailc.at</a><a href="#fnref6"
class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn7" role="doc-endnote"><p>Seules les clés USB connectées au
port le plus éloigné de la carte-mère sont détectées par U-Boot<a
href="#fnref7" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn8" role="doc-endnote"><p><a
href="https://drive.proton.me/urls/9YXA9KSGWG#Sz6k4jHFwQBO">Alexei Colin
- Proton Drive</a><a href="#fnref8" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
<li id="fn9" role="doc-endnote"><p><a
href="https://drive.proton.me/urls/9YXA9KSGWG#Sz6k4jHFwQBO">Alexei Colin
- Proton Drive</a><a href="#fnref9" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
<li id="fn10" role="doc-endnote"><p><a
href="/cms/2025-10-27-nuuo-nvrmini-nv-4080s-promise-ns4600--2-.html">Nuuo
NVRmini NV-4080S/Promise NS4600 (2) - Monorailc.at</a><a href="#fnref10"
class="footnote-back" role="doc-backlink">↩︎</a></p></li>
</ol>
</section>
]]>
		</summary>
	</entry>

	<entry>
		<title>Nuuo NVRmini NV-4080S/Promise NS4600 (2)</title>
		<link href="/cms/2025-10-27-nuuo-nvrmini-nv-4080s-promise-ns4600--2-.html" />
		<updated>2025-10-27T19:00:00+00:00</updated>
		<id>https://monorailc.atoutput/cms/2025-10-27-nuuo-nvrmini-nv-4080s-promise-ns4600--2-.html</id>
		<summary type="html"><![CDATA[<p>Je voulais utiliser le NAS montré dans un <a
href="/cms/2017-05-06-nuuo-nvrmini-nv-4080s-promise-ns4600.html">article
précédent</a>, avec un firmware alternatif, en installant Linux sur un
disque dur ou une clé USB.</p>
<p>Pour des raisons inexpliquées, U-Boot n’alimente pas les
périphériques SATA ni les périphériques USB lors du démarrage. Ça peut
fonctionner avec le firmware original qui n’utilise que la mémoire
flash, mais pas dans mon cas : seuls le noyau et l’initrd sont stockés
dans la mémoire flash. Le reste de l’OS est stocké sur un disque-dur
SATA.</p>
<p>Sauf qu’il est possible de démarrer lorsque l’on interrompt le
démarrage automatique de <em>U-Boot</em>, puis que l’on tape une
commande pour continuer son exécution.</p>
<h1 id="test-manuel">Test manuel</h1>
<p>On branche un PC avec un adaptateur USB-Série 3.3V sur le connecteur
<em>J1</em><a href="#fn1" class="footnote-ref" id="fnref1"
role="doc-noteref"><sup>1</sup></a>, on alimente le NAS, et on regarde
ce qu’il affiche dans un terminal :</p>
<pre><code>U-Boot 1.3.4 (NS4600p - 014 - 800MHz) (Nov 04 2010 - 14:03:07)

CPU:   AMCC PowerPC 431EXr at 800 MHz (PLB=200, OPB=100, EBC=100 MHz)
    Security/Kasumi support
    Bootstrap Option F - Boot ROM Location NAND (8 bits), booting from NAND
    Internal PCI arbiter disabled
    32 kB I-Cache 32 kB D-Cache
Board: NS4600p - PROMISE 4-bay NAS Target Board, 1*PCIe/1*SATA
I2C:   ready
DRAM:  256 MB
Enclosure: Load fan configurations from VPD
NAND:  128 MiB
eth0 MAC = 00:01:55:31:1f:21
eth1 MAC = 00:00:00:00:00:00
PCI:   Bus Dev VenId DevId Class Int
PCIE1: successfully set as root-complex
        01  00  105a  3f20  0104  00
SCSI:  Net:   ppc_4xx_eth0

Hit Ctrl + C to stop autoboot: 10</code></pre>
<p>Si on n’appuie pas sur Ctrl-C, U-Boot charge le noyau et l’initrd en
mémoire, mais n’alimente pas les disques, le noyau ne trouve pas de
disque-dur et plante<a href="#fn2" class="footnote-ref" id="fnref2"
role="doc-noteref"><sup>2</sup></a>.</p>
<p>Si on appuie sur Ctrl-C, U-Boot exécute quelques commandes avant de
donner un shell :</p>
<pre><code>Leave clock generator PD mode... OK
Leave net PHY PD mode... OK
Turn on all activity LED power... OK
FAN_SET mode... OK
Turn off all status LED... OK
Turn on disk power... OK
=&gt;</code></pre>
<p>On entend bien les disques SATA démarrer, on peut taper
<code>boot</code>, et la machine démarre correctement, puisque le noyau
est capable de détecter les disques-durs.</p>
<h1 id="automatisation">Automatisation</h1>
<p>Exécuter une opération manuelle à chaque démarrage n’est pas très
pratique, surtout en cas de re-démarrage imprévu. Comme l’opération est
simple, on va utiliser un microcontrôleur.</p>
<p>Il faut les spécifications suivantes :</p>
<ul>
<li>Alimentation 3.3V</li>
<li>UART 115200 bits/s 8N1</li>
</ul>
<h2 id="arduino">Arduino</h2>
<p>Par habitude, l’environnement de développement <em>Arduino</em> est
pratique pour des prototypes simples, et la variante hardware <em>Pro
Mini</em><a href="#fn3" class="footnote-ref" id="fnref3"
role="doc-noteref"><sup>3</sup></a> est compacte et s’alimente en
3.3V.</p>
<figure>
<img src="/data/diy/nuuo_mcu/ArduinoProMiniFTDIBreakout2.jpg"
title="Arduino Pro Mini FTDI" alt="Arduino Pro Mini FTDI" />
<figcaption aria-hidden="true">Arduino Pro Mini FTDI</figcaption>
</figure>
<p>Je rencontre quelques soucis : il m’est impossible de faire
fonctionner l’UART correctement à 115200 bit/s, puisque les cartes
alimentées en 3.3V ont un quartz à 8MHz, et des diviseurs d’horloge qui
ne permettent pas à l’UART de fonctionner à la bonne fréquence<a
href="#fn4" class="footnote-ref" id="fnref4"
role="doc-noteref"><sup>4</sup></a>.</p>
<p>J’avais commencé par suspecter les bibliothèques Arduino, avant
d’utiliser le MCU <em>bare-metal</em>. Le code est plus long à écrire,
mais l’exécution est plus rapide et on contrôle précisément ce que l’on
fait. Comme mon problème d’UART était matériel, il n’a pas été
résolu.</p>
<h2 id="msp430">MSP430</h2>
<p>J’ai une carte d’évaluation de MSP430 et un MSP430G2553 en stock, qui
correspondent aux besoins<a href="#fn5" class="footnote-ref" id="fnref5"
role="doc-noteref"><sup>5</sup></a>, avec l’intérêt supplémentaire
d’avoir un oscillateur interne assez précis pour qu’aucun quartz ne soit
nécessaire.</p>
<h3 id="energia">Energia</h3>
<p><em>Energia</em> est un port d’Arduino pour MSP430, qui permet de
prototyper rapidement<a href="#fn6" class="footnote-ref" id="fnref6"
role="doc-noteref"><sup>6</sup></a>.</p>
<p>L’intérêt est surtout de fournir une chaîne de développement quand
les paquets ne sont plus présents dans Debian depuis 2019<a href="#fn7"
class="footnote-ref" id="fnref7"
role="doc-noteref"><sup>7</sup></a>.</p>
<p>Pour utiliser la chaîne de développement sans l’IDE, il suffit
d’adapter la commande suivante à l’endroit où les fichiers de Energia
sont présents :</p>
<pre><code>export PATH=$PATH:/opt/energia-1.8.10E23/hardware/tools/msp430/bin/</code></pre>
<p>Le fonctionnement de <em>Energia</em> est correct, mais j’ai
rencontré le même problème qu’avec le bibliothèques <em>Arduino</em> :
le fichier exécutable est volumineux, et son exécution est lente. Ça
fait une bonne excuse pour utiliser le MCU <em>bare-metal</em>.</p>
<h2 id="code">Code</h2>
<p>Le programme est construit avec deux machines d’état, et la réception
des caractères se fait par interruptions.</p>
<p>On utilise un <em>scheduler</em> minimaliste<a href="#fn8"
class="footnote-ref" id="fnref8" role="doc-noteref"><sup>8</sup></a>, où
une interruption de timer va exécuter ce <em>scheduler</em> à 1kHz, qui
va utiliser des variables (<code>milliseconds</code> et
<code>seconds</code>) pour exécuter d’autres tâches. Ça permet de
désactiver le CPU hors des interruptions, pour consommer moins
d’énergie<a href="#fn9" class="footnote-ref" id="fnref9"
role="doc-noteref"><sup>9</sup></a>.</p>
<pre><code>__attribute__ ((interrupt(TIMER0_A0_VECTOR))) void timer_A_ISR(void) {
    milliseconds++;
    if(!(milliseconds % 1000)) {
        seconds++;
    }
    if(!(milliseconds % DELAY_FSM)) {
        fsm();                  // 100 Hz
    }
}</code></pre>
<p>On utilise une machine à 4 états pour recevoir les commandes et
envoyer les commandes correspondantes.</p>
<figure>
<img src="/data/diy/nuuo_mcu/fsm.png" title="FSM" alt="FSM" />
<figcaption aria-hidden="true">FSM</figcaption>
</figure>
<pre><code>void fsm() {
    /*
    * 0: default, listening for 1st string
    * 1: 1st string matched, waiting 100ms, sending &#39;^C&#39;
    * 2: listening for 2nd string
    * 3: 2nd string matched, waiting 100ms, sending &quot;boot\n&quot;
    */
    static unsigned long delay = 0;
    switch(state) {
        case 1:
            if(delay == 0)
                delay = milliseconds;
            if(milliseconds - delay &gt;= 100) {
                putchar(0x03);      // ^C
                delay = 0;
                state = 2;
                //toggle_LED();
            }
            break;
        case 2:
            listening_cond(str2);
            break;
        case 3:
            if(delay == 0)
                delay = milliseconds;
            if(milliseconds - delay &gt;= 100) {
                puts(&quot;boot\n&quot;);
                delay = 0;
                state = 0;
                clearbuf();
                //toggle_LED2();
            }
            break;
        default:
            listening_cond(str1);
            break;
    }
}</code></pre>
<p>Les LEDs permettent de surveiller l’exécution lorsqu’on va tester la
carte en conditions réelles, avec le debugger débranché.</p>
<h3 id="gestion-de-luart">Gestion de l’UART</h3>
<p>La pratique par défaut est de stocker les caractères reçus dans un
buffer circulaire<a href="#fn10" class="footnote-ref" id="fnref10"
role="doc-noteref"><sup>10</sup></a>. Ensuite, on peut les extraire dans
un buffer linéaire pour le comparer avec les chaînes de caractères de
référence.</p>
<figure>
<img src="/data/diy/nuuo_mcu/Circular_Buffer_Animation.gif"
title="Ring buffer" alt="Ring buffer" />
<figcaption aria-hidden="true">Ring buffer</figcaption>
</figure>
<p>Ça fonctionne, mais ça utilise beaucoup de mémoire, et le parcours
puis la copie du buffer sont lents. Il faut augmenter la taille du
buffer pour ne pas rater de caractère, ce qui utilise encore plus de
mémoire.</p>
<p>On va plutôt utiliser un buffer linéaire glissant, qui sont
habituellement utilisés pour des opérations de filtrage. Le
<em>glissement</em> du tableau se fait sur lui-même, et on peut comparer
directement ce buffer avec les chaînes de caractères de référence.</p>
<h2 id="conditions-réelles">Conditions réelles</h2>
<p>Une fois les fonctions unitaires et le système validés, on peut
brancher la carte d’évaluation au NAS.</p>
<p>Une fois l’alimentation du NAS branchée, les LEDs de la carte
d’évaluation s’allument, et les disques durs du NAS se mettent à
tourner.</p>
<p>Il ne reste plus qu’à câbler tout ça sur un morceau de plaque à
trous.</p>
<figure>
<img src="/data/diy/nuuo_mcu/hackboard.jpg" title="Hacked board"
alt="Hacked board" />
<figcaption aria-hidden="true">Hacked board</figcaption>
</figure>
<p>Le code source est disponible<a href="#fn11" class="footnote-ref"
id="fnref11" role="doc-noteref"><sup>11</sup></a> sous license <a
href="https://creativecommons.org/licenses/by-nc/4.0/">CC BY-NC</a>.</p>
<h1 id="références">Références</h1>
<section class="footnotes footnotes-end-of-document"
role="doc-endnotes">
<hr />
<ol>
<li id="fn1" role="doc-endnote"><p><a
href="/cms/2017-05-06-nuuo-nvrmini-nv-4080s-promise-ns4600.html">Nuuo
NVRmini - Monorailc.at</a><a href="#fnref1" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
<li id="fn2" role="doc-endnote"><p><a
href="https://en.wikipedia.org/wiki/Kernel_panic">Kernel Panic -
Wikipedia</a><a href="#fnref2" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
<li id="fn3" role="doc-endnote"><p><a
href="https://docs.arduino.cc/retired/boards/arduino-pro-mini/">Arduino
Pro Mini - Arduino Documentation</a><a href="#fnref3"
class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn4" role="doc-endnote"><p><a
href="https://ww1.microchip.com/downloads/en/DeviceDoc/Atmel-7810-Automotive-Microcontrollers-ATmega328P_Datasheet.pdf">ATMega328P
- Datasheet</a>, section 19.11<a href="#fnref4" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
<li id="fn5" role="doc-endnote"><p><a
href="https://www.ti.com/lit/ug/slau144k/slau144k.pdf">MSP430F2xx,
MSP430G2xx Family User’s Guide (Rev. K)</a>, <a
href="https://www.ti.com/lit/ds/symlink/msp430g2553.pdf">MSP430G2553 -
Datasheet</a><a href="#fnref5" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
<li id="fn6" role="doc-endnote"><p><a
href="https://energia.nu/reference/">Energia</a><a href="#fnref6"
class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn7" role="doc-endnote"><p><a
href="https://sources.debian.org/patches/gcc-msp430/">Package:
gcc-msp430 - Debian sources</a><a href="#fnref7" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
<li id="fn8" role="doc-endnote"><p>Il n’y a pas de drapeau pour forcer
une exécution séquentielle, il faut s’assurer que les tâches se
terminent assez vite et ne bloquent pas<a href="#fnref8"
class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn9" role="doc-endnote"><p>La consommation théorique est de 4mA
en mode <em>Active</em> à 16MHz et 3.3V, et &lt;1uA en mode
<em>LPM3</em>, heureusement que l’alimentation du NAS est capable de
fournir 100W<a href="#fnref9" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
<li id="fn10" role="doc-endnote"><p><a
href="https://en.wikipedia.org/wiki/Circular_buffer">Circular Buffer -
Wikipedia</a><a href="#fnref10" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
<li id="fn11" role="doc-endnote"><p><a
href="/data/diy/nuuo_mcu/msp430_nuuo.tar.gz">Code source</a> <a
href="https://creativecommons.org/licenses/by-nc/4.0/">CC BY-NC</a><a
href="#fnref11" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
</ol>
</section>
]]>
		</summary>
	</entry>

	<entry>
		<title>Pi computation algorithms (2)</title>
		<link href="/cms/2025-08-14-pi-computation-algorithms--2-.html" />
		<updated>2025-08-14T23:00:05+00:00</updated>
		<id>https://monorailc.atoutput/cms/2025-08-14-pi-computation-algorithms--2-.html</id>
		<summary type="html"><![CDATA[<p>We’ve seen multiple algorithms to compute approximations of
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>π</mi><annotation encoding="application/x-tex">\pi</annotation></semantics></math>
in a previous article<a href="#fn1" class="footnote-ref" id="fnref1"
role="doc-noteref"><sup>1</sup></a>. Once we know they all work, we can
compare them, making sure to run them on the same machine within the
same conditions.</p>
<p>As previously, the code is publicly available<a href="#fn2"
class="footnote-ref" id="fnref2" role="doc-noteref"><sup>2</sup></a>
under <a href="https://creativecommons.org/licenses/by-nc/4.0/">CC
BY-NC</a> license.</p>
<h1 id="getting-data">Getting data</h1>
<h2 id="convergence">Convergence</h2>
<p>One important thing is to see how long an algorithm takes to
converge, and make sure they converge. This needs to take the duration
of each iteration of loops, as well as the number of iterations.</p>
<p>First, we can simply run our code, sweeping for different iteration
numbers, and types of algorithms<a href="#fn3" class="footnote-ref"
id="fnref3" role="doc-noteref"><sup>3</sup></a>:</p>
<pre><code>for algo in circle taylor leibniz sphere euler agm newton_gmp \
machin_gmp archimedes_gmp ramanujan chudnovsky plouffe bellard;
    do for n in 1 2 3 10 30 100 300 1000;
        do ./pi $algo $n;
    done;
done &gt; benchmark</code></pre>
<p>We also need to make the file less human-readable and more
machine-readable, to something similar to CSV<a href="#fn4"
class="footnote-ref" id="fnref4"
role="doc-noteref"><sup>4</sup></a>:</p>
<pre><code>sed -i &#39;s/\,\titerations\:\ /\t/g&#39; benchmark
sed -i &#39;s/,\tpi\ \=\ /\t/g&#39; benchmark
sed -i &#39;s/,\terr\ = /\t/g&#39; benchmark</code></pre>
<h2 id="execution-times">Execution times</h2>
<p>We can compare execution times:</p>
<pre><code>hyperfine --export-json benchmark.json -N -r 10 -w 1 -L algo circle,\
taylor,leibniz,sphere,euler,agm,newton,newton_gmp,machin,machin_gmp,\
archimedes,archimedes_gmp,ramanujan,chudnovsky,plouffe,bellard \
-L n 1,2,3,10,30,100,300,1000 &quot;./pi {algo} {n}&quot; -i</code></pre>
<p>Hyperfine returns a JSON file that’s completely different than the
CSV file we built. Having both execution times and accuracy in a single
file would be nicer.</p>
<p>We can do that using <code>jq</code> wrapped around some bash
code:</p>
<pre><code>rm benchmark2.json;
for algo in circle taylor leibniz sphere euler agm newton_gmp \
machin_gmp archimedes_gmp ramanujan chudnovsky plouffe bellard;
    do for n in 1 2 3 10 30 100 300 1000;
        do pi=$(grep ^$algo$&#39;\t&#39;${n}$&#39;\t&#39; benchmark | awk &#39;{ print $3}&#39;);
        diff=$(grep ^$algo$&#39;\t&#39;${n}$&#39;\t&#39; benchmark | awk &#39;{ print $4}&#39;);
        echo $(cat benchmark.json |jq -r &quot;.results[] | \
        select(.parameters.n == \&quot;$n\&quot; and .parameters.algo == \&quot;$algo\&quot;) | \
        .pi=&quot;$pi&quot; |.diff=&quot;$diff&quot;&quot;)$&#39;,&#39; &gt;&gt; benchmark2.json;
        # match parameters.n and parameters.algo from the json file with $n
        # and $algo from the csv file, adds $pi and $diff from the CSV file,
        # adds a comma and write to benchmark2.json
    done;
done;
sed -i &#39;1s/^/{&quot;results&quot;: [\n/&#39; benchmark2.json; # adds a file header
sed -i &#39;/^,$/d&#39; benchmark2.json;    # remove commas from blank lines
truncate -s -2 benchmark2.json      # removes the last comma and \n
echo &quot;\n]}&quot; &gt;&gt; benchmark2.json      # closes brackets at the end of the file</code></pre>
<p>This builds a new JSON file based on the content of the old JSON and
CSV files.</p>
<h1 id="plots">Plots</h1>
<p>We can simply display the content of the CSV file with a line
plot:</p>
<figure>
<img src="/data/diy/pi/convergence.png"
title="Convergence accuracy, Gnuplot"
alt="Convergence accuracy, Gnuplot" />
<figcaption aria-hidden="true">Convergence accuracy,
Gnuplot</figcaption>
</figure>
<p>This shows everything, although it’s not easy to read.</p>
<p>Instead, we can build a Python script to display the data we
collected into the JSON file. This gives barplots showing the execution
time and the accuracy relative to the iteration number for each
algorithm.</p>
<figure>
<img src="/data/diy/pi/convergence1.png"
title="Convergence accuracy, Seaborn"
alt="Convergence accuracy, Seaborn" />
<figcaption aria-hidden="true">Convergence accuracy,
Seaborn</figcaption>
</figure>
<figure>
<img src="/data/diy/pi/execution_time.png" title="Execution time"
alt="Execution time" />
<figcaption aria-hidden="true">Execution time</figcaption>
</figure>
<p>Both informations are interesting, but what’s important is actually
the compromise between execution time and accuracy.</p>
<p>To address that, we can compute a <em>figure of merit</em> by
multiplying the <em>execution time</em> and the <em>accuracy</em>,
without any coefficients. In this case, a smaller number means that an
algorithm is both quick and accurate.</p>
<figure>
<img src="/data/diy/pi/fom.png" title="Figure of merit"
alt="Figure of merit" />
<figcaption aria-hidden="true">Figure of merit</figcaption>
</figure>
<h1 id="first-conclusions">First conclusions</h1>
<p>That enables us rate algorithms, or actually their implementation,
based a few things:</p>
<ul>
<li>Missing data:
<ul>
<li>Failed computation</li>
<li>Accuracy better than 64-bit numbers</li>
</ul></li>
<li>Convergence that stops: accuracy limited by implementation</li>
<li>Convergence speed</li>
<li>Increasing figure of merit after a number of iteration:
<ul>
<li><em>Stalled</em> algorithm</li>
<li>Accuracy limited by implementation</li>
</ul></li>
</ul>
<h2 id="algorithm-ratings">Algorithm ratings</h2>
<table>
<colgroup>
<col style="width: 16%" />
<col style="width: 20%" />
<col style="width: 20%" />
<col style="width: 20%" />
<col style="width: 20%" />
</colgroup>
<thead>
<tr class="header">
<th style="text-align: left;">Algorithm</th>
<th style="text-align: center;">Accuracy</th>
<th style="text-align: center;">Figure of merit</th>
<th style="text-align: center;">Stops converging</th>
<th style="text-align: center;">Accuracy limited by 64-bit floats</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td style="text-align: left;">Circle</td>
<td style="text-align: center;">Poor</td>
<td style="text-align: center;">Poor</td>
<td style="text-align: center;">-</td>
<td style="text-align: center;">-</td>
</tr>
<tr class="even">
<td style="text-align: left;">Sphere</td>
<td style="text-align: center;">Average</td>
<td style="text-align: center;">Poor</td>
<td style="text-align: center;">-</td>
<td style="text-align: center;">-</td>
</tr>
<tr class="odd">
<td style="text-align: left;">Taylor</td>
<td style="text-align: center;">Poor</td>
<td style="text-align: center;">Poor</td>
<td style="text-align: center;">-</td>
<td style="text-align: center;">-</td>
</tr>
<tr class="even">
<td style="text-align: left;">Machin</td>
<td style="text-align: center;">Good</td>
<td style="text-align: center;">Good</td>
<td style="text-align: center;">-</td>
<td style="text-align: center;">-</td>
</tr>
<tr class="odd">
<td style="text-align: left;">Leibniz</td>
<td style="text-align: center;">Poor</td>
<td style="text-align: center;">Poor</td>
<td style="text-align: center;">-</td>
<td style="text-align: center;">-</td>
</tr>
<tr class="even">
<td style="text-align: left;">Euler</td>
<td style="text-align: center;">Poor</td>
<td style="text-align: center;">Poor</td>
<td style="text-align: center;">-</td>
<td style="text-align: center;">-</td>
</tr>
<tr class="odd">
<td style="text-align: left;"><strong>Gauss-AGM</strong></td>
<td style="text-align: center;">Average</td>
<td style="text-align: center;">Average</td>
<td style="text-align: center;"><strong>Y</strong></td>
<td style="text-align: center;">-</td>
</tr>
<tr class="even">
<td style="text-align: left;"><strong>Newton</strong></td>
<td style="text-align: center;">Good</td>
<td style="text-align: center;">Good</td>
<td style="text-align: center;">-</td>
<td style="text-align: center;">-</td>
</tr>
<tr class="odd">
<td style="text-align: left;">Archimedes</td>
<td style="text-align: center;">Average</td>
<td style="text-align: center;">Average</td>
<td style="text-align: center;">-</td>
<td style="text-align: center;">-</td>
</tr>
<tr class="even">
<td style="text-align: left;"><strong><em>Ramanujan</em></strong></td>
<td style="text-align: center;">Very Good</td>
<td style="text-align: center;">Very Good</td>
<td style="text-align: center;"><strong>Y</strong></td>
<td style="text-align: center;"><em>Y</em></td>
</tr>
<tr class="odd">
<td style="text-align: left;"><strong><em>Chudnovsky</em></strong></td>
<td style="text-align: center;">Good</td>
<td style="text-align: center;">Average</td>
<td style="text-align: center;"><strong>Y</strong></td>
<td style="text-align: center;"></td>
</tr>
<tr class="even">
<td style="text-align: left;"><strong><em>Plouffe</em></strong></td>
<td style="text-align: center;">Very Good</td>
<td style="text-align: center;">Very Good</td>
<td style="text-align: center;"><strong>Y</strong></td>
<td style="text-align: center;"><em>Y</em></td>
</tr>
<tr class="odd">
<td style="text-align: left;"><strong><em>Bellard</em></strong></td>
<td style="text-align: center;">Very Good</td>
<td style="text-align: center;">Very Good</td>
<td style="text-align: center;"><strong>Y</strong></td>
<td style="text-align: center;"><em>Y</em></td>
</tr>
</tbody>
</table>
<p>Algorithms shown in <strong>bold</strong> can be implemented again
for better results.</p>
<p>Algorithms shown in <em>italic</em> have been tested with
<em>gmp_printf()</em> to get rid of the 64-bit float limit.</p>
<section class="footnotes footnotes-end-of-document"
role="doc-endnotes">
<hr />
<ol>
<li id="fn1" role="doc-endnote"><p><a
href="/cms/2025-07-31-pi-computation-algorithms.html">Pi computation
algorithms - Monorailc.at</a><a href="#fnref1" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
<li id="fn2" role="doc-endnote"><p><a href="/data/diy/pi/pi.c.gz">Source
code</a> <a href="https://creativecommons.org/licenses/by-nc/4.0/">CC
BY-NC</a><a href="#fnref2" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
<li id="fn3" role="doc-endnote"><p>Long Bash command lines have been
trimmed to roughly fit 80 columns to improve readability. Backslashes at
the end of line aren’t mandatory.<a href="#fnref3" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
<li id="fn4" role="doc-endnote"><p>It’s not proper CSV since we’re using
<em>tabs</em> instead of <em>commas</em><a href="#fnref4"
class="footnote-back" role="doc-backlink">↩︎</a></p></li>
</ol>
</section>
]]>
		</summary>
	</entry>

	<entry>
		<title>Débimètre Bosch HFM</title>
		<link href="/cms/2025-08-13-d-bim-tre-bosch-hfm.html" />
		<updated>2025-08-13T23:00:00+02:00</updated>
		<id>https://monorailc.atoutput/cms/2025-08-13-d-bim-tre-bosch-hfm.html</id>
		<summary type="html"><![CDATA[<p>J’avais trouvé un débimètre en état inconnu dans la poubelle d’un
garage un peu particulier<a href="#fn1" class="footnote-ref" id="fnref1"
role="doc-noteref"><sup>1</sup></a>. Il vient d’une voiture Volkswagen
avec la version <strong>BKD</strong> du moteur 2L TDI (Pumpe-Düse, DOHC,
140 ch).</p>
<h1 id="description">Description</h1>
<p>Le débimètre est placé juste après le filtre à air, et mesure le
débit massique d’air absorbé par le moteur.</p>
<figure>
<img src="/data/diy/bosch_maf/vw_maf.png"
title="Débimètre monté sur un moteur diesel"
alt="Débimètre monté sur un moteur Diesel" />
<figcaption aria-hidden="true">Débimètre monté sur un moteur
Diesel</figcaption>
</figure>
<p>Cette mesure de débit d’air permet d’ajuster précisément la quantité
de carburant injectée, pour s’adapter à différentes conditions de
fonctionnement. Avec un moteur Diesel, l’utilité principale est d’éviter
d’injecter plus de carburant que nécessaire pendant les phases
transitoires, quand le turbo ne fournit pas encore la pression nominale,
et ainsi d’éviter de polluer inutilement.</p>
<p>Ce type de capteurs est parfois aussi monté sur des moteurs à
essence.</p>
<h1 id="documentation">Documentation</h1>
<p>D’après les documentations de Bosch<a href="#fn2"
class="footnote-ref" id="fnref2" role="doc-noteref"><sup>2</sup></a><a
href="#fn3" class="footnote-ref" id="fnref3"
role="doc-noteref"><sup>3</sup></a>, la référence <em>0 281 006 759</em>
est un modèle aftermarket. Il utilise un capteur HFM-7R5, avec
traitement de signal numérique et une sortie analogique compatible avec
les versions HFM-5 analogiques, plus anciennes.</p>
<p>On peut en voir plusieurs choses intéressantes :</p>
<ul>
<li>Connecteur à 5 pins</li>
<li>Tension d’alimentation : 8-17 V</li>
<li>Tension de référence : 5 V</li>
<li>Mesure de débit par <em>film chaud</em></li>
<li>Capteur de température optionnel</li>
<li>Technologie MEMS</li>
</ul>
<figure>
<img src="/data/diy/bosch_maf/hfm_layout.png"
title="Débimètre à film chaud MEMS" alt="Débimètre à film chaud MEMS" />
<figcaption aria-hidden="true">Débimètre à film chaud MEMS</figcaption>
</figure>
<h1 id="teardown">Teardown</h1>
<p>C’est un cylindre creux de 80mm de diamètre et 110mm de long, avec un
guide <em>venturi</em> de 35mm de diamètre.</p>
<figure>
<img src="/data/diy/bosch_maf/bosch_hfm_overview.jpg"
title="Débimètre Bosch HFM" alt="Débimètre Bosch HFM" />
<figcaption aria-hidden="true">Débimètre Bosch HFM</figcaption>
</figure>
<p>Les vis <em>Pentalobe</em> ne suffisent pas à nous empêcher d’accéder
au capteur.</p>
<figure>
<img src="/data/diy/bosch_maf/bosch_hfm_pentalobe.jpg"
title="Pentalobe screws" alt="Vis pentalobe" />
<figcaption aria-hidden="true">Vis pentalobe</figcaption>
</figure>
<figure>
<img src="/data/diy/bosch_maf/bosch_hfm_sensor.jpg"
title="Capteur Bosch HFM" alt="Capteur Bosch HFM" />
<figcaption aria-hidden="true">Capteur Bosch HFM</figcaption>
</figure>
<h1 id="test">Test</h1>
<p>La documentation d’un autre débimètre HFM-5 donne le brochage du
connecteur.</p>
<figure>
<img src="/data/diy/bosch_maf/hfm-5_pinouts.png"
title="Brochage Bosch HFM-5" alt="Brochage Bosch HFM-5" />
<figcaption aria-hidden="true">Brochage Bosch HFM-5</figcaption>
</figure>
<ol type="1">
<li>Capteur de température (non-présent)</li>
<li>+12V, alimentation</li>
<li>GND</li>
<li>+5V, référence</li>
<li>Signal</li>
</ol>
<p>On va construire un banc de test, avec un ventilateur qui force un
flux d’air dans le débimètre, à travers un guide en carton.</p>
<figure>
<img src="/data/diy/bosch_maf/measurement_setup.jpg"
title="Banc de test de débimètre" alt="Test de débimètre" />
<figcaption aria-hidden="true">Test de débimètre</figcaption>
</figure>
<p>Si on regarde les spécifications du ventilateur<a href="#fn4"
class="footnote-ref" id="fnref4" role="doc-noteref"><sup>4</sup></a>, on
peut remarquer 4.84~5.38 m³/min dans des conditions nominales, qui
correspondent à 334~371 kg/h.</p>
<p>Le moteur VW <em>BKD</em> est un moteur Diesel à 4 temps, qui aspire
idéalement un volume d’air correspondant à la moitié de sa cylindrée à
chaque rotation. Il y a aussi un turbo qui fournit une pression de 1
bar, ce qui correspond à un volume d’air deux fois plus élevé qu’à la
pression atmosphérique. Ce moteur a un régime maximal de 5’000 rpm.</p>
<p><math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>Q</mi><mi>m</mi></msub><mo>=</mo><mi>D</mi><mi>i</mi><mi>s</mi><mi>p</mi><mi>l</mi><mi>a</mi><mi>c</mi><mi>e</mi><mi>m</mi><mi>e</mi><mi>n</mi><mi>t</mi><mo>⋅</mo><mfrac><mrow><mi>r</mi><mi>e</mi><mi>v</mi></mrow><mn>2</mn></mfrac><mo>⋅</mo><mrow><mo stretchy="true" form="prefix">(</mo><msub><mi>P</mi><mrow><mi>A</mi><mi>t</mi><mi>m</mi></mrow></msub><mo>+</mo><msub><mi>P</mi><mrow><mi>B</mi><mi>o</mi><mi>o</mi><mi>s</mi><mi>t</mi></mrow></msub><mo stretchy="true" form="postfix">)</mo></mrow><mo>⋅</mo><msub><mi>D</mi><mrow><mi>A</mi><mi>i</mi><mi>r</mi></mrow></msub></mrow><annotation encoding="application/x-tex">
Q_m = Displacement \cdot \frac{rev}{2} \cdot (P_{Atm} + P_{Boost}) \cdot D_{Air}
</annotation></semantics></math></p>
<p><math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>Q</mi><mi>m</mi></msub><mo>=</mo><mn>2</mn><mo>⋅</mo><msup><mn>10</mn><mrow><mo>−</mo><mn>3</mn></mrow></msup><msup><mi>m</mi><mn>3</mn></msup><mo>⋅</mo><mfrac><mn>1</mn><mn>2</mn></mfrac><mo>⋅</mo><mn>5</mn><mi>′</mi><mn>000</mn><mi>R</mi><mi>P</mi><mi>M</mi><mo>⋅</mo><mn>60</mn><mi>m</mi><mi>i</mi><mi>n</mi><mi>/</mi><mi>h</mi><mo>⋅</mo><mrow><mo stretchy="true" form="prefix">(</mo><mn>1</mn><mo>+</mo><mn>1</mn><mo stretchy="true" form="postfix">)</mo></mrow><mi>b</mi><mi>a</mi><mi>r</mi><mo>⋅</mo><mn>1.15</mn><mi>k</mi><mi>g</mi><mi>/</mi><msup><mi>m</mi><mn>3</mn></msup></mrow><annotation encoding="application/x-tex">
Q_m = 2 \cdot 10^{-3} m^3 \cdot \frac{1}{2} \cdot 5&#39;000 RPM \cdot 60 min/h \cdot (1 + 1) bar \cdot 1.15 kg/m^3
</annotation></semantics></math></p>
<p><math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>Q</mi><mi>m</mi></msub><mo>=</mo><mn>690</mn><mi>k</mi><mi>g</mi><mi>/</mi><mi>h</mi></mrow><annotation encoding="application/x-tex">
Q_m = 690 kg/h
</annotation></semantics></math></p>
<p>Les ordres de grandeur correspondent : la pleine échelle du capteur
est de 850 kg/h, et notre ventilateur devrait fournir autour de 350
kg/h.</p>
<h2 id="fonctionnement">Fonctionnement</h2>
<p>On commence par clipser le débimètre et le ventilateur dans le guide
en carton pour observer ce que le capteur revoie.</p>
<p>On lit 0.99 V avec le ventilateur arrêté, et 2.54 V avec le
ventilateur tournant.</p>
<p>Le capteur et le système fonctionnent, on peut vérifier l’absence de
fuites et tester différentes configurations.</p>
<p>On remarque que les valeurs mesurées sont instables et que le
ventilateur consomme plus lorsqu’il souffle à travers le capteur plutôt
que lorsque il aspire. Il est possible qu’il y ait des turbulences. La
configuration typique aspire de l’air à travers le capteur, dans un long
conduit qui évite les turbulences.</p>
<h2 id="mesure-du-ventilateur">Mesure du ventilateur</h2>
<p>Le ventilateur est placé dans un conduit qui résiste à l’air, on ne
peut pas utiliser les valeurs nominales données par le constructeur<a
href="#fn5" class="footnote-ref" id="fnref5"
role="doc-noteref"><sup>5</sup></a>. On va aussi faire varier la vitesse
du ventilateur, or la relation entre le débit et la vitesse n’est pas
linéaire, ce qui rend les mesures indispensables.</p>
<p>On mesure la durée nécessaire au remplissage d’un sac étanche de
volume connu pour en déduire le débit du ventilateur.</p>
<figure>
<img src="/data/diy/bosch_maf/delta_ffb1212ehe_flow_vs_rpm.png"
title="Débit en fonction de la vitesse, ventilateur Delta FFB1212EHE"
alt="Ventilateur Delta FFB1212EHE, débit vs RPM" />
<figcaption aria-hidden="true">Ventilateur Delta FFB1212EHE, débit vs
RPM</figcaption>
</figure>
<h2 id="mesure-du-débimètre">Mesure du débimètre</h2>
<p>Le ventilateur est calibré, il ne reste plus qu’à noter les valeurs
mesurées par le capteur :</p>
<figure>
<img src="/data/diy/bosch_maf/bosch_0281006759_voltage_vs_flow.png"
title="Tension en fonction du débit mesuré, Débimètre Bosch 0 281 006 759"
alt="Débimètre Bosch 0 281 006 759, tension vs débit" />
<figcaption aria-hidden="true">Débimètre Bosch 0 281 006 759, tension vs
débit</figcaption>
</figure>
<p>La forme de la courbe correspond à celles données par tous les types
de capteurs <em>Bosch HFM-5</em><a href="#fn6" class="footnote-ref"
id="fnref6" role="doc-noteref"><sup>6</sup></a>.</p>
<h1 id="résultats">Résultats</h1>
<p>D’autres personnes ont déjà produit ce type d’expériences<a
href="#fn7" class="footnote-ref" id="fnref7"
role="doc-noteref"><sup>7</sup></a> pour corréler des capteurs entre
eux, et ils utilisent aussi un capteur <em>Bosch 0 281 006 759</em>.</p>
<p>Mes mesures correspondent partiellement, je pense que ma mesure de
débit du ventilateur est perfectible.</p>
<h1 id="compatibilité">Compatibilité</h1>
<p>Plusieurs capteurs semblent compatibles entre eux, d’après les sites
de vente de pièces de voitures :</p>
<ul>
<li>0 281 006 759</li>
<li>0 986 284 007</li>
<li>0 281 002 461</li>
<li><strong>0 280 218 008</strong><a href="#fn8" class="footnote-ref"
id="fnref8" role="doc-noteref"><sup>8</sup></a> caractéristiques très
proches</li>
</ul>
<h1 id="références">Références</h1>
<section class="footnotes footnotes-end-of-document"
role="doc-endnotes">
<hr />
<ol>
<li id="fn1" role="doc-endnote"><p><a
href="https://www.autohobby-muc.de/">Autohobbywerkstatt München
West</a><a href="#fnref1" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
<li id="fn2" role="doc-endnote"><p><a
href="https://www.boschaftermarket.com/xrm/media/images/country_specific/gb/parts_1/parts_pdfs/air_mass_meters_2pp_aug_2017_lr.pdf">Air
Mass Meters - Bosch aftermarket</a><a href="#fnref2"
class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn3" role="doc-endnote"><p>Bosch Automotive Handbook
11<sup>th</sup> edition, ISBN 978-1-119-91190-6, pages 1’746-1’749<a
href="#fnref3" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn4" role="doc-endnote"><p><a
href="https://www.delta-fan.com/Download/Spec/FFB1212EHE-F00.pdf">Delta
FFB1212EHE-F00 - Datasheet</a><a href="#fnref4" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
<li id="fn5" role="doc-endnote"><p><a
href="https://www.delta-fan.com/Download/Spec/FFB1212EHE-F00.pdf">Delta
FFB1212EHE-F00 - Datasheet</a><a href="#fnref5" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
<li id="fn6" role="doc-endnote"><p><a
href="https://www.farnell.com/datasheets/312695.pdf">Bosch senors</a>,
pages 56-57<a href="#fnref6" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
<li id="fn7" role="doc-endnote"><p><a
href="https://jsar.ftn.shu.bg/index.php/jsar/article/download/406/401/1664">Anaysis
of the characteristics of automotive airflow sensors - Journal
scientific and applied research, vol. 27, 2024</a><a href="#fnref7"
class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn8" role="doc-endnote"><p><a
href="https://www.farnell.com/datasheets/312695.pdf">Bosch senors</a>,
pages 56-57<a href="#fnref8" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
</ol>
</section>
]]>
		</summary>
	</entry>

	<entry>
		<title>Boite-à-gants Renault Mégane/Scénic</title>
		<link href="/cms/2025-08-08-boite---gants-renault-m-gane-sc-nic.html" />
		<updated>2025-08-08T17:00:00+02:00</updated>
		<id>https://monorailc.atoutput/cms/2025-08-08-boite---gants-renault-m-gane-sc-nic.html</id>
		<summary type="html"><![CDATA[<p>Ça fait plusieurs années que les charnières de la boite-à-gants de ma
voiture sont cassées et que j’aimerais les réparer.</p>
<h1 id="pièces-originales">Pièces originales</h1>
<p>La documentation de Renault donne deux références de charnières :</p>
<ul>
<li>77 01 204 548 “Hinge Kit ME”</li>
<li>77 01 206 200 “Hinge Kit ME”</li>
</ul>
<figure>
<img src="/data/diy/renault_glovebox/dialogys_boite-a-gants.png"
title="Détail des pièces de boite-à-gants"
alt="Détail des pièces de boite-à-gants" />
<figcaption aria-hidden="true">Détail des pièces de
boite-à-gants</figcaption>
</figure>
<p>Deux références compatibles correspondent à la pièce
<strong>[2]</strong> du schéma. La couleur du plastique semble
différente, mais cette pièce n’est pas visible quand la boite-à-gants
est fermée.</p>
<p>Les pièces originales sont encore fournies par Renault, mais à des
prix exagérés, je n’ai pas trouvé de refabrications tierces. J’ai
cherché ces pièces d’occasion : soit les charnières sont déjà cassées
avant même d’être démontées, soit elles ont été cassées par un démontage
peu soigneux.</p>
<figure>
<img src="/data/diy/renault_glovebox/7701204548.jpg"
title="Charnières neuves *77 01 204 548*"
alt="Charnières neuves 77 01 204 548" />
<figcaption aria-hidden="true">Charnières neuves <em>77 01 204
548</em></figcaption>
</figure>
<h1 id="réparation-temporaire">Réparation temporaire</h1>
<p>C’est gênant quand une boite-à-gants s’ouvre de façon imprévisible,
vibre en roulant, ou bien que le contact d’éclairage de boite-à-gants
vibre au point de fondre le fusible d’éclairage à force d’appels de
courant répétés.</p>
<p>Une solution simple consiste à retirer le cadre des charnières et
leur pivot, et placer une ficelle à la place des deux pivots et entre
les deux cadres de charnières. Il suffit ensuite de placer une cale en
carton pour limiter les vibrations.</p>
<h1 id="prototypes">Prototypes</h1>
<p>Les pièces originales sont fabriquées en Polycarbonate déjà fragile à
l’état neuf. Il est possible de les recoller, ça restera très fragile,
mais ça peut servir de gabarit pour mesurer.</p>
<p>On va commencer par fabriquer une pièce identique en carton, puis on
va itérer en les améliorant.</p>
<figure>
<img src="/data/diy/renault_glovebox/glovebox_hinges_prototypes.jpg"
title="Itérations de prototypes de charnières"
alt="Itérations de prototypes de charnières" />
<figcaption aria-hidden="true">Itérations de prototypes de
charnières</figcaption>
</figure>
<h1 id="réparation-finale">Réparation finale</h1>
<p>J’ai trouvé des chutes de <a
href="https://en.wikipedia.org/wiki/Polyoxymethylene">POM</a>, qui est
une matière plastique facile à usiner et avec un faible coefficient de
friction à sec.</p>
<p>On reproduit la forme du dernier prototype :</p>
<figure>
<img src="/data/diy/renault_glovebox/glovebox_final_parts.jpg"
title="Pièces finales" alt="Pièces finales" />
<figcaption aria-hidden="true">Pièces finales</figcaption>
</figure>
<p>Il ne reste plus qu’à assembler :</p>
<figure>
<img src="/data/diy/renault_glovebox/glovebox_assembly.jpg"
title="Assemblage des charnières" alt="Assemblage des charnières" />
<figcaption aria-hidden="true">Assemblage des charnières</figcaption>
</figure>
<figure>
<img src="/data/diy/renault_glovebox/glovebox_assembly2.jpg"
title="Assemblage des charnières" alt="Assemblage des charnières" />
<figcaption aria-hidden="true">Assemblage des charnières</figcaption>
</figure>
<h1 id="alternative">Alternative</h1>
<p>Entre temps, j’ai remarqué qu’<a
href="https://www.thingiverse.com/thing:6553190">une autre personne
avait eu le même problème</a>, et l’avait résolu de façon plus
furtive.</p>
<figure>
<img
src="/data/diy/renault_glovebox/3d_printed_glovebox_hinges_thingiverse.png"
title="Charnières imprimées en 3D" alt="Charnières imprimées en 3D" />
<figcaption aria-hidden="true">Charnières imprimées en 3D</figcaption>
</figure>
]]>
		</summary>
	</entry>

	<entry>
		<title>Pi computation algorithms</title>
		<link href="/cms/2025-07-31-pi-computation-algorithms.html" />
		<updated>2025-07-31T12:00:05+00:00</updated>
		<id>https://monorailc.atoutput/cms/2025-07-31-pi-computation-algorithms.html</id>
		<summary type="html"><![CDATA[<p>Last time I wrote a series of articles about comparing different
programming languages, by using an algorithm to compute an approximated
value of
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>π</mi><annotation encoding="application/x-tex">\pi</annotation></semantics></math>.</p>
<p>This time, I’m going to use the same programming language to compare
different algorithms, just to see if some need less iterations to
converge, or can have faster iterations.</p>
<p>Since I’m going to copy-paste some algorithms, and write some
exclusively from scratch, comparing the time it takes isn’t fair, so
we’re going to compare the number of lines and the execution times
instead.</p>
<p>As previously, the code is publicly available<a href="#fn1"
class="footnote-ref" id="fnref1" role="doc-noteref"><sup>1</sup></a>
under <a href="https://creativecommons.org/licenses/by-nc/4.0/">CC
BY-NC</a> license.</p>
<h1 id="algorithms">Algorithms</h1>
<h2 id="montecarlo">Montecarlo</h2>
<p>This algorithm has been described in a previous article<a href="#fn2"
class="footnote-ref" id="fnref2" role="doc-noteref"><sup>2</sup></a>,
using both C and Python languages.</p>
<h2 id="circle">Circle</h2>
<p>This algorithm has also been described in a previous article<a
href="#fn3" class="footnote-ref" id="fnref3"
role="doc-noteref"><sup>3</sup></a>, using most languages I’ve heard
of.</p>
<p>The idea is to compute
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>π</mi><annotation encoding="application/x-tex">\pi</annotation></semantics></math>
using the ratio of the area of a disc, and its radius squared. The
bigger the radius, the more accurate the approximation should be $S =
r^2 $, which gives us:</p>
<p><math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>π</mi><mo>=</mo><mfrac><mi>S</mi><msup><mi>r</mi><mn>2</mn></msup></mfrac></mrow><annotation encoding="application/x-tex">
\pi = \frac{S}{r^2}
</annotation></semantics></math></p>
<p>This is straightforward to translate to C:</p>
<pre><code>unsigned long count = 0;
int i, j;

for(i = -n; i &lt;= n; i++) {
    for(j = -n; j &lt;= n; j++) {
        if(i*i + j*j &lt; n*n) {
            count++;
        }
    }
}
return (double) count / (n*n);</code></pre>
<h3 id="sphere">Sphere</h3>
<p>Since we can compute
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>π</mi><annotation encoding="application/x-tex">\pi</annotation></semantics></math>
using a <em>disc</em>, why not compute the volume of a <em>sphere</em>.
It’s exactly the same idea with one more dimension.</p>
<p><math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>π</mi><mo>=</mo><mfrac><mn>3</mn><mn>4</mn></mfrac><mfrac><mi>V</mi><msup><mi>r</mi><mn>3</mn></msup></mfrac></mrow><annotation encoding="application/x-tex">
\pi = \frac{3}{4} \frac{V}{r^3}
</annotation></semantics></math></p>
<h3 id="n-sphere">N-Sphere</h3>
<p>Now that we started, why stop here? We can also compute the volume of
a <em>N-sphere</em>, actually a <em>N-Ball</em><a href="#fn4"
class="footnote-ref" id="fnref4" role="doc-noteref"><sup>4</sup></a><a
href="#fn5" class="footnote-ref" id="fnref5"
role="doc-noteref"><sup>5</sup></a>, and find
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>π</mi><annotation encoding="application/x-tex">\pi</annotation></semantics></math>
with a relation between its volume and its radius.</p>
<p>Finding the relation between the volume and the radius may not be
that straightforward, so we can split it for odd and even
dimensions:</p>
<p><math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>V</mi><mi>n</mi></msub><mo>=</mo><mrow><mo stretchy="true" form="prefix">{</mo><mtable><mtr><mtd columnalign="left"><mfrac><mn>1</mn><mrow><mrow><mo stretchy="true" form="prefix">(</mo><mfrac><mi>n</mi><mn>2</mn></mfrac><mo stretchy="true" form="postfix">)</mo></mrow><mi>!</mi></mrow></mfrac><mo>⋅</mo><msup><mi>π</mi><mfrac><mi>n</mi><mn>2</mn></mfrac></msup><mo>⋅</mo><msup><mi>R</mi><mi>n</mi></msup></mtd><mtd columnalign="left"><mrow><mtext mathvariant="normal">if </mtext><mspace width="0.333em"></mspace></mrow><mi>n</mi></mtd><mtd columnalign="left"><mtext mathvariant="normal">is even</mtext></mtd></mtr><mtr><mtd columnalign="left"><mfrac><msup><mn>2</mn><mfrac><mrow><mi>n</mi><mo>+</mo><mn>1</mn></mrow><mn>2</mn></mfrac></msup><mrow><mi>n</mi><mi>!</mi><mi>!</mi></mrow></mfrac><mo>⋅</mo><msup><mi>π</mi><mfrac><mrow><mi>n</mi><mo>−</mo><mn>1</mn></mrow><mn>2</mn></mfrac></msup><mo>⋅</mo><msup><mi>R</mi><mi>n</mi></msup></mtd><mtd columnalign="left"><mrow><mtext mathvariant="normal">if </mtext><mspace width="0.333em"></mspace></mrow><mi>n</mi></mtd><mtd columnalign="left"><mtext mathvariant="normal">is odd</mtext></mtd></mtr></mtable></mrow></mrow><annotation encoding="application/x-tex">
V_n =
\begin{cases}
    \frac{1}{(\frac{n}{2})!} \cdot \pi^{\frac{n}{2}} \cdot R^n &amp;\text{if } n &amp;\text{is even}\\
    \frac{2^{\frac{n+1}{2}}}{n!!} \cdot \pi^{\frac{n-1}{2}} \cdot R^n &amp;\text{if } n &amp;\text{is odd}
\end{cases}
</annotation></semantics></math></p>
<p>The algorithm contains sections of code that need to be broken down
into 3 functions:</p>
<ul>
<li><em>nsphere()</em>, gets all the parameters, counts the number of
p-dimensions elements in a p-sphere split into n along each dimension,
and computes
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>π</mi><annotation encoding="application/x-tex">\pi</annotation></semantics></math>
based on that count and coefficients shown above</li>
<li><em>compute_nd_sphere()</em>, recursive function that counts
elements by looping along one dimension, and calls itself for each lower
dimension</li>
<li><em>compute_1d_sphere()</em>, non-recursive function that only loops
once and is needed for all dimensions greater than one</li>
</ul>
<p>Here’s how the main compute function looks like. It calls itself for
each dimension, until it reaches the dimension 2, where it calls
<em>compute_1d_sphere()</em>.</p>
<pre><code>unsigned long compute_nd_sphere(int n, int carry, unsigned short dim) {
    unsigned long count = 0;
    int i;

    if(dim &lt; 2)
        return 0;
    if(dim == 2) {
        for(i = -n; i &lt;= n; i++)
            count += compute_1d_sphere(-n, n, i*i + carry);
    }
    if(dim &gt; 2) {
        for(i = -n; i &lt;= n; i++)
            count += compute_nd_sphere(n, i*i + carry, dim-1, opt);
    }
    return count;
}</code></pre>
<p><em>compute_1d_sphere()</em> is exactly the same, except that it only
sweeps along one dimension.</p>
<pre><code>unsigned long compute_1d_sphere(int start, int stop, int carry) {
    unsigned long count = 0;
    int i;
    for(i = start; i &lt;= stop; i++) {
        if(i*i + carry &lt; stop*stop)
            count++;
    }
    return count;
}</code></pre>
<h3 id="optimized-n-sphere">Optimized N-Sphere</h3>
<p>As we showed at the end of a previous article<a href="#fn6"
class="footnote-ref" id="fnref6" role="doc-noteref"><sup>6</sup></a>,
discs are symmetric around their center, and also along whichever axis
that cuts their center.</p>
<p>For convenience, we can cut a disk in 4 quadrants, compute the area
of one quadrant and multiply it by 4 to get the same result, using 4
times less computations.</p>
<p>A 3D-sphere can also be split in 8 quadrants, and going further, a
N-sphere can be split in
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><msup><mn>2</mn><mi>N</mi></msup><annotation encoding="application/x-tex">2^N</annotation></semantics></math>
quadrants.</p>
<pre><code>unsigned long compute_nd_sphere(int n, int carry, unsigned short dim, unsigned short opt) {
    unsigned long count = 0;
    int i;
    int start;
    if(opt == 1) {
        start = 1;

        if(dim &lt; 2)
            return 0;
        if(dim == 2) {
            for(i = start; i &lt;= n; i++)
                count += 4*compute_1d_sphere(1, n, i*i + carry);
        }
        if(dim &gt; 2) {
            for(i = start; i &lt;= n; i++)
                count += 2*compute_nd_sphere(n, i*i + carry, dim-1, opt);
        }
    }
    return count;
}</code></pre>
<p>The major difference compared to the previous function, is the
variable <em>start</em> that loops from <em>1</em> instead of
<em>-n</em>, meaning it halves the number of computations for each
dimension.</p>
<p>There’s one catch though. Counting discrete elements inside a shape
can get tricky. We need to make sure no element is forgotten or counted
twice.</p>
<p>On a disc, sweeping
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mn>4</mn><mo>⋅</mo><msup><mi>n</mi><mn>2</mn></msup></mrow><annotation encoding="application/x-tex">4 \cdot n^2</annotation></semantics></math>
elements is straightforward, however simplifying and swiping from 0 to n
on each axis means that each quadrant now overlaps, and swiping from 1
to n on each axis means that there’s a gap between each quadrant. The
solution is intuitive : just add a missing cross that goes from -n to n
on 2 axis, meaning
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mn>4</mn><mi>n</mi><mo>−</mo><mn>1</mn></mrow><annotation encoding="application/x-tex">4n-1</annotation></semantics></math>,
since we shouldn’t count the center twice.</p>
<figure>
<img src="/data/diy/pi/circle_opt.png"
title="Drawing showing quadrants overlap on a disc&lt;br/&gt;Green is computed area, Teal is copied, and Red needs to be computed separarely"
alt="Drawing showing quadrants overlap on a disc Green is computed area, Teal is copied, and Red needs to be computed separarely" />
<figcaption aria-hidden="true">Drawing showing quadrants overlap on a
disc<br/>Green is computed area, Teal is copied, and Red needs to be
computed separarely</figcaption>
</figure>
<p>Things start getting complex when adding dimensions. With a
3D-sphere, we need to add slices that have the shape of a disc.</p>
<p>A brain-twister that took some time to understand was to see that in
the same way as the area of a N-dimension rectangle<a href="#fn7"
class="footnote-ref" id="fnref7"
role="doc-noteref"><sup>7</sup></a>.</p>
<figure>
<img src="/data/diy/pi/binomial_coefficients.png"
title="A visualization of binomial coefficients in N-dimensions"
alt="A visualization of binomial coefficients in N-dimensions" />
<figcaption aria-hidden="true">A visualization of binomial coefficients
in N-dimensions</figcaption>
</figure>
<p>After some time, I found a generic formula that works with
N-dimensions, and a radius r:</p>
<p><math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>V</mi><mrow><mi>l</mi><mi>o</mi><mi>s</mi><mi>t</mi></mrow></msub><mrow><mo stretchy="true" form="prefix">(</mo><mi>N</mi><mo stretchy="true" form="postfix">)</mo></mrow><mo>=</mo><mi>N</mi><mo>⋅</mo><mi>V</mi><mrow><mo stretchy="true" form="prefix">(</mo><mi>N</mi><mo>−</mo><mn>1</mn><mo stretchy="true" form="postfix">)</mo></mrow><mo>+</mo><munderover><mo>∑</mo><mrow><mi>i</mi><mo>=</mo><mn>2</mn></mrow><mrow><mi>N</mi><mo>−</mo><mn>2</mn></mrow></munderover><mrow><mo stretchy="true" form="prefix">(</mo><mfrac linethickness="0"><mi>N</mi><mi>i</mi></mfrac><mo stretchy="true" form="postfix">)</mo></mrow><mo>⋅</mo><mi>V</mi><mrow><mo stretchy="true" form="prefix">(</mo><mi>i</mi><mo stretchy="true" form="postfix">)</mo></mrow><mo>+</mo><mn>2</mn><mo>⋅</mo><mi>N</mi><mo>⋅</mo><mi>r</mi><mo>−</mo><mn>2</mn><mo>⋅</mo><mi>N</mi><mo>+</mo><mn>1</mn></mrow><annotation encoding="application/x-tex">
V_{lost}(N) = N \cdot V(N-1) + \sum_{i=2}^{N-2} \binom{N}{i} \cdot V(i) + 2 \cdot N \cdot r - 2 \cdot N + 1
</annotation></semantics></math></p>
<h2 id="taylor">Taylor</h2>
<p>One way of computing
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>π</mi><annotation encoding="application/x-tex">\pi</annotation></semantics></math>
is to use trigonometric functions, especially
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>a</mi><mi>r</mi><mi>c</mi><mi>t</mi><mi>a</mi><mi>n</mi><mrow><mo stretchy="true" form="prefix">(</mo><mn>1</mn><mo stretchy="true" form="postfix">)</mo></mrow><mo>=</mo><mfrac><mi>π</mi><mn>4</mn></mfrac></mrow><annotation encoding="application/x-tex">arctan(1) = \frac{\pi}{4}</annotation></semantics></math>.
And since
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>a</mi><mi>r</mi><mi>c</mi><mi>t</mi><mi>a</mi><mi>n</mi><mrow><mo stretchy="true" form="prefix">(</mo><mi>x</mi><mo stretchy="true" form="postfix">)</mo></mrow></mrow><annotation encoding="application/x-tex">arctan(x)</annotation></semantics></math>
isn’t easy to use, we’ll approximate it using series of polynoms coming
from the <em>Taylor</em>/<em>McLaurin</em> method<a href="#fn8"
class="footnote-ref" id="fnref8"
role="doc-noteref"><sup>8</sup></a>.</p>
<p><math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>a</mi><mi>r</mi><mi>c</mi><mi>t</mi><mi>a</mi><mi>n</mi><mrow><mo stretchy="true" form="prefix">(</mo><mi>x</mi><mo stretchy="true" form="postfix">)</mo></mrow><mo>=</mo><munderover><mo>∑</mo><mrow><mi>n</mi><mo>=</mo><mn>0</mn></mrow><mo accent="false">∞</mo></munderover><mfrac><msup><mrow><mo stretchy="true" form="prefix">(</mo><mo>−</mo><mn>1</mn><mo stretchy="true" form="postfix">)</mo></mrow><mi>n</mi></msup><mrow><mn>2</mn><mi>n</mi><mo>+</mo><mn>1</mn></mrow></mfrac><msup><mi>x</mi><mrow><mn>2</mn><mi>n</mi><mo>+</mo><mn>1</mn></mrow></msup></mrow><annotation encoding="application/x-tex">
arctan(x) = \sum_{n=0} ^{\infty} \frac{(-1)^n}{2 n + 1} x^{2n+1}
</annotation></semantics></math></p>
<p>That makes it easy for
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>x</mi><mo>=</mo><mn>1</mn></mrow><annotation encoding="application/x-tex">x = 1</annotation></semantics></math>,
where
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>a</mi><mi>r</mi><mi>c</mi><mi>t</mi><mi>a</mi><mi>n</mi><mrow><mo stretchy="true" form="prefix">(</mo><mn>1</mn><mo stretchy="true" form="postfix">)</mo></mrow><mo>=</mo><mfrac><mi>π</mi><mn>4</mn></mfrac></mrow><annotation encoding="application/x-tex">arctan(1) = \frac{\pi}{4}</annotation></semantics></math>,
where we can simplify it and write it in C.</p>
<pre><code>unsigned long i;
int a = 1;
int b = 1;
double pi_4 = 0;
for(i = 0; i &lt; n; i++) {
    pi_4 += (double) a / (double) b;
    a = -a;
    b += 2;
}
return pi_4 * 4.0;</code></pre>
<p><em>a</em> is the numerator, which alternates between
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mo>+</mo><mn>1</mn></mrow><annotation encoding="application/x-tex">+1</annotation></semantics></math>
and
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mo>−</mo><mn>1</mn></mrow><annotation encoding="application/x-tex">-1</annotation></semantics></math>,
and <em>b</em> is the denominator, where we can translate
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mn>2</mn><mi>n</mi><mo>+</mo><mn>1</mn></mrow><annotation encoding="application/x-tex">2n+1</annotation></semantics></math>
by <em>starting with
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mn>1</mn><annotation encoding="application/x-tex">1</annotation></semantics></math>
and adding
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mn>2</mn><annotation encoding="application/x-tex">2</annotation></semantics></math>
for each iteration</em>.</p>
<p>Each iteration has one division, two sums and one sign change. This
takes very little computing power and is very fast. Though, it takes
lots of iterations to converge.</p>
<h2 id="machin">Machin</h2>
<p>Machin’s formula can be used with Taylor’s series<a href="#fn9"
class="footnote-ref" id="fnref9"
role="doc-noteref"><sup>9</sup></a>:</p>
<p><math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mfrac><mi>π</mi><mn>4</mn></mfrac><mo>=</mo><mi>a</mi><mi>r</mi><mi>c</mi><mi>t</mi><mi>a</mi><mi>n</mi><mrow><mo stretchy="true" form="prefix">(</mo><mn>1</mn><mo stretchy="true" form="postfix">)</mo></mrow><mo>=</mo><mn>4</mn><mo>⋅</mo><mi>a</mi><mi>r</mi><mi>c</mi><mi>t</mi><mi>a</mi><mi>n</mi><mrow><mo stretchy="true" form="prefix">(</mo><mfrac><mn>1</mn><mn>5</mn></mfrac><mo stretchy="true" form="postfix">)</mo></mrow><mo>−</mo><mi>a</mi><mi>r</mi><mi>c</mi><mi>t</mi><mi>a</mi><mi>n</mi><mrow><mo stretchy="true" form="prefix">(</mo><mfrac><mn>1</mn><mn>239</mn></mfrac><mo stretchy="true" form="postfix">)</mo></mrow></mrow><annotation encoding="application/x-tex">
\frac{\pi}{4} = arctan(1) = 4 \cdot arctan(\frac{1}{5}) - arctan(\frac{1}{239})
</annotation></semantics></math></p>
<p>Merging that with the Taylor series yields to:</p>
<p><math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mfrac><mi>π</mi><mn>4</mn></mfrac><mo>∼</mo><mn>4</mn><mo>⋅</mo><munderover><mo>∑</mo><mrow><mi>k</mi><mo>=</mo><mn>0</mn></mrow><mi>n</mi></munderover><mfrac><msup><mrow><mo stretchy="true" form="prefix">(</mo><mo>−</mo><mn>1</mn><mo stretchy="true" form="postfix">)</mo></mrow><mi>k</mi></msup><mrow><mrow><mo stretchy="true" form="prefix">(</mo><mn>2</mn><mi>k</mi><mo>+</mo><mn>1</mn><mo stretchy="true" form="postfix">)</mo></mrow><mo>⋅</mo><msup><mn>5</mn><mrow><mn>2</mn><mi>k</mi><mo>+</mo><mn>1</mn></mrow></msup></mrow></mfrac><mo>−</mo><munderover><mo>∑</mo><mrow><mi>k</mi><mo>=</mo><mn>0</mn></mrow><mi>n</mi></munderover><mfrac><msup><mrow><mo stretchy="true" form="prefix">(</mo><mo>−</mo><mn>1</mn><mo stretchy="true" form="postfix">)</mo></mrow><mi>k</mi></msup><mrow><mrow><mo stretchy="true" form="prefix">(</mo><mn>2</mn><mi>k</mi><mo>+</mo><mn>1</mn><mo stretchy="true" form="postfix">)</mo></mrow><mo>⋅</mo><msup><mn>239</mn><mrow><mn>2</mn><mi>k</mi><mo>+</mo><mn>1</mn></mrow></msup></mrow></mfrac></mrow><annotation encoding="application/x-tex">
\frac{\pi}{4} \sim 4\cdot \sum_{k=0} ^{n} \frac{(-1)^k}{(2 k + 1) \cdot 5^{2k+1}} - \sum_{k=0} ^{n} \frac{(-1)^k}{(2 k + 1) \cdot 239^{2k+1}}
</annotation></semantics></math></p>
<p>This can be translated to C:</p>
<pre><code>double machin(unsigned long n) {
    // Machin formula based on Taylor series 4*arctan(1/5) - arctan(1/239) = pi/4
    // unsigned long int is the limit
    unsigned long i;
    int a = -1;
    unsigned long int b = 0;
    unsigned long int c = 0;
    double pi_4 = 0;
    for(i = 0; i &lt; n; i++) {
        a = -a;
        b = pow(5, 2*i+1) * (2*i+1);
        c = pow(239, 2*i+1) * (2*i+1);
        pi_4 += 4.0 * (double) a / (double) b - (double) a / (double) c;
    }
    return pi_4 * 4.0;</code></pre>
<p>Except there’s a catch:
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><msup><mn>239</mn><mrow><mn>2</mn><mi>i</mi><mo>+</mo><mn>1</mn></mrow></msup><annotation encoding="application/x-tex">239^{2i+1}</annotation></semantics></math>
increases fast, and means that <em>c</em> will quickly overflow,
actually for
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>n</mi><mo>≥</mo><mn>5</mn></mrow><annotation encoding="application/x-tex">n \geq 5</annotation></semantics></math>.</p>
<h3 id="improved-resolution">Improved resolution</h3>
<p>Let’s try a way to use larger variables. The GMP library<a
href="#fn10" class="footnote-ref" id="fnref10"
role="doc-noteref"><sup>10</sup></a> seems to fit this use-case.</p>
<pre><code>unsigned long i;
int a = -1;
mpz_t b, c;
mpf_t pi_4, atan5, atan239;
mpz_inits(b, c);
mpf_init(atan5);
mpf_init(atan239);
mpf_init(pi_4);

for(i = 0; i &lt; n; i++) {
    a = -a;
    mpz_set_ui(b, 5);
    mpz_set_ui(c, 239);
    mpz_pow_ui(b, b, 2*i+1);
    mpz_pow_ui(c, c, 2*i+1);
    mpz_mul_ui(b, b, 2*i+1);
    mpz_mul_ui(c, c, 2*i+1);
    mpf_set_z(atan5, b);
    mpf_set_z(atan239, c);
    mpf_ui_div(atan5, 1, atan5);
    mpf_ui_div(atan239, 1, atan239);
    if(a == -1) {
        mpf_neg(atan5, atan5);
        mpf_neg(atan239, atan239);
    }
    mpf_mul_ui(atan5, atan5, 4);
    mpf_add(pi_4, pi_4, atan5);
    mpf_sub(pi_4, pi_4, atan239);
}
return 4.0 * mpf_get_d(pi_4);</code></pre>
<p>The code looks more difficult to read and is also more difficult to
write, but at least, it works for larger values of n.</p>
<h3 id="leibniz">Leibniz</h3>
<p>This is actually a specific case of the <em>Taylor</em> series. The
Leibniz formula<a href="#fn11" class="footnote-ref" id="fnref11"
role="doc-noteref"><sup>11</sup></a> is meant to be set to a specific
point, instead of an interval around a specific point, which yields:</p>
<p><math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>a</mi><mi>r</mi><mi>c</mi><mi>t</mi><mi>a</mi><mi>n</mi><mrow><mo stretchy="true" form="prefix">(</mo><mn>1</mn><mo stretchy="true" form="postfix">)</mo></mrow><mo>=</mo><munderover><mo>∑</mo><mrow><mi>n</mi><mo>=</mo><mn>0</mn></mrow><mo accent="false">∞</mo></munderover><mfrac><msup><mrow><mo stretchy="true" form="prefix">(</mo><mo>−</mo><mn>1</mn><mo stretchy="true" form="postfix">)</mo></mrow><mi>n</mi></msup><mrow><mn>2</mn><mi>n</mi><mo>+</mo><mn>1</mn></mrow></mfrac></mrow><annotation encoding="application/x-tex">
arctan(1) = \sum_{n=0} ^{\infty} \frac{(-1)^n}{2 n + 1}
</annotation></semantics></math></p>
<p>This time, it is translated to C in a more naive way.</p>
<pre><code>unsigned long i;
int a = -1;
double pi_4 = 0;
for(i = 0; i &lt; n; i++) {
    a *= -1;
    pi_4 += (double) a / (2*i + 1);
}
return pi_4 * 4.0;</code></pre>
<p>The numerator <em>a</em> is multiplied by
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mo>−</mo><mn>1</mn></mrow><annotation encoding="application/x-tex">-1</annotation></semantics></math>
each iteration, which is a more complex operation than simply switching
a sign. The numerator is computed for each iteration, including a
multiplication and a sum. Then, each terms are summed.</p>
<p>It should converge at the exact same rate, except that each iteration
will probably take more execution time, depending on the compiler’s
optimizations.</p>
<h2 id="euler">Euler</h2>
<p>Euler’s approach to the Basel problem<a href="#fn12"
class="footnote-ref" id="fnref12" role="doc-noteref"><sup>12</sup></a>
is a specific case of the Riemann Zeta function<a href="#fn13"
class="footnote-ref" id="fnref13"
role="doc-noteref"><sup>13</sup></a>.</p>
<p><math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mfrac><msup><mi>π</mi><mn>2</mn></msup><mn>6</mn></mfrac><mo>=</mo><munderover><mo>∑</mo><mrow><mi>n</mi><mo>=</mo><mn>1</mn></mrow><mo accent="false">∞</mo></munderover><mfrac><mn>1</mn><msup><mi>n</mi><mn>2</mn></msup></mfrac></mrow><annotation encoding="application/x-tex">
\frac{\pi^2}{6} = \sum_{n=1} ^{\infty} \frac{1}{n^2}
</annotation></semantics></math></p>
<p>We can simply write that in C:</p>
<pre><code>unsigned long int i;
double pi2_6 = 0;
for(i = 1; i &lt;= n; i++) {
    pi2_6 += 1.0 / (i*i);
}
return sqrt(6 * pi2_6);</code></pre>
<p>Each iteration has one multiplication, one division and one sum, that
should need little computing power.</p>
<p>We still need to be careful about the square root. Its execution
speed isn’t a serious issue since we only use it once. Floating-point
numbers<a href="#fn14" class="footnote-ref" id="fnref14"
role="doc-noteref"><sup>14</sup></a> limited accuracy can become an
issue, since LSBs are omited when the numbers become too large.</p>
<h2 id="gauss-legendre">Gauss-Legendre</h2>
<p>Let’s start with the <em>Arithmetic-Geometric Mean</em> (AGM), which
is a series that mixes a arithmetic mean and a geometric mean<a
href="#fn15" class="footnote-ref" id="fnref15"
role="doc-noteref"><sup>15</sup></a>, and converges relatively
quickly.</p>
<p>For two numbers,
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><msub><mi>a</mi><mn>0</mn></msub><annotation encoding="application/x-tex">a_0</annotation></semantics></math>
and
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><msub><mi>g</mi><mn>0</mn></msub><annotation encoding="application/x-tex">g_0</annotation></semantics></math>,
this yields to:</p>
<p><math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mo stretchy="true" form="prefix">{</mo><mtable><mtr><mtd columnalign="left"><msub><mi>a</mi><mrow><mi>n</mi><mo>+</mo><mn>1</mn></mrow></msub><mo>=</mo><mfrac><mn>1</mn><mn>2</mn></mfrac><mrow><mo stretchy="true" form="prefix">(</mo><msub><mi>a</mi><mi>n</mi></msub><mo>+</mo><msub><mi>g</mi><mi>n</mi></msub><mo stretchy="true" form="postfix">)</mo></mrow></mtd></mtr><mtr><mtd columnalign="left"><msub><mi>g</mi><mrow><mi>n</mi><mo>+</mo><mn>1</mn></mrow></msub><mo>=</mo><msqrt><mrow><msub><mi>a</mi><mi>n</mi></msub><mo>⋅</mo><msub><mi>g</mi><mi>n</mi></msub></mrow></msqrt></mtd></mtr></mtable></mrow><annotation encoding="application/x-tex">
\begin{cases}
a_{n+1} = \frac{1}{2} (a_n + g_n)\\
g_{n+1} = \sqrt{a_n \cdot g_n}
\end{cases}
</annotation></semantics></math></p>
<p>This has found its way into the <em>Gauss-Legendre algorithm</em><a
href="#fn16" class="footnote-ref" id="fnref16"
role="doc-noteref"><sup>16</sup></a>, using 1 and
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mfrac><mn>1</mn><msqrt><mn>2</mn></msqrt></mfrac><annotation encoding="application/x-tex">\frac{1}{\sqrt{2}}</annotation></semantics></math>
as parameters, as well as some other parameters.</p>
<p>This gives:</p>
<p><math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mo stretchy="true" form="prefix">{</mo><mtable><mtr><mtd columnalign="left"><msub><mi>a</mi><mn>0</mn></msub><mo>=</mo><mn>1</mn></mtd></mtr><mtr><mtd columnalign="left"><msub><mi>b</mi><mn>0</mn></msub><mo>=</mo><mfrac><mn>1</mn><msqrt><mn>2</mn></msqrt></mfrac></mtd></mtr><mtr><mtd columnalign="left"><msub><mi>t</mi><mn>0</mn></msub><mo>=</mo><mn>1</mn></mtd></mtr><mtr><mtd columnalign="left"></mtd></mtr><mtr><mtd columnalign="left"><msub><mi>a</mi><mrow><mi>n</mi><mo>+</mo><mn>1</mn></mrow></msub><mo>=</mo><mfrac><mn>1</mn><mn>2</mn></mfrac><mo>⋅</mo><mrow><mo stretchy="true" form="prefix">(</mo><msub><mi>a</mi><mi>n</mi></msub><mo>+</mo><msub><mi>b</mi><mi>n</mi></msub><mo stretchy="true" form="postfix">)</mo></mrow></mtd></mtr><mtr><mtd columnalign="left"><msub><mi>b</mi><mrow><mi>n</mi><mo>+</mo><mn>1</mn></mrow></msub><mo>=</mo><msqrt><mrow><msub><mi>a</mi><mi>n</mi></msub><mo>⋅</mo><msub><mi>b</mi><mi>n</mi></msub></mrow></msqrt></mtd></mtr><mtr><mtd columnalign="left"><msub><mi>t</mi><mrow><mi>n</mi><mo>+</mo><mn>1</mn></mrow></msub><mo>=</mo><msub><mi>t</mi><mi>n</mi></msub><mo>−</mo><mn>2</mn><mo>⋅</mo><mrow><mo stretchy="true" form="prefix">(</mo><mi>n</mi><mo>+</mo><mn>1</mn><mo stretchy="true" form="postfix">)</mo></mrow><mo>⋅</mo><msup><mrow><mo stretchy="true" form="prefix">(</mo><msub><mi>a</mi><mrow><mi>n</mi><mo>+</mo><mn>1</mn></mrow></msub><mo>−</mo><msub><mi>a</mi><mi>n</mi></msub><mo stretchy="true" form="postfix">)</mo></mrow><mn>2</mn></msup></mtd></mtr></mtable></mrow><annotation encoding="application/x-tex">
\begin{cases}
a_0 = 1\\
b_0 = \frac{1}{\sqrt{2}}\\
t_0 = 1\\
\\
a_{n+1} = \frac{1}{2} \cdot (a_n + b_n)\\
b_{n+1} = \sqrt{a_n \cdot b_n}\\
t_{n+1} = t_n - 2 \cdot (n+1) \cdot (a_{n+1} - a_n)^2
\end{cases}
</annotation></semantics></math></p>
<p>And eventually
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>π</mi><mo>∼</mo><mfrac><msup><mrow><mo stretchy="true" form="prefix">(</mo><msub><mi>a</mi><mi>n</mi></msub><mo>+</mo><msub><mi>b</mi><mi>n</mi></msub><mo stretchy="true" form="postfix">)</mo></mrow><mn>2</mn></msup><msub><mi>t</mi><mi>n</mi></msub></mfrac></mrow><annotation encoding="application/x-tex">\pi \sim \frac{(a_n + b_n)^2}{t_n}</annotation></semantics></math>.</p>
<pre><code>double arithmetic_geometric_mean(unsigned long n) {
    /*
    * https://rosettacode.org/wiki/Arithmetic-geometric_mean/Calculate_Pi#
    * https://en.wikipedia.org/wiki/Arithmetic%E2%80%93geometric_mean#The_number_%CF%80
    * https://mattbaker.blog/2024/03/14/pi-and-the-agm/
    */
    // n = 3
    unsigned long i;
    double olda;
    double a = 1.0;
    double b = sqrt(0.5);
    double t = 1.0;

    for(i = 1; i &lt;= n; i++) {
        olda = a;
        a = (a + b) / 2.0;
        b = sqrt(olda * b);
        t = t - 2.0*(i+1) * (a - olda)*(a - olda);
    }
    return (a + b)*(a + b) / t;
}</code></pre>
<p>That converges very fast, except there’s a similar issue as any other
algorithm that uses floating point numbers, that is the variable’s
limited accuracy.</p>
<p>For reference, the <em>Gauss-Legendre</em> algorithm is implemented
in the famous <em>Super PI</em><a href="#fn17" class="footnote-ref"
id="fnref17" role="doc-noteref"><sup>17</sup></a> program, which was
developped by <em>Professor Kanada</em>, and used as a FPU/RAM
benchmark.</p>
<h2 id="newton">Newton</h2>
<p>Its implementation is interesting, where the factorial function
increases very fast, meaning that overflows are unavoidable.</p>
<pre><code>unsigned long int i;
double pi_2 = 0;
for(i = 0; i &lt; n; i++) {
    pi_2 += pow(2, i) * pow(factorial((unsigned long) i), 2) / factorial((unsigned long) (2*i + 1));
}
return pi_2 * 2.0;</code></pre>
<p>In this case, it starts overflowing when trying to compute
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mn>21</mn><mi>!</mi></mrow><annotation encoding="application/x-tex">21!</annotation></semantics></math><a
href="#fn18" class="footnote-ref" id="fnref18"
role="doc-noteref"><sup>18</sup></a>.</p>
<p>Changing <em>long integers</em> to <em>long long integers</em> sounds
like a good idea. Except that won’t work here, on a 64-bit system, where
both are 64-bit words, meaning no difference at all.</p>
<h3 id="improved-resolution-1">Improved resolution</h3>
<p>This algorithm would probably work better with larger variables,
using the GMP library<a href="#fn19" class="footnote-ref" id="fnref19"
role="doc-noteref"><sup>19</sup></a>, for example.</p>
<pre><code>unsigned long int i;
// A = A*B;
// pi_2 = A / C;
mpz_t a, b, c;
mpf_t pi_a, pi_c, pi_2;
mpz_inits(a, b, c);
mpf_init(pi_a);
mpf_init(pi_c);
mpf_init(pi_2);
mpf_set_ui(pi_2, 0);

for(i = 0; i &lt; n; i++) {
    mpz_ui_pow_ui(a, 2, i);
    factorial__(b, i);
    mpz_pow_ui(b, b, 2);
    mpz_mul(a, a, b);
    factorial__(c, 2*i+1);
    mpf_set_z(pi_a, a);
    mpf_set_z(pi_c, c);
    mpf_div(pi_a, pi_a, pi_c);
    mpf_add(pi_2, pi_2, pi_a);
}
mpz_clears(a, b, c);
mpf_clear(pi_a);
mpf_clear(pi_c);
return mpf_get_d(pi_2)*2.0;</code></pre>
<p>The code is more difficult to read, however it clearly does what we
want without overflowing.</p>
<p>We’re using <em>mpz_t</em> as <em>large integer</em> and
<em>mpf_t</em> as <em>accurate float</em>, both types are from the GMP
library with their own arithmetic functions.</p>
<h2 id="archimedes">Archimedes</h2>
<p>This algorithm is similar to the one we called <em>circle</em>, where
we broke-down a disc into small squares, and counted the one which fit
into a circle.</p>
<p>Here, we use polygons instead. They are centered and fit into a
circle, and we can compute their circumference, and compare it to the
diameter of the circle.</p>
<p>Starting with a square should be self-explanatory, and increasing the
number of vertices should yield to better approximations of
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>π</mi><annotation encoding="application/x-tex">\pi</annotation></semantics></math>.</p>
<figure>
<img src="/data/diy/pi/archimedes.png"
title="Square, Octagon and 16-gon embedded in a circle"
alt="Square, Octagon and 16-gon embedded in a circle" />
<figcaption aria-hidden="true">Square, Octagon and 16-gon embedded in a
circle</figcaption>
</figure>
<p>We can translate that into C:</p>
<pre><code>unsigned int i;
double polygon_edge_sq = 2.0;
unsigned long polygon_sides = 4;
for(i = 0; i &lt; n; i++) {
    polygon_edge_sq = 2.0 - 2.0 * sqrt(1 - polygon_edge_sq / 4.0);
    polygon_sides *= 2;
}
return polygon_sides * (double) sqrt(polygon_edge_sq) / 2.0;</code></pre>
<p>However, we run into an issue, where the approximation gets worse for
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>n</mi><mo>≥</mo><mn>14</mn></mrow><annotation encoding="application/x-tex">n \geq 14</annotation></semantics></math>,
and fails for
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>n</mi><mo>≥</mo><mn>27</mn></mrow><annotation encoding="application/x-tex">n \geq 27</annotation></semantics></math>.
Respectively equivalent to polygons with
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msup><mn>2</mn><mn>15</mn></msup><mo>=</mo><mn>65</mn><mi>′</mi><mn>536</mn></mrow><annotation encoding="application/x-tex">2^15 = 65&#39;536</annotation></semantics></math>
and
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msup><mn>2</mn><mn>28</mn></msup><mo>=</mo><mn>536</mn><mi>′</mi><mn>870</mn><mi>′</mi><mn>912</mn></mrow><annotation encoding="application/x-tex">2^28 = 536&#39;870&#39;912</annotation></semantics></math>
vertices. We’re dealing with very numbers requiring accuracy, something
floating point variables aren’t good at storing<a href="#fn20"
class="footnote-ref" id="fnref20"
role="doc-noteref"><sup>20</sup></a>.</p>
<h3 id="improved-resolution-2">Improved resolution</h3>
<p>Let’s improve it, using the GMP library<a href="#fn21"
class="footnote-ref" id="fnref21"
role="doc-noteref"><sup>21</sup></a>.</p>
<pre><code>unsigned int i;
mpf_t polygon_edge_sq;
mpf_init(polygon_edge_sq);
mpf_t tmp;
mpf_init(tmp);
mpf_set_d(polygon_edge_sq, 2.0);

unsigned long polygon_sides = 4;
for(i = 0; i &lt; n; i++) {
    mpf_div_ui(tmp, polygon_edge_sq, 4);
    mpf_ui_sub(tmp, 1, tmp);
    mpf_sqrt(tmp, tmp);
    mpf_mul_ui(tmp, tmp, 2);
    mpf_ui_sub(polygon_edge_sq, 2, tmp);
    polygon_sides *= 2;
}
mpf_sqrt(polygon_edge_sq, polygon_edge_sq);
mpf_mul_ui(polygon_edge_sq, polygon_edge_sq, polygon_sides/2.0);
//gmp_printf(&quot;pi: %.16Ff\n&quot;, polygon_edge_sq);
return mpf_get_d(polygon_edge_sq);</code></pre>
<p>It now uses more accurate floating-point numbers with variable
mantissa/exponent so the approximation only gets worse for
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>n</mi><mo>≥</mo><mn>50</mn></mrow><annotation encoding="application/x-tex">n \geq 50</annotation></semantics></math>,
and fails for
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>n</mi><mo>≥</mo><mn>61</mn></mrow><annotation encoding="application/x-tex">n \geq 61</annotation></semantics></math>.</p>
<p>The slight downsides are that it’s more difficult to read and slower
to execute.</p>
<h2 id="ramanujan">Ramanujan</h2>
<p>The <em>Ramanujan-Sato<a href="#fn22" class="footnote-ref"
id="fnref22" role="doc-noteref"><sup>22</sup></a> series</em> is an
infinite sum of rational numbers that uses real coefficients to give
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mfrac><mn>1</mn><mi>π</mi></mfrac><annotation encoding="application/x-tex">\frac{1}{\pi}</annotation></semantics></math>.
One thing to note is that it’s from the
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><msup><mn>20</mn><mrow><mi>t</mi><mi>h</mi></mrow></msup><annotation encoding="application/x-tex">20^{th}</annotation></semantics></math>
century, shortly before computers were developped.</p>
<p><math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mfrac><mn>1</mn><mi>π</mi></mfrac><mo>=</mo><mfrac><mrow><mn>2</mn><mo>⋅</mo><msqrt><mn>2</mn></msqrt></mrow><msup><mn>99</mn><mn>2</mn></msup></mfrac><mo>⋅</mo><munderover><mo>∑</mo><mrow><mi>k</mi><mo>=</mo><mn>0</mn></mrow><mo accent="false">∞</mo></munderover><mfrac><mrow><mrow><mo stretchy="true" form="prefix">(</mo><mn>4</mn><mi>k</mi><mo stretchy="true" form="postfix">)</mo></mrow><mi>!</mi></mrow><mrow><mi>k</mi><msup><mi>!</mi><mn>4</mn></msup></mrow></mfrac><mfrac><mrow><mn>26390</mn><mi>k</mi><mo>+</mo><mn>1103</mn></mrow><msup><mn>396</mn><mrow><mn>4</mn><mi>k</mi></mrow></msup></mfrac></mrow><annotation encoding="application/x-tex">
\frac{1}{\pi} = \frac{2 \cdot \sqrt{2}}{99^2} \cdot \sum_{k=0}^{\infty} \frac{(4k)!}{k!^4} \frac{26390k + 1103}{396^{4k}}
</annotation></semantics></math></p>
<p>Since we see factorial and power operations that are likely to
overflow with 64-bit variables, it’s a good idea to start directly with
the <em>GMP</em><a href="#fn23" class="footnote-ref" id="fnref23"
role="doc-noteref"><sup>23</sup></a> library.</p>
<p>That converges very fast and gives 13 digits within 3 iterations,
where it reaches float’s minimum accuracy.</p>
<h2 id="chudnovsky">Chudnovsky</h2>
<p>The <em>Chudnovsky algorithm</em><a href="#fn24" class="footnote-ref"
id="fnref24" role="doc-noteref"><sup>24</sup></a> is an update over
<em>Ramanujan’s</em> algorithm, that’s still used for computing large
numbers of
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>π</mi><annotation encoding="application/x-tex">\pi</annotation></semantics></math>
digits using computers.</p>
<p><math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mfrac><mn>1</mn><mi>π</mi></mfrac><mo>=</mo><mn>12</mn><mo>⋅</mo><munderover><mo>∑</mo><mrow><mi>k</mi><mo>=</mo><mn>0</mn></mrow><mo accent="false">∞</mo></munderover><mfrac><mrow><msup><mrow><mo stretchy="true" form="prefix">(</mo><mo>−</mo><mn>1</mn><mo stretchy="true" form="postfix">)</mo></mrow><mi>k</mi></msup><mrow><mo stretchy="true" form="prefix">(</mo><mn>6</mn><mi>k</mi><mo stretchy="true" form="postfix">)</mo></mrow><mi>!</mi><mrow><mo stretchy="true" form="prefix">(</mo><mn>545</mn><mi>′</mi><mn>140</mn><mi>′</mi><mn>134</mn><mi>k</mi><mo>+</mo><mn>13</mn><mi>′</mi><mn>591</mn><mi>′</mi><mn>409</mn><mo stretchy="true" form="postfix">)</mo></mrow></mrow><mrow><mrow><mo stretchy="true" form="prefix">(</mo><mn>3</mn><mi>k</mi><mo stretchy="true" form="postfix">)</mo></mrow><mi>!</mi><msup><mrow><mo stretchy="true" form="prefix">(</mo><mi>k</mi><mi>!</mi><mo stretchy="true" form="postfix">)</mo></mrow><mn>3</mn></msup><msup><mrow><mo stretchy="true" form="prefix">(</mo><mn>640</mn><mi>′</mi><mn>320</mn><mo stretchy="true" form="postfix">)</mo></mrow><mrow><mn>3</mn><mi>k</mi><mo>+</mo><mn>3</mn><mi>/</mi><mn>2</mn></mrow></msup></mrow></mfrac></mrow><annotation encoding="application/x-tex">
\frac{1}{\pi} = 12 \cdot \sum_{k=0}^{\infty} \frac{ (-1)^k (6k)! (545&#39;140&#39;134k + 13&#39;591&#39;409) }{ (3k)!(k!)^3(640&#39;320)^{3k+3/2} }
</annotation></semantics></math></p>
<p>This is supposed to converge fast and be accurate<a href="#fn25"
class="footnote-ref" id="fnref25" role="doc-noteref"><sup>25</sup></a>,
except that my implementation stopped converging after reaching 7 digits
over 2 iterations.</p>
<h2 id="plouffe">Plouffe</h2>
<p>The <em>Bailey–Borwein–Plouffe formula</em><a href="#fn26"
class="footnote-ref" id="fnref26" role="doc-noteref"><sup>26</sup></a>
is also a modern algorithm based on an infinite sum of rational
numbers.</p>
<p><math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>π</mi><mo>=</mo><munderover><mo>∑</mo><mrow><mi>k</mi><mo>=</mo><mn>0</mn></mrow><mo accent="false">∞</mo></munderover><mfrac><mn>1</mn><msup><mn>16</mn><mi>k</mi></msup></mfrac><mrow><mo stretchy="true" form="prefix">(</mo><mfrac><mn>4</mn><mrow><mn>8</mn><mi>k</mi><mo>+</mo><mn>1</mn></mrow></mfrac><mo>−</mo><mfrac><mn>2</mn><mrow><mn>8</mn><mi>k</mi><mo>+</mo><mn>4</mn></mrow></mfrac><mo>−</mo><mfrac><mn>1</mn><mrow><mn>8</mn><mi>k</mi><mo>+</mo><mn>5</mn></mrow></mfrac><mo>−</mo><mfrac><mn>1</mn><mrow><mn>8</mn><mi>k</mi><mo>+</mo><mn>6</mn></mrow></mfrac><mo stretchy="true" form="postfix">)</mo></mrow></mrow><annotation encoding="application/x-tex">
\pi = \sum_{k=0}^{\infty} \frac{1}{16^k} (\frac{4}{8k+1} - \frac{2}{8k+4} - \frac{1}{8k+5} - \frac{1}{8k+6} )
</annotation></semantics></math></p>
<p>One interesting thing to note is that most terms are close to
negative powers of two, and if not, their bits aren’t spread apart. This
means that each partial sum can be accurate, even using standard
precision floating-point numbers<a href="#fn27" class="footnote-ref"
id="fnref27" role="doc-noteref"><sup>27</sup></a>. High resolution is
only needed when summing partial sums.</p>
<p>This reached 18 digits accuracy after 14 iterations.</p>
<h2 id="bellard">Bellard</h2>
<p><em>Bellard’s formula</em><a href="#fn28" class="footnote-ref"
id="fnref28" role="doc-noteref"><sup>28</sup></a> is an improvement over
the <em>Plouffe formula</em> that works in a similar way, using lots of
terms that are based on powers of 2.</p>
<p><math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>π</mi><mo>=</mo><mfrac><mn>1</mn><msup><mn>2</mn><mn>6</mn></msup></mfrac><munderover><mo>∑</mo><mrow><mi>k</mi><mo>=</mo><mn>0</mn></mrow><mo accent="false">∞</mo></munderover><mfrac><msup><mrow><mo stretchy="true" form="prefix">(</mo><mo>−</mo><mn>1</mn><mo stretchy="true" form="postfix">)</mo></mrow><mi>k</mi></msup><msup><mn>2</mn><mrow><mn>10</mn><mi>n</mi></mrow></msup></mfrac><mrow><mo stretchy="true" form="prefix">(</mo><mo>−</mo><mfrac><msup><mn>2</mn><mn>5</mn></msup><mrow><mn>4</mn><mi>k</mi><mo>+</mo><mn>1</mn></mrow></mfrac><mo>−</mo><mfrac><mn>1</mn><mrow><mn>4</mn><mi>k</mi><mo>+</mo><mn>3</mn></mrow></mfrac><mo>+</mo><mfrac><msup><mn>2</mn><mn>8</mn></msup><mrow><mn>10</mn><mi>n</mi><mo>+</mo><mn>1</mn></mrow></mfrac><mo>−</mo><mfrac><msup><mn>2</mn><mn>6</mn></msup><mrow><mn>10</mn><mi>n</mi><mo>+</mo><mn>3</mn></mrow></mfrac><mo>−</mo><mfrac><msup><mn>2</mn><mn>2</mn></msup><mrow><mn>10</mn><mi>n</mi><mo>+</mo><mn>5</mn></mrow></mfrac><mo>−</mo><mfrac><msup><mn>2</mn><mn>2</mn></msup><mrow><mn>10</mn><mi>n</mi><mo>+</mo><mn>7</mn></mrow></mfrac><mo>+</mo><mfrac><mn>1</mn><mrow><mn>10</mn><mi>n</mi><mo>+</mo><mn>9</mn></mrow></mfrac><mo stretchy="true" form="postfix">)</mo></mrow></mrow><annotation encoding="application/x-tex">
\pi = \frac{1}{2^6} \sum_{k=0}^{\infty} \frac{(-1)^k}{2^{10n}} ( -\frac{2^5}{4k+1} -\frac{1}{4k+3} + \frac{2^8}{10n+1} -\frac{2^6}{10n+3} -\frac{2^2}{10n+5} -\frac{2^2}{10n+7} +\frac{1}{10n+9} )
</annotation></semantics></math></p>
<p>This is even faster than <em>Plouffe’s formula</em>, where it reached
20 digits accuracy after 7 iterations.</p>
<h1 id="helping-functions">Helping functions</h1>
<p>Some of the previous algorithms require external functions that are
generic and can be reused.</p>
<p>Short functions can use the <em>inline</em> keyword<a href="#fn29"
class="footnote-ref" id="fnref29" role="doc-noteref"><sup>29</sup></a>,
meaning that the compiler will try to replace it in the code to avoid
function calls, in a way to improve performance, with depth and length
limitations.</p>
<h3 id="factorial">Factorial</h3>
<p>The <em>factorial</em> function is needed for <em>N-Sphere</em> and
<em>Newton</em> algorithms.</p>
<p>By definition,
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>n</mi><mi>!</mi><mo>=</mo><munderover><mo>∏</mo><mrow><mi>k</mi><mo>=</mo><mn>1</mn></mrow><mi>n</mi></munderover><mi>k</mi><mo>=</mo><mi>n</mi><mo>⋅</mo><mrow><mo stretchy="true" form="prefix">(</mo><mi>n</mi><mo>−</mo><mn>1</mn><mo stretchy="true" form="postfix">)</mo></mrow><mo>⋅</mo><mi>.</mi><mi>.</mi><mi>.</mi><mn>2</mn><mo>⋅</mo><mn>1</mn></mrow><annotation encoding="application/x-tex">n! = \prod\limits_{k=1}^{n} k = n \cdot (n-1) \cdot ... 2 \cdot 1</annotation></semantics></math>,
and
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mn>0</mn><mi>!</mi><mo>=</mo><mn>1</mn></mrow><annotation encoding="application/x-tex">0! = 1</annotation></semantics></math>.</p>
<h4 id="iterative">Iterative</h4>
<p>Let’s translate that in C with a loop:</p>
<pre><code>inline unsigned long factorial_(unsigned long n) {
    unsigned long fact = 1;
    unsigned long i = 0;
    for(i = n; i &gt; 0; i--) {
        fact *= i;
    }
    return fact;
}</code></pre>
<h4 id="recursive">Recursive</h4>
<p>We can also write it in this way, with a recursive function that
calls itself:</p>
<pre><code>inline unsigned long factorial(unsigned long n) {
    if(n &gt; 1)
        return n*factorial(n-1);
    if(n &lt;= 1)
        return 1;
    return 0;   // never happens
}</code></pre>
<p>The reason why both ways have been tried is to compare their
performances, where the recursive method is supposed to use more memory
space, but executes faster.</p>
<h3 id="double-factorial">Double Factorial</h3>
<p><em>Double Factorial</em> is called <em>Factorial2</em> here, to
avoid confusion with variable types. It’s very similar to
<em>factorial</em>, except that it skips evey second iteration:</p>
<p>By definition,
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>n</mi><mi>!</mi><mi>!</mi><mo>=</mo><mi>n</mi><mo>⋅</mo><mrow><mo stretchy="true" form="prefix">(</mo><mi>n</mi><mo>−</mo><mn>2</mn><mo stretchy="true" form="postfix">)</mo></mrow><mo>⋅</mo><mi>.</mi><mi>.</mi><mi>.</mi><mn>4</mn><mo>⋅</mo><mn>2</mn></mrow><annotation encoding="application/x-tex">n!! = n \cdot (n-2) \cdot ... 4 \cdot 2</annotation></semantics></math>
for even numbers,
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>n</mi><mi>!</mi><mi>!</mi><mo>=</mo><mi>n</mi><mo>⋅</mo><mrow><mo stretchy="true" form="prefix">(</mo><mi>n</mi><mo>−</mo><mn>2</mn><mo stretchy="true" form="postfix">)</mo></mrow><mo>⋅</mo><mi>.</mi><mi>.</mi><mi>.</mi><mn>3</mn><mo>⋅</mo><mn>1</mn></mrow><annotation encoding="application/x-tex">n!! = n \cdot (n-2) \cdot ... 3 \cdot 1</annotation></semantics></math>
for odd numbers, and
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mn>0</mn><mi>!</mi><mi>!</mi><mo>=</mo><mn>1</mn></mrow><annotation encoding="application/x-tex">0!! = 1</annotation></semantics></math>.</p>
<p>No need to compare recursive and iterative methods, let’s directly
write a recursive function:</p>
<pre><code>inline unsigned long int factorial2(unsigned long int n) {
    if(n &gt; 2)
        return n*factorial2(n-2);
    if(n &lt;= 2)
        return 1;
    return 0;   // never happens
}</code></pre>
<h3 id="binomial-coefficients">Binomial coefficients</h3>
<p>We need binomial coefficients<a href="#fn30" class="footnote-ref"
id="fnref30" role="doc-noteref"><sup>30</sup></a>,
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mrow><mo stretchy="true" form="prefix">(</mo><mfrac linethickness="0"><mrow><mi>n</mi><mi>k</mi></mrow><mo>=</mo></mfrac><mo stretchy="true" form="postfix">)</mo></mrow><mfrac><mrow><mi>n</mi><mi>!</mi></mrow><mrow><mrow><mo stretchy="true" form="prefix">(</mo><mi>n</mi><mo>−</mo><mi>k</mi><mo stretchy="true" form="postfix">)</mo></mrow><mi>!</mi></mrow></mfrac></mrow><annotation encoding="application/x-tex">\binom{n k} = \frac{n!}{(n-k)!}</annotation></semantics></math>,
and since we already have a factorial function, the code is super
easy:</p>
<pre><code>inline unsigned int binomialc(unsigned int n, unsigned int k) {
    return factorial(n)/(factorial(k)*factorial(n - k));
}</code></pre>
<h1 id="references">References</h1>
<section class="footnotes footnotes-end-of-document"
role="doc-endnotes">
<hr />
<ol>
<li id="fn1" role="doc-endnote"><p><a href="/data/diy/pi/pi.c.gz">Source
code</a> <a href="https://creativecommons.org/licenses/by-nc/4.0/">CC
BY-NC</a><a href="#fnref1" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
<li id="fn2" role="doc-endnote"><p><a
href="/cms/2025-04-22-comparaison-de-langages-de-programmation.html">Comparaison
de langages de programmation : Méthode Monte-Carlo</a><a href="#fnref2"
class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn3" role="doc-endnote"><p><a
href="/cms/2025-05-20-comparaison-de-langages-de-programmation--5----surface-d-un-disque.html">Comparaison
de langages de programmation (5) : Surface d’un disque</a><a
href="#fnref3" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn4" role="doc-endnote"><p><a
href="https://en.wikipedia.org/wiki/N-sphere">n-sphere - Wikipedia</a><a
href="#fnref4" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn5" role="doc-endnote"><p><a
href="https://en.wikipedia.org/wiki/Volume_of_an_n-ball">Volume of an
n-ball - Wikipedia</a><a href="#fnref5" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
<li id="fn6" role="doc-endnote"><p><a
href="/cms/2025-05-20-comparaison-de-langages-de-programmation--5----surface-d-un-disque.html">Comparaison
de langages de programmation (5) : Surface d’un disque</a><a
href="#fnref6" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn7" role="doc-endnote"><p><a
href="https://en.wikipedia.org/wiki/Pascal%27s_triangle">Pascal’s
triangle - Wikipedia</a><a href="#fnref7" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
<li id="fn8" role="doc-endnote"><p><a
href="https://en.wikipedia.org/wiki/Taylor_series#Trigonometric_functions">Taylor
series - Wikipedia</a><a href="#fnref8" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
<li id="fn9" role="doc-endnote"><p><a
href="https://en.wikipedia.org/wiki/Machin-like_formula#Derivation">Machin-like
formula - Wikipedia</a><a href="#fnref9" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
<li id="fn10" role="doc-endnote"><p><a
href="https://gmplib.org/manual/">The GNU Bignum Library</a><a
href="#fnref10" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
<li id="fn11" role="doc-endnote"><p><a
href="https://en.wikipedia.org/wiki/Leibniz_formula_for_%CF%80">Leibniz
formula for
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>π</mi><annotation encoding="application/x-tex">\pi</annotation></semantics></math>
- Wikipedia</a><a href="#fnref11" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
<li id="fn12" role="doc-endnote"><p><a
href="https://en.wikipedia.org/wiki/Basel_problem#Euler&#39;s_approach">Basel
problem - Wikipedia</a><a href="#fnref12" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
<li id="fn13" role="doc-endnote"><p><a
href="https://en.wikipedia.org/wiki/Riemann_zeta_function">Riemann zeta
function - Wikipedia</a><a href="#fnref13" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
<li id="fn14" role="doc-endnote"><p><a
href="https://en.wikipedia.org/wiki/Double-precision_floating-point_format#IEEE_754_double-precision_binary_floating-point_format:_binary64">Double-precision
floating-point format - Wikipedia</a><a href="#fnref14"
class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn15" role="doc-endnote"><p><a
href="https://en.wikipedia.org/wiki/Arithmetic%E2%80%93geometric_mean">Arithmetic–geometric
mean - Wikipedia</a><a href="#fnref15" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
<li id="fn16" role="doc-endnote"><p><a
href="https://en.wikipedia.org/wiki/Gauss%E2%80%93Legendre_algorithm">Gauss–Legendre
algorithm - Wikipedia</a><a href="#fnref16" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
<li id="fn17" role="doc-endnote"><p><a
href="https://en.wikipedia.org/wiki/Gauss%E2%80%93Legendre_algorithm">Gauss–Legendre
algorithm - Wikipedia</a><a href="#fnref17" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
<li id="fn18" role="doc-endnote"><p><a
href="https://en.wikipedia.org/wiki/Arbitrary-precision_arithmetic#History">Arbitrary-precision
arithmetic - Wikipedia</a><a href="#fnref18" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
<li id="fn19" role="doc-endnote"><p><a
href="https://gmplib.org/manual/">The GNU Bignum Library</a><a
href="#fnref19" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
<li id="fn20" role="doc-endnote"><p><a
href="https://en.wikipedia.org/wiki/Double-precision_floating-point_format#IEEE_754_double-precision_binary_floating-point_format:_binary64">Double-precision
floating-point format - Wikipedia</a><a href="#fnref20"
class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn21" role="doc-endnote"><p><a
href="https://gmplib.org/manual/">The GNU Bignum Library</a><a
href="#fnref21" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
<li id="fn22" role="doc-endnote"><p><a
href="https://en.wikipedia.org/wiki/Ramanujan%E2%80%93Sato_series">Ramanujan–Sato
series - Wikipedia</a><a href="#fnref22" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
<li id="fn23" role="doc-endnote"><p><a
href="https://gmplib.org/manual/">The GNU Bignum Library</a><a
href="#fnref23" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
<li id="fn24" role="doc-endnote"><p><a
href="https://en.wikipedia.org/wiki/Chudnovsky_algorithm">Chudnovsky
algorithm - Wikipedia</a><a href="#fnref24" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
<li id="fn25" role="doc-endnote"><p><a
href="https://www.craig-wood.com/nick/articles/pi-chudnovsky/">Pi -
Chudnovsky - Nick Craig-Wood</a><a href="#fnref25" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
<li id="fn26" role="doc-endnote"><p><a
href="https://en.wikipedia.org/wiki/Bailey%E2%80%93Borwein%E2%80%93Plouffe_formula">Bailey–Borwein–Plouffe
formula - Wikipedia</a><a href="#fnref26" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
<li id="fn27" role="doc-endnote"><p><a
href="https://en.wikipedia.org/wiki/Double-precision_floating-point_format#IEEE_754_double-precision_binary_floating-point_format:_binary64">Double-precision
floating-point format - Wikipedia</a><a href="#fnref27"
class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn28" role="doc-endnote"><p><a
href="https://en.wikipedia.org/wiki/Bellard%27s_formula">Bellard’s
formula - Wikipedia</a><a href="#fnref28" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
<li id="fn29" role="doc-endnote"><p><a
href="https://gcc.gnu.org/onlinedocs/gcc/Inline.html">An Inline Function
is As Fast As a Macro - GCC</a><a href="#fnref29" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
<li id="fn30" role="doc-endnote"><p><a
href="https://en.wikipedia.org/wiki/Pascal%27s_triangle">Pascal’s
triangle - Wikipedia</a><a href="#fnref30" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
</ol>
</section>
]]>
		</summary>
	</entry>



</feed>
