Рассчитать перегрузку по ускорению за 1-секундный интервал

Я извлек файл CSV с данными акселерометра (в м / с2) из файла метаданных GoPro (библиотека github).

Одна секунда акселерометра содержит ~ 200 выборок данных по 3 осям. Пример этого файла выглядит так:

образец данных акселерометра

В PHP для каждого мгновенного значения по оси X я конвертирую м / с2 как это:

function convert_meters_per_second_squared_to_g($ms2) {
// 1g = 9.80665 m/s2
return $ms2 * 0.101971621297793; // 1 / 9.80665 == 0.101971621297793
}

Пример кода для 200 строк (1 секунда) файла CSV:

$acc_x_summed_up = 0;
if (($handle = fopen($filepath, "r")) !== FALSE) {
while (($data = fgetcsv($handle, 1000, ",")) !== FALSE) {
list ($millis, $acc_x, $acc_y, $acc_z) = $data;

$acc_x_summed_up += $acc_x;
}
}

$g_force = convert_meters_per_second_squared_to_g($acc_x_summed_up);

Но как мне показать значение g-force для каждой секунды на оси X? Я пытался суммировать значения и конвертировать их, но результат явно неверный, так как я получаю значения до 63 г.

[ ОБНОВИТЬ: ]

  1. Мгновенные значения g-force (все 3 оси разделены) отображаются на графике (с использованием старших графиков). Видео файл gopro отображается (используя JavaScript API YouTube) рядом с графиком и воспроизводится в режиме реального времени.
  2. График и видео уже отлично работают бок о бок. Только значения перегрузки неправильны.
    Примечание: видеофайл имеет оверлей g-force (встроенный в него), показывающий 2 оси (x, y).
  3. Я наградил @Joseph_J только потому, что это казалось хорошим решением, и потому, что я вынужден давать вознаграждение (в выходные дни) системой SO. Спасибо всем за ваши ответы!

6

Решение

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

Я бы сказал, что лучше всего делать каждый расчет умножением $acc_x разрешением ваших данных, деленным на ускорение силы тяжести. Таким образом, в вашем случае разрешение ваших данных составляет 5 мс или одну двести сотой секунды, то есть ваш расчет должен быть $acc_x * 0.005/9.80665,

Используя предоставленную вами информацию, результат 63G, который вы получили, должен быть больше похож на 0.315G. Это кажется более уместным, хотя я не уверен в контексте данных.

РЕДАКТИРОВАТЬ: я забыл упомянуть, что вы все равно должны суммировать все значения, которые вы получаете от $acc_x * 0.005/9.80665 более 200 значений (вы можете сделать это в блоках или в процессе работы, выполнение в блоках будет менее затратным для системы, но работа будет более точной). Указано @Joseph_J

РЕДАКТИРОВАТЬ 2: В соответствии с вашим запросом источника, я не мог найти много от расчета среднего ускорения (и, следовательно, g-сила), но вы можете использовать тот же принцип за средней скоростью от скорости по графику времени, однако я нашел сценарий похож на ваш здесь: Источник а также Источник 2

Надеюсь это поможет!

2

Другие решения

Согласно моему комментарию, суммирование не работает, потому что сила не аддитивна с течением времени. Что вы хотите, чтобы рассчитать средний ускорение:

function convert_meters_per_second_squared_to_g($acc_array) {
$acc_average = array_sum($acc_array)/count($acc_array);
return $acc_average * 0.101971621297793;
}

$acc_x_array = [];
if (($handle = fopen($filepath, "r")) !== FALSE) {
while (($data = fgetcsv($handle, 1000, ",")) !== FALSE) {
list ($millis, $acc_x, $acc_y, $acc_z) = $data;

$acc_x_array[] = $acc_x;
}
}

$g_force = convert_meters_per_second_squared_to_g($acc_x_array);
1

Может быть, ваш вопрос можно рассматривать как эквивалент запроса чистого изменения скорости между выборками с интервалом в одну секунду?

В этом смысле вам нужно интегрировать все небольшие ускорения с интервалом в 5 мс, чтобы рассчитать чистое изменение скорости за период в одну секунду (то есть 200 выборок). Это изменение скорости, деленное на интервал в 1 секунду, представляет собой среднее ускорение за этот период в 1 секунду.

Итак, в вашем случае вам нужно добавить все AcclX, AcclY & Укажите значения за одну секунду и умножьте на 0,005, чтобы получить вектор, представляющий изменение скорости (в единицах метров в секунду). Если вы затем поделите это на одну секунду общего экстента временного окна и на 9.80665 м / с ^ 2, вы получите ускорение (вектор) в единицах G. Если вы хотите (скалярное) ускорение затем вы можете просто вычислить величину этого вектора как sqrt (ax ^ 2 + ay ^ 2 + az ^ 2).

