/*
* Copyright (C) 2010-2014 - Andreas Maier, Martin Berger, Maro B�gel
* CONRAD is developed as an Open Source project under the GNU General Public License (GPL).
*/
package edu.stanford.rsl.conrad.data.numeric;
import edu.emory.mathcs.jtransforms.fft.FloatFFT_1D;
import edu.stanford.rsl.conrad.utils.FFTUtil;
/**
* Class to use complex numbers in a grid structure.
* Internally float arrays are used. The real and imaginary parts are stored in an alternating manner.
* (Note: OpenCL memory management is supported but pointwise operations on the GPU will not execute complex math)
* @author akmaier / berger / boegel
*
*/
public class Grid1DComplex extends Grid1D {
public Grid1DComplex(int width) {
this(width, true);
}
public Grid1DComplex(int width, boolean extendToNextPowerOfTwo) {
super(extendToNextPowerOfTwo ? FFTUtil.getNextPowerOfTwo(width)*2 : width*2);
}
public Grid1DComplex(Grid1D grid){
this(grid,true);
}
public Grid1DComplex(Grid1D grid, boolean extendToNextPowerOfTwo){
super (extendToNextPowerOfTwo ? FFTUtil.getNextPowerOfTwo(grid.getSize()[0])*2 : grid.getSize()[0]*2);
final int inputSize = grid.getSize()[0];
for (int i=0; i < inputSize;++i){
this.setAtIndex(i, grid.getAtIndex(i));
}
}
public Grid1DComplex(Grid1DComplex grid){
this(grid, true);
}
public Grid1DComplex(Grid1DComplex grid, boolean extendToNextPowerOfTwo){
super (extendToNextPowerOfTwo ? FFTUtil.getNextPowerOfTwo(grid.getSize()[0])*2 : grid.getSize()[0]*2);
final int inputSize = grid.getSize()[0];
for (int i=0; i < inputSize;++i){
this.setRealAtIndex(i, grid.getRealAtIndex(i));
this.setImagAtIndex(i, grid.getImagAtIndex(i));
}
}
public float getAtIndex(int index){
return (float) Math.sqrt(super.getAtIndex(index*2)*super.getAtIndex(index*2)
+ super.getAtIndex(index*2+1)*super.getAtIndex(index*2+1));
}
@Override
public void multiplyAtIndex(int index, float val) {
super.multiplyAtIndex(index*2, val);
super.multiplyAtIndex(index*2+1, val);
}
public void multiplyAtIndex(int index, float real, float imag) {
float tmp_re = super.getAtIndex(index*2);
super.setAtIndex(index*2, real * super.getAtIndex(index*2) - imag * super.getAtIndex(index*2+1));
super.setAtIndex(index*2+1, imag * tmp_re + real * super.getAtIndex(index*2+1));
}
@Override
public void addAtIndex(int index, float val) {
super.addAtIndex(index*2, val);
}
public void setAtIndex(int index, float val){
super.setAtIndex(index*2,val);
super.setAtIndex(index*2+1,0);
}
public float getRealAtIndex(int index){
return super.getAtIndex(index*2);
}
public float getImagAtIndex(int index){
return super.getAtIndex(index*2+1);
}
public void setRealAtIndex(int index, float val){
super.setAtIndex(index*2,val);
}
public void setImagAtIndex(int index, float val){
super.setAtIndex(index*2+1,val);
}
public void transformForward(){
FloatFFT_1D fft = new FloatFFT_1D(getSize()[0]);
fft.complexForward(this.buffer); // TODO: Only works if we do not have an offset in the 1D grid
}
public void transformInverse(){
FloatFFT_1D fft = new FloatFFT_1D(getSize()[0]);
fft.complexInverse(this.buffer, true); // TODO: Only works if we do not have an offset in the 1D grid
}
public Grid1D getRealSubGrid(final int startIndex, final int length){
Grid1D subgrid = new Grid1D(new float [length]);
for (int i=0; i < length; ++i){
subgrid.setAtIndex(i, super.getAtIndex((startIndex+i)*2));
}
return subgrid;
}
public Grid1D getImagSubGrid(final int startIndex, final int length){
Grid1D subgrid = new Grid1D(new float [length]);
for (int i=0; i < length; ++i){
subgrid.setAtIndex(i, super.getAtIndex((startIndex+i)*2+1));
}
return subgrid;
}
public Grid1D getMagSubGrid(final int startIndex, final int length){
Grid1D subgrid = new Grid1D(new float [length]);
for (int i=0; i < length; ++i){
float real = super.getAtIndex((startIndex+i)*2);
float imag = super.getAtIndex((startIndex+i)*2+1);
subgrid.setAtIndex(i, (float)Math.sqrt(real*real + imag*imag) );
}
return subgrid;
}
public Grid1D getPhaseSubGrid(final int startIndex, final int length){
Grid1D subgrid = new Grid1D(new float [length]);
for (int i=0; i < length; ++i){
float real = super.getAtIndex((startIndex+i)*2);
float imag = super.getAtIndex((startIndex+i)*2+1);
subgrid.setAtIndex(i, (float)Math.atan(real/imag));
}
return subgrid;
}
@Override
public int[] getSize() {
return new int[] {size[0]/2};
}
}