Mesure analogique et signal aléatoire

Bonjour à tous, je cherche à générer un signal qui soit vraiment aléatoire et non tiré à partir des randomseed classiques.
J’ai lu pas mal de choses sur les forums mais je ne suis pas électronicien alors quelques détails pratiques m’échappent. J’ai lu sur un post que quelqu’un avait des problèmes de mesure sur une voie analogique qui était non connectée. Je me dis que la mesure de bruit blanc est encore le meilleur moyen de générer un nombre aléatoire.
J’ai besoin d’avoir une valeur située entre 0 et environ 10000 toutes les secondes, je pense donc mesurer une broche analogique à vide et faire une opération sur la valeur obtenue. Si j’ai bien suivi on doit avoir une valeur comprise entre 0 et 1023, je pourrai alors la multiplier par 10.
Je n’ai pas le matériel sous la main mais j’essaye d’anticiper… est-ce que la fonction AnalogRead marche dans ce cas ou les valeurs mesurées sont elles trop faibles vu qu’on attend du 5V théoriquement ?
Pourquoi cette méthode qui parait simple n’est pas utilisée à la place de Random() qui n’est pas réellement aléatoire ?
Merci !

Le bruit que l'on peut récolter sur une entrée analogique est lié à son environnement et, pour tout aléatoire qu'il est, il n'est pas forcément blanc.

Ce qui est gênant avec ce type de bruit, est qu'il peut très bien dépasser la dynamique de l'entrée, auquel cas, la probabilité d'avoir uniquement une valeur max ou min est très forte.

Il peut tout aussi bien être faible et rester cantonné dans une plage restreinte de l'entrée, auquel cas, seulement quelques valeurs pourront être obtenues.

On est loin de l'aléatoire pur !

Cordialement.

Pierre.

La lecture risque d’être assez stable de seconde en seconde et en multipliant par 10 vous n’avez pas tous les nombres entre 0 et 10000…

Ce qui est fait classiquement c’est de passer le analogRead plus ou moins aléatoire comme point d’entrée de randomSeed. Ensuite la série arduino sera grosse modo aléatoire (mieux sur un esp32 que sur un avr) et vous aurez possiblement toutes les valeurs entre 0 et 10000 et pas juste des multiples de 10

Si vous rajoutez une RTC, l’heure actuelle unix être aussi utilisée comme seed au lancement ou la différence de temps depuis le dernier reboot (sauvé en eeprom)

Ok, j’y vois plus clair. Est-ce qu’un circuit électronique basique pourrait faire le job en se basant sur une entrée analogique et en amplifiant le signal dans une plage acceptable ? Après il faudrait que le signal soit convertible dans la plage [0;10000].

Si tu veux rester dans l’électronique pure, recherche du côté des générateurs de bruit blanc. Ça existe en électronique analogique.

De mémoire, mais ça date un peu, ça utilise une jonction (diode ou transistor) à la limite de sa tension de seuil.

Ensuite à toi de voir si tu as vraiment besoin d’un générateur aléatoire de très bonne qualité ou si un générateur imprévisible suffit.

Sinon la methode de von neumann peut etre une alternative

Bonne mémoire ! une jonction emetteur base de transistor , polarisée en inverse, génère du bruit
cette jonction se comporte comme une diode zener 'bruyante' d'environ 7V , selon le parametre VEB0 du transistor utilisé

Exmples réalisés par Sonelec :

https://sonelec-musique.com/electronique_realisations_gene_bruit_001.html

https://sonelec-musique.com/electronique_realisations_gene_bruit_002.html

1 Like

Si à la fin je dois mettre en forme un signal de bruit blanc pour qu’il entre dans une certaine plage de valeurs, la mesure brute d’une entrée analogique Arduino à vide n’est elle pas finalement suffisante ? Je me suis basé sur une chance sur 10000 en mesurant toutes les secondes, mais je peux aussi mesurer toutes les 10 sec sur une plage [0;1024]. Ça aurait du sens ?

void generateNoise(){
   unsigned long int newr;
   unsigned char lobit;
   unsigned char b31, b29, b25, b24;
   b31 = (reg & (1L << 31)) >> 31;
   b29 = (reg & (1L << 29)) >> 29;
   b25 = (reg & (1L << 25)) >> 25;
   b24 = (reg & (1L << 24)) >> 24;
   lobit = b31 ^ b29 ^ b25 ^ b24;
   newr = (reg << 1) | lobit;
   reg = newr;
   digitalWrite (speakerPin, reg & 1);
   delayMicroseconds (50);} // Changing this value changes the frequency.

J’ai trouvé ça sur le forum mais je ne comprends pas le code utilisé, c’est quoi cette fonction ´void’ ? On peut l’utiliser telle qu’elle ?
Je débute, on s’en serait douté…

C'est un générateur de séquence pseudo-aléatoire.
Un registre à décalage de 32 bits avec un OU exclusif des bits 31, 29, 25, 24 qui est réintroduits dans le LSB. Mais comme son nom l'indique cette séquence est pseudo-aléatoire, elle se répète à l'infini c'est un algorithme similaire qui est utilisé dans la librairie C.

Mes notions de probabilités sont moins et je n’ai jamais vraiment aimé ça…
Néanmoins (si un vrai matheux ou matheuse peut confirmer…) si les événements sont totalement indépendants, les probabilités s’additionnent.

La différence entre un générateur aléatoire et un pseudo aléatoire sera peut-être dans ce « totalement indépendants »

