Existe-t-il des bibliothèques de lissage de signal pour Arduino?

14

Je travaille sur un robot mobile contrôlé via une liaison sans fil 2,4 GHz. Le récepteur est connecté à l'Arduino Uno qui sert à bord de contrôleur principal. Le canal d'entrée le plus critique (et principal) provenant du récepteur produit un signal très bruyant, ce qui entraîne de nombreux changements mineurs dans la sortie des actionneurs, même si ceux-ci ne sont pas nécessaires.

entrez la description de l'image ici
                    Tracé de l'entrée de l'Arduino dans un intervalle de 30 secondes.

Je recherche des bibliothèques pouvant effectuer un lissage efficace. Existe-t-il des bibliothèques de lissage de signal disponibles pour l'Arduino (Uno)?

asheeshr
la source
Je ne sais pas si vous pouvez trouver ce type de bibliothèques, mais je crains qu'elles n'aient besoin de beaucoup de puissance CPU pour un Arduino. Je préfère opter pour une solution électronique (filtre passe-bas) si possible.
jfpoilpret
Je suis avec jfpoilpret à ce sujet. Je pense que vous avez besoin d'une solution électronique. J'essaierais un condensateur de stabilisation (simple filtre passe-bas). Je suppose que vous utilisez un canal adc, vous devez donc mettre un plafond de ce canal à la terre. Commencez avec des valeurs autour de 100pf et continuez à partir de là.
John b

Réponses:

8

Microsmooth est une bibliothèque de lissage de signal léger actuellement en cours de développement par mes soins.

Il est toujours en cours d'élaboration et l'objectif est de le rendre léger en termes de mémoire et rapide. La bibliothèque propose plusieurs filtres pour le lissage:

  • Moyenne mobile simple
  • Moyenne mobile exponentielle
  • Moyenne mobile cumulative
  • Savitzky Golay Filter
  • Algorithme Ramer Douglas Pecker
  • Filtre Kalmogorov Zurbenko

Pour utiliser la bibliothèque, téléchargez-la et ajoutez-la au répertoire source. Ajoutez également la ligne suivante à votre fichier source:

#include "microsmooth.h"
asheeshr
la source
Salut, j'ai du mal à utiliser votre bibliothèque. Vous n'utiliseriez pas "Importer la bibliothèque ..." pour importer votre bibliothèque, n'est-ce pas? J'ai juste essayé de copier la source dans mon dossier .ino, mais j'obtiens des erreurs à propos de manquant automicrosmooth.h, Serial non défini et manquant ';'. Cette bibliothèque fonctionne-t-elle toujours? Merci
waspinator
@waspinator Désolé à ce sujet. Correction des erreurs. Merci pour les commentaires!
asheeshr
7

Je pense que je vois beaucoup de pics de bruit sur un seul échantillon dans votre signal bruyant.

Le filtre médian fait mieux pour se débarrasser des pics de bruit d'un seul échantillon que tout filtre linéaire. (Il est meilleur que n'importe quel filtre passe-bas, moyenne mobile, moyenne mobile pondérée, etc. en termes de temps de réponse et de capacité à ignorer de telles valeurs aberrantes de pic de bruit).

Il existe, en fait, de nombreuses bibliothèques de lissage de signal pour l'Arduino, dont beaucoup incluent un filtre médian.

bibliothèques de lissage du signal sur arduino.cc:

bibliothèques de lissage du signal sur github:

Est-ce que quelque chose comme ça fonctionnerait dans votre robot? (La médiane de 3 nécessite très peu de puissance CPU, et donc rapide):

/*
median_filter.ino
2014-03-25: started by David Cary
*/

int median_of_3( int a, int b, int c ){
    int the_max = max( max( a, b ), c );
    int the_min = min( min( a, b ), c );
    // unnecessarily clever code
    int the_median = the_max ^ the_min ^ a ^ b ^ c;
    return( the_median );
}

int newest = 0;
int recent = 0;
int oldest = 0;

void setup()
{
    Serial.begin(9600);
    // read first value, initialize with it.
    oldest = random(200);
    recent = oldest;
    newest = recent;
    Serial.println("median filter example: ");
}

void loop()
{
    // drop oldest value and shift in latest value
    oldest = recent;
    recent = newest;
    newest = random(200);

    Serial.print("new value: ");
    Serial.print(newest, DEC);

    int median = median_of_3( oldest, recent, newest );

    Serial.print("smoothed value: ");
    Serial.print(median, DEC);
    Serial.println("");

    delay(5000);
}
David Cary
la source
4

Avez-vous essayé un filtre passe-bas? J'ai trouvé un exemple ici et un autre ici .

Ces deux bibliothèques ont une liste de données lues à partir du capteur analogique de votre choix qui est moyennée. Chaque nouvelle valeur de capteur est ajoutée à la liste et la dernière est supprimée, comme ceci:

List: 3 4 3 3 4 3 5 3 2 3 4 3 
new reading added. old one thrown out
      /--                     /--
List: 5 3 4 3 3 4 3 5 3 2 3 4
list averaged
Le docteur
la source
À peu près ce que fait un simple filtre FIR avec toutes les valeurs de prises définies sur 1. Le fait de jouer avec les valeurs de prises peut améliorer encore le signal, mais nécessite des calculs plus élevés.
jippie
Remarque: Le deuxième lien calcule la moyenne mobile cumulée qui n'est pas un choix pratique pour la commande de l'actionneur, en particulier celle qui peut impliquer des démarrages et des arrêts fréquents. Le signal lissé suivra toujours la valeur de crête du signal réel d'une certaine marge.
asheeshr
2

Vous pouvez filtrer cela numériquement en utilisant un filtre passe-bas:

int valueFilt = (1-0.99)*value + 0.99*valueFilt;

Changez le 0.99 pour changer la fréquence de coupure (plus proche de 1.0 est une fréquence plus basse). L'expression réelle de cette valeur est exp (-2 * pi * f / fs) où f est la fréquence de coupure souhaitée et fs est la fréquence à laquelle les données sont échantillonnées.

Un autre type de "filtre numérique" est un filtre d'événements. Cela fonctionne bien sur les données qui ont des valeurs aberrantes; par exemple 9,9,8,10,9,25,9. Un filtre d'événements renvoie la valeur la plus fréquente. Statistiquement, c'est le mode.

Les moyennes statistiques telles que la moyenne, le mode, etc. peuvent être calculées à l'aide de la bibliothèque moyenne Arduino .

Un exemple tiré de la page de la bibliothèque Arduino fait référence à:

#include <Average.h>
#define CNT 600
int d[CNT];

void setup()
{
  Serial.begin(9600);
}

void loop()
{
  int i;

  for(i=0; i<CNT; i++)
  {
    d[i] = random(500);
  }  

  Serial.print("Mean: ");
  Serial.print(mean(d,CNT),DEC);
  Serial.print(" Mode: ");
  Serial.print(mode(d,CNT),DEC);
  Serial.print(" Max: ");
  Serial.print(maximum(d,CNT),DEC);
  Serial.print(" Min: ");
  Serial.print(minimum(d,CNT),DEC);
  Serial.print(" Standard deviation: ");
  Serial.print(stddev(d,CNT),4);
  Serial.println("");
  Serial.println("");

  delay(5000);
}
akellyirl
la source
1
Notez que cela sera très lent, car il effectue de nombreuses conversions implicites pour flotter et revenir.
Connor Wolf