
org.jtransforms.fft.RealFFTUtils_2D Maven / Gradle / Ivy
/* ***** BEGIN LICENSE BLOCK *****
* JTransforms
* Copyright (c) 2007 onward, Piotr Wendykier
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* ***** END LICENSE BLOCK ***** */
package org.jtransforms.fft;
// @formatter:off
import pl.edu.icm.jlargearrays.DoubleLargeArray;
import pl.edu.icm.jlargearrays.FloatLargeArray;
/**
*
* This is a set of utility methods for R/W access to data resulting from a call
* to the Fourier transform of real data. Memory optimized methods,
* namely
*
* - {@link DoubleFFT_2D#realForward(double[])}
* - {@link DoubleFFT_2D#realForward(DoubleLargeArray)}
* - {@link DoubleFFT_2D#realForward(double[][])}
* - {@link FloatFFT_2D#realForward(float[])}
* - {@link FloatFFT_2D#realForward(FloatLargeArray)}
* - {@link FloatFFT_2D#realForward(float[][])}
*
* are implemented to handle this case specifically. However, packing of the
* data in the data array is somewhat obscure. This class provides methods for
* direct access to the data, without the burden of all necessary tests.
* Example for Fourier Transform of real, double precision 1d data
*
*
* DoubleFFT_2D fft = new DoubleFFT_2D(rows, columns);
* double[] data = new double[2 * rows * columns];
* ...
* fft.realForwardFull(data);
* data[r1 * 2 * columns + c1] = val1;
* val2 = data[r2 * 2 * columns + c2];
*
* is equivalent to
*
* DoubleFFT_2D fft = new DoubleFFT_2D(rows, columns);
* RealFFTUtils_2D unpacker = new RealFFTUtils_2D(rows, columns);
* double[] data = new double[rows * columns];
* ...
* fft.realForward(data);
* unpacker.pack(val1, r1, c1, data);
* val2 = unpacker.unpack(r2, c2, data, 0);
*
* Even (resp. odd) values of c
correspond to the real (resp.
* imaginary) part of the Fourier mode.
* Example for Fourier Transform of real, double precision 2d data
*
*
* DoubleFFT_2D fft = new DoubleFFT_2D(rows, columns);
* double[][] data = new double[rows][2 * columns];
* ...
* fft.realForwardFull(data);
* data[r1][c1] = val1;
* val2 = data[r2][c2];
*
* is equivalent to
*
* DoubleFFT_2D fft = new DoubleFFT_2D(rows, columns);
* RealFFTUtils_2D unpacker = new RealFFTUtils_2D(rows, columns);
* double[][] data = new double[rows][columns];
* ...
* fft.realForward(data);
* unpacker.pack(val1, r1, c1, data);
* val2 = unpacker.unpack(r2, c2, data, 0);
*
* Even (resp. odd) values of c
correspond to the real (resp.
* imaginary) part of the Fourier mode.
*
* @author Sébastien Brisard
*/
// @formatter:on
public class RealFFTUtils_2D
{
/**
* The constant int
value of 1.
*/
private static final int ONE = 1;
/**
* The constant int
value of 2.
*/
private static final int TWO = 2;
/**
* The constant int
value of 0.
*/
private static final int ZERO = 0;
/**
* The constant int
value of 1.
*/
private static final long ONEL = 1;
/**
* The constant int
value of 2.
*/
private static final long TWOL = 2;
/**
* The constant int
value of 0.
*/
private static final long ZEROL = 0;
/**
* The size of the data in the second direction.
*/
private final int columns;
/**
* The size of the data in the first direction.
*/
private final int rows;
/**
* The size of the data in the second direction.
*/
private final long columnsl;
/**
* The size of the data in the first direction.
*/
private final long rowsl;
/**
* Creates a new instance of this class. The size of the underlying
* {@link DoubleFFT_2D} or {@link FloatFFT_2D} must be specified.
*
* @param rows
* number of rows
* @param columns
* number of columns
*/
public RealFFTUtils_2D(final long rows, final long columns)
{
this.columns = (int) columns;
this.rows = (int) rows;
this.columnsl = columns;
this.rowsl = rows;
}
/**
*
* Returns the 1d index of the specified 2d Fourier mode. In other words, if
* packed
contains the transformed data following a call to
* {@link DoubleFFT_2D#realForward(double[])} or
* {@link FloatFFT_2D#realForward(float[])}, then the returned value
* index
gives access to the [r][c]
Fourier mode
*
* - if
index == {@link Integer#MIN_VALUE}
, then the Fourier
* mode is zero,
* - if
index >= 0
, then the Fourier mode is
* packed[index]
,
* - if
index < 0
, then the Fourier mode is
* -packed[-index]
,
*
*
* @param r
* the row index
* @param c
* the column index
*
* @return the value of index
*/
public int getIndex(final int r, final int c)
{
final int cmod2 = c & ONE;
final int rmul2 = r << ONE;
if (r != ZERO) {
if (c <= ONE) {
if (rmul2 == rows) {
if (cmod2 == ONE) {
return Integer.MIN_VALUE;
}
return ((rows * columns) >> ONE);
} else if (rmul2 < rows) {
return columns * r + cmod2;
} else {
if (cmod2 == ZERO) {
return columns * (rows - r);
} else {
return -(columns * (rows - r) + ONE);
}
}
} else if ((c == columns) || (c == columns + ONE)) {
if (rmul2 == rows) {
if (cmod2 == ONE) {
return Integer.MIN_VALUE;
}
return ((rows * columns) >> ONE) + ONE;
} else if (rmul2 < rows) {
if (cmod2 == ZERO) {
return columns * (rows - r) + ONE;
} else {
return -(columns * (rows - r));
}
} else {
return columns * r + ONE - cmod2;
}
} else if (c < columns) {
return columns * r + c;
} else {
if (cmod2 == ZERO) {
return columns * (rows + TWO - r) - c;
} else {
return -(columns * (rows + TWO - r) - c + TWO);
}
}
} else {
if ((c == ONE) || (c == columns + ONE)) {
return Integer.MIN_VALUE;
} else if (c == columns) {
return ONE;
} else if (c < columns) {
return c;
} else {
if (cmod2 == ZERO) {
return (columns << ONE) - c;
} else {
return -((columns << ONE) - c + TWO);
}
}
}
}
/**
*
* Returns the 1d index of the specified 2d Fourier mode. In other words, if
* packed
contains the transformed data following a call to
* {@link DoubleFFT_2D#realForward(DoubleLargeArray)} or
* {@link FloatFFT_2D#realForward(FloatLargeArray)}, then the returned value
* index
gives access to the [r][c]
Fourier mode
*
* - if
index == {@link Long#MIN_VALUE}
, then the Fourier
* mode is zero,
* - if
index >= 0
, then the Fourier mode is
* packed[index]
,
* - if
index < 0
, then the Fourier mode is
* -packed[-index]
,
*
*
* @param r
* the row index
* @param c
* the column index
*
* @return the value of index
*/
public long getIndex(final long r, final long c)
{
final long cmod2 = c & ONEL;
final long rmul2 = r << ONEL;
if (r != ZERO) {
if (c <= ONEL) {
if (rmul2 == rowsl) {
if (cmod2 == ONEL) {
return Long.MIN_VALUE;
}
return ((rowsl * columnsl) >> ONEL);
} else if (rmul2 < rowsl) {
return columnsl * r + cmod2;
} else {
if (cmod2 == ZEROL) {
return columnsl * (rowsl - r);
} else {
return -(columnsl * (rowsl - r) + ONEL);
}
}
} else if ((c == columnsl) || (c == columnsl + ONEL)) {
if (rmul2 == rowsl) {
if (cmod2 == ONEL) {
return Long.MIN_VALUE;
}
return ((rowsl * columnsl) >> ONEL) + ONEL;
} else if (rmul2 < rowsl) {
if (cmod2 == ZEROL) {
return columnsl * (rowsl - r) + ONEL;
} else {
return -(columnsl * (rowsl - r));
}
} else {
return columnsl * r + ONEL - cmod2;
}
} else if (c < columnsl) {
return columnsl * r + c;
} else {
if (cmod2 == ZEROL) {
return columnsl * (rowsl + TWOL - r) - c;
} else {
return -(columnsl * (rowsl + TWOL - r) - c + TWOL);
}
}
} else {
if ((c == ONEL) || (c == columnsl + ONEL)) {
return Long.MIN_VALUE;
} else if (c == columnsl) {
return ONEL;
} else if (c < columnsl) {
return c;
} else {
if (cmod2 == ZEROL) {
return (columnsl << ONEL) - c;
} else {
return -((columnsl << ONEL) - c + TWOL);
}
}
}
}
/**
* Sets the specified Fourier mode of the transformed data. The data array
* results from a call to {@link DoubleFFT_2D#realForward(double[])}.
*
* @param val
* the new value of the [r][c]
Fourier mode
* @param r
* the row index
* @param c
* the column index
* @param packed
* the transformed data
* @param pos
* index of the first element in array packed
*/
public void pack(final double val, final int r, final int c,
final double[] packed, final int pos)
{
final int index = getIndex(r, c);
if (index >= 0) {
packed[pos + index] = val;
} else if (index > Integer.MIN_VALUE) {
packed[pos - index] = -val;
} else {
throw new IllegalArgumentException(
String.format(
"[%d][%d] component cannot be modified (always zero)",
r, c));
}
}
/**
* Sets the specified Fourier mode of the transformed data. The data array
* results from a call to {@link DoubleFFT_2D#realForward(DoubleLargeArray)}.
*
* @param val
* the new value of the [r][c]
Fourier mode
* @param r
* the row index
* @param c
* the column index
* @param packed
* the transformed data
* @param pos
* index of the first element in array packed
*/
public void pack(final double val, final long r, final long c,
final DoubleLargeArray packed, final long pos)
{
final long index = getIndex(r, c);
if (index >= 0) {
packed.setDouble(pos + index, val);
} else if (index > Long.MIN_VALUE) {
packed.setDouble(pos - index, -val);
} else {
throw new IllegalArgumentException(
String.format(
"[%d][%d] component cannot be modified (always zero)",
r, c));
}
}
/**
* Sets the specified Fourier mode of the transformed data. The data array
* results from a call to {@link DoubleFFT_2D#realForward(double[][])}.
*
* @param val
* the new value of the [r][c]
Fourier mode
* @param r
* the row index
* @param c
* the column index
* @param packed
* the transformed data
*/
public void pack(final double val, final int r, final int c,
final double[][] packed)
{
final int index = getIndex(r, c);
if (index >= 0) {
packed[index / columns][index % columns] = val;
} else if (index > Integer.MIN_VALUE) {
packed[(-index) / columns][(-index) % columns] = -val;
} else {
throw new IllegalArgumentException(
String.format(
"[%d][%d] component cannot be modified (always zero)",
r, c));
}
}
/**
* Sets the specified Fourier mode of the transformed data. The data array
* results from a call to {@link FloatFFT_2D#realForward(float[])}.
*
* @param val
* the new value of the [r][c]
Fourier mode
* @param r
* the row index
* @param c
* the column index
* @param packed
* the transformed data
* @param pos
* index of the first element in array packed
*/
public void pack(final float val, final int r, final int c,
final float[] packed, final int pos)
{
final int index = getIndex(r, c);
if (index >= 0) {
packed[pos + index] = val;
} else if (index > Integer.MIN_VALUE) {
packed[pos - index] = -val;
} else {
throw new IllegalArgumentException(
String.format(
"[%d][%d] component cannot be modified (always zero)",
r, c));
}
}
/**
* Sets the specified Fourier mode of the transformed data. The data array
* results from a call to {@link FloatFFT_2D#realForward(FloatLargeArray)}.
*
* @param val
* the new value of the [r][c]
Fourier mode
* @param r
* the row index
* @param c
* the column index
* @param packed
* the transformed data
* @param pos
* index of the first element in array packed
*/
public void pack(final float val, final long r, final long c,
final FloatLargeArray packed, final long pos)
{
final long index = getIndex(r, c);
if (index >= 0) {
packed.setFloat(pos + index, val);
} else if (index > Long.MIN_VALUE) {
packed.setFloat(pos - index, -val);
} else {
throw new IllegalArgumentException(
String.format(
"[%d][%d] component cannot be modified (always zero)",
r, c));
}
}
/**
* Sets the specified Fourier mode of the transformed data. The data array
* results from a call to {@link FloatFFT_2D#realForward(float[][])}.
*
* @param val
* the new value of the [r][c]
Fourier mode
* @param r
* the row index
* @param c
* the column index
* @param packed
* the transformed data
*/
public void pack(final float val, final int r, final int c,
final float[][] packed)
{
final int index = getIndex(r, c);
if (index >= 0) {
packed[index / columns][index % columns] = val;
} else if (index > Integer.MIN_VALUE) {
packed[(-index) / columns][(-index) % columns] = -val;
} else {
throw new IllegalArgumentException(
String.format(
"[%d][%d] component cannot be modified (always zero)",
r, c));
}
}
/**
* Returns the specified Fourier mode of the transformed data. The data
* array results from a call to {@link DoubleFFT_2D#realForward(double[])}.
*
* @param r
* the row index
* @param c
* the column index
* @param packed
* the transformed data
* @param pos
* index of the first element in array packed
*
* @return the value of the [r][c]
Fourier mode
*/
public double unpack(final int r, final int c, final double[] packed,
final int pos)
{
final int index = getIndex(r, c);
if (index >= 0) {
return packed[pos + index];
} else if (index > Integer.MIN_VALUE) {
return -packed[pos - index];
} else {
return ZERO;
}
}
/**
* Returns the specified Fourier mode of the transformed data. The data
* array results from a call to {@link DoubleFFT_2D#realForward(DoubleLargeArray)}.
*
* @param r
* the row index
* @param c
* the column index
* @param packed
* the transformed data
* @param pos
* index of the first element in array packed
*
* @return the value of the [r][c]
Fourier mode
*/
public double unpack(final long r, final long c, final DoubleLargeArray packed,
final long pos)
{
final long index = getIndex(r, c);
if (index >= 0) {
return packed.getDouble(pos + index);
} else if (index > Long.MIN_VALUE) {
return -packed.getDouble(pos - index);
} else {
return ZEROL;
}
}
/**
* Returns the specified Fourier mode of the transformed data. The data
* array results from a call to {@link DoubleFFT_2D#realForward(double[][])}
* .
*
* @param r
* the row index
* @param c
* the column index
* @param packed
* the transformed data
*
* @return the value of the [r][c]
Fourier mode
*/
public double unpack(final int r, final int c, final double[][] packed)
{
final int index = getIndex(r, c);
if (index >= 0) {
return packed[index / columns][index % columns];
} else if (index > Integer.MIN_VALUE) {
return -packed[(-index) / columns][(-index) % columns];
} else {
return ZERO;
}
}
/**
* Returns the specified Fourier mode of the transformed data. The data
* array results from a call to {@link FloatFFT_2D#realForward(float[])}
* .
*
* @param r
* the row index
* @param c
* the column index
* @param packed
* the transformed data
* @param pos
* index of the first element in array packed
*
* @return the value of the [r][c]
Fourier mode
*/
public float unpack(final int r, final int c, final float[] packed,
final int pos)
{
final int index = getIndex(r, c);
if (index >= 0) {
return packed[pos + index];
} else if (index > Integer.MIN_VALUE) {
return -packed[pos - index];
} else {
return ZERO;
}
}
/**
* Returns the specified Fourier mode of the transformed data. The data
* array results from a call to {@link FloatFFT_2D#realForward(FloatLargeArray)}
* .
*
* @param r
* the row index
* @param c
* the column index
* @param packed
* the transformed data
* @param pos
* index of the first element in array packed
*
* @return the value of the [r][c]
Fourier mode
*/
public float unpack(final long r, final long c, final FloatLargeArray packed,
final long pos)
{
final long index = getIndex(r, c);
if (index >= 0) {
return packed.getFloat(pos + index);
} else if (index > Long.MIN_VALUE) {
return -packed.getFloat(pos - index);
} else {
return ZEROL;
}
}
/**
* Returns the specified Fourier mode of the transformed data. The data
* array results from a call to {@link FloatFFT_2D#realForward(float[][])} .
*
* @param r
* the row index
* @param c
* the column index
* @param packed
* the transformed data
*
* @return the value of the [r][c]
Fourier mode
*/
public float unpack(final int r, final int c, final float[][] packed)
{
final int index = getIndex(r, c);
if (index >= 0) {
return packed[index / columns][index % columns];
} else if (index > Integer.MIN_VALUE) {
return -packed[(-index) / columns][(-index) % columns];
} else {
return ZERO;
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy