C# 是否从数据中删除噪声和极值?

C# 是否从数据中删除噪声和极值?,c#,serial-port,psoc,C#,Serial Port,Psoc,我有一个程序,通过串行方式从PSoC上的ADC读取数据 数字以格式发送,包括“”符号,以二进制格式传输00111100 xxxxxxxxxxxxxxxx 00111110,其中“X”构成16位无符号整数 有时读取效果不太好,程序使用“>”符号的二进制数据作为其编号的一部分,导致出现故障,如2500个样本的屏幕截图所示(忽略样本800到1500之间的下降,这是我在玩ADC输入): 您可以清楚地看到,该故障每次都会导致数据采样大致相同的值 数据每秒发送十次,所以我计划做的是采集十个样本,消除任何小

我有一个程序,通过串行方式从PSoC上的ADC读取数据

数字以
格式发送,包括“”符号,以二进制格式传输
00111100 xxxxxxxxxxxxxxxx 00111110
,其中“X”构成16位无符号整数

有时读取效果不太好,程序使用“>”符号的二进制数据作为其编号的一部分,导致出现故障,如2500个样本的屏幕截图所示(忽略样本800到1500之间的下降,这是我在玩ADC输入):

您可以清楚地看到,该故障每次都会导致数据采样大致相同的值

数据每秒发送十次,所以我计划做的是采集十个样本,消除任何小故障(该值远离其他样本),然后平均剩余的值以稍微平滑曲线。输出可以在0到50000+之间,所以我不能只删除某个数字以下的值

我不确定如何删除那些远远超出10个样本组中其他值范围的值,因为可能有两个样本受此故障影响。也许有其他方法可以修复这些故障数据,而不仅仅是解决问题

这样做的最佳方式是什么?以下是我到目前为止的代码(在DataReceivedEvent方法中):


工程上常用的方法是添加阻尼函数。阻尼函数基本上作用于参数的微分,即连续值之间的差值。关于如何选择阻尼函数没有硬性规定,大多数情况下,这些规则都经过调整以产生合理的结果


因此,在您的情况下,这意味着您将最新的值与之前的值进行比较。如果大于某个数量,则将最新值默认为前一个值,或将最新值减少某个固定因子,例如10%或1%。这样既不会丢失信息,也不会出现突然的跳跃和故障。

工程中常用的方法是添加阻尼功能。阻尼函数基本上作用于参数的微分,即连续值之间的差值。关于如何选择阻尼函数没有硬性规定,大多数情况下,这些规则都经过调整以产生合理的结果


因此,在您的情况下,这意味着您将最新的值与之前的值进行比较。如果大于某个数量,则将最新值默认为前一个值,或将最新值减少某个固定因子,例如10%或1%。这样,您既不会丢失信息,也不会出现突然的跳转和故障。

我怀疑您的问题可能是因为您从串行端口读取的字节数比您想象的要少

例如,
sp.Read(spBuffer,0,4)不一定读取4个字节。它可以读取1、2、3或4个字节(但不能读取0)

如果您知道应该读取一定数量的字节,请尝试以下操作:

public static void BlockingRead(SerialPort port, byte[] buffer, int offset, int count)
{
    while (count > 0)
    {
        // SerialPort.Read() blocks until at least one byte has been read, or SerialPort.ReadTimeout milliseconds
        // have elapsed. If a timeout occurs a TimeoutException will be thrown.
        // Because SerialPort.Read() blocks until some data is available this is not a busy loop,
        // and we do NOT need to issue any calls to Thread.Sleep().

        int bytesRead = port.Read(buffer, offset, count);
        offset += bytesRead;
        count -= bytesRead;
    }
}
sp.Read(spBuffer, 0, 4);
如果在读取过程中有超时,则应该有一个
TimeoutException
,因此无需在其中设置自己的超时

然后像这样更改呼叫:

