package cquest; //------------------------------------------------------------------------ // FID.java //------------------------------------------------------------------------ // // HISTORY : //------------------------------------------------------------------------ // 18-05-09|H. Ratiney | adaptation for dquest only //------------------------------------------------------------------------ /** This class instances objects which store the FIDs (or echoes). * @author cc * @version 1.0 */ import java.io.Serializable; import fft.Fft; public class FID implements Cloneable, Serializable { // ------------------------------------------------------------------------ // variables // ------------------------------------------------------------------------ // final int REAL = 0; final int IMAG = 1; /** Name of the FID (filename) */ public String name = ""; /** To store the FID or echo (time domain) */ private double[][] signal; /** To store the FID or echo (time domain) */ private float[][] signalApoView; /** * To store the fourier tranform of the signal with view enhancement * (frequency domain) */ private float[][] fft; /** To store the Fourier Transform of the signal(absolute) */ private double[] specAbs; private int signalLength = 0; private int fftLength = 0; /** Old frequency shift of fft in Hz (used for CANCEL). */ public double oldFrequencyShift = 0; /** Frequency shift of fft in Hz. */ public double frequencyShift = 0; /** minimum value of the FFT (real part) */ private double minSpecR; /** maximum value of the FFT (real part) */ private double maxSpecR; /** minimum value of the FFT (imaginary part) */ private double minSpecI; /** maximum value of the FFT (imaginary part) */ private double maxSpecI; /** minimum value of the FFT (imaginary part) */ private double minSpecA; /** maximum value of the FFT (imaginary part) */ private double maxSpecA; /** minimum value of the Signal (real part) */ private double minSigR; /** maximum value of the Signal (real part) */ private double maxSigR; /** minimum value of the Signal (imaginary part) */ private double minSigI; /** maximum value of the Signal (imaginary part) */ private double maxSigI; /** minimum value of the Signal (imaginary part) */ private double minSigA; /** maximum value of the Signal (imaginary part) */ private double maxSigA; /** calculation time for the quantitation (ms) */ public long calculationTime; /** contains the sampling interval (ms); necessary to calculate phases */ public double samplingInterval; /** Number of truncated points */ public int truncatedPoints; /** Contains the total amplitude of the suppressed components (SVDFILTER) */ private double amplOfSuppressedComp = 0; public int med = 0; // Think it's the index with max abs value public int medspec = 0; // ------------------------------------------------------------------------ // Constructor // ------------------------------------------------------------------------ /** * Takes the time domain signal and calculates the FFT. * * @param zero * order phase * @author H. Ratiney */ public FID(double[][] dataFID) { this.signal = dataFID; this.signalLength = signal[0].length; setMinMaxSignal(); } public FID(float[][] dataFID) { this.signal = floatToDouble(dataFID); this.signalLength = signal[0].length; setMinMaxSignal(); } // ------------------------------------------------------------------------ // Methods // ------------------------------------------------------------------------ protected double[][] getSignal() { return signal; } // ------------------------------------------------------------------------ protected void setSignal(double[][] sig) { this.signal = sig; this.signalLength = signal[0].length; } // ------------------------------------------------------------------------ protected double[][] getSignalApoView() { return floatToDouble(signalApoView); } // ------------------------------------------------------------------------ protected double[][] getFft() { return floatToDouble(fft); } // ------------------------------------------------------------------------ public int getSignalLength() { return signalLength; } // ------------------------------------------------------------------------ public int getFftLength() { return fftLength; } // ------------------------------------------------------------------------ /** * To get the name of the FID. * * @return The name of the fid * @author MJanssen */ public String GetName() { return name; } // ------------------------------------------------------------------- /** * To set a new name for the FID * * @param new * name for the fid * @author MJanssen */ public void SetName(String name) { this.name = name; } // ------------------------------------------------------------------- /** * to provide the min value of the FFT (real part) * * @author H. Ratiney * @return the min value of the FFT (real part) */ public double GetMinReal() { return minSpecR; } // ------------------------------------------------------------------- /** * to provide the min value of the FID (real part) * * @author H. Ratiney * @return the min value of the FID (real part) */ public double GetMinRealS() { return minSigR; } // ------------------------------------------------------------------- /** * to provides the min value of the FFT (imaginary part) * * @author H. Ratiney * @return the min value of the FFT (imaginary part) */ public double GetMinImag() { return minSpecI; } // ------------------------------------------------------------------- /** * to provides the min value of the FID (imaginary part) * * @author H. Ratiney * @return the min value of the FID (imaginary part) */ public double GetMinImagS() { return minSigI; } // ------------------------------------------------------------------- /** * to provides the min value of the FFT (imaginary part) * * @author H. Ratiney * @return the min value of the FFT (imaginary part) */ public double GetMinAbs() { return minSpecA; } // ------------------------------------------------------------------- /** * to provides the min value of the FID (imaginary part) * * @author H. Ratiney * @return the min value of the FID (absolute) */ public double GetMinAbsS() { return minSigA; } // ------------------------------------------------------------------- /** * to provide the max value of the FFT (real part) * * @author H. Ratiney * @return the max value of the FFT (real part) */ public double GetMaxReal() { return maxSpecR; } // ------------------------------------------------------------------- /** * to provide the max value of the FID (real part) * * @author H. Ratiney * @return the max value of the FID (real part) */ public double GetMaxRealS() { return maxSigR; } // ------------------------------------------------------------------- /** * to provide the max value of the FFT (imaginary part) * * @author H. Ratiney * @return the max value of the FFT (imaginary part) */ public double GetMaxImag() { return maxSpecI; } // ------------------------------------------------------------------- /** * to provide the max value of the FID (imaginary part) * * @author H. Ratiney * @return the max value of the FID (imaginary part) */ public double GetMaxImagS() { return maxSigI; } // ------------------------------------------------------------------- /** * to provide the max value of the FFT (imaginary part) * * @author H. Ratiney * @return the max value of the FFT (abolute) */ public double GetMaxAbs() { return maxSpecA; } // ------------------------------------------------------------------- /** * to provide the max value of the FID (imaginary part) * * @author H. Ratiney * @return the max value of the FID (absolute part) */ public double GetMaxAbsS() { return maxSigA; } // ------------------------------------------------------------------- /** * to provide the index of the max value the absolute FFT * * @author H.Ratiney * @return the index corresponding to the max value of the FFT */ public int GetMaxIndexSpec() { return medspec; } // ------------------------------------------------------------------ /** * to provide the absolute FFT signal * * @author H.Ratiney * @return the FFT (absolute) */ public double[] GetMaxFFTAbs() { return specAbs; } /** * to provide the absolute values of the signal * * @author D.Stefan * @return the absolute values of the signal */ public double[] getAbsoluteSignal() { double[] absoluteSignalValues = new double[signal[REAL].length]; for (int i = 0; i < signal[REAL].length; i++) { absoluteSignalValues[i] = signal[REAL][i] * signal[REAL][i] + signal[IMAG][i] * signal[IMAG][i]; } return absoluteSignalValues; } // ------------------------------------------------------------------- /** * To get the array index of the maximum absolute value in this FID. * * @author H. Ratiney * @return the max value of the FID (absolute part) */ public int getMaxIndex() { int maxIndex = 0; double max = 0; for (int i = 0; i < signal[REAL].length; i++) { if (signal[REAL][i] * signal[REAL][i] + signal[IMAG][i] * signal[IMAG][i] > max) { max = signal[REAL][i] * signal[REAL][i] + signal[IMAG][i] * signal[IMAG][i]; maxIndex = i; } } return maxIndex; } // ------------------------------------------------------------------- /** * To get the total amplitude of peaks that were suppressed by a filter * (SVDFILTER!) * * @author Y. Coenradie * @return the total amplitude of peaks that were suppressed by a filter * (SVDFILTER!) */ public double getAmplOfSuppressedComp() { return amplOfSuppressedComp; } // ------------------------------------------------------------------- /** * To set the total amplitude of peaks that were suppressed by a filter * (HLSVDFILTER2!) * * @author Y. Coenradie * @param amplOfSupressedComp * the total amplitude of peaks that were suppressed by a filter * (HLSVDFILTER2!) */ public void setAmplOfSuppressedComp(double amplOfSuppressedComp) { this.amplOfSuppressedComp = amplOfSuppressedComp; } // ------------------------------------------------------------------- /** * To reconstruct the Spectrum to display with the view-enhancing options: * phase, apodize, zerofilling. * * @param Zero * Order Phase (fraction: -0.5 - 0.5) * @param Begin * Time (ms) * @param Apodize * (Hz) * @param ZeroFilling * (-) * @author MJanssen * @author HRatiney */ public void constructSpectrum(double zeroOrderPhase, double beginTime, double apodize, int zeroFilling, boolean areEchoes) { if (samplingInterval == 0) samplingInterval = 1; double twopi = 2 * Math.PI; double apoapo; apoapo = apodize * samplingInterval / 1000.0; // Load the signal in a temp variable signalApoView = new float[2][signal[REAL].length]; fft = new float[2][signal[REAL].length + zeroFilling]; // Apodize the signal and leave the zeros at the end of this temporary fft // Lorentzian: signal*exp(-(i-mean)*apodize*samplingInterval/1000) float factor; if (areEchoes) { int mean = getMaxIndex(); for (int i = 0; i < mean; i++) { factor = (float) Math.exp(((double) (i - mean) * apoapo)); if (factor > 1) System.out.println("apoapo : " + apoapo + " factor : " + factor + " mean : " + mean); fft[REAL][i] = (float) signal[REAL][i] * factor; fft[IMAG][i] = (float) signal[IMAG][i] * factor; signalApoView[REAL][i] = fft[REAL][i]; signalApoView[IMAG][i] = fft[IMAG][i]; } for (int i = mean; i < signal[0].length; i++) { factor = (float) Math.exp(-((double) (i - mean) * apoapo)); if (factor > 1) System.out.println("apoapo : " + apoapo + " factor : " + factor + " mean : " + mean); fft[REAL][i] = (float) signal[REAL][i] * factor; fft[IMAG][i] = (float) signal[IMAG][i] * factor; signalApoView[REAL][i] = fft[REAL][i]; signalApoView[IMAG][i] = fft[IMAG][i]; } } else { for (int i = 0; i < signal[0].length; i++) { factor = (float) Math.exp(-((double) (i) * apoapo)); if (factor > 1) System.out.println("apoapo : " + apoapo + " factor : " + factor); fft[REAL][i] = (float) signal[REAL][i] * factor; fft[IMAG][i] = (float) signal[IMAG][i] * factor; signalApoView[REAL][i] = fft[REAL][i]; signalApoView[IMAG][i] = fft[IMAG][i]; } } // Calculate the FFT Fft fftw = new Fft(); fft = doubleToFloat(fftw.direct_1D_Estim_fft(floatToDouble(fft))); this.fftLength = fft[0].length; double[] specAbs = new double[fft[0].length]; // Phase the FFT double[] temp = new double[fft[0].length]; for (int j = 0; j < fft[0].length; j++) temp[j] = (-0.5 + (double) (j) / fft[0].length) / samplingInterval; // Because beginTime & samplinginterval are in ms no factor 1000 is needed /* * If the signals are Echoes, the beginTime is summed with the maxIndex of * the signal * samplingInterval. */ // if(areEchoes) // beginTime-= mean*samplingInterval; minSpecI = 1e100; minSpecR = 1e100; minSpecA = 1e100; maxSpecI = -1e100; maxSpecR = -1e100; maxSpecA = -1e100; medspec = 0; double tempR, tempI, tempA; double sin, cos; for (int i = 0; i < fft[0].length; i++) { cos = Math.cos(twopi * (zeroOrderPhase + beginTime * temp[i])); sin = Math.sin(twopi * (zeroOrderPhase + beginTime * temp[i])); tempR = fft[REAL][i] * cos + fft[IMAG][i] * sin; tempI = -fft[REAL][i] * sin + fft[IMAG][i] * cos; fft[REAL][i] = (float) tempR; fft[IMAG][i] = (float) tempI; tempA = Math.sqrt(tempR * tempR + tempI * tempI); specAbs[i] = tempA; if (minSpecR > tempR) minSpecR = tempR; if (minSpecI > tempI) minSpecI = tempI; if (minSpecA > tempA) minSpecA = tempA; if (maxSpecR < tempR) maxSpecR = tempR; if (maxSpecI < tempI) maxSpecI = tempI; if (maxSpecA < tempA) { maxSpecA = tempA; medspec = i; } } } // ------------------------------------------------------------------- /** To calculate the min and max values in the fid. */ public void setMinMaxSignal() { minSigI = 1e100; minSigR = 1e100; minSigA = 1e100; maxSigI = -1e100; maxSigR = -1e100; maxSigA = -1e100; med = 0; double tempReal, tempImag, tempAbs; for (int i = 0; i < signal[0].length; i++) { tempReal = signal[REAL][i]; tempImag = signal[IMAG][i]; tempAbs = Math.sqrt(tempReal * tempReal + tempImag * tempImag); if (minSigR > tempReal) minSigR = tempReal; if (minSigI > tempImag) minSigI = tempImag; if (minSigA > tempAbs) minSigA = tempAbs; if (maxSigR < tempReal) maxSigR = tempReal; if (maxSigI < tempImag) maxSigI = tempImag; if (maxSigA < tempAbs) { maxSigA = tempAbs; med = i; } } } // ------------------------------------------------------------------- /** * This method performs a frequency shift (in Hz) of the fft by phasing the * fid. NOTE: the argument is a relative value! */ public void frequencyShift(double shift) { this.frequencyShift = this.frequencyShift + shift; int length = signal[0].length; double[][] shiftedFFT = new double[2][length]; double tempR, tempI; double sin, cos; double twopi = 2 * Math.PI; for (int i = 0; i < signal[0].length; i++) { cos = Math.cos(-twopi * shift * i * samplingInterval / 1000); sin = Math.sin(-twopi * shift * i * samplingInterval / 1000); tempR = signal[REAL][i] * cos + signal[IMAG][i] * sin; tempI = -signal[REAL][i] * sin + signal[IMAG][i] * cos; signal[REAL][i] = tempR; signal[IMAG][i] = tempI; } } // ------------------------------------------------------------------- /** This method performs a time shift (in points) of the FID */ public void timeShift(double nbPoints) { double[][] temp = new double[2][(signal[REAL].length)]; for (int i = 0; i < signal[REAL].length; i++) { temp[REAL][i] = signal[REAL][((int) (signal[REAL].length + i + nbPoints) % signal[REAL].length)]; temp[IMAG][i] = signal[IMAG][((int) (signal[REAL].length + i + nbPoints) % signal[REAL].length)]; } signal = temp; } // ------------------------------------------------------------------- private float[][] doubleToFloat(double[][] d) { float[][] f = new float[2][d[0].length]; for (int i = 0; i < f[0].length; i++) { f[REAL][i] = (float) d[REAL][i]; f[IMAG][i] = (float) d[IMAG][i]; } return f; } // ------------------------------------------------------------------- private double[][] floatToDouble(float[][] f) { double[][] d = new double[2][f[0].length]; for (int i = 0; i < d[0].length; i++) { d[REAL][i] = (double) f[REAL][i]; d[IMAG][i] = (double) f[IMAG][i]; } return d; } // ------------------------------------------------------------------- // ------------------------------------------------------------------- public Object getCopyFIDObject() { try { return (this.clone()); } catch (CloneNotSupportedException cloneE) { System.out.println(cloneE.getMessage()); return (null); } } // ------------------------------------------------------------------- public Object clone() throws CloneNotSupportedException { // Create an initial clone of the object using the default clone method double[][] tempSig = new double[2][signal[0].length]; for (int i = 0; i < signal[0].length; i++) { tempSig[REAL][i] = signal[REAL][i]; tempSig[IMAG][i] = signal[IMAG][i]; } FID returnValue = new FID(tempSig); returnValue.SetName(new String(name)); returnValue.minSpecI = minSpecI; returnValue.minSpecR = minSpecR; returnValue.minSpecA = minSpecA; returnValue.maxSpecI = maxSpecI; returnValue.maxSpecR = maxSpecR; returnValue.maxSpecA = maxSpecA; // T.Petit 25/6/2002 to correct "before" signal in SVD preprocessing results returnValue.samplingInterval = samplingInterval; returnValue.fft = new float[2][signal[0].length]; returnValue.signalApoView = new float[2][signal[0].length]; for (int i = 0; i < signal[0].length; i++) { returnValue.fft[REAL][i] = fft[REAL][i]; returnValue.fft[IMAG][i] = fft[IMAG][i]; returnValue.signalApoView[REAL][i] = signalApoView[REAL][i]; returnValue.signalApoView[IMAG][i] = signalApoView[IMAG][i]; } return returnValue; } }