Ich habe Beschleunigungsmesserdaten im Wert von etwa 32 Sekunden eines einfachen Fahrszenarios mit 25 MPH auf normalen Straßen, zusammen mit etwa 7 Schlaglöchern und einem unebenen Stück Straße. Der Beschleunigungsmesser ist mit doppelseitigem Klebeband auf dem Armaturenbrett meines Autos montiert.
Problem: Ich habe alle Daten, die vom Beschleunigungsmesser verrauscht sind, und ich muss einen einfachen Weg finden, um zu erkennen, dass ein Schlaglochereignis aufgetreten ist. Unten sind mehrere Diagramme von Daten im Zeitbereich und FFT. 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 hat einen einfachen 50-Hz-RC-TIEFPASSFILTER 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-Vollbandbreite des Beschleunigungsmessers 1000 Hz, die mit der höchsten Abtastrate abgetastet wurde, die ich auf Arduino bekommen konnte. Direkter Download der CSV-Datei: Etwa 112 Sekunden Daten
http://hamiltoncomputer.us/RAWUNFILTEREDFULLBANDWIDTH500HZ.csv
Die schwarze Kurve sind ungefilterte RAW-Beschleunigungsmesserdaten: Die blaue Kurve wird durch einen Bandsperrfilter gefiltert, der auf den extremen Frequenzen basiert, die in FFT, Dominate 2HZ und 12HZ gefunden werden.
Pothole-Ereignis sieht im Zeitbereich so aus:
Ich bin mir nicht sicher, was die 10 bis 15 Hz-Komponente in der FFT ist. Ist das das tatsächliche Schlagloch oder ist es das Radspringen der Räder gegen die Straße oder ist es die Resonanzfrequenz des Autos?
FFT:
Es scheint, als ob es sich um die eigentlichen Schlaglochereignisse handelt, hier ist ein HPF bei 13 Hz. Die dominanten Merkmale der Schlaglöcher scheinen verstärkt zu sein
Ich möchte die Schlaglöcher in Echtzeit erkennen und zählen können
Es scheint kontraintuitiv zu sein, dass sich die Federung viel langsamer bewegen sollte als 10 bis 13 Hz, 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 Beispieldatensatz des Schlaglochereignisses und einiger Unebenheiten und Straßengeräusche drumherum:
Die Diodenhüllkurvendetektorschaltung wurde hinzugefügt, die Ausgabe sieht gleich aus ... Der Beschleunigungsmesser gibt immer 0 bis 3,3 Volt aus, nicht negativ ...
AKTUALISIEREN:
Bei vielen Straßentests habe ich in meinem Auto auf der Z-Achse nie 1,6 G bis zu 45 MPH überschritten. Ich habe rand() verwendet, um eine pseudozufällige Gforce-Beschleunigung zu erzeugen.
Meine Idee ist, wenn ich 1 bis 3 Sekunden Datenfenster betrachten kann, kann ich die Verschiebung der Z-Achse berechnen, aber ich war besorgt über die Drift des Beschleunigungsmessers und Fehler bei der Integration. Ich muss hier nicht einmal 90 % genau sein, > 70 % wären schön, aber wenn ich die Verschiebung jeweils ein bis drei Sekunden betrachte, wäre das in Echtzeit möglich? Auf diese Weise kann ich sehen, ob die Verschiebung größer als 1 Zoll, 2 Zoll, 5 Zoll ist. Je größer die Verschiebung, desto rauer war die Bodenwelle oder das Schlagloch:
Können Sie überprüfen, ob ich das richtig mache, ich habe es im Grunde auf meinem Desktop eingerichtet und mit rand() eine zufällige Beschleunigung von -1,6 bis 1,6 G erzeugt, wobei 3 Sekunden Daten bei einer simulierten Abtastrate von 50 Hz erfasst werden
Wenn Sie * nix ausführen, verwende ich Sleep () von Windows.h, um die Verzögerung von 20 ms und die Abtastrate von 50 Hz zu erreichen
Ich wollte nur sehen, ob der Code für Sie richtig aussieht. Ich habe den Cicular-Puffer noch nicht erstellt. Ich bin etwas verwirrt, wie ich ihn implementieren soll: Der auskommentierte Code stammt aus der Klasse, an der ich arbeite , aber ich verstehe es noch nicht zu 100%. Ein Ringpuffer würde es ermöglichen, 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;
}
Beispiellauf:
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 . . .
Dies sieht so aus, als könnte es durch eine ziemlich einfache Filterung gelöst werden. Hier sind Ihre ursprünglichen Daten:
Das ist zu viel, um zu sehen, was in einer einzelnen Veranstaltung in der dafür angemessenen Detailebene vor sich geht. Hier sind nur die Daten von Sekunde 26 bis 28:
Ich hatte ursprünglich gedacht, dies mit einem Tiefpassfilter zu versehen, aber das funktioniert nicht, weil dort kein Niederfrequenzsignal vorhanden ist. Stattdessen steigt die Amplitude des Hochfrequenzsignals an. Hier ist ein dem Original überlagerter Tiefpass:
Beachten Sie, dass dies dem "Durchschnitt" des Signals ziemlich gut folgt, nicht während des Schlaglochereignisses. Wenn wir diesen Mittelwert von dem ursprünglichen Signal subtrahieren, verbleiben während des Ereignisses viel höhere Abweichungen von diesem Mittelwert als sonst. Anders gesagt, was wir wirklich wollen, ist ein Hochpassfilter. Wir tun das, indem wir den Tiefpass vom Original subtrahieren, da wir so hierher gekommen sind, aber in einem Produktionssystem würden Sie dies durch explizite Hochpassfilterung tun. Wie auch immer, hier ist das hochpassgefilterte Original:
Dies weist nun auf einen naheliegenden Ansatz zur Erkennung des Ereignisses hin. Während des Ereignisses gibt es viel mehr Signalamplitude als sonst. Wir können dies erkennen, indem wir den Effektivwert berechnen und eine Tiefpassfilterung anwenden:
Wenn wir auf die gesamten Daten zurückzoomen, sehen wir:
Dies identifiziert eindeutig fünf Ereignisse in den Daten, obwohl ich nicht weiß, ob diese Daten das zeigen sollen. Wenn Sie sich die Ereignisse genauer ansehen, stellen Sie fest, dass jedes von ihnen etwa 1 Sekunde vor und nach den Spitzen niedrige Einbrüche aufweist. Dies bedeutet, dass mehr getan werden kann, wenn das einfache Thresholding des RMS-Signals, so wie es jetzt ist, nicht gut genug ist. Beispielsweise sollte ein einfacher Algorithmus, der nach der Höhe eines Punktes relativ zum niedrigsten innerhalb von 1 Sekunde in beide Richtungen sucht, das Hintergrundrauschen weiter reduzieren. Eine andere Möglichkeit, dasselbe 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 durch ein Dublett erkannt werden, was bedeutet, dass ein hoher Peak gefolgt von einem niedrigen Peak ist.
Eine andere Betrachtungsweise besteht darin, das RMS-Signal zu bandpassieren. Es ist bereits tiefpassgefiltert, aber da Sie nach plötzlichen Ereignissen mit starken Flanken suchen, sollte das Abschneiden einiger niedriger Frequenzen funktionieren, um auch das Hintergrundrauschen zu reduzieren.
Es gibt viele Möglichkeiten, das Signal von hier aus zu verfeinern, aber hoffentlich habe ich gezeigt, wie man zumindest ein nützliches Ergebnis für den ersten Durchgang erhält.
Ich war neugierig, wie gut die Suche nach Einbrüchen auf beiden Seiten eines Gipfels funktionieren würde, also habe ich es versucht. Ich habe einen nichtlinearen Filter verwendet, beginnend mit dem Effektivwert aus dem vorherigen Diagramm. Der Wert jedes Punktes ist das Minimum dessen, wie viel er über dem niedrigsten Punkt in der vorherigen Sekunde und dem niedrigsten Punkt in der nächsten Sekunde liegt. 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.
Ich habe die Filter im Zeitbereich durchgeführt, daher kenne ich den Frequenzgang nicht direkt. Für den Tiefpassfilter habe ich das Eingangssignal mit einem COS^2-Filterkernel gefaltet. Wenn ich mich recht erinnere, beträgt der Radius (Abstand vom Zentrum zum Rand) des Kernels wenige 100 ms. Ich experimentierte mit dem Wert, bis die Handlung gut aussah. Um den Effektivwert tiefpasszufiltern, habe ich denselben Filterkern verwendet, aber diesmal mit einem Radius von etwa einer Sekunde. Ich erinnere mich nicht genau. Experimentieren Sie, bis Sie gute Ergebnisse erzielen.
Das nichtlineare Filter hat keine Dubletten erkannt. Wie gesagt, ich habe die Differenz zwischen dem aktuellen Punkt und dem niedrigsten aller Punkte innerhalb von 1 Sekunde davor und auch die Differenz zwischen dem aktuellen Punkt und dem niedrigsten aller Punkte innerhalb von 1 Sekunde danach gefunden. Dann nahm ich die min von diesen beiden.
Die Software, die ich benutzte, war ein Programm, das ich für diesen Zweck gehackt hatte. Ich hatte bereits verschiedene Routinen zum Lesen und Schreiben von CSV-Dateien, also musste ich nur den Filtercode schreiben, was sehr einfach ist. Der Rest wurde mit bereits vorhandenen Programmen erledigt, die ich zum Bearbeiten und Plotten von CSV-Dateien habe.
Die Kantenerkennung von Schlaglöchern kann zu Problemen führen. Die Antwort liegt in der Vibrationshülle des Autos, da die tatsächlichen Vibrationen, die der Sensor wahrnimmt, bei viel höheren Frequenzen liegen. Ich würde mit RMS zu DC gehen, das bei etwa 15 Hz oder höher reagiert, und das Ding tief passieren.
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 würde als Template-Matching-Technik angesehen und scheint sich für eine Mikrocontroller-Plattform zu eignen.
Siehe http://scribblethink.org/Work/nvisionInterface/vi95_lewis.pdf für einen kurzen Überblick und vielleicht DOBBS, STEVEN E., NEIL M. SCHMITT und HALUK S. OZEMEK. "QRS-Erkennung durch Vorlagenabgleich unter Verwendung von Echtzeitkorrelation auf einem Mikrocomputer." Journal of Clinical Engineering 9.3 (1984): 197-212.
Wenn Sie auf einer kräftigeren Plattform waren, würde ich empfehlen, Wavelets eine Drehung zu geben.
Ein anderer Ansatz wäre die Berechnung einer gleitenden Varianz Ihres Signals, um zu sehen, ob die Schlaglöcher wirklich herausragen. Hier ist eine Matlab-Funktion für einen beweglichen Varianzfilter, N Punkte breit - geschickt (wenn ich das selbst sagen darf) mit einer Faltung zur Berechnung
function y=movingvar(X,N)
% y=movingvar(X,N)
% Calculates N-point moving variance of Vector X
% Highly recommend that N be odd (no error checking)
% Note: first and last N/2 points will be unreliable.
% Output will be a column vector.
X=X(:);
XSQR=X.*X;
convsig=ones(1,N);
y=(conv(convsig,XSQR)-(conv(convsig,X).^2)/N)/(N-1);
y=y(ceil(N/2):length(X)+floor(N/2));
Mein erster Gedanke ist, dass ein Tiefpassfilter möglicherweise der falsche Filtertyp ist. Das Schlagloch ist im Wesentlichen ein hochfrequentes Ereignis – wie eine Stufenfunktion oder eine Rechteckwelle. Wenn ich mir nur die 50-Hz-gefilterten Daten ansehe, denke ich, dass Sie die Informationen über das Schlagloch verlieren - alles sieht aus wie die gleichen Schnörkel ohne signifikanten Unterschied 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 Beschleunigungssensor bereits tiefpassgefiltert ist.
Sobald Sie die hochpassgefilterten Daten haben, denke ich, dass ein einfacher Komparator mit einem geeignet eingestellten Schwellenwert die durch die Schlaglöcher verursachten Spitzen in den Beschleunigungsdaten heraussuchen und es Ihnen ermöglichen wird, sie zu zählen.
Anindo Ghosh
zacharoni16
Chintalagiri Shashank
zacharoni16
Olin Lathrop
Olin Lathrop
Olin Lathrop
zacharoni16
Phil Frost