Files
2026-07-13 12:40:42 +08:00

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()