Skip to content

Commit

Permalink
Adds support for power-of-2 decimation for both real and complex samp…
Browse files Browse the repository at this point in the history
…le 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>
  • Loading branch information
DSheirer and Dennis Sheirer committed Dec 31, 2021
1 parent 5d9d232 commit 2a0427c
Show file tree
Hide file tree
Showing 33 changed files with 1,795 additions and 182 deletions.
71 changes: 34 additions & 37 deletions src/main/java/io/github/dsheirer/buffer/FloatCircularBuffer.java
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -25,13 +26,12 @@
* 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.
Expand Down Expand Up @@ -61,25 +61,27 @@ public float[] getBuffer()
}

/**
* 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];

mBuffer[mBufferPointer] = newValue;

mBufferPointer++;

if(mBufferPointer >= mBuffer.length)
{
mBufferPointer = 0;
}
mOldestSample = mBuffer[mBufferPointer];
put(newValue);
return mOldestSample;
}

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()
Expand Down Expand Up @@ -109,12 +111,7 @@ public float[] getAll()
public void put(float newValue)
{
mBuffer[mBufferPointer] = newValue;

mBufferPointer++;

if(mBufferPointer >= mBuffer.length)
{
mBufferPointer = 0;
}
mBufferPointer %= mBuffer.length;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -1004,7 +1004,7 @@ public static float[] getKaiserSinc(int length, double cutoff, double attenuatio
* @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)
{
Expand All @@ -1013,7 +1013,7 @@ public static double[] getHalfBand(int length, Window.WindowType windowType)
}

double[] window = Window.getWindow(windowType, length);
double[] taps = new double[length];
float[] taps = new float[length];

int halfLength = length / 2;

Expand Down Expand Up @@ -1053,7 +1053,7 @@ public static void main(String[] args)

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++)
{
Expand Down
6 changes: 6 additions & 0 deletions src/main/java/io/github/dsheirer/dsp/filter/Window.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import org.slf4j.LoggerFactory;

import java.util.Arrays;
import java.util.EnumSet;

/**
* Window factory and corresponding utility methods.
Expand Down Expand Up @@ -484,12 +485,17 @@ public enum WindowType
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);
Expand Down
Original file line number Diff line number Diff line change
@@ -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));
}
}
Original file line number Diff line number Diff line change
@@ -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));
}
}
Original file line number Diff line number Diff line change
@@ -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));
}
}
Original file line number Diff line number Diff line change
@@ -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 comments on commit 2a0427c

Please sign in to comment.