246 lines
9.1 KiB
Python
246 lines
9.1 KiB
Python
# Copyright (c) 2026 PaddlePaddle Authors. 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.
|
|
|
|
"""
|
|
FFT操作单元测试 / FFT Operations Unit Tests
|
|
|
|
测试目标 / Test Target:
|
|
paddle.fft 模块 (python/paddle/fft.py, 覆盖率约57.8%)
|
|
|
|
覆盖的模块 / Covered Modules:
|
|
- paddle.fft: FFT变换相关API
|
|
- 包括 fft, ifft, rfft, irfft, fft2, ifft2, fftn, ifftn等
|
|
|
|
作用 / Purpose:
|
|
覆盖fast Fourier transform (快速傅里叶变换)及相关逆变换的代码路径,
|
|
补充未被原有测试覆盖的频域变换函数。
|
|
"""
|
|
|
|
import unittest
|
|
|
|
import numpy as np
|
|
|
|
import paddle
|
|
import paddle.fft
|
|
|
|
paddle.disable_static()
|
|
|
|
|
|
class TestFFTBasic(unittest.TestCase):
|
|
"""测试基本FFT操作 / Test basic FFT operations"""
|
|
|
|
def setUp(self):
|
|
"""初始化测试数据 / Initialize test data"""
|
|
self.x_real = paddle.to_tensor(np.random.randn(8).astype('float32'))
|
|
self.x_2d = paddle.to_tensor(np.random.randn(4, 8).astype('float32'))
|
|
self.x_complex = paddle.to_tensor(
|
|
(np.random.randn(8) + 1j * np.random.randn(8)).astype('complex64')
|
|
)
|
|
|
|
def test_fft_1d(self):
|
|
"""测试1D FFT变换 / Test 1D FFT transform"""
|
|
result = paddle.fft.fft(self.x_complex)
|
|
self.assertEqual(result.shape, self.x_complex.shape)
|
|
self.assertTrue(result.dtype == paddle.complex64)
|
|
|
|
def test_fft_with_n(self):
|
|
"""测试带长度参数的FFT / Test FFT with n parameter"""
|
|
result = paddle.fft.fft(self.x_complex, n=16)
|
|
self.assertEqual(result.shape[-1], 16)
|
|
|
|
def test_fft_with_axis(self):
|
|
"""测试沿指定轴的FFT / Test FFT along specified axis"""
|
|
x = paddle.to_tensor(
|
|
(np.random.randn(4, 8) + 1j * np.random.randn(4, 8)).astype(
|
|
'complex64'
|
|
)
|
|
)
|
|
result = paddle.fft.fft(x, axis=0)
|
|
self.assertEqual(result.shape, x.shape)
|
|
result2 = paddle.fft.fft(x, axis=1)
|
|
self.assertEqual(result2.shape, x.shape)
|
|
|
|
def test_ifft_1d(self):
|
|
"""测试1D IFFT逆变换 / Test 1D IFFT inverse transform"""
|
|
fft_result = paddle.fft.fft(self.x_complex)
|
|
recovered = paddle.fft.ifft(fft_result)
|
|
self.assertEqual(recovered.shape, self.x_complex.shape)
|
|
|
|
def test_rfft_1d(self):
|
|
"""测试实数FFT / Test real FFT"""
|
|
result = paddle.fft.rfft(self.x_real)
|
|
# rfft output has n//2+1 complex elements
|
|
expected_len = self.x_real.shape[-1] // 2 + 1
|
|
self.assertEqual(result.shape[-1], expected_len)
|
|
self.assertTrue(result.dtype in [paddle.complex64, paddle.complex128])
|
|
|
|
def test_irfft_1d(self):
|
|
"""测试实数IFFT逆变换 / Test real IFFT inverse transform"""
|
|
rfft_result = paddle.fft.rfft(self.x_real)
|
|
recovered = paddle.fft.irfft(rfft_result)
|
|
self.assertEqual(recovered.shape[-1], self.x_real.shape[-1])
|
|
self.assertTrue(recovered.dtype in [paddle.float32, paddle.float64])
|
|
|
|
def test_rfft_with_n(self):
|
|
"""测试带长度参数的实数FFT / Test real FFT with n"""
|
|
result = paddle.fft.rfft(self.x_real, n=16)
|
|
self.assertEqual(result.shape[-1], 16 // 2 + 1)
|
|
|
|
|
|
class TestFFT2D(unittest.TestCase):
|
|
"""测试2D FFT操作 / Test 2D FFT operations"""
|
|
|
|
def setUp(self):
|
|
"""初始化2D测试数据 / Initialize 2D test data"""
|
|
self.x_real_2d = paddle.to_tensor(
|
|
np.random.randn(4, 8).astype('float32')
|
|
)
|
|
self.x_complex_2d = paddle.to_tensor(
|
|
(np.random.randn(4, 8) + 1j * np.random.randn(4, 8)).astype(
|
|
'complex64'
|
|
)
|
|
)
|
|
|
|
def test_fft2(self):
|
|
"""测试2D FFT / Test 2D FFT"""
|
|
result = paddle.fft.fft2(self.x_complex_2d)
|
|
self.assertEqual(result.shape, self.x_complex_2d.shape)
|
|
|
|
def test_ifft2(self):
|
|
"""测试2D IFFT / Test 2D IFFT"""
|
|
fft_result = paddle.fft.fft2(self.x_complex_2d)
|
|
recovered = paddle.fft.ifft2(fft_result)
|
|
self.assertEqual(recovered.shape, self.x_complex_2d.shape)
|
|
|
|
def test_rfft2(self):
|
|
"""测试2D 实数FFT / Test 2D real FFT"""
|
|
result = paddle.fft.rfft2(self.x_real_2d)
|
|
# Last dim: n//2+1
|
|
expected_last = self.x_real_2d.shape[-1] // 2 + 1
|
|
self.assertEqual(result.shape[-1], expected_last)
|
|
self.assertEqual(result.shape[-2], self.x_real_2d.shape[-2])
|
|
|
|
def test_irfft2(self):
|
|
"""测试2D 实数IFFT / Test 2D real IFFT"""
|
|
rfft_result = paddle.fft.rfft2(self.x_real_2d)
|
|
recovered = paddle.fft.irfft2(rfft_result)
|
|
self.assertEqual(recovered.shape[-1], self.x_real_2d.shape[-1])
|
|
self.assertEqual(recovered.shape[-2], self.x_real_2d.shape[-2])
|
|
|
|
def test_fft2_with_s(self):
|
|
"""测试带s参数的2D FFT / Test 2D FFT with s parameter"""
|
|
result = paddle.fft.fft2(self.x_complex_2d, s=[8, 16])
|
|
self.assertEqual(result.shape[-2], 8)
|
|
self.assertEqual(result.shape[-1], 16)
|
|
|
|
|
|
class TestFFTND(unittest.TestCase):
|
|
"""测试N维FFT操作 / Test N-dimensional FFT operations"""
|
|
|
|
def setUp(self):
|
|
"""初始化多维测试数据 / Initialize multi-dimensional test data"""
|
|
self.x_real_3d = paddle.to_tensor(
|
|
np.random.randn(2, 4, 8).astype('float32')
|
|
)
|
|
self.x_complex_3d = paddle.to_tensor(
|
|
(np.random.randn(2, 4, 8) + 1j * np.random.randn(2, 4, 8)).astype(
|
|
'complex64'
|
|
)
|
|
)
|
|
|
|
def test_fftn(self):
|
|
"""测试N维FFT / Test N-dimensional FFT"""
|
|
result = paddle.fft.fftn(self.x_complex_3d)
|
|
self.assertEqual(result.shape, self.x_complex_3d.shape)
|
|
|
|
def test_ifftn(self):
|
|
"""测试N维IFFT / Test N-dimensional IFFT"""
|
|
fft_result = paddle.fft.fftn(self.x_complex_3d)
|
|
recovered = paddle.fft.ifftn(fft_result)
|
|
self.assertEqual(recovered.shape, self.x_complex_3d.shape)
|
|
|
|
def test_rfftn(self):
|
|
"""测试N维实数FFT / Test N-dimensional real FFT"""
|
|
result = paddle.fft.rfftn(self.x_real_3d)
|
|
expected_last = self.x_real_3d.shape[-1] // 2 + 1
|
|
self.assertEqual(result.shape[-1], expected_last)
|
|
|
|
def test_irfftn(self):
|
|
"""测试N维实数IFFT / Test N-dimensional real IFFT"""
|
|
rfft_result = paddle.fft.rfftn(self.x_real_3d)
|
|
recovered = paddle.fft.irfftn(rfft_result)
|
|
self.assertEqual(recovered.shape[-1], self.x_real_3d.shape[-1])
|
|
|
|
def test_fftn_with_axes(self):
|
|
"""测试带axes参数的N维FFT / Test N-dimensional FFT with axes parameter"""
|
|
result = paddle.fft.fftn(self.x_complex_3d, axes=[1, 2])
|
|
self.assertEqual(result.shape, self.x_complex_3d.shape)
|
|
|
|
|
|
class TestFFTFreq(unittest.TestCase):
|
|
"""测试FFT频率函数 / Test FFT frequency functions"""
|
|
|
|
def test_fftfreq(self):
|
|
"""测试FFT频率 / Test FFT frequency"""
|
|
result = paddle.fft.fftfreq(8)
|
|
self.assertEqual(result.shape[0], 8)
|
|
|
|
def test_fftfreq_with_d(self):
|
|
"""测试带采样间隔的FFT频率 / Test FFT frequency with sample spacing"""
|
|
result = paddle.fft.fftfreq(8, d=0.5)
|
|
self.assertEqual(result.shape[0], 8)
|
|
|
|
def test_rfftfreq(self):
|
|
"""测试实数FFT频率 / Test real FFT frequency"""
|
|
result = paddle.fft.rfftfreq(8)
|
|
self.assertEqual(result.shape[0], 8 // 2 + 1)
|
|
|
|
def test_rfftfreq_with_d(self):
|
|
"""测试带采样间隔的实数FFT频率 / Test real FFT frequency with sample spacing"""
|
|
result = paddle.fft.rfftfreq(8, d=0.5)
|
|
self.assertEqual(result.shape[0], 8 // 2 + 1)
|
|
|
|
def test_fftshift(self):
|
|
"""测试FFT频率移位 / Test FFT frequency shift"""
|
|
x = paddle.to_tensor(np.fft.fftfreq(8).astype('float32'))
|
|
result = paddle.fft.fftshift(x)
|
|
self.assertEqual(result.shape, x.shape)
|
|
|
|
def test_ifftshift(self):
|
|
"""测试IFFT频率移位 / Test IFFT frequency shift"""
|
|
x = paddle.to_tensor(
|
|
np.fft.fftshift(np.fft.fftfreq(8)).astype('float32')
|
|
)
|
|
result = paddle.fft.ifftshift(x)
|
|
self.assertEqual(result.shape, x.shape)
|
|
|
|
def test_hfft(self):
|
|
"""测试Hermitian FFT / Test Hermitian FFT"""
|
|
x = paddle.to_tensor(
|
|
(np.random.randn(5) + 1j * np.random.randn(5)).astype('complex64')
|
|
)
|
|
result = paddle.fft.hfft(x)
|
|
# hfft output real, length 2*(n-1)
|
|
self.assertTrue(result.dtype in [paddle.float32, paddle.float64])
|
|
|
|
def test_ihfft(self):
|
|
"""测试Hermitian IFFT / Test Hermitian IFFT"""
|
|
x = paddle.to_tensor(np.random.randn(8).astype('float32'))
|
|
result = paddle.fft.ihfft(x)
|
|
self.assertTrue(result.dtype in [paddle.complex64, paddle.complex128])
|
|
|
|
|
|
if __name__ == '__main__':
|
|
unittest.main()
|