Je ne comprends pas vraiment. L'échantillonnage — que l'on va supposer aléatoire — donne une valeur entre 0 et 1023 (1024 possibilités). De quelle "chance" parlez vous ? (si c'est d'avoir une valeur "bonne" toutes les secondes, il vous faut un tirage par seconde).

Si vous utilisez une fonction déterministe (genre x10 etc) sur 1024 valeurs, vous ne conservez que 1024 possibilités et donc vous n'aurez jamais 10,000 possibilités.

Pour obtenir 10 000 possibilités de valeurs aléatoires à partir d'un générateur aléatoire qui en donne 1 024, on peut utiliser une approche d'expansion en prenant deux ou plusieurs sorties consécutives du générateur et les combiner pour augmenter le nombre de possibilités.

➜ Par exemple, avec deux sorties aléatoires que l'on multiplie cela donnerait 10242 = 1 048 576 combinaisons possibles. une fois qu'on est au de la de 10,000 on applique une fonction de réduction (l'idée est de répartir les 1 048 576 valeurs en 10 000 intervalles de taille égale et de sélectionner une valeur représentative pour chaque intervalle pour être equiprobable par exemple)

Une autre approche est d'utiliser la première valeur aléatoire comme seed d'un générateur pseudo-aléatoire à mémoire (qui utilise la valeur précédente pour fabriquer la suivante avec une suite algorithmique).

uint16_t getRandomSeed()
{
  uint16_t RandomSeed = 0;
  byte inc = 16;
  while (inc > 0) {
    byte Bit1 = analogRead(A0) & 0x01;
    byte Bit2 = analogRead(A0) & 0x01;
    if (Bit1 != Bit2) {
      RandomSeed = (RandomSeed << 1) | Bit1;
      inc--;
    }
  }
  return RandomSeed;
}

exécuter dans le setup et initialiser le générateur

randomSeed(getRandomSeed());

Il y a beaucoup de solution, le problème c'est qu'on ne connait pas le besoin.
Pour avoir une vrai séquence aléatoire il faut avoir recours à des moyens extérieurs (bruit d'une jonction électronique, bruit dans une résistance, comptage des événements de désintégration radioactive en utilisant un capteur de fumée, ....). Il y a de nombreux exemples sur la toile.
Tous les moyens utilisant un ATmega seul ne seront jamais complètement aléatoires.
En utilisant analogRead() sur une entrée en l'air on a toujours le risque que celle-ci se mettre en saturation, la capa d'entrée de l'échantillonneur bloqueur pouvant se charger et rester ainsi un bon moment si le milieu est "bruyant".
Si on utilise un événement aléatoire comme graine pour randomSeed() , comme proposé ci-dessus, on va initialiser une séquence pseudo-aléatoire dont la suite est prédictible puisque l'algorithme est connu (il suffit de chercher les sources de la librairie). randomSeed() ne faisant que déplacer le point de départ dans ladite séquence.

oui, c'est pseudo-aléatoire ➜ les nombres générés par random() sont "suffisamment aléatoires" pour des applications courantes sur Arduino, comme les jeux, les simulations simples, ou pour introduire de l'aléa dans des projets électroniques.

Ils ne sont pas assez robustes pour des applications nécessitant des caractéristiques de hasard très élevées comme les simulations scientifiques de haute précision ou la crypto.

Quel type de valeur ?
Entier ou réel ?
Si c'est une valeur entière il faudra 10 000 échantillons possibles.
Si c'est une variable réelle, ce sera un float en C, mais de combien de chiffres utiles derrière la virgule as-tu réellement besoin ?

À partir du nombre d'échantillons nécessaire, il est possible de déterminer le nombre de bits de l'ADC.
Valeur entière, 10 000 valeurs différentes, → ADC 14 bits minimum.

Les ADC des µC dépassent rarement 12 bits soit 4096 valeurs possibles.
Voila, tu as la réponse.

Mon impression est que quoi que tu fasses, tu buteras sur une quantification numérique forcément limitée en nombre de bits.
Le bruit blanc, c'est du bruit aléatoire, mais quand on veut en saisir une valeur instantanée, tu dépends des possibilités de l'instrument de mesure.
Le voltmètre a un pas de mesure, tu ne pourras obtenir qu'un sous-ensemble, non aléatoire puisque dépendant du voltmètre, de l'étendue des valeurs aléatoires.

La bonne question, mais aussi a plus difficile, est :
Pour ton projet, de combien de valeurs aléatoires as-tu réellement besoin.

On peux toujours faire un randomseed pseudo aleatoire avant chaque utilisation de random
Si le facteur temps n avpas d importance.
Et la c est plus vraiment previsible.

C'est moins prévisible qu'une série mathématique déterministe mais changer la seed à chaque tirage / fréquemment peut introduire des biais car les valeurs générées peuvent ne pas couvrir uniformément l'ensemble de la plage possible. (au final vous avez 1024 seeds et random() donnera toujours le premier élément de la série, donc que 1024 valeurs).

Pas sûr qu'on y gagne au niveau aléatoire.

Bien sur si on tire moins de valeur que le max possible on ne couvre pas toutes les valeurs
De même dans un tirage vraiment aleatoire d un nombre entre 1 et 1000000 la probabilité de tirer 2, 3 ou même 4 fois de suite le même nombre n est pas nulle

Apres les cours de stat ont pour moi plus de 45 ans ... ou même 50

pas sûr de comprendre exactement ce que vous voulez dire