uploaded all materials

This commit is contained in:
2025-03-24 00:43:09 -04:00
commit f2fb36f646
78 changed files with 15606 additions and 0 deletions

View File

@ -0,0 +1,37 @@
%% Lesson 6x: the S-plane
% If you happen to have an analog filter represented as a ratio of polynomials,
% MATLAB can analyze that too! `freqs()` will give you the analog frequency
% response evaluated at frequencies in the given vector, interpreted in rad/s.
%% a simple example
% What sort of filter is this?
a = [1 0.4 1];
b = [0.2 0.3 1];
w = logspace(-1, 1);
H = freqs(b, a, w);
Hdb = 20*log10(abs(H));
Hph = rad2deg(unwrap(angle(H)));
figure;
subplot(2, 1, 1);
semilogx(w, Hdb);
xlabel("Frequency (rad/s)");
ylabel("|H| (dB)");
title("Magnitude Response");
subplot(2, 1, 2);
semilogx(w, Hph);
xlabel("Frequency (rad/s)");
ylabel("Phase (deg)");
title("Phase Response");
%% some notes
% `zp2tf` and its associates also work in the analog domain, as they deal
% simply with ratios of polynomials. The interpretation of the results will be
% different, though, as we're working with the *analog* plane rather than the
% digital one. `splane.m` gives an example visualization of the s-plane.
[z, p, k] = tf2zp(b, a);
figure;
splane(z, p);

BIN
lessons/lesson06/bw-cat.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 292 KiB

84
lessons/lesson06/fft_1d.m Normal file
View File

@ -0,0 +1,84 @@
%% Lesson 7a. The FFT
% * Explore how to perform the FFT (DFT) on a 1-D signal
% * Learn how to plot the FFT
clear; clc; close all;
%% Load a sample signal
load handel; % builtin dataset that loads `y` and `Fs` to your workspace
sound(y, Fs);
T = 1/Fs;
t = 0:T:(length(y)-1)*T;
%% Loud noise warning!!!
Fnoise = 2500;
noise = 0.2*sin(2*pi*t*Fnoise).'; % additive "noise" with freq. 2.5kHz
y = noise + y;
% sound(y, Fs);
%% Perform the FFT
% Recall that the Fast Fourier Transform is a well-known and efficient
% implementation of the DFT. The DFT is a Fourier transform on a
% N-point fixed-length signal, and produces a N-point frequency spectrum.
N = 2^15;
S = fft(y, N); % N-point DFT (best to use power of 2)
% Note the behavior of doing `fft(y, N)` (taken from the documentation):
% * If X is a vector and the length of X is less than n, then X is padded
% with trailing zeros to length n.
% * If X is a vector and the length of X is greater than n, then X is
% truncated to length n.
% * If X is a matrix, then each column is treated as in the vector case.
% * If X is a multidimensional array, then the first array dimension
% whose size does not equal 1 is treated as in the vector case.
%
% This is the time when padding with zeros is acceptable (when performing
% a FFT where N > length(y))!
S = fftshift(abs(S)) / N;
% fftshift is necessary since MATLAB returns from DFT the zeroth frequency
% at the first index, then the positive frequencies, then the negative
% frequencies when what you probably want is the zeroth frequency centered
% between the negative and positive frequencies.
% Get (analog) frequency domain. E.g., if you perform a 128-pt
% FFT and sampled at 50kHz, you want to generate a 128-pt frequency range
% from -25kHz to 25kHz.
F = Fs .* (-N/2:N/2-1) / N;
% Each frequency index represents a "bin" of frequencies between -Fs/2 and
% Fs/2 (so index i represents i*Fs/N).
figure;
plot(F, S);
title 'Fourier Transform of Audio';
xlabel 'Frequency (Hz)';
ylabel 'Magnitude';
%% Alternative ways to generate FFT plots:
% Slightly more readable version of frequency domain.
% Get the digital frequency
wd = linspace(-pi, pi, N+1);
wd = wd(1:end-1);
F2 = wd * Fs / (2 * pi);
% Equivalent formulation, without going through the digital domain.
F3 = linspace(-Fs/2, Fs/2, N+1);
F3 = F3(1:end-1);
% Slightly more readable but less accurate version.
F4 = linspace(-Fs/2, Fs/2, N);
% Some arbitrariness in scaling factor. It's more important that
% you use the same scaling when performing FFT as IFFT. See
% https://www.mathworks.com/matlabcentral/answers/15770-scaling-the-fft-and-the-ifft#answer_21372
% (use the formula Prof. Fontaine wants you to use.)
S = fftshift(fft(y, N)) / Fs;
% This S is complex; you can take either abs() or angle() of it to get
% magnitude and phase responses, respectively
figure;
plot(F2, abs(S));
% plot(F3, abs(S));
% plot(F4, abs(S));
title 'Fourier Transform of Audio';
xlabel 'Frequency (Hz)';
ylabel 'Magnitude';

