Advertisement
UF6

FFT Tests

UF6
Dec 23rd, 2024
50
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 6.45 KB | Source Code | 0 0
  1. import numpy as np
  2. import matplotlib.pyplot as plt
  3. import time
  4. import argparse
  5.  
  6. # Import CuPy for GPU acceleration (if available)
  7. try:
  8.     import cupy as cp
  9.     GPU_AVAILABLE = True
  10. except ImportError:
  11.     GPU_AVAILABLE = False
  12.  
  13. # Helper Functions
  14. def generate_cosine_wave(freq, sample_rate, duration, amplitude=1.0, phase=0):
  15.     """Generate a 1D cosine wave."""
  16.     t = np.linspace(0, duration, int(sample_rate * duration), endpoint=False)
  17.     signal = amplitude * np.cos(2 * np.pi * freq * t + phase)
  18.     return t, signal
  19.  
  20. def generate_2d_cosine(fx, fy, size):
  21.     """Generate a 2D cosine pattern."""
  22.     x = np.arange(size)
  23.     y = np.arange(size)
  24.     X, Y = np.meshgrid(x, y)
  25.     signal = np.cos(2 * np.pi * fx * X / size) + np.cos(2 * np.pi * fy * Y / size)
  26.     return signal
  27.  
  28. def plot_and_save_fft_result(freq, fft_result, title="FFT Result", filename="fft_result.png"):
  29.     """Plot and optionally save the magnitude of the FFT result."""
  30.     plt.figure(figsize=(10, 4))
  31.     plt.plot(freq, np.abs(fft_result))
  32.     plt.title(title)
  33.     plt.xlabel("Frequency (Hz)")
  34.     plt.ylabel("Amplitude")
  35.     plt.savefig(filename)
  36.     plt.show()
  37.  
  38. # GPU FFT using CuPy
  39. def gpu_fft_1d(signal):
  40.     if not GPU_AVAILABLE:
  41.         raise RuntimeError("CuPy is not available. Install CuPy for GPU support.")
  42.     signal_gpu = cp.array(signal)
  43.     fft_result_gpu = cp.fft.fft(signal_gpu)
  44.     return cp.asnumpy(fft_result_gpu)
  45.  
  46. def time_logger(func):
  47.     """Decorator to log the execution time of functions."""
  48.     def wrapper(*args, **kwargs):
  49.         start = time.time()
  50.         result = func(*args, **kwargs)
  51.         end = time.time()
  52.         print(f"{func.__name__} executed in {end - start:.4f} seconds")
  53.         return result
  54.     return wrapper
  55.  
  56. @time_logger
  57. def precision_test():
  58.     print("\n--- Precision Test ---")
  59.     t, signal = generate_cosine_wave(10, 1000, 1.0, amplitude=1e-6)
  60.     fft_freq, fft_result = test_fft_1d(signal, 1000)
  61.     plot_and_save_fft_result(fft_freq, fft_result, "FFT of Small Amplitude Signal", "precision_test.png")
  62.     error = validate_inverse_fft(signal)
  63.     print(f"Inverse FFT Reconstruction Error: {error}")
  64.  
  65. @time_logger
  66. def performance_scaling_test():
  67.     print("\n--- Performance Scaling Test ---")
  68.     sizes = [128, 256, 512, 1024, 2048, 4096, 8192]
  69.     times = []
  70.     for size in sizes:
  71.         signal = np.random.rand(size, size).astype(np.float32)
  72.         start = time.time()
  73.         np.fft.fft2(signal)
  74.         times.append(time.time() - start)
  75.     plt.plot(sizes, times, marker='o')
  76.     plt.title("Performance Scaling of 2D FFT")
  77.     plt.xlabel("Matrix Size")
  78.     plt.ylabel("Time (seconds)")
  79.     plt.savefig("performance_scaling_test.png")
  80.     plt.show()
  81.  
  82. @time_logger
  83. def noisy_signal_test():
  84.     print("\n--- Noisy Signal Test ---")
  85.     t, signal = generate_cosine_wave(10, 1000, 1.0)
  86.     noisy_signal = signal + 0.5 * np.random.normal(size=len(signal))
  87.     fft_freq, fft_result = test_fft_1d(noisy_signal, 1000)
  88.     plot_and_save_fft_result(fft_freq, fft_result, "FFT of Noisy Signal", "noisy_signal_test.png")
  89.  
  90. @time_logger
  91. def windowing_test():
  92.     print("\n--- Windowing Test ---")
  93.     t, signal = generate_cosine_wave(10, 1000, 1.0)
  94.     window = np.hamming(len(signal))
  95.     windowed_signal = signal * window
  96.     fft_freq, fft_no_window = test_fft_1d(signal, 1000)
  97.     fft_freq, fft_with_window = test_fft_1d(windowed_signal, 1000)
  98.     plt.plot(fft_freq, np.abs(fft_no_window), label="Without Window")
  99.     plt.plot(fft_freq, np.abs(fft_with_window), label="With Hamming Window")
  100.     plt.title("Effect of Windowing on FFT")
  101.     plt.xlabel("Frequency (Hz)")
  102.     plt.ylabel("Amplitude")
  103.     plt.legend()
  104.     plt.savefig("windowing_test.png")
  105.     plt.show()
  106.  
  107. @time_logger
  108. def cosine_2d_test():
  109.     print("\n--- 2D Cosine Pattern Test ---")
  110.     signal = generate_2d_cosine(10, 15, 256)
  111.     fft_result = np.fft.fftshift(np.fft.fft2(signal))
  112.     plt.subplot(1, 2, 1)
  113.     plt.imshow(signal, cmap='gray')
  114.     plt.title("2D Cosine Pattern")
  115.     plt.subplot(1, 2, 2)
  116.     plt.imshow(np.log(np.abs(fft_result) + 1), cmap='gray')
  117.     plt.title("FFT Magnitude Spectrum")
  118.     plt.savefig("cosine_2d_test.png")
  119.     plt.show()
  120.  
  121. @time_logger
  122. def high_frequency_test():
  123.     print("\n--- High-Frequency Test ---")
  124.     t, signal = generate_cosine_wave(400, 1000, 1.0)
  125.     fft_freq, fft_result = test_fft_1d(signal, 1000)
  126.     plot_and_save_fft_result(fft_freq, fft_result, "FFT of High-Frequency Signal", "high_frequency_test.png")
  127.  
  128. @time_logger
  129. def batch_processing_test():
  130.     print("\n--- Batch Processing Test ---")
  131.     batch_size = 10
  132.     signals = [generate_cosine_wave(10 + i, 1000, 1.0)[1] for i in range(batch_size)]
  133.     batch_fft = [np.fft.fft(signal) for signal in signals]
  134.     fft_freq = np.fft.fftfreq(len(signals[0]), d=1/1000)
  135.     plt.plot(fft_freq, np.abs(batch_fft[0]))
  136.     plt.title("FFT of First Signal in Batch")
  137.     plt.xlabel("Frequency (Hz)")
  138.     plt.ylabel("Amplitude")
  139.     plt.savefig("batch_processing_test.png")
  140.     plt.show()
  141.  
  142. def test_fft_1d(signal, sample_rate):
  143.     """Perform FFT and return frequency and transformed signal."""
  144.     fft_result = np.fft.fft(signal)
  145.     fft_freq = np.fft.fftfreq(len(signal), d=1/sample_rate)
  146.     return fft_freq, fft_result
  147.  
  148. def validate_inverse_fft(signal):
  149.     """Validate that inverse FFT reconstructs the original signal."""
  150.     fft_result = np.fft.fft(signal)
  151.     reconstructed_signal = np.fft.ifft(fft_result)
  152.     error = np.max(np.abs(signal - reconstructed_signal))
  153.     return error
  154.  
  155. def main():
  156.     parser = argparse.ArgumentParser(description="FFT Testing Suite")
  157.     parser.add_argument("--test", type=str, help="Select test to run", default="all")
  158.     args = parser.parse_args()
  159.  
  160.     if args.test == "all":
  161.         precision_test()
  162.         performance_scaling_test()
  163.         noisy_signal_test()
  164.         windowing_test()
  165.         cosine_2d_test()
  166.         high_frequency_test()
  167.         batch_processing_test()
  168.     elif args.test == "precision":
  169.         precision_test()
  170.     elif args.test == "scaling":
  171.         performance_scaling_test()
  172.     elif args.test == "noisy":
  173.         noisy_signal_test()
  174.     elif args.test == "windowing":
  175.         windowing_test()
  176.     elif args.test == "2d":
  177.         cosine_2d_test()
  178.     elif args.test == "highfreq":
  179.         high_frequency_test()
  180.     elif args.test == "batch":
  181.         batch_processing_test()
  182.     else:
  183.         print(f"Unknown test: {args.test}")
  184.  
  185. if __name__ == "__main__":
  186.     main()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement