Quantum Analog Array :
réseau d’oscillateurs couplés pour recuit analogique
Construisez un réseau d’oscillateurs couplés, résolvez des problèmes d’optimisation (Max‑Cut, coloring, etc.) avec des composants de récupération.
Pas de cryogénie, pas de vide – seulement des amplis‑op, des résistances et un microcontrôleur.
Le Quantum Analog Array (QAA) est une machine de recuit analogique inspirée des Coherent Ising Machines. Chaque “qubit analogique” est un oscillateur électronique dont la phase (\(0^\circ\) ou \(180^\circ\)) représente un spin binaire. Les oscillateurs sont couplés entre eux via des interactions qui reproduisent un Hamiltonien d’Ising :
En laissant le système évoluer (recuit), il trouve spontanément une configuration de phases qui minimise l’énergie, ce qui correspond à la solution d’un problème d’optimisation combinatoire (Max‑Cut, coloration, factorisation, etc.).
Deux piles 9V en série : la jonction centrale = masse, les extrémités = +9V et -9V.
Ajoutez des condensateurs 100µF et 100nF pour filtrer.
Pour un premier prototype, l’oscillateur à pont de Wien est simple. Il produit une sinusoïde pure dont l’amplitude est contrôlable par un potentiomètre.
Composants par oscillateur (pont de Wien) :
- 1 ampli‑op (ex. TL082)
- 2 résistances R = 10 kΩ
- 2 condensateurs C = 10 nF
- 1 potentiomètre 10 kΩ en série avec R2 (contrôle amplitude)
- 1 résistance de contre‑réaction Rf = 22 kΩ
- Alim symétrique ±5V à ±12V
Fréquence : f = 1/(2πRC) ≈ 1,6 kHz.
Limites : le pont de Wien nécessite un réglage précis du gain et est sensible au bruit. Pour des résultats plus robustes (et une sortie quasi‑binaire), utilisez des oscillateurs à relaxation (astable à 555) ou des ring oscillators CMOS. Le couplage se fait alors par injection de courant ou portes XOR.
Un comparateur (LM339) transforme la sinusoïde en signal carré. En comparant avec une référence (oscillateur maître), on obtient le spin binaire (0° → +1, 180° → -1).
Sortie oscillateur → +IN comparateur
Référence (osc maître) → -IN comparateur
Sortie comparateur → GPIO (0 = phase 0°, 1 = phase 180°)
L’interaction \(J_{ij} s_i s_j\) s’obtient en multipliant les signaux des deux oscillateurs et en injectant le résultat (avec un signe contrôlé).
Schéma AD633 :
- Sortie A → X1, sortie B → Y1
- W = (X1*Y1)/10 + Z (Z = masse)
- W injecté via R_c dans l'entrée de l'oscillateur A.
Pour J négatif (antiferro), soustraire le signal (buffer inverseur).
Alternative low‑cost : Multiplieur de Gilbert à deux transistors (récupération dans vieilles cartes radio).
| Composant | Référence | Qté | Coût neuf (€) |
|---|---|---|---|
| Ampli‑op | TL084 (4 amplis) | 1 | 0,50 |
| Résistances | 10k, 22k, etc. | 30 | 2 |
| Condensateurs | 10nF, 100nF | 20 | 2 |
| Potentiomètres | 10k (amplitude) | 4 | 2 |
| Comparateurs | LM339 | 1 | 0,30 |
| Multiplicateurs | AD633 (ou fait maison) | 6 | 60 (ou 5) |
| Commutateurs | CD4051 | 2 | 1 |
| Microcontrôleur | ESP32 | 1 | 5 |
| Alim symétrique | ±12V (récupération) | 1 | 10 |
Total ~80€ neuf – bien moins avec de la récupération.
Le microcontrôleur exécute la séquence suivante (code fourni plus bas) :
annealSteps paliers (ex. 100).dwellTime ms.numRuns fois pour histogramme.Recuit avancé : On peut aussi faire une rampe sur la force de couplage (démarrage fort puis décroissant) ou injecter du bruit PWM via une diode Zener.
Problème : partitionner 4 sommets en deux groupes pour maximiser les arêtes coupées. Hamiltonien : \(H = - (s_1s_2 + s_2s_3 + s_3s_4 + s_4s_1)\). Les solutions sont 1010 et 0101.
Programmation des couplages : chaque arête correspond à un multiplicateur avec \(J=1\). Le recuit doit converger vers ces motifs.
Ce simulateur reproduit la dynamique réelle d’oscillateurs couplés. Chaque oscillateur \(i\) a une phase \(\theta_i\) évoluant selon :
\[ \frac{d\theta_i}{dt} = \omega_i + \sum_j J_{ij} \sin(\theta_j - \theta_i) + \text{bruit} \]Le spin binaire est \(s_i = \text{sign}(\cos \theta_i)\). L’énergie Ising est affichée en temps réel. Cliquez sur Lancer la simulation pour voir la convergence vers une configuration de phase (synchro/anti-synchro).
Énergie Ising : --
Spins : --
Remarque : Le modèle Kuramoto reproduit fidèlement la synchronisation progressive des oscillateurs. Observez comment les phases se verrouillent soit en phase (ferro) soit en opposition (antiferro) selon les couplages \(J_{ij}\).
Le code ci‑dessous pilote les potentiomètres numériques (MCP41xxx), les multiplexeurs CD4051, lit les comparateurs et exécute le recuit automatique. Adaptez les broches selon votre montage. Ce firmware correspond exactement à celui que vous avez fourni, avec une structure claire et commentée.
#include <SPI.h>
#define NUM_QUBITS 4 // Nombre d'oscillateurs (max 8)
#define POT_CS 5 // Chip select pour MCP41xxx (SPI)
#define SPI_SCK 18
#define SPI_MOSI 23
int phasePins[NUM_QUBITS] = {32, 33, 25, 26};
#define MUX_ADDR_A 13
#define MUX_ADDR_B 12
#define MUX_ADDR_C 14
#define MUX_INHIBIT 27
struct Coupling {
int i, j; // indices des qubits (0..NUM_QUBITS-1)
int muxChannel; // canal du CD4051 (0..7) associé
float strength; // force du couplage (0..1)
};
Coupling couplings[] = {
{0, 1, 0, 1.0},
{1, 2, 1, 1.0},
{2, 3, 2, 1.0},
{3, 0, 3, 1.0}
};
int numCouplings = sizeof(couplings) / sizeof(couplings[0]);
int initialAmplitude = 0; // 0 = amplitude minimale
int finalAmplitude = 255; // 255 = amplitude maximale
int annealSteps = 100; // nombre de paliers
int dwellTime = 10; // ms par palier
int numRuns = 100; // nombre de répétitions
void setPotentiometer(byte address, byte value) {
digitalWrite(POT_CS, LOW);
SPI.transfer(address);
SPI.transfer(value);
digitalWrite(POT_CS, HIGH);
}
void setAmplitude(int qubit, int value) {
// Supposons que chaque qubit a son propre potentiomètre MCP41xxx
setPotentiometer(qubit, value);
}
void setCoupling(int channel, float strength) {
// Active simplement le canal si strength > 0
digitalWrite(MUX_INHIBIT, LOW);
digitalWrite(MUX_ADDR_A, channel & 1);
digitalWrite(MUX_ADDR_B, (channel >> 1) & 1);
digitalWrite(MUX_ADDR_C, (channel >> 2) & 1);
// Pour un réglage analogique, ajouter une PWM ici
}
void initHardware() {
SPI.begin(SPI_SCK, -1, SPI_MOSI, POT_CS);
SPI.setDataMode(SPI_MODE0);
SPI.setClockDivider(SPI_CLOCK_DIV4);
pinMode(POT_CS, OUTPUT);
digitalWrite(POT_CS, HIGH);
for (int i = 0; i < NUM_QUBITS; i++) {
pinMode(phasePins[i], INPUT);
setAmplitude(i, initialAmplitude);
}
pinMode(MUX_ADDR_A, OUTPUT);
pinMode(MUX_ADDR_B, OUTPUT);
pinMode(MUX_ADDR_C, OUTPUT);
pinMode(MUX_INHIBIT, OUTPUT);
digitalWrite(MUX_INHIBIT, HIGH); // désactive tous les couplages
for (int c = 0; c < numCouplings; c++) {
setCoupling(couplings[c].muxChannel, couplings[c].strength);
}
}
uint8_t readPhases() {
uint8_t state = 0;
for (int i = 0; i < NUM_QUBITS; i++) {
if (digitalRead(phasePins[i]) == HIGH) {
state |= (1 << i);
}
}
return state;
}
uint8_t anneal() {
for (int i = 0; i < NUM_QUBITS; i++) {
setAmplitude(i, 0);
}
delay(50);
for (int step = 0; step <= annealSteps; step++) {
int amp = map(step, 0, annealSteps, initialAmplitude, finalAmplitude);
for (int i = 0; i < NUM_QUBITS; i++) {
setAmplitude(i, amp);
}
delay(dwellTime);
}
return readPhases();
}
void setup() {
Serial.begin(115200);
Serial.println("Quantum Analog Array Ready");
initHardware();
digitalWrite(MUX_INHIBIT, LOW);
}
void loop() {
int histogram[1 << NUM_QUBITS] = {0};
for (int run = 0; run < numRuns; run++) {
uint8_t state = anneal();
histogram[state]++;
Serial.print("Run ");
Serial.print(run);
Serial.print(": state = ");
for (int i = 0; i < NUM_QUBITS; i++) {
Serial.print((state >> i) & 1);
}
Serial.println();
delay(100);
}
Serial.println("\n=== Histogramme des résultats ===");
for (int s = 0; s < (1 << NUM_QUBITS); s++) {
if (histogram[s] > 0) {
for (int i = 0; i < NUM_QUBITS; i++) Serial.print((s >> i) & 1);
Serial.print(" : ");
Serial.println(histogram[s]);
}
}
Serial.println("Fin des tests");
while(1);
}
Connexions typiques : Voir le tableau plus haut. Adaptez les broches SPI (CS, SCK, MOSI) et les entrées des comparateurs. Pour plus de qubits, chaînez des MCP41xxx avec CS distincts.
Pour des performances dignes des publications 2025‑2026, remplacez les oscillateurs sinusoïdaux par :
Le code fourni reste compatible avec ces variantes (seule la partie analogique change).
| Critère | QAA (ce tuto) | Simulateur logiciel | D‑Wave | Ordinateur quantique |
|---|---|---|---|---|
| Coût | 50‑150€ | 0€ | ~15M$ (cloud) | 100M$+ |
| Température | Ambiante | – | 15 mK | 10 mK |
| Évolutivité DIY | 4‑32 spins | illimité | 5000 qubits | ~1000 qubits |
Vous avez désormais une feuille de route complète pour construire votre machine de recuit analogique. Le QAA est un outil pédagogique puissant, accessible et extensible. Partagez vos réalisations, améliorez le code et contribuez à l’open hardware !
➡️ Voir aussi l’introduction au calcul quantique (QuantumTam)