在生活中,有些时候您的信号很嘈杂,而您想摆脱这种情况
对此
现有许多方法可以使数据平滑:局部线性回归和多项式回归,各种移动平均值:
https://en.wikipedia.org/wiki/Kernel_smoother
https://homepages.inf.ed.ac.uk/rbf/HIPR2/gsmooth.htm
https://www.stat.wisc.edu/~mchung/softwares/hk/hk.html
https://matthew-brett.github.io/teaching/smoothing_intro.html
How to calculate a Gaussian kernel matrix efficiently in numpy?
How to smooth the blocks of a 3D voxel world?
但是我发现对于我的情况,最合适的方法是高斯核平滑。对于我来说,它在台式机上像是一种魅力,但是当切换到移动设备时,由于计算量大,该算法使设备停顿了。
原因之一是,在平滑之前,我必须使采样率与其他信号相等,这大大提高了采样率,从而增加了处理所需的数据量。
这也导致了这样一个事实,即高斯内核的大小必须为数以万计的组件,这直接影响了我的幼稚方法的算法的复杂性,它需要将滤波器中的成千上万个元素相乘,将信号中的成千上万个分量相加,仅接收平滑数据的一个分量。
有一种方法可以有效地进行高斯核平滑,这需要使用傅立叶变换,而要高效实现该变换非常复杂。
因此,我认为不用沿着这条路走,实际上可以更有效地进行平滑处理,而不必深入研究傅立叶变换的复杂性。
基本上任何信号都只是按时间排序的对[time, value]
的集合。使用线性插值进行插值时,它始终可以用Polygonal chain表示,并且您实际上可以解析地平滑Polygonal chain的一个分量(即Line Segment)。我将不深入探讨如何在解析定义的线段上实际计算解析定义的内核的convolutional integral。值得在这里说的是,结果是一个巨大的分段函数:
这产生了许多if
语句:
public static Double Solution(Double x, Double w, Double x1, Double y1, Double x2, Double y2)
{
Double result;
if (x + w < x2 && w + x1 <= x)
{
result = (x * y1 - x2 * y1 - x * y2 + x1 * y2) / (x1 - x2);
}
else if (x1 < x + w && x < x1 && x + w < x2)
{
result = Math.Pow(w + x - x1, 2) * ((w + x + 2 * x1 - (3 * x2)) * y1 - (w + x - x1) * y2) * Math.Pow(w, -2) / (x1 - x2) / 6;
}
else if (x == x1 && x + w < x2)
{
result = y1 / 2 + w * (y1 - y2) / (x1 - x2) / 6;
}
else if (x + w < x2 && x1 < x && x < w + x1)
{
result = Math.Pow(w, -2) / (x1 - x2) * (Math.Pow(w, 3) * (y1 - y2) + 3 * w * w * (-x2 * y1 + x * (y1 - y2) + x1 * y2) - Math.Pow(x - x1, 2) * ((x + 2 * x1 - (3 * x2)) * y1 + (-x + x1) * y2) + 3 * w * (x - x1) * ((x + x1 - (2 * x2)) * y1 + (-x + x1) * y2)) / 6;
}
else if (x2 <= x + w && x < x1)
{
result = (x1 - x2) * (2 * y1 * x1 + x2 * y1 + x1 * y2 + 2 * x2 * y2 - 3 * w * (y1 + y2) - 3 * x * (y1 + y2)) * Math.Pow(w, -2) / 6;
}
else if (x2 <= x && w + x1 <= x && x < w + x2)
{
result = -Math.Pow(w - x + x2, 2) * ((w - x + x2) * y1 + (-w + x - 3 * x1 + (2 * x2)) * y2) * Math.Pow(w, -2) / (x1 - x2) / 6;
}
else if (x2 <= x && x < w + x1)
{
result = -(x1 - x2) * (2 * y1 * x1 + x2 * y1 + x1 * y2 + 2 * x2 * y2 + 3 * w * (y1 + y2) - 3 * x * (y1 + y2)) * Math.Pow(w, -2) / 6;
}
else if (x == x1 && (x + w == x2 && (x2 <= x && x + w < x1 && w + x2 <= x || x < w + x1) || x < w + x1 && x2 <= x + w && x < x2))
{
result = (-x1 + x2) * (3 * w * (y1 + y2) + (x1 - x2) * (y1 + 2 * y2)) * Math.Pow(w, -2) / 6;
}
else if (x < x2 && x2 <= x + w && w + x1 <= x)
{
result = Math.Pow(w, -2) / (x1 - x2) * (Math.Pow(w, 3) * (-y1 + y2) + 3 * w * w * (-x2 * y1 + x * (y1 - y2) + x1 * y2) + Math.Pow(x - x2, 2) * ((-x + x2) * y1 + (x - 3 * x1 + (2 * x2)) * y2) + 3 * w * (x - x2) * (-2 * x1 * y2 + x * (-y1 + y2) + x2 * (y1 + y2))) / 6;
}
else if (x < x2 && x2 <= x + w && x1 < x && x < w + x1)
{
result = Math.Pow(w, -2) / (x1 - x2) * (-2 * Math.Pow(x1, 3) * y1 + 3 * x1 * x1 * x2 * y1 + Math.Pow(x2, 3) * y1 - Math.Pow(x1, 3) * y2 - 3 * x1 * (x2 * x2) * y2 + 2 * Math.Pow(x2, 3) * y2 + 2 * Math.Pow(x, 3) * (-y1 + y2) - 3 * w * Math.Pow(x1 - x2, 2) * (y1 + y2) + 6 * x * x * (x2 * y1 - x1 * y2) + 3 * x * (2 * x1 * x2 * (-y1 + y2) + x1 * x1 * (y1 + y2) - (x2 * x2) * (y1 + y2))) / 6;
}
else
{
result = 0.0e0;
}
return result;
}
您还可以通过对这些线段进行平滑处理的总和来合并多个线段
从而将计算复杂度降低到您拥有的点数:
上面的if语句效率低下,并且存在数值稳定性问题。当x1,y1,x2,y2
定义的线段越来越大时,结果会爆炸。我正在尝试解决这些问题,但是比我预期的要难。甚至方程的仔细扩展也会在计算中引入一些奇怪的错误。因此,我认为与StackOverflow进行协商是一个好主意,以获取有关如何优化此语句并使它在数值上更稳定的更多想法。
先谢谢您