Вы можете применить тот же принцип, чтобы получить среднее ускорение в другом временном окне, при условии, что вы делите сумму AcclX, AcclY, AcclY (после умножения на время выборки 0,005 с) на длительность временного окна. над которым вы интегрировали. Это похоже на аппроксимацию производной по времени функции f(t) от (f(t+d) - f(t))/d, Фактически, это лучшее приближение к производной в середине временного интервала, а именно t+d/2, Например, вы можете суммировать значения в окне 2 с, чтобы получить среднее значение в центре этого интервала 2 с. Нет необходимости просто сообщать об этих средних ускорениях каждые две секунды; вместо этого вы можете просто переместить окно на 0,5 с, чтобы получить следующее среднее значение ускорения, которое вы получите через 0,5 с.

1

ОБНОВЛЕНО ОБНОВЛЕНО РЕШЕНИЕ

Это решение возьмет ваш CSV и создаст массив, содержащий ваше время, Axe, Ay, & Значения Az после того, как они были преобразованы в G. Вы должны быть в состоянии взять этот массив и вставить его прямо в ваш график.

Значение, отображаемое на каждом интервале, будет усредненным ускорением «на» интервале до или после него.

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

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

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

Надеюсь, это работает для вас!

function formatAccelData($data, $split, $scale, $overlap = TRUE){

if(!$data || !$split || !$scale || !is_int($split) || !is_int($scale)){

return FALSE;

}

$g = 9.80665;
$round = 3;

$value1 = 1;
$value2 = 2;

if(!$overlap){ //Toggle overlapping data.

$value1 = 2;
$value2 = 1;

}

//Set the initial condition at t=0;
$results =  array();
$results[0]['seconds'] = 0;
$results[0]['Ax'] = round(($data[0][1])/$g, $round);
$results[0]['Ay'] = round(($data[0][2])/$g, $round);
$results[0]['Az'] = round(($data[0][3])/$g, $round);

$count = 1;
$interval = (int)(1000/$split)/$scale;

for($i = $interval; $i < count($data); $i += $interval){

$Ax = $Ay = $Az = 0;

for($j = $i - ($interval/$value1); $j < $i + ($interval/$value1); $j++){

$Ax += $data[$j][1];
$Ay += $data[$j][2];
$Az += $data[$j][3];

}

$results[$count]['seconds'] = round($count/$scale, $round);
$results[$count]['Ax'] = round(($Ax/($interval * $value2))/$g, $round);
$results[$count]['Ay'] = round(($Ay/($interval * $value2))/$g, $round);
$results[$count]['Az'] = round(($Az/($interval * $value2))/$g, $round);

$count++;

}


array_pop($results); //We do this because the last interval
//will not have enought data to be calculated.

//Set the final condition with the data from the end of the last complete interval.
$results[$count - 1]['seconds'] = round(($count - 1)/$scale, $round);
$results[$count - 1]['Ax'] = round(($data[$i - $interval][1])/$g, $round);
$results[$count - 1]['Ay'] = round(($data[$i - $interval][2])/$g, $round);
$results[$count - 1]['Az'] = round(($data[$i - $interval][3])/$g, $round);

return $results;

}

Использовать:

$data = array_map('str_getcsv', file($path));

$split = 5; //(int) - # of milliseconds inbetween datapoints.
$scale = 4; // (int) # of data points per second you want to display.
$overlap = TRUE;  //(Bool) - Overlap data from one interval to the next.
$results = formatAccelData($data, $split, $scale, $overlap);

print_r($results);

СТАРЫЕ ОБНОВЛЕННЫЕ РЕШЕНИЯ

Помните, что эта функция принимает среднее значение, приводящее к интервалу. Так что это действительно половина интервала позади.

function formatAccelData($data, $step){

$fps = 1000/$step;

$second = 1;
$frame = 0;
$count = 0;

for($i = 0; $i < count($data); $i += $fps){

$Ax = $Ay = $Az = 0;

for($j = 0; $j < $fps; $j++){

$Ax += $data[$frame][1];
$Ay += $data[$frame][2];
$Az += $data[$frame][3];

$frame++;

}

$results[$count]['seconds'] = $second;
$results[$count]['Ax'] = ($Ax/$fps) * 0.101971621297793;
$results[$count]['Ay'] = ($Ay/$fps) * 0.101971621297793;
$results[$count]['Az'] = ($Az/$fps) * 0.101971621297793;

$second++;
$count++;
}

return $results;

}

Как пользоваться:

$data = array_map('str_getcsv', file($path));

$step = 5; //milliseconds

$results = formatAccelData($data, $step);

print_r($results);
1
По вопросам рекламы [email protected]