public void Transform2D() { // Transform forward and inverse and compare with initial values. var random = new Random(1234567); var s = new Vector2F[16, 8]; var t = new Vector2F[16, 8]; for (int i = 0; i < s.GetLength(0); i++) { for (int j = 0; j < s.GetLength(1); j++) { s[i, j] = random.NextVector2F(-10, 10); t[i, j] = s[i, j]; } } var fft = new FastFourierTransformF(16); fft.Transform2D(t, true); Assert.IsFalse(Vector2F.AreNumericallyEqual(s[0, 0], t[0, 0])); fft.Transform2D(t, false); for (int i = 0; i < s.GetLength(0); i++) { for (int j = 0; j < s.GetLength(1); j++) { Assert.IsTrue(Vector2F.AreNumericallyEqual(s[i, j], t[i, j])); } } }
public void Transform2DArguments() { var fft = new FastFourierTransformF(16); Assert.Throws <ArgumentNullException>(() => fft.Transform2D(null, true)); // Senseless. Assert.Throws <ArgumentException>(() => fft.Transform2D(new Vector2F[0, 0], true)); // Not POT. Assert.Throws <ArgumentException>(() => fft.Transform2D(new Vector2F[13, 2], true)); Assert.Throws <ArgumentException>(() => fft.Transform2D(new Vector2F[2, 6], true)); // Too large for capacity. Assert.Throws <ArgumentException>(() => fft.Transform2D(new Vector2F[32, 6], true)); fft.Transform2D(new Vector2F[1, 1], true); // This is ok. fft.Transform2D(new Vector2F[2, 4], true); fft.Transform2D(new Vector2F[16, 1], false); }
public void Transform1DAs2DColumn() { // Result of 2D with one row/column must be the same as 1D. var fft = new FastFourierTransformF(16); var random = new Random(1234567); var s1D = new Vector2F[16]; var s2D = new Vector2F[16, 1]; for (int i = 0; i < s1D.Length; i++) { s1D[i] = random.NextVector2F(-10, 10); s2D[i, 0] = s1D[i]; } FastFourierTransformF.Transform1D(s1D, true); fft.Transform2D(s2D, true); for (int i = 0; i < s1D.Length; i++) Assert.AreEqual(s1D[i], s2D[i, 0]); }
public void Transform1DAs2DRow() { // Result of 2D with one row/column must be the same as 1D. var fft = new FastFourierTransformF(16); var random = new Random(1234567); var s1D = new Vector2F[8]; var s2D = new Vector2F[1, 8]; for (int i = 0; i < s1D.Length; i++) { s1D[i] = random.NextVector2F(-10, 10); s2D[0, i] = s1D[i]; } FastFourierTransformF.Transform1D(s1D, true); fft.Transform2D(s2D, true); for (int i = 0; i < s1D.Length; i++) { Assert.AreEqual(s1D[i], s2D[0, i]); } }
private void PerformCpuFft(float time) { // Compute _h. int n = CpuSize; for (int x = -n / 2; x < n / 2; x++) { for (int y = -n / 2; y < n / 2; y++) { var indexX = GetIndex(x, n); var indexY = GetIndex(y, n); // The frequency domain images have a different order: var fftIndexX = x & (n - 1); var fftIndexY = y & (n - 1); var k = new Vector2F(GetKx(x), GetKy(y)); //float omega = GetOmega(water, k.Length); float omega = _omega[indexX, indexY]; // h = h0(x, y) * e^(i * omega * t) + conj(h0(-x, -y)) * e^(-i * omega * t). float cos = (float)Math.Cos(omega * time); float sin = (float)Math.Sin(omega * time); // conj(Z) = Z.Re - i * Z.Im. // e^(ix) = cos(x) + i * sin(x) // e^(-ix) = cos(x) - i * sin(x) // Multiplication of two complex: (a + ib) * (c + id) = (ac - bd) + i(ad + bc) // --> h.Re = h0(x, y).Re * cos - h0(x, y).Im *sin + h0(-x, -y).Re * cos - h0(-x, -y).Im * sin // h.Im = h0(x, y).Re * sin + h0(x, y).Im * cos - h0(-x, -y).Re * sin - h0(-x, -y).Im * cos var h0XY = _h0[indexX, indexY] * HeightScale; var h0NegXNegY = _h0[GetIndex(-x, n), GetIndex(-y, n)] * HeightScale; var h = new Vector2F((h0XY.X + h0NegXNegY.X) * cos - (h0XY.Y + h0NegXNegY.Y) * sin, (h0XY.X - h0NegXNegY.X) * sin + (h0XY.Y - h0NegXNegY.Y) * cos); _h[fftIndexX, fftIndexY] = h; // For normals, we have to perform inverse FFT for normal.X and normal.Y. // normal.x = InverseFFT(-i * k.x / kLength * h).Re // normal.y = InverseFFT(-i * k.y / kLength * h).Re // However, since FFT is linear and normal.X/Y are real (imaginary values are 0), // we can combine them into a single FFT: // FFT(Nx) = SpectrumNx, FFT(Ny) = SpectrumNy // Add and multiply by any constant, e.g. i! // FFT(Nx + i * Ny) = SpectrumNx + i * SpectrumNy // Nx + i * Ny = InverseFFT(SpectrumNx + i * SpectrumNy) // SpectrumNx = i * k.X * h = i * (k.X * h.Re + i * k.X * h.Im) = -k.X * h.Im + i * k.X * h.Re // i * SpectrumNy = i * i * k.Y * h = -1 * (k.Y * h.Re + i * k.Y * h.Im) _N[fftIndexX, fftIndexY] = new Vector2F(-k.X * h.Y - k.Y * h.X, k.X * h.X - k.Y * h.Y); // Horizontal displacements for choppy waves: // Again we combine the x and y displacement into one FFT. // D.x = InverseFFT(-i * k.x / kLength * h).Re // D.y = InverseFFT(-i * k.y / kLength * h).Re k *= _oneOverKLength[indexX, indexY]; _D[fftIndexX, fftIndexY] = new Vector2F(k.X * h.Y + k.Y * h.X, -k.X * h.X + k.Y * h.Y); } } // Transform data from frequency domain to spatial domain. if (_fft == null) _fft = new FastFourierTransformF(n); else if (_fft.Capacity < n) _fft.Capacity = n; _fft.Transform2D(_h, false); _fft.Transform2D(_D, false); _fft.Transform2D(_N, false); }
public void Transform2DArguments() { var fft = new FastFourierTransformF(16); Assert.Throws<ArgumentNullException>(() => fft.Transform2D(null, true)); // Senseless. Assert.Throws<ArgumentException>(() => fft.Transform2D(new Vector2F[0, 0], true)); // Not POT. Assert.Throws<ArgumentException>(() => fft.Transform2D(new Vector2F[13, 2], true)); Assert.Throws<ArgumentException>(() => fft.Transform2D(new Vector2F[2, 6], true)); // Too large for capacity. Assert.Throws<ArgumentException>(() => fft.Transform2D(new Vector2F[32, 6], true)); fft.Transform2D(new Vector2F[1, 1], true); // This is ok. fft.Transform2D(new Vector2F[2, 4], true); fft.Transform2D(new Vector2F[16, 1], false); }
public void Transform2D() { // Transform forward and inverse and compare with initial values. var random = new Random(1234567); var s = new Vector2F[16, 8]; var t = new Vector2F[16, 8]; for (int i = 0; i < s.GetLength(0); i++) { for (int j = 0; j < s.GetLength(1); j++) { s[i, j] = random.NextVector2F(-10, 10); t[i, j] = s[i, j]; } } var fft = new FastFourierTransformF(16); fft.Transform2D(t, true); Assert.IsFalse(Vector2F.AreNumericallyEqual(s[0, 0], t[0, 0])); fft.Transform2D(t, false); for (int i = 0; i < s.GetLength(0); i++) for (int j = 0; j < s.GetLength(1); j++) Assert.IsTrue(Vector2F.AreNumericallyEqual(s[i, j], t[i, j])); }