使用 windows phone 中的加速计传感器数据在 canvas 中绘制线条 8.1

Drawing lines in canvas using accelerometer sensor data in windows phone 8.1

我正在canvas基于设备移动绘制,我想在canvas中基于移动移动绘制不同的字符。

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

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

我无法帮助加速器部分,但对于数据中的噪声,这是使用 Weighted Moving Average.

的一种方法

基础很简单:

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

现场演示

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

移动滑块以增加权重点数。您可以 运行 通过多次传递来使数据更加平滑。原始数据是带有噪声抖动的正弦曲线。对于许多点,您可以看到曲线平滑以复制它。只需在 2 遍中使用 9-10 点长度即可获得良好的结果,并且几乎没有时间延迟:

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 给出类似的结果,但不是 "sacrifice" 末尾的任何点(移动平均线将向前推进或在末尾裁剪)。