J'ai environ 32 secondes de données d'accéléromètre d'un scénario de conduite de base sur des routes normales de 25 MPH, avec environ 7 nids de poule et un morceau de route accidenté. L'accéléromètre est monté sur le tableau de bord de ma voiture avec du ruban adhésif double face.
Problème: J'ai toutes les données bruyantes de l'accéléromètre et je dois trouver un moyen simple de détecter qu'un événement de nid-de-poule s'est produit. Vous trouverez ci-dessous plusieurs graphiques de données dans le domaine temporel et la FFT. L'accéléromètre mesure en GForce
Fondamentalement, je veux que mon arduino sache qu'un nid de poule s'est produit avec une assez grande précision et sans utiliser de mathématiques et de techniques de niveau supérieur.
L'accéléromètre échantillonné à 100 Hz a un simple filtre passe-bas RC 50 Hz sur l'axe Z
Here is the CSV data for the 32 seconds of accelerometer readings TIME, GFORCE format:
http://hamiltoncomputer.us/50HZLPFDATA.CSV
MISE À JOUR: Il s'agit de la bande passante RAW complète de l'accéléromètre 1000HZ échantillonné au taux d'échantillonnage le plus élevé que j'ai pu obtenir sur Arduino. Téléchargement direct de fichiers CSV: environ 112 secondes de données
http://hamiltoncomputer.us/RAWUNFILTEREDFULLBANDWIDTH500HZ.csv
La trace noire est des données d'accéléromètre RAW non filtrées: la trace bleue est filtrée par un filtre coupe-bande basé sur les fréquences extrêmes trouvées dans FFT, Dominate 2HZ et 12HZ.
L'événement de nid-de-poule ressemble à ceci dans le domaine temporel:
vous ne savez pas quel est le composant 10 à 15 Hz dans la FFT, est-ce le nid-de-poule réel, ou est-ce le saut de roue des roues contre la route, ou est-ce la fréquence de résonance de la voiture?
FFT:
semble que ce sont les événements réels des nids de poule, voici un HPF @ 13HZ Les caractéristiques dominantes des nids de poule semblent améliorées
Je veux pouvoir détecter et compter les nids de poule en temps réel
Il semble être contre-intuitif que la suspension devrait bouger beaucoup plus lentement qu'un 10 à 13 HZ qui provoquerait le mal des transports je crois
MISE À JOUR:
Selon les suggestions d'AngryEE, j'ai utilisé toute la bande passante de l'accéléromètre 1000HZ et la fréquence d'échantillonnage maximale que je pouvais obtenir sur l'arduino.
FFT:
voici un échantillon de données de l'événement de nid-de-poule et quelques bosses et le bruit de la route autour de lui:
Ajout du circuit détecteur d'enveloppe de diode, la sortie est la même ... L'accéléromètre produit toujours 0 à 3,3 Volts non négatifs ...
MISE À JOUR:
De nombreux essais routiers, je n'ai jamais dépassé 1,6G jusqu'à 45 MPH dans ma voiture sur l'axe Z, j'ai utilisé rand () pour générer une accélération pseudo-aléatoire Gforce.
Mon idée est que si je peux regarder des fenêtres de données de 1 à 3 secondes, je peux calculer le déplacement de l'axe Z, mais je m'inquiétais de la dérive de l'accéléromètre et des erreurs d'intégration. Je n'ai pas besoin d'être précis à 90% ici,> 70% serait bien, mais si je regarde le déplacement à une à trois secondes à la fois, serait-il possible de le faire en temps réel? De cette façon, je peux voir si le déplacement est supérieur à 1 pouce, 2 pouces, 5 pouces. Plus le déplacement était important, plus la bosse ou le nid de poule était rugueux:
Pouvez-vous vérifier si je fais cela correctement, j'ai essentiellement configuré sur mon bureau, en utilisant rand () pour générer une accélération aléatoire de -1,6 à 1,6 G, capturant 3 secondes de données @ un taux d'échantillonnage simulé de 50 Hz
Si comme vous exécutez * nix, j'utilise Sleep () à partir de Windows.h pour faire le retard de 20 ms, un taux d'échantillonnage de 50 Hz
Je voulais juste voir si le code vous convenait, je n'ai pas encore fait le tampon ciculaire, je suis un peu confus sur la façon de l'implémenter: le code commenté, vient de la classe sur laquelle je travaille , mais je ne le comprends pas encore à 100%. Un tampon circulaire permettrait de déplacer de façon contiguë des fenêtres de données non?
#include <cstdlib>
#include <iostream>
#include <iomanip>
#include <ctime> // USED BY RAND
#include <windows.h> // Used for delay
using namespace std;
#define SAMPLE_RATE 0.020 // Sample rate in Milliseconds
#define GRAVITYFT_SEC 32 // Gravity velocity 32 feet/sec
#define INCH_FOOT 12 // 12 inches in foot, from velocity to inch displacement calculation
int main(int argc, char *argv[])
{
srand((unsigned)time(0)); // SEED RAND() for simulation of Geforce Readings
// SIMULATING ACCELERATION READINGS INTO A CIRCULAR BUFFER
// circular_buffer Acceleration; // Create a new Circular buffer for Acceleration
// cb_init(&Acceleration, 150, 4); // Sampling @ 50HZ, 3 seconds of data = 150, size is float data of 4 bytes
//Simulate a sample run of Acceleration data using Rand()
// WE WILL BE SIMULATING "RANDOM" GEFORCE RATINGS using the rand() function constraining to -1.6 to 1.6 GFORCE
// These ratings are consistent with our road tests of apparently random vibration and Geforce readings not exceeding about 1.6 G's
float Gforce[150]; // Random Geforce for 3 second window of data
float velocity[150]; // Hold velocity information
float displacement[150]; // Hold Displacement information
float LO = -1.6; // Low GForce limit recorded from 6 road tests at different speeds
float HI = 1.6; // High GForce limit recorded from 6 road tests at different speeds
for(int i = 0; i < 150; i++) // 3 Second iwndow of random acceleration data
{
Gforce[i] = LO + (float)rand()/((float)RAND_MAX/(HI-LO)); // Borrowed from Stackexchange : http://stackoverflow.com/questions/686353/c-random-float
if( i == 0) // Initial values @ first Acceleration
{
velocity[i] = Gforce[i] * SAMPLE_RATE * GRAVITYFT_SEC; // Initial velocity
displacement[i] = velocity[i] * SAMPLE_RATE * INCH_FOOT; // Initial Displacement
}
else
{
velocity[i] = velocity[i-1] + (Gforce[i] * SAMPLE_RATE * GRAVITYFT_SEC); // Calculate running velocity into buffer
displacement[i] = displacement[i-1] +(velocity[i] * SAMPLE_RATE * INCH_FOOT); // Calculate running displacement into buffer
}
//cout << endl << Gforce[i]; // Debugging
//cb_push_back(&Acceleration, &Gforce[i]); // Push the GeForce into the circular buffer
Sleep(SAMPLE_RATE*1000); // 20mS delay simulates 50HZ sampling rate Sleep() expects number in mS already so * 1000
}
// PRINT RESULTS
for (int j = 0; j < 150; j++)
{
cout << setprecision (3) << Gforce[j] << "\t\t" << velocity[j] << "\t\t" << displacement[j] << endl;
}
// READ THE BUFFER
//cb_free(&Acceleration); // Pervent Memory leaks
system("PAUSE");
return EXIT_SUCCESS;
}
Exemple d'exécution:
GFORCE FT/SEC Inch Displacement Z axis
-0.882 -0.565 -0.136
0.199 -0.437 -0.24
-1.32 -1.29 -0.549
0.928 -0.691 -0.715
0.6 -0.307 -0.788
1.47 0.635 -0.636
0.849 1.18 -0.353
-0.247 1.02 -0.108
1.29 1.85 0.335
0.298 2.04 0.824
-1.04 1.37 1.15
1.1 2.08 1.65
1.52 3.05 2.38
0.078 3.1 3.12
-0.0125 3.09 3.87
1.24 3.88 4.8
0.845 4.42 5.86
0.25 4.58 6.96
0.0463 4.61 8.06
1.37 5.49 9.38
-0.15 5.39 10.7
0.947 6 12.1
1.18 6.75 13.7
-0.791 6.25 15.2
-1.43 5.33 16.5
-1.58 4.32 17.5
1.52 5.29 18.8
-0.208 5.16 20.1
1.36 6.03 21.5
-0.294 5.84 22.9
1.22 6.62 24.5
1.14 7.35 26.3
1.01 8 28.2
0.284 8.18 30.1
1.18 8.93 32.3
-1.43 8.02 34.2
-0.167 7.91 36.1
1.14 8.64 38.2
-1.4 7.74 40
-1.49 6.79 41.7
-0.926 6.2 43.2
-0.575 5.83 44.6
0.978 6.46 46.1
-0.909 5.87 47.5
1.46 6.81 49.2
0.353 7.04 50.8
-1.12 6.32 52.4
-1.12 5.6 53.7
-0.141 5.51 55
0.463 5.8 56.4
-1.1 5.1 57.6
0.591 5.48 59
0.0912 5.54 60.3
-0.47 5.23 61.5
-0.437 4.96 62.7
0.734 5.42 64
-0.343 5.21 65.3
0.836 5.74 66.7
-1.11 5.03 67.9
-0.771 4.54 69
-0.783 4.04 69.9
-0.501 3.72 70.8
-0.569 3.35 71.6
0.765 3.84 72.5
0.568 4.21 73.5
-1.45 3.28 74.3
0.391 3.53 75.2
0.339 3.75 76.1
0.797 4.26 77.1
1.3 5.09 78.3
0.237 5.24 79.6
1.52 6.21 81.1
0.314 6.41 82.6
0.369 6.65 84.2
-0.598 6.26 85.7
-0.905 5.68 87.1
-0.732 5.22 88.3
-1.47 4.27 89.4
0.828 4.8 90.5
0.261 4.97 91.7
0.0473 5 92.9
1.53 5.98 94.3
1.24 6.77 96
-0.0228 6.76 97.6
-0.0453 6.73 99.2
-1.07 6.04 101
-0.345 5.82 102
0.652 6.24 104
1.37 7.12 105
1.15 7.85 107
0.0238 7.87 109
1.43 8.79 111
1.08 9.48 113
1.53 10.5 116
-0.709 10 118
-0.811 9.48 121
-1.06 8.8 123
-1.22 8.02 125
-1.4 7.13 126
0.129 7.21 128
0.199 7.34 130
-0.182 7.22 132
0.135 7.31 133
0.885 7.87 135
0.678 8.31 137
0.922 8.9 139
-1.54 7.91 141
-1.16 7.16 143
-0.632 6.76 145
1.3 7.59 146
-0.67 7.16 148
0.124 7.24 150
-1.19 6.48 151
-0.728 6.01 153
1.22 6.79 154
-1.33 5.94 156
-0.402 5.69 157
-0.532 5.35 159
1.27 6.16 160
0.323 6.37 162
0.428 6.64 163
0.414 6.91 165
-0.614 6.51 166
1.37 7.39 168
0.449 7.68 170
0.55 8.03 172
1.33 8.88 174
-1.2 8.11 176
-0.641 7.7 178
-1.59 6.69 179
1.02 7.34 181
-0.86 6.79 183
-1.55 5.79 184
-0.515 5.46 186
0.352 5.69 187
0.824 6.22 188
1.14 6.94 190
-1.03 6.29 192
-1.13 5.56 193
0.139 5.65 194
0.293 5.84 196
1.08 6.53 197
-1.23 5.75 199
-1.1 5.04 200
-1.17 4.29 201
-0.8 3.78 202
-0.905 3.2 203
-0.0769 3.15 203
-0.323 2.95 204
-0.0186 2.93 205
Press any key to continue . . .
Réponses:
Il semble que cela puisse être résolu par un filtrage assez simple. Voici vos données d'origine:
C'est trop pour voir ce qui se passe dans un événement individuel au niveau de détail approprié pour ici. Voici juste les données du deuxième 26 au 28:
Au départ, j'avais pensé à filtrer le filtre passe-bas, mais cela ne fonctionne pas car il n'y a pas de signal basse fréquence. L'amplitude du signal haute fréquence augmente à la place. Voici un passe-bas superposé à l'original:
Remarquez que cela suit assez bien la "moyenne" du signal, pas pendant l'événement de nid-de-poule. Si nous soustrayons cette moyenne du signal d'origine, nous nous retrouvons avec des excursions beaucoup plus élevées de cette moyenne pendant l'événement qu'autrement. Autrement dit, ce que nous voulons vraiment, c'est un filtre passe-haut. Nous le ferons en soustrayant le passe-bas de l'original puisque c'est comme ça que nous sommes arrivés ici, mais dans un système de production, vous le feriez en filtrant explicitement le passe-haut. Quoi qu'il en soit, voici l'original filtré passe-haut:
Cela indique maintenant une approche évidente pour détecter l'événement. Il y a beaucoup plus d'amplitude du signal pendant l'événement qu'autrement. Nous pouvons détecter cela en calculant le RMS et en appliquant un filtrage passe-bas:
En zoomant sur l'ensemble des données, nous voyons:
Cela identifie clairement cinq événements dans les données, même si je ne sais pas si c'est ce que ces données sont censées montrer. En regardant les événements de plus près, vous remarquez que chacun d'eux a de faibles creux environ 1 seconde avant et après les pics. Cela signifie que davantage peut être fait si le simple seuillage du signal RMS tel qu'il est maintenant n'est pas suffisant. Par exemple, un algorithme simple qui recherchait la hauteur d'un point par rapport au plus bas en 1 seconde dans les deux sens devrait réduire davantage le bruit de fond. Une autre façon de dire la même chose est de différencier ce signal en recherchant la montée sur une période de 1 seconde. Un nid de poule serait alors détecté par un doublet, ce qui signifie un pic élevé suivi d'un pic faible.
Une autre façon de voir les choses est de passer la bande du signal RMS. Il est déjà filtré passe-bas, mais comme vous recherchez des événements soudains avec de fortes pentes, le fait de supprimer certaines des basses fréquences devrait également réduire le bruit de fond.
Il existe de nombreuses façons d'affiner le signal à partir d'ici, mais j'espère avoir montré comment obtenir au moins un premier résultat utile.
Ajoutée:
J'étais curieux de savoir comment la recherche de trempettes de chaque côté d'un pic fonctionnerait, alors je l'ai essayé. J'ai utilisé un filtre non linéaire en commençant par le RMS du tracé précédent. La valeur de chaque point est le minimum de combien il est au-dessus du point le plus bas dans la seconde précédente et le point le plus bas dans la seconde suivante. Le résultat semble assez bon:
Le plus faible des 5 pics est plus de 3 fois plus élevé que le bruit de fond le plus élevé. C'est bien sûr en supposant que ces 5 bosses représentent des événements que vous voulez détecter et le reste ne le fait pas.
Ajouté en réponse aux commentaires:
J'ai fait les filtres dans le domaine temporel, donc je ne connais pas directement la réponse en fréquence. Pour le filtre passe-bas, j'ai convolutionné le signal d'entrée avec un noyau de filtre COS ^ 2. Si je me souviens bien, le rayon (distance du centre au bord) du noyau est de quelques 100 ms. J'ai expérimenté la valeur jusqu'à ce que l'intrigue soit bonne. Pour filtrer passe-bas le RMS, j'ai utilisé le même noyau de filtre mais cette fois avec un rayon d'environ une seconde. Je ne me souviens pas exactement. Expérimentez jusqu'à obtenir de bons résultats.
Le filtre non linéaire n'a pas détecté de doublets. Comme je l'ai dit, j'ai trouvé la différence entre le point actuel et le plus bas de tous les points en 1 seconde avant, ainsi que la différence entre le point actuel et le plus bas de tous les points en 1 seconde après. Ensuite, j'ai pris le min de ces deux.
Le logiciel que j'ai utilisé était un programme que j'ai piraté à cet effet. J'avais déjà plusieurs routines pour lire et écrire des fichiers CSV, donc tout ce que j'avais à écrire était le code de filtrage, qui est très simple. Le reste a été fait avec des programmes préexistants que j'ai pour manipuler et tracer des fichiers CSV.
la source
Les nids-de-poule à détection de bord peuvent poser problème. L'enveloppe de vibration de la voiture est là où réside la réponse, car les vibrations réelles vues par le capteur sont à des fréquences beaucoup plus élevées. J'irais avec RMS vers DC qui répond à environ 15 Hz ou plus et passe la chose.
la source
Au lieu de chercher un filtre de domaine de fréquence ou un seuil, je recommande d'essayer de trouver un noyau pour un nid de poule "typique", et de faire une corrélation courante avec lui. Elle serait considérée comme une technique d'appariement de modèles et semblerait se prêter à une plate-forme de microcontrôleur.
Voir http://scribblethink.org/Work/nvisionInterface/vi95_lewis.pdf pour une revue rapide, et peut-être DOBBS, STEVEN E., NEIL M. SCHMITT et HALUK S. OZEMEK. "Détection QRS par correspondance de modèles à l'aide d'une corrélation en temps réel sur un micro-ordinateur." Journal of clinic engineering 9.3 (1984): 197-212.
Si vous étiez sur une plate-forme plus robuste, je recommanderais de faire tourner les ondelettes.
la source
Une autre approche consisterait à calculer une variance mobile de votre signal pour voir si les nids-de-poule dépassent vraiment. Voici une fonction matlab pour un filtre de variance mobile, N points large - intelligemment (si je dois le dire moi-même) en utilisant une convolution pour le calcul
la source
Ma pensée initiale est qu'un filtre passe-bas pourrait être le mauvais type de filtre à utiliser. Le nid-de-poule est essentiellement un événement à haute fréquence - comme une fonction de pas ou une onde carrée. Le simple fait de regarder les données filtrées à 50 Hz me fait penser que vous perdez les informations sur le nid-de-poule - tout cela ressemble aux mêmes gribouillis sans distinction significative pour l'événement de nid-de-poule. J'utiliserais d'abord un filtre passe-haut, puis un filtre passe-bas avec une fréquence beaucoup plus élevée. Vous pourriez éviter complètement le filtre passe-bas si votre accéléromètre est déjà filtré passe-bas.
Une fois que vous avez les données filtrées passe-haut, je pense qu'un simple comparateur avec un seuil défini de manière appropriée détectera les pics dans les données d'accélération causées par les nids de poule et vous permettra de les compter.
la source