mirror of
https://github.com/PAMGuard/PAMGuard.git
synced 2024-11-21 22:52:22 +00:00
Merge branch 'main' of https://github.com/douggillespie/PAMGuardTethys
This commit is contained in:
commit
8842166f43
@ -473,8 +473,7 @@ final public class PamModel implements PamModelInterface, PamSettings {
|
||||
mi.setToolTipText("Interface to Tethys Database");
|
||||
mi.setModulesMenuGroup(utilitiesGroup);
|
||||
mi.setMaxNumber(1);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
|
@ -551,6 +551,71 @@ public abstract class SQLLogging {
|
||||
// }
|
||||
return resultSet;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the data point which is closest in time to that given, or null
|
||||
* returning whatever type of data unit this deals with.
|
||||
* @param timeMillis
|
||||
* @return
|
||||
*/
|
||||
public PamDataUnit findClosestDataPoint(PamConnection con, long timeMillis) {
|
||||
|
||||
PamCursor pamCursor = loggingCursorFinder.getCursor(con, pamTableDefinition);
|
||||
|
||||
// can't really do any math with the string based dates, so will have to query from
|
||||
// a few s before the time we want.
|
||||
PamDataUnit[] beforeNafter = new PamDataUnit[2];
|
||||
|
||||
SQLTypes sqlTypes = con.getSqlTypes();
|
||||
|
||||
for (int i = 0; i < 2; i++) {
|
||||
String clause;
|
||||
|
||||
if (i == 0) {
|
||||
clause = String.format("WHERE UTC <= %s ORDER BY UTC DESC", sqlTypes.formatDBDateTimeQueryString(timeMillis));
|
||||
}
|
||||
else {
|
||||
clause = String.format("WHERE UTC >= %s ORDER BY UTC ASC", sqlTypes.formatDBDateTimeQueryString(timeMillis));
|
||||
}
|
||||
|
||||
ResultSet result = pamCursor.openReadOnlyCursor(con, clause);
|
||||
if (result==null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
PamTableItem tableItem;
|
||||
try {
|
||||
if (result.next()) {
|
||||
// for (int i = 0; i < pamTableDefinition.getTableItemCount(); i++) {
|
||||
// tableItem = pamTableDefinition.getTableItem(i);
|
||||
// tableItem.setValue(result.getObject(i + 1));
|
||||
// }
|
||||
// return true;
|
||||
boolean ok = transferDataFromResult(con.getSqlTypes(), result);
|
||||
result.close();
|
||||
beforeNafter[i] = createDataUnit(sqlTypes, lastTime, lastLoadIndex);
|
||||
}
|
||||
} catch (SQLException ex) {
|
||||
ex.printStackTrace();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
// now pick the closest
|
||||
if (beforeNafter[0] == null) {
|
||||
return beforeNafter[1];
|
||||
}
|
||||
if (beforeNafter[1] == null) {
|
||||
return beforeNafter[0];
|
||||
}
|
||||
long t1 = timeMillis-beforeNafter[0].getTimeMilliseconds();
|
||||
long t2 = beforeNafter[1].getTimeMilliseconds()-timeMillis;
|
||||
if (t1 < t2) {
|
||||
return beforeNafter[0];
|
||||
}
|
||||
else {
|
||||
return beforeNafter[1];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a new database is connected to read the last values back in
|
||||
|
85
src/tethys/TethysLocationFuncs.java
Normal file
85
src/tethys/TethysLocationFuncs.java
Normal file
@ -0,0 +1,85 @@
|
||||
package tethys;
|
||||
|
||||
import Array.ArrayManager;
|
||||
import Array.HydrophoneLocator;
|
||||
import Array.PamArray;
|
||||
import Array.Streamer;
|
||||
import GPS.GPSControl;
|
||||
import GPS.GpsData;
|
||||
import GPS.GpsDataUnit;
|
||||
import PamUtils.LatLong;
|
||||
import PamUtils.PamUtils;
|
||||
import PamguardMVC.PamDataUnit;
|
||||
import generalDatabase.DBControlUnit;
|
||||
import generalDatabase.PamConnection;
|
||||
import nilus.Deployment;
|
||||
import nilus.DeploymentRecoveryDetails;
|
||||
|
||||
/**
|
||||
* Function(s) to get location information for Tethys in the required format.
|
||||
* @author dg50
|
||||
*
|
||||
*/
|
||||
public class TethysLocationFuncs {
|
||||
|
||||
|
||||
/**
|
||||
* Get everything we need for a deployment document including the track #
|
||||
* and the deployment / recovery information. Basically this means we
|
||||
* have to load the GPS data, then potentially filter it. Slight risk this
|
||||
* may all be too much for memory, but give it a go by loading GPS data for
|
||||
* the deployment times.
|
||||
* @param deployment
|
||||
*/
|
||||
public static void getTrackAndPositionData(Deployment deployment) {
|
||||
long start = TethysTimeFuncs.millisFromGregorianXML(deployment.getDeploymentDetails().getAudioTimeStamp());
|
||||
long end = TethysTimeFuncs.millisFromGregorianXML(deployment.getRecoveryDetails().getAudioTimeStamp());
|
||||
/*
|
||||
* Need to load data for GPS, Hydrophones and Streamers datablocks for this time period. Can then use
|
||||
* the snapshot geomentry classes to do the rest from the array manager ?
|
||||
*/
|
||||
boolean ok = true;
|
||||
ok &= addPositionData(deployment.getDeploymentDetails());
|
||||
ok &= addPositionData(deployment.getRecoveryDetails());
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Add position data to DeploymentRecoveryDetails.
|
||||
* @param drd
|
||||
* @return
|
||||
*/
|
||||
public static boolean addPositionData(DeploymentRecoveryDetails drd) {
|
||||
long timeMillis = TethysTimeFuncs.millisFromGregorianXML(drd.getAudioTimeStamp());
|
||||
LatLong pos = getLatLongData(timeMillis);
|
||||
if (pos == null) {
|
||||
return false;
|
||||
}
|
||||
drd.setLongitude(PamUtils.constrainedAngle(pos.getLongitude(), 360));
|
||||
drd.setLatitude(pos.getLatitude());
|
||||
drd.setElevationInstrumentM(pos.getHeight());
|
||||
drd.setDepthInstrumentM(-pos.getHeight());
|
||||
return true;
|
||||
}
|
||||
|
||||
public static LatLong getLatLongData(long timeMillis) {
|
||||
// check the array time.
|
||||
PamArray array = ArrayManager.getArrayManager().getCurrentArray();
|
||||
Streamer aStreamer = array.getStreamer(0);
|
||||
GPSControl gpsControl = GPSControl.getGpsControl();
|
||||
PamConnection con = DBControlUnit.findConnection();
|
||||
if (gpsControl != null) {
|
||||
// check GPS data are loaded for times around this.
|
||||
GpsDataUnit gpsData = (GpsDataUnit) gpsControl.getGpsDataBlock().getLogging().findClosestDataPoint(con, timeMillis);
|
||||
if (gpsData != null) {
|
||||
return gpsData.getGpsData();
|
||||
}
|
||||
}
|
||||
HydrophoneLocator hydrophoneLocator = aStreamer.getHydrophoneLocator();
|
||||
if (hydrophoneLocator == null) {
|
||||
return null;
|
||||
}
|
||||
return hydrophoneLocator.getStreamerLatLong(timeMillis);
|
||||
}
|
||||
|
||||
}
|
39
src/tethys/TethysTimeFuncs.java
Normal file
39
src/tethys/TethysTimeFuncs.java
Normal file
@ -0,0 +1,39 @@
|
||||
package tethys;
|
||||
|
||||
import java.util.GregorianCalendar;
|
||||
|
||||
import javax.xml.datatype.DatatypeConfigurationException;
|
||||
import javax.xml.datatype.DatatypeFactory;
|
||||
import javax.xml.datatype.XMLGregorianCalendar;
|
||||
|
||||
public class TethysTimeFuncs {
|
||||
|
||||
/*
|
||||
* Copied from http://www.java2s.com/Code/Java/Development-Class/ConvertsagiventimeinmillisecondsintoaXMLGregorianCalendarobject.htm
|
||||
*/
|
||||
public static XMLGregorianCalendar xmlGregCalFromMillis(long millis) {
|
||||
try {
|
||||
final GregorianCalendar calendar = new GregorianCalendar();
|
||||
calendar.setTimeInMillis(millis);
|
||||
return DatatypeFactory.newInstance().newXMLGregorianCalendar(
|
||||
calendar);
|
||||
}
|
||||
catch (final DatatypeConfigurationException ex) {
|
||||
System.out.println("Unable to convert date '%s' to an XMLGregorianCalendar object");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a Gregorian calendar value back to milliseconds.
|
||||
* @param xmlGregorian
|
||||
* @return
|
||||
*/
|
||||
public static Long millisFromGregorianXML(XMLGregorianCalendar xmlGregorian) {
|
||||
if (xmlGregorian == null) {
|
||||
return null;
|
||||
}
|
||||
GregorianCalendar gc2 = xmlGregorian.toGregorianCalendar();
|
||||
return gc2.getTimeInMillis();
|
||||
}
|
||||
}
|
@ -37,8 +37,11 @@ import generalDatabase.DBSchemaWriter;
|
||||
import generalDatabase.SQLLogging;
|
||||
import metadata.MetaDataContol;
|
||||
import metadata.deployment.DeploymentData;
|
||||
import nilus.Deployment;
|
||||
import nilus.DeploymentRecoveryDetails;
|
||||
import tethys.TethysControl;
|
||||
import tethys.TethysLocationFuncs;
|
||||
import tethys.TethysTimeFuncs;
|
||||
import tethys.dbxml.DBXMLConnect;
|
||||
import tethys.pamdata.TethysDataProvider;
|
||||
import tethys.pamdata.TethysSchema;
|
||||
@ -145,77 +148,83 @@ public class TethysExporter {
|
||||
/*
|
||||
* A load of notes Katie put in ....654654654
|
||||
*/
|
||||
// 1. grab DeploymentRecoveryPair that has deployment details and recovery
|
||||
// details
|
||||
// a. this is based on start and end times
|
||||
// Douglas calculates out dutycycles to only grab the
|
||||
|
||||
// 2. loop through the pairs to populate the extra information
|
||||
// one pair is one deployment
|
||||
// see below for matching
|
||||
|
||||
// id => unique
|
||||
// project => project in pamguard
|
||||
// deploymentId == id
|
||||
// deploymentAlias => blank
|
||||
// site => UI addition in pamguard, not done, can be blank
|
||||
// siteAlias => blank
|
||||
// cruise => UI addition, optional
|
||||
// Platform=> UI addition in pamguard
|
||||
// region => UI addition
|
||||
// Instrument/Type => UI, array manager details (hydrophone names area)
|
||||
// Instrument/Id => UI, array manager details
|
||||
// Instrument/Geometry => in pamguard array manager
|
||||
// SamplingDetails/Channel
|
||||
// ChannelNumber => in pamguard, hyrdrophone array
|
||||
// SensorNumber => in pamguard,
|
||||
// Start => same as timestamp deployment detail
|
||||
// End => same as timestamp recovery detail
|
||||
// Sampling/Regimen (change sample rate, pamgauard doesnt handle, only on, get
|
||||
// channel info in that loop)
|
||||
// TimeStamp => start time
|
||||
// SampleRate_kHz =>
|
||||
// SampleBits =>
|
||||
// Gain (another func call to get gain info)
|
||||
// DutyCycles => needs to be calculated, not fields in pamguard, have fun
|
||||
// Douglas
|
||||
// QualityAssurance => not in pamguard, UI, maybe deployment notes, optional
|
||||
// Data/Audio (static)
|
||||
// URI => folder where audio is saved
|
||||
// Data/Tracks
|
||||
// Track => GPS datatable (granularity filter)
|
||||
// TrackId => not unique between deployments,
|
||||
// TrackEffort
|
||||
// OnPath => scattered throughout pamguard
|
||||
// URI => option, check with Shannon on how they are doing deployments
|
||||
// Sensors/Audio (per hydrophone not quad array) streamer info + individual
|
||||
// hydrophone data together
|
||||
// pamguard hydrophone data
|
||||
// number => hydrophoneId
|
||||
// sensorId => sensor serial number
|
||||
// Geometry => array geometry field goes to
|
||||
// Sensors/Depth
|
||||
// optional
|
||||
// Sensors/Sensor
|
||||
// Number => hydrophoneId in pamguard
|
||||
// SensorId => addition to UI
|
||||
// Geometry => array geometry fields
|
||||
// Type => Hydrophone Type
|
||||
|
||||
// get list of deployment recovery details (start, stop times and lat/long)
|
||||
// deployment details and recovery details are same structure
|
||||
// per pair, go through a loop to fill in each deployment
|
||||
// ArrayList<DeploymentRecoveryPair> deployRecover = getSamplingDetails();
|
||||
// if (deployRecover == null) {
|
||||
// return false;
|
||||
// }
|
||||
//
|
||||
// for (DeploymentRecoveryPair drd : deployRecover) {
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
// }
|
||||
//1. grab DeploymentRecoveryPair that has deployment details and recovery details
|
||||
//a. this is based on start and end times
|
||||
//Douglas calculates out dutycycles to only grab the
|
||||
|
||||
//2. loop through the pairs to populate the extra information
|
||||
//one pair is one deployment
|
||||
//see below for matching
|
||||
|
||||
|
||||
//id => unique
|
||||
//project => project in pamguard
|
||||
//deploymentId == id
|
||||
//deploymentAlias => blank
|
||||
//site => UI addition in pamguard, not done, can be blank
|
||||
//siteAlias => blank
|
||||
//cruise => UI addition, optional
|
||||
//Platform=> UI addition in pamguard
|
||||
//region => UI addition
|
||||
//Instrument/Type => UI, array manager details (hydrophone names area)
|
||||
//Instrument/Id => UI, array manager details
|
||||
//Instrument/Geometry => in pamguard array manager
|
||||
//SamplingDetails/Channel
|
||||
//ChannelNumber => in pamguard, hyrdrophone array
|
||||
//SensorNumber => in pamguard,
|
||||
//Start => same as timestamp deployment detail
|
||||
//End => same as timestamp recovery detail
|
||||
//Sampling/Regimen (change sample rate, pamgauard doesnt handle, only on, get channel info in that loop)
|
||||
//TimeStamp => start time
|
||||
//SampleRate_kHz =>
|
||||
//SampleBits =>
|
||||
//Gain (another func call to get gain info)
|
||||
//DutyCycles => needs to be calculated, not fields in pamguard, have fun Douglas
|
||||
//QualityAssurance => not in pamguard, UI, maybe deployment notes, optional
|
||||
//Data/Audio (static)
|
||||
//URI => folder where audio is saved
|
||||
//Data/Tracks
|
||||
//Track => GPS datatable (granularity filter)
|
||||
//TrackId => not unique between deployments,
|
||||
//TrackEffort
|
||||
//OnPath => scattered throughout pamguard
|
||||
//URI => option, check with Shannon on how they are doing deployments
|
||||
//Sensors/Audio (per hydrophone not quad array) streamer info + individual hydrophone data together
|
||||
//pamguard hydrophone data
|
||||
//number => hydrophoneId
|
||||
//sensorId => sensor serial number
|
||||
//Geometry => array geometry field goes to
|
||||
//Sensors/Depth
|
||||
//optional
|
||||
//Sensors/Sensor
|
||||
//Number => hydrophoneId in pamguard
|
||||
//SensorId => addition to UI
|
||||
//Geometry => array geometry fields
|
||||
//Type => Hydrophone Type
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//get list of deployment recovery details (start, stop times and lat/long)
|
||||
//deployment details and recovery details are same structure
|
||||
//per pair, go through a loop to fill in each deployment
|
||||
ArrayList<DeploymentRecoveryPair> deployRecover = getSamplingDetails();
|
||||
if (deployRecover == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* This will become the main loop over deployment documents
|
||||
*/
|
||||
int i = 0;
|
||||
for (DeploymentRecoveryPair drd : deployRecover) {
|
||||
|
||||
Deployment deployment = createDeploymentDocument(i++, drd);
|
||||
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Call some general export function
|
||||
@ -241,6 +250,18 @@ public class TethysExporter {
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private Deployment createDeploymentDocument(int i, DeploymentRecoveryPair drd) {
|
||||
Deployment deployment = new Deployment();
|
||||
deployment.setDeploymentDetails(drd.deploymentDetails);
|
||||
deployment.setRecoveryDetails(drd.recoveryDetails);
|
||||
|
||||
TethysLocationFuncs.getTrackAndPositionData(deployment);
|
||||
|
||||
|
||||
|
||||
return deployment;
|
||||
}
|
||||
|
||||
/**
|
||||
* find Deployment data. This is stored in a separate PAMGuard module, which may
|
||||
@ -348,9 +369,9 @@ public class TethysExporter {
|
||||
// just load everything. Probably OK for the acqusition, but will bring down
|
||||
daqInfoDataBlock.loadViewerData(0, Long.MAX_VALUE, null);
|
||||
ArrayList<DaqStatusDataUnit> allStatusData = daqInfoDataBlock.getDataCopy();
|
||||
long dataStart = Long.MAX_VALUE;
|
||||
long dataEnd = Long.MIN_VALUE;
|
||||
if (allStatusData != null && allStatusData.size() > 0) {
|
||||
long dataStart = Long.MAX_VALUE;
|
||||
long dataEnd = Long.MIN_VALUE;
|
||||
// find the number of times it started and stopped ....
|
||||
int nStart = 0, nStop = 0, nFile = 0;
|
||||
for (DaqStatusDataUnit daqStatus : allStatusData) {
|
||||
@ -392,8 +413,22 @@ public class TethysExporter {
|
||||
//// for ()
|
||||
// }
|
||||
|
||||
return null;
|
||||
|
||||
DeploymentRecoveryPair pair = new DeploymentRecoveryPair();
|
||||
DeploymentRecoveryDetails deployment = new DeploymentRecoveryDetails();
|
||||
DeploymentRecoveryDetails recovery = new DeploymentRecoveryDetails();
|
||||
pair.deploymentDetails = deployment;
|
||||
pair.recoveryDetails = recovery;
|
||||
|
||||
deployment.setTimeStamp(TethysTimeFuncs.xmlGregCalFromMillis(dataStart));
|
||||
deployment.setAudioTimeStamp(TethysTimeFuncs.xmlGregCalFromMillis(dataStart));
|
||||
recovery.setTimeStamp(TethysTimeFuncs.xmlGregCalFromMillis(dataEnd));
|
||||
recovery.setAudioTimeStamp(TethysTimeFuncs.xmlGregCalFromMillis(dataEnd));
|
||||
|
||||
ArrayList<DeploymentRecoveryPair> drPairs = new ArrayList<>();
|
||||
drPairs.add(pair);
|
||||
return drPairs;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
Loading…
Reference in New Issue
Block a user