package edu.sc.seis.sod.process.waveform; import org.w3c.dom.Element; import com.oregondsp.signalProcessing.filter.iir.PassbandType; import edu.iris.Fissures.IfSeismogramDC.RequestFilter; import edu.iris.Fissures.model.QuantityImpl; import edu.iris.Fissures.model.UnitImpl; import edu.iris.Fissures.network.ChannelImpl; import edu.iris.Fissures.seismogramDC.LocalSeismogramImpl; import edu.sc.seis.fissuresUtil.bag.Arithmatic; import edu.sc.seis.fissuresUtil.bag.Statistics; import edu.sc.seis.fissuresUtil.cache.CacheEvent; import edu.sc.seis.sod.CookieJar; import edu.sc.seis.sod.SodUtil; import edu.sc.seis.sod.Threadable; import edu.sc.seis.sod.status.StringTreeBranch; public class Decimate implements WaveformProcess, Threadable { public Decimate(Element config) { this.config = config; if (SodUtil.getElement(config, ANTIALIAS_NAME) != null) { antiAlias = true; } if (SodUtil.getElement(config, TOSPS_NAME) != null) { toSampleRate = Float.parseFloat(SodUtil.loadText(config, TOSPS_NAME, "not used")); } else if (SodUtil.getElement(config, FACTOR_NAME) != null) { decimate = new edu.sc.seis.fissuresUtil.bag.Decimate(Integer.parseInt(SodUtil.getNestedText(SodUtil.getElement(config, FACTOR_NAME)))); } else { System.err.println("WARNING, naked int in <decimate> is depricated, please use <" + TOSPS_NAME + "> or <" + FACTOR_NAME + ">."); decimate = new edu.sc.seis.fissuresUtil.bag.Decimate(Integer.parseInt(SodUtil.getNestedText(config))); } } public boolean isThreadSafe() { return true; } public WaveformResult accept(CacheEvent event, ChannelImpl channel, RequestFilter[] original, RequestFilter[] available, LocalSeismogramImpl[] seismograms, CookieJar cookieJar) throws Exception { LocalSeismogramImpl[] out = new LocalSeismogramImpl[seismograms.length]; LocalSeismogramImpl[] filteredSeis = seismograms; if (seismograms.length != 0) { edu.sc.seis.fissuresUtil.bag.Decimate d = decimate; if (d == null) { d = new edu.sc.seis.fissuresUtil.bag.Decimate((int)Math.ceil(seismograms[0].getSampling() .getFrequency() .getValue(UnitImpl.HERTZ) / toSampleRate)); } if (antiAlias) { antiAliasFilter = new OregonDSPFilter(SodUtil.getElement(config, ANTIALIAS_NAME), PassbandType.LOWPASS, ZERO, seismograms[0].getSampling() .getFrequency() .divideBy(2*d.getFactor())); // nyquist is 1/2 sample rate // remove mean before filter double[] mean = new double[seismograms.length]; LocalSeismogramImpl[] demeanedSeis = new LocalSeismogramImpl[seismograms.length]; for (int i = 0; i < seismograms.length; i++) { Statistics stats = new Statistics(seismograms[i]); mean[i] = stats.mean(); demeanedSeis[i] = rmean.apply(seismograms[i]); } WaveformResult filtered = antiAliasFilter.apply(demeanedSeis); if (! filtered.isSuccess()) { return new WaveformResult(seismograms, new StringTreeBranch(this, false, filtered.getReason())); } // add mean back in again filteredSeis = filtered.getSeismograms(); for (int i = 0; i < filteredSeis.length; i++) { filteredSeis[i] = Arithmatic.add(filteredSeis[i], (float)mean[i]); } } for (int i = 0; i < out.length; i++) { out[i] = d.apply(filteredSeis[i]); } } return new WaveformResult(true, out, this); } Element config; boolean antiAlias = true; float toSampleRate; OregonDSPFilter antiAliasFilter; edu.sc.seis.fissuresUtil.bag.Decimate decimate; public static final String TOSPS_NAME = "maxSamplesPerSec"; public static final String FACTOR_NAME = "byFactor"; public static final String ANTIALIAS_NAME = "antiAliasFilter"; private static final QuantityImpl ZERO = new QuantityImpl(0, UnitImpl.HERTZ); private edu.sc.seis.fissuresUtil.bag.RMean rmean = new edu.sc.seis.fissuresUtil.bag.RMean(); }