void CheckAgainstFFTW() { if (m_FFTW_2D == null) { m_FFTW_2D = new fftwlib.FFT2D(SIGNAL_SIZE_2D, SIGNAL_SIZE_2D); m_test_CPU = new Texture2D(m_device2D, SIGNAL_SIZE_2D, SIGNAL_SIZE_2D, 1, 1, ImageUtility.PIXEL_FORMAT.RG32F, ImageUtility.COMPONENT_FORMAT.AUTO, true, false, null); m_FFTW2D_Output = new Texture2D(m_device2D, SIGNAL_SIZE_2D, SIGNAL_SIZE_2D, 1, 1, ImageUtility.PIXEL_FORMAT.RG32F, ImageUtility.COMPONENT_FORMAT.AUTO, false, true, null); } // Retrieve input as CPU-accessible m_test_CPU.CopyFrom(m_FFT2D_GPU.Input); PixelsBuffer bufferIn = m_test_CPU.MapRead(0, 0); m_test_CPU.UnMap(bufferIn); float2[,] input_GPU = new float2[SIGNAL_SIZE_2D, SIGNAL_SIZE_2D]; using (System.IO.BinaryReader R = bufferIn.OpenStreamRead()) for (int Y = 0; Y < SIGNAL_SIZE_2D; Y++) { for (int X = 0; X < SIGNAL_SIZE_2D; X++) { input_GPU[X, Y].Set(R.ReadSingle(), R.ReadSingle()); } } bufferIn.Dispose(); // Apply FFT m_FFT2D_GPU.FFT_GPUInOut(-1.0f); // Retrieve output as CPU-accessible m_test_CPU.CopyFrom(m_FFT2D_GPU.Output); PixelsBuffer bufferOut = m_test_CPU.MapRead(0, 0); m_test_CPU.UnMap(bufferOut); float2[,] output_GPU = new float2[SIGNAL_SIZE_2D, SIGNAL_SIZE_2D]; using (System.IO.BinaryReader R = bufferOut.OpenStreamRead()) for (int Y = 0; Y < SIGNAL_SIZE_2D; Y++) { for (int X = 0; X < SIGNAL_SIZE_2D; X++) { output_GPU[X, Y].Set(R.ReadSingle(), R.ReadSingle()); } } bufferOut.Dispose(); // Process input with FFTW m_FFTW_2D.FillInputSpatial((int _x, int _y, out float _r, out float _i) => { _r = input_GPU[_x, _y].x; _i = input_GPU[_x, _y].y; }); m_FFTW_2D.Execute(fftwlib.FFT2D.Normalization.DIMENSIONS_PRODUCT); float2[,] output_FFTW = new float2[SIGNAL_SIZE_2D, SIGNAL_SIZE_2D]; m_FFTW_2D.GetOutput((int _x, int _y, float _r, float _i) => { output_FFTW[_x, _y].Set(_r, _i); }); // Upload FFTW output to GPU bufferOut = m_test_CPU.MapWrite(0, 0); using (System.IO.BinaryWriter W = bufferOut.OpenStreamWrite()) for (int Y = 0; Y < SIGNAL_SIZE_2D; Y++) { for (int X = 0; X < SIGNAL_SIZE_2D; X++) { W.Write(output_FFTW[X, Y].x); W.Write(output_FFTW[X, Y].y); } } m_test_CPU.UnMap(bufferOut); bufferOut.Dispose(); m_FFTW2D_Output.CopyFrom(m_test_CPU); // Compare float sumSqDiffR = 0.0f; float sumSqDiffI = 0.0f; for (int Y = 0; Y < SIGNAL_SIZE_2D; Y++) { for (int X = 0; X < SIGNAL_SIZE_2D; X++) { float2 GPU = output_GPU[X, Y]; float2 FFTW = output_FFTW[X, Y]; float2 diff = GPU - FFTW; sumSqDiffR += diff.x * diff.x; sumSqDiffI += diff.y * diff.y; } } labelDiff2D.Text = "SqDiff = " + sumSqDiffR.ToString("G3") + " , " + sumSqDiffI.ToString("G3"); }
void TestTransform1D(double _time) { // Build the input signal Array.Clear(m_signalSource, 0, m_signalSource.Length); switch (m_signalType1D) { case SIGNAL_TYPE.SQUARE: for (int i = 0; i < SIGNAL_SIZE; i++) { m_signalSource[i].r = 0.5 * Math.Sin(_time) + ((i + 50.0 * _time) % (SIGNAL_SIZE / 2.0) < (SIGNAL_SIZE / 4.0) ? 0.5 : -0.5); } break; case SIGNAL_TYPE.SINE: for (int i = 0; i < SIGNAL_SIZE; i++) { // m_signalSource[i].r = Math.Cos( 2.0 * Math.PI * i / SIGNAL_SIZE + _time ); m_signalSource[i].r = Math.Cos((4.0 * (1.0 + Math.Sin(_time))) * 2.0 * Math.PI * i / SIGNAL_SIZE); } break; case SIGNAL_TYPE.SAW: for (int i = 0; i < SIGNAL_SIZE; i++) { m_signalSource[i].r = 0.5 * Math.Sin(_time) + ((((i + 50.0 * _time) / 128.0) % 1.0) - 0.5); } break; case SIGNAL_TYPE.SINC: for (int i = 0; i < SIGNAL_SIZE; i++) { // double a = 4.0 * (1.0 + Math.Sin( _time )) * 2.0 * Math.PI * (1+i) / SIGNAL_SIZE; // Asymmetrical double a = 4.0 * (1.0 + Math.Sin(_time)) * 2.0 * Math.PI * (i - SIGNAL_SIZE / 2.0) * 2.0 / SIGNAL_SIZE; // Symmetrical m_signalSource[i].r = Math.Abs(a) > 0.0 ? Math.Sin(a) / a : 1.0; } break; case SIGNAL_TYPE.RANDOM: for (int i = 0; i < SIGNAL_SIZE; i++) { m_signalSource[i].r = SimpleRNG.GetUniform(); } // m_signalSource[i].r = SimpleRNG.GetExponential(); // m_signalSource[i].r = SimpleRNG.GetBeta( 0.5, 1 ); // m_signalSource[i].r = SimpleRNG.GetGamma( 1.0, 0.1 ); // m_signalSource[i].r = SimpleRNG.GetCauchy( 0.0, 1.0 ); // m_signalSource[i].r = SimpleRNG.GetChiSquare( 1.0 ); // m_signalSource[i].r = SimpleRNG.GetNormal( 0.0, 0.1 ); // m_signalSource[i].r = SimpleRNG.GetLaplace( 0.0, 0.1 ); // m_signalSource[i].r = SimpleRNG.GetStudentT( 2.0 ); break; } // Transform if (m_FFTW_1D != null && checkBoxUseFFTW.Checked) { m_FFTW_1D.FillInputSpatial((int x, int y, out float r, out float i) => { r = (float)m_signalSource[x].r; i = (float)m_signalSource[x].i; }); m_FFTW_1D.Execute(fftwlib.FFT2D.Normalization.DIMENSIONS_PRODUCT); m_FFTW_1D.GetOutput((int x, int y, float r, float i) => { m_spectrum[x].Set(r, i); }); } else { // DFT1D.DFT_Forward( m_signalSource, m_spectrum ); FFT1D.FFT_Forward(m_signalSource, m_spectrum); } // Try the GPU version m_FFT1D_GPU.FFT_Forward(m_signalSource, m_spectrumGPU); // m_FFT1D_GPU.FFT_Forward( m_signalSource, m_spectrum ); double sumSqDiffR = 0.0; double sumSqDiffI = 0.0; for (int i = 0; i < m_spectrum.Length; i++) { Complex diff = m_spectrum[i] - m_spectrumGPU[i]; sumSqDiffR += diff.r * diff.r; sumSqDiffI += diff.i * diff.i; } labelDiff.Text = "SqDiff = " + sumSqDiffR.ToString("G3") + " , " + sumSqDiffI.ToString("G3"); if (m_FFTW_1D == null && checkBoxUseFFTW.Checked) { labelDiff.Text += "\r\nERROR: Can't use FFTW because of an initialization error!"; } if (checkBoxInvertFilter.Checked) { for (int i = 0; i < m_spectrum.Length; i++) { m_spectrum[i] = m_spectrumGPU[i]; } } // else // for ( int i=0; i < m_spectrum.Length; i++ ) // m_spectrum[i] *= 2.0; // Filter FilterDelegate filter = null; switch (m_filter1D) { case FILTER_TYPE.CUT_LARGE: filter = (int i, int frequency) => { return(Math.Abs(frequency) > 256 ? 0 : 1.0); }; // Cut break; case FILTER_TYPE.CUT_MEDIUM: filter = (int i, int frequency) => { return(Math.Abs(frequency) > 128 ? 0 : 1.0); }; // Cut break; case FILTER_TYPE.CUT_SHORT: filter = (int i, int frequency) => { return(Math.Abs(frequency) > 64 ? 0 : 1.0); }; // Cut break; case FILTER_TYPE.EXP: filter = (int i, int frequency) => { return(Math.Exp(-0.01f * Math.Abs(frequency))); }; // Exponential break; case FILTER_TYPE.GAUSSIAN: filter = (int i, int frequency) => { return(Math.Exp(-0.005f * frequency * frequency)); }; // Gaussian break; case FILTER_TYPE.INVERSE: filter = (int i, int frequency) => { return(Math.Min(1.0, 4.0 / (1 + Math.Abs(frequency)))); }; // Inverse break; // case FILTER_TYPE.SINUS: // filter = ( int i, int frequency ) => { return Math.Sin( -2.0f * Math.PI * frequency / 32 ); }; // Gni ? // break; } if (filter != null) { int size = m_spectrum.Length; int halfSize = size >> 1; if (!checkBoxInvertFilter.Checked) { for (int i = 0; i < size; i++) { int frequency = ((i + halfSize) % size) - halfSize; double filterValue = filter(i, frequency); m_spectrum[i] *= filterValue; } } else { for (int i = 0; i < size; i++) { int frequency = ((size - i) % size) - halfSize; double filterValue = filter(i, frequency); m_spectrum[i] *= filterValue; } } } // Inverse Transform if (m_FFTW_1D != null && checkBoxUseFFTW.Checked) { m_FFTW_1D.FillInputFrequency((int x, int y, out float r, out float i) => { r = (float)m_spectrum[x].r; i = (float)m_spectrum[x].i; }); m_FFTW_1D.Execute(fftwlib.FFT2D.Normalization.NONE); m_FFTW_1D.GetOutput((int x, int y, float r, float i) => { m_signalReconstructed[x].Set(r, i); }); } else { // DFT1D.DFT_Inverse( m_spectrum, m_signalReconstructed ); FFT1D.FFT_Inverse(m_spectrum, m_signalReconstructed); } }