package org.signalml.domain.signal.filter.iir.helper; import org.signalml.domain.signal.samplesource.SampleSource; import org.signalml.domain.signal.samplesource.SampleSourceEngine; import org.signalml.math.ArrayOperations; import org.signalml.math.iirdesigner.FilterCoefficients; /** * Adds additional samples to a sample source so that filtering it * with an IIR filter will be more stable. * * @author Piotr Szachewicz */ public class GrowSignalSampleSource extends SampleSourceEngine { protected double[] bCoefficients; protected double[] aCoefficients; /** * The samples added to the left of the original sample source. */ protected double[] leftExtension; /** * The samples added to the right of the original sample source. */ protected double[] rightExtension; /** * Constructor. * @param source the sample source which should be enriched by the additional samples. * @param filterCoefficients the coefficients of the filter for which the stability * should be optimized after growing the sample source. */ public GrowSignalSampleSource(SampleSource source, FilterCoefficients filterCoefficients) { super(source); this.bCoefficients = filterCoefficients.getBCoefficients(); this.aCoefficients = filterCoefficients.getACoefficients(); int ntaps = Math.max(aCoefficients.length, bCoefficients.length); int edge = ntaps * 3; calculateEdges(edge); } /** * Calculates the samples that should be added to the left * and right of the original sample source. * @param edgeSize number of samples that should be added to each side. */ protected void calculateEdges(int edgeSize) { double[] leftEnd = new double[1]; leftExtension = new double[edgeSize]; source.getSamples(leftEnd, 0, 1, 0); source.getSamples(leftExtension, 1, edgeSize, 0); leftExtension = ArrayOperations.reverse(leftExtension); double[] rightEnd = new double[1]; rightExtension = new double[edgeSize]; source.getSamples(rightEnd, source.getSampleCount()-1, 1, 0); source.getSamples(rightExtension, source.getSampleCount()-edgeSize-1, edgeSize, 0); rightExtension = ArrayOperations.reverse(rightExtension); for (int i = 0; i < leftExtension.length; i++) leftExtension[i] = 2 * leftEnd[0] - leftExtension[i]; for (int i = 0; i < rightExtension.length; i++) rightExtension[i] = 2 * rightEnd[0] - rightExtension[i]; } @Override public int getSampleCount() { return super.getSampleCount() + leftExtension.length + rightExtension.length; } /** * Returns the samples from the {@link GrowSignalSampleSource#leftExtension} * that intersect with the given signalOffset and count. * @param signalOffset the first sample which is requested in the invocation * of the {@link GrowSignalSampleSource#getSamples(double[], int, int, int)} * method. * * @param count the number of samples requested in the * {@link GrowSignalSampleSource#getSamples(double[], int, int, int)} * @return the samples from the left extension. */ protected double[] getLeftPart(int signalOffset, int count) { int leftBegin = signalOffset; if (leftBegin > leftExtension.length) leftBegin = leftExtension.length; int leftEnd = leftBegin + count; if (leftEnd > leftExtension.length) leftEnd = leftExtension.length; int size = leftEnd - leftBegin; double[] left = new double[size]; System.arraycopy(leftExtension, leftBegin, left, 0, size); return left; } /** * Returns the samples from the original sample source * that intersect with the given signalOffset and count. * @param signalOffset the first sample which is requested in the invocation * of the {@link GrowSignalSampleSource#getSamples(double[], int, int, int)} * method. * * @param count the number of samples requested in the * {@link GrowSignalSampleSource#getSamples(double[], int, int, int)} * @return the samples from the left extension. */ protected double[] getCenterPart(int signalOffset, int count) { int centerBegin = signalOffset - leftExtension.length; if (centerBegin < 0) centerBegin = 0; else if (centerBegin >= source.getSampleCount()) centerBegin = source.getSampleCount(); int centerEnd = signalOffset + count - leftExtension.length; if (centerEnd < 0) centerEnd = 0; else if (centerEnd >= source.getSampleCount()) centerEnd = source.getSampleCount(); int centerSize = centerEnd - centerBegin; double[] center = new double[centerSize]; source.getSamples(center, centerBegin, centerSize, 0); return center; } /** * Returns the samples from the {@link GrowSignalSampleSource#rightExtension} * that intersect with the given signalOffset and count. * @param signalOffset the first sample which is requested in the invocation * of the {@link GrowSignalSampleSource#getSamples(double[], int, int, int)} * method. * * @param count the number of samples requested in the * {@link GrowSignalSampleSource#getSamples(double[], int, int, int)} * @return the samples from the left extension. */ protected double[] getRightPart(int signalOffset, int count) { int rightBegin = signalOffset - leftExtension.length - source.getSampleCount(); if (rightBegin < 0) rightBegin = 0; int rightEnd = signalOffset - leftExtension.length - source.getSampleCount() + count; if (rightEnd < 0) rightEnd = 0; int size = rightEnd - rightBegin; double[] right = new double[size]; System.arraycopy(rightExtension, rightBegin, right, 0, size); return right; } @Override public void getSamples(double[] target, int signalOffset, int count, int arrayOffset) { double[] left = getLeftPart(signalOffset, count); double[] center = getCenterPart(signalOffset, count); double[] right = getRightPart(signalOffset, count); System.arraycopy(left, 0, target, 0, left.length); System.arraycopy(center, 0, target, left.length, center.length); System.arraycopy(right, 0, target, left.length+center.length, right.length); } }