74
lessons/lesson06/fft_2d.m Normal file
View File

@ -0,0 +1,74 @@
%% Lesson 7b: The FFT -- for images!
% * Explore how to perform and plot the FFT of a 2-D signal
% * Implement a filter by masking in the frequency domain
clc; clear; close all;
%% Image Example
% Low pass filtering
% Here we look at images. Think frequencies spatially. High frequency
% represents fast change in the image, low frequency represents slight
% change. Also frequenies have two dimensions, vertial and horizontal.
x = imread('bw-cat.jpg');
imshow(x);
%% 2-D FFT!
F = fftshift(fft2(x));
% Generate a mask (which will be a high-pass filter).
% This mask will be 1 for low frequencies, and 0 for high frequencies.
% Since the signal and its FFT are 2-D (an image), this will be a
% white square centered in the FFT.
lpf_mask = zeros(size(F));
[H, W] = size(F);
lpf_mask(floor(H/2-H/10):floor(H/2+H/10), ...
floor(W/2-W/10):floor(W/2+W/10)) = 1;
% Show the 2-D FFT of the image
figure;
subplot(121);
% Normalize FFT to range [0, 1]
imshow(log(abs(F)) / max(log(abs(F(:)))));
title 'Fourier transform';
% Show the LPF mask
subplot(122);
imshow(lpf_mask);
title 'LPF mask';
%% Perform a LPF by only multiplying by frequency mask
im_filtered_fft = lpf_mask .* F; % high frequencies removed
f = ifft2(ifftshift(im_filtered_fft)); % ifft2 == ifft 2-D
imshow(log(abs(im_filtered_fft)) / max(log(abs(im_filtered_fft(:)))));
title 'Filtered FFT';
%% Altered image vs. original image
% Check out how the new image looks a bit blurry. That's because we removed
% the high frequency band! All "edges" are less noticable.
%
% Alternatively, we can perform a high-pass filter. What would this do
% to the image? (Hint: see next section.)
figure;
subplot(121);
fnorm = abs(f) / max(abs(f(:)));
imshow(fnorm);
title 'High frequencies removed';
subplot(122);
xnorm = abs(double(x)) / max(double(x(:)));
imshow(xnorm);
title 'Original image';
%% Basic Edge Detection
% The difference between the old image and the new image: The edges!
sharp_image = abs(fnorm - xnorm);
sharp_image_norm = sharp_image / max(sharp_image(:));
imshow(sharp_image_norm);
%% Pinpoints these changes
edge_image = zeros(size(sharp_image_norm));
edge_image(sharp_image_norm > 3.5*std(sharp_image_norm(:))) = 1;
imshow(edge_image);
% Edge detection algorithms are one application of high-pass filters!
% If you want to get started with these, look up Sobel or Laplacian
% filters, which are simple convolutions that act as edge detectors/HPFs.

BIN
lessons/lesson06/handel.mat Normal file

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 236 KiB

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,66 @@
%% Lesson 6a: Polynomials
% Before we step into z transform, we should take a look at what functions
% are there in MATLAB to evaluate polynomials. There are 4 major functions
% to know about -- polyval, root/poly and conv.
clc; clear; close all;
%% polyval
% Allows you to evaluate polynomials specified as an array of coefficients.
p = [2 -2 0 -3]; % 2x^3 - 2x^2 - 3
x = -5:.05:5;
a = polyval(p,x);
a2 = 2*x.^3 - 2*x.^2 - 3;
figure;
subplot(2, 1, 1);
plot(x, a);
title('Using polyval');
subplot(2, 1, 2);
plot(x, a2);
title('Using algebraic expression');
% The graphs are the same!
%% roots/poly
% These two functions are ~inverses! They allow you
% to find the roots / coefficients of a vector of numbers
r = roots(p);
p1 = poly(r);
% `poly` will always return a monic polynomial (the highest coefficient
% will be 1).
%% residue
% Will apply later in the Signals course. Pretty much partial fractions
% from Calc I.
b = [-4 8];
a = [1 6 8];
[r, p, k] = residue(b, a);
[bb, aa] = residue(r, p, k); % can go both ways
% Note that a, b are row vectors, whereas r, p are column vectors! This
% convention is true when we look at tf/zpk forms.
%% conv
% You've probably heard this a lot from Prof. Fontaine.
% Convolution in the time domain is multiplication in the frequency domain
% (applying a LTI system to a signal is convolution in the time domain).
%
% Convolution is also used to multiply two polynomials together (if
% specified as an array of coefficients.)
a = [1 2 -3 4];
b = [5 0 3 -2];
p2 = conv(a, b); % Use convolution
x = -5:.05:5;
% a little experiment
figure;
subplot(2, 1, 1);
plot(x, polyval(a, x) .* polyval(b, x));
title('Multiplying polynomial values elementwise');
subplot(2, 1, 2);
plot(x, polyval(p2, x));
title('Using conv on convolved polynomials');

