I am trying to generate a time series from a defined PSD function, however i tried to do this in python , with the following steps:
- Define the Power Spectral Density
- Define the time parameters
- Define the frequency range
- Descritize the PSD
- Single-Sided and Normalized DFT
- Generate random phase
- Calculate Discrete Fourier Transform (DFT)
- Perform the inverse Fourier transform (IFFT).
However , at the end when i try the make the comparison between the defined the PSD and the one generated from the time serie , i do get a significant difference , as showed in the following plot :
And this is the code that i am using in python:
import numpy as np import matplotlib.pyplot as plt from scipy.interpolate import interp1d import control from scipy.signal import welch import scipy.signal import random import cmath # ------------------------------------------------------------------------------------------ # Define the Power Spectral Density Curve # ------------------------------------------------------------------------------------------ # Define frequency range # Define frequency range freq = np.linspace(1, 60, 1000) # Initialize PSD array psd = np.zeros_like(freq) # Linearly increasing PSD from 0 to 1 Hz psd[:100] = np.linspace(2, 2.4, 100) # Constant PSD from 1 to 2 Hz psd[100:200] = 2.4 # Linearly decreasing PSD from 2 to 10 Hz psd[200:] = np.linspace(2.4, 0.001, 800) # Plot PSD plt.figure(figsize=(10, 6)) plt.plot(freq, psd, color='blue') plt.title('Power Spectral Density') plt.xlabel('Frequency (Hz)') plt.ylabel('PSD (dB/Hz)') plt.grid(True) plt.show() # ------------------------------------------------------------------------------------------ # Define the time parameters # ------------------------------------------------------------------------------------------ t_fin = 4 Fr = 1 / t_fin # ------------------------------------------------------------------------------------------ # Define the frequency range # ------------------------------------------------------------------------------------------ F0 = 4 F_max = 50 Fs = 2 * freq[-1] # Generate time vector t = np.arange(0, t_fin+1/Fs, 1/Fs) t = t[1:-1] # ------------------------------------------------------------------------------------------ # Descritize the PSD # ------------------------------------------------------------------------------------------ # Sampling PSD f = np.arange(0, Fs/2+ Fr, Fr) PSD = interp1d(freq, psd, fill_value="extrapolate")(f) PSD[f < F0] = -np.inf PSD[f > F_max] = -np.inf # Plot PSD curve plt.figure(figsize=(10, 6)) plt.plot(freq, psd, color='blue', label='Original PSD') plt.scatter(f, PSD, color='red', label='Sampled PSD') plt.title('Power Spectral Density (PSD) of Simplified Seismic Data') plt.xlabel('Frequency (Hz)') plt.ylabel('Power/Frequency') plt.grid(True) plt.xlim([0, 60]) plt.legend() plt.tight_layout() plt.show() # ------------------------------------------------------------------------------------------ # Single-Sided and Normalized DFT # ------------------------------------------------------------------------------------------ # Initialize plampl array plampl = np.zeros_like(PSD) PSD= control.db2mag(PSD) # Calculate plampl plampl[0] = np.sqrt(Fr * PSD[0]) plampl[1:] = np.sqrt(2 * Fr * PSD[1:]) # ------------------------------------------------------------------------------------------ # Generate random phase # ------------------------------------------------------------------------------------------ plphase = np.random.randn(1, len(plampl)) * (2 * np.pi) # From Single-Sided Ampl/Phase to Double-Sided Real/Imag plampl[0:-1] = plampl[0:-1] / 2 plreal = plampl * np.cos(plphase) plimag = plampl * np.sin(plphase) # Construct p2 array p2 = np.concatenate((plreal + 1j * plimag, np.conj(plreal[0:-1] + 1j * plimag[0:-1])[::-1])) # ------------------------------------------------------------------------------------------ # Calculate Discrete Fourier Transform (DFT) # ------------------------------------------------------------------------------------------ DFT = len(p2) * p2 # ------------------------------------------------------------------------------------------ # Perform the inverse Fourier transform (IFFT) # ------------------------------------------------------------------------------------------ s = np.fft.ifft(DFT) s_real = s.real.squeeze() # Remove any singleton dimensions s_imag = s.imag.squeeze() sqrt_sum = np.sqrt(s_real**2 + s_imag**2) #time_vector = np.arange(0, len(s) / Fr, len(s_real)) #print(time_vector) # Extract the real part of s # Plotting plt.plot(np.arange(len(s_real)), s_real) plt.xlabel('Length') plt.ylabel('Real part of s') plt.title('Real part of s vs Length') plt.grid(True) plt.show() # Calculate the Power Spectral Density (PSD) using Welch's method f, Pxx_den = welch(s.real, fs=Fs, nperseg=len(s_real)) Pxx_den = np.squeeze(Pxx_den) # Flatten Pxx_den if necessary plt.semilogy(f, Pxx_den) plt.plot(freq, psd, color='red', label='Original PSD') plt.xlabel('frequency [Hz]') plt.legend(['PSD from Time Series', 'Original PSD']) plt.ylabel('PSD [V**2/Hz]') plt.xlim(0, 100) # Set the frequency range from 0 to 100 Hz plt.yscale('log') # Set the x-axis to logarithmic scale plt.show() Any Help will be much appreciated .


DFTandwelchare undefined, some lines need a comment character and I don't see a random phase anywhere in there. $\endgroup$