[Python] Discrepancy Between NumPy and TensorFlow FFT Outputs: Missing Imaginary Components in...

Discussão em 'Python' iniciado por Stack, Março 12, 2025.

  1. Stack

    Stack Membro Participativo

    I am working on a project where I need to perform Fourier Transform on synthetic periodic data using both NumPy and TensorFlow. However, I am encountering a discrepancy between the FFT outputs of NumPy and TensorFlow. Specifically, the TensorFlow FFT output seems to be missing the imaginary components, while the NumPy FFT output includes them as expected.

    Even though the TensorFlow output has missing imaginary components, using ifft for both NumPy and TensorFlow real-imaginary values reconstructs the signal identically. However, I am unable to predict future steps with TensorFlow. NumPy reconstructs future values as expected.

    Why does the TensorFlow FFT output not include the expected imaginary components, while the NumPy FFT output does?

    I believe TensorFlow handles frequency components, padding and transformation to complex numbers differently what Numpy does. I just purely convert real values to imaginary with casting real values to complex64.

    How can I ensure that the TensorFlow FFT output includes both real and imaginary components correctly? Additionally, how can I predict future values using TensorFlow as I do with NumPy?

    This is what I have been trying to do, compare the differences between NumPy and TensorFlow:

    import numpy as np
    import tensorflow as tf
    import matplotlib.pyplot as plt

    # Define constants
    timesteps = 50
    future_steps = 20
    features = 5 # Number of features

    time = np.linspace(0, 10, timesteps) # Time vector
    time_extended = np.linspace(0, 10 + (future_steps * (10 / timesteps)), timesteps + future_steps)

    # Generate synthetic periodic data
    synthetic_data = np.zeros((timesteps, features))
    synthetic_data[:, 0] = np.sin(2 * np.pi * 1.0 * time) + 0.5 * np.cos(2 * np.pi * 3.0 * time)
    synthetic_data[:, 1] = np.sin(2 * np.pi * 0.5 * time) + np.cos(2 * np.pi * 2.5 * time)
    synthetic_data[:, 2] = 1.5 * np.sin(2 * np.pi * 2.0 * time) - 0.3 * np.cos(2 * np.pi * 1.0 * time)
    synthetic_data[:, 3] = np.sin(2 * np.pi * 1.5 * time) + 0.2 * np.cos(2 * np.pi * 4.0 * time)
    synthetic_data[:, 4] = 0.7 * np.sin(2 * np.pi * 2.8 * time) - 0.4 * np.cos(2 * np.pi * 1.8 * time)

    # Compute FFT using NumPy
    fft_output_np = np.fft.fft(synthetic_data, axis=0)
    frequencies_np = np.fft.fftfreq(timesteps)
    amplitudes_np = np.abs(fft_output_np) / timesteps
    phases_np = np.angle(fft_output_np)

    # Compute FFT using TensorFlow
    fft_output_tf = tf.signal.fft(synthetic_data)
    amplitudes_tf = tf.abs(fft_output_tf) / tf.cast(timesteps, tf.float32)
    phases_tf = tf.math.angle(fft_output_tf)

    # Convert TensorFlow tensors to NumPy arrays
    fft_output_tf_np = fft_output_tf.numpy()
    amplitudes_tf_np = amplitudes_tf.numpy()
    phases_tf_np = phases_tf.numpy()

    # --------------------------------------------
    # ✅ Direct IFFT Reconstruction (Original FFT)
    # --------------------------------------------
    ifft_reconstructed_np = np.fft.ifft(fft_output_np, axis=0).real
    ifft_reconstructed_tf = tf.signal.ifft(fft_output_tf).numpy().real

    # --------------------------------------------
    # ✅ IFFT Reconstruction from Amplitudes & Phases
    # --------------------------------------------
    # NumPy Reconstruction
    complex_reconstructed_np = amplitudes_np * np.exp(1j * phases_np) * timesteps # Recreate FFT values
    ifft_reconstructed_from_ap_np = np.fft.ifft(complex_reconstructed_np, axis=0).real # IFFT

    # TensorFlow Reconstruction
    complex_reconstructed_tf = tf.complex(amplitudes_tf * tf.cos(phases_tf), amplitudes_tf * tf.sin(phases_tf)) * tf.cast(timesteps, tf.complex64)
    ifft_reconstructed_from_ap_tf = tf.signal.ifft(complex_reconstructed_tf).numpy().real

    complex_reconstructed_tf_np = complex_reconstructed_tf.numpy() # Convert to NumPy for printing

    # Select a feature for detailed debugging
    feature_idx = 0

    # ✅ Print Debugging Information
    print("\n Debugging Fourier Transform Components for Feature", feature_idx)

    # Print Complex Numbers (Real & Imaginary)
    print("\n--- COMPLEX NUMBERS (Reconstructed from Amplitudes & Phases) ---")
    print("TensorFlow FFT Output:\n", fft_output_tf[:, feature_idx])

    print("NumPy FFT Output:\n", fft_output_np[:, feature_idx])

    # --------------------------------------------
    # ✅ Predict Future Values using Fourier Expansion
    # --------------------------------------------
    future_predictions_np = np.zeros((future_steps, features))
    future_predictions_tf = np.zeros((future_steps, features))

    for t in range(future_steps):
    t_future = timesteps + t # Time index for future steps

    # NumPy: Predict future values using Fourier series expansion
    future_predictions_np[t] = np.sum(amplitudes_np * np.cos(2 * np.pi * frequencies_np[:, None] * t_future + phases_np), axis=0)

    # TensorFlow: Predict future values using Fourier series expansion
    future_predictions_tf[t] = np.sum(amplitudes_tf_np * np.cos(2 * np.pi * frequencies_np[:, None] * t_future + phases_tf_np), axis=0)

    # --------------------------------------------
    # ✅ Extend Data for Plotting
    # --------------------------------------------
    full_signal_np = np.concatenate((ifft_reconstructed_np, future_predictions_np), axis=0)
    full_signal_tf = np.concatenate((ifft_reconstructed_tf, future_predictions_tf), axis=0)

    # --------------------------------------------
    # ✅ Plotting: Future Predictions from Different Reconstructions
    # --------------------------------------------
    plt.figure(figsize=(12, 8))

    for i in range(features):
    plt.subplot(features, 1, i + 1)
    plt.plot(time_extended, full_signal_np[:, i], label='Direct IFFT + Prediction (NumPy)', linestyle='solid', linewidth=2, alpha=0.7, color='blue')
    plt.plot(time_extended, full_signal_tf[:, i], label='Direct IFFT + Prediction (TensorFlow)', linestyle='dashed', linewidth=2, alpha=0.7, color='green')
    plt.axvline(x=time[-1], color='black', linestyle='--', label="Prediction Start")
    plt.legend()
    plt.title(f"Prediction Comparison (Feature {i+1})")

    plt.tight_layout()
    plt.show()


    The results for NumPy and TensorFlow FFT outputs are:

    --- COMPLEX NUMBERS (Reconstructed from Amplitudes & Phases) ---

    TensorFlow FFT Output:

    tf.Tensor(
    [ 1. +0.j 1.8956809 +0.j 1.2586026 +0.j -0.40646017+0.j
    0.9350877 +0.j -1.1103796 +0.j 0.95443094+0.j -1.3580153 +0.j
    0.7564049 +0.j -4.5968194 +0.j 1.9695193 +0.j 2.206369 +0.j
    0.08039129+0.j 1.4168235 +0.j -1.279043 +0.j 0.13616711+0.j
    0.5050415 +0.j -1.5471683 +0.j 1.381841 +0.j -5.525199 +0.j
    3.2019842 +0.j 1.9095042 +0.j -0.61422163+0.j 2.509771 +0.j
    -2.2938673 +0.j 0.8726954 +0.j -0.800195 +0.j 0.24049258+0.j
    -1.170131 +0.j -2.8509908 +0.j 2.538548 +0.j 1.1680496 +0.j
    0.6346374 +0.j 0.6699722 +0.j -0.62059027+0.j 0.39178047+0.j
    -1.8831189 +0.j 2.1379056 +0.j -4.2216344 +0.j 0.34866822+0.j
    1.6591074 +0.j 1.0568695 +0.j 0.50590456+0.j 0.43404764+0.j
    -0.5220758 +0.j 0.55441445+0.j -1.6021513 +0.j 1.195328 +0.j
    -4.12398 +0.j 1. +0.j], shape=(50,), dtype=complex64)

    NumPy FFT Output:

    [ 5.00000000e-01+0.00000000e+00j 5.05609841e-01-5.34290797e-02j
    5.23097541e-01-1.10961382e-01j 5.54643041e-01-1.77614989e-01j
    6.04694370e-01-2.60679983e-01j 6.81793083e-01-3.72364007e-01j
    8.03155178e-01-5.36032682e-01j 1.00793942e+00-8.04020615e-01j
    1.40671379e+00-1.32388205e+00j 2.47744792e+00-2.73489136e+00j
    1.40631845e+01-1.82238953e+01j -3.45850242e+00+5.30263973e+00j
    -1.45817369e+00+2.69066818e+00j -8.76036084e-01+2.00643206e+00j
    -5.82708758e-01+1.75124914e+00j -3.84581501e-01+1.69374226e+00j
    -2.08832880e-01+1.79764496e+00j 8.58395137e-03+2.14129348e+00j
    4.36072145e-01+3.13644006e+00j 2.85720849e+00+9.60556002e+00j
    -2.56086256e+00-5.18343952e+00j -1.24899273e+00-1.64805604e+00j
    -9.45467631e-01-8.17719794e-01j -8.19803359e-01-4.33572383e-01j
    -7.63022000e-01-1.92211030e-01j -7.46319396e-01-5.55111512e-16j
    -7.63022000e-01+1.92211030e-01j -8.19803359e-01+4.33572383e-01j
    -9.45467631e-01+8.17719794e-01j -1.24899273e+00+1.64805604e+00j
    -2.56086256e+00+5.18343952e+00j 2.85720849e+00-9.60556002e+00j
    4.36072145e-01-3.13644006e+00j 8.58395137e-03-2.14129348e+00j
    -2.08832880e-01-1.79764496e+00j -3.84581501e-01-1.69374226e+00j
    -5.82708758e-01-1.75124914e+00j -8.76036084e-01-2.00643206e+00j
    -1.45817369e+00-2.69066818e+00j -3.45850242e+00-5.30263973e+00j
    1.40631845e+01+1.82238953e+01j 2.47744792e+00+2.73489136e+00j
    1.40671379e+00+1.32388205e+00j 1.00793942e+00+8.04020615e-01j
    8.03155178e-01+5.36032682e-01j 6.81793083e-01+3.72364007e-01j
    6.04694370e-01+2.60679983e-01j 5.54643041e-01+1.77614989e-01j
    5.23097541e-01+1.10961382e-01j 5.05609841e-01+5.34290797e-02j]


    The accuracy does not matter here. I know very well that NumPy and TensorFlow have different accuracies. NumPy calculates with complex128 and TensorFlow with complex64. However, this should yield just a minor misalignment with values, but these are drastically different.

    These are the outputs for calculated future values for both NumPy and TensorFlow:

    Differences of NumPy and TensorFlow future step values

    Continue reading...

Compartilhe esta Página