Stocker un tableau de "float" en mémoire

Bonjour à tous et à toutes.

Tout d'abord, très belle année à vous.

Voici mon problème :

Je souhaiterais stocké un tableau de float dans la mémoire.

  • Quelle mémoire me direz-vous ?

Je ne sais pas encore justement.

Au vu de la taille du tableau : 500 valeurs (==> 4*500 = 2000 octets).

Je voulais le stocker dans la Flash mais je suis tombé sur cette phrase dans le site officiel qui m'a refroidie :

" Note: Flash (PROGMEM) memory can only be populated at program burn time. You can’t change the values in the flash after the program has started running. " (Ce qui est logic après tout !)

Concernant la EEPROM, quand je vois tout ce qu'il faut mettre en oeuvre pour stocker un int, ça ne me motive pas de faire une fonction pour stocker et lire un tableau de float de cette taille.

Il y aurait-il une solution plus simple à mettre en place ?

Je vous remercie.

Bonjour,

La question à se poser c'est pourquoi faire?

  • Est ce que ces données sont modifiables
  • Est ce que ces données doivent être lues séquentiellement ou aléatoirement
  • Est ce que ces données doivent persister à la mise hors tension
    ...

Quelle carte tu compte utiliser?

Bonjour

Est-ce que tes 500 float sont des valeurs constantes pré-déterminées ?

