-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathProject2_RUNNING_debug_2.py
More file actions
925 lines (719 loc) · 28.6 KB
/
Project2_RUNNING_debug_2.py
File metadata and controls
925 lines (719 loc) · 28.6 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
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
from scipy import io
from scipy import interpolate
import mpl_toolkits.mplot3d as a3
from mpl_toolkits.mplot3d import Axes3D
from matplotlib.patches import Polygon
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
import matplotlib.animation as manimation
import numpy as np
from rotplot import rotplot
def quat_mult(a,b):
c = np.array([0.,0.,0.,0.])
c[0] = (a[0]*b[0]-a[1]*b[1]-a[2]*b[2]-a[3]*b[3] )
c[1] = (a[0]*b[1]+a[1]*b[0]+a[2]*b[3]-a[3]*b[2] )
c[2] = (a[0]*b[2]-a[1]*b[3]+a[2]*b[0]+a[3]*b[1] )
c[3] = (a[0]*b[3]+a[1]*b[2]-a[2]*b[1]+a[3]*b[0] )
return c
def verify_quat(A,strrr):
if np.abs(np.linalg.norm(A))-1 > .001:
print(strrr + 'has mag: ' + str(np.linalg.norm(A)))
#Change file name here to view various data sets
filename = "imuRaw1"
filename2 = "viconRot1"
#load data
print('loading data')
file = io.loadmat("Data/Train/IMU/"+filename+".mat")
VICONfile = io.loadmat("Data/Train/Vicon/"+filename2+".mat")
IMUparams = io.loadmat("IMUParams.mat")
raw = file['vals']
ts = file['ts']
IMUparams_raw = IMUparams['IMUParams']
w_raw = np.array([raw[4,:],raw[5,:],raw[3,:]]) #reorder for x, y, z
a_raw = np.array([raw[0,:],raw[1,:],raw[2,:]])
# Find bias:
# assume bias is average of first 200 points
bias_w = np.array([w_raw[0,0:200].mean(),w_raw[1,0:200].mean(),w_raw[2,0:200].mean()])
# extract accelerometer bias from IMU params. b_ax, b_ay, b_az
bias_a = np.array([IMUparams_raw[1,0],IMUparams_raw[1,1],IMUparams_raw[1,2]])
# extract accelerometer scale from IMU params. s_x, s_y, s_z
scale_a = np.array([IMUparams_raw[0,0],IMUparams_raw[0,1],IMUparams_raw[0,2]])
#converting w to rads and account for bias
w_rad_x = (3300/1023)* (np.pi/180) * 0.3 * (w_raw[0,:]-bias_w[0])
w_rad_y = (3300/1023)* (np.pi/180) * 0.3 * (w_raw[1,:]-bias_w[1])
w_rad_z = (3300/1023)* (np.pi/180) * 0.3 * (w_raw[2,:]-bias_w[2])
w_rad = np.array([w_rad_x,w_rad_y,w_rad_z])
# convert accelerations to m/s2 account for bias
a_x4 = (a_raw[0,:]*scale_a[0]+bias_a[0])*9.81
a_y4 = (a_raw[1,:]*scale_a[1]+bias_a[1])*9.81
a_z4 = (a_raw[2,:]*scale_a[2]+bias_a[2])*9.81
a_scaled = np.array([a_x4,a_y4,a_z4])
#find Euler angles of Gyro only
x_gyro_rad=np.zeros(w_rad.shape)
for i in range(x_gyro_rad.shape[1]-1):
#have to convert gyro [p q r] to euler angle dots:
#current conditions
phi=x_gyro_rad[0,i]
theta=x_gyro_rad[1,i]
psi=x_gyro_rad[2,i]
#conversion matrix
#page 1 of stengel.mycpanel.princeton.edu/Quaternions.pdf
LBI= np.array([[1, np.sin(phi)*np.tan(theta), np.cos(phi)*np.tan(theta)],[0, np.cos(phi), -np.sin(phi)],[0, np.sin(phi)/np.cos(theta), np.cos(phi)/np.cos(theta)]])
#dEul= phidot,thetadot,psidot
#w_rad[:,:i]= p q r
#convert to d/dt Euler angle
dEul= np.matmul(LBI,w_rad[:,i])
#integrate timestep
dt=ts[0,i+1]-ts[0,i]
temp= np.array([phi+ dt*dEul[0],theta+ dt*dEul[1],psi+ dt*dEul[2]])
x_gyro_rad[:,i+1] = np.transpose(temp)
#find Euler angles of Accelerometer only
a_orientation = np.zeros(a_scaled.shape)
for i in range(x_gyro_rad.shape[1]):
#slide 9
a_phi = np.arctan2(a_y4[i],np.sqrt((a_x4[i]**2)+(a_z4[i]**2)))
a_theta = np.arctan2(-a_x4[i],np.sqrt((a_y4[i]**2)+(a_z4[i]**2)))
a_psi = np.arctan2(np.sqrt((a_x4[i]**2)+(a_y4[i]**2)),a_z4[i])
a_orientation_temp = np.array([a_phi,a_theta,a_psi])
a_orientation[:,i] = a_orientation_temp
# Process VICON data
V_ts= VICONfile['ts']
V_rot_m= VICONfile['rots']
V_x_rad=np.zeros((6,V_rot_m.shape[2]))
for i in range(V_rot_m.shape[2]):
#R is the rotation matrix
R=V_rot_m[:,:,i]
# two solutions exist for a given matrix
th1= -np.arcsin(R[2,0])
th2= np.pi-th1
psi1= np.arctan2(np.sign(np.cos(th1))*R[2,1],np.sign(np.cos(th1))*R[2,2])
psi2= np.arctan2(np.sign(np.cos(th2))*R[2,1],np.sign(np.cos(th2))*R[2,2])
phi1= np.arctan2(np.sign(np.cos(th1))*R[1,0],np.sign(np.cos(th1))*R[0,0])
phi2= np.arctan2(np.sign(np.cos(th2))*R[1,0],np.sign(np.cos(th2))*R[0,0])
#take first solution since lack of information
V_x_rad[0,i]=phi1
V_x_rad[1,i]=th1
V_x_rad[2,i]=psi1
if i>1:
dt = V_ts[0,i]- V_ts[0,i-1]
V_x_rad[3,i] = (V_x_rad[0,i]-V_x_rad[0,i-1])/dt
V_x_rad[4,i] = (V_x_rad[1,i]-V_x_rad[1,i-1])/dt
V_x_rad[5,i] = (V_x_rad[2,i]-V_x_rad[2,i-1])/dt
#ON TO THE MADGWICK FILTER
print('starting Madgwick filter')
######################################################################
#####TUNE Parameters############
Beta=.1
Muu=.1 #Muu accel + (1-Muu)*gyro
#####################################################################
#####################################################################
Magwick_x= np.zeros([3,x_gyro_rad.shape[1]])
est_quat= np.zeros([4,x_gyro_rad.shape[1]])
est_quat[0,0]=1 #let initial rotation be null rotation
qdot_est= np.zeros([4,x_gyro_rad.shape[1]])
qdot_est[0,0]=0
#cant go all the way to end since putting in state at t+1 every time
for i in range(x_gyro_rad.shape[1]-1):
#current state
q_est_t=est_quat[:,i]
#GYRO BRANCH
#slide 17 lecture 2b
# right side of equation
tempquat = [ 0, w_rad[0,i+1],w_rad[1,i+1],w_rad[2,i+1]]
# left side
temp = q_est_t
#quaternion multiply
a = temp
b = tempquat
orien_incr_quat = [0,0,0,0]
orien_incr_quat[0] = .5*(a[0]*b[0]-a[1]*b[1]-a[2]*b[2]-a[3]*b[3])
orien_incr_quat[1] = .5*(a[0]*b[1]+a[1]*b[0]+a[2]*b[3]-a[3]*b[2] )
orien_incr_quat[2] = .5*(a[0]*b[2]-a[1]*b[3]+a[2]*b[0]+a[3]*b[1] )
orien_incr_quat[3] = .5*(a[0]*b[3]+a[1]*b[2]-a[2]*b[1]+a[3]*b[0] )
orientation_inc= np.array([orien_incr_quat[0],orien_incr_quat[1],orien_incr_quat[2],orien_incr_quat[3]])
#ACCEL BRANCH
#for simplicity of eq writing:
q1=q_est_t[0]
q2=q_est_t[1]
q3=q_est_t[2]
q4=q_est_t[3]
#normalize a and take components
ahat=a_scaled[:,i+1]*(1/np.linalg.norm(a_scaled[:,i+1]))
ax=ahat[0]
ay=ahat[1]
az=ahat[2]
#eq in slide 19,20
little_f= np.array([(2*(q2*q4-q1*q3)-ax),(2*(q1*q2+q3*q4)-ay),(2*(0.5 - q2**2 - q3**2)-az)])
big_J= np.array([[-2*q3, 2*q4, -2*q1, 2*q2],[2*q2, 2*q1, 2*q4, 2*q3],[0, -4*q2, -4*q3,0]])
Del_F= np.matmul(np.transpose(big_J),little_f)
#another mistake in slides, normalized by its own magnitude not little f
grad_func= -Beta/(np.linalg.norm(Del_F)) * Del_F
#BRANCH COMBINATION
#INTEGRATE
dt= ts[0,i+1]-ts[0,i]
#temp2 is our next quaternion state
temp2= q_est_t + (1-Muu)*dt*orientation_inc + Muu*grad_func
#normalize before saving
if np.count_nonzero(temp2)==0:
temp2[0]=1
temp2=temp2/(np.linalg.norm(temp2))
#save
est_quat[:,i+1] = np.transpose(temp2)
#convert to Euler angles for plots
#phi
Magwick_x[2,i+1]= np.arctan2((2*(temp2[0]*temp2[1] + temp2[2]*temp2[3])),(1-2*(temp2[1]**2 + temp2[2]**2)))
#theta
Magwick_x[1,i+1]= np.arcsin(2*(temp2[0]*temp2[2] - temp2[3]*temp2[1]))
#psi
Magwick_x[0,i+1]= np.arctan2((2*(temp2[0]*temp2[3] + temp2[1]*temp2[2])),(1-2*(temp2[2]**2 + temp2[3]**2)))
def AVG_statevectors(state_vectors,mean_quat=np.array([1.,0.,0.,0.])):
#make state vectors 7 rows by n column vectors, every column is 7d [quat, p,q,r] state vector
n=float(state_vectors.shape[1])
#normalize the quaternions (just in case)
for i in range(int(n)):
state_vectors[0:4,i]=state_vectors[0:4,i]*(1/np.linalg.norm(state_vectors[0:4,i]))
mean_inv=np.array([1.,0.,0.,0.])
error_matrix=np.zeros((4,int(n)))
error_val=100.0
#in case of infinite loop debug with counter
counter=0
last_error_vector_mean=np.array([0.,0.,0.])
while error_val>0.01:
#this for debugging infinite loop
counter=counter+1
#print('counter is ' + str(counter) + ' error val ' + str(error_val))
if(counter>10000):
if counter==10001:
print('avging input:')
print(state_vectors)
print('counter is ' + str(counter) + ' error val ' + str(error_val) + ' mean quat: ' + str(mean_quat) + '. BREAKING')
print('mean error vector '+ str(error_vector_mean))
#break
#inverse the mean
mean_inv[0]=mean_quat[0]
mean_inv[1:]=-1*mean_quat[1:]
#initialize error_vector
error_vector_mean=np.array([0.,0.,0.])
#print(counter)
for i in range(int(n)):
#calc error quaternions
error_matrix[:,i]= quat_mult(state_vectors[:4,i],mean_inv)
#normalize (just in case)
#verify_quat(error_matrix[:,i],'Error_sub_quat')
error_matrix[:,i]= error_matrix[:,i]*(1/np.linalg.norm(error_matrix[:,i]))
#you have quaternion, now make into error vector subscript i
theta= 2*np.arccos(error_matrix[0,i])
if (np.abs(theta)>0.00001):
error_vector= error_matrix[1:,i]/(np.sin(theta/2))
else:
error_vector= np.array([0.,0.,0.])#error_matrix[1:,i]
#print(error_vector)
#add it to the mean
error_vector_mean= error_vector_mean + (error_vector/n)
#print(error_vector_mean)
#heres your convergence value, when error vector is 0,0,0 you're good, this should be close enough
#relaxation factor:
error_vector_mean= .96*last_error_vector_mean+ .04*error_vector_mean
last_error_vector_mean=error_vector_mean
error_val=np.linalg.norm(error_vector_mean)
#print(error_matrix)
#okay now convert your mean error vector back into a quaternion to update the mean quaternion
error_quat=np.array([np.cos(error_val/2), error_vector_mean[0]*np.sin(error_val/2),error_vector_mean[1]*np.sin(error_val/2),error_vector_mean[2]*np.sin(error_val/2)])
#normalize for those floating point errors and stuff
#verify_quat(error_quat,'Error_full_quat')
error_quat= error_quat*(1/np.linalg.norm(error_quat))
#update your mean quaternion
mean_quat=quat_mult(error_quat,mean_quat)
#normalize that too
#verify_quat(mean_quat,'mean_quat')
mean_quat=mean_quat*(1/np.linalg.norm(mean_quat))
#holy hell, finally have mean quat
#alright finish up the mean with regular averaging
#initialize the mean rates and average them up
mean_rates=np.array([0.,0.,0.])
for i in range(int(n)):
mean_rates=mean_rates + state_vectors[4:,i]*(1/n)
#put it all together
xbar=np.concatenate((mean_quat, mean_rates))
return xbar
def COV_6d(state_vectors,xbar=np.array([0.,0.,0.,0.,0.,0.])):
#so you got a bunch of 6d state vectors, and their average
#give back a 6x6 covariance matrix, itll always be 6x6 for this input
oned=0
try:
n=float(state_vectors.shape[1])
except:
n=1.
oned=1
temp=np.zeros((6,1))
cov_matrix=np.zeros((6,6))
for i in range(int(n)):
if(oned==1):
temp[:,0]=state_vectors-xbar
else:
temp[:,0]=state_vectors[:,i]-xbar
#print(temp.shape)
temp_matrix=np.matmul(temp,np.transpose(temp))
#print(temp_matrix.shape)
cov_matrix= cov_matrix+(temp_matrix/n)
#print(cov_matrix)
return cov_matrix
def COV_7d(state_vectors,xbar):#=np.array([1.,0.,0.,0.,0.,0.,0.])):
#alright so we got these 7d vectors right, so we want to get some sick ass 6d covariance matrix out of it
n=float(state_vectors.shape[1])
temp=np.zeros((6,1))
cov_matrix=np.zeros((6,6))
Wprime=np.zeros((6,int(n)))
for i in range(int(n)):
#so we need to grab this quaternion shit and find the error quaternions (subtract out the mean quaternion)
e_quat=quat_mult(state_vectors[:4,i],np.array([xbar[0],-xbar[1],-xbar[2],-xbar[3]]))
#verify_quat(e_quat,'E_quat COV_7d')
#okay lets put this bitch ass error quaternion into a rotation vector thingy thang
theta= 2*np.arccos(e_quat[0]) #angle
if (np.abs(np.abs(e_quat[0])-1)>0.01):
axis= e_quat[1:]/(np.sin(theta/2)) #vector
else:
axis= e_quat[1:] #if angle is 0 then this bitch boi is also all 0s
#okay bet so now we grab this a_w and e_w things from like equation 14,15 and make into w_q, which is r_w now for this thing because consistent notation is for CHUMPS
r_w=theta*axis
#alright now gg2ez subtract out the rates
w_w=state_vectors[4:,i]#-xbar[4:]
#bet now we can get these W'i vectors that are basically X-xbar so we can do the transposy thingy and mean it all out
#Wprime[:,i]=np.array([r_w[0],r_w[1],r_w[2],w_w[0],w_w[1],w_w[2]]) #could have concat but didnt want to deal with axis and dimensions and shit
Wprime[:,i]=np.array([r_w[0],r_w[1],r_w[2],w_w[0]-xbar[4],w_w[1]-xbar[5],w_w[2]-xbar[6]])
temp[:,0]=Wprime[:,i]
temp_matrix=np.matmul(temp,np.transpose(temp))
cov_matrix= cov_matrix+(temp_matrix/n)
#bet
return cov_matrix,Wprime
def ProcessModel(State0,dt):
# State is a 7x1 vector of position quaternions and angular velocity
# State = [q0,q1,q2,q3,wx,wy,wz]
# dt in seconds
# w_k is noise vector [wq,ww] NOT USED
# Initialize the next state as the current state
State1 = np.zeros(7)
# The simple process model A assumes constant angular velocity
# Over a short time period, this assumption holds well
w_k = np.array(State0[4:])
State1[4:7] = w_k
q_k = np.array(State0[:4])
# Calculate delta angle of rotation assuming constant angluar velocity over time dt
mag= np.linalg.norm(w_k)
da = dt*mag
# Calculate rotation axis for constant angular rotation
if np.abs(mag) > 0.0001:
de = w_k/mag
else:
de= np.array([0.,0.,0.])
# Calculate change in quaternions as a result of rotation
dq = np.array([np.cos(da/2),de[0]*np.sin(da/2),de[1]*np.sin(da/2),de[2]*np.sin(da/2)])
#verify_quat(dq,'dq Processmodel')
# Noise Calculations
#w_q = np.array(w_k[0:3])
#a_w = np.linalg.norm(w_q)
#e_w = w_q/np.linalg.norm(w_q)
#q_w = np.array([np.cos(a_w/2),e_w[0]*np.sin(a_w/2),e_w[1]*np.sin(a_w/2),e_w[2]*np.sin(a_w/2)])
# Assemble new state vector
#temp = quat_mult(q_k,q_w)
State1[0:4] = quat_mult(q_k,dq)
#verify_quat(State1[0:4],'Y_quat')
return State1
# Measurement Model
def MeasurementModel(State0):
# State is a 7x1 vector of position quaternions and angular velocity
# State = [q0,q1,q2,q3,wx,wy,wz]
# v is 7x1 noise vector NOT USED
Gyro1 = np.zeros(3)
Gyro1 = np.array(State0[4:7])#+np.array(v[4:7])
Accel1 = np.zeros(4)
q_k = np.array(State0[0:4])
# Define g as gravity down, ie a_z = -9.81 m/s/s
g = np.array([0,0,0,9.81])
# inverse q_k is the negative of the last 3 components
qi = np.array([q_k[0],-q_k[1],-q_k[2],-q_k[3]])
temp = quat_mult(qi,g)
gprime = quat_mult(temp,q_k)
Accel1 = gprime[1:4]#+v[0:4]
#put it all together
Z = np.concatenate((Accel1,Gyro1),axis=None)
return Z
#MAIN_------------------------------------------------------------------------------
#-----------------------------------------------------------------------------------
#TUNING PARAM
#R=np.zeros((6,6)) #Measurement uncertainty covariance: idk what else to set this to rn
Ra = 200 #accelerometer observation model noise
Rg = 200 #.04 # Gyro observation model noise <
#^^ This parameter seems to play a big role in changing output values
R = np.diag(np.concatenate([Ra*np.ones([1,3]),Rg*np.ones([1,3])],axis=None))
#Q=np.zeros((6,6)) #ProcessModel uncertainty covariance: idk what else to set this to rn
Qa = 200 #.5#100#.001#1 # Process model accel noise <
Qg = 150 # Process model gyro noise <
Q = np.diag(np.concatenate([Qa*np.ones([1,3]),Qg*np.ones([1,3])],axis=None))
#STABLE params: Ra Rg Qa Qg 20.1 3.01 100.1 0.3
#1.1 3.01 100.1 .03
#.71 .11 102.1 .3
#Qa = .001 gave no movement
#.71 .11 .0064 .91 Was stable in sort of moved
#.1 .01 .018 .01
#Here are some states from just pure gyro data and their covariance
#init_mean=np.array([np.mean(x_gyro_rad[0,:200]),np.mean(x_gyro_rad[1,:200]),np.mean(x_gyro_rad[2,:200]),np.mean(w_rad[0,:200]),np.mean(w_rad[1,:200]),np.mean(w_rad[2,:200])])
#init_states=np.zeros((6,200))
#for i in range(200):
# init_states[:,i]=np.concatenate((x_gyro_rad[:,i],w_rad[:,i]),axis=None)
##Q=np.matmul(w_k,np.transpose(w_k))
#Q=COV_6d(init_states,init_mean)
#INITIALIZE
#previous state vector x_k-1 initialize to 0's baseline:
x_prev=np.array([1.,0.,0.,0.,0.,0.,0.])
#its covariance P_k-1
#lets initialize at 0, this gets updated as we go so fuck it as long as its mildly valid
P_prev=0.001*np.ones((6,6))
#P_prev=np.diag(0.1*np.ones(6))
Xs_filter=np.zeros((7,ts.shape[1]))
UKF_out=np.zeros((6,ts.shape[1]))
Xs_filter[:,0]=x_prev
#ALLLLLLLRIGHTTYYYY THEN WE START THE LOOPAROONI NOW
for I_time in range(ts.shape[1]-1): #range(10): range(3): #
# print('main loop I: ')
#print(I_time)
print(str(I_time)+ ' : '+ str((100*I_time)/ts.shape[1]) + '%')
#Cholesky square root
S=np.transpose(np.linalg.cholesky(P_prev+Q))
#S=np.linalg.cholesky(P_prev+Q)
# print('confirming')
# print(P_prev+Q)
# print('P_prev ^ StS down')
# print(np.matmul(np.transpose(S),S))
#take the columns of S to eat up W
W= np.concatenate((S*(np.sqrt(1*6)),S*(-1*np.sqrt(1*6))),axis=1)
#print('W:')
#print(W)
#Make the sigma points
X=np.zeros((7,W.shape[1])) #alrighhtttty so X needs to be a 7 d boiii
#lets throw x_prev into the W boi witha quaternion conversion thingy
for i in range(W.shape[1]):
temp_rot_v=W[:3,i] #first three are the rotation angles, second 3 are the rates so...we grab the angles to make a quaternion transform
a_w=np.linalg.norm(W[:4,i])#angle
if np.abs(a_w) > 0.001:
e_w=W[:3,i]/a_w#rot vecotor
else:
e_w=np.array([0.,0.,0.]) #W[:3,i]
q_w=np.array([np.cos(a_w/2),e_w[0]*np.sin(a_w/2),e_w[1]*np.sin(a_w/2),e_w[2]*np.sin(a_w/2)])#convert to quaternion
#verify_quat(q_w,'q_w in sigma make')
X[:4,i]= quat_mult(x_prev[:4],q_w)#shove it in there
#verify_quat(X[:4,i],'X[:4,i] in sigma make')
X[:4,i]=X[:4,i]/np.linalg.norm(X[:4,i])#just in fucking case yo
X[4:,i]= x_prev[4:] + W[3:,i]#gg2ez with the rotation rates
#print(S)
# print(W)
# print(x_prev)
#print(X)
#Alrighty, lets tranform these sigma points BOIIII
Y=np.zeros(X.shape)
dt=ts[0,I_time+1]-ts[0,I_time]
for i in range(X.shape[1]):
Y[:,i]= ProcessModel(X[:,i],dt)
#Now with Y we can pull out x_kminus, Wiprime,and Pkminus which is step 4,5,6
x_prior=AVG_statevectors(Y,x_prev[:4]) #use the mean of X as the starting point duh
P_k_prior,Wprime=COV_7d(Y,x_prior)
# if np.mod(I_time,500)==1:
# print(I_time)
# print(Y)
# #print(P_prev)
# #print(Y)
# print('Avg of above')
# print(x_prior)
# print('error')
# print(Wprime)
# # print('up is P_prev')
# # print(X)
# # print('upX dwn Y')
# # print(Y)
# # print(dt)
# Step 7, Calculate Expected Sensor output Z at predicted states Y
Z=np.zeros((6,Y.shape[1]))
for i in range(Y.shape[1]):
Z[:,i] = MeasurementModel(Y[:,i])
z_bar=np.mean(Z,axis=1)
#Step 8
SensorState = np.concatenate((a_scaled[:,I_time],x_gyro_rad[:,I_time]),axis=None)
innovation=np.zeros((6,1))
innovation[:,0] = SensorState - z_bar
#Step 9
P_zz=COV_6d(Z,z_bar)
Pvv=P_zz+R
#Cross Correlation Matrix
Pxz= np.zeros((6,6))
for i in range(12):
temp_matrix= np.outer(Wprime[:,i],(Z[:,i]-z_bar))
Pxz=Pxz+(temp_matrix/12)
Kk= np.matmul(Pxz,np.linalg.inv(Pvv))
#okay so we cant just add a 6d to a 7d, IE( x_posteriori=x_prior+ np.matmul(Kk,innovation) )
x_posteriori=np.zeros(7)
Kalman6d=np.matmul(Kk,innovation)
#print(Kalman6d.shape)
# so... gonna have to take the 6d and make it 7
#so build the quaternion
mag= np.linalg.norm(Kalman6d[:3,0])
if mag != 0:
de = Kalman6d[:3,0]/mag
else:
de=Kalman6d[:3,0]
KalmanQ = np.array([np.cos(mag/2),de[0]*np.sin(mag/2),de[1]*np.sin(mag/2),de[2]*np.sin(mag/2)])
#verify_quat(KalmanQ,'Kalman6d')
KalmanQ = KalmanQ*(1/np.linalg.norm(KalmanQ))
x_posteriori[:4]=quat_mult(x_prior[:4],KalmanQ)
#okay now do the state vector addition thingy
x_posteriori[4:]=Kalman6d[3:,0]+x_prior[4:]
#update P
# print('P_prev')
# print(P_prev)
P_prev=P_k_prior - np.matmul(np.matmul(Kk,Pvv),np.transpose(Kk))
#reset x for next round
x_prev=x_posteriori
Xs_filter[:,I_time+1]=x_posteriori
#convert to Euler angles for plots
#phi
UKF_out[2,I_time+1]= np.arctan2((2*(x_posteriori[0]*x_posteriori[1] + x_posteriori[2]*x_posteriori[3])),(1-2*(x_posteriori[1]**2 + x_posteriori[2]**2)))
#theta
UKF_out[1,I_time+1]= np.arcsin(2*(x_posteriori[0]*x_posteriori[2] - x_posteriori[3]*x_posteriori[1]))
#psi
UKF_out[0,I_time+1]= np.arctan2((2*(x_posteriori[0]*x_posteriori[3] + x_posteriori[1]*x_posteriori[2])),(1-2*(x_posteriori[2]**2 + x_posteriori[3]**2)))
UKF_out[3:,I_time+1] = x_posteriori[4:]
# print('P_k_prior')
# print(P_k_prior)
# print('Kk')
# print(Kk)
# print('Pxz')
# print(Pxz)
# print('Pvv^-1')
# print(np.linalg.inv(Pvv))
#print('Y')
#print(Y)
#print('x_prior')
#print(x_prior)
#print('x_prior quat mag')
#print(np.linalg.norm(x_prior[:4]))
#print('Wprime')
#print(Wprime)
#print('Wprime[:,11],np.transpose(Wprime[:,11]')
#print(np.matmul(Wprime[:,11],np.transpose(Wprime[:,11])))
#print('Wprime[:,11].shape')
#print(Wprime[:,11].shape)
#for debugging
# raw_input("Press Enter to continue...")
print('plotting')
#print(x_gyro_rad)
plot_time = np.zeros([1,x_gyro_rad.shape[1]])
plot_time_V = np.zeros([1,V_x_rad.shape[1]])
for i in range(x_gyro_rad.shape[1]):
plot_time[0,i] = (ts[0,i]-ts[0,0])/1
for i in range(V_x_rad.shape[1]):
plot_time_V[0,i] = (V_ts[0,i]-V_ts[0,0])/1
plot_time = np.transpose(plot_time)
plot_time_V = np.transpose(plot_time_V)
fig = plt.figure(figsize=(12,10),dpi=80,facecolor = 'w', edgecolor = 'k')
ax1 = fig.add_subplot(3,1,1,title = 'Yaw, Psi')
ax1.plot(plot_time_V,V_x_rad[0,:],label = 'Vicon')
#plt.hold(True)
ax1.plot(plot_time,x_gyro_rad[2,:],label = 'Gyro')
ax1.plot(plot_time,a_orientation[2,:],label = 'Accel')
ax1.plot(plot_time,UKF_out[0,:],label = 'UKF')
#ax1.plot(plot_time,UKF_out[5,:],label = 'UKF rate?')
plt.ylabel('angle, Radians')
plt.legend(loc = 'lower right')
ax2 = fig.add_subplot(3,1,2,title = 'Pitch, Theta')
ax2.plot(plot_time_V,V_x_rad[1,:],label = 'Vicon')
#plt.hold(True)
ax2.plot(plot_time,x_gyro_rad[1,:],label = 'Gyro')
ax2.plot(plot_time,a_orientation[1,:],label = 'Accel')
ax2.plot(plot_time,UKF_out[1,:],label = 'UKF')
#ax2.plot(plot_time,UKF_out[4,:],label = 'UKF rate?')
plt.ylabel('angle, Radians')
plt.legend(loc = 'lower right')
ax3 = fig.add_subplot(3,1,3,title = 'Roll, Phi')
ax3.plot(plot_time_V,V_x_rad[2,:],label = 'Vicon')
#plt.hold(True)
ax3.plot(plot_time,x_gyro_rad[0,:],label = 'Gyro')
ax3.plot(plot_time,a_orientation[0,:],label = 'Accel')
ax3.plot(plot_time,UKF_out[2,:],label = 'UKF')
#ax3.plot(plot_time,UKF_out[3,:],label = 'UKF rate?')
plt.xlabel('time, s')
plt.ylabel('angle, Radians')
plt.legend(loc = 'lower right')
plt.savefig(filename + ".png")
#plt.show()
# fig2 = plt.figure(figsize=(12,10),dpi=80,facecolor = 'w', edgecolor = 'k')
# ax4 = fig2.add_subplot(3,1,1,title = 'RollRate')
# #plt.hold(True)
# #ax4.plot(plot_time_V,V_x_rad[3,:],label = 'Vicon')
# ax4.plot(plot_time,w_rad[0,:],label = 'Gyro')
# ax4.plot(plot_time,UKF_out[3,:],label = 'UKF')
# plt.xlabel('time, s')
# plt.ylabel('angular rate, Radians/s')
# plt.legend(loc = 'lower right')
# ax5 = fig2.add_subplot(3,1,2,title = 'PitchRate')
# #plt.hold(True)
# #ax5.plot(plot_time_V,V_x_rad[4,:],label = 'Vicon')
# ax5.plot(plot_time,w_rad[1,:],label = 'Gyro')
# ax5.plot(plot_time,UKF_out[4,:],label = 'UKF')
# plt.xlabel('time, s')
# plt.ylabel('angular rate, Radians/s')
# plt.legend(loc = 'lower right')
# ax6 = fig2.add_subplot(3,1,3,title = 'YawRate')
# #plt.hold(True)
# #ax6.plot(plot_time_V,V_x_rad[5,:],label = 'Vicon')
# ax6.plot(plot_time,w_rad[2,:],label = 'Gyro')
# ax6.plot(plot_time,UKF_out[5,:],label = 'UKF')
# plt.xlabel('time, s')
# plt.ylabel('angular rate, Radians/s')
# plt.legend(loc = 'lower right')
fig2 = plt.figure(figsize=(12,10),dpi=80,facecolor = 'w', edgecolor = 'k')
ax4 = fig2.add_subplot(4,1,1,title = 'q0')
ax4.plot(plot_time,Xs_filter[0,:],label = 'UKF')
ax5 = fig2.add_subplot(4,1,2,title = 'q1')
ax5.plot(plot_time,Xs_filter[1,:],label = 'Gyro')
ax6 = fig2.add_subplot(4,1,3,title = 'q2')
ax6.plot(plot_time,Xs_filter[2,:],label = 'UKF')
ax7 = fig2.add_subplot(4,1,4,title = 'q3')
ax7.plot(plot_time,Xs_filter[3,:],label = 'UKF')
plt.xlabel('time, s')
plt.ylabel('q')
plt.show()
# begin video production
print('Creating video simulation')
# produce ZYX Euler rotation matrices for every time step
# gyro data
print('The dimensions of x_gyro_rad are: ' + str(x_gyro_rad.shape))
Rzyx_gyro = np.zeros(shape = (3, 3, x_gyro_rad.shape[1]))
for i in range(0, Rzyx_gyro.shape[2]):
Rz_gyro = np.array([[np.cos(x_gyro_rad[2, i]), -np.sin(x_gyro_rad[2, i]), 0],
[np.sin(x_gyro_rad[2, i]), np.cos(x_gyro_rad[2, i]), 0],
[0, 0, 1]])
Ry_gyro = np.array([[np.cos(x_gyro_rad[1, i]), 0, np.sin(x_gyro_rad[1, i])],
[0, 1, 0],
[-np.sin(x_gyro_rad[1, i]), 0, np.cos(x_gyro_rad[1, i])]])
Rx_gyro = np.array([[1, 0, 0],
[0, np.cos(x_gyro_rad[0, i]), -np.sin(x_gyro_rad[0, i])],
[0, np.sin(x_gyro_rad[0, i]), np.cos(x_gyro_rad[0, i])]])
Rzyx_gyro[:, :, i] = np.matmul(Rz_gyro, np.matmul(Ry_gyro, Rx_gyro))
print('The dimensions of Rzyx_gyro are: ' + str(Rzyx_gyro.shape))
# accel data
print('The dimensions of a_orientation are: ' + str(a_orientation.shape))
Rzyx_accel = np.zeros(shape = (3, 3, a_orientation.shape[1]))
for i in range(0, Rzyx_accel.shape[2]):
Rz_accel = np.array([[np.cos(a_orientation[2, i]), -np.sin(a_orientation[2, i]), 0],
[np.sin(a_orientation[2, i]), np.cos(a_orientation[2, i]), 0],
[0, 0, 1]])
Ry_accel = np.array([[np.cos(a_orientation[1, i]), 0, np.sin(a_orientation[1, i])],
[0, 1, 0],
[-np.sin(a_orientation[1, i]), 0, np.cos(a_orientation[1, i])]])
Rx_accel = np.array([[1, 0, 0],
[0, np.cos(a_orientation[0, i]), -np.sin(a_orientation[0, i])],
[0, np.sin(a_orientation[0, i]), np.cos(a_orientation[0, i])]])
Rzyx_accel[:, :, i] = np.matmul(Rz_accel, np.matmul(Ry_accel, Rx_accel))
print('The dimensions of Rzyx_accel are: ' + str(Rzyx_accel.shape))
# Madgwick data
print('The dimensions of Magwick_x are: ' + str(Magwick_x.shape))
Rzyx_madg = np.zeros(shape = (3, 3, Magwick_x.shape[1]))
for i in range(0, Rzyx_madg.shape[2]):
Rz_madg = np.array([[np.cos(Magwick_x[0, i]), -np.sin(Magwick_x[0, i]), 0],
[np.sin(Magwick_x[0, i]), np.cos(Magwick_x[0, i]), 0],
[0, 0, 1]])
Ry_madg = np.array([[np.cos(Magwick_x[1, i]), 0, np.sin(Magwick_x[1, i])],
[0, 1, 0],
[-np.sin(Magwick_x[1, i]), 0, np.cos(Magwick_x[1, i])]])
Rx_madg = np.array([[1, 0, 0],
[0, np.cos(Magwick_x[2, i]), -np.sin(Magwick_x[2, i])],
[0, np.sin(Magwick_x[2, i]), np.cos(Magwick_x[2, i])]])
Rzyx_madg[:, :, i] = np.matmul(Rz_madg, np.matmul(Ry_madg, Rx_madg))
print('The dimensions of Rzyx_madg are: ' + str(Rzyx_madg.shape))
# UKF data
Rzyx_UKF = np.zeros(shape = (3, 3, UKF_out.shape[1]))
for i in range(0, Rzyx_UKF.shape[2]):
Rz_UKF = np.array([[np.cos(UKF_out[0, i]), -np.sin(UKF_out[0, i]), 0],
[np.sin(UKF_out[0, i]), np.cos(UKF_out[0, i]), 0],
[0, 0, 1]])
Ry_UKF = np.array([[np.cos(UKF_out[1, i]), 0, np.sin(UKF_out[1, i])],
[0, 1, 0],
[-np.sin(UKF_out[1, i]), 0, np.cos(UKF_out[1, i])]])
Rx_UKF = np.array([[1, 0, 0],
[0, np.cos(UKF_out[2, i]), -np.sin(UKF_out[2, i])],
[0, np.sin(UKF_out[2, i]), np.cos(UKF_out[2, i])]])
Rzyx_UKF[:, :, i] = np.matmul(Rz_UKF, np.matmul(Ry_UKF, Rx_UKF))
print('The dimensions of Rzyx_UKF are: ' + str(Rzyx_UKF.shape))
#Initialize videomaker
Framerate=15 #fps
AnimFig=plt.figure()
FFMpegWriter = manimation.writers['ffmpeg']
#if Requested MovieWriter not available error then:
#$ sudo apt install ffmpeg
metadata = dict(title='', artist='Ilya',
comment='')
writer = FFMpegWriter(fps=Framerate, metadata=metadata)
#reduce data to frameratefps
#lets just use Vicon time as the basis
#idea from team "sudo rm -rf"
ViconTs = np.linspace(V_ts[0,0], V_ts[0,-1], num=((V_ts[0,-1]-V_ts[0,0])*Framerate) )
print('The dimensions of ViconTs are: ' + str(ViconTs.shape))
counter=0
Vicon_Rot_Ms=np.zeros((3,3,ViconTs.shape[0]))
for i in range(V_rot_m.shape[2]):
#if you passed it grab the last one, should be close enough
if V_ts[0,i]>ViconTs[counter]:
Vicon_Rot_Ms[:,:,counter]=V_rot_m[:,:,i]
counter+=1
if counter==ViconTs.shape[0]:
break
#IMUTs = np.linspace(ts[0,0], ts[0,-1], num=((ts[0,-1]-ts[0,0])*Framerate) )
#print('The dimensions of IMUTs are: ' + str(IMUTs.shape))
Accel_Rot_Ms=np.zeros((3,3,ViconTs.shape[0]))
Gyro_Rot_Ms=np.zeros((3,3,ViconTs.shape[0]))
Magwick_Rot_Ms=np.zeros((3,3,ViconTs.shape[0]))
UKF_Rot_Ms=np.zeros((3,3,ViconTs.shape[0]))
#print('The dimensions of ts are: ' + str(ts.shape))
counter=0
for i in range(0,x_gyro_rad.shape[1]):
if ts[0,i]>ViconTs[counter]:
Accel_Rot_Ms[:,:,counter]=Rzyx_accel[:,:,i]
Gyro_Rot_Ms[:,:,counter]=Rzyx_gyro[:,:,i]
Magwick_Rot_Ms[:,:,counter]=Rzyx_madg[:,:,i]
UKF_Rot_Ms[:,:,counter]=Rzyx_UKF[:,:,i]
counter+=1
if counter==ViconTs.shape[0]:
break
#lets get plotting and writing!
#plotting setup:
Fig_animate= plt.figure(figsize=(10,4))
ax1=plt.subplot(141,projection='3d')
ax2=plt.subplot(142,projection='3d')
ax3=plt.subplot(143,projection='3d')
ax4=plt.subplot(144,projection='3d')
ax5=plt.subplot(144,projection='3d')
ax1.title.set_text('Gyro')
ax2.title.set_text('Accel')
ax3.title.set_text('Magwick')
ax4.title.set_text('Vicon')
ax5.title.set_text('UKF')
print('writing file...')
with writer.saving(Fig_animate, filename +"_vid"+ ".mp4", ViconTs.shape[0]):
for i in range(ViconTs.shape[0]):
print(str(i) +'of' + str(ViconTs.shape[0]))
ax1.clear()
ax2.clear()
ax3.clear()
ax4.clear()
ax5.clear()
ax1.title.set_text('Gyro')
ax2.title.set_text('Accel')
ax3.title.set_text('Magwick')
ax4.title.set_text('Vicon')
ax5.title.set_text('UKF')
rotplot(Gyro_Rot_Ms[:,:,i],ax1)
rotplot(Accel_Rot_Ms[:,:,i],ax2)
rotplot(Magwick_Rot_Ms[:,:,i],ax3)
rotplot(Vicon_Rot_Ms[:,:,i],ax4)
rotplot(UKF_Rot_Ms[:,:,i],ax5)
writer.grab_frame()