📄 waveform.java
字号:
* root from the database and checks that is can be reached. Needs a
* DataSource open connection.
*/
public boolean filesAreLocal()
{
String root = getFileRoot();
if (root == null) return false;
// System.out.println ("root: "+root);
// check existance
File file = new File(root);
// System.out.println ("file: "+file.toString());
return file.isDirectory();
}
/** Returns true if this Waveform is accessible through some transport
* method. */
/* DEPRECATED
public abstract boolean isAccessible () ;
*/
/**
* Return the generic waveform file root. Access to this path is tested
* to determine if files can be read locally.
*/
protected abstract String getFileRoot();
/**
* Return the waveform file root for a particular event id.
* Access to this path is tested
* to determine if files can be read locally.
*/
protected abstract String getFileRoot(long eventId);
/**
* Create AssocWaE record for existing WaveForm and pointing at this Solution.
* The underlying stored procedure commits, so you don't have to.
* */
public abstract boolean commit (Solution sol);
/**
* Load the time series data for this Waveform. This is done as a separate step
* because it is often more efficient to only load selected waveforms after
* you have examined or sorted the Waveform objects by their header info.<p>
*
* The waveform is collapsed into the minimum number of WFSegments possible. More
* then one WFSegment would only be necessary if there are time tears. The start-stop
* times of the original data packets is preserved in the packetSpans array.<p>
*
* Fires ChangeEvents when the time-series is loaded so that time-series can be
* loaded asynchronously (in background thread) then notify a graphics object when
* loading is complete. <p>
*
* This method must synchronize on the waveform object for thread safty. Simply
* synchronizing the method is not enough.
*/
public abstract boolean loadTimeSeries() ;
public abstract boolean loadTimeSeries(double startTime, double endTime) ;
/**
* Delete the time series for this waveform and allow the GC to reclaim
* the memory space. This is used to manage memory and prevent overflows. */
public boolean unloadTimeSeries() {
synchronized (this) {
segList = new ArrayList() ;
packetSpans = null;
}
return true;
}
/** Reduce waveform to the minimum possible number of WFSegments. Preserve
* WFSegment boundaries in packetSpans array. */
public void collapse() {
// save the original packet timeSpans so we can plot packet boundaries later
// also detects time tears
WFSegment seg[] = WFSegment.getArray(getSegmentList());
packetSpans = new TimeSpan[seg.length];
// scan original packets to preserve pack boundaries for later display
for (int i=0; i < seg.length; i++) {
packetSpans[i] = new TimeSpan(seg[i].getEpochStart(),
seg[i].getEpochEnd());
}
// collapse multiple segements into minimum possible
setSegmentList(WFSegment.collapse(getSegmentList()));
}
/** Return true if there are actual samples (time-series) loaded for this
waveform. */
public boolean hasTimeSeries() {
if (segList.size() == 0) return false;
return true;
}
/**
* Convert this Collection of WFSegments to an Array of WFSegments.
*/
public WFSegment[] getArray() {
if (segList.size() == 0) return (null); // no segments
WFSegment segArray[] = new WFSegment[segList.size()];
return (WFSegment[]) segList.toArray(segArray);
}
/**
* Return total samples in memory for this Waveform. Note that they may not
* be contiguous.
*/
public int samplesInMemory() {
if (!hasTimeSeries()) { return 0; } // no time series
int k = 0;
WFSegment seg[] = WFSegment.getArray(segList);
for (int i=0; i < seg.length; i++) {
k += seg[i].ts.length;
}
return k;
}
/** Return the units of the amplitude dimension of this Waveform.
@See: Units */
public int getAmpUnits() {
return ampUnits;
}
/** Set the units of the amplitude dimension of this Waveform.
@See: Units */
public void setAmpUnits(int units) {
if (Units.isLegal(units)) ampUnits = units;
}
/** Set the units of the amplitude dimension of this Waveform.
@See: Units */
public void setAmpUnits(String units) {
ampUnits = Units.getInt(units);
}
/** Return the Sample Interval (secs) for this Waveform */
public double getSampleInterval() {
if (samplesPerSecond.isNull()) return 0;
return 1.0/samplesPerSecond.doubleValue(); //Samp/sec -> sec/Samp
}
/**
* Return the time of where the sample closest to the given time would be.
* NOTE: there may be no sample there if there is a time tear or the time is beyond
* either end of the data! Times are raw epoch seconds.
* If there is no time series the original time is returned.
*/
public double closestSampleInterval(double dtime) {
if (!hasTimeSeries()) { return dtime; } // no time series
double dt0 = timeStart.doubleValue();
double sps = samplesPerSecond.doubleValue();
// integral number of samples to from startTime to dtime
double nsamps = Math.rint((dtime - dt0) * sps);
// offset in sec's to that sample
return dt0 + (nsamps / sps);
}
/**
* Calculate the bias of this waveform by examining all waveform segments.
* Sets bias = 0.0 if there is no time-series.
* For efficiency this should only be called the first time a time-series
* is loaded.
*/
public void scanForBias () {
synchronized (this) {
if (!hasTimeSeries()) {
biasVal = 0.0f;
return;
} // no time series
double sum = 0.0;
double totalSamples = 0.0;
WFSegment seg[] = WFSegment.getArray(segList);
//Segments aren't equal in length :. weight the bias by sample count
for (int i=0; i < seg.length; i++) {
sum += seg[i].getBias() * seg[i].ts.length;
totalSamples += seg[i].ts.length;
}
biasVal = (float) (sum / totalSamples);
} // end of synch
} // end of bias
/** Remove the bias from this time series in place. */
public void demean() {
if (!hasTimeSeries()) return;
scanForBias();
WFSegment seg[] = WFSegment.getArray(segList);
float val = - (getBias()); // must subtract :. "-"
for (int i=0; i < seg.length; i++) {
seg[i].addY(val);
}
}
/** Return this waveform filtered. To reduce edge effects
* the WFSegments are concatinated before they are filtered. */
public Waveform filter(FilterIF filter) {
if (hasTimeSeries()) {
return (Waveform) filter.filter(this);
} else {
return this;
}
}
/**
* Scan the whole time-series for the recified peak. Returns the Sample of the
* peak which may have a negative value; the bias is NOT removed.
* Returns null if no timeseries.
*/
public Sample scanForPeak () {
return scanForPeak(getTimeSpan());
}
/**
* Return the Sample with the maximum amplitude in the waveform.
* "Maximum" value could be
* the largest excursion downward. Bias is NOT removed.
* Because of large biases even "positive" peak
* could be a negative number. Returns 'null' if no time-series.
*/
public Sample scanForPeak (double startTime, double endTime) {
return scanForPeak (new TimeSpan(startTime, endTime));
}
/**
* Return the Sample with the maximum amplitude in the waveform.
* "Maximum" value could be
* the largest excursion downward. Bias is NOT removed.
* Because of large biases even "positive" peak
* could be a negative number. Returns 'null' if no time-series.
*/
public Sample scanForPeak (TimeSpan timeSpan) {
if (!hasTimeSeries()) return null; // no time series
synchronized (this) {
WFSegment seg[] = WFSegment.getArray(segList);
Sample peakSample = seg[0].getPeakSample(timeSpan.getStart(), timeSpan.getEnd());
Sample tmpSample = null;
for (int i=1; i < seg.length; i++) {
tmpSample = seg[i].getPeakSample(timeSpan.getStart(), timeSpan.getEnd());
peakSample = Sample.absMax(peakSample, tmpSample);
// past end of time window, bail
if (seg[i].getEnd().doubleValue() > timeSpan.getEnd()) break;
}
return peakSample;
} // end of synch
}
/**
* Calculate the background noise level. It is
* the median of the peaks between zero-crossings for a rectified time-series
* with the bias removed for the whole time-series.
* Returns Float.NaN if it cannot be calculated.
*/
public float scanForNoiseLevel () {
return scanForNoiseLevel(getEpochStart(), getEpochEnd());
}
/**
* Calculate the background noise level. Sets value of 'noiseLevel'. It is
* the median of the peaks between zero-crossings for a rectified time-series
* with the bias removed for the time window given.
* Returns Float.NaN if it cannot be calculated.
*/
public float scanForNoiseLevel (TimeSpan ts) {
return scanForNoiseLevel(ts.getStart(), ts.getEnd());
}
/**
* Calculate the background noise level. Sets value of 'noiseLevel'. It is
* the median of the peaks between zero-crossings for a rectified time-series
* with the bias removed for the time window given.
* Returns Float.NaN if it cannot be calculated.
*/
public float scanForNoiseLevel (double startTime, double endTime) {
if (!hasTimeSeries()) {
noiseLevel = Float.NaN;
return noiseLevel;
} // no time series
synchronized (this) {
WFSegment seg[] = WFSegment.getArray(segList);
float segNoise;
noiseLevel = 0.0f;
//Segments aren't equal in length :. weight the bias by sample count
for (int i=0; i < seg.length; i++) {
segNoise = seg[i].scanForNoiseLevel(startTime, endTime);
if (segNoise != Float.NaN) {
noiseLevel = Math.max(noiseLevel, segNoise);
}
// past end of time window, bail
if (seg[i].getEnd().doubleValue() > endTime) break;
}
} // end of synch
return noiseLevel;
}
/** Return true if the Waveform has time tears.
* Because waveforms are ALWAYS collapsed, > 1 segment means there are time tears.
*/
public boolean hasTimeTears() {
if (segList.size() > 1) {
return true;
} else {
return false;
}
}
/**
* Return the bias of this waveform.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -