6

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

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

加速度计数据样本

在 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
}

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

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

[ 更新: ]

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

4 回答 4

2

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

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

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

编辑:我忘了提到你仍然应该对你从$acc_x * 0.005/9.80665200 多个值中收到的所有值求和,(你可以选择在块中执行此操作,或者在运行中执行,在块中执行对系统的负担会更少,但是运行会更准确)。@Joseph_J指出

编辑 2:根据您对来源的要求,我无法从计算平均加速度(因此 g 力)中找到太多信息,但您可以使用与时间图的平均速度相同的原理,但是,我确实找到了类似于您的场景:Source and Source 2

希望这可以帮助!

于 2018-05-04T10:56:16.997 回答
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);
于 2018-04-25T13:46:35.060 回答
1

更新的更新解决方案

此解决方案将获取您的 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);
于 2018-05-04T01:41:59.493 回答
1

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

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

因此,在您的情况下,您需要做的是在一秒钟内将所有 AcclX、AcclY 和 AcclZ 值相加,然后乘以 0.005 以获得表示速度变化的向量(以米为单位)每秒)。如果然后将其除以时间窗口的一秒总范围,再除以 9.80665m/s^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 秒后获得下一个报告的平均加速度。

于 2018-05-05T18:41:22.740 回答