mirror of
https://github.com/DSheirer/sdrtrunk.git
synced 2026-11-12 08:37:25 -05:00
Adds support for power-of-2 decimation for both real and complex sample buffers. Creates new class to analyze the filter attenuation rates using a variety of filter lengths and window options to enable selecting the optimal combination of cascaded power-of-2 half band decimation filters. (#1127)
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
This commit is contained in:
@@ -1,20 +1,21 @@
|
||||
/*******************************************************************************
|
||||
* SDR Trunk
|
||||
* Copyright (C) 2014 Dennis Sheirer
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2021 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
******************************************************************************/
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
* ****************************************************************************
|
||||
*/
|
||||
package io.github.dsheirer.buffer;
|
||||
|
||||
import java.util.Arrays;
|
||||
@@ -25,13 +26,12 @@ import java.util.Arrays;
|
||||
* fills buffer with 0-valued samples
|
||||
*
|
||||
* Can be used as a delay-type buffer, to delay samples by the 'size' amount
|
||||
*
|
||||
* @author denny
|
||||
*/
|
||||
public class FloatCircularBuffer
|
||||
{
|
||||
float[] mBuffer;
|
||||
int mBufferPointer = 0;
|
||||
private float[] mBuffer;
|
||||
private int mBufferPointer = 0;
|
||||
private float mOldestSample;
|
||||
|
||||
/**
|
||||
* Creates a circular double buffer of the specified size and all entries filled with the specified initial value.
|
||||
@@ -61,25 +61,27 @@ public class FloatCircularBuffer
|
||||
}
|
||||
|
||||
/**
|
||||
* Puts the new value into the buffer and returns the oldest buffer value that it replaced
|
||||
* Gets the current buffer value and overwrites that value position in the buffer with the new value.
|
||||
*
|
||||
* @param newValue to add to the buffer
|
||||
* @return oldest value that was overwritten by the new value
|
||||
*/
|
||||
public float get(float newValue)
|
||||
public float getAndPut(float newValue)
|
||||
{
|
||||
float oldestSample = mBuffer[mBufferPointer];
|
||||
mOldestSample = mBuffer[mBufferPointer];
|
||||
put(newValue);
|
||||
return mOldestSample;
|
||||
}
|
||||
|
||||
mBuffer[mBufferPointer] = newValue;
|
||||
|
||||
mBufferPointer++;
|
||||
|
||||
if(mBufferPointer >= mBuffer.length)
|
||||
{
|
||||
mBufferPointer = 0;
|
||||
}
|
||||
|
||||
return oldestSample;
|
||||
/**
|
||||
* Puts the value into the buffer, updates the pointer and returns the buffer value at the pointer position.
|
||||
* @param sample to add
|
||||
* @return next pointed sample.
|
||||
*/
|
||||
public float putAndGet(float sample)
|
||||
{
|
||||
put(sample);
|
||||
return mBuffer[mBufferPointer];
|
||||
}
|
||||
|
||||
public float[] getAll()
|
||||
@@ -109,12 +111,7 @@ public class FloatCircularBuffer
|
||||
public void put(float newValue)
|
||||
{
|
||||
mBuffer[mBufferPointer] = newValue;
|
||||
|
||||
mBufferPointer++;
|
||||
|
||||
if(mBufferPointer >= mBuffer.length)
|
||||
{
|
||||
mBufferPointer = 0;
|
||||
}
|
||||
mBufferPointer %= mBuffer.length;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1004,7 +1004,7 @@ public class FilterFactory
|
||||
* @param windowType to apply to the filter.
|
||||
* @return coefficients
|
||||
*/
|
||||
public static double[] getHalfBand(int length, Window.WindowType windowType)
|
||||
public static float[] getHalfBand(int length, Window.WindowType windowType)
|
||||
{
|
||||
if((length - 3) % 4 != 0)
|
||||
{
|
||||
@@ -1013,7 +1013,7 @@ public class FilterFactory
|
||||
}
|
||||
|
||||
double[] window = Window.getWindow(windowType, length);
|
||||
double[] taps = new double[length];
|
||||
float[] taps = new float[length];
|
||||
|
||||
int halfLength = length / 2;
|
||||
|
||||
@@ -1053,7 +1053,7 @@ public class FilterFactory
|
||||
|
||||
int length = 15;
|
||||
|
||||
double [] taps = FilterFactory.getHalfBand(length, Window.WindowType.HAMMING);
|
||||
float [] taps = FilterFactory.getHalfBand(length, Window.WindowType.HAMMING);
|
||||
|
||||
for(int x = 0; x < length; x++)
|
||||
{
|
||||
|
||||
@@ -24,6 +24,7 @@ import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.EnumSet;
|
||||
|
||||
/**
|
||||
* Window factory and corresponding utility methods.
|
||||
@@ -484,12 +485,17 @@ public class Window
|
||||
mLabel = label;
|
||||
}
|
||||
|
||||
|
||||
public String toString()
|
||||
{
|
||||
return mLabel;
|
||||
}
|
||||
}
|
||||
|
||||
public static final EnumSet<WindowType> NO_PARAMETER_WINDOWS = EnumSet.of(WindowType.BLACKMAN, WindowType.BLACKMAN_HARRIS_4,
|
||||
WindowType.BLACKMAN_HARRIS_7, WindowType.BLACKMAN_NUTALL, WindowType.COSINE, WindowType.FLAT_TOP,
|
||||
WindowType.HAMMING, WindowType.HANN, WindowType.NUTALL);
|
||||
|
||||
public static void main(String[] args)
|
||||
{
|
||||
double[] kaiser = getKaiser(16, 80.0);
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2021 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
* ****************************************************************************
|
||||
*/
|
||||
|
||||
package io.github.dsheirer.dsp.filter.decimate;
|
||||
|
||||
import io.github.dsheirer.dsp.filter.FilterFactory;
|
||||
import io.github.dsheirer.dsp.filter.Window;
|
||||
import io.github.dsheirer.dsp.filter.halfband.complex.ComplexHalfBandDecimationFilter;
|
||||
|
||||
/**
|
||||
* Decimate by 1024 filter for complex valued sample buffers.
|
||||
*/
|
||||
public class ComplexDecimateX1024Filter extends ComplexDecimateX512Filter
|
||||
{
|
||||
private static final int VALIDATION_LENGTH = 1024 * 2;
|
||||
private static final int DECIMATE_BY_1024_FILTER_LENGTH = 11;
|
||||
private static final Window.WindowType DECIMATE_BY_1024_WINDOW_TYPE = Window.WindowType.BLACKMAN;
|
||||
private ComplexHalfBandDecimationFilter mFilter;
|
||||
|
||||
/**
|
||||
* Constructs the decimation filter.
|
||||
*/
|
||||
public ComplexDecimateX1024Filter()
|
||||
{
|
||||
mFilter = new ComplexHalfBandDecimationFilter(FilterFactory.getHalfBand(DECIMATE_BY_1024_FILTER_LENGTH,
|
||||
DECIMATE_BY_1024_WINDOW_TYPE));
|
||||
}
|
||||
|
||||
@Override
|
||||
public float[] decimateComplex(float[] samples)
|
||||
{
|
||||
validate(samples, VALIDATION_LENGTH);
|
||||
|
||||
//Decimate by this filter, then by the parent decimation filter
|
||||
return super.decimateComplex(mFilter.decimateComplex(samples));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2021 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
* ****************************************************************************
|
||||
*/
|
||||
|
||||
package io.github.dsheirer.dsp.filter.decimate;
|
||||
|
||||
import io.github.dsheirer.dsp.filter.FilterFactory;
|
||||
import io.github.dsheirer.dsp.filter.Window;
|
||||
import io.github.dsheirer.dsp.filter.halfband.complex.ComplexHalfBandDecimationFilter;
|
||||
|
||||
/**
|
||||
* Decimate by 128 filter for complex valued sample buffers.
|
||||
*/
|
||||
public class ComplexDecimateX128Filter extends ComplexDecimateX64Filter
|
||||
{
|
||||
private static final int VALIDATION_LENGTH = 128 * 2;
|
||||
private static final int DECIMATE_BY_128_FILTER_LENGTH = 11;
|
||||
private static final Window.WindowType DECIMATE_BY_128_WINDOW_TYPE = Window.WindowType.BLACKMAN;
|
||||
private ComplexHalfBandDecimationFilter mFilter;
|
||||
|
||||
/**
|
||||
* Constructs the decimation filter.
|
||||
*/
|
||||
public ComplexDecimateX128Filter()
|
||||
{
|
||||
mFilter = new ComplexHalfBandDecimationFilter(FilterFactory.getHalfBand(DECIMATE_BY_128_FILTER_LENGTH,
|
||||
DECIMATE_BY_128_WINDOW_TYPE));
|
||||
}
|
||||
|
||||
@Override
|
||||
public float[] decimateComplex(float[] samples)
|
||||
{
|
||||
validate(samples, VALIDATION_LENGTH);
|
||||
|
||||
//Decimate by this filter, then by the parent decimation filter
|
||||
return super.decimateComplex(mFilter.decimateComplex(samples));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2021 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
* ****************************************************************************
|
||||
*/
|
||||
|
||||
package io.github.dsheirer.dsp.filter.decimate;
|
||||
|
||||
import io.github.dsheirer.dsp.filter.FilterFactory;
|
||||
import io.github.dsheirer.dsp.filter.Window;
|
||||
import io.github.dsheirer.dsp.filter.halfband.complex.ComplexHalfBandDecimationFilter;
|
||||
|
||||
/**
|
||||
* Decimate by 16 filter for complex valued sample buffers.
|
||||
*/
|
||||
public class ComplexDecimateX16Filter extends ComplexDecimateX8Filter
|
||||
{
|
||||
private static final int VALIDATION_LENGTH = 16 * 2;
|
||||
private static final int DECIMATE_BY_16_FILTER_LENGTH = 15;
|
||||
private static final Window.WindowType DECIMATE_BY_16_WINDOW_TYPE = Window.WindowType.BLACKMAN;
|
||||
private ComplexHalfBandDecimationFilter mFilter;
|
||||
|
||||
/**
|
||||
* Constructs the decimation filter.
|
||||
*/
|
||||
public ComplexDecimateX16Filter()
|
||||
{
|
||||
mFilter = new ComplexHalfBandDecimationFilter(FilterFactory.getHalfBand(DECIMATE_BY_16_FILTER_LENGTH,
|
||||
DECIMATE_BY_16_WINDOW_TYPE));
|
||||
}
|
||||
|
||||
@Override
|
||||
public float[] decimateComplex(float[] samples)
|
||||
{
|
||||
validate(samples, VALIDATION_LENGTH);
|
||||
|
||||
//Decimate by this filter, then by the parent decimation filter
|
||||
return super.decimateComplex(mFilter.decimateComplex(samples));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2021 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
* ****************************************************************************
|
||||
*/
|
||||
|
||||
package io.github.dsheirer.dsp.filter.decimate;
|
||||
|
||||
import io.github.dsheirer.dsp.filter.FilterFactory;
|
||||
import io.github.dsheirer.dsp.filter.Window;
|
||||
import io.github.dsheirer.dsp.filter.halfband.complex.ComplexHalfBandDecimationFilter;
|
||||
|
||||
/**
|
||||
* Decimate by 256 filter for complex valued sample buffers.
|
||||
*/
|
||||
public class ComplexDecimateX256Filter extends ComplexDecimateX128Filter
|
||||
{
|
||||
private static final int VALIDATION_LENGTH = 256 * 2;
|
||||
private static final int DECIMATE_BY_256_FILTER_LENGTH = 11;
|
||||
private static final Window.WindowType DECIMATE_BY_256_WINDOW_TYPE = Window.WindowType.BLACKMAN;
|
||||
private ComplexHalfBandDecimationFilter mFilter;
|
||||
|
||||
/**
|
||||
* Constructs the decimation filter.
|
||||
*/
|
||||
public ComplexDecimateX256Filter()
|
||||
{
|
||||
mFilter = new ComplexHalfBandDecimationFilter(FilterFactory.getHalfBand(DECIMATE_BY_256_FILTER_LENGTH,
|
||||
DECIMATE_BY_256_WINDOW_TYPE));
|
||||
}
|
||||
|
||||
@Override
|
||||
public float[] decimateComplex(float[] samples)
|
||||
{
|
||||
validate(samples, VALIDATION_LENGTH);
|
||||
|
||||
//Decimate by this filter, then by the parent decimation filter
|
||||
return super.decimateComplex(mFilter.decimateComplex(samples));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2021 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
* ****************************************************************************
|
||||
*/
|
||||
|
||||
package io.github.dsheirer.dsp.filter.decimate;
|
||||
|
||||
import io.github.dsheirer.dsp.filter.FilterFactory;
|
||||
import io.github.dsheirer.dsp.filter.Window;
|
||||
import io.github.dsheirer.dsp.filter.halfband.complex.ComplexHalfBandDecimationFilter;
|
||||
|
||||
/**
|
||||
* Constructs the decimation filter.
|
||||
*/
|
||||
public class ComplexDecimateX2Filter extends ComplexHalfBandDecimationFilter
|
||||
{
|
||||
private static final int DECIMATE_BY_2_FILTER_LENGTH = 63;
|
||||
private static final Window.WindowType DECIMATE_BY_2_WINDOW_TYPE = Window.WindowType.HAMMING;
|
||||
|
||||
/**
|
||||
* Creates a half band filter with inherent decimation by two.
|
||||
*/
|
||||
public ComplexDecimateX2Filter()
|
||||
{
|
||||
super(FilterFactory.getHalfBand(DECIMATE_BY_2_FILTER_LENGTH, DECIMATE_BY_2_WINDOW_TYPE));
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates that the samples length is an integer multiple of the specified validation multiple argument.
|
||||
* @param samples to validate
|
||||
* @param validationMultiple to validate against
|
||||
*/
|
||||
protected static void validate(float[] samples, int validationMultiple)
|
||||
{
|
||||
if(samples.length % validationMultiple != 0)
|
||||
{
|
||||
throw new IllegalArgumentException("Sample buffer length [" + samples.length +
|
||||
"] must be an integer multiple of " + validationMultiple);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2021 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
* ****************************************************************************
|
||||
*/
|
||||
|
||||
package io.github.dsheirer.dsp.filter.decimate;
|
||||
|
||||
import io.github.dsheirer.dsp.filter.FilterFactory;
|
||||
import io.github.dsheirer.dsp.filter.Window;
|
||||
import io.github.dsheirer.dsp.filter.halfband.complex.ComplexHalfBandDecimationFilter;
|
||||
|
||||
/**
|
||||
* Decimate by 32 filter for complex valued sample buffers.
|
||||
*/
|
||||
public class ComplexDecimateX32Filter extends ComplexDecimateX16Filter
|
||||
{
|
||||
private static final int VALIDATION_LENGTH = 32 * 2;
|
||||
private static final int DECIMATE_BY_32_FILTER_LENGTH = 11;
|
||||
private static final Window.WindowType DECIMATE_BY_32_WINDOW_TYPE = Window.WindowType.BLACKMAN;
|
||||
private ComplexHalfBandDecimationFilter mFilter;
|
||||
|
||||
/**
|
||||
* Constructs the decimation filter.
|
||||
*/
|
||||
public ComplexDecimateX32Filter()
|
||||
{
|
||||
mFilter = new ComplexHalfBandDecimationFilter(FilterFactory.getHalfBand(DECIMATE_BY_32_FILTER_LENGTH,
|
||||
DECIMATE_BY_32_WINDOW_TYPE));
|
||||
}
|
||||
|
||||
@Override
|
||||
public float[] decimateComplex(float[] samples)
|
||||
{
|
||||
validate(samples, VALIDATION_LENGTH);
|
||||
|
||||
//Decimate by this filter, then by the parent decimation filter
|
||||
return super.decimateComplex(mFilter.decimateComplex(samples));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2021 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
* ****************************************************************************
|
||||
*/
|
||||
|
||||
package io.github.dsheirer.dsp.filter.decimate;
|
||||
|
||||
import io.github.dsheirer.dsp.filter.FilterFactory;
|
||||
import io.github.dsheirer.dsp.filter.Window;
|
||||
import io.github.dsheirer.dsp.filter.halfband.complex.ComplexHalfBandDecimationFilter;
|
||||
import io.github.dsheirer.dsp.filter.halfband.real.RealHalfBandDecimationFilter;
|
||||
|
||||
/**
|
||||
* Decimate by 4 filter for complex valued sample buffers.
|
||||
*/
|
||||
public class ComplexDecimateX4Filter extends ComplexDecimateX2Filter
|
||||
{
|
||||
private static final int VALIDATION_LENGTH = 4 * 2;
|
||||
private static final int DECIMATE_BY_4_FILTER_LENGTH = 23;
|
||||
private static final Window.WindowType DECIMATE_BY_4_WINDOW_TYPE = Window.WindowType.BLACKMAN;
|
||||
private ComplexHalfBandDecimationFilter mFilter;
|
||||
|
||||
/**
|
||||
* Constructs the decimation filter.
|
||||
*/
|
||||
public ComplexDecimateX4Filter()
|
||||
{
|
||||
mFilter = new ComplexHalfBandDecimationFilter(FilterFactory.getHalfBand(DECIMATE_BY_4_FILTER_LENGTH,
|
||||
DECIMATE_BY_4_WINDOW_TYPE));
|
||||
}
|
||||
|
||||
@Override
|
||||
public float[] decimateComplex(float[] samples)
|
||||
{
|
||||
validate(samples, VALIDATION_LENGTH);
|
||||
|
||||
//Decimate by this filter, then by the parent decimation filter
|
||||
return super.decimateComplex(mFilter.decimateComplex(samples));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2021 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
* ****************************************************************************
|
||||
*/
|
||||
|
||||
package io.github.dsheirer.dsp.filter.decimate;
|
||||
|
||||
import io.github.dsheirer.dsp.filter.FilterFactory;
|
||||
import io.github.dsheirer.dsp.filter.Window;
|
||||
import io.github.dsheirer.dsp.filter.halfband.complex.ComplexHalfBandDecimationFilter;
|
||||
|
||||
/**
|
||||
* Decimate by 512 filter for complex valued sample buffers.
|
||||
*/
|
||||
public class ComplexDecimateX512Filter extends ComplexDecimateX256Filter
|
||||
{
|
||||
private static final int VALIDATION_LENGTH = 512 * 2;
|
||||
private static final int DECIMATE_BY_512_FILTER_LENGTH = 11;
|
||||
private static final Window.WindowType DECIMATE_BY_512_WINDOW_TYPE = Window.WindowType.BLACKMAN;
|
||||
private ComplexHalfBandDecimationFilter mFilter;
|
||||
|
||||
/**
|
||||
* Constructs the decimation filter.
|
||||
*/
|
||||
public ComplexDecimateX512Filter()
|
||||
{
|
||||
mFilter = new ComplexHalfBandDecimationFilter(FilterFactory.getHalfBand(DECIMATE_BY_512_FILTER_LENGTH,
|
||||
DECIMATE_BY_512_WINDOW_TYPE));
|
||||
}
|
||||
|
||||
@Override
|
||||
public float[] decimateComplex(float[] samples)
|
||||
{
|
||||
validate(samples, VALIDATION_LENGTH);
|
||||
|
||||
//Decimate by this filter, then by the parent decimation filter
|
||||
return super.decimateComplex(mFilter.decimateComplex(samples));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2021 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
* ****************************************************************************
|
||||
*/
|
||||
|
||||
package io.github.dsheirer.dsp.filter.decimate;
|
||||
|
||||
import io.github.dsheirer.dsp.filter.FilterFactory;
|
||||
import io.github.dsheirer.dsp.filter.Window;
|
||||
import io.github.dsheirer.dsp.filter.halfband.complex.ComplexHalfBandDecimationFilter;
|
||||
|
||||
/**
|
||||
* Decimate by 64 filter for complex valued sample buffers.
|
||||
*/
|
||||
public class ComplexDecimateX64Filter extends ComplexDecimateX32Filter
|
||||
{
|
||||
private static final int VALIDATION_LENGTH = 64 * 2;
|
||||
private static final int DECIMATE_BY_64_FILTER_LENGTH = 11;
|
||||
private static final Window.WindowType DECIMATE_BY_64_WINDOW_TYPE = Window.WindowType.BLACKMAN;
|
||||
private ComplexHalfBandDecimationFilter mFilter;
|
||||
|
||||
/**
|
||||
* Constructs the decimation filter.
|
||||
*/
|
||||
public ComplexDecimateX64Filter()
|
||||
{
|
||||
mFilter = new ComplexHalfBandDecimationFilter(FilterFactory.getHalfBand(DECIMATE_BY_64_FILTER_LENGTH,
|
||||
DECIMATE_BY_64_WINDOW_TYPE));
|
||||
}
|
||||
|
||||
@Override
|
||||
public float[] decimateComplex(float[] samples)
|
||||
{
|
||||
validate(samples, VALIDATION_LENGTH);
|
||||
|
||||
//Decimate by this filter, then by the parent decimation filter
|
||||
return super.decimateComplex(mFilter.decimateComplex(samples));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2021 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
* ****************************************************************************
|
||||
*/
|
||||
|
||||
package io.github.dsheirer.dsp.filter.decimate;
|
||||
|
||||
import io.github.dsheirer.dsp.filter.FilterFactory;
|
||||
import io.github.dsheirer.dsp.filter.Window;
|
||||
import io.github.dsheirer.dsp.filter.halfband.complex.ComplexHalfBandDecimationFilter;
|
||||
|
||||
/**
|
||||
* Decimate by 8 filter for complex valued sample buffers.
|
||||
*/
|
||||
public class ComplexDecimateX8Filter extends ComplexDecimateX4Filter
|
||||
{
|
||||
private static final int VALIDATION_LENGTH = 8 * 2;
|
||||
private static final int DECIMATE_BY_8_FILTER_LENGTH = 15;
|
||||
private static final Window.WindowType DECIMATE_BY_8_WINDOW_TYPE = Window.WindowType.BLACKMAN;
|
||||
private ComplexHalfBandDecimationFilter mFilter;
|
||||
|
||||
/**
|
||||
* Constructs the decimation filter.
|
||||
*/
|
||||
public ComplexDecimateX8Filter()
|
||||
{
|
||||
mFilter = new ComplexHalfBandDecimationFilter(FilterFactory.getHalfBand(DECIMATE_BY_8_FILTER_LENGTH,
|
||||
DECIMATE_BY_8_WINDOW_TYPE));
|
||||
}
|
||||
|
||||
@Override
|
||||
public float[] decimateComplex(float[] samples)
|
||||
{
|
||||
validate(samples, VALIDATION_LENGTH);
|
||||
|
||||
//Decimate by this filter, then by the parent decimation filter
|
||||
return super.decimateComplex(mFilter.decimateComplex(samples));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2021 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
* ****************************************************************************
|
||||
*/
|
||||
|
||||
package io.github.dsheirer.dsp.filter.decimate;
|
||||
|
||||
/**
|
||||
* Factory for creating real and complex decimation filters.
|
||||
*/
|
||||
public class DecimationFilterFactory
|
||||
{
|
||||
private static final int[] SUPPORTED_RATES = new int[]{2,4,8,16,32,64,128,256,512,1024};
|
||||
|
||||
/**
|
||||
* Creates a real-valued decimation filter for float array sample buffers providing greater than 100 dB of
|
||||
* attenuation for out of band signal aliases. Supports power of 2 decimation rates up to 1024.
|
||||
*
|
||||
* @param decimationRate requested @see SUPPORTED_RATES
|
||||
* @return constructed decimation filter
|
||||
*/
|
||||
public static IRealDecimationFilter getRealDecimationFilter(int decimationRate)
|
||||
{
|
||||
switch(decimationRate)
|
||||
{
|
||||
case 2:
|
||||
return new RealDecimateX2Filter();
|
||||
case 4:
|
||||
return new RealDecimateX4Filter();
|
||||
case 8:
|
||||
return new RealDecimateX8Filter();
|
||||
case 16:
|
||||
return new RealDecimateX16Filter();
|
||||
case 32:
|
||||
return new RealDecimateX32Filter();
|
||||
case 64:
|
||||
return new RealDecimateX64Filter();
|
||||
case 128:
|
||||
return new RealDecimateX128Filter();
|
||||
case 256:
|
||||
return new RealDecimateX256Filter();
|
||||
case 512:
|
||||
return new RealDecimateX512Filter();
|
||||
case 1024:
|
||||
return new RealDecimateX1024Filter();
|
||||
default:
|
||||
throw new IllegalArgumentException("Unsupported decimation rate: " + decimationRate +
|
||||
". Supported decimation rates are:" + SUPPORTED_RATES);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a complex-valued decimation filter for float array sample buffers providing greater than 100 dB of
|
||||
* attenuation for out of band signal aliases. Supports power of 2 decimation rates up to 1024.
|
||||
*
|
||||
* @param decimationRate requested @see SUPPORTED_RATES
|
||||
* @return constructed decimation filter
|
||||
*/
|
||||
public static IComplexDecimationFilter getComplexDecimationFilter(int decimationRate)
|
||||
{
|
||||
switch(decimationRate)
|
||||
{
|
||||
case 2:
|
||||
return new ComplexDecimateX2Filter();
|
||||
case 4:
|
||||
return new ComplexDecimateX4Filter();
|
||||
case 8:
|
||||
return new ComplexDecimateX8Filter();
|
||||
case 16:
|
||||
return new ComplexDecimateX16Filter();
|
||||
case 32:
|
||||
return new ComplexDecimateX32Filter();
|
||||
case 64:
|
||||
return new ComplexDecimateX64Filter();
|
||||
case 128:
|
||||
return new ComplexDecimateX128Filter();
|
||||
case 256:
|
||||
return new ComplexDecimateX256Filter();
|
||||
case 512:
|
||||
return new ComplexDecimateX512Filter();
|
||||
case 1024:
|
||||
return new ComplexDecimateX1024Filter();
|
||||
default:
|
||||
throw new IllegalArgumentException("Unsupported decimation rate: " + decimationRate +
|
||||
". Supported decimation rates are:" + SUPPORTED_RATES);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2021 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
* ****************************************************************************
|
||||
*/
|
||||
|
||||
package io.github.dsheirer.dsp.filter.decimate;
|
||||
|
||||
/**
|
||||
* Interface for a decimation filter for float array sample buffers
|
||||
*/
|
||||
public interface IComplexDecimationFilter
|
||||
{
|
||||
float[] decimateComplex(float[] samples);
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2021 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
* ****************************************************************************
|
||||
*/
|
||||
|
||||
package io.github.dsheirer.dsp.filter.decimate;
|
||||
|
||||
/**
|
||||
* Interface for a decimation filter for float array sample buffers
|
||||
*/
|
||||
public interface IRealDecimationFilter
|
||||
{
|
||||
float[] decimateReal(float[] samples);
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2021 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
* ****************************************************************************
|
||||
*/
|
||||
|
||||
package io.github.dsheirer.dsp.filter.decimate;
|
||||
|
||||
import io.github.dsheirer.dsp.filter.FilterFactory;
|
||||
import io.github.dsheirer.dsp.filter.Window;
|
||||
import io.github.dsheirer.dsp.filter.halfband.real.RealHalfBandDecimationFilter;
|
||||
|
||||
/**
|
||||
* Decimate by 1024 filter for real valued sample buffers.
|
||||
*/
|
||||
public class RealDecimateX1024Filter extends RealDecimateX512Filter
|
||||
{
|
||||
private static final int VALIDATION_LENGTH = 1024;
|
||||
private static final int DECIMATE_BY_1024_FILTER_LENGTH = 11;
|
||||
private static final Window.WindowType DECIMATE_BY_1024_WINDOW_TYPE = Window.WindowType.BLACKMAN;
|
||||
private RealHalfBandDecimationFilter mFilter;
|
||||
|
||||
/**
|
||||
* Constructs the decimation filter.
|
||||
*/
|
||||
public RealDecimateX1024Filter()
|
||||
{
|
||||
mFilter = new RealHalfBandDecimationFilter(FilterFactory.getHalfBand(DECIMATE_BY_1024_FILTER_LENGTH,
|
||||
DECIMATE_BY_1024_WINDOW_TYPE));
|
||||
}
|
||||
|
||||
@Override
|
||||
public float[] decimateReal(float[] samples)
|
||||
{
|
||||
validate(samples, VALIDATION_LENGTH);
|
||||
|
||||
//Decimate by this filter, then by the parent decimation filter
|
||||
return super.decimateReal(mFilter.decimateReal(samples));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2021 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
* ****************************************************************************
|
||||
*/
|
||||
|
||||
package io.github.dsheirer.dsp.filter.decimate;
|
||||
|
||||
import io.github.dsheirer.dsp.filter.FilterFactory;
|
||||
import io.github.dsheirer.dsp.filter.Window;
|
||||
import io.github.dsheirer.dsp.filter.halfband.real.RealHalfBandDecimationFilter;
|
||||
import io.github.dsheirer.gui.playlist.alias.ViewAliasIdentifierRequest;
|
||||
|
||||
/**
|
||||
* Decimate by 128 filter for real valued sample buffers.
|
||||
*/
|
||||
public class RealDecimateX128Filter extends RealDecimateX64Filter
|
||||
{
|
||||
private static final int VALIDATION_LENGTH = 128;
|
||||
private static final int DECIMATE_BY_128_FILTER_LENGTH = 11;
|
||||
private static final Window.WindowType DECIMATE_BY_128_WINDOW_TYPE = Window.WindowType.BLACKMAN;
|
||||
private RealHalfBandDecimationFilter mFilter;
|
||||
|
||||
/**
|
||||
* Constructs the decimation filter.
|
||||
*/
|
||||
public RealDecimateX128Filter()
|
||||
{
|
||||
mFilter = new RealHalfBandDecimationFilter(FilterFactory.getHalfBand(DECIMATE_BY_128_FILTER_LENGTH,
|
||||
DECIMATE_BY_128_WINDOW_TYPE));
|
||||
}
|
||||
|
||||
@Override
|
||||
public float[] decimateReal(float[] samples)
|
||||
{
|
||||
validate(samples, VALIDATION_LENGTH);
|
||||
|
||||
//Decimate by this filter, then by the parent decimation filter
|
||||
return super.decimateReal(mFilter.decimateReal(samples));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2021 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
* ****************************************************************************
|
||||
*/
|
||||
|
||||
package io.github.dsheirer.dsp.filter.decimate;
|
||||
|
||||
import io.github.dsheirer.dsp.filter.FilterFactory;
|
||||
import io.github.dsheirer.dsp.filter.Window;
|
||||
import io.github.dsheirer.dsp.filter.halfband.real.RealHalfBandDecimationFilter;
|
||||
|
||||
/**
|
||||
* Decimate by 16 filter for real valued sample buffers.
|
||||
*/
|
||||
public class RealDecimateX16Filter extends RealDecimateX8Filter
|
||||
{
|
||||
private static final int VALIDATION_LENGTH = 16;
|
||||
private static final int DECIMATE_BY_16_FILTER_LENGTH = 15;
|
||||
private static final Window.WindowType DECIMATE_BY_16_WINDOW_TYPE = Window.WindowType.BLACKMAN;
|
||||
private RealHalfBandDecimationFilter mFilter;
|
||||
|
||||
/**
|
||||
* Constructs the decimation filter.
|
||||
*/
|
||||
public RealDecimateX16Filter()
|
||||
{
|
||||
mFilter = new RealHalfBandDecimationFilter(FilterFactory.getHalfBand(DECIMATE_BY_16_FILTER_LENGTH,
|
||||
DECIMATE_BY_16_WINDOW_TYPE));
|
||||
}
|
||||
|
||||
@Override
|
||||
public float[] decimateReal(float[] samples)
|
||||
{
|
||||
validate(samples, VALIDATION_LENGTH);
|
||||
|
||||
//Decimate by this filter, then by the parent decimation filter
|
||||
return super.decimateReal(mFilter.decimateReal(samples));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2021 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
* ****************************************************************************
|
||||
*/
|
||||
|
||||
package io.github.dsheirer.dsp.filter.decimate;
|
||||
|
||||
import io.github.dsheirer.dsp.filter.FilterFactory;
|
||||
import io.github.dsheirer.dsp.filter.Window;
|
||||
import io.github.dsheirer.dsp.filter.halfband.real.RealHalfBandDecimationFilter;
|
||||
|
||||
/**
|
||||
* Decimate by 256 filter for real valued sample buffers.
|
||||
*/
|
||||
public class RealDecimateX256Filter extends RealDecimateX128Filter
|
||||
{
|
||||
private static final int VALIDATION_LENGTH = 256;
|
||||
private static final int DECIMATE_BY_256_FILTER_LENGTH = 11;
|
||||
private static final Window.WindowType DECIMATE_BY_256_WINDOW_TYPE = Window.WindowType.BLACKMAN;
|
||||
private RealHalfBandDecimationFilter mFilter;
|
||||
|
||||
/**
|
||||
* Constructs the decimation filter.
|
||||
*/
|
||||
public RealDecimateX256Filter()
|
||||
{
|
||||
mFilter = new RealHalfBandDecimationFilter(FilterFactory.getHalfBand(DECIMATE_BY_256_FILTER_LENGTH,
|
||||
DECIMATE_BY_256_WINDOW_TYPE));
|
||||
}
|
||||
|
||||
@Override
|
||||
public float[] decimateReal(float[] samples)
|
||||
{
|
||||
validate(samples, VALIDATION_LENGTH);
|
||||
|
||||
//Decimate by this filter, then by the parent decimation filter
|
||||
return super.decimateReal(mFilter.decimateReal(samples));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2021 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
* ****************************************************************************
|
||||
*/
|
||||
|
||||
package io.github.dsheirer.dsp.filter.decimate;
|
||||
|
||||
import io.github.dsheirer.dsp.filter.FilterFactory;
|
||||
import io.github.dsheirer.dsp.filter.Window;
|
||||
import io.github.dsheirer.dsp.filter.halfband.real.RealHalfBandDecimationFilter;
|
||||
|
||||
/**
|
||||
* Constructs the decimation filter.
|
||||
*/
|
||||
public class RealDecimateX2Filter extends RealHalfBandDecimationFilter
|
||||
{
|
||||
private static final int DECIMATE_BY_2_FILTER_LENGTH = 63;
|
||||
private static final Window.WindowType DECIMATE_BY_2_WINDOW_TYPE = Window.WindowType.HAMMING;
|
||||
|
||||
/**
|
||||
* Creates a half band filter with inherent decimation by two.
|
||||
*/
|
||||
public RealDecimateX2Filter()
|
||||
{
|
||||
super(FilterFactory.getHalfBand(DECIMATE_BY_2_FILTER_LENGTH, DECIMATE_BY_2_WINDOW_TYPE));
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates that the samples length is an integer multiple of the specified validation multiple argument.
|
||||
* @param samples to validate
|
||||
* @param validationMultiple to validate against
|
||||
*/
|
||||
protected static void validate(float[] samples, int validationMultiple)
|
||||
{
|
||||
if(samples.length % validationMultiple != 0)
|
||||
{
|
||||
throw new IllegalArgumentException("Sample buffer length [" + samples.length +
|
||||
"] must be an integer multiple of " + validationMultiple);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2021 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
* ****************************************************************************
|
||||
*/
|
||||
|
||||
package io.github.dsheirer.dsp.filter.decimate;
|
||||
|
||||
import io.github.dsheirer.dsp.filter.FilterFactory;
|
||||
import io.github.dsheirer.dsp.filter.Window;
|
||||
import io.github.dsheirer.dsp.filter.halfband.real.RealHalfBandDecimationFilter;
|
||||
|
||||
/**
|
||||
* Decimate by 32 filter for real valued sample buffers.
|
||||
*/
|
||||
public class RealDecimateX32Filter extends RealDecimateX16Filter
|
||||
{
|
||||
private static final int VALIDATION_LENGTH = 32;
|
||||
private static final int DECIMATE_BY_32_FILTER_LENGTH = 11;
|
||||
private static final Window.WindowType DECIMATE_BY_32_WINDOW_TYPE = Window.WindowType.BLACKMAN;
|
||||
private RealHalfBandDecimationFilter mFilter;
|
||||
|
||||
/**
|
||||
* Constructs the decimation filter.
|
||||
*/
|
||||
public RealDecimateX32Filter()
|
||||
{
|
||||
mFilter = new RealHalfBandDecimationFilter(FilterFactory.getHalfBand(DECIMATE_BY_32_FILTER_LENGTH,
|
||||
DECIMATE_BY_32_WINDOW_TYPE));
|
||||
}
|
||||
|
||||
@Override
|
||||
public float[] decimateReal(float[] samples)
|
||||
{
|
||||
validate(samples, VALIDATION_LENGTH);
|
||||
|
||||
//Decimate by this filter, then by the parent decimation filter
|
||||
return super.decimateReal(mFilter.decimateReal(samples));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2021 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
* ****************************************************************************
|
||||
*/
|
||||
|
||||
package io.github.dsheirer.dsp.filter.decimate;
|
||||
|
||||
import io.github.dsheirer.dsp.filter.FilterFactory;
|
||||
import io.github.dsheirer.dsp.filter.Window;
|
||||
import io.github.dsheirer.dsp.filter.halfband.real.RealHalfBandDecimationFilter;
|
||||
|
||||
/**
|
||||
* Decimate by 4 filter for real valued sample buffers.
|
||||
*/
|
||||
public class RealDecimateX4Filter extends RealDecimateX2Filter
|
||||
{
|
||||
private static final int VALIDATION_LENGTH = 4;
|
||||
private static final int DECIMATE_BY_4_FILTER_LENGTH = 23;
|
||||
private static final Window.WindowType DECIMATE_BY_4_WINDOW_TYPE = Window.WindowType.BLACKMAN;
|
||||
private RealHalfBandDecimationFilter mFilter;
|
||||
|
||||
/**
|
||||
* Constructs the decimation filter.
|
||||
*/
|
||||
public RealDecimateX4Filter()
|
||||
{
|
||||
mFilter = new RealHalfBandDecimationFilter(FilterFactory.getHalfBand(DECIMATE_BY_4_FILTER_LENGTH,
|
||||
DECIMATE_BY_4_WINDOW_TYPE));
|
||||
}
|
||||
|
||||
@Override
|
||||
public float[] decimateReal(float[] samples)
|
||||
{
|
||||
validate(samples, VALIDATION_LENGTH);
|
||||
|
||||
//Decimate by this filter, then by the parent decimation filter
|
||||
return super.decimateReal(mFilter.decimateReal(samples));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2021 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
* ****************************************************************************
|
||||
*/
|
||||
|
||||
package io.github.dsheirer.dsp.filter.decimate;
|
||||
|
||||
import io.github.dsheirer.dsp.filter.FilterFactory;
|
||||
import io.github.dsheirer.dsp.filter.Window;
|
||||
import io.github.dsheirer.dsp.filter.halfband.real.RealHalfBandDecimationFilter;
|
||||
|
||||
/**
|
||||
* Decimate by 512 filter for real valued sample buffers.
|
||||
*/
|
||||
public class RealDecimateX512Filter extends RealDecimateX256Filter
|
||||
{
|
||||
private static final int VALIDATION_LENGTH = 512;
|
||||
private static final int DECIMATE_BY_512_FILTER_LENGTH = 11;
|
||||
private static final Window.WindowType DECIMATE_BY_512_WINDOW_TYPE = Window.WindowType.BLACKMAN;
|
||||
private RealHalfBandDecimationFilter mFilter;
|
||||
|
||||
/**
|
||||
* Constructs the decimation filter.
|
||||
*/
|
||||
public RealDecimateX512Filter()
|
||||
{
|
||||
mFilter = new RealHalfBandDecimationFilter(FilterFactory.getHalfBand(DECIMATE_BY_512_FILTER_LENGTH,
|
||||
DECIMATE_BY_512_WINDOW_TYPE));
|
||||
}
|
||||
|
||||
@Override
|
||||
public float[] decimateReal(float[] samples)
|
||||
{
|
||||
validate(samples, VALIDATION_LENGTH);
|
||||
|
||||
//Decimate by this filter, then by the parent decimation filter
|
||||
return super.decimateReal(mFilter.decimateReal(samples));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2021 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
* ****************************************************************************
|
||||
*/
|
||||
|
||||
package io.github.dsheirer.dsp.filter.decimate;
|
||||
|
||||
import io.github.dsheirer.dsp.filter.FilterFactory;
|
||||
import io.github.dsheirer.dsp.filter.Window;
|
||||
import io.github.dsheirer.dsp.filter.halfband.real.RealHalfBandDecimationFilter;
|
||||
|
||||
/**
|
||||
* Decimate by 64 filter for real valued sample buffers.
|
||||
*/
|
||||
public class RealDecimateX64Filter extends RealDecimateX32Filter
|
||||
{
|
||||
private static final int VALIDATION_LENGTH = 64;
|
||||
private static final int DECIMATE_BY_64_FILTER_LENGTH = 11;
|
||||
private static final Window.WindowType DECIMATE_BY_64_WINDOW_TYPE = Window.WindowType.BLACKMAN;
|
||||
private RealHalfBandDecimationFilter mFilter;
|
||||
|
||||
/**
|
||||
* Constructs the decimation filter.
|
||||
*/
|
||||
public RealDecimateX64Filter()
|
||||
{
|
||||
mFilter = new RealHalfBandDecimationFilter(FilterFactory.getHalfBand(DECIMATE_BY_64_FILTER_LENGTH,
|
||||
DECIMATE_BY_64_WINDOW_TYPE));
|
||||
}
|
||||
|
||||
@Override
|
||||
public float[] decimateReal(float[] samples)
|
||||
{
|
||||
validate(samples, VALIDATION_LENGTH);
|
||||
|
||||
//Decimate by this filter, then by the parent decimation filter
|
||||
return super.decimateReal(mFilter.decimateReal(samples));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2021 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
* ****************************************************************************
|
||||
*/
|
||||
|
||||
package io.github.dsheirer.dsp.filter.decimate;
|
||||
|
||||
import io.github.dsheirer.dsp.filter.FilterFactory;
|
||||
import io.github.dsheirer.dsp.filter.Window;
|
||||
import io.github.dsheirer.dsp.filter.halfband.real.RealHalfBandDecimationFilter;
|
||||
|
||||
/**
|
||||
* Decimate by 8 filter for real valued sample buffers.
|
||||
*/
|
||||
public class RealDecimateX8Filter extends RealDecimateX4Filter
|
||||
{
|
||||
private static final int VALIDATION_LENGTH = 8;
|
||||
private static final int DECIMATE_BY_8_FILTER_LENGTH = 15;
|
||||
private static final Window.WindowType DECIMATE_BY_8_WINDOW_TYPE = Window.WindowType.BLACKMAN;
|
||||
private RealHalfBandDecimationFilter mFilter;
|
||||
|
||||
/**
|
||||
* Constructs the decimation filter.
|
||||
*/
|
||||
public RealDecimateX8Filter()
|
||||
{
|
||||
mFilter = new RealHalfBandDecimationFilter(FilterFactory.getHalfBand(DECIMATE_BY_8_FILTER_LENGTH,
|
||||
DECIMATE_BY_8_WINDOW_TYPE));
|
||||
}
|
||||
|
||||
@Override
|
||||
public float[] decimateReal(float[] samples)
|
||||
{
|
||||
validate(samples, VALIDATION_LENGTH);
|
||||
|
||||
//Decimate by this filter, then by the parent decimation filter
|
||||
return super.decimateReal(mFilter.decimateReal(samples));
|
||||
}
|
||||
}
|
||||
@@ -1,28 +1,26 @@
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2021 Dennis Sheirer
|
||||
*
|
||||
* * ******************************************************************************
|
||||
* * Copyright (C) 2014-2019 Dennis Sheirer
|
||||
* *
|
||||
* * This program is free software: you can redistribute it and/or modify
|
||||
* * it under the terms of the GNU General Public License as published by
|
||||
* * the Free Software Foundation, either version 3 of the License, or
|
||||
* * (at your option) any later version.
|
||||
* *
|
||||
* * This program is distributed in the hope that it will be useful,
|
||||
* * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* * GNU General Public License for more details.
|
||||
* *
|
||||
* * You should have received a copy of the GNU General Public License
|
||||
* * along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
* * *****************************************************************************
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
* ****************************************************************************
|
||||
*/
|
||||
|
||||
package io.github.dsheirer.dsp.filter.design;
|
||||
|
||||
import io.github.dsheirer.dsp.filter.FilterFactory;
|
||||
import io.github.dsheirer.dsp.filter.Window;
|
||||
import io.github.dsheirer.dsp.filter.fir.FIRFilterSpecification;
|
||||
import javafx.application.Application;
|
||||
import javafx.scene.Scene;
|
||||
@@ -61,74 +59,10 @@ public class FilterViewer extends Application
|
||||
*/
|
||||
private float[] getFilter()
|
||||
{
|
||||
// FIRFilterSpecification specification = FIRFilterSpecification.lowPassBuilder()
|
||||
// .sampleRate(8000)
|
||||
// .gridDensity(16)
|
||||
// .oddLength(true)
|
||||
// .passBandCutoff(300)
|
||||
// .passBandAmplitude(1.0)
|
||||
// .passBandRipple(0.01)
|
||||
// .stopBandStart(500)
|
||||
// .stopBandAmplitude(0.0)
|
||||
// .stopBandRipple(0.03) //Approximately 60 dB attenuation
|
||||
// .build();
|
||||
//
|
||||
// FIRFilterSpecification specification = FIRFilterSpecification.highPassBuilder()
|
||||
// .sampleRate(8000)
|
||||
// .stopBandCutoff(200)
|
||||
// .stopBandAmplitude(0.0)
|
||||
// .stopBandRipple(0.025)
|
||||
// .passBandStart(300)
|
||||
// .passBandAmplitude(1.0)
|
||||
// .passBandRipple(0.01)
|
||||
// .build();
|
||||
|
||||
// FIRFilterSpecification specification = FIRFilterSpecification.lowPassBuilder()
|
||||
// .sampleRate(50000.0)
|
||||
// .passBandCutoff(6500)
|
||||
// .passBandAmplitude(1.0)
|
||||
// .passBandRipple(0.005)
|
||||
// .stopBandAmplitude(0.0)
|
||||
// .stopBandStart(7200)
|
||||
// .stopBandRipple(0.01)
|
||||
// .build();
|
||||
|
||||
float[] taps = null;
|
||||
|
||||
boolean rrc = false;
|
||||
|
||||
if(rrc)
|
||||
{
|
||||
double sampleRate = 50000.0;
|
||||
int symbolRate = 4800;
|
||||
double samplesPerSymbol = sampleRate / symbolRate / 2;
|
||||
float alpha = 0.25f;
|
||||
int symbolCount = 20;
|
||||
|
||||
taps = FilterFactory.getRootRaisedCosine(samplesPerSymbol, symbolCount, alpha);
|
||||
}
|
||||
else
|
||||
{
|
||||
FIRFilterSpecification specification = FIRFilterSpecification.lowPassBuilder()
|
||||
.sampleRate(50000)
|
||||
.passBandCutoff(4500)
|
||||
.passBandAmplitude(1.0)
|
||||
.passBandRipple(0.1)
|
||||
.stopBandAmplitude(0.0)
|
||||
.stopBandStart(7000)
|
||||
.stopBandRipple(0.01)
|
||||
.build();
|
||||
|
||||
try
|
||||
{
|
||||
taps = FilterFactory.getTaps(specification);//
|
||||
}
|
||||
catch(Exception fde) //FilterDesignException
|
||||
{
|
||||
mLog.error("Couldn't design low pass baseband filter for sample rate");
|
||||
}
|
||||
}
|
||||
int filterLength = 63;
|
||||
Window.WindowType windowType = Window.WindowType.HAMMING;
|
||||
|
||||
float[] taps = FilterFactory.getHalfBand(filterLength, windowType);
|
||||
|
||||
if(taps == null)
|
||||
{
|
||||
|
||||
@@ -0,0 +1,170 @@
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2021 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
* ****************************************************************************
|
||||
*/
|
||||
|
||||
package io.github.dsheirer.dsp.filter.design;
|
||||
|
||||
import io.github.dsheirer.dsp.filter.FilterFactory;
|
||||
import io.github.dsheirer.dsp.filter.Window;
|
||||
import org.apache.commons.math3.util.FastMath;
|
||||
import org.jtransforms.fft.FloatFFT_1D;
|
||||
|
||||
import java.text.DecimalFormat;
|
||||
|
||||
/**
|
||||
* Develop tables that illustrate Half-Band filter attenutation at various filter lenths and decimation by two scenarios.
|
||||
*/
|
||||
public class HalfBandDecimationFilterAnalysis
|
||||
{
|
||||
private static final int FFT_SIZE = 4096;
|
||||
private static FloatFFT_1D FFT = new FloatFFT_1D(FFT_SIZE);
|
||||
private static final DecimalFormat DECIMAL_FORMAT = new DecimalFormat("0.0");
|
||||
|
||||
private static final Window.WindowType WINDOW_TYPE = Window.WindowType.BLACKMAN;
|
||||
private static final int[] TAP_LENGTHS = new int[]{7,11,15,19,23,27,31,35,39,43,47,51,55,59,63,67,71,75,79,83,87,91,95,99,103,107};
|
||||
private static final int BY_2 = (int)(FFT_SIZE / 2 * (1.0 / 2.0));
|
||||
private static final int BY_2_25 = (int)(FFT_SIZE / 2 * (1.0 / 2.25));
|
||||
private static final int BY_2_50 = (int)(FFT_SIZE / 2 * (1.0 / 2.5));
|
||||
private static final int BY_2_75 = (int)(FFT_SIZE / 2 * (1.0 / 2.75));
|
||||
private static final int BY_3 = (int)(FFT_SIZE / 2 * (1.0 / 3.0));
|
||||
private static final int BY_4 = (int)(FFT_SIZE / 2 * (1.0 / 4.0));
|
||||
private static final int BY_8 = (int)(FFT_SIZE / 2 * (1.0 / 8.0));
|
||||
private static final int BY_16 = (int)(FFT_SIZE / 2 * (1.0 / 16.0));
|
||||
private static final int BY_32 = (int)(FFT_SIZE / 2 * (1.0 / 32.0));
|
||||
private static final int BY_64 = (int)(FFT_SIZE / 2 * (1.0 / 64.0));
|
||||
private static final int BY_128 = (int)(FFT_SIZE / 2 * (1.0 / 128.0));
|
||||
private static final int BY_256 = (int)(FFT_SIZE / 2 * (1.0 / 256.0));
|
||||
private static final int BY_512 = (int)(FFT_SIZE / 2 * (1.0 / 512.0));
|
||||
private static final int BY_1024 = (int)(FFT_SIZE / 2 * (1.0 / 1024.0));
|
||||
|
||||
public HalfBandDecimationFilterAnalysis()
|
||||
{
|
||||
}
|
||||
|
||||
public static void analyze()
|
||||
{
|
||||
for(Window.WindowType windowType: Window.NO_PARAMETER_WINDOWS)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("Window: " + windowType).append("\n");
|
||||
sb.append("Length\t\t2x\t\t2.25x\t2.50x\t2.75x\t3x\t\t4x\t\t8x\t\t16x\t\t32x\t\t64x\t\t128x\t256x\t512x\t1024x\n");
|
||||
|
||||
for(int length: TAP_LENGTHS)
|
||||
{
|
||||
float[] taps = getTaps(length, windowType);
|
||||
float[] dft = getDFT(taps);
|
||||
float[] decibels = convertDFTToDecibel(dft, FFT_SIZE / 2);
|
||||
float x2Cutoff = getCutoff(BY_2, decibels);
|
||||
float x225Cutoff = getCutoff(BY_2_25, decibels);
|
||||
float x250Cutoff = getCutoff(BY_2_50, decibels);
|
||||
float x275Cutoff = getCutoff(BY_2_75, decibels);
|
||||
float x3Cutoff = getCutoff(BY_3, decibels);
|
||||
float x4Cutoff = getCutoff(BY_4, decibels);
|
||||
float x8Cutoff = getCutoff(BY_8, decibels);
|
||||
float x16Cutoff = getCutoff(BY_16, decibels);
|
||||
float x32Cutoff = getCutoff(BY_32, decibels);
|
||||
float x64Cutoff = getCutoff(BY_64, decibels);
|
||||
float x128Cutoff = getCutoff(BY_128, decibels);
|
||||
float x256Cutoff = getCutoff(BY_256, decibels);
|
||||
float x512Cutoff = getCutoff(BY_512, decibels);
|
||||
float x1024Cutoff = getCutoff(BY_1024, decibels);
|
||||
|
||||
sb.append(length).append("\t\t\t");
|
||||
sb.append(DECIMAL_FORMAT.format(x2Cutoff)).append("\t");
|
||||
sb.append(DECIMAL_FORMAT.format(x225Cutoff)).append("\t");
|
||||
sb.append(DECIMAL_FORMAT.format(x250Cutoff)).append("\t");
|
||||
sb.append(DECIMAL_FORMAT.format(x275Cutoff)).append("\t");
|
||||
sb.append(DECIMAL_FORMAT.format(x3Cutoff)).append("\t");
|
||||
sb.append(DECIMAL_FORMAT.format(x4Cutoff)).append("\t");
|
||||
sb.append(DECIMAL_FORMAT.format(x8Cutoff)).append("\t");
|
||||
sb.append(DECIMAL_FORMAT.format(x16Cutoff)).append("\t");
|
||||
sb.append(DECIMAL_FORMAT.format(x32Cutoff)).append("\t");
|
||||
sb.append(DECIMAL_FORMAT.format(x64Cutoff)).append("\t");
|
||||
sb.append(DECIMAL_FORMAT.format(x128Cutoff)).append("\t");
|
||||
sb.append(DECIMAL_FORMAT.format(x256Cutoff)).append("\t");
|
||||
sb.append(DECIMAL_FORMAT.format(x512Cutoff)).append("\t");
|
||||
sb.append(DECIMAL_FORMAT.format(x1024Cutoff)).append("\n");
|
||||
}
|
||||
|
||||
System.out.println(sb.toString());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the maximum cutoff starting at the specified index through the end index.
|
||||
* @param index
|
||||
* @return
|
||||
*/
|
||||
private static float getCutoff(int index, float[] decibels)
|
||||
{
|
||||
float cutoff = -200.0f;
|
||||
|
||||
int startIndex = decibels.length - index;
|
||||
|
||||
for(int x = startIndex; x < decibels.length; x++)
|
||||
{
|
||||
if(decibels[x] > cutoff)
|
||||
{
|
||||
cutoff = decibels[x];
|
||||
}
|
||||
}
|
||||
|
||||
return cutoff;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a half-band filter for the specified filter lenth and window type.
|
||||
* @param filterLength for the filter
|
||||
* @param windowType to apply to the taps during filter creation
|
||||
* @return filter
|
||||
*/
|
||||
private static float[] getTaps(int filterLength, Window.WindowType windowType)
|
||||
{
|
||||
return FilterFactory.getHalfBand(filterLength, windowType);
|
||||
}
|
||||
|
||||
private static float[] getDFT(float[] taps)
|
||||
{
|
||||
float[] dft = new float[FFT_SIZE];
|
||||
System.arraycopy(taps, 0, dft, 0, taps.length);
|
||||
FFT.realForward(dft);
|
||||
return dft;
|
||||
}
|
||||
|
||||
public static float[] convertDFTToDecibel(float[] dft, int tapLength)
|
||||
{
|
||||
float[] decibels = new float[dft.length / 2];
|
||||
|
||||
int index = 0;
|
||||
|
||||
for(int x = 0; x < decibels.length; x++)
|
||||
{
|
||||
index = x * 2;
|
||||
|
||||
decibels[x] = 20.0f * (float) FastMath.log10(((dft[index] * dft[index]) +
|
||||
(dft[index + 1] * dft[index + 1])));
|
||||
}
|
||||
|
||||
return decibels;
|
||||
}
|
||||
|
||||
public static void main(String[] args)
|
||||
{
|
||||
HalfBandDecimationFilterAnalysis.analyze();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2021 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
* ****************************************************************************
|
||||
*/
|
||||
|
||||
package io.github.dsheirer.dsp.filter.halfband.complex;
|
||||
|
||||
import io.github.dsheirer.dsp.filter.decimate.IComplexDecimationFilter;
|
||||
|
||||
/**
|
||||
* Complex half-band filter that processes samples on a per-array basis, versus a per-sample basis.
|
||||
*/
|
||||
public class ComplexHalfBandDecimationFilter implements IComplexDecimationFilter
|
||||
{
|
||||
private static final float CENTER_COEFFICIENT = 0.5f;
|
||||
private float[] mCoefficients;
|
||||
private float[] mBuffer;
|
||||
private float mIAccumulator;
|
||||
private float mQAccumulator;
|
||||
private int mCoefficientPointer;
|
||||
private int mCoefficientsLengthMinus2;
|
||||
private int mBufferPointer;
|
||||
private int mHalf;
|
||||
|
||||
/**
|
||||
* Constructs a complex sample half-band decimate x2 filter using the specified filter coefficients.
|
||||
* @param coefficients for the half-band filter where the middle coefficient is 0.5, and the even-numbered
|
||||
* coefficients are non-zero and symmetrical, and the odd-numbered coefficients are all zero valued.
|
||||
*/
|
||||
public ComplexHalfBandDecimationFilter(float[] coefficients)
|
||||
{
|
||||
if((coefficients.length + 1) % 4 != 0)
|
||||
{
|
||||
throw new IllegalArgumentException("Half-band filter coefficients must be odd-length and " +
|
||||
"symmetrical where L = [x * 4 - 1]");
|
||||
}
|
||||
|
||||
mCoefficients = new float[coefficients.length * 2];
|
||||
for(int x = 0; x < coefficients.length; x++)
|
||||
{
|
||||
mCoefficients[2 * x] = coefficients[x];
|
||||
mCoefficients[2 * x + 1] = coefficients[x];
|
||||
}
|
||||
|
||||
mCoefficientsLengthMinus2 = mCoefficients.length - 2;
|
||||
mHalf = mCoefficients.length / 2 - 1;
|
||||
}
|
||||
|
||||
public float[] decimateComplex(float[] samples)
|
||||
{
|
||||
if(samples.length % 4 != 0)
|
||||
{
|
||||
throw new IllegalArgumentException("Samples array length must be an integer multiple of 4");
|
||||
}
|
||||
|
||||
int bufferLength = samples.length + mCoefficientsLengthMinus2;
|
||||
|
||||
if(mBuffer == null)
|
||||
{
|
||||
mBuffer = new float[bufferLength];
|
||||
}
|
||||
else if(mBuffer.length != bufferLength)
|
||||
{
|
||||
float[] temp = new float[bufferLength];
|
||||
//Move residual samples from end of old buffer to the beginning of the new temp buffer
|
||||
System.arraycopy(mBuffer, mBuffer.length - mCoefficientsLengthMinus2, temp, 0, mCoefficientsLengthMinus2);
|
||||
mBuffer = temp;
|
||||
}
|
||||
else
|
||||
{
|
||||
//Move residual samples from end of buffer to the beginning of the buffer
|
||||
System.arraycopy(mBuffer, samples.length, mBuffer, 0, mCoefficientsLengthMinus2);
|
||||
}
|
||||
|
||||
//Copy new sample array into end of buffer
|
||||
System.arraycopy(samples, 0, mBuffer, mCoefficientsLengthMinus2, samples.length);
|
||||
|
||||
float[] filtered = new float[samples.length / 2];
|
||||
|
||||
for(mBufferPointer = 0; mBufferPointer < samples.length; mBufferPointer += 4)
|
||||
{
|
||||
mIAccumulator = 0.0f;
|
||||
mQAccumulator = 0.0f;
|
||||
|
||||
for(mCoefficientPointer = 0; mCoefficientPointer < mHalf; mCoefficientPointer += 4)
|
||||
{
|
||||
//Half band filter coefficients are mirrored, so we add the mirrored samples and then multiply by
|
||||
//one of the coefficients to achieve the same effect.
|
||||
mIAccumulator += mCoefficients[mCoefficientPointer] *
|
||||
(mBuffer[mBufferPointer + mCoefficientPointer] +
|
||||
mBuffer[mBufferPointer + (mCoefficientsLengthMinus2 - mCoefficientPointer)]);
|
||||
|
||||
mQAccumulator += mCoefficients[mCoefficientPointer] *
|
||||
(mBuffer[mBufferPointer + mCoefficientPointer + 1] +
|
||||
mBuffer[mBufferPointer + (mCoefficientsLengthMinus2 - mCoefficientPointer) + 1]);
|
||||
}
|
||||
|
||||
mIAccumulator += mBuffer[mBufferPointer + mHalf] * CENTER_COEFFICIENT;
|
||||
mQAccumulator += mBuffer[mBufferPointer + mHalf + 1] * CENTER_COEFFICIENT;
|
||||
|
||||
filtered[mBufferPointer / 2] = mIAccumulator;
|
||||
filtered[mBufferPointer / 2 + 1] = mQAccumulator;
|
||||
}
|
||||
|
||||
return filtered;
|
||||
}
|
||||
}
|
||||
@@ -1,18 +1,21 @@
|
||||
/*******************************************************************************
|
||||
* sdr-trunk
|
||||
* Copyright (C) 2014-2018 Dennis Sheirer
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2021 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public
|
||||
* License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any
|
||||
* later version.
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
|
||||
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with this program.
|
||||
* If not, see <http://www.gnu.org/licenses/>
|
||||
*
|
||||
******************************************************************************/
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
* ****************************************************************************
|
||||
*/
|
||||
package io.github.dsheirer.dsp.filter.halfband.complex;
|
||||
|
||||
import io.github.dsheirer.dsp.filter.Filters;
|
||||
@@ -36,10 +39,10 @@ public class ComplexHalfBandFilter
|
||||
private float[] mFilteredSamples;
|
||||
private int mFilteredSamplesPointer;
|
||||
|
||||
public ComplexHalfBandFilter(float[] coefficients, float gain)
|
||||
public ComplexHalfBandFilter(float[] coefficients)
|
||||
{
|
||||
mIFilter = new HalfBandFilter2(coefficients, gain);
|
||||
mQFilter = new HalfBandFilter2(coefficients, gain);
|
||||
mIFilter = new HalfBandFilter2(coefficients);
|
||||
mQFilter = new HalfBandFilter2(coefficients);
|
||||
}
|
||||
|
||||
public ReusableComplexBuffer filter(ReusableComplexBuffer originalBuffer)
|
||||
@@ -63,7 +66,7 @@ public class ComplexHalfBandFilter
|
||||
while(mSamplesPointer + 3 < mSamples.length)
|
||||
{
|
||||
mFilteredSamples[mFilteredSamplesPointer++] = mIFilter.filter(mSamples[mSamplesPointer], mSamples[mSamplesPointer + 2]);
|
||||
mFilteredSamples[mFilteredSamplesPointer++] = mIFilter.filter(mSamples[mSamplesPointer + 1], mSamples[mSamplesPointer + 3]);
|
||||
mFilteredSamples[mFilteredSamplesPointer++] = mQFilter.filter(mSamples[mSamplesPointer + 1], mSamples[mSamplesPointer + 3]);
|
||||
mSamplesPointer += 4;
|
||||
}
|
||||
|
||||
@@ -81,7 +84,7 @@ public class ComplexHalfBandFilter
|
||||
public static void main(String[] args)
|
||||
{
|
||||
Oscillator oscillator = new Oscillator(1, 16);
|
||||
ComplexHalfBandFilter filter = new ComplexHalfBandFilter(Filters.HALF_BAND_FILTER_27T.getCoefficients(), 1.0f);
|
||||
ComplexHalfBandFilter filter = new ComplexHalfBandFilter(Filters.HALF_BAND_FILTER_27T.getCoefficients());
|
||||
|
||||
ReusableComplexBufferQueue bufferQueue = new ReusableComplexBufferQueue("Test");
|
||||
|
||||
|
||||
@@ -1,20 +1,29 @@
|
||||
/*******************************************************************************
|
||||
* sdr-trunk
|
||||
* Copyright (C) 2014-2018 Dennis Sheirer
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2021 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public
|
||||
* License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any
|
||||
* later version.
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
|
||||
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with this program.
|
||||
* If not, see <http://www.gnu.org/licenses/>
|
||||
*
|
||||
******************************************************************************/
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
* ****************************************************************************
|
||||
*/
|
||||
package io.github.dsheirer.dsp.filter.halfband.real;
|
||||
|
||||
import io.github.dsheirer.buffer.FloatCircularBuffer;
|
||||
import io.github.dsheirer.dsp.filter.FilterFactory;
|
||||
import io.github.dsheirer.dsp.filter.Window;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* Implements a half-band filter that produces one filtered output for every two input samples.
|
||||
*
|
||||
@@ -26,30 +35,26 @@ public class HalfBandFilter2
|
||||
private static final float CENTER_COEFFICIENT = 0.5f;
|
||||
private float[] mCoefficients;
|
||||
private float[] mEvenSamples;
|
||||
private float[] mOddSamples;
|
||||
private int mCenterSampleIndex;
|
||||
private float mAccumulator;
|
||||
private int mPointer;
|
||||
private float mGain;
|
||||
private FloatCircularBuffer mCircularBuffer;
|
||||
|
||||
/**
|
||||
* Creates a half band filter with inherent decimation by two.
|
||||
*
|
||||
* @param coefficients of the half-band filter that is odd-length where all odd index coefficients are
|
||||
* zero valued except for the middle odd index coefficient which should be valued 0.5
|
||||
* @param gain value to apply to the output
|
||||
*/
|
||||
public HalfBandFilter2(float[] coefficients, float gain)
|
||||
public HalfBandFilter2(float[] coefficients)
|
||||
{
|
||||
if(coefficients.length % 2 == 0)
|
||||
if((coefficients.length + 1) % 4 != 0)
|
||||
{
|
||||
throw new IllegalArgumentException("Half-band filter coefficients must be odd-length");
|
||||
throw new IllegalArgumentException("Half-band filter coefficients must be odd-length and symmetrical (length = [x * 4 + 1]");
|
||||
}
|
||||
|
||||
mGain = gain;
|
||||
|
||||
int half = coefficients.length / 2 + 1;
|
||||
|
||||
mCircularBuffer = new FloatCircularBuffer(half / 2);
|
||||
mCoefficients = new float[half];
|
||||
mEvenSamples = new float[half];
|
||||
|
||||
@@ -58,20 +63,14 @@ public class HalfBandFilter2
|
||||
{
|
||||
mCoefficients[x / 2] = coefficients[x];
|
||||
}
|
||||
|
||||
//Setup the odd samples array as a simple delay line, half the size of the even samples array
|
||||
mOddSamples = new float[half / 2];
|
||||
mCenterSampleIndex = mOddSamples.length - 1;
|
||||
}
|
||||
|
||||
public float filter(float sample1, float sample2)
|
||||
{
|
||||
//Structured for SIMD array copy optimization when supported by host CPU
|
||||
System.arraycopy(mEvenSamples, 0, mEvenSamples, 1, mEvenSamples.length - 1);
|
||||
System.arraycopy(mOddSamples, 0, mOddSamples, 1, mOddSamples.length - 1);
|
||||
|
||||
mEvenSamples[0] = sample1;
|
||||
mOddSamples[0] = sample2;
|
||||
|
||||
mAccumulator = 0.0f;
|
||||
|
||||
@@ -81,9 +80,53 @@ public class HalfBandFilter2
|
||||
mAccumulator += (mEvenSamples[mPointer] * mCoefficients[mPointer]);
|
||||
}
|
||||
|
||||
mAccumulator += (mOddSamples[mCenterSampleIndex] * CENTER_COEFFICIENT);
|
||||
mAccumulator *= mGain;
|
||||
mAccumulator += (mCircularBuffer.getAndPut(sample2) * CENTER_COEFFICIENT);
|
||||
|
||||
return mAccumulator;
|
||||
}
|
||||
|
||||
public float[] filter(float[] samples)
|
||||
{
|
||||
float[] filtered = new float[samples.length / 2];
|
||||
for(int x = 0; x < samples.length; x += 2)
|
||||
{
|
||||
filtered[x / 2] = filter(samples[x], samples[x + 1]);
|
||||
}
|
||||
|
||||
return filtered;
|
||||
}
|
||||
|
||||
public static void main(String[] args)
|
||||
{
|
||||
System.out.println("Starting ...");
|
||||
float[] taps = FilterFactory.getHalfBand(99, Window.WindowType.HAMMING);
|
||||
|
||||
HalfBandFilter2 halfband = new HalfBandFilter2(taps);
|
||||
|
||||
Random random = new Random();
|
||||
float[] samples = new float[1024];
|
||||
float[] filtered = new float[512];
|
||||
|
||||
for(int x = 0; x < samples.length; x++)
|
||||
{
|
||||
samples[x] = (2.0f * random.nextFloat()) - 1.0f;
|
||||
}
|
||||
|
||||
System.out.println("Testing ...");
|
||||
long current = System.currentTimeMillis();
|
||||
|
||||
int iterations = 10_000_000;
|
||||
|
||||
for(int x = 0; x < iterations; x++)
|
||||
{
|
||||
for(int y = 0; y < samples.length; y += 2)
|
||||
{
|
||||
filtered[y / 2] = halfband.filter(samples[y], samples[y + 1]);
|
||||
}
|
||||
}
|
||||
|
||||
long elapsed = System.currentTimeMillis() - current;
|
||||
|
||||
System.out.println("Elapsed: " + (elapsed / 1000d) + " seconds");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2021 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
* ****************************************************************************
|
||||
*/
|
||||
package io.github.dsheirer.dsp.filter.halfband.real;
|
||||
|
||||
import io.github.dsheirer.dsp.filter.decimate.IRealDecimationFilter;
|
||||
|
||||
/**
|
||||
* Implements a half-band filter that produces one filtered output for every two input samples.
|
||||
*
|
||||
* This filter is structured for Java 8+ compiler JIT optimization for SIMD instructions when
|
||||
* supported by the host CPU.
|
||||
*
|
||||
* Note: this class is structured to process an entire float array, versus processing one sample at a time from the
|
||||
* array.
|
||||
*/
|
||||
public class RealHalfBandDecimationFilter implements IRealDecimationFilter
|
||||
{
|
||||
private static final float CENTER_COEFFICIENT = 0.5f;
|
||||
private float[] mCoefficients;
|
||||
private float[] mBuffer;
|
||||
private float mAccumulator;
|
||||
private int mCoefficientPointer;
|
||||
private int mCoefficientsLengthMinus1;
|
||||
private int mBufferPointer;
|
||||
private int mHalf;
|
||||
|
||||
/**
|
||||
* Creates a half band filter with inherent decimation by two.
|
||||
*
|
||||
* @param coefficients of the half-band filter that is odd-length where all odd index coefficients are
|
||||
* zero valued except for the middle odd index coefficient which should be valued 0.5
|
||||
*/
|
||||
public RealHalfBandDecimationFilter(float[] coefficients)
|
||||
{
|
||||
if((coefficients.length + 1) % 4 != 0)
|
||||
{
|
||||
throw new IllegalArgumentException("Half-band filter coefficients must be odd-length and symmetrical (length = [x * 4 + 1]");
|
||||
}
|
||||
|
||||
mCoefficients = coefficients;
|
||||
mCoefficientsLengthMinus1 = mCoefficients.length - 1;
|
||||
mHalf = mCoefficientsLengthMinus1 / 2;
|
||||
}
|
||||
|
||||
public float[] decimateReal(float[] samples)
|
||||
{
|
||||
if(samples.length % 2 != 0)
|
||||
{
|
||||
throw new IllegalArgumentException("Samples array length must be an integer multiple of 2");
|
||||
}
|
||||
|
||||
int bufferLength = samples.length + mCoefficientsLengthMinus1;
|
||||
|
||||
if(mBuffer == null)
|
||||
{
|
||||
mBuffer = new float[bufferLength];
|
||||
}
|
||||
else if(mBuffer.length != bufferLength)
|
||||
{
|
||||
float[] temp = new float[bufferLength];
|
||||
//Move residual samples from end of old buffer to the beginning of the new temp buffer
|
||||
System.arraycopy(mBuffer, mBuffer.length - mCoefficientsLengthMinus1, temp, 0, mCoefficientsLengthMinus1);
|
||||
mBuffer = temp;
|
||||
}
|
||||
else
|
||||
{
|
||||
//Move residual samples from end of buffer to the beginning of the buffer
|
||||
System.arraycopy(mBuffer, samples.length, mBuffer, 0, mCoefficientsLengthMinus1);
|
||||
}
|
||||
|
||||
//Copy new sample array into end of buffer
|
||||
System.arraycopy(samples, 0, mBuffer, mCoefficientsLengthMinus1, samples.length);
|
||||
|
||||
float[] filtered = new float[samples.length / 2];
|
||||
|
||||
for(mBufferPointer = 0; mBufferPointer < samples.length; mBufferPointer += 2)
|
||||
{
|
||||
mAccumulator = 0.0f;
|
||||
|
||||
for(mCoefficientPointer = 0; mCoefficientPointer < mHalf; mCoefficientPointer += 2)
|
||||
{
|
||||
//Half band filter coefficients are mirrored, so we add the mirrored samples and then multiply by
|
||||
//one of the coefficients to achieve the same effect.
|
||||
mAccumulator += mCoefficients[mCoefficientPointer] *
|
||||
(mBuffer[mBufferPointer + mCoefficientPointer] +
|
||||
mBuffer[mBufferPointer + (mCoefficientsLengthMinus1 - mCoefficientPointer)]);
|
||||
}
|
||||
|
||||
mAccumulator += mBuffer[mBufferPointer + mHalf] * CENTER_COEFFICIENT;
|
||||
|
||||
filtered[mBufferPointer / 2] = mAccumulator;
|
||||
}
|
||||
|
||||
return filtered;
|
||||
}
|
||||
}
|
||||
@@ -1,18 +1,21 @@
|
||||
/*******************************************************************************
|
||||
* sdr-trunk
|
||||
* Copyright (C) 2014-2018 Dennis Sheirer
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2021 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public
|
||||
* License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any
|
||||
* later version.
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
|
||||
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with this program.
|
||||
* If not, see <http://www.gnu.org/licenses/>
|
||||
*
|
||||
******************************************************************************/
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
* ****************************************************************************
|
||||
*/
|
||||
package io.github.dsheirer.dsp.gain;
|
||||
|
||||
import io.github.dsheirer.buffer.FloatCircularBuffer;
|
||||
@@ -78,7 +81,7 @@ public class ComplexFeedForwardGainControl implements ComplexSampleListener
|
||||
}
|
||||
|
||||
/* Replace oldest envelope value with current envelope value */
|
||||
float oldestEnvelope = mEnvelopeHistory.get(envelope);
|
||||
float oldestEnvelope = mEnvelopeHistory.getAndPut(envelope);
|
||||
|
||||
/* If the oldest envelope value was the max envelope value, then we
|
||||
* have to rediscover the max value from the envelope history */
|
||||
|
||||
Reference in New Issue
Block a user