def test_interpolate_gps(self): est_lat, est_lon = interpolate_gps(timestamps=masked_epoch(self.df.t), latitude=self.df.y, longitude=self.df.x) assert len(est_lat) == len(est_lon) assert len(est_lat) == self.df.y.size assert len(est_lon) == self.df.x.size
def test_density(self): sr = SlocumReader(ctd_filepath) df = sr.standardize() salinity = calculate_practical_salinity( sr.data.sci_water_cond, sr.data.sci_water_temp, sr.data.sci_water_pressure, ) assert sr.data.sci_m_present_time.size == salinity.size est_lat, est_lon = interpolate_gps(timestamps=masked_epoch(df.t), latitude=df.y, longitude=df.x) density = calculate_density(sr.data.sci_water_temp, sr.data.sci_water_pressure, salinity, est_lat, est_lon) assert sr.data.sci_m_present_time.size == density.size
def standardize(self, gps_prefix=None): df = self.data.copy() # Convert NMEA coordinates to decimal degrees for col in df.columns: # Ignore if the m_gps_lat and/or m_gps_lon value is the default masterdata value if col.endswith('_lat'): df[col] = df[col].map(lambda x: get_decimal_degrees(x) if x <= 9000 else np.nan) elif col.endswith('_lon'): df[col] = df[col].map(lambda x: get_decimal_degrees(x) if x < 18000 else np.nan) # Standardize 'time' to the 't' column for t in self.TIMESTAMP_SENSORS: if t in df.columns: df['t'] = pd.to_datetime(df[t], unit='s') break # Interpolate GPS coordinates if 'm_gps_lat' in df.columns and 'm_gps_lon' in df.columns: df['drv_m_gps_lat'] = df.m_gps_lat.copy() df['drv_m_gps_lon'] = df.m_gps_lon.copy() # Fill in data will nulls where value is the default masterdata value masterdatas = (df.drv_m_gps_lon >= 18000) | (df.drv_m_gps_lat > 9000) df.loc[masterdatas, 'drv_m_gps_lat'] = np.nan df.loc[masterdatas, 'drv_m_gps_lon'] = np.nan try: # Interpolate the filled in 'x' and 'y' y_interp, x_interp = interpolate_gps(masked_epoch(df.t), df.drv_m_gps_lat, df.drv_m_gps_lon) except (ValueError, IndexError): L.warning("Raw GPS values not found!") y_interp = np.empty(df.drv_m_gps_lat.size) * np.nan x_interp = np.empty(df.drv_m_gps_lon.size) * np.nan df['y'] = y_interp df['x'] = x_interp """ ---- Option 1: Always calculate Z from pressure ---- It's really a matter of data provider preference and varies from one provider to another. That being said, typically the sci_water_pressure or m_water_pressure variables, if present in the raw data files, will typically have more non-NaN values than m_depth. For example, all MARACOOS gliders typically have both m_depth and sci_water_pressure contained in them. However, m_depth is typically heavily decimated while sci_water_pressure contains a more complete pressure record. So, while we transmit both m_depth and sci_water_pressure, I calculate depth from pressure & (interpolated) latitude and use that as my NetCDF depth variable. - Kerfoot """ # Search for a 'pressure' column for p in self.PRESSURE_SENSORS: if p in df.columns: # Convert bar to dbar here df['pressure'] = df[p].copy() * 10 # Calculate depth from pressure and latitude # Negate the results so that increasing values note increasing depths df['z'] = -z_from_p(df.pressure, df.y) break if 'z' not in df and 'pressure' not in df: # Search for a 'z' column for p in self.DEPTH_SENSORS: if p in df.columns: df['z'] = df[p].copy() # Calculate pressure from depth and latitude # Negate the results so that increasing values note increasing depth df['pressure'] = -p_from_z(df.z, df.y) break # End Option 1 """ ---- Option 2: Use raw pressure/depth data that was sent across ---- # Standardize to the 'pressure' column for p in self.PRESSURE_SENSORS: if p in df.columns: # Convert bar to dbar here df['pressure'] = df[p].copy() * 10 break # Standardize to the 'z' column for p in self.DEPTH_SENSORS: if p in df.columns: df['z'] = df[p].copy() break # Don't calculate Z from pressure if a metered depth column exists already if 'pressure' in df and 'z' not in df: # Calculate depth from pressure and latitude # Negate the results so that increasing values note increasing depths df['z'] = -z_from_p(df.pressure, df.y) if 'z' in df and 'pressure' not in df: # Calculate pressure from depth and latitude # Negate the results so that increasing values note increasing depth df['pressure'] = -p_from_z(df.z, df.y) # End Option 2 """ rename_columns = { 'm_water_vx': 'u_orig', 'm_water_vy': 'v_orig', } # These need to be standardize so we can compute salinity and density! for vname in self.TEMPERATURE_SENSORS: if vname in df.columns: rename_columns[vname] = 'temperature' break for vname in self.CONDUCTIVITY_SENSORS: if vname in df.columns: rename_columns[vname] = 'conductivity' break # Standardize columns df = df.rename(columns=rename_columns) # Compute additional columns df = self.compute(df) return df