diff --git a/src/TensorFlowNET.Core/APIs/tf.signal.cs b/src/TensorFlowNET.Core/APIs/tf.signal.cs new file mode 100644 index 000000000..2471124c5 --- /dev/null +++ b/src/TensorFlowNET.Core/APIs/tf.signal.cs @@ -0,0 +1,40 @@ +/***************************************************************************** + Copyright 2023 Konstantin Balashov All Rights Reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +******************************************************************************/ + +using Tensorflow.Operations; + +namespace Tensorflow +{ + public partial class tensorflow + { + public SignalApi signal { get; } = new SignalApi(); + public class SignalApi + { + public Tensor fft(Tensor input, string name = null) + => gen_ops.f_f_t(input, name: name); + public Tensor ifft(Tensor input, string name = null) + => gen_ops.i_f_f_t(input, name: name); + public Tensor fft2d(Tensor input, string name = null) + => gen_ops.f_f_t2d(input, name: name); + public Tensor ifft2d(Tensor input, string name = null) + => gen_ops.i_f_f_t2d(input, name: name); + public Tensor fft3d(Tensor input, string name = null) + => gen_ops.f_f_t3d(input, name: name); + public Tensor ifft3d(Tensor input, string name = null) + => gen_ops.i_f_f_t3d(input, name: name); + } + } +} diff --git a/src/TensorFlowNET.Core/Operations/gen_ops.cs b/src/TensorFlowNET.Core/Operations/gen_ops.cs index c9693f055..bf178b60f 100644 --- a/src/TensorFlowNET.Core/Operations/gen_ops.cs +++ b/src/TensorFlowNET.Core/Operations/gen_ops.cs @@ -10475,10 +10475,7 @@ public static Tensor extract_jpeg_shape(Tensor contents, TF_DataType? output_typ /// public static Tensor f_f_t(Tensor input, string name = "FFT") { - var dict = new Dictionary(); - dict["input"] = input; - var op = tf.OpDefLib._apply_op_helper("FFT", name: name, keywords: dict); - return op.output; + return tf.Context.ExecuteOp("FFT", name, new ExecuteOpArgs(input)); } /// @@ -10505,10 +10502,7 @@ public static Tensor f_f_t(Tensor input, string name = "FFT") /// public static Tensor f_f_t2d(Tensor input, string name = "FFT2D") { - var dict = new Dictionary(); - dict["input"] = input; - var op = tf.OpDefLib._apply_op_helper("FFT2D", name: name, keywords: dict); - return op.output; + return tf.Context.ExecuteOp("FFT2D", name, new ExecuteOpArgs(input)); } /// @@ -10535,10 +10529,7 @@ public static Tensor f_f_t2d(Tensor input, string name = "FFT2D") /// public static Tensor f_f_t3d(Tensor input, string name = "FFT3D") { - var dict = new Dictionary(); - dict["input"] = input; - var op = tf.OpDefLib._apply_op_helper("FFT3D", name: name, keywords: dict); - return op.output; + return tf.Context.ExecuteOp("FFT3D", name, new ExecuteOpArgs(input)); } /// @@ -12861,10 +12852,7 @@ public static Tensor host_const(Tensor value, TF_DataType dtype, string name = " /// public static Tensor i_f_f_t(Tensor input, string name = "IFFT") { - var dict = new Dictionary(); - dict["input"] = input; - var op = tf.OpDefLib._apply_op_helper("IFFT", name: name, keywords: dict); - return op.output; + return tf.Context.ExecuteOp("IFFT", name, new ExecuteOpArgs(input)); } /// @@ -12891,10 +12879,7 @@ public static Tensor i_f_f_t(Tensor input, string name = "IFFT") /// public static Tensor i_f_f_t2d(Tensor input, string name = "IFFT2D") { - var dict = new Dictionary(); - dict["input"] = input; - var op = tf.OpDefLib._apply_op_helper("IFFT2D", name: name, keywords: dict); - return op.output; + return tf.Context.ExecuteOp("IFFT2D", name, new ExecuteOpArgs(input)); } /// @@ -12921,10 +12906,7 @@ public static Tensor i_f_f_t2d(Tensor input, string name = "IFFT2D") /// public static Tensor i_f_f_t3d(Tensor input, string name = "IFFT3D") { - var dict = new Dictionary(); - dict["input"] = input; - var op = tf.OpDefLib._apply_op_helper("IFFT3D", name: name, keywords: dict); - return op.output; + return tf.Context.ExecuteOp("IFFT3D", name, new ExecuteOpArgs(input)); } /// diff --git a/test/TensorFlowNET.Graph.UnitTest/SignalTest.cs b/test/TensorFlowNET.Graph.UnitTest/SignalTest.cs new file mode 100644 index 000000000..01014a102 --- /dev/null +++ b/test/TensorFlowNET.Graph.UnitTest/SignalTest.cs @@ -0,0 +1,103 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Tensorflow.NumPy; +using System; +using System.Collections.Generic; +using System.Linq; +using Tensorflow; +using static Tensorflow.Binding; +using Buffer = Tensorflow.Buffer; +using TensorFlowNET.Keras.UnitTest; + +namespace TensorFlowNET.UnitTest.Basics +{ + [TestClass] + public class SignalTest : EagerModeTestBase + { + [TestMethod] + public void fft() + { + double[] d_real = new double[] { 1.0, 2.0, 3.0, 4.0 }; + double[] d_imag = new double[] { -1.0, -3.0, 5.0, 7.0 }; + + Tensor t_real = tf.constant(d_real, dtype: TF_DataType.TF_DOUBLE); + Tensor t_imag = tf.constant(d_imag, dtype: TF_DataType.TF_DOUBLE); + + Tensor t_complex = tf.complex(t_real, t_imag); + + Tensor t_frequency_domain = tf.signal.fft(t_complex); + Tensor f_time_domain = tf.signal.ifft(t_frequency_domain); + + Tensor t_real_result = tf.math.real(f_time_domain); + Tensor t_imag_result = tf.math.imag(f_time_domain); + + NDArray n_real_result = t_real_result.numpy(); + NDArray n_imag_result = t_imag_result.numpy(); + + double[] d_real_result = n_real_result.ToArray(); + double[] d_imag_result = n_imag_result.ToArray(); + + Assert.IsTrue(base.Equal(d_real_result, d_real)); + Assert.IsTrue(base.Equal(d_imag_result, d_imag)); + } + [TestMethod] + public void fft2d() + { + double[] d_real = new double[] { 1.0, 2.0, 3.0, 4.0 }; + double[] d_imag = new double[] { -1.0, -3.0, 5.0, 7.0 }; + + Tensor t_real = tf.constant(d_real, dtype: TF_DataType.TF_DOUBLE); + Tensor t_imag = tf.constant(d_imag, dtype: TF_DataType.TF_DOUBLE); + + Tensor t_complex = tf.complex(t_real, t_imag); + + Tensor t_complex_2d = tf.reshape(t_complex,new int[] { 2, 2 }); + + Tensor t_frequency_domain_2d = tf.signal.fft2d(t_complex_2d); + Tensor t_time_domain_2d = tf.signal.ifft2d(t_frequency_domain_2d); + + Tensor t_time_domain = tf.reshape(t_time_domain_2d, new int[] { 4 }); + + Tensor t_real_result = tf.math.real(t_time_domain); + Tensor t_imag_result = tf.math.imag(t_time_domain); + + NDArray n_real_result = t_real_result.numpy(); + NDArray n_imag_result = t_imag_result.numpy(); + + double[] d_real_result = n_real_result.ToArray(); + double[] d_imag_result = n_imag_result.ToArray(); + + Assert.IsTrue(base.Equal(d_real_result, d_real)); + Assert.IsTrue(base.Equal(d_imag_result, d_imag)); + } + [TestMethod] + public void fft3d() + { + double[] d_real = new double[] { 1.0, 2.0, 3.0, 4.0, -3.0, -2.0, -1.0, -4.0 }; + double[] d_imag = new double[] { -1.0, -3.0, 5.0, 7.0, 6.0, 4.0, 2.0, 0.0}; + + Tensor t_real = tf.constant(d_real, dtype: TF_DataType.TF_DOUBLE); + Tensor t_imag = tf.constant(d_imag, dtype: TF_DataType.TF_DOUBLE); + + Tensor t_complex = tf.complex(t_real, t_imag); + + Tensor t_complex_3d = tf.reshape(t_complex, new int[] { 2, 2, 2 }); + + Tensor t_frequency_domain_3d = tf.signal.fft2d(t_complex_3d); + Tensor t_time_domain_3d = tf.signal.ifft2d(t_frequency_domain_3d); + + Tensor t_time_domain = tf.reshape(t_time_domain_3d, new int[] { 8 }); + + Tensor t_real_result = tf.math.real(t_time_domain); + Tensor t_imag_result = tf.math.imag(t_time_domain); + + NDArray n_real_result = t_real_result.numpy(); + NDArray n_imag_result = t_imag_result.numpy(); + + double[] d_real_result = n_real_result.ToArray(); + double[] d_imag_result = n_imag_result.ToArray(); + + Assert.IsTrue(base.Equal(d_real_result, d_real)); + Assert.IsTrue(base.Equal(d_imag_result, d_imag)); + } + } +} \ No newline at end of file