Delay a signal in time domain with a phase change

2020-07-22 19:36发布

问题:

I have a problem with a basic time/frequency property implemented in a Matlab script. The property is:

I've tried to implement this in a Matlab script. I've supposed a sinusoidal signal with 5Hz of frequency value, Sampling frequency equal to 800Hz and I want to delay this signal by 1.8 seconds. So I've implemented this script:

Fs = 800;
Time_max = 4; % seconds
t = 0:(1/Fs):Time_max;
delay = 1.8; % One second of delay

f = 5; %Hz
y = sin(2 * pi * f * t);

figure
subplot(2,1,1)
plot(t,y);
xlabel('time (s)')
legend('Original');

%FFT
SIZE = 2^nextpow2(length(y));
Y = fft(y,SIZE);

df = Fs/SIZE;
f= -Fs/2:df:Fs/2 - df;

for k = 1:SIZE

    Y(k) = Y(k)*exp(-(1i*2*pi*f(k)*delay));

end

subplot(2,1,2)
plot(real(ifft(Y)),'r')
legend('Shifted');

And the output plot is :

Where is the problem? How can I achieve the correct time delay?

Thanks

回答1:

The problem is not in the implementation, but lies within the properties of the FFT (respectively of the DFT): The formula you posted for a time delay is correct, but you have to keep in mind, that it you are doing a circular shift. This means that all the signal parts from 2.2s to 4.0s will be copied to the beginning of the output. This is exactly what you see:

The signal you want does start at 1.8s, but from 0 to 0.6837s there is the part which is inserted due to the circular shift. Small calculation: your input signal is 1 x 3201, i.e. it will be zero-padded with 895 zeros. In seconds, this is 1.1187 seconds of zeros. The circular shift will insert the last 1.8s at the beginning, i.e. 1.8 - 1.1187 = 0.86 seconds will not be zeros but contain a sine. This is exactly the amount we see in the plot.

To avoid this effect, you have to pad the input signal with at least the amount of zeros by which you delay the signal. In your case that would be

Fs = 800;
Time_max = 4; % seconds
t = 0:(1/Fs):Time_max;
delay = 1.8; % One second of delay

f = 5; %Hz
y = sin(2 * pi * f * t);
y = [y, zeros(1,delay*Fs)];          % Zero-pad the signal by the amount of delay

SIZE = 2^nextpow2(length(y));
Y = fft(y,SIZE);

df = Fs/SIZE;
f= -Fs/2:df:Fs/2 - df;

for k = 1:SIZE
    Y(k) = Y(k)*exp(-(1i*2*pi*f(k)*delay));
end

td = (0:SIZE-1)/Fs;
yd = real(ifft(Y));

Which gives us



回答2:

I believe you need to take a larger FFT to accommodate the shift/delay. You could force this by zero-padding the input with the proper number of zero's (> 1440 with your provided sampling frequency and delay amount). Then you get the desired result.

Your original plot had the tail wrapping around because the FFT/IFFT were limited to 4096 bins, which was not enough to incorporate the entire shifted signal + leading zeros.



回答3:

You can try this:

Fs = 800;
Time_max = 4; % seconds
t = 0:(10/Fs):Time_max;
delay = 1.8; % One second of delay
f = 5; %Hz
y = sin(2 * pi * f * t);
figure;subplot(2,1,1);plot(t,y);xlabel('time (s)')
legend('Original');

w = 2*pi*f;
X=fft(y);
Y=X.*exp(-1i*w*(t+delay));
ynew = real(ifft(Y));
subplot(2,1,2);plot(ynew);
legend('Shifted');

Consider that using vectorized implementation, you can get rid of the for-loop.

the result would be such as follows: