Ich habe Beschleunigungsmesserdaten für ein grundlegendes Fahrszenario von 25 MPH auf normalen Straßen im Wert von 32 Sekunden zusammen mit etwa 7 Schlaglöchern und einem unebenen Straßenabschnitt. Der Beschleunigungsmesser ist mit doppelseitigem Klebeband am Armaturenbrett meines Autos angebracht.
Problem: Ich habe alle Daten, die vom Beschleunigungsmesser verrauscht sind, und ich muss auf einfache Weise feststellen, dass ein Schlaglochereignis aufgetreten ist. Nachfolgend sind einige Diagramme von Daten in Zeitdomäne und FFT aufgeführt. Der Beschleunigungsmesser misst in GForce
Grundsätzlich möchte ich, dass mein Arduino weiß, dass ein Schlagloch mit ziemlich großer Genauigkeit aufgetreten ist und keine Mathematik und Techniken auf Hochschulniveau verwendet.
Der bei 100 Hz abgetastete Beschleunigungsmesser verfügt über einen einfachen 50-Hz-RC-LOW-PASS-Filter auf der Z-Achse
Here is the CSV data for the 32 seconds of accelerometer readings TIME, GFORCE format:
http://hamiltoncomputer.us/50HZLPFDATA.CSV
UPDATE: Dies ist die RAW-Bandbreite des Beschleunigungsmessers 1000 Hz, abgetastet mit der höchsten Abtastrate, die ich auf Arduino bekommen konnte. Direkter Download der CSV-Datei: Ungefähr 112 Sekunden Daten
http://hamiltoncomputer.us/RAWUNFILTEREDFULLBANDWIDTH500HZ.csv
Schwarze Spur ist RAW-ungefilterte Beschleunigungsmesserdaten: Die blaue Spur wird von einem Bandsperrfilter basierend auf den Extremfrequenzen von FFT, Dominate 2HZ und 12HZ gefiltert.
Das Schlaglochereignis sieht im Zeitbereich so aus:
Sie sind sich nicht sicher, welche 10 bis 15 Hz-Komponente in der FFT enthalten ist, ist dies das eigentliche Schlagloch, oder ist es der Radsprung der Räder gegen die Straße, oder ist es die Resonanzfrequenz des Autos?
FFT:
Es scheint, als ob es sich um die tatsächlichen Schlaglochereignisse handelt. Hier ist ein HPF bei 13 Hz. Die dominanten Merkmale der Schlaglöcher scheinen verstärkt zu sein
Ich möchte Schlaglöcher in Echtzeit erkennen und zählen können
Es scheint kontraintuitiv zu sein, dass sich die Federung viel langsamer als 10 bis 13 Hz bewegen sollte, was meiner Meinung nach Reisekrankheit verursachen würde
AKTUALISIEREN:
Gemäß den Vorschlägen von AngryEE habe ich die volle Bandbreite des Beschleunigungsmessers 1000 Hz und die maximale Abtastrate verwendet, die ich auf dem Arduino erreichen konnte.
FFT:
Hier ist ein Beispiel von Daten des Schlaglochereignisses und einiger Unebenheiten und Straßengeräusche:
Die Diodenhüllkurvendetektorschaltung wurde hinzugefügt, der Ausgang sieht gleich aus ... Der Beschleunigungsmesser gibt immer 0 bis 3,3 Volt aus, nicht negativ ...
AKTUALISIEREN:
Bei vielen Straßentests habe ich 1,6 G bis zu 45 MPH in meinem Auto auf der Z-Achse nie überschritten. Ich habe rand () verwendet, um eine pseudozufällige Gforce-Beschleunigung zu generieren.
Meine Idee ist, wenn ich Datenfenster von 1 bis 3 Sekunden betrachten kann, die Verschiebung der Z-Achse berechnen kann, aber ich war besorgt über die Drift des Beschleunigungsmessers und über Fehler bei der Integration. Ich muss hier nicht einmal 90% genau sein,> 70% wären nett, aber wenn ich die Verschiebung mit ein bis drei Sekunden auf einmal betrachte, wäre das in Echtzeit möglich? Auf diese Weise kann ich sehen, ob der Versatz größer als 1 Zoll, 2 Zoll, 5 Zoll ist. Je größer die Verschiebung, desto rauer war die Erhebung oder das Schlagloch:
Kannst du überprüfen, ob ich das richtig mache? Ich habe es im Grunde genommen auf meinem Desktop eingerichtet und benutze rand (), um eine zufällige Beschleunigung von -1,6 auf 1,6 G zu erzeugen und 3 Sekunden Daten mit einer simulierten Abtastrate von 50 Hz zu erfassen
Wenn Sie * nix ausführen, verwende ich Sleep () von Windows.h, um die Abtastrate von 20 ms Verzögerung und 50 Hz zu ermitteln
Ich wollte nur sehen, ob der Code für Sie richtig aussieht. Ich habe noch keinen Cicular Buffer erstellt. Ich bin ein bisschen verwirrt darüber, wie er implementiert wird. Der auskommentierte Code stammt aus der Klasse, an der ich arbeite , aber ich verstehe es noch nicht 100%. Ein Ringpuffer würde es erlauben, Datenfenster zusammenhängend zu verschieben, oder?
#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;
}
Probelauf:
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 . . .
Antworten:
Dies kann anscheinend durch einfaches Filtern gelöst werden. Hier sind Ihre ursprünglichen Daten:
Das ist zu viel, um zu sehen, was in einer einzelnen Veranstaltung in der Detailtiefe vor sich geht, die hier angemessen ist. Hier sind nur die Daten von 26 bis 28 Sekunden:
Ich hatte ursprünglich gedacht, dies mit einem Tiefpassfilter zu filtern, aber das funktioniert nicht, weil dort kein Niederfrequenzsignal vorhanden ist. Die Amplitude des Hochfrequenzsignals steigt stattdessen an. Hier ist ein Tiefpass, der dem Original überlagert ist:
Beachten Sie, dass dies dem "Durchschnitt" des Signals ziemlich genau folgt, nicht während des Schlaglochereignisses. Wenn wir diesen Durchschnitt vom ursprünglichen Signal subtrahieren, verbleiben während des Ereignisses viel höhere Abweichungen von diesem Durchschnitt als sonst. Anders ausgedrückt: Was wir wirklich wollen, ist ein Hochpassfilter. Wir werden dies tun, indem wir den Tiefpass vom Original subtrahieren, da wir so hierher gekommen sind. In einem Produktionssystem würden Sie dies jedoch durch explizite Hochpassfilterung tun. Wie auch immer, hier ist das hochpassgefilterte Original:
Dies zeigt nun einen offensichtlichen Ansatz zum Erfassen des Ereignisses. Während des Ereignisses gibt es viel mehr Signalamplituden als sonst. Wir können dies erkennen, indem wir den Effektivwert berechnen und einige Tiefpassfilter anwenden:
Beim Zurückzoomen der gesamten Daten sehen wir:
Dadurch werden fünf Ereignisse in den Daten eindeutig identifiziert, obwohl ich nicht weiß, ob diese Daten dies anzeigen sollen. Wenn Sie sich die Ereignisse genauer ansehen, werden Sie feststellen, dass jedes Ereignis etwa 1 Sekunde vor und nach den Peaks niedrige Einbrüche aufweist. Dies bedeutet, dass mehr getan werden kann, wenn nur das Schwellensignal, wie es jetzt ist, nicht gut genug ist. Zum Beispiel sollte ein einfacher Algorithmus, der die Höhe eines Punktes relativ zum niedrigsten innerhalb von 1 Sekunde suchte, das Hintergrundrauschen weiter reduzieren. Eine andere Möglichkeit, das Gleiche zu sagen, besteht darin, dieses Signal zu differenzieren und nach dem Anstieg über einen Zeitraum von 1 Sekunde zu suchen. Ein Schlaglochereignis würde dann von einem Dublett erfasst, was bedeutet, dass ein hoher Peak gefolgt von einem niedrigen Peak.
Eine andere Betrachtungsweise besteht darin, das RMS-Signal im Band durchzulassen. Es ist bereits tiefpassgefiltert, aber da Sie nach plötzlichen Ereignissen mit starken Steigungen suchen, sollten einige der tiefen Frequenzen abgeschwächt werden, um auch die Hintergrundgeräusche zu reduzieren.
Es gibt viele Möglichkeiten, das Signal von hier aus zu verfeinern, aber ich habe hoffentlich gezeigt, wie man zu mindestens einem nützlichen Ergebnis für den ersten Durchgang kommt.
Hinzugefügt:
Ich war neugierig, wie gut die Suche nach Dips auf beiden Seiten eines Gipfels funktionieren würde, also habe ich es versucht. Ich habe einen nichtlinearen Filter verwendet, der mit dem Effektivwert aus der vorherigen Darstellung beginnt. Der Wert jedes Punkts gibt an, um wie viel mindestens er sich in der vorherigen Sekunde über dem niedrigsten Punkt und in der nächsten Sekunde über dem niedrigsten Punkt befindet. Das Ergebnis sieht ganz gut aus:
Der niedrigste der 5 Peaks ist mehr als dreimal höher als das höchste Hintergrundrauschen. Dies setzt natürlich voraus, dass diese 5 Unebenheiten Ereignisse darstellen, die Sie erkennen möchten, und der Rest nicht.
Als Antwort auf Kommentare hinzugefügt:
Ich habe die Filter im Zeitbereich durchgeführt, daher kenne ich den Frequenzgang nicht direkt. Für das Tiefpassfilter habe ich das Eingangssignal mit einem COS ^ 2-Filterkern gefaltet. Wenn ich mich recht erinnere, beträgt der Radius (Abstand von Mitte zu Rand) des Kernels einige 100 ms. Ich habe mit dem Wert experimentiert, bis die Handlung gut aussah. Zum Tiefpassfiltern des RMS habe ich denselben Filterkern verwendet, diesmal jedoch mit einem Radius von etwa einer Sekunde. Ich erinnere mich nicht genau. Experimentieren Sie, bis Sie gute Ergebnisse erhalten.
Das nichtlineare Filter erkannte keine Dubletten. Wie gesagt, ich habe den Unterschied zwischen dem aktuellen Punkt und dem niedrigsten aller Punkte innerhalb von 1 Sekunde zuvor und auch den Unterschied zwischen dem aktuellen Punkt und dem niedrigsten aller Punkte innerhalb von 1 Sekunde danach gefunden. Dann nahm ich die Minute von diesen beiden.
Die Software, die ich verwendete, war ein Programm, das ich für diesen Zweck gehackt habe. Ich hatte bereits verschiedene Routinen zum Lesen und Schreiben von CSV-Dateien, daher musste ich nur den Filtercode schreiben, der sehr einfach ist. Den Rest erledigte ich mit bereits vorhandenen Programmen zum Bearbeiten und Plotten von CSV-Dateien.
quelle
Die Erkennung von Schlaglöchern kann zu Problemen führen. In der Schwingungshüllkurve des Autos liegt die Antwort, da die tatsächlichen vom Sensor wahrgenommenen Schwingungen bei viel höheren Frequenzen liegen. Ich würde mit RMS zu DC gehen, das bei ca. 15Hz oder höher anspricht und das Ding tiefpasst.
quelle
Anstatt nach einem Frequenzbereichsfilter oder einem Schwellenwert zu suchen, empfehle ich, einen Kernel für ein "typisches" Schlagloch zu finden und eine laufende Korrelation damit durchzuführen. Es wird als Template-Matching-Technik angesehen und scheint sich für eine Mikrocontroller-Plattform zu eignen.
Sehen Eine kurze Übersicht finden http://scribblethink.org/Work/nvisionInterface/vi95_lewis.pdf und möglicherweise unter DOBBS, STEVEN E., NEIL M. SCHMITT und HALUK S. OZEMEK. "QRS-Erkennung durch Template-Matching unter Verwendung von Echtzeit-Korrelation auf einem Mikrocomputer." Journal of Clinical Engineering 9.3 (1984): 197 & ndash; 212.
Wenn Sie sich auf einer bulligeren Plattform befinden, würde ich empfehlen, Wavelets eine Drehung zu geben.
quelle
Ein anderer Ansatz wäre die Berechnung einer sich bewegenden Varianz Ihres Signals, um festzustellen, ob die Schlaglöcher wirklich hervorstehen. Hier ist eine Matlab-Funktion für ein sich bewegendes Varianzfilter mit N Punkten Breite - geschickt (wenn ich es selbst sagen muss), die eine Faltung zur Berechnung verwendet
quelle
Mein erster Gedanke ist, dass ein Tiefpassfilter möglicherweise der falsche Filtertyp ist. Das Schlagloch ist im Wesentlichen ein hochfrequentes Ereignis - wie eine Sprungfunktion oder eine Rechteckwelle. Allein der Blick auf die mit 50 Hz gefilterten Daten lässt mich denken, dass Sie die Informationen über das Schlagloch verlieren - alles sieht aus wie die gleichen Kringel, ohne signifikante Unterscheidung für das Schlaglochereignis. Ich würde zuerst einen Hochpassfilter verwenden, dann einen Tiefpassfilter mit einer viel höheren Frequenz. Sie können den Tiefpassfilter ganz vermeiden, wenn Ihr Beschleunigungsmesser bereits tiefpassgefiltert ist.
Sobald Sie die hochpassgefilterten Daten haben, denke ich, dass ein einfacher Komparator mit einem geeigneten Schwellenwert die Spitzen in den Beschleunigungsdaten, die durch die Schlaglöcher verursacht werden, heraussucht und es Ihnen ermöglicht, sie zu zählen.
quelle