TrackFileReader { @NonNull private List<MLocation> parse(@NonNull BufferedReader br) throws IOException { final Filter baroAltitudeFilter = new FilterKalman(); final Filter gpsAltitudeFilter = new FilterKalman(); long baroLastNano = -1L; long gpsLastMillis = -1L; boolean initAltGps = false; boolean initAltBaro = false; double baroOffset = 0; final List<MLocation> data = new ArrayList<>(); String line = br.readLine(); final CSVHeader columns = new CSVHeader(line); columns.addMapping("timeMillis", "millis"); columns.addMapping("latitude", "lat"); columns.addMapping("longitude", "lon"); columns.addMapping("altitude_gps", "hMSL"); while ((line = br.readLine()) != null) { final String[] row = line.split(","); final Integer sensorIndex = columns.get("sensor"); if (sensorIndex == null || sensorIndex >= row.length) { final long millis = getColumnDate(row, columns, "time"); if (millis > 0) { final double lat = getColumnDouble(row, columns, "lat"); final double lon = getColumnDouble(row, columns, "lon"); final double alt_gps = getColumnDouble(row, columns, "hMSL"); final double climb = -getColumnDouble(row, columns, "velD"); final double vN = getColumnDouble(row, columns, "velN"); final double vE = getColumnDouble(row, columns, "velE"); if (!Double.isNaN(lat) && !Double.isNaN(lon)) { final MLocation loc = new MLocation(millis, lat, lon, alt_gps, climb, vN, vE, Float.NaN, Float.NaN, Float.NaN, Float.NaN, 0, 0); data.add(loc); } } } else if (row[sensorIndex].equals("gps")) { final long millis = getColumnLong(row, columns, "millis"); final double lat = getColumnDouble(row, columns, "lat"); final double lon = getColumnDouble(row, columns, "lon"); final double alt_gps = getColumnDouble(row, columns, "hMSL"); final double vN = getColumnDouble(row, columns, "velN"); final double vE = getColumnDouble(row, columns, "velE"); if (gpsLastMillis < 0) { gpsAltitudeFilter.update(alt_gps, 0); } else { final double dt = (millis - gpsLastMillis) * 0.001; gpsAltitudeFilter.update(alt_gps, dt); } if (!Double.isNaN(alt_gps)) { if (initAltBaro && !initAltGps) { baroOffset = alt_gps - baroAltitudeFilter.x(); } } double integratedAlt; if (initAltBaro && initAltGps) { integratedAlt = baroAltitudeFilter.x() + baroOffset; } else { integratedAlt = alt_gps; } double climb = baroAltitudeFilter.v(); if (baroLastNano < 0 || Double.isNaN(climb)) { climb = gpsAltitudeFilter.v(); } if (!Double.isNaN(lat) && !Double.isNaN(lon)) { final MLocation loc = new MLocation(millis, lat, lon, integratedAlt, climb, vN, vE, Float.NaN, Float.NaN, Float.NaN, Float.NaN, 0, 0); data.add(loc); } gpsLastMillis = millis; initAltGps = true; } else if (row[sensorIndex].equals("alt")) { final long nano = getColumnLong(row, columns, "nano"); final double pressure = getColumnDouble(row, columns, "pressure"); final double pressureAltitude = BaroAltimeter.pressureToAltitude(pressure); if (baroLastNano < 0) { baroAltitudeFilter.update(pressureAltitude, 0); } else { final double dt = (nano - baroLastNano) * 1E-9; baroAltitudeFilter.update(pressureAltitude, dt); } if (!initAltBaro && initAltGps) { baroOffset = gpsAltitudeFilter.x() - baroAltitudeFilter.x(); } baroLastNano = nano; initAltBaro = true; } } return data; } TrackFileReader(@NonNull File trackFile);   }
@Test public void corrupted() throws IOException { assertEquals(1, parse("millis,sensor,lat,lon,alt\n1,gps,2,3,4\n5,").size()); assertEquals(1, parse("millis,sensor,lat,lon,alt\n1,gps,2,3,NOPE").size()); assertEquals(0, parse("millis,sensor,lat,lon,alt\n1,gps,2,NOPE").size()); assertEquals(0, parse("time,lat,lon,alt\nNOPE,2,3,4").size()); }