16
lessons/lesson06/splane.m Normal file
View File

@ -0,0 +1,16 @@
% `splane` creates a pole-zero plot using pole and zero inputs with the
% real and imaginary axes superimposed
function splane(z,p)
x1 = real(z);
x2 = real(p);
y1 = imag(z);
y2 = imag(p);
plot(x1, y1, 'o', x2, y2, 'x');
xlabel('Real Part');
ylabel('Imaginary Part');
axis('equal');
line([0 0], ylim(), 'LineStyle', ':');
line(xlim(), [0 0], 'LineStyle', ':');
end

Binary file not shown.

View File

@ -0,0 +1,237 @@
%% Lesson 6b: The Z-transform
% * Have a overview idea of the z transform
% * Know how to plot pole zero plots of the z transform, and what to infer
% * Know how to input a signal to the transfer function of z transform
clc; clear; close all;
%% Review
% Plot all discrete-time signals with `stem()`! Don't use `plot()`.
x = [2 4 7 2 0 8 5];
stem(x);
title("Discrete Time signal");
%% Overview of the z transform
% The z transform converts a discrete time signal into a complex frequency
% domain representation (a series of complex exponentials).
% There are two key motivations of the z transform:
%
% * By identifying the impulse response of the system we can determine how
% it would perform in different frequencies
% * By identifying the presence of increasing or decreasing oscillations in
% the impulse response of a system we can determine whether the system
% could be stable or not
%% Z transform
% One of the things we usually evaluate in the z transform is the pole zero
% plot, since it can tell us about stability and causality in
% different regions of convergence. Let us just look at one simple example
% of a pole zero plot.
%% Z transform - generate a pole zero plot
% There are multiple ways to generate the pole zero plot. If you are
% interested, you should look up tf2zp (and its inverse, zp2tf), pzplot,
% etc. We are going to introduce the most simple function -- zplane. In the
% example, b1 and a1 and coefficients of the numerator and denominator,
% i.e, the transfer function. The transfer function is the
% the ratio between output (denominator) and input (numerator).
b1 = [1]; % numerator
a1 = [1 -0.5]; % denominator
figure;
zplane(b1, a1);
%% BE CAREFUL!
% If the input vectors are COLUMN vectors, they would be interpreted as
% poles and zeros, and if they are ROW vectors, they would be interpreted
% as coefficients of the transfer function.
%% BE CAREFUL!
% zplane takes negative power coefficients, while tf2zp (the one used
% in the homework) uses positive power coefficients.
% In particular, note that polynomials with negative power efficients are
% LEFT-ALIGNED, while polynomials with positive power coefficients are
% RIGHT-ALIGNED. E.g., for positive coefficients b1 and [0 b1] are the
% same polynomial, but not so if negative coefficients. See the following
% example.
% $1/(1-0.5z^-1) = z/(z-0.5)$
figure;
zplane(b1, a1);
% $(0+z^-1)/(1-z^-1) = 1/(z-0.5)$
figure;
zplane([0 b1], a1);
%% tf2zp and zp2tf
b = [2 3 0];
a = [1 1/sqrt(2) 1/4];
[z, p, k] = tf2zp(b, a);
% alternatively, tf2zpk
figure;
zplane(z, p);
[b, a] = zp2tf(z, p, k);
%% Z transform - More examples!
b2 = [1];
a2 = [1 -1.5];
b3 = [1 -1 0.25];
a3 = [1 -23/10 1.2];
% Example 1 : One pole, outer region is stable and causal
figure;
subplot(3, 1, 1);
zplane(b1, a1);
title('$$H_1(z)=\frac{z}{z-\frac{1}{2}}$$', 'interpreter', 'latex');
% Example 2 : One pole, outer region is causal but not stable, inner region
% is stable but not causal
subplot(3, 1, 2);
zplane(b2, a2);
title('$$H_2(z)=\frac{z}{z-\frac{3}{2}}$$', 'interpreter', 'latex');
% Example 3 : Two poles, outer region is causal, middle region is stable
subplot(3, 1, 3);
zplane(b3, a3);
title('$$H_3(z)=\frac{(z-\frac{1}{2})^2}{(z-\frac{4}{5})(z-\frac{3}{2})}$$', ...
'interpreter', 'latex');
%% On Stability and Causality
% * The system is stable iff the region contains the unit circle.
% * The system is causal iff the region contains infinity.
% * If there is an infinity to the pole, then it's not stable.
% * If all the poles are in the unit circle, then the system could be both
% stable and causal.
%% Z transform - Impulse Response
% The impulse response is useful because its Fourier transform
% (the frequency response) allows us to observe how an input sinusoid
% at different frequencies will be transformed.
%
% The impulse response is obtained by applying the filter to a delta.
% There is a custom function to do this (`impz`), but you can also obtain
% it other ways.
%
% The impulse response for the running example is the following (can you
% derive this by hand?)
% $h[n] = (1/2)^n$
[h1, t] = impz(b1, a1, 8); % h is the IMPULSE RESPONSE
figure;
impz(b1, a1, 32); % for visualization don't get the return value
%% Z transform - Convolution
% You can apply a system on a signal in two ways:
% * Convolve with the impulse response (which we obtained just now).
% * Use the `filter` functions (which uses tf coefficients).
n = 0:1:5;
x1 = (1/2).^n;
y1 = conv(x1, h1);
figure;
subplot(2, 1, 1);
stem(y1);
title('Convolution between x_1 and h_1');
subplot(2, 1, 2);
y2 = filter(b1, a1, x1);
stem(y2);
title('Filter with b_1,a_1 and x_1');
xlim([0 14]);
% The above are the same! Except note that convolution creates a longer
% "tail."
%% freqz: digital frequency response
% The frequency response is the z-transform of the impulse response. It
% tells us how the system will act on each frequency of the input signal
% (scaling and phase-shifting).
%
% This is a somewhat complicated setup -- you may want to save it to a
% function if you have to do this repeatedly.
[H, w] = freqz(b1, a1);
Hdb = 20*log10(abs(H));
Hph = rad2deg(unwrap(angle(H)));
% Note the above, especially the `unwrap` function! Make sure to understand
% what each of the functions above is for.
figure;
subplot(2, 1, 1);
plot(w, Hdb);
xlabel("Frequency (rad)");
ylabel("|H| (dB)");
xlim([0 pi]);
xticks([0 pi/2 pi]);
xticklabels({'0', '\pi/2', '\pi'});
title("Magnitude Response");
subplot(2, 1, 2);
plot(w, Hph);
xlabel("Frequency (rad)");
ylabel("Phase (deg)");
xlim([0 pi]);
xticks([0 pi/2 pi]);
xticklabels({'0', '\pi/2', '\pi'});
title("Phase Response");
%% Another example of freqz
% By default, `freqz` knows nothing about the sampling rate, so the
% frequency scale is digital. We can make it in analog frequency by
% specifying the sampling rate of the digital signal.
n = 1024; % number of samples in frequency response
fs = 20000; % sampling frequency of input signal
[H, f] = freqz(b1, a1, n, fs);
Hdb = 20*log10(abs(H));
Hph = rad2deg(unwrap(angle(H)));
figure;
subplot(2, 1, 1);
plot(f, Hdb);
xlabel("Frequency (Hz)");
ylabel("|H| (dB)")
xlim([0 fs/2]);
title("Magnitude Response");
subplot(2, 1, 2);
plot(f, Hph);
xlabel("Frequency (Hz)");
ylabel("Phase (deg)");
xlim([0 fs/2]);
title("Phase Response");
%% Yet another example of freqz
zer = -0.5;
pol = 0.9*exp(j*2*pi*[-0.3 0.3]');
figure;
zplane(zer, pol);
[b4,a4] = zp2tf(zer, pol, 1);
[H,w] = freqz(b4, a4);
Hdb = 20*log10(abs(H));
Hph = rad2deg(unwrap(angle(H)));
figure;
subplot(2, 1, 1);
plot(w, Hdb);
xlabel("Frequency (rad)");
ylabel("|H| (dB)");
xlim([0 pi]);
xticks([0 pi/2 pi]);
xticklabels({'0', '\pi/2', '\pi'});
title("Magnitude Response");
subplot(2, 1, 2);
plot(w, Hph);
xlabel("Frequency (rad)");
ylabel("Phase (deg)");
xlim([0 pi]);
xticks([0 pi/2 pi]);
xticklabels({'0', '\pi/2', '\pi'});
title("Phase Response");

Binary file not shown.