/// <summary> /// Performs the DFT -- converting a 2D position-domain signal into a 2D frequency-domain signal. /// </summary> /// <param name="samples"> /// The samples from an input signal. /// </param> /// <param name="outResult"> /// The output array. /// If it's null or the wrong size, it will be automatically created. /// Contains the sine/cosine wave amplitudes for each frequency in the signal. /// </param> public static void Forward(Complex[,] samples, ref Complex[,] outResult) { //Make sure the output array is the right size. if (outResult == null || outResult.GetLength(0) != samples.GetLength(0) || outResult.GetLength(1) != samples.GetLength(1)) { outResult = new Complex[samples.GetLength(0), samples.GetLength(1)]; } //Perform the 1D DFT along every row and column. //Row: Complex[][] dftByRow = new Complex[samples.GetLength(1)][]; ThreadedRunner.Run(NThreads, samples.GetLength(1), (startY, endY) => { Complex[] sampleLine = new Complex[samples.GetLength(0)]; for (int sampleY = startY; sampleY <= endY; ++sampleY) { //Populate the sample array. for (int sampleX = 0; sampleX < samples.GetLength(0); ++sampleX) { sampleLine[sampleX] = samples[sampleX, sampleY]; } //Run the dft. dftByRow[sampleY] = Algo1D.Forward(sampleLine); } }); //Column: var _outResult = outResult; //ref variables can't be used inside a lambda. ThreadedRunner.Run(NThreads, samples.GetLength(0), (startX, endX) => { Complex[] sampleLine = new Complex[samples.GetLength(1)]; for (int sampleX = startX; sampleX <= endX; ++sampleX) { //Populate the sample array. for (int sampleY = 0; sampleY < samples.GetLength(1); ++sampleY) { sampleLine[sampleY] = dftByRow[sampleY][sampleX]; } //Run the dft. var results = Algo1D.Forward(sampleLine); for (int sampleY = 0; sampleY < samples.GetLength(1); ++sampleY) { _outResult[sampleX, sampleY] = results[sampleY]; } } }); }
/// <summary> /// Performs the inverse DFT -- converting a frequency-domain signal /// back into a 2D position-domain signal. /// </summary> /// <param name="dftResults"> /// The frequency-domain signal. /// </param> /// <param name="outSamples"> /// The position-domain signal samples. /// If the array is null or the wrong size, it will be automatically created. /// </param> public static void Inverse(Complex[,] dftResults, ref Complex[,] outSamples) { //Make sure the output array is the right size. if (outSamples == null || outSamples.GetLength(0) != dftResults.GetLength(0) || outSamples.GetLength(1) != dftResults.GetLength(1)) { outSamples = new Complex[dftResults.GetLength(0), dftResults.GetLength(1)]; } //Perform the 1D inverse DFT along each row/column. //Column: Complex[][] inverseDFTByCol = new Complex[dftResults.GetLength(0)][]; ThreadedRunner.Run(NThreads, dftResults.GetLength(0), (startX, endX) => { Complex[] sampleLine = new Complex[dftResults.GetLength(1)]; for (int sampleX = startX; sampleX <= endX; ++sampleX) { //Populate the sample array. for (int sampleY = 0; sampleY < dftResults.GetLength(1); ++sampleY) { sampleLine[sampleY] = dftResults[sampleX, sampleY]; } //Run the dft. inverseDFTByCol[sampleX] = Algo1D.Inverse(sampleLine); } }); //Row: var _outSamples = outSamples; //Can't use a ref variable in a lambda. ThreadedRunner.Run(NThreads, dftResults.GetLength(1), (startY, endY) => { Complex[] sampleLine = new Complex[dftResults.GetLength(0)]; for (int sampleY = startY; sampleY <= endY; ++sampleY) { //Populate the sample array. for (int sampleX = 0; sampleX < dftResults.GetLength(0); ++sampleX) { sampleLine[sampleX] = inverseDFTByCol[sampleX][sampleY]; } //Run the dft. var results = Algo1D.Inverse(sampleLine); for (int sampleX = 0; sampleX < dftResults.GetLength(0); ++sampleX) { _outSamples[sampleX, sampleY] = results[sampleX]; } } }); }