1

I want to recover a time signals from a given power spectral density, assuming a normal distribution of the original signal:

PSD;                                 % [(m/s)^2/Hz] given spectrum
T = 60;                              % [s] length of original signal
dt = 0.005;                          % [s] time step of original signal
N = T/dt;                            % [-] number of samples
NFFT = 2^nextpow2(N);                % [-] number of bins for FFT
fs = 1/dt;                           % [Hz] sampling frequency
ASD = sqrt(PSD);                     % [(m/s)/sqrt(Hz)] get amplitude spectrum 
omega = 2*pi*rand(NFFT/2,1);         % [rad] generate phase vector
Z = ASD.*exp(1i*omega);              % create complex amplitude vector
Z = [0;Z;flipud(conj(Z))];           % extend to satisfy symmetry
Y = real(ifft(Z));                   % inverse FFT
[PSDY,f] = pwelch(Y,[],[],NFFT,fs);  % generate PSD from Y to compare

The results show a power spectrum several orders of magnitude lower than the original, but the shape matches very good. I guess there is something wrong with the units or there might be a scaling factor missing. I'm not sure about the units of the time signal after ifft, since the amplitude has [(m/s)/sqrt(Hz)].

Cris Luengo
  • 55,762
  • 10
  • 62
  • 120
djf
  • 13
  • 3

1 Answers1

1

I believe there are two problems here.
First, I think that the PSD as you define it (or rather, as you use it) is in the wrong units.
When you define the signal as

Z = ASD.*exp(1i*omega); 

then ASD should be in m/s and not in (m/s)/Hz.
So you should do something like that:

ASD = sqrt(PSD*fs/2)

Now, since PSD is in (m/s)^2/Hz, ASD is in units of m/s.

Next, the ifft should be normalised. That is, you should define the Y as

Y = ifft(Z)*sqrt(NFFT);

One more thing, I am not sure if this is on purpose, but the following line

[PSDY,f] = pwelch(Y,[],[],NFFT,fs);

results in Y being divided into 8 parts (with length <NFFT) with 50% overlap. Each part is zero padded to length of NFFT.
A better practice would be to use something like

[PSDY,f] = pwelch(Y,L,L/2,L,fs);

for some L or

    [PSDY,f] = pwelch(Y,NFFT,[],NFFT,fs);

if you insist. To find out more, go to http://www.mathworks.com/help/signal/ref/pwelch.html

In conclusion, this is your (modified) code:

PSD = 5;                                 % [(m/s)^2/Hz] given spectrum
T = 60;                              % [s] length of original signal
dt = 0.005;                          % [s] time step of original signal
N = T/dt;                            % [-] number of samples
NFFT = 2^nextpow2(N);                % [-] number of bins for FFT
fs = 1/dt;                           % [Hz] sampling frequency
ASD = sqrt(PSD*fs/2);                     % [(m/s)] get amplitude spectrum 
omega = 2*pi*rand(NFFT/2,1);         % [rad] generate phase vector
Z = ASD.*exp(1i*omega);              % create complex amplitude vector
Z = [0;Z;flipud(conj(Z))];           % extend to satisfy symmetry
Y = ifft(Z)*sqrt(NFFT);                   % inverse FFT
[PSDY,f] = pwelch(Y,256,128,256,fs);  % generate PSD from Y to compare

which results in

enter image description here

where the blue line is the estimate PSD.

ThP
  • 2,312
  • 4
  • 19
  • 25
  • Thank's for your answer. Can you please explain the normalization factors? About the nits of the psd I assume from the definition power/Hz --> (m/s)^2/Hz since the original signal is in (m/s). The windows in pwelch are for smoothing purpose and have no effect on the magnitudes. – djf Sep 12 '14 at 18:27
  • @Felipe: You have 2 factors: 1) Since PSD is in (m/s)^2/Hz and the amplitude is in (m/s), you should multiply the PSD by the bandwidth when converting to amplitude. 2) Since MATLAB's ifft is not unitary, in order to conserve energy (or power) you should multiply the result by the square-root of the FFT length. Regarding the windowing, what I meant is that you should notice that the signal is divided and zero-padded (If you are aware of it and it is what you meant then its OK) – ThP Sep 12 '14 at 18:47