Около 3 лет назад мне и моему товарищу по лаборатории было поручено реализовать алгоритм обнаружения шагов. Реализация будет использоваться для нашего исследования, связанного с чем-то IoT’ish работой.

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

А. Запишите шаги

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

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

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

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

В отличие от предыдущего состояния, в конце каждого шага человек толкается вперед, поставив ногу на пол, и, таким образом, статическое трение направлено назад (в положительном направлении оси z). На рисунке 1 видно, что выступающие пики в отрицательном направлении z в начале каждого шага, но также и в положительном направлении z в конце каждого шага.

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

Б. Сделайте чтение более плавным

Когда мы записали данные акселерометра, показания были как-то очень грубыми. Итак, чтобы сделать чтение более плавным, необходима функция фильтра нижних частот, чтобы возвращать относительно небольшие изменения значения z, используя 2 параметра:
a. Новое значение акселерометра Z и предыдущее значение Z.
б. Последнее значение Z фильтра нижних частот, полученное по этой формуле

Z[t’] = (α x Z[t-1]) + (1 — α) * Z[t]

Z [t ']: значение Z после фильтрации нижних частот
Z [t-1]: Предыдущее значение Z из показаний акселерометра
Z [t]: Текущее значение Z из показаний акселерометра
α: Константа (в этой реализации значение 0,9f)

Теперь давайте сосредоточимся на рисунке 1, а теперь я собираюсь проиллюстрировать изображение более наглядно.

С. Анализируйте пошаговое чтение

Если вы посмотрите на график на рисунке 1. Мы можем увидеть крутой скачок между верхним и нижним числами. Как вы можете предположить, это ключ самого обнаружения шага.

Для обнаружения каждой фазы шага алгоритм обнаружения шага поддерживает четыре порога: верхний порог, верхний порог, нижний порог и нижний порог. На рис. 2 мы показываем эти четыре порога и значение ускорения во времени.

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

Фаза качания - это переходная фаза между фазой подъема и фазой шага. Алгоритм обнаружения шага определяет фазу качания, когда текущая фаза является фазой подъема, а значение ускорения проходит вверх через нижний порог. Шаговая фаза приводит к положительному значению ускорения, поскольку вызывает ускорение, противоположное обнаружению силы тяжести. Алгоритм обнаружения шага определяет фазу шага, когда текущая фаза является фазой качания, а значение ускорения увеличивается до верхнего порогового значения. Наконец, ступенька обнаруживается, когда значение ускорения снижается до верхнего порогового значения в ступенчатой ​​фазе.

Д. Реализация кода

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

Прежде всего, давайте объявим некоторые константы для проверки границ шага.

double lastAccelZValue = -9999; 
long lastCheckTime = 0; 
boolean highLineState = true; 
boolean lowLineState = true; 
boolean passageState = false; 
double highLine = 1; 
double highBoundaryLine = 0; 
double highBoundaryLineAlpha = 1.0; 
double highLineMin = 0.50; 
double highLineMax = 1.5; 
double highLineAlpha = 0.0005; 
double lowLine = -1; 
double lowBoundaryLine = 0; 
double lowBoundaryLineAlpha = -1.0; 
double lowLineMax = -0.50; 
double lowLineMin = -1.5; 
double lowLineAlpha = 0.0005; 
double lowPassFilterAlpha = 0.9;  
float[] rotationData = new float[9]; 
float[] resultData = new float[3];

Затем нам нужно создать функцию или метод для обнаружения шага, применив приведенную выше теорему. Назовем эту функцию функцией readStepDetection. Указанная ниже функция должна вызываться при считывании показаний датчика. Эта функция обнаруживает событие шага, считывая данные жидкости с акселерометра. Мы используем линейные данные акселерометра для обнаружения шагов.

private void readStepDetection(float[] accelLinearData) {
  long currentTime = System.currentTimeMillis();
  long gapTime1 = (currentTime - lastCheckTime);
  if (lastAccelZValue == -9999){
     lastAccelZValue = accelLinearData[2];
  }
  if (highLineState && highLine > highLineMin) {
     highLine = highLine - highLineAlpha;
     highBoundaryLine = highLine * highBoundaryLineAlpha;
  }
  if (lowLineState && lowLine < lowLineMax) {
     lowLine = lowLine + lowLineAlpha;
     lowBoundaryLine = lowLine * lowBoundaryLineAlpha;
  }
//perform a low pass filter for sensor reading
  double zValue = (lowPassFilterAlpha * lastAccelZValue) + (1 -lowPassFilterAlpha) * accelLinearData[2];
  if (highLineState && gapTime1 > 100 && zValue > highBoundaryLine){
     highLineState = false;
  }
  if (lowLineState && zValue < lowBoundaryLine && passageState) {
    lowLineState = false;
  }
  if (!highLineState) {
     if (zValue > highLine) {
       highLine = zValue;
       highBoundaryLine = highLine * highBoundaryLineAlpha;
       
       if (highLine > highLineMax) {
         highLine = highLineMax;
         highBoundaryLine = highLine * highBoundaryLineAlpha;
       }
     } else {
       if (highBoundaryLine > zValue) {
         highLineState = true;
         passageState = true;
       }
     }
  }
  if (!lowLineState && passageState) {
     if (zValue < lowLine) {
       lowLine = zValue;
       lowBoundaryLine = lowLine * lowBoundaryLineAlpha;
     
       if (lowLine < lowLineMin) {
         lowLine = lowLineMin;
         lowBoundaryLine = lowLine * lowBoundaryLineAlpha;
       }
      } else {
        if (lowBoundaryLine < zValue) {
          lowLineState = true;
          passageState = false;
          
          //step is detected here
          //do something
          
          lastCheckTime = currentTime;
        }
      }
  }  
  
  lastAccelZValue = zValue;
}

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

public void onSensorChanged(SensorEvent sensorEvent) {
  if (sensorEvent.sensor.getType() ==  Sensor.TYPE_LINEAR_ACCELERATION) {
    this.accelLinearData = sensorEvent.values.clone();
  }
  if (this.accelLinearData != null) {
    actionReadStepDetection(accelLinearData);
  }
}

Э. Наконец-то ..

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

Однако разве в коде нет недостатков? Конечно нет. Есть некоторые проблемы, которые необходимо решить, если мы будем использовать этот код.

  1. Шаг каждого человека индивидуален, нам нужно выяснить, как поддерживать эти константы, указанные выше, как можно более адаптивными.
  2. Отчетливая ходьба и бег. Эти действия создают другую тенденцию считывания показаний датчиков.
  3. Положение рукоятки. Итак, предположим, что мы используем смартфон, тогда его положение имеет значение. Более того, если мы положим смартфон в сумку или карман, я опасаюсь, что эта реализация недействительна.

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

Источники

Фанг, Л., Анцаклис, П.Дж., Монтеструк, Л.А., Макмикелл, М.Б., Леммон, М., Сун, Ю., Фанг, Х., Кутрулис, И., Хенгги, М., Се, М. и Се, X ., 2005. Разработка беспроводной системы счисления мертвых пешеходов - опыт NavMote. IEEE Transactions on Instrumentation and Measurement, 54 (6), pp.2342–2358.

Наквиб Н.З., Кумар А., Чаухан А. и Сахни К., 2012. Подсчет шагов с помощью акселерометра на базе смартфона. Международный журнал компьютерных наук и инженерии, 4 (5), стр.675.

Диас, Э.М., Гонсалес, А.Л.М., октябрь 2014 г. Детектор шагов и устройство оценки длины шага для инерциальной карманной навигационной системы. В статье Внутреннее позиционирование и внутренняя навигация (IPIN), Международная конференция 2014 г. (стр. 105–110). IEEE.