【问题标题】:Drawing lines in canvas using accelerometer sensor data in windows phone 8.1在 windows phone 8.1 中使用加速度计传感器数据在画布中绘制线条
【发布时间】:2015-05-06 17:22:18
【问题描述】:

我正在根据设备移动在画布上绘制,我想根据移动移动在画布上绘制不同的字符。

目前它的工作,但我想找到时差,我想检测暂停,暂停意味着当用户不尝试绘制并且用户不移动手机时,因此应用程序可以假设现在用户想要绘制下一个字符。

如何在加速度计值中找到暂停。有什么逻辑吗?还告诉我如何平滑加速度计值,以便用户可以绘制没有噪音的线条。

【问题讨论】:

  • Weighted Moving Average 应该可以帮助您处理噪声数据。
  • 但是如何定义权重值,我将所有值视为平等。还告诉我,我在 3 轴上有加速度计值,但在 2D(x 和 y)中绘制线如何基于 3D 确定 2D 点以使线更有效。
  • 只要决定你想要使用多少之前的点。把这些加起来,f.ex。如果最后 5 个,则 5+4+3+2+1 = 15。现在您使用 1/15 加权 5.最后一个点,使用 1/15 加权 4.最后一个 2/15 等,直到它们总和为当前值位置,继续下一个。每个轴都相同。你使用什么语言(VB.net/C#..)?
  • 我给出了一个更多关于移动平均的答案。它可能不完全是您所要求的 - 如果不是,则将其视为附录。代码在 JS 中,如果您使用其中之一,应该很容易转换为 VB/C#/C++ 等。

标签: c# windows-phone-8.1 wpf-controls accelerometer


【解决方案1】:

我对加速器部分无能为力,但对于数据中的噪音,这是使用 Weighted Moving Average 的一种方法。

基础很简单:

  • 找出要在电流前多少点用于平滑
  • 根据长度 f.ex. 计算重量如果长度为 5,那么权重 = 1+2+3+4+5 = 15
  • 从权重长度开始迭代每个数据点(您可以从 1 开始并缩短权重 - 下面我将演示后一种方法)
  • 对于点电流 - 5 乘以 1/15,对于电流 - 4 乘以 2/15,依此类推。总和存储为该点的值,重复下一个值点

现场演示

下面是一个演示(进入整页查看所有图形)。我用 JavaScript 编写了它,因此它可以在答案中实时显示。我认为您将其转换为您正在使用的语言应该没有什么问题(未说明)。

移动滑块以增加权重的点数。您可以通过多次运行数据以使数据更加平滑。原始数据是带有噪声抖动的正弦曲线。通过许多点,您可以看到曲线平滑以复制这一点。仅使用 9-10 点长度超过 2 次传球即可获得良好的结果,且时间延迟非常短:

var ctx = document.querySelector("canvas").getContext("2d"),
    rng = document.querySelector("input"),
    val = document.querySelector("span"),
    data = [], scale = 30;

// generate sinus wave with noise jitters
for(var i = 0; i < ctx.canvas.width; i += 2)
    data.push(Math.sin(i*0.1) * Math.random() + Math.random())

// draw initial smoothed curve (length=1, no smoothing)
drawWMA();

// calculate moving average
function drawWMA() {
    var len = +rng.value,        // get smoothing length (number of previous points)
        dataa = [], datab = [],  // pass A and B arrays
        weight = 0;              // calc weight based on length
  
  val.innerHTML = len;
  
  ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
  ctx.beginPath();
  
  // calc weight
  for(var i = 1; i <= len; i++) weight += i;  // add range together [1, length]
  
  // plot original data at top of canvas
  plot(data, 30);

  // PASS 1: Calc new smoothed array
  dataa = calcWMA(data, len, weight);
  
  // plot smoothed curve
  ctx.fillText("FIRST PASS:", 0, 100);
  plot(dataa, 120);
    
  // PASS 2 (optional)
  datab = calcWMA(dataa, len, weight);
  ctx.fillText("SECOND PASS:", 0, 190);
  plot(datab, 210);
  
  ctx.stroke();  // render plots
}

function calcWMA(data, len, weight) {
  var i, t, datao = [];
  
  // calc new smoothed array 
  for(i = 0; i < data.length; i++) {       // iterate from length to end of data
    var v = 0;                             // calc average value for this position
    for(t = 0; t < len; t++) {             // [1, len]
      if (i-t >= 0)
        v += data[i-t] * ((t+1) / weight); // weight previous values based on -delta
    }
    datao.push(v);                         // store new value
  }
  return datao
}

function plot(data, y) {
  ctx.moveTo(0, y + data[0]*scale);
  for(i = 1; i < data.length; i++) ctx.lineTo(i * 2, y + data[i]*scale);
}

rng.onchange = rng.oninput = drawWMA;
<label>Points to consider: <input type="range" min=1 max=50 value=1></label><span>1</span><br>
<canvas width=600 height=300></canvas>

另一种方法是使用Savitzky–Golay filter,它给出了类似的结果,但不会“牺牲”最后的任何点(移动平均线将向前推进或在最后裁剪)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-10-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多