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

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

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

accelerometer data sample

В 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. Спасибо всем за ваши ответы!

Ответы [ 4 ]

0 голосов
/ 05 мая 2018

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

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

Итак, в вашем случае вам нужно сложить все AcclX, Значения AcclY и AcclZ за одну секунду и умножить на 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 с.

0 голосов
/ 04 мая 2018

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

Это решение примет ваш CSV и создаст массив, содержащий ваши значения времени, Ax, 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);
0 голосов
/ 04 мая 2018

Я полагаю, что вы обрабатываете каждое мгновенное значение, как если бы оно произошло в течение 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

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

0 голосов
/ 25 апреля 2018

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

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);
...