使用 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" 末尾的任何点(移动平均线将向前推进或在末尾裁剪)。
我正在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" 末尾的任何点(移动平均线将向前推进或在末尾裁剪)。