ISDataAnalytics.py
Go to the documentation of this file.
1 '''
2 Created on Feb 17, 2017
3 
4 '''
5 # from numbers import Number
6 import numpy as np
7 import os
8 import sys
9 # import ctypes as ct
10 import math
11 import pylib.ISToolsDataSorted as itd
12 import subprocess as subprocess
13 import pdb
14 
15 from pylab import plt
16 from scipy.interpolate import interp1d
17 
18 RAD2DEG = 180/np.pi
19 DEG2RAD = np.pi/180
20 
21 def calculateDistance(lat1,lon1,lat2,lon2):
22  # All angles are in radians
23 
24  # Haversine formula
25  Re = 6371000 # (m)
26  dLat = lat2-lat1
27  dLon = lon2-lon1
28 
29  a = math.sin(dLat/2)*math.sin(dLat/2) + math.cos(lat1) * math.cos(lat2) * math.sin(dLon/2) * math.sin(dLon/2)
30  c = 2 * math.atan2(math.sqrt(a), math.sqrt(1-a))
31 
32  d = Re * c
33 
34  return d
35 
37  for dev in log.devices:
38  if 'debugArray' in dev.data.keys() and 'GPS1Raw' in dev.data.keys():
39  dbg = dev.data['debugArray']['i']
40  counts = dev.data['GPS1Raw']['count'][dev.data['GPS1Raw']['type'] == 1]
41  total_obs_in_log=np.sum(counts)
42  obs_at_start = dbg[0,:]
43  obs_at_end = dbg[-1, :]
44  print("===================== Raw GPS Message Statistics ======================")
45  print("uINS - %d", dev.serialNumber)
46  print("recorded observations: %d, " % total_obs_in_log)
47  print("observations reported by firmware %d, " % obs_at_end[3])
48 
49 
50 # RMS Support Functions
52  offset = 0
53  newData = []
54  for dIndex in range(0,len(ins.v['euler'])):
55  if dIndex == 0:
56  prevHeading = ins.v['euler'][0][2]
57  newData.append(ins.v['euler'][0][2])
58  else:
59  currHeading = ins.v['euler'][dIndex][2]
60  if prevHeading - currHeading > np.pi:
61  offset += 1
62  elif prevHeading - currHeading < -np.pi:
63  offset -= 1
64  prevHeading = currHeading
65  newData.append((currHeading + offset*2*np.pi))
66 
67  #plt.plot(ins.v['tow'], newData)
68 
69  for dIndex in range(0,len(ins.v['euler'])):
70  ins.v['euler'][dIndex][2] = newData[dIndex]
71  return ins
72 
73 # TODO: Compile this function into C-extension
74 def shiftTime(tow,dataSet,time):
75 
76  for n in range(0,len(time)):
77  if time[n] > max(tow):
78  time[n] = max(tow)
79  elif time[n] < min(tow):
80  time[n] = min(tow)
81 
82  newDataSet = np.zeros((len(time),3),dtype=np.float32)
83  for sIndex in range(0,3):
84  newData = np.zeros((len(time)),dtype=np.float32)
85  oldData = np.zeros((len(tow)),dtype=np.float32)
86  for dIndex in range(0,len(tow)):
87  oldData[dIndex] = dataSet[dIndex][sIndex]
88 
89  f = interp1d(tow,oldData,kind='cubic')
90  newData = f(time)
91 
92  for n in range(0,len(time)):
93  newDataSet[n][sIndex] = newData[n]
94 
95  return newDataSet
96 
97 def computeRmsAccuracies(log, directory, subdir):
98  numDev = len(log.devices)
99  averageRMS = {}
100  if numDev > 1:
101 
102  print("\nComputing RMS Accuracies: (%d devices)" % (numDev))
103 
104  # Setup Data Analyics
105  # States available in ins structure - ('dataSerNum', 'week', 'tow', 'iStatus', 'hStatus', 'q', 'uvw', 'lla', 'euler')
106  # Or data for each device can be called to access converted euler angles
107  # ins = itd.cINS(log.devices[i].data['ins2'])
108  States = ['uvw','lla','euler']
109  ins = []
110  for index in range(0,numDev):
111  ins.append(itd.cINS(log.devices[index].data['ins2']))
112 
113  # --------------------------------------------- Data handling --------------------------------------------
114  plt.figure() # Test Figure
115 
116  # 1. Unwrapping Heading to handle discontinuity at -180/180
117  unwrappedHeading = {}
118  for devIndex in range(0,numDev):
119  ins[devIndex] = handleHeadingWrapping(ins[devIndex])
120  headingData = []
121  time = []
122  for dIndex in range(0,len(ins[devIndex].v['euler'])):
123  headingData.append(ins[devIndex].v['euler'][dIndex][2])
124  time.append(ins[devIndex].v['tow'][dIndex])
125  plt.plot(time, headingData)
126 
127  # TODO: Consider debugging why this is required and instead of shifting the baselines consider Testing for errors
128  # TODO: Compile the C Data Shift code to a C extension
129  # 2. Shift data to common time scale
130  nPts = len(ins[0].v['tow'])
131  time = np.zeros((nPts,1),dtype=np.float32)
132  for n in range(0,nPts):
133  time[n] = ins[0].v['tow'][n]
134 
135  insA = []
136  totalRebaselines = 3*numDev
137  rebaseline = 0;
138  for stateSet in States:
139  for devIndex in range(0,numDev):
140  insA.append({})
141  insA[devIndex][stateSet] = shiftTime(ins[devIndex].v['tow'],ins[devIndex].v[stateSet],time)
142  rebaseline += 1
143  print("Rebaselining - %d of %d" % (rebaseline,totalRebaselines) )
144 
145  # --------------------------------------------- Calc RMS --------------------------------------------
146  cumulativeValues = {}
147  averageValues = {}
148  bias = {}
149  se = {}
150  deviceRMS = {}
151  averageRMS = {}
152  for stateSet in States:
153 
154  # 1. Compute Average Values Across All Devices as Truth
155  cumulativeValues[stateSet] = [[0.0 for x in range(3)] for y in range(len(insA[0][stateSet]))]
156  for devIndex in range(0,numDev):
157  for sIndex in range(0,3):
158  for dIndex in range(0,len(insA[0][stateSet])):
159  cumulativeValues[stateSet][dIndex][sIndex] += insA[devIndex][stateSet][dIndex][sIndex]
160 
161  averageValues[stateSet] = [[0 for x in range(3)] for y in range(len(insA[0][stateSet]))]
162  for sIndex in range(0,3):
163  for dIndex in range(0,len(insA[0][stateSet])):
164  averageValues[stateSet][dIndex][sIndex] = cumulativeValues[stateSet][dIndex][sIndex] / numDev # [x / myInt for x in myList]
165 
166  # 2. For Angles - Remove mounting biasses
167  bias[stateSet] = [[0 for x in range(3)] for y in range(numDev)]
168  if 'euler' in stateSet:
169  for devIndex in range(0,numDev):
170  for sIndex in range(0,3):
171  n = len(insA[0][stateSet])
172  cumError = 0
173  for dIndex in range(int(n/2),n-1):
174  cumError += averageValues[stateSet][dIndex][sIndex] - insA[devIndex][stateSet][dIndex][sIndex]
175  bias[stateSet][devIndex][sIndex] = cumError/(n/2-1)
176 
177  # 3. Calculate the Squared Error Values for each state in each device
178  se[stateSet] = [[[0 for x in range(3)] for y in range(len(insA[0][stateSet]))] for z in range(numDev)]
179  for devIndex in range(0,numDev):
180  for sIndex in range(0,3):
181  for dIndex in range(0,len(insA[0][stateSet])):
182  se[stateSet][devIndex][dIndex][sIndex] = pow(averageValues[stateSet][dIndex][sIndex] - insA[devIndex][stateSet][dIndex][sIndex] - bias[stateSet][devIndex][sIndex],2)
183 
184  # 4. Calculte the RMS for each device
185  deviceRMS[stateSet] = [[0 for x in range(3)] for y in range(numDev)]
186  for devIndex in range(0,numDev):
187  for sIndex in range(0,3):
188  n = len(se[stateSet][devIndex])
189  cumValue = 0;
190  # Only use the second half of the data for the final calculation. Index starts at n/2
191  for dIndex in range(int(n/2),n-1):
192  cumValue += se[stateSet][devIndex][dIndex][sIndex]
193  deviceRMS[stateSet][devIndex][sIndex] = math.sqrt(cumValue/(n/2-1))
194 
195  # 5. Calculate the average RMS values across all devices
196  averageRMS[stateSet] = [0 for x in range(3)]
197  for sIndex in range(0,3):
198  cumValue = 0;
199  for devIndex in range(0,numDev):
200  cumValue += deviceRMS[stateSet][devIndex][sIndex]
201  averageRMS[stateSet][sIndex]=cumValue/numDev
202 
203  # Test Code to overlay average value over heading
204  average = np.zeros(shape=(len(insA[0][stateSet]),1))
205  for dIndex in range(0,len(insA[0][stateSet])):
206  average[dIndex] = averageValues['euler'][dIndex][2]
207  plt.plot(ins[0].v['tow'],average)
208 
209 # if not os.path.exists(os.path.join(directory,'post_processed')):
210 # os.makedirs(os.path.join(directory,'post_processed'))
211 
212  # Convert LLA to NED (m)
213  deviceRMS['ned'] = deviceRMS['lla']
214  for devNum in range(0,numDev):
215  # create lat/lon from initial lat/lon and delta
216  n = len(averageValues['lla'])
217  iLat = averageValues['lla'][int(n/2)][0] * DEG2RAD
218  iLon = averageValues['lla'][int(n/2)][1] * DEG2RAD
219  fLat = iLat + deviceRMS['lla'][devNum][0] * DEG2RAD
220  fLon = iLon
221 
222  dNorth = calculateDistance(iLat,iLon,fLat,fLon)
223 
224  fLat = iLat
225  fLon = iLon + deviceRMS['lla'][devNum][1] * DEG2RAD
226 
227  dEast = calculateDistance(iLat,iLon,fLat,fLon)
228 
229  deviceRMS['ned'][devNum][0] = dNorth
230  deviceRMS['ned'][devNum][1] = dEast
231  deviceRMS['ned'][devNum][2] = -deviceRMS['lla'][devNum][2]
232 
233  n = len(averageValues['lla'])
234  iLat = averageValues['lla'][int(n/2)][0] * DEG2RAD
235  iLon = averageValues['lla'][int(n/2)][1] * DEG2RAD
236  fLat = iLat + averageRMS['lla'][0] * DEG2RAD
237  fLon = iLon
238 
239  dNorth = calculateDistance(iLat,iLon,fLat,fLon)
240 
241  fLat = iLat
242  fLon = iLon + averageRMS['lla'][1] * DEG2RAD
243 
244  dEast = calculateDistance(iLat,iLon,fLat,fLon)
245 
246  averageRMS['ned'] = averageRMS['lla']
247  averageRMS['ned'][0] = dNorth
248  averageRMS['ned'][1] = dEast
249  averageRMS['ned'][2] = -averageRMS['lla'][2]
250 
251  navMode = ins[0].iStatus().navMode[-1]
252 
253  #==================================
254  # Specification and Tolerance
255  tolerance = 0.9
256  specThresh = {}
257  specThresh['ned'] = np.array([0.2,0.2,0.2])
258  specThresh['uvw'] = np.array([0.1,0.1,0.1])
259  specThresh['euler'] = np.array([0.1,0.1,0.0])
260  if navMode: # NAV heading
261  specThresh['euler'][2] = 0.3
262  else: # AHRS heading
263  specThresh['euler'][2] = 2.0
264 
265  specThresh['euler'] = tolerance * specThresh['euler']
266  specThresh['ned'] = tolerance * specThresh['ned']
267  specThresh['uvw'] = tolerance * specThresh['uvw']
268 
269  sigTest = {}
270  sigTest['euler'] = ['NA ','NA ','NA ']
271  sigTest['ned'] = ['NA ','NA ','NA ']
272  sigTest['uvw'] = ['NA ','NA ','NA ']
273  for i in range(3):
274  sigTest['euler'][i] = 'PASS' if averageRMS['euler'][i]*RAD2DEG < specThresh['euler'][i] else 'FAIL'
275  if navMode: # Nav
276  sigTest['ned'][i] = 'PASS' if averageRMS['ned'][i] < specThresh['ned'][i] else 'FAIL'
277  sigTest['uvw'][i] = 'PASS' if averageRMS['uvw'][i] < specThresh['uvw'][i] else 'FAIL'
278 
279  filename = os.path.join(directory,'RMS_report.txt');
280  f = open(filename, 'w')
281  f.write( '***** Performance Analysis Report - %s *****\n' % (subdir))
282  f.write( '\n');
283  f.write( 'Directory: %s\n' % (directory))
284  f.write( '\n');
285 
286  # Print Table of RMS accuracies
287  line = 'Device '
288  if navMode:
289  f.write( '--------------------------------------------------- RMS Accuracy -------------------------------------------\n')
290  line = line + 'UVW[ (m/s) (m/s) (m/s) ], NED[ (m) (m) (m) ],'
291  else: # AHRS mode
292  f.write( '-------------- RMS Accuracy --------------\n')
293  line = line + ' Eul[ (deg) (deg) (deg) ]\n'
294  f.write(line)
295 
296  for n in range(0,numDev):
297  devInfo = itd.cDevInfo(log.devices[n].data['devInfo'])
298  line = '%2d SN%d ' % (n, devInfo.v['serialNumber'][-1])
299  if navMode:
300  line = line + '[%7.4f %7.4f %7.4f ], ' % (deviceRMS['uvw'][n][0],deviceRMS['uvw'][n][1],deviceRMS['uvw'][n][2])
301  line = line + '[%7.4f %7.4f %7.4f ], ' % (deviceRMS['ned'][n][0],deviceRMS['ned'][n][1],deviceRMS['ned'][n][2])
302  line = line + '[%7.4f %7.4f %7.4f ]\n' % (deviceRMS['euler'][n][0]*RAD2DEG,deviceRMS['euler'][n][1]*RAD2DEG,deviceRMS['euler'][n][2]*RAD2DEG)
303  f.write(line)
304 
305  line = 'AVERAGE: '
306  if navMode:
307  f.write( '------------------------------------------------------------------------------------------------------------\n')
308  line = line + '[%7.4f %7.4f %7.4f ], ' % (averageRMS['uvw'][0],averageRMS['uvw'][1],averageRMS['uvw'][2])
309  line = line + '[%7.4f %7.4f %7.4f ], ' % (averageRMS['ned'][0],averageRMS['ned'][1],averageRMS['ned'][2])
310  else: # AHRS mode
311  f.write( '------------------------------------------\n')
312  line = line + '[%7.4f %7.4f %7.4f ]\n' % (averageRMS['euler'][0]*RAD2DEG,averageRMS['euler'][1]*RAD2DEG,averageRMS['euler'][2]*RAD2DEG)
313  f.write(line)
314 
315  line = 'THRESHOLD: '
316  if navMode:
317  line = line + '[%7.4f %7.4f %7.4f ], ' % (specThresh['uvw'][0],specThresh['uvw'][1],specThresh['uvw'][2])
318  line = line + '[%7.4f %7.4f %7.4f ], ' % (specThresh['ned'][0],specThresh['ned'][1],specThresh['ned'][2])
319  line = line + '[%7.4f %7.4f %7.4f ]\n' % (specThresh['euler'][0],specThresh['euler'][1],specThresh['euler'][2])
320  f.write(line)
321 
322  line = 'PASS/FAIL: '
323  if navMode:
324  line = line + '[ %s %s %s ], ' % (sigTest['uvw'][0],sigTest['uvw'][1],sigTest['uvw'][2])
325  line = line + '[ %s %s %s ], ' % (sigTest['ned'][0],sigTest['ned'][1],sigTest['ned'][2])
326  line = line + '[ %s %s %s ]\n' % (sigTest['euler'][0],sigTest['euler'][1],sigTest['euler'][2])
327  f.write(line)
328 
329  if navMode:
330  f.write(' ')
331  else: # AHRS mode
332  f.write(' ')
333  f.write('(NAV mode)\n\n' if ins[0].iStatus().navMode[-1] else '(AHRS mode)\n\n')
334 
335  # Print Mounting Biases
336  f.write( '--------------- Angular Mounting Biases ----------------\n')
337  f.write( 'Device Euler Biases[ (deg) (deg) (deg) ]\n')
338  for n in range(0,numDev):
339  devInfo = itd.cDevInfo(log.devices[n].data['devInfo'])
340  f.write('%2d SN%d [ %7.4f %7.4f %7.4f ]\n' % (n, devInfo.v['serialNumber'][-1],bias['euler'][n][0]*RAD2DEG,bias['euler'][n][1]*RAD2DEG,bias['euler'][n][2]*RAD2DEG))
341  f.write('\n')
342 
343  # Print Device Version Information
344  f.write( '------------------------------------------- Device Info -------------------------------------------------\n')
345  for n in range(0,numDev):
346  devInfo = itd.cDevInfo(log.devices[n].data['devInfo'])
347  hver = devInfo.v['hardwareVer'][-1]
348  cver = devInfo.v['commVer'][-1]
349  fver = devInfo.v['firmwareVer'][-1]
350  buld = devInfo.v['build'][-1]
351  repo = devInfo.v['repoRevision'][-1]
352  date = devInfo.v['buildDate'][-1]
353  time = devInfo.v['buildTime'][-1]
354  addi = devInfo.v['addInfo'][-1]
355  f.write('%2d SN%d HW: %d.%d.%d.%d FW: %d.%d.%d.%d build %d repo %d Proto: %d.%d.%d.%d Date: %04d-%02d-%02d %02d:%02d:%02d %s\n' %(
356  n, devInfo.v['serialNumber'][-1],
357  hver[3], hver[2], hver[1], hver[0],
358  fver[3], fver[2], fver[1], fver[0], buld, repo,
359  cver[3], cver[2], cver[1], cver[0],
360  2000+date[2], date[1], date[0],
361  time[3], time[2], time[1],
362  addi ) )
363  f.write('\n')
364 
365  f.close()
366 
367  # Automatically open report in Windows
368  if 'win' in sys.platform:
369  subprocess.Popen(["notepad.exe", filename]) # non-blocking call
370  else:
371  subprocess.Popen(["gedit", filename]) # non-blocking call
372 
373 
374  print("Done.")
375 
376  # TODO: Pass out the union of the test errors
377  return averageRMS
378 
def calculateDistance(lat1, lon1, lat2, lon2)
GeneratorWrapper< T > range(T const &start, T const &end, T const &step)
Definition: catch.hpp:4141
#define max(a, b)
Takes the maximal value of a and b.
Definition: compiler.h:823
def computeRmsAccuracies(log, directory, subdir)
def shiftTime(tow, dataSet, time)


inertial_sense_ros
Author(s):
autogenerated on Sun Feb 28 2021 03:17:57