Si oui, aucun souci pour le stocker en flash ou en EEPROM (ce qui n'a vraiment rien de très compliqué).

Si non, par exemple si tes float sont le résultat d'une acquisition :
=> le plus simple est de passer sur une arduino MEGA qui dispose de 8 ko de RAM

L'EEPROM est envisageable si le nombre de réécritures est restreint, par exemple si tu réalises 10 mesures par jour et que tu veux conserver l'historique des mesures sur 50 jours glissants.

Autre possibilité : fichier log sur carte SD

Si tes floats sont corrélés entre eux, par exemple si la variation de l'un à l'autre est minime, il est peut-être possible de les compresser en modifiant la logique stockage, et de passer dans la ram d'une uno.

Ils correspondent à quoi ces float ?

Si jamais c'est un résultat de calcul effectué à partir de données binaires de moins de 32 bits (par ex lecture d'une température sur 12 bits via une sonde DS18b20, ou encore calcul à partir d'un analogRead à 10 bits), il serait bien plus futé de stocker les données source.

:slight_smile:

EEPROMex.h est ton amie

Combien de chiffre après la virgule? Pour 4 ou 5, peut être est il possible de multiplier par 1000 ou 10000 et de stocker un unsigned int.

Pour répondre à vos remarques et pour être plus précis, il s'agit en fait de stocker les valeurs d'un capteur de courant.

Je lis le courant d'un moteur DC et j'aimerais stocker l'évolution de ce courant afin de pouvoir l'afficher et l'analyser après extinction de ma carte.

J'utilise une Méga2560 et concernant l'EEPROM je sais que j'ai un peu de marge mais quand même, c'est beaucoup plus simple d'écrire et de lire dans la Flash (dommage :frowning: ).

Je vais voir ce qu'est EEPROMex.h (jamais entendu parler ^^ ).

Merci

J'insiste sur un point : si ton capteur de courant te délivre une tension analogique, que tu lis via un analogRead(), pas la peine de stocker un float. 10 bits suffisent et tu peux stocker trois fois plus de mesures.

bricoleau:
J'insiste sur un point : si ton capteur de courant te délivre une tension analogique, que tu lis via un analogRead(), pas la peine de stocker un float. 10 bits suffisent et tu peux stocker trois fois plus de mesures.

Oui, effectivement je peux stocker que les valeurs entières [0;500] puis faire la conversion après.
C'est une autre approche que je n'avais pas envisagé dans la mesure où je voulais stocker le "lissage" du courant lu mais je peux toujours appliquer l'algorithme de lissage après.

En parlant de lissage, j'ai jeté un oeil à cet algorithme https://www.arduino.cc/en/Tutorial/Smoothing et il y a une ligne que je ne comprends pas.
Celle là :

 // subtract the last reading:
  total = total - readings[readIndex];

Pourquoi cette soustraction ?

Personnellement je n'aurais fait qu'ajouter mes valeurs, puis fait ma moyenne à la fin.

Quelqu'un pourrait m'éclairer ?

Merci

pepe:
Dans l'exemple, on réalise la moyenne sur les dix dernières mesures. On doit donc retirer la onzième plus ancienne valeur mesurée à chaque ajout d'une nouvelle.

Dans le cas contraire, on calculerait une moyenne sur toutes les mesures effectuées depuis l'allumage de la carte, et au fil du temps la valeur des nouvelles mesures aurait une importance de plus en plus négligeable dans le résultat obtenu.

Je voyais ça comme ça mais pour ma part j'aurais mis cette ligne dans une condition sinon comment être sûr
que c'est tout le temps la 11e valeur qui sera soustraite ?

J'ai essayé de raisonner par coup d'horloge du microcontrôleur en partant des conditions initiales et c'est là que je bloque.

Voici le code :

const int numReadings = 10;

int readings[numReadings];      // the readings from the analog input
int readIndex = 0;              // the index of the current reading
int total = 0;                  // the running total
int average = 0;                // the average

int inputPin = A0;

void setup() {
  // initialize serial communication with computer:
  Serial.begin(9600);
  // initialize all the readings to 0:
  for (int thisReading = 0; thisReading < numReadings; thisReading++) {
    readings[thisReading] = 0;
  }
}

void loop() {
  // subtract the last reading:
  total = total - readings[readIndex];
  // read from the sensor:
  readings[readIndex] = analogRead(inputPin);
  // add the reading to the total:
  total = total + readings[readIndex];
  // advance to the next position in the array:
  readIndex = readIndex + 1;

  // if we're at the end of the array...
  if (readIndex >= numReadings) {
    // ...wrap around to the beginning:
    readIndex = 0;
  }
  // calculate the average:
  average = total / numReadings;
  // send it to the computer as ASCII digits
  Serial.println(average);
  delay(1);        // delay in between reads for stability
}

Voici mon raisonnement :

Au premier coup d'horloge on part des conditions initiales :
 total = total - readings[readIndex]; // total = 0 - readings[0] => total = 0
 readings[readIndex] = analogRead(inputPin); // readings[0]= 25 (par exemple)
 total = total + readings[readIndex]; // total = 0 + readings[0] <==> total=0+25 ==> total=25
 readIndex = readIndex + 1; //readIndex = 0+1 ==> readIndex = 1;

if (readIndex >= numReadings) { // condition fausse on passe à la ligne suivante
    // ...wrap around to the beginning:
    readIndex = 0;
  }
 average = total / numReadings; // average = 25/10 ==> average = 2 (car c'est un int)

// A ce stade  on a : 
// readIndex = 1; et readings[1] est inconnu = x
//total=25

// Au coup d'horloge suivant : 

total = total - readings[readIndex]; // total = 25 - readings[1] => total = 25 - x (c'est ça qui ne me va pas !)
 readings[readIndex] = analogRead(inputPin); // readings[1]= 18 (par exemple)
 total = total + readings[readIndex]; // total = (25 - x) + readings[1] <==> total=25-x+18 ==> total=43-x
 readIndex = readIndex + 1; //readIndex = 1+1 ==> readIndex = 2;

if (readIndex >= numReadings) { // condition fausse on passe à la ligne suivante
    // ...wrap around to the beginning:
    readIndex = 0;
  }
 average = total / numReadings; // average = (43-x)/10 ==> average = ? 

// A ce stade  on a : 
// readIndex = 2; et readings[2] est inconnu 
//total = 43-x !!!!!!!

Mon raisonnement est il faussé ?

pepe:
On utilise un tampon circulaire (readings[]) initialisé à 0.

  • Durant les dix premières boucles loop(), on "retire" donc juste une valeur 0 du tampon, et la moyenne passe progressivement de 0 à une valeur correspondant à la valeur moyenne réelle des mesures.
  • À partir de la onzième boucle loop(), on "retire" une valeur correspondant effectivement à une ancienne mesure, effectuée dix boucles plus tôt (puisqu'il y a exactement 10 valeurs stockées dans le tampon circulaire), et la moyenne est calculée sur 10 véritables mesures.

C'est plus compréhensible en raisonnant par boucle et non par coup d'horloge.

Je vais bidouiller un peu ce code pour mieux le comprendre.

Merco

Pour optimiser cette portion de code, utiliser une puissance de 2 pour le nombre d'échantillons (16 au lieu de 10 par exemple) ainsi la division peut-être réalisée avec des décalages (beaucoup plus rapide) Le compteur/index dans le tableau d'échantillons peut être borné par un & au lieu d'un test.

fdufnews:
Pour optimiser cette portion de code, utiliser une puissance de 2 pour le nombre d'échantillons (16 au lieu de 10 par exemple) ainsi la division peut-être réalisée avec des décalages (beaucoup plus rapide) Le compteur/index dans le tableau d'échantillons peut être borné par un & au lieu d'un test.

Ce que tu suggères c'est décaler juste l'index tous les 16 valeurs ? Au lieu de revenir à 0 et supprimer à jamais les valeurs du tableau (en remettant l'index à 0).
Mais du coup avec une puissance de 2, on ne perd pas en précision ?
Je comptais faire l'inverse, prendre 5 au lieu de 10 pour être 2 fois plus précis mais cela implique une certaine lenteur.