Нужен алгоритм для обнаружения больших пиков в колебательных данных - PullRequest
1 голос
/ 20 июня 2019

Я анализирую данные на SD-карте по одному крупному за раз на микроконтроллере. Это данные акселерометра, поэтому он постоянно колеблется. В определенные моменты происходят огромные колебания (показано на графике). Мне нужен алгоритм, чтобы иметь возможность обнаруживать эти большие колебания, более того, определить диапазон данных, которые содержат этот всплеск.

У меня есть пример данных:

Overall graph Это общий график, есть только один всплеск интереса, первый.

zoomed in Здесь увеличено немного

oscillation Как вы можете видеть, это большое колебание, которое вызывает всплеск.

Так что любой алгоритм, который может сканировать набор данных и определять порцию данных, которая содержит скачок относительно некоторого порога, был бы великолепен. Этот набор данных составляет около 50000 отсчетов, каждый отсчет имеет длину 32 бита. У меня достаточно оперативной памяти, чтобы вместить столько данных.

Спасибо!

Ответы [ 3 ]

3 голосов
/ 22 июня 2019

Для следующего сигнала:

enter image description here

Если вы берете абсолютное значение разности между двумя последовательными выборками, вы получите:

enter image description here

Этого недостаточно для того, чтобы однозначно отличить от незначительных "неподдерживаемых" нарушений. Но если вы тогда возьмете простую скользящую сумму (негерметичный интегратор) из abs-дифференциалов. Здесь использовалось окно шириной 4 различных образца:

enter image description here

Скользящее среднее вводит задержку или фазовый сдвиг, который в случаях, когда данные сохраняются, а обработка не в реальном времени , может быть легко компенсирована вычитанием половины ширины окна из времени:

enter image description here

Для обработки в реальном времени, если задержка является критической, может быть целесообразен более сложный БИХ-фильтр. В любом случае из этих данных может быть выбран четкий порог.

В коде для вышеуказанного набора данных:

#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
#include <stdlib.h>

static int32_t dataset[] = { 0,0,0,0,0,3,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,
                             0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,3,0,0,0,0,0,
                             0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,
                             0,-10,-15,-5,20,25,50,-10,-20,-30,0,30,5,-5,
                             0,0,5,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,
                             0,0,0,0,0,0,0,0,0,1,0,0,0,0,6,0,0,0,0,0,0,0} ;

#define DATA_LEN (sizeof(dataset)/sizeof(*dataset))
#define WINDOW_WIDTH 4
#define THRESHOLD 15 
int main()
{
    uint32_t window[WINDOW_WIDTH] = {0} ;
    int window_index = 0 ;
    int window_sum = 0 ;
    bool spike = false ;

    for( int s = 1; s < DATA_LEN ; s++ )
    {
        uint32_t diff = abs( dataset[s] - dataset[s-1] ) ;
        window_sum -= window[window_index] ;
        window[window_index] = diff ;
        window_index++ ;
        window_index %= WINDOW_WIDTH ;
        window_sum += diff ;

        if( !spike && window_sum >= THRESHOLD )
        {
            spike = true ;
            printf( "Spike START @ %d\n", s - WINDOW_WIDTH / 2 ) ;
        }
        else if( spike && window_sum < THRESHOLD )
        {
            spike = false ;
            printf( "Spike END @   %d\n", s - WINDOW_WIDTH / 2 ) ;
        }
    }

    return 0;
}

Вывод:

Spike START @ 66
Spike END @   82

https://onlinegdb.com/ryEw69jJH

Сравнение исходных данных с порогом обнаружения дает:

enter image description here

Для ваших реальных данных вам нужно будет выбрать подходящую ширину окна и порог, чтобы получить желаемый результат, оба из которых будут зависеть от ширины полосы и амплитуды помех, которые вы хотите обнаружить.

Также вам может потребоваться защита от арифметического переполнения, если ваши выборки имеют достаточную величину. Они должны быть меньше 2 32 / ширина окна , чтобы гарантировать отсутствие переполнения в интеграторе. В качестве альтернативы вы можете использовать число с плавающей точкой или uint64_t для типа window или добавить код для обработки saturation .

3 голосов
/ 21 июня 2019

Вы можете посмотреть на статистический анализ. Вычисление стандартного отклонения по набору данных и затем проверка, когда ваши данные выходят за пределы.

Вы можете сделать это двумя способами; либо вы используете скользящее среднее по фиксированному (относительно небольшому) количеству выборок, либо вы берете среднее по всему набору данных. Поскольку я вижу несколько шипов в вашем наборе, я бы предложил первый. Таким образом, вы можете остановить обработку (а затем продолжить) каждый раз, когда обнаружите всплеск.

Для вашей цели вам не нужно рассчитывать сигма стандартного отклонения. Вы могли бы на самом деле оставить его в квадрате сигмы. Это даст вам небольшую оптимизацию производительности без необходимости вычисления квадратного корня.

Какой-то псевдокод:

// The data set.
int x[N];   

// The number of samples in your mean and std calculation.
int M <= N;  

// Simga at index i over the previous M samples.
int sigma_i = sqrt( sum( pow(x[i] - mean(x,M), 2) ) / M );

// Or the squared of sigma 
int sigma_squared_i = sum( pow(x[i] - mean(x,M), 2) ) / M;

Недостатком этого метода является то, что вам необходимо установить пороговое значение для значения сигма, при котором вы запускаете. Однако можно с уверенностью сказать, что при установке порогового значения в 4 или 5 раз выше среднего значения сигмы у вас будет работающая система.

0 голосов
/ 21 июня 2019

удалось получить работающий алгоритм.В основном, определяют среднюю разницу между точками данных.Если мои данные начинают последовательно превышать это кратное значение, то, скорее всего, происходит всплеск.

...