# Merits of “Zero-Phase” Zero Padding

I understand the reasons for zero-padding a finite signal before FFT.

Top image: windowed finite signal.
Bottom image: Zero Phase Zero Padded version of the same signal.


The merit of Zero Phase Zero Padding over "regular" zero padding (whether adding zeros before, after or at both ends of the finite signal) isn't obvious to me. What is its advantage?

EDIT:

To help anyone else who might have this question in the future, I am adding my comments here and things I tried in order to understand this more - hopefully this will save time for anyone with this question in the future.

After @matt-l's comment, I wrote a matlab script for seeing the difference in the magnitude and phase responses of a symmetric signal that was zero-padded in 3 ways (signal000000, 000signal000 and nal000000sig). The third one is Zero-Phase Zero Padding.

The imaginary part of the frequency response in case 3 is very close to 0 (on the order of magnitude of the noise floor - eps in Matlab). However, the unwrapped phase still exists - which, as Matt pointed out might be due to numerical issues.

High-res

The script I wrote is:

NSIG = 128; % Signal length
NFFT = 512; % FFT length

% Make signal
n = 0:NSIG - 1;
w1 = pi/8;
w2 = 3*pi/4; % w1 and w2 are normalized frequencies of the signal

signal = 0.5*cos(w1*n) + cos(w2*n);

% Make signal symmetric about NSIG/2
signal = [fliplr(signal), signal(2:end)]; % Make signal symmetric
NSIG = length(signal);

% Window the input
window = ones (size(signal));
% window = hanning(NSIG)';
raw_in = signal.*window;

%% A. Zero pad at the end only
NZERO = NFFT-NSIG;
in = [raw_in, zeros(1,NFFT-NSIG)];
show_spec1 = fft (in);

%% B. Zero pad on both sides
in = [zeros(1, floor(NZERO/2)), raw_in, zeros(1,ceil(NZERO/2))];
show_spec2 = fft (in);

%% C. Zero phase zero pad
in = [raw_in(floor(NSIG/2)+1:NSIG), zeros(1,NZERO), raw_in(1:floor(NSIG/2))];
show_spec3 = fft (in);

% Prepare to plot
fs = 500;
fres = fs/NFFT;     % Freq resolution
w = fres.*([0:NFFT/2, -NFFT/2+1:-1]);
figure;

%% PLOTS
titleStr = 'A. - s i g n a l 0 0 0 0 0 0 -';
h(1) = subplot (3,2,1); stem (w, abs(show_spec1),'.-'); axis tight; title (titleStr); grid on;
xlabel('Frequency (Hz)'); ylabel('Magnitude');
h(2) = subplot (3,2,2); plot (w, unwrap(angle(show_spec1)),'r'); axis tight; title (titleStr); grid on;
xlabel('Frequency (Hz)'); ylabel('Unwrapped Phase');

titleStr = 'B. - 0 0 0 s i g n a l 0 0 0 -';
h(3) = subplot (3,2,3); stem (w, abs(show_spec2),'.-'); axis tight; title (titleStr); grid on;
xlabel('Frequency (Hz)'); ylabel('Magnitude');
h(4) = subplot (3,2,4); plot (w, unwrap(angle(show_spec2)),'r'); axis tight; title (titleStr); grid on;
xlabel('Frequency (Hz)'); ylabel('Unwrapped Phase');

titleStr = 'C. - n a l 0 0 0 0 0 0 s i g -';
h(5) = subplot (3,2,5); stem (w, abs(show_spec3),'.-'); axis tight; title (titleStr); grid on;
xlabel('Frequency (Hz)'); ylabel('Magnitude');
h(6) = subplot (3,2,6); plot (w, unwrap(angle(show_spec3)),'r'); axis tight; title (titleStr); grid on;
xlabel('Frequency (Hz)'); ylabel('Unwrapped Phase');


This is just about obtaining a symmetric signal after zero-padding. Take a symmetric signal (w.r.t. to time index $n=0$) and append zeros. Due to the implicit periodicity of the time signal used as input to the DFT, it does not matter if you append all zeros to the right, to the left, or on both ends of the symmetric signal. In any case, since the DFT/FFT assumes the first sample in the buffer to be the time origin, the input vector to the FFT needs to be arranged as
[right half of the signal | left half of the signal]
which is basically one period of the periodically continued zero-padded signal between $n=0$ and $n=N-1$, where $N$ is the FFT length, i.e. the length of the signal after zero-padding. Note that now all the zeros end up in the middle of the vector to be transformed. If done correctly, the result of the FFT will be purely real-valued (apart from numerical errors). If the signal is asymmetrical, its FFT will be purely imaginary.