У меня около 32 секунд данных акселерометра для базового сценария вождения на 25 миль в час по обычным дорогам, а также около 7 выбоин и неровного участка дороги. Акселерометр установлен на приборной панели моей машины с двухсторонним скотчем.
Проблема: у меня есть все данные, которые шумят от акселерометра, и мне нужно сделать простой способ обнаружить, что произошло выбоина. Ниже приведены несколько графиков данных во временной области и БПФ. Акселерометр измеряет в GForce
По сути, я хочу, чтобы мой arduino знал, что выбоина произошла с довольно большой точностью и без использования математики и методов последипломного уровня.
У акселерометра, отобранного на частоте 100 Гц, имеется простой 50 Гц RC-фильтр низких частот на оси Z
Here is the CSV data for the 32 seconds of accelerometer readings TIME, GFORCE format:
http://hamiltoncomputer.us/50HZLPFDATA.CSV
ОБНОВЛЕНИЕ: Это полная полоса пропускания RAW акселерометра 1000 Гц, сэмплированная с максимальной частотой дискретизации, которую я мог получить на Arduino. Прямая загрузка файла CSV: около 112 секунд данных
http://hamiltoncomputer.us/RAWUNFILTEREDFULLBANDWIDTH500HZ.csv
Черная кривая - это нефильтрованные RAW данные акселерометра: синяя кривая фильтруется полосовым фильтром на основе экстремальных частот, найденных в БПФ, с преобладанием 2 Гц и 12 Гц.
Событие выбоины выглядит так во временной области:
Не уверен, что компонент от 10 до 15 Гц находится в БПФ, это фактическая выбоина, или это скачок колес от дороги, или это резонансная частота автомобиля?
FFT:
кажется, что это фактические события выбоины, здесь HPF @ 13HZ Доминирующие свойства выбоин кажутся усиленными
Я хочу, чтобы иметь возможность обнаруживать и считать выбоины в режиме реального времени
Кажется нелогичным, что подвеска должна двигаться намного медленнее, чем 10-13 Гц, что может вызвать укачивание
ОБНОВИТЬ:
В соответствии с рекомендациями AngryEE, я использовал полную полосу пропускания акселерометра 1000 Гц и максимальную частоту дискретизации, которую я мог получить на Arduino.
FFT:
Вот пример данных о событии выбоины, а также о некоторых неровностях и дорожном шуме вокруг него:
Добавлена схема детектора огибающей диода, выход выглядит одинаково ... Акселерометр всегда выдает от 0 до 3,3 Вольт, не отрицательно ...
ОБНОВИТЬ:
Из многих дорожных тестов, я никогда не превышал 1.6G до 45 миль в час в моей машине по оси Z, я использовал rand () для генерации псевдослучайного ускорения Gforce.
Моя идея заключается в том, что если я могу посмотреть на окна данных продолжительностью от 1 до 3 секунд, я могу рассчитать смещение оси Z, но меня беспокоит смещение акселерометра и ошибки в интеграции. Мне не нужно быть точным даже на 90%,> 70% было бы неплохо, но если бы я смотрел на смещение от одной до трех секунд за раз, можно ли было бы это сделать в реальном времени? Таким образом, я могу видеть, больше ли смещение, чем 1 дюйм, 2 дюйма, 5 дюймов. Чем больше смещение, тем грубее была неровность или выбоина:
Можете ли вы проверить, правильно ли я это делаю, я в основном настроил на своем рабочем столе, используя rand (), чтобы генерировать случайное ускорение от -1,6 до 1,6 Гс, захватывая данные за 3 секунды при симулированной частоте дискретизации 50 Гц
Если вы запускаете * nix, я использую Sleep () из Windows.h, чтобы сделать задержку 20 мс, частоту дискретизации 50 Гц
Я просто хотел посмотреть, подходит ли вам код, я еще не делал конкретный буфер, я не совсем понимаю, как его реализовать: закомментированный код взят из класса, над которым я работаю , но я пока не понимаю 100%. Круговой буфер позволил бы непрерывно перемещать окна данных, верно?
#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;
}
Образец прогона:
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 . . .
Ответы:
Похоже, это можно решить с помощью довольно прямой фильтрации. Вот ваши исходные данные:
Это слишком много, чтобы увидеть, что происходит в отдельном событии на уровне детализации, подходящем для этого. Вот только данные со второго 26 по 28:
Первоначально я думал, что это фильтр низких частот, но это не работает, потому что там нет низкочастотного сигнала. Вместо этого увеличивается амплитуда высокочастотного сигнала. Вот нижний проход, наложенный на оригинал:
Обратите внимание, что это соответствует «среднему» сигналу довольно хорошо, а не во время выбоины. Если мы вычтем это среднее значение из исходного сигнала, мы получим гораздо более высокие отклонения от этого среднего значения во время события, чем в противном случае. Другими словами, нам действительно нужен фильтр верхних частот. Мы сделаем это путем вычитания нижних частот из оригинала, поскольку именно так мы и здесь оказались, но в производственной системе вы бы сделали это с помощью явной фильтрации верхних частот. Во всяком случае, вот фильтрованный оригинал верхних частот:
Теперь это указывает на очевидный подход к обнаружению события. Во время мероприятия намного больше амплитуды сигнала, чем в противном случае. Мы можем обнаружить это, вычислив RMS и применив низкочастотную фильтрацию:
Уменьшая все данные, мы видим:
Это четко идентифицирует пять событий в данных, хотя я не знаю, должны ли эти данные это показывать. При более внимательном рассмотрении событий вы замечаете, что каждое из них имеет низкие провалы примерно за 1 секунду до и после пиков. Это означает, что можно сделать больше, если недостаточно просто установить пороговое значение RMS-сигнала, как сейчас. Например, простой алгоритм, который ищет высоту точки относительно самой низкой в течение 1 секунды в любом случае, должен еще больше снизить фоновый шум. Другой способ сказать то же самое - дифференцировать этот сигнал в поисках повышения в течение 1 секунды. Событие выбоины затем будет обнаружено дублетом, что означает высокий пик, сопровождаемый низким пиком.
Другой способ посмотреть на это - пропустить сигнал RMS. Он уже отфильтрован по нижним частотам, но, так как вы ищете внезапные события с сильными наклонами, отключение некоторых низких частот также должно работать для снижения фонового шума.
Здесь есть много способов улучшить сигнал, но, надеюсь, я показал, как получить хотя бы первый проход полезного результата.
Добавлено:
Мне было любопытно, насколько хорошо будет работать падение на любой стороне пика, поэтому я попробовал. Я использовал нелинейный фильтр, начиная с RMS из предыдущего графика. Значение каждой точки является минимумом того, насколько она выше самой низкой точки в предыдущую секунду и самой низкой точки в следующую секунду. Результат выглядит неплохо:
Самый низкий из 5 пиков более чем в 3 раза превышает самый высокий фоновый шум. Это, конечно, предполагает, что эти 5 ударов представляют события, которые вы хотите обнаружить, а остальные нет.
Добавлено в ответ на комментарии:
Я сделал фильтры во временной области, поэтому я не знаю частотную характеристику напрямую. Для фильтра нижних частот я свернул входной сигнал с ядром фильтра COS ^ 2. Если я правильно помню, радиус (расстояние от центра до края) ядра составляет несколько 100 мс. Я экспериментировал со значением, пока сюжет не выглядел хорошо. Для фильтрации низких частот RMS я использовал то же ядро фильтра, но на этот раз с радиусом около секунды. Я точно не помню. Экспериментируйте, пока не получите хорошие результаты.
Нелинейный фильтр не обнаружил дублетов. Как я уже сказал, я нашел разницу между текущей точкой и самой низкой из всех точек в течение 1 секунды до, а также разницу между текущей точкой и самой низкой из всех точек в течение 1 секунды после. Затем я взял мин из этих двух.
Программное обеспечение, которое я использовал, было программой, которую я взломал для этой цели. У меня уже были различные процедуры для чтения и записи CSV-файлов, поэтому все, что мне нужно было написать, это код фильтрации, который очень прост. Остальное было сделано с уже существующими программами для работы с CSV-файлами.
источник
Бреши, обнаруживающие края, могут вызывать проблемы. Ответ заключается в вибрации автомобиля, поскольку фактические вибрации, воспринимаемые датчиком, имеют гораздо более высокие частоты. Я бы пошел с RMS на DC, который реагирует на частоте около 15 Гц или выше и на низких частотах.
источник
Вместо того, чтобы искать фильтр в частотной области или порог, я рекомендую попытаться найти ядро для «типичной» выбоины и выполнить текущую корреляцию с ним. Это будет рассматриваться как метод сопоставления с шаблоном, и, похоже, подойдет для платформы микроконтроллера.
См. Http://criblethink.org/Work/nvisionInterface/vi95_lewis.pdf для быстрого обзора, и, возможно, DOBBS, Стивен Е., Нейл М. Шмитт и HALUK S. OZEMEK. «Обнаружение QRS по сопоставлению шаблонов с использованием корреляции в реальном времени на микрокомпьютере». Журнал клинической инженерии 9.3 (1984): 197-212.
Если бы вы были на более мощной платформе, я бы порекомендовал сделать вейвлеты.
источник
Другим подходом будет вычисление движущейся дисперсии вашего сигнала, чтобы увидеть, действительно ли выбоины выпадают. Вот функция Matlab для фильтра движущихся дисперсий, N точек в ширину - умно (если я должен так сказать сам), используя свертку для расчета
источник
Сначала я думал, что фильтр нижних частот может быть неправильным типом фильтра для использования. По сути, выбоина - это высокочастотное событие, такое как ступенчатая функция или прямоугольная волна. Глядя на отфильтрованные данные с частотой 50 Гц, я думаю, что вы теряете информацию об выбоине - все это выглядит как одни и те же кривые, без какого-либо существенного различия для события выбоины. Сначала я бы использовал фильтр верхних частот, затем фильтр нижних частот с гораздо более высокой частотой. Вы можете вообще избежать фильтра нижних частот, если ваш акселерометр уже отфильтрован по нижним частотам.
Как только вы получите данные, отфильтрованные по верхним частотам, я думаю, что простой компаратор с соответствующим пороговым значением выберет пики в данных ускорения, вызванных выбоинами, и позволит вам их подсчитать.
источник