Удалить шум и экстремальные значения из данных?

У меня есть программа, которая читает данные по последовательному с АЦП на PSoC.

Числа отправляются в формате <uint16>включая символы "<" и ">", передаваемые в двоичном формате 00111100 XXXXXXXX XXXXXXXX 00111110 где 'X' составляют 16-битный без знака int.

Иногда чтение не работает очень хорошо, и программа использует двоичные данные для символа ">" как часть его числа, что приводит к сбою, как показано на этом снимке экрана с 2500 выборками (игнорируйте падение между выборками от 800 до 1500, что Был ли я играть с входом АЦП):

Скриншот

Вы можете ясно видеть, что сбой приводит к тому, что данные каждый раз примерно одинаково выбираются.

Данные отправляются десять раз в секунду, поэтому я планировал взять десять выборок, удалить все сбои (если значение находится далеко от других выборок), а затем усреднить оставшиеся значения, чтобы немного сгладить кривую., Выход может быть в любом месте от 0 до 50000+, поэтому я не могу просто удалить значения ниже определенного числа.

Я не уверен, как удалить значения, которые находятся далеко от диапазона других значений в группе из 10 выборок, потому что могут быть случаи, когда есть два выборки, на которые влияет этот сбой. Возможно, есть какой-то другой способ исправить эти сбойные данные вместо того, чтобы просто обойти их!

Каков наилучший способ сделать это? Вот мой код (это внутри метода DataReceivedEvent):

SerialPort sp = (SerialPort)sender; //set up serial port
byte[] spBuffer = new byte[4];
int indata = 0;

sp.Read(spBuffer, 0, 4);
indata = BitConverter.ToUInt16(spBuffer, 1);

object[] o = { numSamples, nudDutyCycle.Value, freqMultiplied, nudDistance.Value, pulseWidth, indata };
lock (dt)    //lock for multithread safety
{
    dt.Rows.Add(o); //add data to datatable
}

3 ответа

Решение

Я подозреваю, что ваша проблема может быть в том, что вы читаете из последовательного порта меньше байтов, чем вы думаете.

Например, 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;
    }
}

Если во время чтения есть тайм-аут, должен быть TimeoutExceptionтак что нет необходимости указывать там свое время ожидания.

Затем измените звонки следующим образом:

sp.Read(spBuffer, 0, 4);

К этому:

BlockingRead(sp, spbuffer, 0, 4);

Прежде всего, я настоятельно рекомендую просто исправить проблему с синтаксическим анализом, тогда вам не придется беспокоиться о сбоях.

Однако, если вы все же решите пойти по пути исправления данных впоследствии: я вижу, что все сбитые данные имеют определенное значение: ~16000. На самом деле, судя по графику, я бы сказал, что он почти всегда одинаков. Вы можете просто игнорировать данные, находящиеся в диапазоне сбитых значений (вам придется провести некоторое тестирование, чтобы найти точные границы), и использовать вместо этого последнее не сбитое значение.

Распространенным методом в инженерии является добавление демпфирующей функции. Функция демпфирования в основном действует на дифференциал параметра, то есть на разницу между последовательными значениями. Не существует жестких и быстрых правил о том, как выбрать функцию демпфирования, и в основном они настроены для получения разумного результата.

Так что в вашем случае это означает, что вы сравниваете последнее значение с предыдущим значением. Если оно больше определенной величины, либо по умолчанию последнее значение по умолчанию равно предыдущему, либо уменьшите последнее значение на некоторый фиксированный коэффициент, скажем, на 10% или 1%. Таким образом, вы не теряете информацию, но и не получаете внезапных скачков и глюков.

Другие вопросы по тегам