-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathKalmanFilterTest.c
More file actions
220 lines (179 loc) · 7.03 KB
/
KalmanFilterTest.c
File metadata and controls
220 lines (179 loc) · 7.03 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
/**
******************************************************************************
* File Name : KalmanFilterTesting.c
* Description : This file contains an implementation of a Kalman filter
* designed to obtain accurate altitude readings from both
* the accelerometer and barometer on board the rocket.
* I have totally chainsawed the file to work with the
* provided testing data.
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* Constants -----------------------------------------------------------------*/
static const int SEA_LEVEL_PRESSURE = 101421.93903699999;
// TODO: THIS NEEDS TO BE UPDATED AND RECORDED ON LAUNCH DAY
static const double KALMAN_GAIN[][2] =
{
{0.105553059 * 2, 0.109271566},
{0.0361533034, 0.0661198847},
{0.000273178915, 0.618030079}
};
/* Structs -------------------------------------------------------------------*/
struct KalmanStateVector
{
double altitude;
double velocity;
double acceleration;
};
/* Functions -----------------------------------------------------------------*/
/**
* Gets the ith field in a line seperated by commas.
*
* Params:
* line - (char*) Pointer to a string seperated by commas
* num - (int) The number of the field to get. 1 indexed. I'm sorry.
*/
char* getfield(char* line, int num)
{
char* tok;
for (tok = strtok(line, ",");
tok && *tok;
tok = strtok(NULL, ",\n"))
{
if (!--num)
{
return tok;
}
}
return NULL;
}
/**
* Takes an old state vector and current state measurements and
* converts them into a prediction of the rocket's current state.
*
* Params:
* oldState - (KalmanStateVector) Past altitude, velocity and acceleration
* currentAccel - (double) Measured acceleration
* currentAltitude - (double) Measured altitude
* dt - (double) Time since last step. In ms.
*
* Returns:
* newState - (KalmanStateVector) Current altitude, velocity and acceleration
*/
struct KalmanStateVector filterSensors(
struct KalmanStateVector oldState,
double currentAccel,
double currentPressure,
double dt
)
{
struct KalmanStateVector newState;
double accelIn = (double) currentAccel; // Milli-g -> g -> m/s
// Convert from 100*millibars to m. This may or may not be right, depending on where you look. Needs testing
double altIn = (double) 44307.69396 * (1 - pow(currentPressure / SEA_LEVEL_PRESSURE, 0.190284));
// Propagate old state using simple kinematics equations
newState.altitude = oldState.altitude + oldState.velocity * dt + 0.5 * dt * dt * oldState.acceleration;
newState.velocity = oldState.velocity + oldState.acceleration * dt;
newState.acceleration = oldState.acceleration;
// Calculate the difference between the new state and the measurements
double baroDifference = altIn - newState.altitude;
double accelDifference = accelIn - newState.acceleration;
// Minimize the chi2 error by means of the Kalman gain matrix
newState.altitude = newState.altitude + KALMAN_GAIN[0][0] * baroDifference + KALMAN_GAIN[0][1] * accelDifference;
newState.velocity = newState.velocity + KALMAN_GAIN[1][0] * baroDifference + KALMAN_GAIN[1][1] * accelDifference;
newState.acceleration = newState.velocity + KALMAN_GAIN[2][0] * baroDifference + KALMAN_GAIN[2][1] * accelDifference;
return newState;
}
/**
* Runs through the input file, reading acceleration, pressure, time, and read altitude.
* Uses just the acceleration, pressure, and time to calculate altitude using the Kalman filter.
* Logs all of the data to the output file.
*
* Must configure data in the "Touchy" section.
* Leave the "No Touchy" section alone unless you know what you're doing.
*/
int main()
{
/* Touchy --------------------------------------------------------------- */
// File names
char* inputFileName = "KalmanTestInput.csv";
char* outputFileName = "KalmanTestOutput.csv";
// Line max settings
int lineMaxEnable = 0;
int lineMax = 3;
// Initial readings before launch
double lastTime = 1174.0074;
double lastAlt = 1289;
// Field indexes. 1 indexed. I'm sorry.
int timeIndex = 1;
int accelIndex = 15;
int pressureIndex = 10;
int readAltitudeIndex = 11;
// Detectionp parameters
int detectStart = 200; // Line to start checking for descent on
int desTrigger = 3; // Number of descents in a row to confirm the rocket is descending
/* No Touchy ------------------------------------------------------------ */
// IO
FILE* inputStream = fopen(inputFileName, "r");
FILE* outputStream = fopen(outputFileName, "w");
fprintf(outputStream, "dt, Acceleration, Pressure, Their Altitude, Our Altitude, DES\n");
char line[1024];
// Parameters
int i = 0; // Number of lines processed
int descount = 0; // Number of descents counted in a row
double DES = 0; // "Digital" parameter, stores altitude of descent detection
// Kalman Vector
struct KalmanStateVector ksv;
ksv.altitude = lastAlt;
// For each line in the input file
while (fgets(line, 1024, inputStream) && ((lineMaxEnable && i <= lineMax) || ~lineMaxEnable))
{
// The empty pointers are things to help strtod. They're stupid, but they work.
// Get the time
char* timeStr = getfield(strdup(line), 1);
char* ptr1;
double time = strtod(timeStr, &ptr1) / 10000;
double dt = time - lastTime;
// Get the acceleration
char* accelerationStr = getfield(strdup(line), 15);
char* ptr2;
double acceleration = strtod(accelerationStr, &ptr2);
// Get the pressure
char* pressureStr = getfield(strdup(line), 10);
char* ptr3;
double pressure = strtod(pressureStr, &ptr3);
// Get the read altitude
char* altitudeStr = getfield(strdup(line), 11);
char* ptr4;
double theirAltitude = strtod(altitudeStr, &ptr4);
// Calculate our altitude
ksv = filterSensors(ksv, acceleration, pressure, dt);
// Check for descent
if (i >= detectStart)
{
if (ksv.altitude < lastAlt)
{
descount++;
}
else
{
descount = 0;
}
if (descount > desTrigger && DES == 0)
{
DES = ksv.altitude; // Activate descent stuff!
}
}
// Log data
fprintf(outputStream, "%f,%f,%f,%f,%f,%f\n", dt, acceleration, pressure, theirAltitude, ksv.altitude, DES);
// Update parameters
lastAlt = ksv.altitude;
lastTime = time;
i++;
}
printf("Done.\n");
}