% EE3221 - Dr. Durant - W10D3 - 2022-02-18 - Upsampling
function w10d3()
% Example: increase sample rate 3x.
% Step 1: Insert 2 0s between every sample
% Step 2: Apply sinc lowpass filter to interpolate, which removes the extra
% (periodic extension) images in the frequency domain.
% Upsampling (increasing the sampling rate) is closely related to oversampling (using a sampling
% rate much higher than Nyquist demands to allow the antialias or reconstruction filter requirements
% to be relaxed). For an oversampling example, see
% https://durant.io/courses/ee3221/w8oversampling_m.txt
fs = 8000;
f = 2500; % Test signal frequency
N = 100;
n = 0:(N-1); % Sample number
t = n/fs; % time in seconds
x = sinpi(f/fs*2*n); % sinpi(x) == sin(pi*x)
f_res = fs / N; % resolution of the above spectrum
f_dft = (0:N-1)*f_res; % frequency samples resulting from the DFT
X = fft(x) / sqrt(N) / sqrt(N); % Effectively dividing by N. Two parts represent:
% (a) Convert Energy of signal to Power (average per sample) and
% (b) Normalize power for transform length. (b) is necessary since the
% 1/N factor in the IDFT must be partitioned as 1/sqrt(N) for both the DFT
% and IDFT to preserve energy scaling across domains. Following MA383
% terminology, the DFT and IDFTs have all eigenvalues equal to sqrt(N) and
% 1/sqrt(N), respectively. This scaling makes all eigenvalues of both equal
% to 1. In both cases, the eigenvectors are the positive/negative rotating
% complex exponentials of the DFT frequencies sampled at N points.
stemPlotAndSpectrum(t, x, 'Original signal', f_dft, X)
p = 3; % upsampling factor
fs2 = p*fs; % Our new, higher sampling frequency
n2 = 0:(N*p-1); % new sample numbers
t2 = n2/fs2;
pif = 4; % periods of interpolation filter (computation cost, delay, fidelity)
nh = -(p*pif):(p*pif); % widen by upsampling factor
h = sinc(nh/p); % Here we omit the 1/p = Omega1/pi factor derived in class.
% This compensates for the power reduction from the 0-insertion step.
xus = reshape([x; zeros(p-1,N)],1,[]); % 0-insertion
XUS = fft(xus) / length(xus); % energy->power & power normalizations discussed above, make dB come out correctly
f_res = fs2 / length(xus);
f_dft = (0:length(xus)-1)*f_res;
stemPlotAndSpectrum(t2, xus, 'Upsampled signal', f_dft, XUS)
y = filter(h,1,xus); % p*pif-sample delay since h implicitly moved to 0 for causality
% The time domain signal looks like a sinusoid with the proper samples/s,
% But the spectrum will highlight any subtle flaws.
Y = fft(y) / length(y); % energy->power & power normalizations discussed above, make dB come out correctly
stemPlotAndSpectrum(t2, y, 'Interpolated, upsampled signal', f_dft, Y)
end % function
%% Function encapsulating repetitive graphing code
function stemPlotAndSpectrum(t,x,ttl,f,X)
figure
% Time domain:
subplot(2,2,1), stem(t,x), title(ttl)
subplot(2,2,3), plot(t,x)
% Frequency domain:
subplot(2,2,2), plot(f, abs(X) ), ylabel('Magnitude')
subplot(2,2,4), plot(f, 20*log10(abs(X))), ylabel('dB'), xlabel('Hz')
end % function