5

I am streaming data into a C# application from an inertial sensor. The data is a bit noisy, and so I need to add a filter to smooth it. I have a kalman filter implementation that works great when given an array, but I cannot get my head around how to use it on a constant datastream.

I have:

double sensorData; //the noisy value, constantly updating from another class.

The filter:

public static double[] noisySine = new double[20] { 40, 41, 38, 40, 45, 42, 43, 44, 40, 38, 44, 45, 40, 39, 37, 41, 42, 70, 44, 42 };
    public static double[] clean = new double[20];

      public static void KalmanFilter(double[] noisy)  
            {                  
                double A = double.Parse("1"); //factor of real value to previous real value
                // double B = 0; //factor of real value to real control signal
                double H = double.Parse("1"); 
                double P = double.Parse("0.1");
                double Q = double.Parse("0.125");  //Process noise. 
                double R = double.Parse("1"); //assumed environment noise.
                double K;
                double z;
                double x;

                //assign to first measured value
                x = noisy[0];
                for (int i = 0; i < noisy.Length; i++)  
                {
                    //get current measured value
                    z = noisy[i];

                    //time update - prediction
                    x = A * x;
                    P = A * P * A + Q;

                    //measurement update - correction
                    K = P * H / (H * P * H + R);
                    x = x + K * (z - H * x);
                    P = (1 - K * H) * P;
                    //estimated value
                    clean[i] = x;
                    Console.WriteLine(noisy[i] + " " + clean[i]);
                }
            }

How can i stream a double in, instead of an array, and return a (filtered) double?

Thank you.

anti
  • 3,011
  • 7
  • 36
  • 86
  • A double is eight bytes. To stream data you need a byte array. So use Bit.Converter class. – jdweng Sep 04 '16 at 11:35
  • Hi, thanks for your reply. i don't understand what you mean. I have a variable (double) constantly updating. I need to send it into a filter function that currently works with a double[]. – anti Sep 04 '16 at 11:37
  • @anti Did you ever solve this? – Chris Dec 06 '17 at 11:12
  • There's a bug in this implementation: when this code iterates, P soon becomes a value close to R/100000 and is noise-independent (there are no references to the noisy or stable readings in his calculation) – Rudy Feb 23 '18 at 00:01

3 Answers3

6

Create this class:

public class KalmanFilter
{
    private double A, H, Q, R, P, x;

    public KalmanFilter(double A, double H, double Q, double R, double initial_P, double initial_x)
    {
        this.A = A;
        this.H = H;
        this.Q = Q;
        this.R = R;
        this.P = initial_P;
        this.x = initial_x;
    }

    public double Output(double input)
    {
        // time update - prediction
        x = A * x;
        P = A * P * A + Q;

        // measurement update - correction
        double K = P * H / (H * P * H + R);
        x = x + K * (input - H * x);
        P = (1 - K * H) * P;

        return x;
    }
}

And use the class:

KalmanFilter filter = new KalmanFilter(1, 1, 0.125, 1, 0.1, noisySine[0]);
for (int i = 0; i < noisy.Length; i++) clean[i] = filter.Output(noisySine[i]);
Ivan
  • 61
  • 1
  • 2
0

Try following code

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            double[] input = {1.1,2.2,3.3,4.4};
            byte[] bArray = input.Select(x => BitConverter.GetBytes(x)).SelectMany(y => y).ToArray();
            MemoryStream inStream = new MemoryStream(bArray);
            long length = inStream.Length;
            byte[] outArray = new byte[length];
            inStream.Read(outArray, 0, (int)length);
            List<double> output = new List<double>();
            for (int i = 0; i < bArray.Length; i += 8)
            {
                output.Add(BitConverter.ToDouble(outArray,i));
            }
        }
    }
}
jdweng
  • 33,250
  • 2
  • 15
  • 20
  • Thanks, but I do not think this is what i need. How does this help me send the datastream into the filter function above? Apologies if I am missing something! – anti Sep 04 '16 at 11:46
  • I updated code to show all needed code. I used a memory stream. – jdweng Sep 04 '16 at 11:52
0

This is How you can modify your code to stream a double in, and return a filtered double.

  public static void KalmanTest()
      {
          double[] noisySine = new double[20] { 40, 41, 38, 40, 45, 42, 43, 44, 40, 38, 44, 45, 40, 39, 37, 41, 42, 70, 44, 42 };
          for (int i = 0; i < noisySine.Length; i++)  
          {
                Console.WriteLine(noisySine[i] + " " + KalmanFilter(noisySine[i]));
          }
      }


  // assign default values
  // for a new mwasurement, reset this values
  public static double P = double.Parse("1");  // MUST be greater than 0
  public static double clean = double.Parse("0"); // any value

  public static double KalmanFilter(double noisy)  
        {                  
            double A = double.Parse("1"); //factor of real value to previous real value
            // double B = 0; //factor of real value to real control signal
            double H = double.Parse("1"); 
            double Q = double.Parse("0.125");  //Process noise. 
            double R = double.Parse("1"); //assumed environment noise.
            double K;
            double z;
            double x;

                //get current measured value
                z = noisy;

                //time update - prediction
                x = A * clean;
                P = A * P * A + Q;

                //measurement update - correction
                K = P * H / (H * P * H + R);
                x = x + K * (z - H * x);
                P = (1 - K * H) * P;
                //estimated value
                clean = x;
                return clean;
        }

NOTE: There's a bug. When this code iterates, P soon becomes a value close to R/100000 and this behaviour is noise-independent because there are no references to the noisy or stable readings in P calculation. The clean code looks like a low-pass filter:

  // assign default values
  public static double clean = double.Parse("0"); // any value

  public static double KalmanFilter(double noisy)  
        {                  
            double K = double.Parse("0.125");  // noise 0 < K < 1
            clean = clean + K * (noisy - clean);
            return clean;
        }
Rudy
  • 181
  • 2
  • 10
  • 1
    It's not a bug, P (estimate uncertainty) goes to 0 for every new measurement as we have more data for estimation. – Guney Ozsan Oct 07 '19 at 11:10