一台机器正在测量,并给我连续的离散数字,像这样:
1 2 5 7 8 10 11 12 13 14 18
假设这些测量值可以偏离2个点,并且每5秒生成一次测量值。我想忽略可能相同的测量
就像连续的2和3可以是相同的因为误差范围是2那么我如何划分数据以使我只得到不同的测量值但是我也想处理测量值不断增加的情况,就像这样
1 2 3 4 5 6 7 8 9 10
在这种情况下,如果我们继续忽略差值小于2的连续数字,那么我们可能会失去实际的测量值。
是否存在一类算法?你怎么解决这个问题?
只要去掉在前一个(保留的)数字范围内的任何数字。它应该只是工作。
递增的例子:
1被保留,2被删除,因为它在1的范围内,3被删除,因为它在1的范围内,然后4被保留,5和6被删除到4的范围,然后7被保留,等等,所以如果它足够大,你仍然保持增加的趋势(这是你想要的,对吗?
对于原始示例,结果将得到1、5、8、11、14、18。
在某些工作中,处理这种性质的问题的标准方法是使用卡尔曼滤波器。
引用维基百科:
它的[卡尔曼滤波器的]目的是利用测量随时间观察,包含噪音(随机变化)和其他不准确,产生的值倾向于更接近真实值测量和它们的相关的计算值。
过滤器本身很容易实现,但确实需要校准。
我将有两个队列:
- 临时队列
- 最后队列/列表
您的第一个值将进入临时队列并进入最终列表。当新值传入时,检查新值是否在列表中最后一个值的死区内。如果是,则将其添加到临时队列中。如果没有,那么将其添加到最终列表中。如果在死带之外获得新值之前临时队列的大小开始增加,那么一旦超出死带,就检查一下这些值在整个时间内是单调增加还是减少。如果它们总是增加或减少,则将队列的内容添加到最终列表中,否则只需向最终列表添加单个新值。这是它的总体要点。
下面是我快速编写的一些代码,它实现了一个类来做我上面描述的事情:
public class MeasurementsFilter
{
private Queue<int> tempQueue = new Queue<int>();
private List<int> finalList = new List<int>();
private int deadband;
public MeasurementsFilter(int deadband)
{
this.deadband = deadband;
}
public void Reset()
{
finalList.Clear();
tempQueue.Clear();
}
public int[] FinalValues()
{
return finalList.ToArray();
}
public void AddNewValue(int value)
{
// if we are just starting then the first value always goes in the list and queue
if (tempQueue.Count == 0)
{
tempQueue.Enqueue(value);
finalList.Add(value);
}
else
{
// if the new value is within the deadband of the last value added to the final list
// then enqueue the value and wait
if ((tempQueue.Peek() - deadband <= value) && (value <= tempQueue.Peek() + deadband))
{
tempQueue.Enqueue(value);
}
// else the new value is outside of the deadband of the last value added to the final list
else
{
tempQueue.Enqueue(value);
if (QueueIsAlwaysIncreasingOrAlwaysDecreasing())
{
//dequeue first item (we already added it to the list before, but we need it for comparison purposes)
int currentItem = tempQueue.Dequeue();
while (tempQueue.Count > 0)
{
// if we are not seeing two in a row of the same (i.e. they are not duplicates of each other)
// then add the newest value to the final list
if (currentItem != tempQueue.Peek())
{
currentItem = tempQueue.Dequeue();
finalList.Add(currentItem);
}
// otherwise if we are seeing two in a row (i.e. duplicates)
// then discard the value and loop to the next value
else
{
currentItem = tempQueue.Dequeue();
}
}
// add the last item from the final list back into the queue for future deadband comparisons
tempQueue.Enqueue(finalList[finalList.Count - 1]);
}
else
{
// clear the queue and add the new value to the list and as the starting point of the queue
// for future deadband comparisons
tempQueue.Clear();
tempQueue.Enqueue(value);
finalList.Add(value);
}
}
}
}
private bool QueueIsAlwaysIncreasingOrAlwaysDecreasing()
{
List<int> queueList = new List<int>(tempQueue);
bool alwaysIncreasing = true;
bool alwaysDecreasing = true;
int tempIncreasing = int.MinValue;
int tempDecreasing = int.MaxValue;
int i = 0;
while ((alwaysIncreasing || alwaysDecreasing) && (i < queueList.Count))
{
if (queueList[i] >= tempIncreasing)
tempIncreasing = queueList[i];
else
alwaysIncreasing = false;
if (queueList[i] <= tempDecreasing)
tempDecreasing = queueList[i];
else
alwaysDecreasing = false;
i++;
}
return (alwaysIncreasing || alwaysDecreasing);
}
}
下面是一些测试代码,您可以将其放入Winform Load事件或按钮点击中:
int[] values = new int[] { 1, 2, 2, 1, 4, 8, 3, 2, 1, 0, 6 };
MeasurementsFilter filter = new MeasurementsFilter(2);
for (int i = 0; i < values.Length; i++)
{
filter.AddNewValue(values[i]);
}
int[] finalValues = filter.FinalValues();
StringBuilder printValues = new StringBuilder();
for (int i = 0; i < finalValues.Length; i++)
{
printValues.Append(finalValues[i]);
printValues.Append(" ");
}
MessageBox.Show("The final values are: " + printValues);