Repository: wearereasonablepeople/KalmanFilter
Branch: master
Commit: 4f2f2b57b74e
Files: 17
Total size: 51.8 KB
Directory structure:
gitextract_m49pruxa/
├── .gitignore
├── .travis.yml
├── KalmanFilter/
│ ├── DoubleExtension.swift
│ ├── Info.plist
│ ├── KalmanFilter.h
│ ├── KalmanFilter.swift
│ ├── KalmanFilterType.swift
│ └── Matrix.swift
├── KalmanFilter.xcodeproj/
│ ├── project.pbxproj
│ ├── project.xcworkspace/
│ │ └── contents.xcworkspacedata
│ └── xcshareddata/
│ └── xcschemes/
│ └── KalmanFilter.xcscheme
├── KalmanFilterTests/
│ ├── DoubleExtensionTests.swift
│ ├── Info.plist
│ ├── KalmanFilterTests.swift
│ └── MatrixTests.swift
├── LICENSE
└── README.md
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
KalmanFilter.xcodeproj/xcuserdata
================================================
FILE: .travis.yml
================================================
language: objective-c
osx_image: xcode9.1
script:
- xcodebuild clean build test -project KalmanFilter.xcodeproj -scheme KalmanFilter -destination 'platform=iOS Simulator,name=iPhone 8'
after_success:
- bash <(curl -s https://codecov.io/bash)
notifications:
email: true
================================================
FILE: KalmanFilter/DoubleExtension.swift
================================================
//
// DoubleExtension.swift
// KalmanFilterTest
//
// Created by Oleksii on 20/06/16.
// Copyright © 2016 Oleksii Dykan. All rights reserved.
//
import Foundation
// MARK: Double as Kalman input
extension Double: KalmanInput {
public var transposed: Double {
return self
}
public var inversed: Double {
return 1 / self
}
public var additionToUnit: Double {
return 1 - self
}
}
================================================
FILE: KalmanFilter/Info.plist
================================================
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>0.1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>$(CURRENT_PROJECT_VERSION)</string>
<key>NSPrincipalClass</key>
<string></string>
</dict>
</plist>
================================================
FILE: KalmanFilter/KalmanFilter.h
================================================
//
// KalmanFilter.h
// KalmanFilter
//
// Created by Oleksii on 17/08/16.
// Copyright © 2016 Oleksii Dykan. All rights reserved.
//
#import <UIKit/UIKit.h>
//! Project version number for KalmanFilter.
FOUNDATION_EXPORT double KalmanFilterVersionNumber;
//! Project version string for KalmanFilter.
FOUNDATION_EXPORT const unsigned char KalmanFilterVersionString[];
// In this header, you should import all the public headers of your framework using statements like #import <KalmanFilter/PublicHeader.h>
================================================
FILE: KalmanFilter/KalmanFilter.swift
================================================
//
// KalmanFilter.swift
// KalmanFilter
//
// Created by Oleksii on 18/08/16.
// Copyright © 2016 Oleksii Dykan. All rights reserved.
//
import Foundation
/**
Conventional Kalman Filter
*/
public struct KalmanFilter<Type: KalmanInput>: KalmanFilterType {
/// x̂_k|k-1
public let stateEstimatePrior: Type
/// P_k|k-1
public let errorCovariancePrior: Type
public init(stateEstimatePrior: Type, errorCovariancePrior: Type) {
self.stateEstimatePrior = stateEstimatePrior
self.errorCovariancePrior = errorCovariancePrior
}
/**
Predict step in Kalman filter.
- parameter stateTransitionModel: F_k
- parameter controlInputModel: B_k
- parameter controlVector: u_k
- parameter covarianceOfProcessNoise: Q_k
- returns: Another instance of Kalman filter with predicted x̂_k and P_k
*/
public func predict(stateTransitionModel: Type, controlInputModel: Type, controlVector: Type, covarianceOfProcessNoise: Type) -> KalmanFilter {
// x̂_k|k-1 = F_k * x̂_k-1|k-1 + B_k * u_k
let predictedStateEstimate = stateTransitionModel * stateEstimatePrior + controlInputModel * controlVector
// P_k|k-1 = F_k * P_k-1|k-1 * F_k^t + Q_k
let predictedEstimateCovariance = stateTransitionModel * errorCovariancePrior * stateTransitionModel.transposed + covarianceOfProcessNoise
return KalmanFilter(stateEstimatePrior: predictedStateEstimate, errorCovariancePrior: predictedEstimateCovariance)
}
/**
Update step in Kalman filter. We update our prediction with the measurements that we make
- parameter measurement: z_k
- parameter observationModel: H_k
- parameter covarienceOfObservationNoise: R_k
- returns: Updated with the measurements version of Kalman filter with new x̂_k and P_k
*/
public func update(measurement: Type, observationModel: Type, covarienceOfObservationNoise: Type) -> KalmanFilter {
// H_k^t transposed. We cache it improve performance
let observationModelTransposed = observationModel.transposed
// ỹ_k = z_k - H_k * x̂_k|k-1
let measurementResidual = measurement - observationModel * stateEstimatePrior
// S_k = H_k * P_k|k-1 * H_k^t + R_k
let residualCovariance = observationModel * errorCovariancePrior * observationModelTransposed + covarienceOfObservationNoise
// K_k = P_k|k-1 * H_k^t * S_k^-1
let kalmanGain = errorCovariancePrior * observationModelTransposed * residualCovariance.inversed
// x̂_k|k = x̂_k|k-1 + K_k * ỹ_k
let posterioriStateEstimate = stateEstimatePrior + kalmanGain * measurementResidual
// P_k|k = (I - K_k * H_k) * P_k|k-1
let posterioriEstimateCovariance = (kalmanGain * observationModel).additionToUnit * errorCovariancePrior
return KalmanFilter(stateEstimatePrior: posterioriStateEstimate, errorCovariancePrior: posterioriEstimateCovariance)
}
}
================================================
FILE: KalmanFilter/KalmanFilterType.swift
================================================
//
// KalmanFilterType.swift
// KalmanFilter
//
// Created by Oleksii on 18/08/16.
// Copyright © 2016 Oleksii Dykan. All rights reserved.
//
import Foundation
public protocol KalmanInput {
var transposed: Self { get }
var inversed: Self { get }
var additionToUnit: Self { get }
static func + (lhs: Self, rhs: Self) -> Self
static func - (lhs: Self, rhs: Self) -> Self
static func * (lhs: Self, rhs: Self) -> Self
}
public protocol KalmanFilterType {
associatedtype Input: KalmanInput
var stateEstimatePrior: Input { get }
var errorCovariancePrior: Input { get }
func predict(stateTransitionModel: Input, controlInputModel: Input, controlVector: Input, covarianceOfProcessNoise: Input) -> Self
func update(measurement: Input, observationModel: Input, covarienceOfObservationNoise: Input) -> Self
}
================================================
FILE: KalmanFilter/Matrix.swift
================================================
//
// Matrix.swift
// KalmanFilterTest
//
// Created by Oleksii on 20/06/16.
// Copyright © 2016 Oleksii Dykan. All rights reserved.
//
import Foundation
import Accelerate
public struct Matrix: Equatable {
// MARK: - Properties
public let rows: Int, columns: Int
public var grid: [Double]
var isSquare: Bool {
return rows == columns
}
// MARK: - Initialization
/**
Initialization of matrix with rows * columns
size where all the elements are set to 0.0
- parameter rows: number of rows in matrix
- parameter columns: number of columns in matrix
*/
public init(rows: Int, columns: Int) {
let grid = Array(repeating: 0.0, count: rows * columns)
self.init(grid: grid, rows: rows, columns: columns)
}
/**
Initialization with grid that contains all the
elements of matrix with given matrix size
- parameter grid: array of matrix elements. **warning**
Should be of rows * column size.
- parameter rows: number of rows in matrix
- parameter columns: number of columns in matrix
*/
public init(grid: [Double], rows: Int, columns: Int) {
assert(rows * columns == grid.count, "grid size should be rows * column size")
self.rows = rows
self.columns = columns
self.grid = grid
}
/**
Initialization of
[column vector](https://en.wikipedia.org/wiki/Row_and_column_vectors)
with given array. Number of
elements in array equals to number of rows in vector.
- parameter vector: array with elements of vector
*/
public init(vector: [Double]) {
self.init(grid: vector, rows: vector.count, columns: 1)
}
/**
Initialization of
[column vector](https://en.wikipedia.org/wiki/Row_and_column_vectors)
with given number of rows. Every element is assign to 0.0
- parameter size: vector size
*/
public init(vectorOf size: Int) {
self.init(rows: size, columns: 1)
}
/**
Initialization of square matrix with given size. Number of
elements in array equals to size * size. Every elements is
assigned to 0.0
- parameter size: number of rows and columns in matrix
*/
public init(squareOfSize size: Int) {
self.init(rows: size, columns: size)
}
/**
Initialization of
[identity matrix](https://en.wikipedia.org/wiki/Identity_matrix)
of given sizen
- parameter size: number of rows and columns in identity matrix
*/
public init(identityOfSize size: Int) {
self.init(squareOfSize: size)
for i in 0..<size {
self[i, i] = 1
}
}
/**
Convenience initialization from 2D array
- parameter array2d: 2D array representation of matrix
*/
public init(_ array2d: [[Double]]) {
self.init(grid: array2d.flatMap({$0}), rows: array2d.count, columns: array2d.first?.count ?? 0)
}
// MARK: - Public Methods
/**
Determines whether element exists at specified row and
column
- parameter row: row index of element
- parameter column: column index of element
- returns: bool indicating whether spicified indeces are valid
*/
public func indexIsValid(forRow row: Int, column: Int) -> Bool {
return row >= 0 && row < rows && column >= 0 && column < columns
}
public subscript(row: Int, column: Int) -> Double {
get {
assert(indexIsValid(forRow: row, column: column), "Index out of range")
return grid[(row * columns) + column]
}
set {
assert(indexIsValid(forRow: row, column: column), "Index out of range")
grid[(row * columns) + column] = newValue
}
}
}
// MARK: - Equatable
public func == (lhs: Matrix, rhs: Matrix) -> Bool {
return lhs.rows == rhs.rows && lhs.columns == rhs.columns && lhs.grid == rhs.grid
}
// MARK: - Matrix as KalmanInput
extension Matrix: KalmanInput {
/**
[Transposed](https://en.wikipedia.org/wiki/Transpose)
version of matrix
Compexity: O(n^2)
*/
public var transposed: Matrix {
var resultMatrix = Matrix(rows: columns, columns: rows)
let columnLength = resultMatrix.columns
let rowLength = resultMatrix.rows
grid.withUnsafeBufferPointer { xp in
resultMatrix.grid.withUnsafeMutableBufferPointer { rp in
vDSP_mtransD(xp.baseAddress!, 1, rp.baseAddress!, 1, vDSP_Length(rowLength), vDSP_Length(columnLength))
}
}
return resultMatrix
}
/**
Addition to Unit in form: **I - A**
where **I** - is
[identity matrix](https://en.wikipedia.org/wiki/Identity_matrix)
and **A** - is self
**warning** Only for square matrices
Complexity: O(n ^ 2)
*/
public var additionToUnit: Matrix {
assert(isSquare, "Matrix should be square")
return Matrix(identityOfSize: rows) - self
}
/**
Inversed matrix if
[it is invertible](https://en.wikipedia.org/wiki/Invertible_matrix)
*/
public var inversed: Matrix {
assert(isSquare, "Matrix should be square")
if rows == 1 {
return Matrix(grid: [1/self[0, 0]], rows: 1, columns: 1)
}
var inMatrix:[Double] = grid
// Get the dimensions of the matrix. An NxN matrix has N^2
// elements, so sqrt( N^2 ) will return N, the dimension
var N:__CLPK_integer = __CLPK_integer(sqrt(Double(grid.count)))
var N2:__CLPK_integer = N
var N3:__CLPK_integer = N
var lwork = __CLPK_integer(grid.count)
// Initialize some arrays for the dgetrf_(), and dgetri_() functions
var pivots:[__CLPK_integer] = [__CLPK_integer](repeating: 0, count: grid.count)
var workspace:[Double] = [Double](repeating: 0.0, count: grid.count)
var error: __CLPK_integer = 0
// Perform LU factorization
dgetrf_(&N, &N2, &inMatrix, &N3, &pivots, &error)
// Calculate inverse from LU factorization
dgetri_(&N, &inMatrix, &N2, &pivots, &workspace, &lwork, &error)
if error != 0 {
assertionFailure("Matrix Inversion Failure")
}
return Matrix.init(grid: inMatrix, rows: rows, columns: rows)
}
/**
[Matrix determinant](https://en.wikipedia.org/wiki/Determinant)
*/
public var determinant: Double {
assert(isSquare, "Matrix should be square")
var result = 0.0
if rows == 1 {
result = self[0, 0]
} else {
for i in 0..<rows {
let sign = i % 2 == 0 ? 1.0 : -1.0
result += sign * self[i, 0] * additionalMatrix(row: i, column: 0).determinant
}
}
return result
}
public func additionalMatrix(row: Int, column: Int) -> Matrix {
assert(indexIsValid(forRow: row, column: column), "Invalid arguments")
var resultMatrix = Matrix(rows: rows - 1, columns: columns - 1)
for i in 0..<rows {
if i == row {
continue
}
for j in 0..<columns {
if j == column {
continue
}
let resI = i < row ? i : i - 1
let resJ = j < column ? j : j - 1
resultMatrix[resI, resJ] = self[i, j]
}
}
return resultMatrix
}
// MARK: - Private methods
fileprivate func operate(with otherMatrix: Matrix, closure: (Double, Double) -> Double) -> Matrix {
assert(rows == otherMatrix.rows && columns == otherMatrix.columns, "Matrices should be of equal size")
var resultMatrix = Matrix(rows: rows, columns: columns)
for i in 0..<rows {
for j in 0..<columns {
resultMatrix[i, j] = closure(self[i, j], otherMatrix[i, j])
}
}
return resultMatrix
}
}
/**
Naive add matrices
Complexity: O(n^2)
*/
public func + (lhs: Matrix, rhs: Matrix) -> Matrix {
assert(lhs.rows == rhs.rows && lhs.columns == rhs.columns, "Matrices should be of equal size")
var resultMatrix = Matrix(rows: lhs.rows, columns: lhs.columns)
vDSP_vaddD(lhs.grid, vDSP_Stride(1), rhs.grid, vDSP_Stride(1), &resultMatrix.grid, vDSP_Stride(1), vDSP_Length(lhs.rows * lhs.columns))
return resultMatrix
}
/**
Naive subtract matrices
Complexity: O(n^2)
*/
public func - (lhs: Matrix, rhs: Matrix) -> Matrix {
assert(lhs.rows == rhs.rows && lhs.columns == rhs.columns, "Matrices should be of equal size")
var resultMatrix = Matrix(rows: lhs.rows, columns: lhs.columns)
vDSP_vsubD(rhs.grid, vDSP_Stride(1), lhs.grid, vDSP_Stride(1), &resultMatrix.grid, vDSP_Stride(1), vDSP_Length(lhs.rows * lhs.columns))
return resultMatrix
}
/**
Naive matrices multiplication
Complexity: O(n^3)
*/
public func * (lhs: Matrix, rhs: Matrix) -> Matrix {
assert(lhs.columns == rhs.rows, "Left matrix columns should be the size of right matrix's rows")
var resultMatrix = Matrix(rows: lhs.rows, columns: rhs.columns)
let order = CblasRowMajor
let atrans = CblasNoTrans
let btrans = CblasNoTrans
let α = 1.0
let β = 1.0
let resultColumns = resultMatrix.columns
lhs.grid.withUnsafeBufferPointer { pa in
rhs.grid.withUnsafeBufferPointer { pb in
resultMatrix.grid.withUnsafeMutableBufferPointer { pc in
cblas_dgemm(order, atrans, btrans, Int32(lhs.rows), Int32(rhs.columns), Int32(lhs.columns), α, pa.baseAddress!, Int32(lhs.columns), pb.baseAddress!, Int32(rhs.columns), β, pc.baseAddress!, Int32(resultColumns))
}
}
}
return resultMatrix
}
// MARK: - Nice additional methods
public func * (lhs: Matrix, rhs: Double) -> Matrix {
return Matrix(grid: lhs.grid.map({ $0*rhs }), rows: lhs.rows, columns: lhs.columns)
}
public func * (lhs: Double, rhs: Matrix) -> Matrix {
return rhs * lhs
}
// MARK: - CustomStringConvertible for debug output
extension Matrix: CustomStringConvertible {
public var description: String {
var description = ""
for i in 0..<rows {
let contents = (0..<columns).map{"\(self[i, $0])"}.joined(separator: "\t")
switch (i, rows) {
case (0, 1):
description += "(\t\(contents)\t)"
case (0, _):
description += "⎛\t\(contents)\t⎞"
case (rows - 1, _):
description += "⎝\t\(contents)\t⎠"
default:
description += "⎜\t\(contents)\t⎥"
}
description += "\n"
}
return description
}
}
================================================
FILE: KalmanFilter.xcodeproj/project.pbxproj
================================================
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 46;
objects = {
/* Begin PBXBuildFile section */
CE866F241D80A2FF00B5A9DD /* DoubleExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE866F231D80A2FF00B5A9DD /* DoubleExtension.swift */; };
CE866F261D80A63400B5A9DD /* DoubleExtensionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE866F251D80A63400B5A9DD /* DoubleExtensionTests.swift */; };
CEA8B1E91D7EC02B009E3AAD /* Matrix.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEA8B1E81D7EC02B009E3AAD /* Matrix.swift */; };
CEA8B1EF1D7F1B99009E3AAD /* MatrixTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEA8B1EE1D7F1B99009E3AAD /* MatrixTests.swift */; };
CEAAE1F11D66640400D29016 /* KalmanFilterType.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEAAE1F01D66640400D29016 /* KalmanFilterType.swift */; };
CEAAE1F31D66661D00D29016 /* KalmanFilter.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEAAE1F21D66661D00D29016 /* KalmanFilter.swift */; };
CEF0077C1D650AEE0084F081 /* KalmanFilter.h in Headers */ = {isa = PBXBuildFile; fileRef = CEF0077B1D650AEE0084F081 /* KalmanFilter.h */; settings = {ATTRIBUTES = (Public, ); }; };
CEF007831D650AEE0084F081 /* KalmanFilter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CEF007781D650AEE0084F081 /* KalmanFilter.framework */; };
CEF007881D650AEE0084F081 /* KalmanFilterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEF007871D650AEE0084F081 /* KalmanFilterTests.swift */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
CEF007841D650AEE0084F081 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = CEF0076F1D650AEE0084F081 /* Project object */;
proxyType = 1;
remoteGlobalIDString = CEF007771D650AEE0084F081;
remoteInfo = KalmanFilter;
};
/* End PBXContainerItemProxy section */
/* Begin PBXFileReference section */
CE866F231D80A2FF00B5A9DD /* DoubleExtension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DoubleExtension.swift; sourceTree = "<group>"; };
CE866F251D80A63400B5A9DD /* DoubleExtensionTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DoubleExtensionTests.swift; sourceTree = "<group>"; };
CEA8B1E81D7EC02B009E3AAD /* Matrix.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Matrix.swift; sourceTree = "<group>"; };
CEA8B1EE1D7F1B99009E3AAD /* MatrixTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MatrixTests.swift; sourceTree = "<group>"; };
CEAAE1F01D66640400D29016 /* KalmanFilterType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KalmanFilterType.swift; sourceTree = "<group>"; };
CEAAE1F21D66661D00D29016 /* KalmanFilter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KalmanFilter.swift; sourceTree = "<group>"; };
CEF007781D650AEE0084F081 /* KalmanFilter.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = KalmanFilter.framework; sourceTree = BUILT_PRODUCTS_DIR; };
CEF0077B1D650AEE0084F081 /* KalmanFilter.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KalmanFilter.h; sourceTree = "<group>"; };
CEF0077D1D650AEE0084F081 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
CEF007821D650AEE0084F081 /* KalmanFilterTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = KalmanFilterTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
CEF007871D650AEE0084F081 /* KalmanFilterTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KalmanFilterTests.swift; sourceTree = "<group>"; };
CEF007891D650AEE0084F081 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
CEF007741D650AEE0084F081 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
CEF0077F1D650AEE0084F081 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
CEF007831D650AEE0084F081 /* KalmanFilter.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
CEF0076E1D650AEE0084F081 = {
isa = PBXGroup;
children = (
CEF0077A1D650AEE0084F081 /* KalmanFilter */,
CEF007861D650AEE0084F081 /* KalmanFilterTests */,
CEF007791D650AEE0084F081 /* Products */,
);
sourceTree = "<group>";
};
CEF007791D650AEE0084F081 /* Products */ = {
isa = PBXGroup;
children = (
CEF007781D650AEE0084F081 /* KalmanFilter.framework */,
CEF007821D650AEE0084F081 /* KalmanFilterTests.xctest */,
);
name = Products;
sourceTree = "<group>";
};
CEF0077A1D650AEE0084F081 /* KalmanFilter */ = {
isa = PBXGroup;
children = (
CEF0077B1D650AEE0084F081 /* KalmanFilter.h */,
CEAAE1F01D66640400D29016 /* KalmanFilterType.swift */,
CEAAE1F21D66661D00D29016 /* KalmanFilter.swift */,
CEA8B1E81D7EC02B009E3AAD /* Matrix.swift */,
CE866F231D80A2FF00B5A9DD /* DoubleExtension.swift */,
CEF0077D1D650AEE0084F081 /* Info.plist */,
);
path = KalmanFilter;
sourceTree = "<group>";
};
CEF007861D650AEE0084F081 /* KalmanFilterTests */ = {
isa = PBXGroup;
children = (
CEF007871D650AEE0084F081 /* KalmanFilterTests.swift */,
CEA8B1EE1D7F1B99009E3AAD /* MatrixTests.swift */,
CE866F251D80A63400B5A9DD /* DoubleExtensionTests.swift */,
CEF007891D650AEE0084F081 /* Info.plist */,
);
path = KalmanFilterTests;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXHeadersBuildPhase section */
CEF007751D650AEE0084F081 /* Headers */ = {
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
files = (
CEF0077C1D650AEE0084F081 /* KalmanFilter.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXHeadersBuildPhase section */
/* Begin PBXNativeTarget section */
CEF007771D650AEE0084F081 /* KalmanFilter */ = {
isa = PBXNativeTarget;
buildConfigurationList = CEF0078C1D650AEE0084F081 /* Build configuration list for PBXNativeTarget "KalmanFilter" */;
buildPhases = (
CEF007731D650AEE0084F081 /* Sources */,
CEF007741D650AEE0084F081 /* Frameworks */,
CEF007751D650AEE0084F081 /* Headers */,
CEF007761D650AEE0084F081 /* Resources */,
);
buildRules = (
);
dependencies = (
);
name = KalmanFilter;
productName = KalmanFilter;
productReference = CEF007781D650AEE0084F081 /* KalmanFilter.framework */;
productType = "com.apple.product-type.framework";
};
CEF007811D650AEE0084F081 /* KalmanFilterTests */ = {
isa = PBXNativeTarget;
buildConfigurationList = CEF0078F1D650AEE0084F081 /* Build configuration list for PBXNativeTarget "KalmanFilterTests" */;
buildPhases = (
CEF0077E1D650AEE0084F081 /* Sources */,
CEF0077F1D650AEE0084F081 /* Frameworks */,
CEF007801D650AEE0084F081 /* Resources */,
);
buildRules = (
);
dependencies = (
CEF007851D650AEE0084F081 /* PBXTargetDependency */,
);
name = KalmanFilterTests;
productName = KalmanFilterTests;
productReference = CEF007821D650AEE0084F081 /* KalmanFilterTests.xctest */;
productType = "com.apple.product-type.bundle.unit-test";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
CEF0076F1D650AEE0084F081 /* Project object */ = {
isa = PBXProject;
attributes = {
LastSwiftUpdateCheck = 0730;
LastUpgradeCheck = 0910;
ORGANIZATIONNAME = "Oleksii Dykan";
TargetAttributes = {
CEF007771D650AEE0084F081 = {
CreatedOnToolsVersion = 7.3.1;
LastSwiftMigration = 0910;
};
CEF007811D650AEE0084F081 = {
CreatedOnToolsVersion = 7.3.1;
LastSwiftMigration = 0910;
};
};
};
buildConfigurationList = CEF007721D650AEE0084F081 /* Build configuration list for PBXProject "KalmanFilter" */;
compatibilityVersion = "Xcode 3.2";
developmentRegion = English;
hasScannedForEncodings = 0;
knownRegions = (
en,
);
mainGroup = CEF0076E1D650AEE0084F081;
productRefGroup = CEF007791D650AEE0084F081 /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
CEF007771D650AEE0084F081 /* KalmanFilter */,
CEF007811D650AEE0084F081 /* KalmanFilterTests */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
CEF007761D650AEE0084F081 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
CEF007801D650AEE0084F081 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
CEF007731D650AEE0084F081 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
CE866F241D80A2FF00B5A9DD /* DoubleExtension.swift in Sources */,
CEAAE1F11D66640400D29016 /* KalmanFilterType.swift in Sources */,
CEAAE1F31D66661D00D29016 /* KalmanFilter.swift in Sources */,
CEA8B1E91D7EC02B009E3AAD /* Matrix.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
CEF0077E1D650AEE0084F081 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
CE866F261D80A63400B5A9DD /* DoubleExtensionTests.swift in Sources */,
CEA8B1EF1D7F1B99009E3AAD /* MatrixTests.swift in Sources */,
CEF007881D650AEE0084F081 /* KalmanFilterTests.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXTargetDependency section */
CEF007851D650AEE0084F081 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = CEF007771D650AEE0084F081 /* KalmanFilter */;
targetProxy = CEF007841D650AEE0084F081 /* PBXContainerItemProxy */;
};
/* End PBXTargetDependency section */
/* Begin XCBuildConfiguration section */
CEF0078A1D650AEE0084F081 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 1;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 9.3;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
TARGETED_DEVICE_FAMILY = "1,2";
VERSIONING_SYSTEM = "apple-generic";
VERSION_INFO_PREFIX = "";
};
name = Debug;
};
CEF0078B1D650AEE0084F081 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 1;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 9.3;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
TARGETED_DEVICE_FAMILY = "1,2";
VALIDATE_PRODUCT = YES;
VERSIONING_SYSTEM = "apple-generic";
VERSION_INFO_PREFIX = "";
};
name = Release;
};
CEF0078D1D650AEE0084F081 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
APPLICATION_EXTENSION_API_ONLY = YES;
CLANG_ENABLE_MODULES = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
DEFINES_MODULE = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
INFOPLIST_FILE = KalmanFilter/Info.plist;
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = com.violentoctopus.KalmanFilter;
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_SWIFT3_OBJC_INFERENCE = Default;
SWIFT_VERSION = 4.0;
};
name = Debug;
};
CEF0078E1D650AEE0084F081 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
APPLICATION_EXTENSION_API_ONLY = YES;
CLANG_ENABLE_MODULES = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
DEFINES_MODULE = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
INFOPLIST_FILE = KalmanFilter/Info.plist;
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = com.violentoctopus.KalmanFilter;
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
SWIFT_SWIFT3_OBJC_INFERENCE = Default;
SWIFT_VERSION = 4.0;
};
name = Release;
};
CEF007901D650AEE0084F081 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
INFOPLIST_FILE = KalmanFilterTests/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = com.violentoctopus.KalmanFilterTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_SWIFT3_OBJC_INFERENCE = Default;
SWIFT_VERSION = 4.0;
};
name = Debug;
};
CEF007911D650AEE0084F081 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
INFOPLIST_FILE = KalmanFilterTests/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = com.violentoctopus.KalmanFilterTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_SWIFT3_OBJC_INFERENCE = Default;
SWIFT_VERSION = 4.0;
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
CEF007721D650AEE0084F081 /* Build configuration list for PBXProject "KalmanFilter" */ = {
isa = XCConfigurationList;
buildConfigurations = (
CEF0078A1D650AEE0084F081 /* Debug */,
CEF0078B1D650AEE0084F081 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
CEF0078C1D650AEE0084F081 /* Build configuration list for PBXNativeTarget "KalmanFilter" */ = {
isa = XCConfigurationList;
buildConfigurations = (
CEF0078D1D650AEE0084F081 /* Debug */,
CEF0078E1D650AEE0084F081 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
CEF0078F1D650AEE0084F081 /* Build configuration list for PBXNativeTarget "KalmanFilterTests" */ = {
isa = XCConfigurationList;
buildConfigurations = (
CEF007901D650AEE0084F081 /* Debug */,
CEF007911D650AEE0084F081 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = CEF0076F1D650AEE0084F081 /* Project object */;
}
================================================
FILE: KalmanFilter.xcodeproj/project.xcworkspace/contents.xcworkspacedata
================================================
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "self:KalmanFilter.xcodeproj">
</FileRef>
</Workspace>
================================================
FILE: KalmanFilter.xcodeproj/xcshareddata/xcschemes/KalmanFilter.xcscheme
================================================
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0910"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "CEF007771D650AEE0084F081"
BuildableName = "KalmanFilter.framework"
BlueprintName = "KalmanFilter"
ReferencedContainer = "container:KalmanFilter.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
language = ""
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "CEF007811D650AEE0084F081"
BuildableName = "KalmanFilterTests.xctest"
BlueprintName = "KalmanFilterTests"
ReferencedContainer = "container:KalmanFilter.xcodeproj">
</BuildableReference>
</TestableReference>
</Testables>
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "CEF007771D650AEE0084F081"
BuildableName = "KalmanFilter.framework"
BlueprintName = "KalmanFilter"
ReferencedContainer = "container:KalmanFilter.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
language = ""
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "CEF007771D650AEE0084F081"
BuildableName = "KalmanFilter.framework"
BlueprintName = "KalmanFilter"
ReferencedContainer = "container:KalmanFilter.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "CEF007771D650AEE0084F081"
BuildableName = "KalmanFilter.framework"
BlueprintName = "KalmanFilter"
ReferencedContainer = "container:KalmanFilter.xcodeproj">
</BuildableReference>
</MacroExpansion>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>
================================================
FILE: KalmanFilterTests/DoubleExtensionTests.swift
================================================
//
// DoubleExtensionTests.swift
// KalmanFilterTest
//
// Created by Oleksii on 02/07/16.
// Copyright © 2016 Oleksii Dykan. All rights reserved.
//
import XCTest
@testable import KalmanFilter
class DoubleExtensionTests: XCTestCase {
func testDoubleAsKalmanInput() {
XCTAssertEqual(5.2.transposed, 5.2)
XCTAssertEqual(2.0.inversed, 0.5)
XCTAssertEqual(0.2.additionToUnit, 0.8)
}
}
================================================
FILE: KalmanFilterTests/Info.plist
================================================
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>BNDL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1</string>
</dict>
</plist>
================================================
FILE: KalmanFilterTests/KalmanFilterTests.swift
================================================
//
// KalmanFilterTests.swift
// KalmanFilterTests
//
// Created by Oleksii on 17/08/16.
// Copyright © 2016 Oleksii Dykan. All rights reserved.
//
import XCTest
@testable import KalmanFilter
class KalmanFilterTests: XCTestCase {
func testKalmanFilter2D() {
let measurements = [1.0, 2.0, 3.0]
let accuracy = 0.00001
let x = Matrix(vector: [0, 0])
let P = Matrix(grid: [1000, 0, 0, 1000], rows: 2, columns: 2)
let B = Matrix(identityOfSize: 2)
let u = Matrix(vector: [0, 0])
let F = Matrix(grid: [1, 1, 0, 1], rows: 2, columns: 2)
let H = Matrix(grid: [1, 0], rows: 1, columns: 2)
let R = Matrix(grid: [1], rows: 1, columns: 1)
let Q = Matrix(rows: 2, columns: 2)
var kalmanFilter = KalmanFilter(stateEstimatePrior: x, errorCovariancePrior: P)
for measurement in measurements {
let z = Matrix(grid: [measurement], rows: 1, columns: 1)
kalmanFilter = kalmanFilter.update(measurement: z, observationModel: H, covarienceOfObservationNoise: R)
kalmanFilter = kalmanFilter.predict(stateTransitionModel: F, controlInputModel: B, controlVector: u, covarianceOfProcessNoise: Q)
}
let resultX = Matrix(vector: [3.9996664447958645, 0.9999998335552873])
let resultP = Matrix(grid: [2.3318904241194827, 0.9991676099921091, 0.9991676099921067, 0.49950058263974184], rows: 2, columns: 2)
XCTAssertEqual(kalmanFilter.stateEstimatePrior[0, 0], resultX[0, 0], accuracy: accuracy)
XCTAssertEqual(kalmanFilter.stateEstimatePrior[1, 0], resultX[1, 0], accuracy: accuracy)
XCTAssertEqual(kalmanFilter.errorCovariancePrior[0, 0], resultP[0, 0], accuracy: accuracy)
XCTAssertEqual(kalmanFilter.errorCovariancePrior[0, 1], resultP[0, 1], accuracy: accuracy)
XCTAssertEqual(kalmanFilter.errorCovariancePrior[1, 0], resultP[1, 0], accuracy: accuracy)
XCTAssertEqual(kalmanFilter.errorCovariancePrior[1, 1], resultP[1, 1], accuracy: accuracy)
}
}
================================================
FILE: KalmanFilterTests/MatrixTests.swift
================================================
//
// MatrixTests.swift
// KalmanFilterTest
//
// Created by Oleksii on 20/06/16.
// Copyright © 2016 Oleksii Dykan. All rights reserved.
//
import XCTest
@testable import KalmanFilter
class MatrixTests: XCTestCase {
func testMatrixIsSquare() {
XCTAssertTrue(Matrix(identityOfSize: 2).isSquare)
XCTAssertFalse(Matrix(rows: 3, columns: 1).isSquare)
}
func testMatrixEquatable() {
var matrixOne = Matrix(rows: 1, columns: 2)
var matrixTwo = Matrix(rows: 1, columns: 2)
XCTAssertTrue(matrixOne == matrixTwo)
XCTAssertTrue(matrixTwo == matrixOne)
matrixOne[0, 0] = 1
XCTAssertFalse(matrixOne == matrixTwo)
matrixOne[0, 0] = 0
XCTAssertTrue(matrixTwo == matrixOne)
matrixTwo = Matrix(rows: 2, columns: 1)
XCTAssertFalse(matrixOne == matrixTwo)
}
func testMatrixInitialization() {
let rows = 4
let columns = 3
let matrix = Matrix(rows: rows, columns: columns)
XCTAssertEqual(matrix.rows, rows)
XCTAssertEqual(matrix.columns, columns)
XCTAssertEqual(matrix.grid.count, rows * columns)
let squareMatrix = Matrix(squareOfSize: rows)
XCTAssertEqual(squareMatrix.rows, rows)
XCTAssertEqual(squareMatrix.columns, rows)
XCTAssertEqual(squareMatrix.grid.count, rows * rows)
let identityMatrixSize = 3
let identityMatrix = Matrix(identityOfSize: identityMatrixSize)
var identityMatrixProper = Matrix(squareOfSize: identityMatrixSize)
identityMatrixProper[0, 0] = 1
identityMatrixProper[1, 1] = 1
XCTAssertNotEqual(identityMatrix, identityMatrixProper)
identityMatrixProper[2, 2] = 1
XCTAssertEqual(identityMatrix, identityMatrixProper)
let vectorMatrixEmpty = Matrix(vectorOf: 2)
XCTAssertEqual(vectorMatrixEmpty.rows, 2)
XCTAssertEqual(vectorMatrixEmpty.columns, 1)
let vectorMatrix = Matrix(vector: [2, 1, 3])
XCTAssertEqual(vectorMatrix.rows, 3)
XCTAssertEqual(vectorMatrix.columns, 1)
XCTAssertEqual(vectorMatrix[0, 0], 2)
XCTAssertEqual(vectorMatrix[1, 0], 1)
XCTAssertEqual(vectorMatrix[2, 0], 3)
let array2d = [[1.0, 0.0], [0.0, 1.0]]
XCTAssertEqual(Matrix(array2d), Matrix(identityOfSize: 2))
XCTAssertEqual(Matrix([[2.0], [1], [3]]), vectorMatrix)
}
func testMatrixCheckForSquare() {
XCTAssertTrue(Matrix(rows: 2, columns: 2).isSquare)
XCTAssertTrue(Matrix(squareOfSize: 2).isSquare)
XCTAssertTrue(Matrix(identityOfSize: 2).isSquare)
XCTAssertFalse(Matrix(rows: 3, columns: 2).isSquare)
XCTAssertFalse(Matrix(rows: 2, columns: 3).isSquare)
}
func testMatrixIndexValidation() {
let rows = 2
let columns = 3
let matrix = Matrix(rows: rows, columns: columns)
XCTAssertTrue(matrix.indexIsValid(forRow: 0, column: 0))
XCTAssertTrue(matrix.indexIsValid(forRow: rows - 1, column: columns - 1))
XCTAssertFalse(matrix.indexIsValid(forRow: rows, column: columns))
XCTAssertFalse(matrix.indexIsValid(forRow: -1, column: -1))
}
// MARK: Matrix Kalman Filter Extension Tests
func testMatrixTranspose() {
let initialMatrix = Matrix([[5, 4], [4, 0], [7, 10], [-1, 8]])
let transposedMatrixProper = Matrix([[5, 4, 7, -1], [4, 0, 10, 8]])
XCTAssertEqual(initialMatrix.transposed, transposedMatrixProper)
}
func testAdditionToUnit() {
let initialMatrix = Matrix([[4, 7, 1], [-2, 8, 3], [5, -4, 11]])
let properAddiotionToUnitMatrix = Matrix([[-3, -7, -1], [2, -7, -3], [-5, 4, -10]])
XCTAssertEqual(initialMatrix.additionToUnit, properAddiotionToUnitMatrix)
}
func testMatrixDeterminant() {
let initialMatrix = Matrix([[-2, 2, -3], [-1, 1, 3], [2, 0, -1]])
XCTAssertEqual(initialMatrix.determinant, 18)
}
func testMatrixInversed() {
let initialMatrix = Matrix([[1, 2, 3], [0, 1, 4], [5, 6, 0]])
// Using accelerate causes a very slight precision issue
let properInversedMatrix = Matrix([[-24.000000000000089, 18.000000000000068, 5.0000000000000178], [20.000000000000075, -15.000000000000055, -4.0000000000000142], [-5.0000000000000195, 4.0000000000000133, 1.0000000000000033]])
XCTAssertEqual(initialMatrix.inversed, properInversedMatrix)
XCTAssertEqual(Matrix(grid: [2], rows: 1, columns: 1).inversed, Matrix(grid: [1.0/2], rows: 1, columns: 1))
}
func testMatrixAdditionAndSubtraction() {
let size = (2, 3)
let matrixOne = Matrix([[5, 7, 9], [11, -2, -3]])
let matrixTwo = Matrix([[-8, 4, 9], [6, 3, 2]])
var additionMatrix = Matrix(rows: size.0, columns: size.1)
var subtractionMatrix = Matrix(rows: size.0, columns: size.1)
additionMatrix[0, 0] = matrixOne[0, 0] + matrixTwo[0, 0]
additionMatrix[0, 1] = matrixOne[0, 1] + matrixTwo[0, 1]
additionMatrix[0, 2] = matrixOne[0, 2] + matrixTwo[0, 2]
additionMatrix[1, 0] = matrixOne[1, 0] + matrixTwo[1, 0]
additionMatrix[1, 1] = matrixOne[1, 1] + matrixTwo[1, 1]
additionMatrix[1, 2] = matrixOne[1, 2] + matrixTwo[1, 2]
XCTAssertEqual(matrixOne + matrixTwo, additionMatrix)
subtractionMatrix[0, 0] = matrixOne[0, 0] - matrixTwo[0, 0]
subtractionMatrix[0, 1] = matrixOne[0, 1] - matrixTwo[0, 1]
subtractionMatrix[0, 2] = matrixOne[0, 2] - matrixTwo[0, 2]
subtractionMatrix[1, 0] = matrixOne[1, 0] - matrixTwo[1, 0]
subtractionMatrix[1, 1] = matrixOne[1, 1] - matrixTwo[1, 1]
subtractionMatrix[1, 2] = matrixOne[1, 2] - matrixTwo[1, 2]
XCTAssertEqual(matrixOne - matrixTwo, subtractionMatrix)
}
func testMatrixMultiplication() {
let matrixOne = Matrix([[3.0, 4, 2]])
let matrixTwo = Matrix([[13, 9, 7, 15], [8, 7, 4, 6], [6, 4, 0, 3]])
let multipliedMatrices = Matrix([[83.0, 63, 37, 75]])
XCTAssertEqual(matrixOne * matrixTwo, multipliedMatrices)
}
func testMatrixMultiplicationByScalar() {
let matrix = Matrix(grid: [1, 2, 3, 4], rows: 2, columns: 2)
XCTAssertEqual(matrix * 2, Matrix([[2, 4], [6, 8]]))
XCTAssertEqual(2 * matrix, Matrix([[2, 4], [6, 8]]))
XCTAssertEqual(matrix * 0.5, Matrix([[0.5, 1], [1.5, 2]]))
}
func testMatrixStringDescription() {
let matrix = Matrix([[0.0, 2.0, 3.0, 4.0],
[0.0, 2.0, 3.0, 4.0],
[0.0, 2.0, 3.0, 4.0]])
let string = "⎛\t0.0\t2.0\t3.0\t4.0\t⎞\n" +
"⎜\t0.0\t2.0\t3.0\t4.0\t⎥\n" +
"⎝\t0.0\t2.0\t3.0\t4.0\t⎠\n"
XCTAssertEqual(matrix.description, string)
XCTAssertEqual(Matrix([[0.0, 2.0, 3.0, 4.0]]).description, "(\t0.0\t2.0\t3.0\t4.0\t)\n")
}
}
================================================
FILE: LICENSE
================================================
MIT License
Copyright (c) 2019 WEAREREASONABLEPEOPLE B.V.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: README.md
================================================
# KalmanFilter
Swift implementation of Conventional Kalman Filter algorithm
[](https://github.com/Carthage/Carthage)
[](https://travis-ci.org/wearereasonablepeople/KalmanFilter)
[](https://codecov.io/gh/wearereasonablepeople/KalmanFilter)
## Motivation:
[Kalman filter](https://en.wikipedia.org/wiki/Kalman_filter) is a widely applied algorithm to get a more
accurate guess in noisy environment. It has a lot of applications in real life such as guidance, navigation
control for vehicles, etc. **Although it is mostly used to filter GPS data, this framework doesn't have a
ready-to-use solutions that work with GPS and is more general implementation of algorithm.**
## Example of usage
`Kalman filter` can work with anything that adopts `KalmanInput` protocol. Framework provides `Matrix`
struct that conforms to this protocol, although you can use anything that is more suitable for you. For
example, framework also provides `Double`'s extension with `KalmanInput` and you can use it if your
`KalmanFilter` has only 1 dimension.
The code below is the example of usage of `1D KalmanFilter` taken from
[here](http://bilgin.esme.org/BitsAndBytes/KalmanFilterforDummies).
```swift
let measurements = [0.39, 0.50, 0.48, 0.29, 0.25, 0.32, 0.34, 0.48, 0.41, 0.45, 0.46, 0.59, 0.42]
var filter = KalmanFilter(stateEstimatePrior: 0.0, errorCovariancePrior: 1)
for measurement in measurements {
let prediction = filter.predict(1, controlInputModel: 0, controlVector: 0, covarianceOfProcessNoise: 0)
let update = prediction.update(measurement, observationModel: 1, covarienceOfObservationNoise: 0.1)
filter = update
}
```
## Sources
All the names of properties and methods' parameters names are taken from
[wikipedia page](https://en.wikipedia.org/wiki/Kalman_filter#Details).
If you are looking for a good source to understand how `Kalman Filter` works then take a look at
[this page](http://bilgin.esme.org/BitsAndBytes/KalmanFilterforDummies),
[this one](http://www.bzarg.com/p/how-a-kalman-filter-works-in-pictures/) and there is a great series of
video tutorials on [udacity](https://www.udacity.com/course/artificial-intelligence-for-robotics--cs373)
gitextract_m49pruxa/ ├── .gitignore ├── .travis.yml ├── KalmanFilter/ │ ├── DoubleExtension.swift │ ├── Info.plist │ ├── KalmanFilter.h │ ├── KalmanFilter.swift │ ├── KalmanFilterType.swift │ └── Matrix.swift ├── KalmanFilter.xcodeproj/ │ ├── project.pbxproj │ ├── project.xcworkspace/ │ │ └── contents.xcworkspacedata │ └── xcshareddata/ │ └── xcschemes/ │ └── KalmanFilter.xcscheme ├── KalmanFilterTests/ │ ├── DoubleExtensionTests.swift │ ├── Info.plist │ ├── KalmanFilterTests.swift │ └── MatrixTests.swift ├── LICENSE └── README.md
Condensed preview — 17 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (57K chars).
[
{
"path": ".gitignore",
"chars": 34,
"preview": "KalmanFilter.xcodeproj/xcuserdata\n"
},
{
"path": ".travis.yml",
"chars": 278,
"preview": "language: objective-c\nosx_image: xcode9.1\n\nscript:\n - xcodebuild clean build test -project KalmanFilter.xcodeproj -sche"
},
{
"path": "KalmanFilter/DoubleExtension.swift",
"chars": 441,
"preview": "//\n// DoubleExtension.swift\n// KalmanFilterTest\n//\n// Created by Oleksii on 20/06/16.\n// Copyright © 2016 Oleksii Dy"
},
{
"path": "KalmanFilter/Info.plist",
"chars": 808,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
},
{
"path": "KalmanFilter/KalmanFilter.h",
"chars": 515,
"preview": "//\n// KalmanFilter.h\n// KalmanFilter\n//\n// Created by Oleksii on 17/08/16.\n// Copyright © 2016 Oleksii Dykan. All ri"
},
{
"path": "KalmanFilter/KalmanFilter.swift",
"chars": 3031,
"preview": "//\n// KalmanFilter.swift\n// KalmanFilter\n//\n// Created by Oleksii on 18/08/16.\n// Copyright © 2016 Oleksii Dykan. Al"
},
{
"path": "KalmanFilter/KalmanFilterType.swift",
"chars": 864,
"preview": "//\n// KalmanFilterType.swift\n// KalmanFilter\n//\n// Created by Oleksii on 18/08/16.\n// Copyright © 2016 Oleksii Dykan"
},
{
"path": "KalmanFilter/Matrix.swift",
"chars": 10939,
"preview": "//\n// Matrix.swift\n// KalmanFilterTest\n//\n// Created by Oleksii on 20/06/16.\n// Copyright © 2016 Oleksii Dykan. All "
},
{
"path": "KalmanFilter.xcodeproj/project.pbxproj",
"chars": 18206,
"preview": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 46;\n\tobjects = {\n\n/* Begin PBXBuildFile section *"
},
{
"path": "KalmanFilter.xcodeproj/project.xcworkspace/contents.xcworkspacedata",
"chars": 157,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Workspace\n version = \"1.0\">\n <FileRef\n location = \"self:KalmanFilter.xc"
},
{
"path": "KalmanFilter.xcodeproj/xcshareddata/xcschemes/KalmanFilter.xcscheme",
"chars": 3758,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n LastUpgradeVersion = \"0910\"\n version = \"1.3\">\n <BuildAction\n "
},
{
"path": "KalmanFilterTests/DoubleExtensionTests.swift",
"chars": 430,
"preview": "//\n// DoubleExtensionTests.swift\n// KalmanFilterTest\n//\n// Created by Oleksii on 02/07/16.\n// Copyright © 2016 Oleks"
},
{
"path": "KalmanFilterTests/Info.plist",
"chars": 733,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
},
{
"path": "KalmanFilterTests/KalmanFilterTests.swift",
"chars": 2092,
"preview": "//\n// KalmanFilterTests.swift\n// KalmanFilterTests\n//\n// Created by Oleksii on 17/08/16.\n// Copyright © 2016 Oleksii"
},
{
"path": "KalmanFilterTests/MatrixTests.swift",
"chars": 7206,
"preview": "//\n// MatrixTests.swift\n// KalmanFilterTest\n//\n// Created by Oleksii on 20/06/16.\n// Copyright © 2016 Oleksii Dykan."
},
{
"path": "LICENSE",
"chars": 1083,
"preview": "MIT License\n\nCopyright (c) 2019 WEAREREASONABLEPEOPLE B.V.\n\nPermission is hereby granted, free of charge, to any person "
},
{
"path": "README.md",
"chars": 2461,
"preview": "# KalmanFilter\nSwift implementation of Conventional Kalman Filter algorithm\n\n[. The extraction includes 17 files (51.8 KB), approximately 15.7k tokens. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.