7

我正在测量一些系统性能数据以将其存储在数据库中。从这些数据点,我随着时间的推移绘制折线图。从本质上讲,这些数据点有点嘈杂,即。每个点都至少偏离局部平均值。当从一个点直接绘制线图到下一个点时,它会产生锯齿状的图形。在像每个像素 > 10 个数据点这样的大时间尺度上,这种噪声被压缩成一个宽的锯齿线区域,即 20 像素高而不是较小尺度的 1 像素。

我读过关于线条平滑、抗锯齿、简化和所有这些东西。但我发现的一切似乎都与别的东西有关。

我不需要抗锯齿,.NET 在屏幕上画线时已经为我做到了。

我不想简化。我需要极端值保持可见,至少其中大部分是可见的。

我认为它朝着样条曲线的方向发展,但我找不到太多示例图像来评估所描述的东西是否是我想要的。不过,我确实在 Google Books 上找到了一本高度科学的书,里面全是半页长的公式,我现在不想读完……

举个例子,看看 Linux/Gnome 的系统监视器应用程序。我用平滑线绘制了最近的 CPU/内存/网络使用情况。这可能有点过于简单,但我会尝试一下,看看我是否可以调整它。

我更喜欢 C# 代码,但算法或其他语言的代码也可以,只要我可以将其移植到 C# 而不需要外部引用。

4

5 回答 5

6

你可以做一些数据平滑。不要使用真实数据,而是应用一个简单的平滑算法来保持峰值,如 Savitzky-Golayfilter。

你可以在这里得到系数

最简单的做法是:

从我链接到的网站上获取最高系数:

// For np = 5 = 5 data points
var h = 35.0;
var coeff = new float[] { 17, 12, -3 }; // coefficients from the site
var easyCoeff = new float[] {-3, 12, 17, 12, -3}; // Its symmetrical
var center = 2; // = the center of the easyCoeff array

// 现在为您的数据中的每个点计算一个平滑点:

smoothed[x] = 
   ((data[x - 2] * easyCoeff[center - 2]) +
    (data[x - 1] * easyCoeff[center - 1]) +
    (data[x - 0] * easyCoeff[center - 0]) +
    (data[x + 1] * easyCoeff[center + 1]) +
    (data[x + 2] * easyCoeff[center + 2])) / h;

前 2 点和后 2 点在使用 5 点时无法平滑。

如果您希望您的数据更加“平滑”,您可以尝试使用更大数据点的系数。

现在您可以通过“平滑”数据画一条线。np = 点数越大,数据越平滑。但是你也会失去峰值精度,但当简单地将一些点平均在一起时不会那么多。

于 2010-12-08T16:32:40.323 回答
2

您无法在图形代码中解决此问题。如果您的数据有噪声,那么无论您使用哪种线平滑算法,图表也会有噪声。您需要先过滤数据。使用从原始数据插值的点创建第二个数据集。最小二乘拟合是一种常用技术。平均很容易实现,但往往会隐藏极端情况。

于 2010-12-08T16:04:29.140 回答
1

我认为您正在寻找的是提供“样条线”的例程。这是一个描述样条的链接:

http://en.wikipedia.org/wiki/Spline_(数学)

如果是这种情况,我对样条库没有任何建议,但最初的谷歌搜索出现了一堆。

抱歉没有代码,但希望知道这些术语将有助于您的搜索。

鲍勃

于 2010-12-08T15:08:20.380 回答
0

减少数据点的数量,在显示之前使用 MIN/MAX/AVG。它会看起来更好,它会更快

于 2010-12-08T15:15:28.167 回答
0

网络流量图通常使用加权平均值。您可以每秒采样一次到一个长度为 10 的循环列表中,并且对于图形,在每个样本处,绘制样本的平均值。

如果 10 个不够,您可以存储更多。您也不需要从头开始重新计算平均值:

new_average = (old_average*10 - replaced_sample + new_sample)/10

但是,如果您不想存储全部 10 个,则可以使用以下方法进行近似:

new_average = old_average*9/10 + new_sample/10

许多路由器使用它来节省存储空间。这以指数方式向当前的流量速率倾斜。

如果您确实实现了这一点,请执行以下操作:

new_average = old_average*min(9,number_of_samples)/10 + new_sample/10
number_of_samples++

以避免最初的加速。您还应该调整 9/10、1/10 比率以实际反映每个样本的时间段,因为您的计时器不会每秒准确触发一次。

于 2010-12-08T16:41:10.750 回答