在VB.Net中平滑曲线 [英] Smoothing a curve in VB.Net

查看:152
本文介绍了在VB.Net中平滑曲线的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

您好,所有

我是一个业余爱好者开发人员,而我碰到了一个问题问题,对于我的大脑来说太多了.我有一个数据集,该数据集为我提供了一组数据点-每个X值一个Y值.这些值给出的曲线是锯齿状的,我需要使曲线平滑.第二个问题是,对于某些数据集,缺少一些X值.如何填写缺失的值?

任何帮助或示例代码将不胜感激.

Hi, All

I''m a hobbyist developer, and I''ve hit a corker of a problem, too much for my brain. I have a data set that gives me a set of data points - one Y value for every X-value. The curve that these values give is jagged, and I need to smooth the curve. The second problem is that for some data sets, there are some X-values missing. How do I fill in the missing values?

Any help or sample code would be greatly appreciated.

推荐答案

嗨!

可以通过计算所谓的移动平均线来平滑曲线.因此,原始数据集中的每个值(数据点)都将替换为根据值本身及其周围值计算出的平均值.

下面是一个示例函数:
Hi!

Smoothing a curve can be done by calculating what is called a moving average. Hereby, each value (data point) in the original data set is replaced by an average calculated from the value itself and its surrounding values.

