filtrage par moyenne glissante

Portrait de mecano

Bonjour,
 j'essaie de mesurer un courant avec arduino et capteur ACS712 5A.
La mesure de courant est accompagnée par des perturbations (bruit).
pour obtenir un signal plus propre, j'essaie de  filtrer numériquement (passe-bas).
J'ai appliqué la méthode de la moyenne glissante pour le filtrage.
Mais les résultats ne sont pas transcendants.
Est ce que quelqu'un pourrait, svp, jeter un oeil sur le petit programme et donner un avis sur mon interprétation de la moyenne glissante?
Merci d'avance.
Bonne journée.

Programme capteur de courant

//declaration des constantes de broches
const int B_courant = A0;

//declaration des variables globales
int CAN_courant[6];

float moy_courant;
float U_courant;//(mv)
float K_capteur = 185; //(mv/A)
float I_courant;//(A)

//configuration intiale
void setup()
{
  Serial.begin(9600);
  pinMode(B_courant,INPUT);
    for (int i = 1 ; i<5; i++)
    {
      CAN_courant [i] = analogRead(B_courant);
      delay(2);
    }
}

//instructions en boucle
void loop()
{
  CAN_courant [5] = analogRead(B_courant);
  moy_courant = (CAN_courant[1]+CAN_courant[2]+CAN_courant[3]+CAN_courant[4]+CAN_courant[5])/5.0 ;
  
    for (int i=1 ; i<5 ; i++)
    {
      CAN_courant [i] = CAN_courant [i+1];
    }
  
   U_courant = (moy_courant/1024.0)*5000;
  I_courant = (U_courant - 2500)/K_capteur;
  
  //Serial.println("moy_courant =");
  Serial.println(moy_courant);
  //Serial.println("U_courant =");
  //Serial.println(U_courant,3);
  //Serial.println("I_courant=");
  //Serial.println(I_courant,3);
  delay(1);
}

Portrait de Walter

Salut, ton code est bon, si ce n'est que le premier indice d'un tableau est 0, du coup c'est dommage de créer un élément pour rien.

Quel est l'ordre de ton bruit ?
 

Portrait de mecano

Ok pour le tableau.

Concernant le bruit, je ne sais pas quel est son ordre, comment on le définit.

J'ai donc mis en fichier joint les acquisitions des courant à 2 échelles différentes.

ça devrait répondre à la question.

Portrait de Walter

Ba a vue de nez de tes graphes tu as 0.05A de bruit sur le 0 et un peu plus sur le 2A.
tes graphes c'est avec ton lissage ?

si tu arrondis a un chiffre après la virgule cela ne bouge pas temps que ça.
en quoi ce bruit te gêne ?

Portrait de mecano

Au départ je pensais que c'était assez lisse.

Mais j'essaie de faire un asservissement en courant (Imax=1A). Je n'ai jamais fait. La charge est composée d'une inductance et d'un rhéostat.

J'ai commencé par une correction proportionnelle. Et j'ai l'impression que ce bruit déstabilise l'asservissement. à Kp =20, ça ne va pas.

Donc j'ai limité à Kp=10, mais on voit des perturbations et l'écart avec la consigne est important.

Je pensais donc qu'en ayant un signal retour moins perturbé, je pourrais augmenter Kp.

Portrait de mecano

Bonjour,

J'ai poursuivi mes recherches. J'ai lu qu'on pouvait améliorer la moyenne glissante en ajoutant des coef. de Hanning ou Hamming.
Mais j'ai trouvé une autre méthode qui se comporte comme un filtre passe-bas du 1er ordre.
Moyenne mobile exponentielle. décrite sur un autre forum. 

https://www.developpez.net/forums/d1525028/general-developpement/program...

Elle semble se programmer facilement. Même si la définition de la fréquence de coupure n'est pas très claire pour moi. Je vais la tester.

Mais je n'avais pas saisi tout de suite tout ton message, Walter. Il est vrai qu'il suffit d'arrondir le résultat de la moyenne pour supprimer une bonne partie de ce bruit. Je vais le tester aussi. Ce sera peut-être suffisant d'ailleurs. Merci pour ton aide.

Portrait de mecano

Par contre, je pense que je me suis un peu emballé. (je me suis mis à l'arduino il y a 3 semaines).Je n'ai pas trouvé de fonction pour arrondir. Pour arrondir au dixieme, je pensais mutliplier un nombre float par 10, le convertir en entier, puis le diviser par 10. ça me paraît un peu usine à gaz. Est - ce qu'il existe, svp, une methode plus directe ?

Merci d'avance.

Portrait de Manoé

Mecano juste un petit truc, dans ton code tu fais un nombre de calcul qui ne sert pas à grand-chose si ce n'est répéter ce que tu as déjà calculé.

Je m'explique, lorsque tu as calculé la moyenne sur un panel de x valeurs, pour glisser avec une valeur supplémentaire il te suffit de d'additionner la dernière valeur à prendre en compte avec X-1 fois la moyenne précédente et de diviser cette somme par X ! Ceci pour augmenter le poids de la dernière moyenne calculée.

Soit Moyenne = la moyenne sur les 5 valeurs précédentes

NouvVal = la dernière valeur mesurée

Cela donne :

Moyenne =( NouvVal + moyenne x 4) / 5 je trouve que c'est plus simple et surtout plus rapide si ton module à d'autres valeurs à traiter.

En outre tu remarqueras que pour lisser beaucoup plus ta moyenne il te suffit de limiter la valeur de X à un nombre plus important sans pour cela augmenter le nombre de valeurs dans ton tableau, tu peux même moduler ce nombre par un système de switches ou même un potentiomètre !

De plus les quatre premières moyennes sont fausses puisque tu fais une moyenne avec des valeurs nulles

La solution en logique pure est :

X = 0
Boucle
  NouvVal
= Lit la valeur
  Si X < 5 alors
    X++
  Fin Si
  Moyenne = ((Moyenne * X-1) + NouvVal) / X
Fin Boucle

Ainsi le code me semble on ne peut plus simple et exact pour X < 5 premières valeurs (C'est important si la moyenne fait réagir des actionneurs par exemple !)

Pour ce qui est de l'arrondi il ne faut pas le faire si ce n'est à l'affichage car plus tu auras de décimales et plus ta moyenne sera précise.

Pour limiter le nombre de décimales à l'affichage il suffit de donner le nombre de décimales à afficher dans Serial.println ainsi :

float Pi = 3.1416;

Serial.println( Pi,1); // Donnera 3.1 !
Serial.println( Pi,2); // Donnera 3.14 !
Serial.println( Pi,3); // Donnera 3.142et oui tu auras même l'arrondi à la valeur supérieure !!!!!

Portrait de Walter

Ton algo calcule une moyenne sur tout les valeurs mesurées pas une moyenne flottante sur les 5 derniers.

Je ne suis pas d'accord, il ne faut pas faire un arrondis à l'affichage de debug(Serial.print), puisque dans ce cas la valeur que tu lis n'étant pas la valeur utilisée par l'algo elle perd de sa pertinance.
Soit tu as besoin de faire un arrondis aux n-ieme chiffre après la virgule, car cela étant du bruit, tu ne veux pas en tenir compte dans ton algo et donc ne fait pas partie de la précision, soit tu n'a pas besoin de l'arrondis.
Pour un affichage sur LCD ou uniquement comme témoin de l'ordre de valeur des valeurs utilisées par contre cela à tous sont sens.