LoginSignup
3
1

More than 5 years have passed since last update.

Golang で カルマンフィルタ

Last updated at Posted at 2017-11-25

はじめに

  • 以前作ったこれ(pythonで時系列フィルタするパッケージをつくった) の kalman filter を、 golang に移植した
  • gonum/matrix 使えば割と簡単にできた
  • golangでのグラフプロット用ライブラリ gonum/plot とかもちょっと触れて面白かった
  • filter実装した時点でさほど速くないことが分かったので、平滑化は書かずに途中で終了

リポジトリ

とりあえずつくったとこまで公開

サンプルコード

package main

import (
    "math"
    "math/rand"

    kalman "github.com/ryskiwt/go-kalman"

    "github.com/gonum/matrix/mat64"
    "gonum.org/v1/plot"
    "gonum.org/v1/plot/plotter"
    "gonum.org/v1/plot/plotutil"
    "gonum.org/v1/plot/vg"
)

func main() {

    //
    // kalman filter
    //

    sstd := 0.000001
    ostd := 0.1

    // 2次トレンドモデル
    filter, err := kalman.New(&kalman.Config{
        F: mat64.NewDense(2, 2, []float64{2, -1, 1, 0}),
        G: mat64.NewDense(2, 1, []float64{1, 0}),
        Q: mat64.NewDense(1, 1, []float64{sstd}),
        H: mat64.NewDense(1, 2, []float64{1, 0}),
        R: mat64.NewDense(1, 1, []float64{ostd}),
    })
    if err != nil {
        panic(err)
    }

    // 10000個サンプル生成
    n := 10000
    s := mat64.NewDense(1, n, nil)
    x, dx := 0.0, 0.01
    xary := make([]float64, 0, n)
    yaryOrig := make([]float64, 0, n)

    // sin波 + ガウスノイズ
    for i := 0; i < n; i++ {
        y := math.Sin(x) + 0.1*(rand.NormFloat64()-0.5)
        s.Set(0, i, y)
        x += dx

        xary = append(xary, x)
        yaryOrig = append(yaryOrig, y)
    }

    // フィルタ実行
    filtered := filter.Filter(s)
    yaryFilt := mat64.Row(nil, 0, filtered)

    //
    // plot
    //

    p, err := plot.New()
    if err != nil {
        panic(err)
    }

    err = plotutil.AddLinePoints(p,
        "Original", generatePoints(xary, yaryOrig),
        "Filtered", generatePoints(xary, yaryFilt),
    )
    if err != nil {
        panic(err)
    }

    // Save the plot to a PNG file.
    if err := p.Save(16*vg.Inch, 4*vg.Inch, "sample.png"); err != nil {
        panic(err)
    }
}

func generatePoints(x []float64, y []float64) plotter.XYs {
    pts := make(plotter.XYs, len(x))

    for i := range pts {
        pts[i].X = x[i]
        pts[i].Y = y[i]
    }

    return pts
}

sample.png

3
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1