从加速度计算g力1秒间隔

时间:2018-04-25 13:20:56

标签: php gopro

我从GoPro元数据文件(github library)中提取了一个包含加速度计数据(以m / s 2 为单位)的CSV文件。

一秒的加速度计在3轴上包含约200个数据样本。此文件的示例如下所示:

accelerometer data sample

在PHP中,对于X轴上的每个瞬时值,我将m / s 2 转换为:

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

CSV文件的200行(1秒)的示例代码:

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

但是如何在X轴上显示每秒的g力值?我试图总结这些值并将其转换,但结果显然是错误的,因为我得到了值到63 G。

[更新:]

  1. 即时g力值(全部3轴,分开)显示在图表上(使用highcharts)。 gopro视频文件(使用YouTube javascript API)与图表并排显示并实时播放。
  2. 图表和视频已经并排运行良好。只有g-force值是错误的 注意:视频文件有一个g-force叠加(嵌入其中),显示2轴(x,y)。
  3. 我已经奖励了@Joseph_J,因为它似乎是一个很好的解决方案,因为我被迫通过SO系统给予奖励(周末)。谢谢大家的回答!

4 个答案:

答案 0 :(得分:2)

我相信你将每个瞬时值视为超过1秒,而不是瞬间。

我说你最好的选择是通过将$acc_x乘以数据的分辨率除以重力的加速度来进行每次计算。因此,在您的情况下,数据的分辨率为5毫秒或百分之二十二秒,这意味着您的计算应为$acc_x * 0.005/9.80665

使用您提供的信息,您获得的63G结果应该更像是0.315G。这似乎更合适,但我不确定数据的上下文。

编辑:我忘了提到你仍然应该从$acc_x * 0.005/9.80665超过200个值总结你收到的所有值(你可以选择在块中执行此操作,或者在运行时执行此操作,在块中执行将是减少对系统的负担,但运行会更准确)。由@Joseph_J

指出

编辑2:根据您对来源的要求,我无法从计算平均加速度(以及因此g力)中找到太多,但是您可以使用与速度随时间变化的平均速度相同的原理图,但是,我确实在这里找到了与您类似的方案:SourceSource 2

希望这有帮助!

答案 1 :(得分:1)

根据我的评论,总结它并不起作用,因为力量不会随着时间的推移而累加。你想要的是计算平均加速度:

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

答案 2 :(得分:1)

更新的更新解决方案

此解决方案将使用您的CSV并创建一个包含您的时间的数组,Ax,Ay,&转换为G&之后的Az值。您应该可以使用此数组并将其直接输入到图表中。

每个间隔显示的值将是平均加速度" at"它之前或之后的间隔时间。

我在函数中添加了一个参数,以便您定义要在图表上显示的每秒间隔数。这有助于平滑图表。

我还设置了初始值和最终值。由于这在该间隔处找到平均加速度,因此需要间隔两侧的数据。显然在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);

答案 3 :(得分:1)

也许您的问题可以被视为等同于以一秒的间隔要求样本之间的速度净变化?

从这个意义上说,你需要做的是整合5ms间隔内的所有小加速度,以便计算一秒钟内的速度净变化(即200个样本)。速度的变化除以1秒的间隔,表示在1秒的时间内的平均加速度。

所以,在你的情况下,你需要做的是将所有的AcclX,AcclY&amp; AcclZ值在一秒钟的时间内,乘以0.005得到表示速度变化的矢量(以米/秒为单位)。如果你将它除以时间窗口的一秒总范围,然后除以9.80665m / s ^ 2,你将得到以G为单位的(向量)加速度。如果你想要(标量)加速度然后你可以计算出该向量的大小,如sqrt(ax ^ 2 + ay ^ 2 + az ^ 2)。

您可以应用相同的原则来获得不同时间窗口的平均加速度,只要您将AcclX,AcclY,AcclY(乘以0.005s样本间时间)之和除以持续时间您整合的时间窗口。这就像通过f(t)逼近函数(f(t+d) - f(t))/d的时间导数一样。实际上,这是对时间间隔中点的导数的更好近似,即t+d/2。例如,您可以在2s窗口中总结值,以获得2s时间中心的平均值。没有必要每两秒报告一次这些平均加速度;相反,您只需将窗口移动0.5秒即可在0.5秒后获得下一次报告的平均加速度。