public static void BlockingRead(SerialPort port, byte[] buffer, int offset, int count)
{
    while (count > 0)
    {
        // SerialPort.Read() blocks until at least one byte has been read, or SerialPort.ReadTimeout milliseconds
        // have elapsed. If a timeout occurs a TimeoutException will be thrown.
        // Because SerialPort.Read() blocks until some data is available this is not a busy loop,
        // and we do NOT need to issue any calls to Thread.Sleep().

        int bytesRead = port.Read(buffer, offset, count);
        offset += bytesRead;
        count -= bytesRead;
    }
}
sp.Read(spBuffer, 0, 4);
为此:

BlockingRead(sp, spbuffer, 0, 4);

我怀疑您的问题可能是因为从串行端口读取的字节数比您想象的要少

例如,
sp.Read(spBuffer,0,4)不一定读取4个字节。它可以读取1、2、3或4个字节(但不能读取0)

如果您知道应该读取一定数量的字节,请尝试以下操作:

public static void BlockingRead(SerialPort port, byte[] buffer, int offset, int count)
{
    while (count > 0)
    {
        // SerialPort.Read() blocks until at least one byte has been read, or SerialPort.ReadTimeout milliseconds
        // have elapsed. If a timeout occurs a TimeoutException will be thrown.
        // Because SerialPort.Read() blocks until some data is available this is not a busy loop,
        // and we do NOT need to issue any calls to Thread.Sleep().

        int bytesRead = port.Read(buffer, offset, count);
        offset += bytesRead;
        count -= bytesRead;
    }
}
sp.Read(spBuffer, 0, 4);
如果在读取过程中有超时,则应该有一个
TimeoutException
,因此无需在其中设置自己的超时

然后像这样更改呼叫:

public static void BlockingRead(SerialPort port, byte[] buffer, int offset, int count)
{
    while (count > 0)
    {
        // SerialPort.Read() blocks until at least one byte has been read, or SerialPort.ReadTimeout milliseconds
        // have elapsed. If a timeout occurs a TimeoutException will be thrown.
        // Because SerialPort.Read() blocks until some data is available this is not a busy loop,
        // and we do NOT need to issue any calls to Thread.Sleep().

        int bytesRead = port.Read(buffer, offset, count);
        offset += bytesRead;
        count -= bytesRead;
    }
}
sp.Read(spBuffer, 0, 4);
为此:

BlockingRead(sp, spbuffer, 0, 4);

首先,我强烈建议您解决解析问题,这样您就不必担心小故障值

但是,如果您仍然决定在以后继续修复数据:
我看到所有的故障数据都在某个特定值附近:~16000。事实上,从图表上看,每次都差不多。您可以简单地忽略故障值范围内的数据(您必须进行一些测试以找到准确的界限),然后使用最后一个非故障值来代替。

首先,我强烈建议您只需解决解析问题,然后您就不必担心故障值

但是,如果您仍然决定在以后继续修复数据:
我看到所有的故障数据都在某个特定值附近:~16000。事实上,从图表上看,每次都差不多。您只需忽略故障值范围内的数据(您必须进行一些测试以找到准确的界限),然后使用最后一个非故障值。

IMO您需要修复错误读取数据的错误-之后尝试修复可能会受到伤害。我同意,但是我不知道怎么做!首先,您会意识到
sp.Read(spBuffer,0,4)不一定要读取4个字节,对吗?它可以读取1、2、3或4个字节(但绝对不能为0)。我认为你需要修复错误读取数据的错误-事后尝试修复可能会导致伤害。我同意,但我不知道如何做到这一点!首先,您会意识到
sp.Read(spBuffer,0,4)不一定要读取4个字节,对吗?它可以读取1、2、3或4个字节(但不能读取0).如果10个样本中的第一个样本是小故障,这难道不会失败吗?如果你知道小故障的特征-值下降-那么它不会产生影响,因为你没有对大于前一个的读数应用阻尼-只对比前一个小一定数量的值不会在这种情况下,这是失败的