#c# #language-agnostic #coordinates #motion #categorization
#c# #язык-агностик #координаты #движение #классификация #язык не зависит #категоризация
Вопрос:
У меня есть серия CSV-файлов с координатами с метками времени (X, Y и Z в мм). Какой был бы самый простой способ извлечь из них данные о движении?
Измеряемые
Информация, которую я хотел бы извлечь, включает следующее:
- Количество изменений направления
- Начальное ускорение первого и последнего движений
- …и направление (угол) этих движений
- Средняя скорость при нестационарном
В идеале, я бы в конечном итоге хотел иметь возможность классифицировать паттерны движения, так что бонусные баллы для любого, кто может предложить способ сделать это. Мне приходит в голову, что одним из способов, которым я мог бы это сделать, было бы сгенерировать изображения / видео движения по координатам и попросить людей классифицировать их — предложения относительно того, как я бы это сделал, очень приветствуются.
Шум
Осложнением является тот факт, что показания загрязнены шумом. Чтобы преодолеть это, каждой записи предшествует не менее 20 секунд тишины, которые могут служить своего рода «профилем шума». Хотя я не уверен, как это реализовать.
Специфика
Если это поможет, записываемое движение — это движение руки человека во время простого захвата. Данные генерируются с помощью магнитного трекера движения, прикрепленного к запястью. Кроме того, я использую C #, но я предполагаю, что математика не зависит от языка.
Правки
- Спецификация магнитного трекера: http://www.ascension-tech.com/realtime/RTminiBIRD500_800.php
- Пример файла данных: http://tdwright.co.uk/sample.csv
Щедрость
Что касается вознаграждения, я бы очень хотел увидеть несколько примеров (псевдо-) кода.
Комментарии:
1. Вы хотите получать информацию о движении по каждой оси?
2. Ах, извините. Я удалил свои предыдущие комментарии, как только вы ответили.
3. Не беспокойтесь, ваше перефразирование полезно. Думая об этом, я действительно забочусь только о движении в плоскости XY — высота выше / ниже начала координат менее интересна.
4. ОК. Вы хотели бы обнаруживать изменения движения по осям x и y отдельно? Или вы хотели бы обнаружить отклонения от прямой линии движения (т. Е. принимая во внимание как оси x, так и y)
5. Основываясь на моих наблюдениях за записями, кажется, что было бы лучше учитывать оба: часто изменения направления были довольно незаметными.
Ответ №1:
Давайте посмотрим, что можно сделать с вашими примерами данных.
Отказ от ответственности: я не читал спецификации вашего оборудования (tl; dr :))
Для удобства я разберу это в Mathematica. Соответствующие алгоритмы (не многие) будут предоставлены в виде ссылок.
Первое наблюдение заключается в том, что все ваши измерения равномерно распределены по времени, что наиболее удобно для упрощения подхода и алгоритмов. Мы будем представлять «время» или «тики» (измерения) для нашего удобства, поскольку они эквивалентны.
Давайте сначала построим ваше положение по оси, чтобы понять, в чем проблема:
(* This is Mathematica code, don't mind, I am posting this only for
future reference *)
ListPlot[Transpose@(Take[p1[[All, 2 ;; 4]]][[1 ;;]]),
PlotRange -> All,
AxesLabel -> {Style["Ticks", Medium, Bold],
Style["Position (X,Y,Z)", Medium, Bold]}]
Теперь два наблюдения:
- Ваше перемещение начинается примерно с отметки 1000
- Ваше движение не начинается с {0,0,0}
Итак, мы слегка преобразуем ваши данные, вычитая нулевую позицию и начиная с отметки 950.
ListLinePlot[
Drop[Transpose@(x - Array[Mean@(x[[1 ;; 1000]]) amp;, Length@x]), {}, 950],
PlotRange -> All,
AxesLabel -> {Style["Ticks", Medium, Bold],
Style["Position (X,Y,Z)", Medium, Bold]}]
Поскольку в кривых достаточно шума, чтобы испортить вычисления, мы свернем их с помощью ядра Гаусса, чтобы уменьшить шум:
kern = Table[Exp[-n^2/100]/Sqrt[2. Pi], {n, -10, 10}];
t = Take[p1[[All, 1]]];
x = Take[p1[[All, 2 ;; 4]]];
x1 = ListConvolve[kern, #] amp; /@
Drop[Transpose@(x - Array[Mean@(x[[1 ;; 1000]]) amp;, Length@x]), {},
950];
Итак, вы можете увидеть ниже исходную и сглаженную траектории:
Теперь мы готовы взять производные для скорости и ускорения. Мы будем использовать аппроксиманты четвертого порядка для первой и второй производных. Мы также будем сглаживать их, используя ядро Гаусса, как и раньше:
Vel = ListConvolve[kern, #] amp; /@
Transpose@
Table[Table[(-x1[[axis, i 2]] x1[[axis, i - 2]] -
8 x1[[axis, i - 1]]
8 x1[[axis, i 1]])/(12 (t[[i 1]] - t[[i]])), {axis, 1, 3}],
{i, 3, Length[x1[[1]]] - 2}];
Acc = ListConvolve[kern, #] amp; /@
Transpose@
Table[Table[(-x1[[axis, i 2]] - x1[[axis, i - 2]]
16 x1[[axis, i - 1]] 16 x1[[axis, i 1]] -
30 x1[[axis, i]])/(12 (t[[i 1]] - t[[i]])^2), {axis, 1, 3}],
{i, 3, Length[x1[[1]]] - 2}];
И мы наносим их на график:
Show[ListLinePlot[Vel,PlotRange->All,
AxesLabel->{Style["Ticks",Medium,Bold],
Style["Velocity (X,Y,Z)",Medium,Bold]}],
ListPlot[Vel,PlotRange->All]]
Show[ListLinePlot[Acc,PlotRange->All,
AxesLabel->{Style["Ticks",Medium,Bold],
Style["Acceleation (X,Y,Z)",Medium,Bold]}],
ListPlot[Acc,PlotRange->All]]
Теперь у нас также есть модуль скорости и ускорения:
ListLinePlot[Norm /@ (Transpose@Vel),
AxesLabel -> {Style["Ticks", Medium, Bold],
Style["Speed Module", Medium, Bold]},
Filling -> Axis]
ListLinePlot[Norm /@ (Transpose@Acc),
AxesLabel -> {Style["Ticks", Medium, Bold],
Style["Acceleration Module", Medium, Bold]},
Filling -> Axis]
И заголовок, как направление скорости:
Show[Graphics3D[
{Line@(Normalize/@(Transpose@Vel)),
Opacity[.7],Sphere[{0,0,0},.7]},
Epilog->Inset[Framed[Style["Heading",20],
Background->LightYellow],{Right,Bottom},{Right,Bottom}]]]
Я думаю, этого достаточно, чтобы вы начали. дайте мне знать, если вам понадобится помощь в вычислении определенного параметра.
HTH!
Редактировать
Просто в качестве примера предположим, что вы хотите вычислить среднюю скорость, когда рука не находится в состоянии покоя. итак, мы выбираем все точки, скорость которых больше порогового значения, например 5, и вычисляем среднее:
Mean@Select[Norm /@ (Transpose@Vel), # > 5 amp;]
-> 148.085
Единицы измерения для этой величины зависят от ваших единиц времени, но я нигде не вижу, чтобы они были указаны.
Пожалуйста, обратите внимание, что скорость отсечки не является «интуитивной». Вы можете выполнить поиск подходящего значения, построив график зависимости средней скорости от скорости отсечки:
ListLinePlot[
Table[Mean@Select[Norm /@ (Transpose@Vel), # > h amp;], {h, 1, 30}],
AxesLabel -> {Style["Cutoff Speed", Medium, Bold],
Style["Mean Speed", Medium, Bold]}]
Итак, вы видите, что 5 является подходящим значением.
Комментарии:
1. Отличный ответ, но вам удалось вызвать серьезную зависть Mathematica! Собираюсь попытаться найти хороший алгоритм ядра Гаусса для C #…
2. @Tom Фильтр Гаусса хорош, но, возможно, подойдут и другие фильтры. Не зацикливайтесь на этом.
3. Я думаю, велисарий действительно заслуживает награды!
4. @gpu_drug Я полностью согласен. Спасибо @belisarius!
Ответ №2:
решение могло бы быть таким же простым, как конечный автомат, где каждое состояние представляет направление. Последовательности движений представлены последовательностями направлений. Этот подход будет работать только в том случае, если ориентация датчика не меняется относительно движений, в противном случае вам понадобится метод преобразования движений в правильную ориентацию, прежде чем вычислять последовательности направлений.
С другой стороны, вы могли бы использовать различные методы искусственного интеллекта, хотя то, что именно вы бы использовали, мне недоступно.
Чтобы получить скорость между любыми двумя координатами:
_________________________________
Avg Speed = /(x2-x1)^2 (y2-y1)^2 (z2-z1)^2
--------------------------------------
(t2-t1)
Чтобы получить среднюю скорость для всего движения, допустим, у вас есть 100 координат с метками времени, используйте приведенное выше уравнение для вычисления 99 значений скорости. Затем суммируйте все скорости и разделите на количество скоростей (99)
Для получения ускорения требуется местоположение в три момента или скорость в два момента.
Accel X = (x3 - 2*x x1) / (t3 - t2)
Accel Y = (y3 - 2*y y1) / (t3 - t2)
Accel Z = (z3 - 2*z z1) / (t3 - t2)
Комментарии:
1. Скорость всегда скалярна. Скорость — это вектор.
2. Спецификация — длинный, скучный документ — какую информацию вы хотите? Я загружу пример файла данных, если это все же поможет.
3. Ваша средняя скорость (которая может быть дополнительно обобщена для включения координат z) не работает, если начальная и конечная точки совпадают. Это можно было бы применять на каждом шаге (пара координат), но это все равно не учитывало бы моменты неподвижности.
Ответ №3:
Примечание: Все это предполагает вычисления для каждой оси: У меня нет опыта работы с двухосевым движением частиц.
Вам будет намного проще справиться с этим, если вы сначала преобразуете свои измерения местоположения в измерения скорости.
Первый шаг: удалите шум. Как вы сказали, каждой записи предшествует 20 секунд тишины. Итак, чтобы найти фактические измерения, найдите 20-секундные интервалы, в течение которых положение не меняется. Затем непосредственно после этого выполните измерение.
Второй шаг: Вычислите скорости, используя: (x2 — x1) / (t2 — t1); формулу наклона. Интервал должен соответствовать интервалу записей.
Вычисления:
Изменение направления:
Изменение направления происходит там, где ускорение равно нулю. Используйте числовое интегрирование, чтобы найти это время. Интегрируйте от 0 до момента, когда результат интегрирования равен нулю. Запишите это время. Затем интегрируйте с предыдущего раза, пока снова не получите ноль. Повторяйте, пока не дойдете до конца данных.
Начальные ускорения:
Они снова находятся с использованием формулы наклона, заменяя v
на x
.
Средняя скорость:
Формула средней скорости — это формула наклона. x1 и t1 должны соответствовать первому показанию, а x2 и t2 должны соответствовать окончательному показанию.
Комментарии:
1. Как я уже сказал, это неприменимо к 2d движению. Надеюсь, кто-то, кто лучше разбирается в математике, чем я, сможет применить это к 2d движению 🙂