Documentation ¶
Index ¶
- Constants
- Variables
- func Max(x, y int) int
- func Min(x, y int) int
- func Plot(data *TrackData, config PlotConfig) error
- func PrettyPrintLaps(laps []Lap)
- type DataConfig
- type GPSMeasureGetFunc
- type GPSMeasurement
- type KalmanFilterFusedPositionAccelerometer
- func (k *KalmanFilterFusedPositionAccelerometer) GetPredictedPosition() float64
- func (k *KalmanFilterFusedPositionAccelerometer) GetPredictedVelocityThisAxis() float64
- func (k *KalmanFilterFusedPositionAccelerometer) Predict(accelerationThisAxis, timestampNow float64)
- func (k *KalmanFilterFusedPositionAccelerometer) Update(position float64, velocityThisAxis float64, positionError *float64, ...)
- type Lap
- type PlotConfig
- type TrackData
- type TrackInformation
Constants ¶
const EarthRadiusInMeters = 6372797.560856
const NumLapCooldownMeasures = 1000
Variables ¶
Functions ¶
func Plot ¶
func Plot(data *TrackData, config PlotConfig) error
func PrettyPrintLaps ¶
func PrettyPrintLaps(laps []Lap)
Types ¶
type DataConfig ¶
type GPSMeasureGetFunc ¶
type GPSMeasureGetFunc func(measurement GPSMeasurement) float64
type GPSMeasurement ¶
type GPSMeasurement struct {
// contains filtered or unexported fields
}
func MeasuresForLap ¶
func MeasuresForLap(lap Lap, measures []GPSMeasurement) []GPSMeasurement
func PredictKalmanFilteredMeasures ¶
func PredictKalmanFilteredMeasures(measurement []GPSMeasurement) []GPSMeasurement
type KalmanFilterFusedPositionAccelerometer ¶
type KalmanFilterFusedPositionAccelerometer struct { I *basicMatrix.Matrix // identity matrix used in some calculations H *basicMatrix.Matrix // transformation matrix for input data P *basicMatrix.Matrix // initial guess for covariance Q *basicMatrix.Matrix // process (accelerometer) error variance R *basicMatrix.Matrix // measurement (GPS) error variance A *basicMatrix.Matrix // State Transition matrix B *basicMatrix.Matrix // Control matrix // contains filtered or unexported fields }
Although these variables aren't expressive, they're based on existing mathematical conventions and in reality should be completely abstract. The variables in my own words expressed below:
H: For our usage, this should just be an identity matrix. In practice this is meant to be a transformation matrix to standardize inputs to the system, but I'm enforcing this in the API itself; This should simplify usage and a bit of performance by not having to use this
P: Newest estimate for average error for each part of state. This value will evolve internally from the kalman filter, so initializing as an identity matrix is also acceptable
Q: Abstractly, the process error variance. Explicitly for our use case, this is the covariance matrix for the accelerometer. To find, you can leave the accelerometer at rest and take the standard deviation, then square that for the variance. Matrix would then be
[AVariance 0] [0 AVariance]
Additionally, when computing standard deviation, in this context it would make sense to override the mean value of the readings to be 0 to account for a blatant offset from the sensor.
R: Abstractly, the measurement error variance. Explicitly for our use case, this is the covariance matrix of the GPS. If you can get the actual standard deviation of the GPS, this might work, but if you take GPS readings at rest, you might have a GPS lock that results in extremely minimal error.
In practice, I just took the advertised +/- value from the GPS (i.e. uBlock is accurate +/- 1 meter allegedly, so you can use that).
u: Overridden during each prediction step; Setting as a struct attribute for performance reasons. This is the input matrix of high frequency sensor readings that without subject to any error would give us an accurate state of the world.
In our case, it's a 1x1 matrix of accelerometer input in a given direction.
z: Overridden during each prediction step; Setting as a struct attribute for performance reasongs. This is the input matrix of low frequency sensor readings that are absolute but presumably high standard deviation.
In our case, it's a 2x1 matrix of GPS position and velocity [ P
v ] A: The state transition matrix. Abstractly, this is a matrix that defines a set of of equations that define what the next step would like given no additional inputs but a "next step" (or more than likely, change in time). Given that this struct is explicitly for fusing position and acceleration, it's: [ 1 t 0 1 ]
To explain the above, if you have position, then its next position is the previous position + current velocity * times. If you have velocity, then its next velocity will be the current velocity.
B: Control matrix. Given input changes to the system, this matrix multiplied by the input will present new deltas to the current state. In our case, these are the equations needed to handle input acceleration. Specifically:
[ 0.5t^2
t ]
func NewKalmanFilterFusedPositionAccelerometer ¶
func NewKalmanFilterFusedPositionAccelerometer(initialPosition float64, positionStandardDeviation float64, accelerometerStandardDeviation float64, currentTimestampSeconds float64) *KalmanFilterFusedPositionAccelerometer
func (*KalmanFilterFusedPositionAccelerometer) GetPredictedPosition ¶
func (k *KalmanFilterFusedPositionAccelerometer) GetPredictedPosition() float64
func (*KalmanFilterFusedPositionAccelerometer) GetPredictedVelocityThisAxis ¶
func (k *KalmanFilterFusedPositionAccelerometer) GetPredictedVelocityThisAxis() float64
func (*KalmanFilterFusedPositionAccelerometer) Predict ¶
func (k *KalmanFilterFusedPositionAccelerometer) Predict(accelerationThisAxis, timestampNow float64)
type PlotConfig ¶
type TrackData ¶
type TrackData struct { Laps []Lap TrackInformation *TrackInformation GPSMeasurement []GPSMeasurement FilteredGPSMeasurement []GPSMeasurement }
func ReadData ¶
func ReadData(config DataConfig) (*TrackData, error)
type TrackInformation ¶
type TrackInformation struct {
// contains filtered or unexported fields
}