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

丶灬走出姿态 提交于 2019-12-02 10:42:24

I cannot help with the accelerator part, but for the noise in the data, here is one approach using Weighted Moving Average.

The basics are simple:

  • Find out how many points before current you want to use for smoothing
  • Calculate a weight based on length, f.ex. if length is 5 then the weight = 1+2+3+4+5 = 15
  • Iterate each data point starting from length of weight (you can start at 1 and cut the weighting short - below I'll demo the latter approach)
  • For point current - 5 multiply with 1/15, for current - 4 multiply with 2/15 and so forth. The sum is stored as value for this point, repeat for the next value points

Live demo

Below is a demo (enter full page to see all graphics). I wrote it in JavaScript so it could be shown live here in the answer. I think you should have little problem converting it into the language you're using (which is not stated).

Move the slider to increase number of points to weight. You can run the data through several passes to smooth even more. The original data is a sinus curve with noise jitter. With many points you can see the curve smooths to replicate this. Just using 9-10 points length over 2 passes will give a good result with very little time delay:

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>

A different approach would be to use a Savitzky–Golay filter which gives a similar result, but not "sacrifice" any points at the end (moving average will push forward or crop at the end).

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!