An example function would be the following:
''' <summary>
''' Calculates the moving average with the given range over the given array and returns the result.
''' </summary>
''' <param name="arr">The array to use for calculation.</param>
''' <param name="Range">The number of previous and following values to average to the resulting value.</param>
Public Function CalcMovAvg(ByVal arr As Double(), ByVal Range As Byte) As Double()
	'Create an array with the same size as the given one
	Dim ret(UBound(arr)) As Double

	'The indizes between which the values will be averaged; change with each iteration
	Dim FromIndex, ToIndex As Integer
	'Buffer for average calculation; changes with each iteration
	Dim TempAvg As Double

	'Iterate through every element in the given array
	For i As Integer = 0 To UBound(arr)
		'Set start and end indizes (keep array bounds in mind)
		FromIndex = If(i < Range, 0, i - Range)
		ToIndex = If((UBound(arr) - i) < Range, UBound(arr), i + Range)

		'Clear buffer from previous calculations
		TempAvg = 0

		'Calculate the average from arr(FromIndex) to arr(ToIndex)
		For j As Integer = FromIndex To ToIndex
			TempAvg += arr(j) / (ToIndex + 1 - FromIndex)
		Next

		'Save average in resulting array
		ret(i) = TempAvg
	Next

	'Return result
	Return ret
End Function



例如,如果您有一系列这样的值:
arr = {3,8,1,7,4,2}

并将Range设置为1,该函数将计算如下:
ret(0)=(3 + 8)/2
ret(1)=(3 + 8 + 1)/3
ret(2)=(8 +1 + 7)/3
...

Range的值越高,平均的值越多,结果曲线将越平滑.

对于您有时遇到的X值缺失的第二个问题,我想最简单的解决方案是执行看起来像这样的线性插值(将0值视为缺失):

arr = {3,8, 0 0 ,4,2}
->
ret = {3,8, 6.666 5.333 ,4,2}

您采用与缺失值相邻的现有值(在本例中为8和4),并设想它们之间的线性增加/减少.也许其他人可以为您提供一些代码.

希望对您有所帮助.



If you, for example have a series of values like this:
arr = {3, 8, 1, 7, 4, 2}

and have Range set to 1, the function will calculate as follows:
ret(0) = (3 + 8) / 2
ret(1) = (3 + 8 + 1) / 3
ret(2) = (8 + 1 + 7) / 3
...

The higher the value of Range, the more values will be averaged, the smoother the resulting curve will be.

For your second problem of X values sometimes missing, I suppose the simplest solution would be to perform a linear interpolation that would look like this (treating 0-values as missing):

arr = {3, 8, 0, 0, 4, 2}
->
ret = {3, 8, 6.666, 5.333, 4, 2}

You take the existing values that are next to those that are missing (in the example, 8 and 4) and imagine a linear increase/decrease between them. Maybe somebody else can provide you some code for that.

Hope this helped.


问候,

如前所述,填写缺失数据点的最简单方法是应用线性插值".基本上,这涉及到计算两个已知数据值之间的梯度,然后使用它来计算与已知数据点之一的垂直偏移.

例如给定两个数据点(X1=1, Y1=10)(X4=4, Y4=25),我们可以如下计算缺少的X2和X3的Y值;
Greetings,

As previously stated, the simplest way to fill in the missing data points is to apply "Linear Interpolation". Basically this involves calculating the gradient between the two known data values and then using it to calculate the vertical offset from one of the known data points.

e.g. Given two data points (X1=1, Y1=10) and (X4=4, Y4=25) we can calculate the Y values for the missing X2 and X3 as follows;
<br />
       Gradient = (Y2-Y1)/(X2-X1)<br />
       Y2 = Y1 + Gradient*(X2-X1)<br />
       Y3 = Y1 + Gradient*(X3-X1)<br />



自动填充数据数组中的空白只需在数组中找到一个连续丢失的数据点的块,然后将上述公式应用于该块中的每个点即可.

例如



Automatically filling in the gaps in your data array is simply a matter of locating a block of consecutive missing data points in the array and then applying the above formulas to each point in the block.

e.g.

Private Sub ArrayInterpolation(ByRef arr() As Double)
  Dim FirstMissingItem As Integer = 0
  For Current As Integer = arr.GetLowerBound(0) To arr.GetUpperBound(0)
    If arr(Current) = 0.0 Then
      If FirstMissingItem = 0 Then
        FirstMissingItem = Current  'mark start of block
      End If
    Else
      If FirstMissingItem > 0 Then  'true if preceded by a known value

        'interpolate values for block
        Dim Gradient As Double = (arr(Current) - arr(FirstMissingItem -1)) _
                                 /(Current - FirstMissingItem + 1)
        For MissingItem As Integer = FirstMissingItem To (Current - 1)
           arr(MissingItem) = arr(FirstMissingItem - 1) _
                              + Gradient * (MissingItem - FirstMissingItem + 1)
        Next
      End If
      FirstMissingItem = 0  'clear flag
    End If
  Next
End Sub



外循环标识连续丢失的数据项的块.它将FirstMissingItem 变量设置为遇到的第一个缺失项的索引;当遇到第二个已知值时,它将验证该块之前是否有一个已知数据值,然后进入内插部分.此时,Current 将保存该块之后的第一个已知数据项的索引.然后计算两个已知数据点(FirstMissingItem-1Current)之间的梯度,并由内部循环使用该梯度对块中每个项目的值进行插值.

可以通过运行此小的测试例程来测试以上内容;



The outer loop identifies blocks of consecutive missing data items. It sets the FirstMissingItem variable to the index of the first missing item encountered; when a second known value is encountered it verifies that the block was preceded by a known data value and then proceeds to the interpolation section. At this point Current will hold the index of the first known data item following the block. The gradient is then calculated between the two known data points (FirstMissingItem-1 and Current) and is used by the inner loop to interpolate values for each item within the block.

The above can be tested by running this small test routine;

Private Sub ArrayTest()
    Dim arr() As Double = {3, 8, 0, 0, 4, 2}
    Call ArrayInterpolation(arr)
    For i As Integer = arr.GetLowerBound(0) To arr.GetUpperBound(0)
        Debug.Print(String.Format("X={0}, Y={1}", i, arr(i)))
    Next i
End Sub




请注意,给出的代码假定数组索引等于X坐标.同样,上述例程仅进行内插...而不进行内插(要看到这一点,请用{0, 3, 8, 0, 0, 4, 2, 0}替换测试Sub中的数组初始化值.数组将不会被替换,因为在每种情况下只有一个已知的数据值).

希望对您有所帮助.




Note that the code given assumes that the array index is equal to the X-coordinate. Also, the above routine only interpolates ... it does not extrapolate (to see this, replace the array initialization value in the test Sub with {0, 3, 8, 0, 0, 4, 2, 0} .. the zeroes at the start and end of the array will not be replaced because there is only one known data value in each case).

Hope this helps.


非常感谢所有建议-我将把它们应用于数据,并让您知道会发生什么.如果我能动动脑筋,那就麻木了!
Thanks SO MUCH for all the suggestions - I''m going to apply them to the data and will let you know what happens. If I can get my brain to co-operate, it''s gone numb!


这篇关于在VB.Net中平滑曲线的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