uploaded all materials

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

3
README.md Normal file
View File

@ -0,0 +1,3 @@
notes from matlab seminar
thanks to cat van west for all the knowledge :D

138
hw1/Ryan_hw1_012424.m Normal file
View File

@ -0,0 +1,138 @@
%%%% ECE210-B Matlab Seminar, Homework 1.
% james ryan, 1/24/24
% preamble
close all;
clear;
clc;
%% Scale-'ers
% (1)
% Takes the absolute value of
% sin(pi/3)
% PLUS
% j divided by secant of (-5/3)*pi
a = abs(sin(pi ./ 3) ...
+ ((1 * j) ./ (sec((-5 * pi) / 3))) ...
);
% (2)
% n = 3, cubic root
l = nthroot(8, 3);
% (3)
% [1, 2, 3, ..., 79, 80]
u_mat = 1:80;
% Sums all the terms from u_mat, scales by 2 / 6!, and takes the square root
u = sqrt((2 / factorial(6)) * sum(u_mat));
% q4
% takes the square
% of imaginary value
% of the floor
% of the log
% of the square root of 66
% taken to the power of 7j
m = (imag(floor(log(sqrt(66).^(7 * j))))).^2;
%% Mother...?
% (1)
% Makes a 1x4 matrix from a l u & m,
% and transposes the formed matrix into a 4x1 matrix
A = [a; l; u; m];
% (2)
% makes a 2x2 matrix using a l u & m.
F = [a l; u m];
% (3)
% takes the non-conjugate transpose of F
T = F.';
% (4)
% takes the inverse of the matrix product of T * F
B = inv(T * F);
check = B * (T * F)
% (5)
% Makes a square matrix comprised of T and F
C = [T F; F T];
%% Cruelty
meanB = mean(B, "all"); % sums "all" values in matrix B into one scalar
% squashes every row down into the sum of all elements
% in a given row
meanC = mean(C, 2); % ... or takes the mean of every value along a
% dimension (the 2nd dimension), and squashes
% the matrix down into one dimension.
%% Odd Types
% eval one
evalOne = T + F;
%{
comments:
evalOne =
2 5
5 8
This makes sense, considering T was [1 3; 2 4] and F was [1 2; 3 4]
It seems like, at the same index on both matrices, the value occupying
that spot was taken from both and summed.
%}
% eval 2
evalTwo = T + 1;
%{
comments:
evalTwo =
2 4
3 5
This makes sense, since it seems like 1 was interpreted as a 2x2 matrix
occupied only by 1's. The same summing algorithm was applied, and every
value occupying T was incremented by 1.
This could be confusing if we were multiplying instead of dividing,
since it would make more intuitive sense to be referring to the
identity matrix as 1, rather than a matrix filled wuth 1's.
%}
% eval kicks
evalKicks = A + C;
%{
comments:
evalKicks =
2 5 4 6
3 6 6 8
2 4 4 7
4 6 5 8
A and C are not the same dimensions. A is 1x4 while C is 4x4.
It seems that C was sliced by rows in order to let this
operation make sense.
so for every Row in C, the value corresponding
to the matching column in A was added to that value in C.
Put nicely: Every row in C (a 1x4 matrix) was summed with A,
and then returned to the row index it previously occupied in C proper.
%}
%% Not What it Seems...
for k = [3 5 10 300 1e6]
% sets up a 1xk matrix of `k` evenly spaced vals that are [0, 1]
genericMatrix = linspace(0, 1, k);
% squares every val in the matrix, sums all squared vals together, and divs
% every element by k.
% Essentially -- average value of x^2 from 0 to 1
% Also known as power, according to fred
genericScalar = sum(genericMatrix.^2) ./ k;
end

View File

@ -0,0 +1,150 @@
%%%% ECE210-B Matlab Seminar, Homework 1.
% james ryan, 1/24/24
% <-.0> style point: please ensure files are named so that
% MATLAB (sorry, i'd rather grade in Octave, but this is not
% Octave seminar...) can run them! this one had a space in it.
% preamble
close all;
clear;
clc;
%% Scale-'ers
% (1)
% Takes the absolute value of
% sin(pi/3)
% PLUS
% j divided by secant of (-5/3)*pi
a = abs(sin(pi ./ 3) ...
+ ((1 * j) ./ (sec((-5 * pi) / 3))) ...
);
% MATLAB interptes complex literals, so you could also write
% `1j`.
% (2)
% n = 3, cubic root
l = nthroot(8, 3);
% could also do `8^(1/3)`, if you're mathematically inclined.
% (3)
% [1, 2, 3, ..., 79, 80]
u_mat = 1:80;
% Sums all the terms from u_mat, scales by 2 / 6!, and takes the square root
u = sqrt((2 / factorial(6)) * sum(u_mat));
% q4
% takes the square
% of imaginary value
% of the floor
% of the log
% of the square root of 66
% taken to the power of 7j
m = (imag(floor(log(sqrt(66).^(7 * j))))).^2;
% since these are scalars, the `.^` is not strictly necessary,
% but i see you have a vector bent...
%% Mother...?
% (1)
% Makes a 1x4 matrix from a l u & m,
% and transposes the formed matrix into a 4x1 matrix
A = [a; l; u; m];
% (2)
% makes a 2x2 matrix using a l u & m.
F = [a l; u m];
% (3)
% takes the non-conjugate transpose of F
T = F.';
% (4)
% takes the inverse of the matrix product of T * F
B = inv(T * F);
check = B * (T * F)
% aaaaaaa no semicolon
% (5)
% Makes a square matrix comprised of T and F
C = [T F; F T];
%% Cruelty
meanB = mean(B, "all"); % sums "all" values in matrix B into one scalar
% squashes every row down into the sum of all elements
% in a given row
meanC = mean(C, 2); % ... or takes the mean of every value along a
% dimension (the 2nd dimension), and squashes
% the matrix down into one dimension.
%% Odd Types
% eval one
evalOne = T + F;
%{
comments:
evalOne =
2 5
5 8
This makes sense, considering T was [1 3; 2 4] and F was [1 2; 3 4]
It seems like, at the same index on both matrices, the value occupying
that spot was taken from both and summed.
%}
% eval 2
evalTwo = T + 1;
%{
comments:
evalTwo =
2 4
3 5
This makes sense, since it seems like 1 was interpreted as a 2x2 matrix
occupied only by 1's. The same summing algorithm was applied, and every
value occupying T was incremented by 1.
This could be confusing if we were multiplying instead of dividing,
since it would make more intuitive sense to be referring to the
identity matrix as 1, rather than a matrix filled wuth 1's.
%}
% eval kicks
evalKicks = A + C;
%{
comments:
evalKicks =
2 5 4 6
3 6 6 8
2 4 4 7
4 6 5 8
A and C are not the same dimensions. A is 1x4 while C is 4x4.
It seems that C was sliced by rows in order to let this
operation make sense.
so for every Row in C, the value corresponding
to the matching column in A was added to that value in C.
Put nicely: Every row in C (a 1x4 matrix) was summed with A,
and then returned to the row index it previously occupied in C proper.
%}
% <+.06> love the extensive commentary.
%% Not What it Seems...
for k = [3 5 10 300 1e6]
% sets up a 1xk matrix of `k` evenly spaced vals that are [0, 1]
genericMatrix = linspace(0, 1, k);
% squares every val in the matrix, sums all squared vals together, and divs
% every element by k.
% Essentially -- average value of x^2 from 0 to 1
% Also known as power, according to fred
genericScalar = sum(genericMatrix.^2) ./ k;
end
% right, and what *is* that average, in terms of math objects?

105
hw2/Ryan_hw2_013124.m Normal file
View File

@ -0,0 +1,105 @@
%%%% ECE210-B Matlab Seminar, Homework 2.
% james kit paul thomas ryan murphy, 1/31/24
% this is james' full name. -A.
% this should run in octave (7.3.0)!
close all; clear; clc;
%% Spatial Awareness
% (1)
A = reshape(0:63, 8, 8).';
B = 2 .^ A;
% (2)
B_colvec = reshape(B, [], 1);
% primes(64) = [2, 3, 5... 61]
% since we're asking for the prime indices from index 1 to index 64,
% getting all prime numbers within [0, 64] seems fitting
B_primeinds = B_colvec(primes(length(B_colvec)));
% (3)
B_primeinds_geometric_mean = prod(B_primeinds) .^ (1 / length(B_primeinds));
% (4)
% (1, :) -- Grab ALL of row 1 (aka the top row) in the matrix.
% fliplr -- flip left to right
A(1, :) = fliplr(A(1, :)); % :)
% (5)
% Keep all rows, keep all cols minus the end col
A_lastcol_del = A(1:8, 1:end-1);
%% Smallest Addition
% (1)
N = 100;
t = linspace(0, 6.66, N);
erf_integrand = exp(-t .^ 2);
figure;
title("Plot of e^{-t^2}, (100pts, [0, 6.66])");
xlabel("time");
ylabel("e^{-t^2}");
plot(t, erf_integrand);
% (2)
% derivative approximation,
% form some dt being the distance between points on our time axis
% form the derivative by dividing the formed erf_integrand over dt
dt = t(2) - t(1);
dfdt = diff(erf_integrand) ./ dt;
% padding op
dfdt = dfdt([1 1:end]);
% mean squared error between approximate taken and real erf deriv
dfdt_anal = -2 .* t .* exp( -t .^ 2);
msqerr_dfdt = (1 / N) .* mean((dfdt - dfdt_anal) .^ 2);
figure; hold on;
title('d/dt[e^{-t^2}] -- analytic vs approximate (100pts, [0, 6.66])');
xlabel('time');
ylabel('d/dt[-exp(t^2)]');
plot(t, dfdt, 'g-');
plot(t, dfdt_anal, 'r-');
% (3)
% integral approx
% take the area under the curve between t(n) and t(n-1)
% sum the area and scale by 2/sqrt(pi)
figure; hold on;
title('erf -- analytic vs approximate (100pts, [0, 6.66])');
xlabel('time');
ylabel('erf(t)');
% baseline
erf_anal = (sqrt(pi) ./ 2) .* erf(t);
% cum sum
erf_approx_cumsum = cumsum(erf_integrand) .* dt;
msqerr_erf_cumsum = (1 / N) .* mean((erf_approx_cumsum - erf_anal) .^ 2);
% cum trapz
erf_approx_cumtrapz = cumtrapz(erf_integrand) .* dt;
msqerr_erf_cumtrapz = (1 / N) .* mean((erf_approx_cumtrapz - erf_anal) .^ 2);
%{
The mean-square error of the cumsum op is 5 orders of magnitude larger
than the result from the cumtrapz op.
Qualitatively, the cumsum approximation (blue line) is noticably further
away than the cumtrapz approximation (red line). the cumsum also has
a non-negligible y intercept, which is much further than the cumtrapz
assumption. However, the cumtrapz is basically on top of the analytic
function (green line), which is especially novel considering both ops
used the same data set.
%}
% check
plot(t, erf_approx_cumsum, "b-");
plot(t, erf_approx_cumtrapz, "r-");
plot(t, erf_anal, "g-");

View File

@ -0,0 +1,117 @@
%%%% ECE210-B Matlab Seminar, Homework 2.
% james kit paul thomas ryan murphy, 1/31/24
% this is james' full name. -A.
% <+.01> i needed this.
% this should run in octave (7.3.0)!
% <3, turns out it also runs in MATLAB. love the comment,
% though.
close all; clear; clc;
%% Spatial Awareness
% (1)
A = reshape(0:63, 8, 8).';
B = 2 .^ A;
% (2)
B_colvec = reshape(B, [], 1);
% primes(64) = [2, 3, 5... 61]
% since we're asking for the prime indices from index 1 to index 64,
% getting all prime numbers within [0, 64] seems fitting
B_primeinds = B_colvec(primes(length(B_colvec)));
% very clean, like it.
% (3)
B_primeinds_geometric_mean = prod(B_primeinds) .^ (1 / length(B_primeinds));
% (4)
% (1, :) -- Grab ALL of row 1 (aka the top row) in the matrix.
% fliplr -- flip left to right
A(1, :) = fliplr(A(1, :)); % :)
% (5)
% Keep all rows, keep all cols minus the end col
A_lastcol_del = A(1:8, 1:end-1);
% that's one way! another is to assign to A (or a copy) with an
% empty matrix:
% A(:, end) = [];
%% Smallest Addition
% (1)
N = 100;
t = linspace(0, 6.66, N);
erf_integrand = exp(-t .^ 2);
figure;
title("Plot of e^{-t^2}, (100pts, [0, 6.66])");
xlabel("time");
ylabel("e^{-t^2}");
plot(t, erf_integrand);
% (2)
% derivative approximation,
% form some dt being the distance between points on our time axis
% form the derivative by dividing the formed erf_integrand over dt
dt = t(2) - t(1);
dfdt = diff(erf_integrand) ./ dt;
% padding op
dfdt = dfdt([1 1:end]);
% mean squared error between approximate taken and real erf deriv
dfdt_anal = -2 .* t .* exp( -t .^ 2);
msqerr_dfdt = (1 / N) .* mean((dfdt - dfdt_anal) .^ 2);
% <-.03> (repeated) this will underreport -- `mean()` already
% does a divide by the length of the array, so another divide
% by N is not necessary.
figure; hold on;
title('d/dt[e^{-t^2}] -- analytic vs approximate (100pts, [0, 6.66])');
xlabel('time');
ylabel('d/dt[-exp(t^2)]');
plot(t, dfdt, 'g-');
plot(t, dfdt_anal, 'r-');
% (3)
% integral approx
% take the area under the curve between t(n) and t(n-1)
% sum the area and scale by 2/sqrt(pi)
figure; hold on;
title('erf -- analytic vs approximate (100pts, [0, 6.66])');
xlabel('time');
ylabel('erf(t)');
% baseline
erf_anal = (sqrt(pi) ./ 2) .* erf(t);
% cum sum
erf_approx_cumsum = cumsum(erf_integrand) .* dt;
msqerr_erf_cumsum = (1 / N) .* mean((erf_approx_cumsum - erf_anal) .^ 2);
% cum trapz
erf_approx_cumtrapz = cumtrapz(erf_integrand) .* dt;
msqerr_erf_cumtrapz = (1 / N) .* mean((erf_approx_cumtrapz - erf_anal) .^ 2);
%{
The mean-square error of the cumsum op is 5 orders of magnitude larger
than the result from the cumtrapz op.
Qualitatively, the cumsum approximation (blue line) is noticably further
away than the cumtrapz approximation (red line). the cumsum also has
a non-negligible y intercept, which is much further than the cumtrapz
assumption. However, the cumtrapz is basically on top of the analytic
function (green line), which is especially novel considering both ops
used the same data set.
%}
% <+.02> love the explanatory comment. `cumtrapz` is
% surprisingly good at what it does!
% check
plot(t, erf_approx_cumsum, "b-");
plot(t, erf_approx_cumtrapz, "r-");
plot(t, erf_anal, "g-");

BIN
hw2/notes/lesson02.zip Normal file

Binary file not shown.

View File

@ -0,0 +1,75 @@
%% Lesson 2c: Numerical estimation of integrals and derivatives
% Numerical integration and differentiation are a staple of numerical
% computing. We will now see how easy these are in MATLAB!
clc; clear; close all;
%% The diff and cumsum functions
% Note the lengths of z, zdiff, and zcumsum! (Fencepost problem)
z = [0 5 -2 3 4];
zdiff = diff(z);
zcumsum = cumsum(z);
%% Setup: A simple function
% Let's start with a simple example: y = x.^2. The domain is N points
% linearly sampled from lo to hi.
lo = -2;
hi = 2;
N = 1e2;
x = linspace(lo, hi, N);
y = x.^2;
plot(x, y);
title('x^2');
%% Numerical (Approximate) Derivatives
% We can calculate a difference quotient between each pair of (x,y) points
% using the diff() function.
dydx = diff(y)./diff(x); % difference quotient
figure();
plot(x(1:end-1), dydx);
%% Numerical (Approximate) Integrals
% Now suppose we want to approximate the cumulative integral (Riemann sum)
% of a function.
xdiff = diff(x);
dx = xdiff(1); % spacing between points
dx = (hi-lo) / (N-1); % alternative to the above (note: N-1)
Y = cumsum(y) * dx; % Riemann sum
figure();
plot(x, Y);
%% Error metrics: Check how close we are!
% dydx should be derivative of x.^2 = 2*x
dydx_actual = 2 * x;
% Y should be \int_{-2}^{x}{t.^2 dt}
Y_actual = (x .^3 - (-2)^3) / 3;
% Slightly more accurate -- can you figure out why?
% Y_actual = (x .^3 - (-2-dx)^3) / 3;
% Error metric: MSE (mean square error) or RMSE (root mean square error)
% Try changing N and see how the error changes. Try this with both the
% integral and derivative.
% estimated = dydx;
% actual = dydx_actual(1:end-1);
estimated = Y;
actual = Y_actual;
mse = mean((estimated - actual) .^ 2);
rmse = rms(estimated - actual);
%% Fundamental Theorem of Calculus
% Now, use the approximate derivative to get the original function, y back
% as yhat and plot it. You may need to use/create another variable for
% the x axis when plotting.
figure();
yhat = diff(Y)./diff(x); % differentiate Y
plot(x(1:end-1), yhat);
figure();
yhat2 = cumsum(dydx) * dx; % integrate dydx
plot(x(1:end-1), yhat2);

1378
hw2/notes/octave-log.txt Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,124 @@
%% Lesson 2a: More vector and matrix operations
%
% Objectives:
% * Understand how to perform vector operations in MATLAB
% * Understand arithmetic and basic functions in MATLAB
%% Vector operations
% In lesson 1, we saw how to create a vector with the colon operator and
% linspace. Now let's perform some operations on them!
%
% There are two common classes of operations that you can perform on vectors:
% element-wise operations (which produce another vector) and aggregate
% operations (which produce a scalar value). There are also many functions that
% don't fall under these categories, but these cover many of the common
% functions.
%% Element-wise operations
% Many operations that work on scalars (which are really degenerate matrices)
% also work element-wise on vectors (or matrices).
x = 0:0.01:2*pi; % Create a linearly-spaced vector
y = sin(x); % sin() works element-wise on vectors!
y = abs(x); % same with abs()!
y = x .^ 4; % element-wise power
y = power(x, 4); % same as above
plot(x, y); % Plot y vs. x (line graph)
title('y vs. x');
%% Aggregate operations
% Another common class of operations produce a single output or statistic about
% a vector (or matrix).
length(x); % number of elements in x
sum(x); % sum of the elements of x
mean(x); % average of the elements of x
min(x); % minimum element of x
diff(x); % difference between adjacent elements of x
%% Exercise 1 : Vector operations
T = 1e-6; % Sampling period (s)
t = 0:T:2e-3; % Time (domain/x-axis)
f0 = 50; % Initial frequency (Hz)
b = 10e6; % Chirp rate (Hz/s)
A = 10; % Amplitude
y1 = A * cos(2*pi*f0*t + pi*b*t.^2);
figure;
plot(t,y1);
%% Exercise: Numerical calculus
% See numerical_calculus.m.
%% Basic indexing in MATLAB
% The process of extracting values from a vector (or matrix) is called
% "indexing." In MATLAB, indices start at 1, rather than 0 in most languages
% (in which it is more of an "offset" than a cardinal index).
%% Exercise 2 : Basic indexing
% The syntax for indexing is "x(indices)", where x is the variable to index,
% and indices is a scalar or a vector of indices. There are many variations on
% this. Note that indices can be any vector
x(1); % first element of x
x(1:3); % elements 1, 2 and 3 (inclusive!)
x(1:length(x)); % all elements in x
x(1:end); % same as above
x(:); % same as above
x(end); % last element of x
x(3:end); % all elements from 3 onwards
x([1,3,5]); % elements 1, 3, and 5 from x
x(1:2:end); % all odd-indexed elements of x
ind = 1:2:length(x);
x(ind); % same as the previous example
%% Exercises to improve your understanding
% Take some time to go through these on your own.
x([1,2,3]); % Will these produce the same result?
x([3,2,1]);
x2 = 1:5;
x2(6); % What will this produce?
x2(0); % What will this produce?
x2(1:1.5:4); % What will this produce?
ind = 1:1.5:4;
x2(ind); % What will this produce?
z = 4;
z(1); % What will this produce?
%% Matrix operations
% Matrices is closely related to vectors, and we have also explored some matrix
% operations last class. This class, we are going to explore functions that are
% very useful but are hard to grasp for beginners, namely reshape, meshgrid,
% row-wise and column-wise operations.
%% Reshape
% Change a matrix from one shape to another. The new shape has to have the same
% number of elements as the original shape.
%
% When you are reshaping an array / matrix, the first dimension is filled
% first, and then the second dimension, so on and so forth. I.e., elements
% start filling down columns, then rows, etc.
M = 1:100;
N1 = reshape(M,2,2,[]); % It would create a 2*2*25 matrix
N2 = reshape(M,[2,2,25]); % Same as N1
N2(:,:,25); % Gives you 97,98,99,100
N2(:,1,25); % Gives you 97 and 98
%% Row-wise / Column-wise operations
% Vector operations can also be performed on matrices. We can perform a vector
% operation on each row/column of a matrix, or on a particular row/column by
% indexing.
H = magic(4); % create the magical matrix H
sum(H,1); % column wise sum, note that this is a row vector(default)
fliplr(H); % flip H from left to right
flipud(H); % flip H upside down
H(1,:) = fliplr(H(1,:)); % flip only ONE row left to right
H(1,:) = []; % delete the first row
%% Exercise 7 : Matrix Operations
H2 = randi(20,4,5); % random 4x5 matrix with integers from 1 to 20
sum(H2(:,2));
mean(H2(3,:));
C = reshape(H2,2,2,5);
C(2,:,:) = [];

181
hw3/Ryan_HW3_021424.m Normal file
View File

@ -0,0 +1,181 @@
%%%% ECE-210-B HW 3 - Plotting
% James Ryan, 02/14/24
% preamble
close all; clear; clc;
%% Two Dimensions
% (1)
x = linspace(0, 2*pi, 50);
f = sin(x);
figure;
plot(x, f, "g");
xlim([0 2*pi]); % plot only within x's range
xticks([0:pi/2:2*pi]);
xticklabels({'0','\pi/2','\pi','3\pi/2','2\pi'})
xlabel("x");
ylabel("sin(x)");
title('Plot of sin(x) over 50 evenly spaced points between [0, 2\pi]');
% (2)
x; % 50 evenly spaced pts between [0, 2pi]
g = cos(2.*x);
figure;
hold on;
plot(x, f, "g");
plot(x, g, "b");
hold off;
xlim([0 2*pi]); % plot only within x's range
xticks([0:pi/2:2*pi]);
xticklabels({'0','\pi/2','\pi','3\pi/2','2\pi'})
xlabel("x");
ylabel("y");
legend( 'y = sin(x)', ...
'y = cos(2x)');
title('knock knock! whose there? sin! sine who? $\pm\sqrt{\frac{1 + cos2\theta}{2}}$', "interpreter", "latex");
% (3)
figure;
x; % 50 evenly spaced pts between [0, 2pi]
% top plot - f = sin(x)
subplot(2,1,1);
stem(x, f, "r*");
grid on
xlim([0 2*pi]);
xticks([0:pi/2:2*pi]);
xticklabels({'0','\pi/2','\pi','3\pi/2','2\pi'})
xlabel("t [s]"); % we're pretending its time now :)
ylabel("Position [d]");
title('Position of a controlled laser pointer, relative to origin location');
%subtitle('Sampled 50 times over 2\pi seconds.');
% bottom plot - g = cos(2x)
% changing cos(2x)'s amplitude; computing amplitude ratio in d
rand_amp = 100 * rand;
g = rand_amp .* g;
amplitude_ratio_db = 20.*log10(rand_amp);
subplot(2,1,2);
stem(x, g, "color", "#D95319", "Marker", "+", "MarkerEdgeColor", "#D95319", "MarkerFaceColor", "#D95319");
grid on
xlim([0 2*pi]);
xticks([0:pi/2:2*pi]);
xticklabels({'0','\pi/2','\pi','3\pi/2','2\pi'})
yticks(linspace(-rand_amp, rand_amp, 5));
xlabel("t [s]");
ylabel("Position [d]");
title(sprintf('Pet cats vertical position while seeking laser pointer. \n Position Ratio (vs sin) [dB]: %d' ...
,amplitude_ratio_db));
%subtitle('Sampled 50 times over 2\pi seconds.');
% (4)
pointer = imread("./pointer.jpg");
%{
returns a 720x1280x3 matrix, corresponding to
720 rows
1280 columns
3 color channels per (row,col) pair
to form a complete color image, in matrix form.
Each entry in the matrix is stored as uint8, or
an 8-bit integer, implying colors are specified as
hex codes (eg #RRGGBB - specify the Red, Green, and
Blue values in HEX, 8 bits per channel, 3 channels).
%}
% Invert color channels
new_pointer = 255 - pointer;
figure;
imshow(pointer);
figure;
imshow(new_pointer);
%% Three Dimensions
% (1)
x = 0:.01:1;
y = x;
z = exp(-x.^2 - y.^2);
figure;
% "Create this plot
% three times
% in three different subplots
% using plot3..., scatter3, surf, *and* mesh (4 tools?)"
% I'm making 4 plots, because you said "and", meaning all the tools.
% plot3
subplot(2,2,1);
plot3(x,y,z);
xlabel("x");
ylabel("y");
zlabel("z");
title('z = exp(-x^2 - y^2) (PLOT3)');
legend('z = exp(-x^2 - y^2)');
daspect([1 1 1]);
view([-2 2 1]);
grid on;
% scatter3
subplot(2,2,2);
scatter3(x,y,z);
xlabel("x");
ylabel("y");
zlabel("z");
title('z = exp(-x^2 - y^2) (SCATTER)');
legend('z = exp(-x^2 - y^2)');
daspect([1 1 1]);
view([-2 2 1]);
grid on;
% surf
[X, Y] = meshgrid(x);
Z = exp(-X.^2 - Y.^2);
subplot(2,2,3);
surf(X,Y,Z);
xlabel("x");
ylabel("y");
zlabel("z");
title('z = exp(-x^2 - y^2) (SURF)');
legend('z = exp(-x^2 - y^2)');
grid on;
view([-2 5 1.3]);
% mesh
subplot(2,2,4);
mesh(X,Y,Z);
xlabel("x");
ylabel("y");
zlabel("z");
title('z = exp(-x^2 - y^2) (MESH)');
legend('z = exp(-x^2 - y^2)');
grid on;
view([-2 5 1.3]);
% (2)
t = 0:0.01:1;
x = t.*cos(27.*t);
y = t.*sin(27.*t);
z = t;
figure;
plot3(x,y,t);
xlabel("x");
ylabel("y");
zlabel("z");
title('Wheeee!');
grid on;
daspect([1 1 1]);
view([90 90 20]);

View File

@ -0,0 +1,195 @@
%%%% ECE-210-B HW 3 - Plotting
% James Ryan, 02/14/24
% preamble
close all; clear; clc;
%% Two Dimensions
% (1)
x = linspace(0, 2*pi, 50);
f = sin(x);
figure;
plot(x, f, "g");
xlim([0 2*pi]); % plot only within x's range
xticks([0:pi/2:2*pi]);
xticklabels({'0','\pi/2','\pi','3\pi/2','2\pi'})
xlabel("x");
ylabel("sin(x)");
title('Plot of sin(x) over 50 evenly spaced points between [0, 2\pi]');
% (2)
x; % 50 evenly spaced pts between [0, 2pi]
g = cos(2.*x);
figure;
hold on;
plot(x, f, "g");
plot(x, g, "b");
hold off;
xlim([0 2*pi]); % plot only within x's range
xticks([0:pi/2:2*pi]);
xticklabels({'0','\pi/2','\pi','3\pi/2','2\pi'})
xlabel("x");
ylabel("y");
legend( 'y = sin(x)', ...
'y = cos(2x)');
% <-.02> (style) one thing about tabs: they don't always line
% up the same way on other people's machines. this indentation
% looks... strange to me, with my 8-space tabstops.
title('knock knock! whose there? sin! sine who? $\pm\sqrt{\frac{1 + cos2\theta}{2}}$', "interpreter", "latex");
% <+.02> nice.
% (3)
figure;
x; % 50 evenly spaced pts between [0, 2pi]
% top plot - f = sin(x)
subplot(2,1,1);
stem(x, f, "r*");
grid on
xlim([0 2*pi]);
xticks([0:pi/2:2*pi]);
xticklabels({'0','\pi/2','\pi','3\pi/2','2\pi'})
xlabel("t [s]"); % we're pretending its time now :)
ylabel("Position [d]");
title('Position of a controlled laser pointer, relative to origin location');
subtitle('Sampled 50 times over 2\pi seconds.');
% <+.01> the theme here really gets me.
% bottom plot - g = cos(2x)
% changing cos(2x)'s amplitude; computing amplitude ratio in d
rand_amp = 100 * rand;
g = rand_amp .* g;
amplitude_ratio_db = 20.*log10(rand_amp);
subplot(2,1,2);
stem(x, g, "color", "#D95319", "Marker", "+", "MarkerEdgeColor", "#D95319", "MarkerFaceColor", "#D95319");
% (style) these are very long lines...
grid on
xlim([0 2*pi]);
xticks([0:pi/2:2*pi]);
xticklabels({'0','\pi/2','\pi','3\pi/2','2\pi'})
yticks(linspace(-rand_amp, rand_amp, 5));
% usually ticks are nicely readable numbers for, well,
% readability.
xlabel("t [s]");
ylabel("Position [d]");
title(sprintf('Pet cats vertical position while seeking laser pointer. \n Position Ratio (vs sin) [dB]: %d' ...
,amplitude_ratio_db));
% (interesting place for that comma)
subtitle('Sampled 50 times over 2\pi seconds.');
% (4)
pointer = imread("./pointer.jpg");
% <-.05> image was not submitted! i went and found one...
%{
returns a 720x1280x3 matrix, corresponding to
720 rows
1280 columns
3 color channels per (row,col) pair
to form a complete color image, in matrix form.
Each entry in the matrix is stored as uint8, or
an 8-bit integer, implying colors are specified as
hex codes (eg #RRGGBB - specify the Red, Green, and
Blue values in HEX, 8 bits per channel, 3 channels).
%}
% Invert color channels
new_pointer = 255 - pointer;
figure;
imshow(pointer);
figure;
imshow(new_pointer);
%% Three Dimensions
% (1)
x = 0:.01:1;
y = x;
z = exp(-x.^2 - y.^2);
figure;
% "Create this plot
% three times
% in three different subplots
% using plot3..., scatter3, surf, *and* mesh (4 tools?)"
% I'm making 4 plots, because you said "and", meaning all the tools.
% that is indeed what i meant for you to do. good catch.
% plot3
subplot(2,2,1);
plot3(x,y,z);
xlabel("x");
ylabel("y");
zlabel("z");
title('z = exp(-x^2 - y^2) (PLOT3)');
legend('z = exp(-x^2 - y^2)');
daspect([1 1 1]);
view([-2 2 1]);
grid on;
% scatter3
subplot(2,2,2);
scatter3(x,y,z);
xlabel("x");
ylabel("y");
zlabel("z");
title('z = exp(-x^2 - y^2) (SCATTER)');
legend('z = exp(-x^2 - y^2)');
daspect([1 1 1]);
view([-2 2 1]);
grid on;
% <-.00> i was not totally clear here, so i'll let this slide,
% but i meant plot the surface itself using `scatter` and
% `plot3`.
% surf
[X, Y] = meshgrid(x);
Z = exp(-X.^2 - Y.^2);
subplot(2,2,3);
surf(X,Y,Z);
xlabel("x");
ylabel("y");
zlabel("z");
title('z = exp(-x^2 - y^2) (SURF)');
legend('z = exp(-x^2 - y^2)');
grid on;
view([-2 5 1.3]);
% mesh
subplot(2,2,4);
mesh(X,Y,Z);
xlabel("x");
ylabel("y");
zlabel("z");
title('z = exp(-x^2 - y^2) (MESH)');
legend('z = exp(-x^2 - y^2)');
grid on;
view([-2 5 1.3]);
% (2)
t = 0:0.01:1;
x = t.*cos(27.*t);
y = t.*sin(27.*t);
z = t;
figure;
plot3(x,y,t);
xlabel("x");
ylabel("y");
zlabel("z");
title('Wheeee!');
grid on;
daspect([1 1 1]);
view([90 90 20]);

BIN
hw3/pointer.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 123 KiB

221
hw4/Ryan_HW4_022124.m Normal file
View File

@ -0,0 +1,221 @@
%%%% ECE-210-B HW 4 - Functions and Objects
% James Ryan, 02/21/24
% preamble
close all; clear; clc;
%% My Sinc Is Broken
% (1)
% see deriv.m
x = linspace(-5, 5, 1e3);
sinc_x = sinc(x);
deriv_sinc = deriv(sinc_x, x);
% see antideriv.m
% approximates an integral of a given function using `cumtrapz`
int_sinc = antideriv(sinc_x, x);
% (2)
% see switchsign.m
% (3)
[extrema_sinc_x, extrema_x] = extrema(sinc_x, x);
[inflect_sinc_x, inflect_x] = inflections(sinc_x, x);
% (4)
figure;
plot(x, sinc_x, x, int_sinc, x, deriv_sinc, ...
extrema_x, extrema_sinc_x, 'r*', ...
inflect_x, inflect_sinc_x, 'bo');
ylim([-2 2.45]);
xlim([-5, 5]);
ylabel("y-axis");
xlabel("x-axis");
grid on;
title( {'y = sinc(x) plotted over 1000 evenly spaced pts between x \epsilon [-5,5]', ...
'Plotted alongside its first derivative and antiderivative.'});
legend( 'y = sinc(x)',"$\int [sinc(x)] dx$",'$\frac{d}{dx} [sinc(x)]$', ...
'Points of Extrema', 'Inflection Points', ...
"Interpreter","latex");
%% Objectification
% (1)
% Matlab Classic Noteworthy Logo (TM) (C) (Not-for-individual-sale)
L = 160*membrane(1,100);
f = figure;
ax = axes;
s = surface(L);
s.EdgeColor = 'none';
view(3)
ax.XLim = [1 201];
ax.YLim = [1 201];
ax.ZLim = [-53.4 160];
ax.CameraPosition = [-145.5 -229.7 283.6];
ax.CameraTarget = [77.4 60.2 63.9];
ax.CameraUpVector = [0 0 1];
ax.CameraViewAngle = 36.7;
ax.Position = [0 0 1 1];
ax.DataAspectRatio = [1 1 .9];
l1 = light;
l1.Position = [160 400 80];
l1.Style = 'local';
l1.Color = [0 0.8 0.8];
l2 = light; % l2 = l1;
l2.Position = [.5 -1 .4];
l2.Color = [0.8 0.8 0];
s.FaceColor = [0.9 0.2 0.2];
s.FaceLighting = 'gouraud';
s.AmbientStrength = 0.3;
s.DiffuseStrength = 0.6;
s.BackFaceLighting = 'lit';
s.SpecularStrength = 1;
s.SpecularColorReflectance = 1;
s.SpecularExponent = 7;
axis off
f.Color = 'black';
% (2)
% Copyobj is not cooperating. Time to be lazy!
% Matlab Classic Noteworthy Logo (TM) (C) (Not-for-individual-sale)
f_dupe = figure;
ax_dupe = axes;
s_dupe = surface(L);
s_dupe.EdgeColor = 'none';
view(3)
ax_dupe.XLim = [1 201];
ax_dupe.YLim = [1 201];
ax_dupe.ZLim = [-53.4 160];
ax_dupe.CameraPosition = [-145.5 -229.7 283.6];
ax_dupe.CameraTarget = [77.4 60.2 63.9];
ax_dupe.CameraUpVector = [0 0 1];
ax_dupe.CameraViewAngle = 36.7;
ax_dupe.Position = [0 0 1 1];
ax_dupe.DataAspectRatio = [1 1 .9];
l3 = light;
l3.Position = [160 400 80];
l3.Style = 'local';
l3.Color = [0 0.8 0.8];
l4 = light; % l2 = l1;
l4.Position = [.5 -1 .4];
l4.Color = [0.8 0.8 0];
s_dupe.FaceColor = [0.9 0.2 0.2];
s_dupe.FaceLighting = 'gouraud';
s_dupe.AmbientStrength = 0.3;
s_dupe.DiffuseStrength = 0.6;
s_dupe.BackFaceLighting = 'lit';
s_dupe.SpecularStrength = 1;
s_dupe.SpecularColorReflectance = 1;
s_dupe.SpecularExponent = 7;
axis off
f_dupe.Color = 'black';
% James's Changes
% Change one - light at the origin!
l4.Position = [0 0 0];
l4.Color = [1 1 1];
% This made the logo significantly more purple!
% Change two - colormap
colormap winter;
% I didnt really notice a change with this one.
% Change three - function
s_dupe.FaceLighting = 'flat';
% I changed the surface! It has different face lighting. Thats changing
% the function, right?
% It helped emphasize the purple-maroon which possesses the shape at the moment
% Change four - backround
f_dupe.Color = 'red';
% Hard to miss - the entire background is now red!
% (3)
figure;
% Matlab <TM>
ax_former = subplot(2,1,1);
copyobj(ax.Children, ax_former);
title('Matlab <TM>');
ax_former.XLim = [1 201];
ax_former.YLim = [1 201];
ax_former.ZLim = [-53.4 160];
ax_former.XTick = [];
ax_former.YTick = [];
ax_former.ZTick = [];
ax_former.CameraPosition = [-145.5 -229.7 283.6];
ax_former.CameraTarget = [77.4 60.2 63.9];
ax_former.CameraUpVector = [0 0 1];
ax_former.CameraViewAngle = 36.7;
l5 = light;
l5.Position = [160 400 80];
l5.Style = 'local';
l5.Color = [0 0.8 0.8];
l6 = light; % l2 = l1;
l6.Position = [.5 -1 .4];
l6.Color = [0.8 0.8 0];
% James Plot
ax_latter = subplot(2,1,2);
copyobj(ax_dupe.Children, ax_latter);
title('Conspicuous Copycat');
ax_latter.XLim = [1 201];
ax_latter.YLim = [1 201];
ax_latter.ZLim = [-53.4 160];
ax_latter.XTick = [];
ax_latter.YTick = [];
ax_latter.ZTick = [];
ax_latter.CameraPosition = [-145.5 -229.7 283.6];
ax_latter.CameraTarget = [77.4 60.2 63.9];
ax_latter.CameraUpVector = [0 0 1];
ax_latter.CameraViewAngle = 36.7;
l7 = light;
l7.Position = [160 400 80];
l7.Style = 'local';
l7.Color = [0 0.8 0.8];
l8 = light; % l2 = l1;
l8.Position = [.5 -1 .4];
l8.Color = [0.8 0.8 0];
% James's Changes
% Change one - light at the origin!
l8.Position = [0 0 0];
l8.Color = [1 1 1];
% This made the logo significantly more purple!
% (4)
get(f)
f.PaperOrientation = 'landscape';
f.PaperType = 'a4';
f.PaperUnits = 'centimeters';
% My figure now is configured to print in Europe! And its sideways.

3
hw4/antideriv.m Normal file
View File

@ -0,0 +1,3 @@
function int_Y_dx = antideriv(y, x)
int_Y_dx = ( cumtrapz(y) .* (x(2) - x(1)) );
end

4
hw4/deriv.m Normal file
View File

@ -0,0 +1,4 @@
function dy = deriv(y, x)
dy = diff(y) ./ (x(2) - x(1));
dy = dy([1 1:end]);
end

5
hw4/extrema.m Normal file
View File

@ -0,0 +1,5 @@
function [y_ext, x_ext] = extrema(y, x)
y_switch = switchsign( deriv(y, x) );
y_ext = nonzeros(y_switch .* y);
x_ext = nonzeros(y_switch .* x);
end

View File

@ -0,0 +1,231 @@
%%%% ECE-210-B HW 4 - Functions and Objects
% James Ryan, 02/21/24
% preamble
close all; clear; clc;
%% My Sinc Is Broken
% (1)
% see deriv.m
x = linspace(-5, 5, 1e3);
sinc_x = sinc(x);
deriv_sinc = deriv(sinc_x, x);
% see antideriv.m
% approximates an integral of a given function using `cumtrapz`
int_sinc = antideriv(sinc_x, x);
% (2)
% see switchsign.m
% (3)
[extrema_sinc_x, extrema_x] = extrema(sinc_x, x);
[inflect_sinc_x, inflect_x] = inflections(sinc_x, x);
% (4)
figure;
plot(x, sinc_x, x, int_sinc, x, deriv_sinc, ...
extrema_x, extrema_sinc_x, 'r*', ...
inflect_x, inflect_sinc_x, 'bo');
ylim([-2 2.45]);
xlim([-5, 5]);
ylabel("y-axis");
xlabel("x-axis");
grid on;
title( {'y = sinc(x) plotted over 1000 evenly spaced pts between x \epsilon [-5,5]', ...
'Plotted alongside its first derivative and antiderivative.'});
legend( 'y = sinc(x)',"$\int [sinc(x)] dx$",'$\frac{d}{dx} [sinc(x)]$', ...
'Points of Extrema', 'Inflection Points', ...
"Interpreter","latex");
% <+.02> this is a very pretty legend.
%% Objectification
% (1)
% Matlab Classic Noteworthy Logo (TM) (C) (Not-for-individual-sale)
L = 160*membrane(1,100);
f = figure;
ax = axes;
s = surface(L);
s.EdgeColor = 'none';
view(3)
ax.XLim = [1 201];
ax.YLim = [1 201];
ax.ZLim = [-53.4 160];
ax.CameraPosition = [-145.5 -229.7 283.6];
ax.CameraTarget = [77.4 60.2 63.9];
ax.CameraUpVector = [0 0 1];
ax.CameraViewAngle = 36.7;
ax.Position = [0 0 1 1];
ax.DataAspectRatio = [1 1 .9];
l1 = light;
l1.Position = [160 400 80];
l1.Style = 'local';
l1.Color = [0 0.8 0.8];
l2 = light; % l2 = l1;
l2.Position = [.5 -1 .4];
l2.Color = [0.8 0.8 0];
s.FaceColor = [0.9 0.2 0.2];
s.FaceLighting = 'gouraud';
s.AmbientStrength = 0.3;
s.DiffuseStrength = 0.6;
s.BackFaceLighting = 'lit';
s.SpecularStrength = 1;
s.SpecularColorReflectance = 1;
s.SpecularExponent = 7;
axis off
f.Color = 'black';
% (2)
% Copyobj is not cooperating. Time to be lazy!
% Matlab FOR MS-DOS! Noteworthy Logo (TM) (C) (Not-for-individual-sale)
disk_operating_system = 2;
L_disk_operating_system = disk_operating_system .* L;
f_dupe = figure;
ax_dupe = axes;
s_dupe = surface(L_disk_operating_system);
s_dupe.EdgeColor = 'none';
view(3)
ax_dupe.XLim = disk_operating_system .* [1 201];
ax_dupe.YLim = disk_operating_system .* [1 201];
ax_dupe.ZLim = disk_operating_system .* [-53.4 160];
ax_dupe.CameraPosition = disk_operating_system .* [-145.5 -229.7 283.6];
ax_dupe.CameraTarget = disk_operating_system .* [77.4 60.2 63.9];
ax_dupe.CameraUpVector = [0 0 1];
ax_dupe.CameraViewAngle = 36.7;
ax_dupe.Position = [0 0 1 1];
ax_dupe.DataAspectRatio = [1 1 .9];
l3 = light;
l3.Position = [160 400 80];
l3.Style = 'local';
l3.Color = [0 0.8 0.8];
l4 = light; % l2 = l1;
l4.Position = [.5 -1 .4];
l4.Color = [0.8 0.8 0];
s_dupe.FaceColor = [0.9 0.2 0.2];
s_dupe.FaceLighting = 'gouraud';
s_dupe.AmbientStrength = 0.3;
s_dupe.DiffuseStrength = 0.6;
s_dupe.BackFaceLighting = 'lit';
s_dupe.SpecularStrength = 1;
s_dupe.SpecularColorReflectance = 1;
s_dupe.SpecularExponent = 7;
axis off
f_dupe.Color = 'black';
% James's Changes
% Change one - light at the origin!
l4.Position = [0 0 0];
l4.Color = [1 1 1];
% This made the logo significantly more purple!
% Change two - colormap
colormap winter;
% I didnt really notice a change with this one.
% Change three - function
s_dupe.FaceLighting = 'flat';
% I changed the surface! It has different face lighting. Thats changing
% the function, right?
% It helped emphasize the purple-maroon which possesses the shape at the moment
% Change four - backround
f_dupe.Color = 'red';
% Hard to miss - the entire background is now red!
% (3)
f_both = figure;
% Matlab <TM>
ax_former = subplot(1,2,1);
copyobj(ax.Children, ax_former);
title('Matlab <TM>');
ax_former.XLim = [1 201];
ax_former.YLim = [1 201];
ax_former.ZLim = [-53.4 160];
ax_former.XTick = [];
ax_former.YTick = [];
ax_former.ZTick = [];
ax_former.CameraPosition = [-145.5 -229.7 283.6];
ax_former.CameraTarget = [77.4 60.2 63.9];
ax_former.CameraUpVector = [0 0 1];
ax_former.CameraViewAngle = 36.7;
l5 = light;
l5.Position = [160 400 80];
l5.Style = 'local';
l5.Color = [0 0.8 0.8];
l6 = light; % l2 = l1;
l6.Position = [.5 -1 .4];
l6.Color = [0.8 0.8 0];
% James Plot Matlab for DOS
ax_latter = subplot(1,2,2);
copyobj(ax_dupe.Children, ax_latter);
title('Conspicuous Copycat');
% <+.02> MATLAB for DOS lol
% disk operating system, or DOS, is 2 for short :)
ax_latter.XLim = disk_operating_system .* [1 201];
ax_latter.YLim = disk_operating_system .* [1 201];
ax_latter.ZLim = disk_operating_system .* [-53.4 160];
ax_latter.XTick = [];
ax_latter.YTick = [];
ax_latter.ZTick = [];
ax_latter.CameraPosition = disk_operating_system .* [-145.5 -229.7 283.6];
ax_latter.CameraTarget = disk_operating_system .* [77.4 60.2 63.9];
ax_latter.CameraUpVector = [0 0 1];
ax_latter.CameraViewAngle = 36.7;
l7 = light;
l7.Position = [160 400 80];
l7.Style = 'local';
l7.Color = [0 0.8 0.8];
l8 = light; % l2 = l1;
l8.Position = [.5 -1 .4];
l8.Color = [0.8 0.8 0];
f_both.Color = 'green';
% James's Changes
% Change one - light at the origin!
l8.Position = [0 0 0];
l8.Color = [1 1 1];
% This made the logo significantly more purple!
% (4)
%get(f)
f.PaperOrientation = 'landscape';
f.PaperType = 'a4';
f.PaperUnits = 'centimeters';
% My figure now is configured to print in Europe! And its sideways.
% <+.01> lmao, incredible

3
hw4/feedback/antideriv.m Normal file
View File

@ -0,0 +1,3 @@
function int_Y_dx = antideriv(y, x)
int_Y_dx = ( cumtrapz(y) .* (x(2) - x(1)) );
end

4
hw4/feedback/deriv.m Normal file
View File

@ -0,0 +1,4 @@
function dy = deriv(y, x)
dy = diff(y) ./ (x(2) - x(1));
dy = dy([1 1:end]);
end

5
hw4/feedback/extrema.m Normal file
View File

@ -0,0 +1,5 @@
function [y_ext, x_ext] = extrema(y, x)
y_switch = switchsign( deriv(y, x) );
y_ext = nonzeros(y_switch .* y);
x_ext = nonzeros(y_switch .* x);
end

View File

@ -0,0 +1,5 @@
function [y_inf, x_inf] = inflections(y, x)
y_switch = switchsign( deriv(deriv(y, x), x) );
y_inf = nonzeros(y_switch .* y);
x_inf = nonzeros(y_switch .* x);
end

17
hw4/feedback/switchsign.m Normal file
View File

@ -0,0 +1,17 @@
% cursed
% lmao
% basically - I take pairs of adjacent values on the vector `x` and add them
% together. These sums are then checked against both members of the pair,
% and if either member is *larger* than the sum, that indicates a sign change
% since one of the values acted as a subtractor.
% "Glue" is added in the comparison stage, to skew ONLY on cases where
% we are comparing zero to zero (origin case). Its really a rounding error otherwise. lol
% The front is padded w/ a zero.
function ret = switchsign(x)
sum_check = x(1:end-1) + x(2:end);
ret = [0, ( abs(sum_check) < abs(x(1:end-1)+1e-7) ) | ( abs(sum_check) < abs(x(2:end)+1e-7) ) ];
end
% <-.01> works here (this is insane), but technically has an
% error: calling `switchsign([-1 2 1 0 1 -3])` (the example i
% gave) returns `[0 1 0 1 1 1]` rather than `[0 1 0 0 0 1]`.
% not that that really matters. sorry...

5
hw4/inflections.m Normal file
View File

@ -0,0 +1,5 @@
function [y_inf, x_inf] = inflections(y, x)
y_switch = switchsign( deriv(deriv(y, x), x) );
y_inf = nonzeros(y_switch .* y);
x_inf = nonzeros(y_switch .* x);
end

12
hw4/switchsign.m Normal file
View File

@ -0,0 +1,12 @@
% cursed
% basically - I take pairs of adjacent values on the vector `x` and add them
% together. These sums are then checked against both members of the pair,
% and if either member is *larger* than the sum, that indicates a sign change
% since one of the values acted as a subtractor.
% "Glue" is added in the comparison stage, to skew ONLY on cases where
% we are comparing zero to zero (origin case). Its really a rounding error otherwise. lol
% The front is padded w/ a zero.
function ret = switchsign(x)
sum_check = x(1:end-1) + x(2:end);
ret = [0, ( abs(sum_check) < abs(x(1:end-1)+1e-7) ) | ( abs(sum_check) < abs(x(2:end)+1e-7) ) ];
end

121
hw5/Ryan_HW5_ECE210.m Normal file
View File

@ -0,0 +1,121 @@
%%%% ECE-210-B HW5 - Advanced Manipulations - James Ryan
% James Ryan, 03/18/24
% preamble
close all; clc; clear;
%% On the Air
% 1
R = [-9:9] + fliplr([-9:9]).'.*j;
% 2
n = [1:50];
t = [linspace(0,1,1e5)].';
sin_int = sum(trapz(sin(t.^n)) .* (t(2) - t(1)), 'all');
% 3
% a
[theta, phi] = meshgrid(...
linspace(0, 2*pi, 5), ...
linspace(0, pi, 5));
% b
x = sin(phi) .* cos(theta);
y = sin(phi) .* sin(theta);
z = cos(phi);
% c
figure;
surf(x,y,z);
pbaspect([1 1 1]);
colormap winter;
title("The best sphere");
xlabel("over axis")
ylabel("yonder axis")
zlabel("up axis")
%% Under the Sea
% 1
interest = sin(linspace(0,5,100).*linspace(-5,0,100).');
half_extract = ( abs(interest - .5) < (5/1000) ) .* interest; % < min quantized val
indices = find(half_extract);
% 2
% find area on xy where both intersect
% volume of z2 - volume of z1
% incomplete for now
x = linspace(0, 10, 1000);
intersect = (1/4).*sqrt(x.^2 + (x.').^2) == exp(-(1-x.*x.').^2);
volume = (...
( cumtrapz( (1/4).*sqrt(x.^2 + (x.').^2) .* (x(2) - x(1)) )) - ...
( cumtrapz( exp(-(1-x.*x.').^2 ) .* (x(2) - x(1)) ))...
) .* intersect;
%% I Need a Vacation
% 1
A_vals = sqrt(...
([1:256] - 99).^2 + ...
([1:256].' - 99).^2);
A = A_vals < 29;
% What's happening here is that our A indices are taken, shifted "down" 99
% values, and then a norm is taken on them. If its final norm is < 29, its true!
% otherwise, they're false.
% Theres a circle localized around an origin of (i,j) = (99,99), and extends
% out. This makes sense! relative to everywhere else, this is our lowest value,
% and it creates the smallest norm we see (zer0).
% This holds experimentally! If we change 29 to 1, we just get a single teeny
% pixel at (99,99), surrounded by a false sea. So, the equality we have acts
% to give our circle some radius.
figure;
imshow(A);
% 2
B_vals = sqrt(...
([1:256] - 62).^2 + ...
([1:256].' - 62).^2);
B = B_vals < 58;
% Close to the previous idea, however we shift down only by 68 units, so our
% origin is (68, 68).
% We have a larger radius, given we doubled our tolerance for whats true.
figure;
imshow(B);
% 3
C_vals = [1:256] - 4.*sin(([1:256].'./10));
C = C_vals > 200;
% We get a vertical ripple!! The ripple runs along our y axis and has a period
% of 10 and a peak-to-trough distance of 8. This acts as a wavefront from our
% true shoreline and our false sea.
figure;
imshow(C);
% 4
S_vals = rand(256, 256, 3);
S = permute(permute(S_vals,[3 1 2]) .* [0 0 1].', [2 3 1]);
% Interpreting this as a 256 x 256 image with 3 color channels, it looks
% like we applied a filter to kill R and G! We're left with the blue channel
figure;
imshow(S);
% 5
M = A & ~B;
% We get a crescent moon! The portion of B that cast over A was negated and
% compared, which resulted in that poriton being removed.
% We're left with the parts of A that was free from B's grasp
figure;
imshow(M);
% 6
Z = (C .* S) + M;
% Its a scene of a beach! Our moon is casting its light onto the dark beach,
% as the water casts itself onto the shore.
% reminds me of good times :D
figure;
imshow(Z);

View File

@ -0,0 +1,150 @@
%%%% ECE-210-B HW5 - Advanced Manipulations - James Ryan
% James Ryan, 03/18/24
% preamble
close all; clc; clear;
%% On the Air
% 1
R = [-9:9] + fliplr([-9:9]).'.*j;
% 2
n = [1:50];
t = [linspace(0,1,1e5)].';
sin_int = sum(trapz(sin(t.^n)) .* (t(2) - t(1)), 'all');
% <-.02> erm... the integral calculation seems to be correct
% (though `trapz` has an independent variable argument), but
% why the `sum` at the end? should have said this was supposed
% to be 50 different integral estimates in parallel. :p
% 3
% a
[theta, phi] = meshgrid(...
linspace(0, 2*pi, 5), ...
linspace(0, pi, 5));
% b
x = sin(phi) .* cos(theta);
y = sin(phi) .* sin(theta);
z = cos(phi);
% c
figure;
surf(x,y,z);
pbaspect([1 1 1]);
colormap winter;
title("The best sphere");
xlabel("over axis")
ylabel("yonder axis")
zlabel("up axis")
%% Under the Sea
% 1
interest = sin(linspace(0,5,100).*linspace(-5,0,100).');
half_extract = ( abs(interest - .5) < (5/1000) ) .* interest; % < min quantized val
indices = find(half_extract);
% <-.06> two things:
% 1. the minimum quantized value is pretty uncertain after
% you pass the input through the sine function -- in fact,
% the nearest points are (i think) significantly closer than
% this. you'll have to use `min` to find them.
% 2. i did say something about 2D indices, but that's less
% important -- linear indices often work just as well.
% 2
X = linspace(-5,5,100);
[x, y] = meshgrid(X, X);
intersect = (1/4).*sqrt(x.^2 + y.^2) < exp(-(1-x.*y).^2);
% integral(end) = volume
integral = cumtrapz(X, cumtrapz(X, exp(-(1-x.*y).^2).*intersect, 2));
% <-.02> not, alas, the volume contained between the surfaces,
% but just the volume under the first surface and above the
% xy-plane. i think that's just a small oversight, though.
figure;
surf(x, y, exp(-(1-x.*y).^2).*intersect);
xlabel("X Axis");
ylabel("Y Axis");
zlabel("Z Axis");
title('Volume representing $\frac{1}{4}\sqrt{x^2 + y^2} < e^{-(1-x * y)^2}$',...
'interpreter', 'latex');
pbaspect([4 4 3])
% <+.02> volume is consistent with the above, so i'll give a
% few points.
%% I Need a Vacation
% 1
A_vals = sqrt(...
([1:256] - 99).^2 + ...
([1:256].' - 99).^2);
A = A_vals < 29;
% What's happening here is that our A indices are taken, shifted "down" 99
% values, and then a norm is taken on them. If its final norm is < 29, its true!
% otherwise, they're false.
% Theres a circle localized around an origin of (i,j) = (99,99), and extends
% out. This makes sense! relative to everywhere else, this is our lowest value,
% and it creates the smallest norm we see (zer0).
% This holds experimentally! If we change 29 to 1, we just get a single teeny
% pixel at (99,99), surrounded by a false sea. So, the equality we have acts
% to give our circle some radius.
figure;
imshow(A);
% 2
B_vals = sqrt(...
([1:256] - 62).^2 + ...
([1:256].' - 62).^2);
B = B_vals < 58;
% Close to the previous idea, however we shift down only by 68 units, so our
% origin is (68, 68).
% We have a larger radius, given we doubled our tolerance for whats true.
figure;
imshow(B);
% 3
C_vals = [1:256] - 4.*sin(([1:256].'./10));
C = C_vals > 200;
% <-.02> traditionally, the i index is the first index in the
% MATLAB sense -- that is, the index which increments down each
% column, not across each row. in short, (x, y) (j, i),
% whereas you effectively have y equivalent to j.
% We get a vertical ripple!! The ripple runs along our y axis and has a period
% of 10 and a peak-to-trough distance of 8. This acts as a wavefront from our
% true shoreline and our false sea.
figure;
imshow(C);
% 4
S_vals = rand(256, 256, 3);
S = permute(permute(S_vals,[3 1 2]) .* [0 0 1].', [2 3 1]);
% Interpreting this as a 256 x 256 image with 3 color channels, it looks
% like we applied a filter to kill R and G! We're left with the blue channel
figure;
imshow(S);
% 5
M = A & ~B;
% We get a crescent moon! The portion of B that cast over A was negated and
% compared, which resulted in that poriton being removed.
% We're left with the parts of A that was free from B's grasp
figure;
imshow(M);
% 6
Z = (C .* S) + M;
% Its a scene of a beach! Our moon is casting its light onto the dark beach,
% as the water casts itself onto the shore.
% reminds me of good times :D
figure;
imshow(Z);
% ahhhh, that it does me. figured y'all could use something
% calming.

136
hw6/Ryan_HW6_ECE210.m Normal file
View File

@ -0,0 +1,136 @@
%%%% ECE-210-B HW6 - Filters - James Ryan
% James Ryan, 03/27/24
% preamble
close all; clc; clear;
%% Generate white noise
Fs = 44100; % Hz = s^-1
N = Fs*2; % 2s * 44100 samples/sec = 88200 samples of noise
F = linspace(-Fs/2, Fs/2, N); % range of noise
% noise generation
% good way
noise = randn(1, N); % intensity of noise
% funny way - requires `fortune` as a dependency
%noise = fortune_favors_the_fontaine(Fs, 2);
% thank you!
shifted_fft_mag = @(sig, len) fftshift(abs(fft(sig, len))) / len;
%% Butterworth Filter
Hbutter = butterworth;
fvm_butter = fvtool(Hbutter, 'magnitude');
axm_butter = fvm_butter.Children(5);
axm_butter.YLim = [-60 5];
axm_butter.Title.String = 'Butterworth Bandpass Filter Magnitude Plot';
fvp_butter = fvtool(Hbutter, 'phase');
axp_butter = fvp_butter.Children(5);
axp_butter.Title.String = 'Butterworth Bandpass Filter Phase Plot';
butter_noise = Hbutter.filter(noise);
fftm_butter = shifted_fft_mag(butter_noise, N);
figure;
plot(F, fftm_butter);
xlim([-Fs/2 Fs/2]);
xlabel("Frequency (Hz)");
ylabel("Magnitude (dB)");
title("FFT of noisy signal passed through Butterworth Bandpass Filter");
% to save you, i played it back in the matlab terminal:
%soundsc(noise)
%soundsc(fftm_butter)
% to me, its just a mostly mute audio track minus two bursts of sound.
% that must be the negative and positive passband regions
% so the filter took the noise, and just took the regions outside of
% the band and killed them.
%% Elliptic Filter
Hellip = elliptic;
fvm_ellip = fvtool(Hellip, 'magnitude');
axm_ellip = fvm_ellip.Children(5);
axm_ellip.YLim = [-60 5];
axm_ellip.Title.String = 'Elliptical Bandstop Filter Magnitude Plot';
fvp_ellip = fvtool(Hellip, 'phase');
axp_ellip = fvp_ellip.Children(5);
axp_ellip.Title.String = 'Elliptical Bandstop Filter Phase Plot';
ellip_noise = Hellip.filter(noise);
fftm_ellip = shifted_fft_mag(ellip_noise, N);
figure;
plot(F, fftm_ellip);
xlim([-Fs/2 Fs/2]);
xlabel("Frequency (Hz)");
ylabel("Magnitude (dB)");
title("FFT of noisy signal passed through Elliptical Bandstop Filter");
%soundsc(fftm_ellip)
% I can hear this one.. come back? like very faintly
% I guess it goes to show how butterworth doesnt have that elliptic
% stopband portion, and everything decays to -inf dB. Interesting
% difference!
% same pattern as the past passband
%% Chebyshev Type 1 Filter
Hcheb1 = chebyshev1;
fvm_cheb1 = fvtool(Hcheb1, 'magnitude');
axm_cheb1 = fvm_cheb1.Children(5);
axm_cheb1.YLim = [-60 5];
axm_cheb1.Title.String = 'Chebyshev Type I Lowpass Filter Magnitude Plot';
fvp_cheb1 = fvtool(Hcheb1, 'phase');
axp_cheb1 = fvp_cheb1.Children(5);
axp_cheb1.Title.String = 'Chebyshev Type I Lowpass Filter Phase Plot';
cheb1_noise = Hcheb1.filter(noise);
fftm_cheb1 = shifted_fft_mag(cheb1_noise, N);
figure;
plot(F, fftm_cheb1);
xlim([-Fs/2 Fs/2]);
xlabel("Frequency (Hz)");
ylabel("Magnitude (dB)");
title("FFT of noisy signal passed through Chebyshev I Lowpass Filter");
%soundsc(fftm_cheb1)
% It sounds choppy, almost, where it wibbles in and out for the starting portion
% where its present. Definitely not the choice for audio filters!
% Unless you `want` that distortion in like music production, in which case, go for it
% Sort of sounds like a car engine firing
%% Chebyshev Type 2 Filter
Hcheb2 = chebyshev2;
fvm_cheb2 = fvtool(Hcheb2, 'magnitude');
axm_cheb2 = fvm_cheb2.Children(5);
axm_cheb2.YLim = [-60 5];
axm_cheb2.Title.String = 'Chebyshev Type I Highpass Filter Magnitude Plot';
fvp_cheb2 = fvtool(Hcheb2, 'phase');
axp_cheb2 = fvp_cheb2.Children(5);
axp_cheb2.Title.String = 'Chebyshev Type II Highpass Filter Phase Plot';
cheb2_noise = Hcheb2.filter(noise);
fftm_cheb2 = shifted_fft_mag(cheb2_noise, N);
figure;
plot(F, fftm_cheb2);
xlim([-Fs/2 Fs/2]);
xlabel("Frequency (Hz)");
ylabel("Magnitude (dB)");
title("FFT of noisy signal passed through Chebyshev II Highpass Filter");
%soundsc(fftm_cheb2)
% Its passband is sorta similar to the butterworth passband, but its die-out
% has an audible drop off to me. maybe i missed that in others with elliptic
% stop bands? No just played back fftm_ellip, and that dropped immediately. hmm
% placebo, perhaps

27
hw6/butterworth.m Normal file
View File

@ -0,0 +1,27 @@
function Hd = butterworth
%BUTTERWORTH Returns a discrete-time filter object.
% MATLAB Code
% Generated by MATLAB(R) 23.2 and Signal Processing Toolbox 23.2.
% Generated on: 27-Mar-2024 18:56:52
% Butterworth Bandpass filter designed using FDESIGN.BANDPASS.
% All frequency values are in Hz.
Fs = 44100; % Sampling Frequency
Fstop1 = 6300; % First Stopband Frequency
Fpass1 = 7350; % First Passband Frequency
Fpass2 = 14700; % Second Passband Frequency
Fstop2 = 17640; % Second Stopband Frequency
Astop1 = 50; % First Stopband Attenuation (dB)
Apass = 1; % Passband Ripple (dB)
Astop2 = 50; % Second Stopband Attenuation (dB)
match = 'stopband'; % Band to match exactly
% Construct an FDESIGN object and call its BUTTER method.
h = fdesign.bandpass(Fstop1, Fpass1, Fpass2, Fstop2, Astop1, Apass, ...
Astop2, Fs);
Hd = design(h, 'butter', 'MatchExactly', match);
% [EOF]

12
hw6/chebyshev1.m Normal file
View File

@ -0,0 +1,12 @@
function Hcheb = chebyshev1
Fs = 44100;
Fpass = Fs/9;
Fstop = Fs/8;
Apass = 5;
Astop = 40;
specs = fdesign.lowpass(Fpass, Fstop, Apass, Astop, Fs);
Hcheb = design(specs,"cheby1",MatchExactly="passband");
end

12
hw6/chebyshev2.m Normal file
View File

@ -0,0 +1,12 @@
function Hcheb = chebyshev2
Fs = 44100;
Fpass = Fs/3;
Fstop = Fs/4;
Apass = 5;
Astop = 40;
specs = fdesign.highpass(Fstop, Fpass, Astop, Apass, Fs);
Hcheb = design(specs,"cheby2",MatchExactly="passband");
end

27
hw6/elliptic.m Normal file
View File

@ -0,0 +1,27 @@
function Hd = elliptic
%ELLIPTIC Returns a discrete-time filter object.
% MATLAB Code
% Generated by MATLAB(R) 23.2 and Signal Processing Toolbox 23.2.
% Generated on: 27-Mar-2024 18:58:12
% Elliptic Bandstop filter designed using FDESIGN.BANDSTOP.
% All frequency values are in Hz.
Fs = 44100; % Sampling Frequency
Fpass1 = 6300; % First Passband Frequency
Fstop1 = 7350; % First Stopband Frequency
Fstop2 = 14700; % Second Stopband Frequency
Fpass2 = 17640; % Second Passband Frequency
Apass1 = 1; % First Passband Ripple (dB)
Astop = 50; % Stopband Attenuation (dB)
Apass2 = 1; % Second Passband Ripple (dB)
match = 'both'; % Band to match exactly
% Construct an FDESIGN object and call its ELLIP method.
h = fdesign.bandstop(Fpass1, Fstop1, Fstop2, Fpass2, Apass1, Astop, ...
Apass2, Fs);
Hd = design(h, 'ellip', 'MatchExactly', match);
% [EOF]

View File

@ -0,0 +1,138 @@
%%%% ECE-210-B HW6 - Filters - James Ryan
% James Ryan, 03/27/24
% preamble
close all; clc; clear;
%% Generate white noise
Fs = 44100; % Hz = s^-1
N = Fs*2; % 2s * 44100 samples/sec = 88200 samples of noise
F = linspace(-Fs/2, Fs/2, N); % range of noise
% noise generation
% good way
noise = randn(1, N); % intensity of noise
% funny way - requires `fortune` as a dependency
%noise = fortune_favors_the_fontaine(Fs, 2);
% thank you!
% you're welcome!
shifted_fft_mag = @(sig, len) fftshift(abs(fft(sig, len))) / len;
%% Butterworth Filter
% had to change `5` to `end`, but otherwise perfect.
Hbutter = butterworth;
fvm_butter = fvtool(Hbutter, 'magnitude');
axm_butter = fvm_butter.Children(end);
axm_butter.YLim = [-60 5];
axm_butter.Title.String = 'Butterworth Bandpass Filter Magnitude Plot';
fvp_butter = fvtool(Hbutter, 'phase');
axp_butter = fvp_butter.Children(end);
axp_butter.Title.String = 'Butterworth Bandpass Filter Phase Plot';
butter_noise = Hbutter.filter(noise);
fftm_butter = shifted_fft_mag(butter_noise, N);
figure;
plot(F, fftm_butter);
xlim([-Fs/2 Fs/2]);
xlabel("Frequency (Hz)");
ylabel("Magnitude (dB)");
title("FFT of noisy signal passed through Butterworth Bandpass Filter");
% to save you, i played it back in the matlab terminal:
%soundsc(noise)
%soundsc(fftm_butter)
% to me, its just a mostly mute audio track minus two bursts of sound.
% that must be the negative and positive passband regions
% so the filter took the noise, and just took the regions outside of
% the band and killed them.
%% Elliptic Filter
Hellip = elliptic;
fvm_ellip = fvtool(Hellip, 'magnitude');
axm_ellip = fvm_ellip.Children(end);
axm_ellip.YLim = [-60 5];
axm_ellip.Title.String = 'Elliptical Bandstop Filter Magnitude Plot';
fvp_ellip = fvtool(Hellip, 'phase');
axp_ellip = fvp_ellip.Children(end);
axp_ellip.Title.String = 'Elliptical Bandstop Filter Phase Plot';
ellip_noise = Hellip.filter(noise);
fftm_ellip = shifted_fft_mag(ellip_noise, N);
figure;
plot(F, fftm_ellip);
xlim([-Fs/2 Fs/2]);
xlabel("Frequency (Hz)");
ylabel("Magnitude (dB)");
title("FFT of noisy signal passed through Elliptical Bandstop Filter");
%soundsc(fftm_ellip)
% I can hear this one.. come back? like very faintly
% I guess it goes to show how butterworth doesnt have that elliptic
% stopband portion, and everything decays to -inf dB. Interesting
% difference!
% same pattern as the past passband
%% Chebyshev Type 1 Filter
Hcheb1 = chebyshev1;
fvm_cheb1 = fvtool(Hcheb1, 'magnitude');
axm_cheb1 = fvm_cheb1.Children(end);
axm_cheb1.YLim = [-60 5];
axm_cheb1.Title.String = 'Chebyshev Type I Lowpass Filter Magnitude Plot';
fvp_cheb1 = fvtool(Hcheb1, 'phase');
axp_cheb1 = fvp_cheb1.Children(end);
axp_cheb1.Title.String = 'Chebyshev Type I Lowpass Filter Phase Plot';
cheb1_noise = Hcheb1.filter(noise);
fftm_cheb1 = shifted_fft_mag(cheb1_noise, N);
figure;
plot(F, fftm_cheb1);
xlim([-Fs/2 Fs/2]);
xlabel("Frequency (Hz)");
ylabel("Magnitude (dB)");
title("FFT of noisy signal passed through Chebyshev I Lowpass Filter");
%soundsc(fftm_cheb1)
% It sounds choppy, almost, where it wibbles in and out for the starting portion
% where its present. Definitely not the choice for audio filters!
% Unless you `want` that distortion in like music production, in which case, go for it
% Sort of sounds like a car engine firing
%% Chebyshev Type 2 Filter
Hcheb2 = chebyshev2;
fvm_cheb2 = fvtool(Hcheb2, 'magnitude');
axm_cheb2 = fvm_cheb2.Children(end);
axm_cheb2.YLim = [-60 5];
axm_cheb2.Title.String = 'Chebyshev Type I Highpass Filter Magnitude Plot';
fvp_cheb2 = fvtool(Hcheb2, 'phase');
axp_cheb2 = fvp_cheb2.Children(end);
axp_cheb2.Title.String = 'Chebyshev Type II Highpass Filter Phase Plot';
cheb2_noise = Hcheb2.filter(noise);
fftm_cheb2 = shifted_fft_mag(cheb2_noise, N);
figure;
plot(F, fftm_cheb2);
xlim([-Fs/2 Fs/2]);
xlabel("Frequency (Hz)");
ylabel("Magnitude (dB)");
title("FFT of noisy signal passed through Chebyshev II Highpass Filter");
%soundsc(fftm_cheb2)
% Its passband is sorta similar to the butterworth passband, but its die-out
% has an audible drop off to me. maybe i missed that in others with elliptic
% stop bands? No just played back fftm_ellip, and that dropped immediately. hmm
% placebo, perhaps

View File

@ -0,0 +1,27 @@
function Hd = butterworth
%BUTTERWORTH Returns a discrete-time filter object.
% MATLAB Code
% Generated by MATLAB(R) 23.2 and Signal Processing Toolbox 23.2.
% Generated on: 27-Mar-2024 18:56:52
% Butterworth Bandpass filter designed using FDESIGN.BANDPASS.
% All frequency values are in Hz.
Fs = 44100; % Sampling Frequency
Fstop1 = 6300; % First Stopband Frequency
Fpass1 = 7350; % First Passband Frequency
Fpass2 = 14700; % Second Passband Frequency
Fstop2 = 17640; % Second Stopband Frequency
Astop1 = 50; % First Stopband Attenuation (dB)
Apass = 1; % Passband Ripple (dB)
Astop2 = 50; % Second Stopband Attenuation (dB)
match = 'stopband'; % Band to match exactly
% Construct an FDESIGN object and call its BUTTER method.
h = fdesign.bandpass(Fstop1, Fpass1, Fpass2, Fstop2, Astop1, Apass, ...
Astop2, Fs);
Hd = design(h, 'butter', 'MatchExactly', match);
% [EOF]

12
hw6/feedback/chebyshev1.m Normal file
View File

@ -0,0 +1,12 @@
function Hcheb = chebyshev1
Fs = 44100;
Fpass = Fs/9;
Fstop = Fs/8;
Apass = 5;
Astop = 40;
specs = fdesign.lowpass(Fpass, Fstop, Apass, Astop, Fs);
Hcheb = design(specs,"cheby1",MatchExactly="passband");
end

12
hw6/feedback/chebyshev2.m Normal file
View File

@ -0,0 +1,12 @@
function Hcheb = chebyshev2
Fs = 44100;
Fpass = Fs/3;
Fstop = Fs/4;
Apass = 5;
Astop = 40;
specs = fdesign.highpass(Fstop, Fpass, Astop, Apass, Fs);
Hcheb = design(specs,"cheby2",MatchExactly="passband");
end

27
hw6/feedback/elliptic.m Normal file
View File

@ -0,0 +1,27 @@
function Hd = elliptic
%ELLIPTIC Returns a discrete-time filter object.
% MATLAB Code
% Generated by MATLAB(R) 23.2 and Signal Processing Toolbox 23.2.
% Generated on: 27-Mar-2024 18:58:12
% Elliptic Bandstop filter designed using FDESIGN.BANDSTOP.
% All frequency values are in Hz.
Fs = 44100; % Sampling Frequency
Fpass1 = 6300; % First Passband Frequency
Fstop1 = 7350; % First Stopband Frequency
Fstop2 = 14700; % Second Stopband Frequency
Fpass2 = 17640; % Second Passband Frequency
Apass1 = 1; % First Passband Ripple (dB)
Astop = 50; % Stopband Attenuation (dB)
Apass2 = 1; % Second Passband Ripple (dB)
match = 'both'; % Band to match exactly
% Construct an FDESIGN object and call its ELLIP method.
h = fdesign.bandstop(Fpass1, Fstop1, Fstop2, Fpass2, Apass1, Astop, ...
Apass2, Fs);
Hd = design(h, 'ellip', 'MatchExactly', match);
% [EOF]

View File

@ -0,0 +1,12 @@
function noise = fortune_favors_the_fontaine(Fs, duration)
% make some noise
output = "";
while strlength(output) < Fs*duration
[ret dirty_snippet] = unix('fortune');
% clean
snippet = regexprep(dirty_snippet, '[^A-Za-z]+', '');
output = strcat(output, snippet);
end
noise = normalize(letters2numbers(convertStringsToChars(output)));
end
% <+.03> what the fuck

View File

@ -0,0 +1,4 @@
function num = letters2numbers(word)
asc = double( upper(word) ); % http://www.asciitable.com/
num = 26 + double('A') - asc; % simple arithmetic
end

View File

@ -0,0 +1,11 @@
function noise = fortune_favors_the_fontaine(Fs, duration)
% make some noise
output = "";
while strlength(output) < Fs*duration
[ret dirty_snippet] = unix('fortune');
% clean
snippet = regexprep(dirty_snippet, '[^A-Za-z]+', '');
output = strcat(output, snippet);
end
noise = normalize(letters2numbers(convertStringsToChars(output)));
end

4
hw6/letters2numbers.m Normal file
View File

@ -0,0 +1,4 @@
function num = letters2numbers(word)
asc = double( upper(word) ); % http://www.asciitable.com/
num = 26 + double('A') - asc; % simple arithmetic
end

View File

@ -0,0 +1,180 @@
%% Lesson 1
%% Objective
% After this class, you should be able to:
%%
%
% * Know why you need MATLAB
% * Manuever around the MATLAB interface
% * Understand arithmetic and basic functions in MATLAB
% * Know how to make scalar, vector and matrix variables in MATLAB
% * Know how to perform matrix operations in MATLAB
%
%% MATLAB overview
% MATLAB (short for MATrix LABoratory) is a commonly used interactive
% software amongst engineers. As the name suggests, MATLAB organizes its
% data as matrices and is specially designed for matrix multiplication. In
% addition, it has a plethora of plugins and functions that engineers can
% use, such as machine learning, financial analysis, filter design etc.
%%
% In Cooper, MATLAB is widely used in electrical and computer engineering
% classes (signals, comm theory, machine learning, etc.), and is more broadly
% used for these purposes and others (physics simulations, controls design,
% etc.) across many engineering and scientific disciplines.
%
%% MATLAB Environment
%%% Command window
% The command window is sort of the equivalent of a terminal in Linux, or
% Cygwin in Windows. When you type a command into the command window, an
% operation performs. You can type a MATLAB command, such as 5+10, and the
% answer would be printed out. If a variable is not assigned to the
% command, the result would be stored in the variable ans automatically. If
% a semicolon is added at the end of the line, the result would be
% suppressed. You can clear the command window by typing clc. Moreover, you
% can also type command line commands in the command window, such as ls,
% pwd etc.
%%% Command history
% When you are playing around with different functions in MATLAB, you might
% want to trace back what functions you played with. At that time, you can
% press the up arrow, which would show you your command history.
%%% Workspace
% The workspace is where all the variables are stored. Each variable is
% displayed as a name value pair in the workspace. If the variable is a
% scalar, then the actual value would be shown. If it is a vector or matrix
% , then depending on the size of the vector / matrix, it would either be
% shown as its value or simply the size of the vector / array and its type.
% You can double click on the variables to investigate its actual value in
% a spreadsheet.
%%% Current Folder
% The current folder shows you where you are located at in MATLAB. If you
% execute the command pwd on the command window, it should show you the
% location of the current folder. You might find a time where you need to
% add a folder and link it to your current folder location. At that time,
% you can right click and select "Add to Path". To change current folder,
% you can execute the cd command on your command window
%%% Editor
% The editor is where you can write a script and execute it. All MATLAB
% scripts are saved as .m files. To execute a script, press the play button
% on top in EDITOR tab. When you are executing a script, you can use the
% semicolon to suppress the output of each line. To display a certain
% variable at an arbitrary location in your script, you can use disp()
% function.
%% Arithmetic and Basic functions
%% Basic Operations
5+10; % Addition
ans; % Prints out previous answer
25-7; % Subtraction
24*86; % Multiplication
123.456*78.90; % Multiplication
145/123; % Division
2^5; % Exponential
log10(1000); % Logarithm base 10
log(exp(5)); % Natural logarithm
sqrt(625); % Square root
sin(pi); % sine function
asin(0); % arc sine function
1e5; % e5 multiplies 1 by 10^5
1e-2; % e-2 multiplies 1 by 10^-2
%% Complex Numbers
2+1i; % equivalently, 2+i
2+1j; % equivalently, 2+j
(2+2i)*(3+4j);
%% Special Numbers
pi;
exp(2*pi*j);
inf;
%% Complex number operations
conj(2+i); % complex conjugate
real(2+i); % real part
imag(2+i); % imaginary part
abs(2+i); % magnitude/absolute value
angle(2+i); % angle or phase
%% Variables
% In matlab, there are 3 (main) different kinds of variables
%%
% * Scalar - A scalar appears as 1-by-1 and it is a single real or complex
% number
% * Vector - A vector is 1-by-n or n-by-1, and appears in MATLAB as a row or
% column of complex numbers
% * Matrix - A matrix is m-by-n, and appears in MATLAB as, essentially, a
% matrix. A matrix is a 2-D array
% If you want to see what variables you've declared, either look in the
% Workspace section of the MATLAB window, or type:
who;
whos;
%% Scalar Variables
a = 5;
b = 10;
c = a+b;
z1 = 2+j;
z2 = 3+4j;
z = z1*z2;
%% Vector Variables
x = [1 2+3j 2.718 pi cos(pi)]; % row vector
x = [1, 2+3j, 2.718, pi, cos(pi)]; % same thing with commas
xT = transpose(x); % now you created the column vector
xT = x.'; % regular tranpose
xT = x'; % complex tranpose
y = [1 ; 2.5 ; 3.2 ; 4*pi; cos(pi)]; % column vector
xlen = length(x); % length of row/col vector
ylen = length(y); % same value as length(x)!
%% BE CAREFUL!
% The following two vectors produces vectors of different sizes, the reason
% being linspace(x1, x2, n) creates n evenly spaced points between x1 and
% x2 , with the value of interval (x2-x1)/(n+1), while the colon operator
% (used in the form of x1:i:x2) creates an array with [x1, x1+i, x1+2i...,
% x1+mi], where m = (x2-x1)/i. Hence when creating a vector with the colon
% operator or linspace, make sure you know when to use it. In conclusion,
% linspace works with number of points, whereas the colon operator works
% with increments.
%%
v1 = linspace(-5,5,10);
v2 = -5:1:5;
%% Matrix Variables
A = [1 2 3; 4 5 6; 7 8 9]; % basic construction of matrix
B = repmat(A,2,1); % you concatenated A one above the other
C = [A; A]; % same as above
C1 = transpose(C); % now you transposed C!
C2 = C.'; % still transposed! if it is only C' then it is
% conjugate transpose
size(C); % Confirm that they are tranposes of each other
size(C1);
size(C1,1); % You get the dimension you want!
eye(3); % Create identity matrix
speye(30000000); % Create sparse identity matrix
D = ones(50,60); % D is 50-by-60 ones
E = zeros(40); % E is 40-by-40 zeros
%% Matrix Operations
B+C; % addition
B-C; % subtraction
4*B + C/5; % multiplication and division with a constant
A+ones(size(A)); % elementwise addition with a constant
B*C'; % matrix multiplication
B.*C; % elementwise multiplication
B.^3; % elementwise exponentiation! note: do not use B^3
2*(eye(3))^3; % only possible with square matrices
%% Documentation
% If you don't know how to use a function, look it up using one of the
% following commands. help opens a textual documentation in the
% command window (just like Linux's man command), while doc will open a
% new window with graphical documentation just like their website. The
% MATLAB documentation website is also a great resource!
help clc;
doc size;

View File

@ -0,0 +1,75 @@
%% Lesson 2c: Numerical estimation of integrals and derivatives
% Numerical integration and differentiation are a staple of numerical
% computing. We will now see how easy these are in MATLAB!
clc; clear; close all;
%% The diff and cumsum functions
% Note the lengths of z, zdiff, and zcumsum! (Fencepost problem)
z = [0 5 -2 3 4];
zdiff = diff(z);
zcumsum = cumsum(z);
%% Setup: A simple function
% Let's start with a simple example: y = x.^2. The domain is N points
% linearly sampled from lo to hi.
lo = -2;
hi = 2;
N = 1e2;
x = linspace(lo, hi, N);
y = x.^2;
plot(x, y);
title('x^2');
%% Numerical (Approximate) Derivatives
% We can calculate a difference quotient between each pair of (x,y) points
% using the diff() function.
dydx = diff(y)./diff(x); % difference quotient
figure();
plot(x(1:end-1), dydx);
%% Numerical (Approximate) Integrals
% Now suppose we want to approximate the cumulative integral (Riemann sum)
% of a function.
xdiff = diff(x);
dx = xdiff(1); % spacing between points
dx = (hi-lo) / (N-1); % alternative to the above (note: N-1)
Y = cumsum(y) * dx; % Riemann sum
figure();
plot(x, Y);
%% Error metrics: Check how close we are!
% dydx should be derivative of x.^2 = 2*x
dydx_actual = 2 * x;
% Y should be \int_{-2}^{x}{t.^2 dt}
Y_actual = (x .^3 - (-2)^3) / 3;
% Slightly more accurate -- can you figure out why?
% Y_actual = (x .^3 - (-2-dx)^3) / 3;
% Error metric: MSE (mean square error) or RMSE (root mean square error)
% Try changing N and see how the error changes. Try this with both the
% integral and derivative.
% estimated = dydx;
% actual = dydx_actual(1:end-1);
estimated = Y;
actual = Y_actual;
mse = mean((estimated - actual) .^ 2);
rmse = rms(estimated - actual);
%% Fundamental Theorem of Calculus
% Now, use the approximate derivative to get the original function, y back
% as yhat and plot it. You may need to use/create another variable for
% the x axis when plotting.
figure();
yhat = diff(Y)./diff(x); % differentiate Y
plot(x(1:end-1), yhat);
figure();
yhat2 = cumsum(dydx) * dx; % integrate dydx
plot(x(1:end-1), yhat2);

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,124 @@
%% Lesson 2a: More vector and matrix operations
%
% Objectives:
% * Understand how to perform vector operations in MATLAB
% * Understand arithmetic and basic functions in MATLAB
%% Vector operations
% In lesson 1, we saw how to create a vector with the colon operator and
% linspace. Now let's perform some operations on them!
%
% There are two common classes of operations that you can perform on vectors:
% element-wise operations (which produce another vector) and aggregate
% operations (which produce a scalar value). There are also many functions that
% don't fall under these categories, but these cover many of the common
% functions.
%% Element-wise operations
% Many operations that work on scalars (which are really degenerate matrices)
% also work element-wise on vectors (or matrices).
x = 0:0.01:2*pi; % Create a linearly-spaced vector
y = sin(x); % sin() works element-wise on vectors!
y = abs(x); % same with abs()!
y = x .^ 4; % element-wise power
y = power(x, 4); % same as above
plot(x, y); % Plot y vs. x (line graph)
title('y vs. x');
%% Aggregate operations
% Another common class of operations produce a single output or statistic about
% a vector (or matrix).
length(x); % number of elements in x
sum(x); % sum of the elements of x
mean(x); % average of the elements of x
min(x); % minimum element of x
diff(x); % difference between adjacent elements of x
%% Exercise 1 : Vector operations
T = 1e-6; % Sampling period (s)
t = 0:T:2e-3; % Time (domain/x-axis)
f0 = 50; % Initial frequency (Hz)
b = 10e6; % Chirp rate (Hz/s)
A = 10; % Amplitude
y1 = A * cos(2*pi*f0*t + pi*b*t.^2);
figure;
plot(t,y1);
%% Exercise: Numerical calculus
% See numerical_calculus.m.
%% Basic indexing in MATLAB
% The process of extracting values from a vector (or matrix) is called
% "indexing." In MATLAB, indices start at 1, rather than 0 in most languages
% (in which it is more of an "offset" than a cardinal index).
%% Exercise 2 : Basic indexing
% The syntax for indexing is "x(indices)", where x is the variable to index,
% and indices is a scalar or a vector of indices. There are many variations on
% this. Note that indices can be any vector
x(1); % first element of x
x(1:3); % elements 1, 2 and 3 (inclusive!)
x(1:length(x)); % all elements in x
x(1:end); % same as above
x(:); % same as above
x(end); % last element of x
x(3:end); % all elements from 3 onwards
x([1,3,5]); % elements 1, 3, and 5 from x
x(1:2:end); % all odd-indexed elements of x
ind = 1:2:length(x);
x(ind); % same as the previous example
%% Exercises to improve your understanding
% Take some time to go through these on your own.
x([1,2,3]); % Will these produce the same result?
x([3,2,1]);
x2 = 1:5;
x2(6); % What will this produce?
x2(0); % What will this produce?
x2(1:1.5:4); % What will this produce?
ind = 1:1.5:4;
x2(ind); % What will this produce?
z = 4;
z(1); % What will this produce?
%% Matrix operations
% Matrices is closely related to vectors, and we have also explored some matrix
% operations last class. This class, we are going to explore functions that are
% very useful but are hard to grasp for beginners, namely reshape, meshgrid,
% row-wise and column-wise operations.
%% Reshape
% Change a matrix from one shape to another. The new shape has to have the same
% number of elements as the original shape.
%
% When you are reshaping an array / matrix, the first dimension is filled
% first, and then the second dimension, so on and so forth. I.e., elements
% start filling down columns, then rows, etc.
M = 1:100;
N1 = reshape(M,2,2,[]); % It would create a 2*2*25 matrix
N2 = reshape(M,[2,2,25]); % Same as N1
N2(:,:,25); % Gives you 97,98,99,100
N2(:,1,25); % Gives you 97 and 98
%% Row-wise / Column-wise operations
% Vector operations can also be performed on matrices. We can perform a vector
% operation on each row/column of a matrix, or on a particular row/column by
% indexing.
H = magic(4); % create the magical matrix H
sum(H,1); % column wise sum, note that this is a row vector(default)
fliplr(H); % flip H from left to right
flipud(H); % flip H upside down
H(1,:) = fliplr(H(1,:)); % flip only ONE row left to right
H(1,:) = []; % delete the first row
%% Exercise 7 : Matrix Operations
H2 = randi(20,4,5); % random 4x5 matrix with integers from 1 to 20
sum(H2(:,2));
mean(H2(3,:));
C = reshape(H2,2,2,5);
C(2,:,:) = [];

View File

@ -0,0 +1,57 @@
%% Creating the MATLAB logo
% from https://www.mathworks.com/help/matlab/visualize/creating-the-matlab-logo.html
% Copyright (C) 2014 Mathworks Inc.
close all; clear; clc;
%% Create the surface
L = 160*membrane(1,100);
%% Create the figure and axes
f = figure;
ax = axes;
s = surface(L);
s.EdgeColor = 'none';
view(3)
%% Adjust axis limits
ax.XLim = [1 201];
ax.YLim = [1 201];
ax.ZLim = [-53.4 160];
%% Adjust the camera position
ax.CameraPosition = [-145.5 -229.7 283.6];
ax.CameraTarget = [77.4 60.2 63.9];
ax.CameraUpVector = [0 0 1];
ax.CameraViewAngle = 36.7;
%% Adjust the position of the x, y, z axes themselves
ax.Position = [0 0 1 1];
ax.DataAspectRatio = [1 1 .9];
%% Add some light
l1 = light;
l1.Position = [160 400 80];
l1.Style = 'local';
l1.Color = [0 0.8 0.8];
l2 = light;
l2.Position = [.5 -1 .4];
l2.Color = [0.8 0.8 0];
%% Change the surface color
s.FaceColor = [0.9 0.2 0.2];
%% Adjust lighting algorithm
s.FaceLighting = 'gouraud';
s.AmbientStrength = 0.3;
s.DiffuseStrength = 0.6;
s.BackFaceLighting = 'lit';
s.SpecularStrength = 1;
s.SpecularColorReflectance = 1;
s.SpecularExponent = 7;
%% Remove background
axis off
f.Color = 'black';

View File

@ -0,0 +1,711 @@
octave:2>
octave:2>
octave:2>
octave:16>
y2 = x.^2;^[[201~octave:16>
octave:16>
octave:16>
octave:16>
octave:16> x = -10:0.1:10;
y = x.^3;
y2 = x.^2;
octave:19> size(y)
ans =
1 201
octave:20> size(x)
ans =
1 201
octave:21> plot(x, y)
octave:22> plot(x, y2)
octave:23> hold on
octave:24> plot(x, y)
octave:25> figure
octave:26> plot(x, y)
octave:27> close all
octave:28> figure
octave:29> plot(x, y)
octave:30> xlabel('x axis')
octave:31> ylabel('y axis')
octave:32> ylabel('y axis! yay!')
octave:33> ylabel('y axis! yay! more letters')
octave:34> title('a plot of a cubic')
octave:35> grid on
octave:36> legend('x^3')
octave:37> hold on
octave:38> close all
octave:39>
^[[201~octave:39>
octave:39>
octave:39>
octave:39>
octave:39> hold on; % plotting more than 1 plot on 1 figure rather than overwriting
plot(x, y, 'DisplayName', 'x^3');
plot(x, y2, 'DisplayName', 'x^2');
hold off;
xlabel 'x axis';
ylabel 'y axis';
title 'Example 1';
xlim([-10 10]);
ylim([-10 10]);
% axis([-10 10 -10 10]);
grid on;
legend show; % 'DisplayName does thisi
octave:50> close all
octave:51> help axis
'axis' is a function from the file /usr/share/octave/7.3.0/m/plot/appearance/axis.m
-- axis ()
-- axis ([X_LO X_HI])
-- axis ([X_LO X_HI Y_LO Y_HI])
-- axis ([X_LO X_HI Y_LO Y_HI Z_LO Z_HI])
-- axis ([X_LO X_HI Y_LO Y_HI Z_LO Z_HI C_LO C_HI])
-- axis (OPTION)
-- axis (OPTION1, OPTION2, ...)
-- axis (HAX, ...)
-- LIMITS = axis ()
Set axis limits and appearance.
The argument LIMITS should be a 2-, 4-, 6-, or 8-element vector.
The first and second elements specify the lower and upper limits
for the x-axis. The third and fourth specify the limits for the
y-axis, the fifth and sixth specify the limits for the z-axis, and
the seventh and eighth specify the limits for the color axis. The
special values '-Inf' and 'Inf' may be used to indicate that the
limit should be automatically computed based on the data in the
axes.
Without any arguments, 'axis' turns autoscaling on.
With one output argument, 'LIMITS = axis' returns the current axis
limits.
The vector argument specifying limits is optional, and additional
string arguments may be used to specify various axis properties.
The following options control the aspect ratio of the axes.
"equal"
Force x-axis unit distance to equal y-axis (and z-axis) unit
distance.
"square"
Force a square axis aspect ratio.
"vis3d"
Set aspect ratio modes ("DataAspectRatio",
"PlotBoxAspectRatio") to "manual" for rotation without
stretching.
"normal"
"fill"
Restore default automatically computed aspect ratios.
The following options control the way axis limits are interpreted.
"auto"
"auto[xyz]"
"auto [xyz]"
Set nice auto-computed limits around the data for all axes, or
only the specified axes.
"manual"
Fix the current axes limits.
"tight"
Fix axes to the limits of the data.
"image"
Equivalent to "tight" and "equal".
The following options affect the appearance of tick marks.
"tic"
"tic[xyz]"
"tic [xyz]"
Turn tick marks on for all axes, or turn them on for the
specified axes and off for the remainder.
"label"
"label[xyz]"
"label [xyz]"
Turn tick labels on for all axes, or turn them on for the
specified axes and off for the remainder.
"nolabel"
Turn tick labels off for all axes.
Note: If there are no tick marks for an axes then there can be no
labels.
The following options affect the direction of increasing values on
the axes.
"xy"
Default y-axis, larger values are near the top.
"ij"
Reverse y-axis, smaller values are near the top.
The following options affects the visibility of the axes.
"on"
Make the axes visible.
"off"
Hide the axes.
If the first argument HAX is an axes handle, then operate on this
axes rather than the current axes returned by 'gca'.
Example 1: set X/Y limits and force a square aspect ratio
axis ([1, 2, 3, 4], "square");
Example 2: enable tick marks on all axes, enable tick mark labels
only on the y-axis
axis ("tic", "labely");
See also: xlim, ylim, zlim, caxis, daspect, pbaspect, box, grid.
Additional help for built-in functions and operators is
available in the online version of the manual. Use the command
'doc <topic>' to search the manual index.
Help and information about Octave is also available on the WWW
at https://www.octave.org and via the help@octave.org
mailing list.
octave:52>
d2 = cos(t);^[[201~octave:52>
octave:52>
octave:52>
octave:52>
octave:52> t = 0:.1:10;
d1 = sin(t);
d2 = cos(t);
octave:55> figure
octave:56>
^[[200~hold on;
plot(t, d1);
plot(t, d2);
hold off;^[[201~octave:56>
octave:56>
octave:56>
octave:56>
octave:56> hold on;
plot(t, d1);
plot(t, d2);
hold off;
octave:60>
^[[200~title 'Trig Functions';^[[201~octave:60>
octave:60>
octave:60>
octave:60>
octave:60> title 'Trig Functions';
octave:61>
^[[200~xlabel 'time (\mu)s';^[[201~octave:61>
octave:61>
octave:61>
octave:61>
octave:61> xlabel('time (\mu)s');
octave:62> ylabel('voltage')
octave:63> legend('sin', 'cos')
octave:64> close all
octave:65> figure
octave:66>
octave:66>
octave:66>
octave:66>
octave:66>
octave:66> plot(t, d1, 'b-.', t, d2, 'rp');
octave:67>
^[[200~title 'Trig Functions';
xlabel 'time ($\mu$s)' Interpreter latex
ylabel voltage;
legend('sin', 'cos');
xticks(0:pi/2:10);
xticklabels({'0', '\pi/2', '\pi', '3\pi/2', '2\pi', '5\pi/2', '3\pi'});^[[201~octave:6
7>
octave:67>
octave:67>
octave:67>
octave:67> title 'Trig Functions';
xlabel 'time ($\mu$s)' Interpreter latex
ylabel voltage;
legend('sin', 'cos');
xticks(0:pi/2:10);
xticklabels({'0', '\pi/2', '\pi', '3\pi/2', '2\pi', '5\pi/2', '3\pi'});
sh: 1: dvipng: not found
warning: latex_renderer: a run-time test failed and the 'latex' interpreter has been d
isabled.
warning: called from
__axis_label__ at line 36 column 6
xlabel at line 59 column 8
octave:73> title 'Trig Functions';
xlabel 'time ($\mu$s)' Interpreter latex
ylabel voltage;
legend('sin', 'cos');
xticks(0:pi/2:10);
xticklabels({'0', '\pi/2', '\pi', '3\pi/2',
octave:73>
^[[200~xticks(0:pi/2:10);^[[201~octave:73>
octave:73>
octave:73>
octave:73>
octave:73> xticks(0:pi/2:10);
octave:74>
^[[200~xticklabels({'0', '\pi/2', '\pi', '3\pi/2', '2\pi', '5\pi/2', '3\pi'});^[[201~o
ctave:74>
octave:74>
octave:74>
octave:74>
octave:74> xticklabels({'0', '\pi/2', '\pi', '3\pi/2', '2\pi', '5\pi/2', '3\pi'});
octave:75> close all
octave:76> figure
octave:77> subplot(2, 1, 1)
octave:78>
^[[200~octave:75> close all^[[201~octave:78>
octave:78>
octave:78>
octave:78>
octave:78> octave:75> close all
octave:78> figure
octave:79> subplot(2, 1, 1)
octave:80> plot(t, d1)
octave:81> hold on
octave:82> plot(t, d2)
octave:83> title('an ordinary plot')
octave:84> subplot(2, 1, 2)
octave:85>
octave:85>
octave:85>
octave:85>
octave:85>
octave:85> plot(t, d1, 'b-.', t, d2, 'rp');
title 'Customized plot';
octave:87> close all
octave:88> figure
octave:89> stem(t, d1)
octave:90> hold on
octave:91> scatter(t, d2)
octave:92> close all
octave:93>
^[[200~t = linspace(0,10*pi);^[[201~octave:93>
octave:93>
octave:93>
octave:93>
octave:93> t = linspace(0,10*pi);
octave:94> figure
octave:95> plot3(sin(t), cos(t), t)
octave:96> zlabel('t')
octave:97> zlabel('tttttttttttttttttttttttttttttttttttt')
octave:98> title('a helix! in space!')
octave:99> text(0, 0, 0, 'origin')
octave:100> close all
octave:101>
^[[200~a1 = -2:0.25:2;
b1 = a1;
[A1, B1] = meshgrid(a1);
F = A1.*exp(-A1.^2-B1.^2);^[[201~octave:101>
octave:101>
octave:101>
octave:101>
octave:101> a1 = -2:0.25:2;
b1 = a1;
[A1, B1] = meshgrid(a1);
F = A1.*exp(-A1.^2-B1.^2);
octave:105> A1
A1 =
Columns 1 through 9:
-2.0000 -1.7500 -1.5000 -1.2500 -1.0000 -0.7500 -0.5000 -0.2500 0
-2.0000 -1.7500 -1.5000 -1.2500 -1.0000 -0.7500 -0.5000 -0.2500 0
-2.0000 -1.7500 -1.5000 -1.2500 -1.0000 -0.7500 -0.5000 -0.2500 0
-2.0000 -1.7500 -1.5000 -1.2500 -1.0000 -0.7500 -0.5000 -0.2500 0
-2.0000 -1.7500 -1.5000 -1.2500 -1.0000 -0.7500 -0.5000 -0.2500 0
-2.0000 -1.7500 -1.5000 -1.2500 -1.0000 -0.7500 -0.5000 -0.2500 0
-2.0000 -1.7500 -1.5000 -1.2500 -1.0000 -0.7500 -0.5000 -0.2500 0
-2.0000 -1.7500 -1.5000 -1.2500 -1.0000 -0.7500 -0.5000 -0.2500 0
-2.0000 -1.7500 -1.5000 -1.2500 -1.0000 -0.7500 -0.5000 -0.2500 0
-2.0000 -1.7500 -1.5000 -1.2500 -1.0000 -0.7500 -0.5000 -0.2500 0
-2.0000 -1.7500 -1.5000 -1.2500 -1.0000 -0.7500 -0.5000 -0.2500 0
-2.0000 -1.7500 -1.5000 -1.2500 -1.0000 -0.7500 -0.5000 -0.2500 0
-2.0000 -1.7500 -1.5000 -1.2500 -1.0000 -0.7500 -0.5000 -0.2500 0
-2.0000 -1.7500 -1.5000 -1.2500 -1.0000 -0.7500 -0.5000 -0.2500 0
-2.0000 -1.7500 -1.5000 -1.2500 -1.0000 -0.7500 -0.5000 -0.2500 0
-2.0000 -1.7500 -1.5000 -1.2500 -1.0000 -0.7500 -0.5000 -0.2500 0
-2.0000 -1.7500 -1.5000 -1.2500 -1.0000 -0.7500 -0.5000 -0.2500 0
Columns 10 through 17:
0.2500 0.5000 0.7500 1.0000 1.2500 1.5000 1.7500 2.0000
0.2500 0.5000 0.7500 1.0000 1.2500 1.5000 1.7500 2.0000
0.2500 0.5000 0.7500 1.0000 1.2500 1.5000 1.7500 2.0000
0.2500 0.5000 0.7500 1.0000 1.2500 1.5000 1.7500 2.0000
0.2500 0.5000 0.7500 1.0000 1.2500 1.5000 1.7500 2.0000
0.2500 0.5000 0.7500 1.0000 1.2500 1.5000 1.7500 2.0000
0.2500 0.5000 0.7500 1.0000 1.2500 1.5000 1.7500 2.0000
0.2500 0.5000 0.7500 1.0000 1.2500 1.5000 1.7500 2.0000
0.2500 0.5000 0.7500 1.0000 1.2500 1.5000 1.7500 2.0000
0.2500 0.5000 0.7500 1.0000 1.2500 1.5000 1.7500 2.0000
0.2500 0.5000 0.7500 1.0000 1.2500 1.5000 1.7500 2.0000
0.2500 0.5000 0.7500 1.0000 1.2500 1.5000 1.7500 2.0000
0.2500 0.5000 0.7500 1.0000 1.2500 1.5000 1.7500 2.0000
0.2500 0.5000 0.7500 1.0000 1.2500 1.5000 1.7500 2.0000
0.2500 0.5000 0.7500 1.0000 1.2500 1.5000 1.7500 2.0000
0.2500 0.5000 0.7500 1.0000 1.2500 1.5000 1.7500 2.0000
0.2500 0.5000 0.7500 1.0000 1.2500 1.5000 1.7500 2.0000
octave:106> B1
B1 =
Columns 1 through 9:
-2.0000 -2.0000 -2.0000 -2.0000 -2.0000 -2.0000 -2.0000 -2.0000 -2.0000
-1.7500 -1.7500 -1.7500 -1.7500 -1.7500 -1.7500 -1.7500 -1.7500 -1.7500
-1.5000 -1.5000 -1.5000 -1.5000 -1.5000 -1.5000 -1.5000 -1.5000 -1.5000
-1.2500 -1.2500 -1.2500 -1.2500 -1.2500 -1.2500 -1.2500 -1.2500 -1.2500
-1.0000 -1.0000 -1.0000 -1.0000 -1.0000 -1.0000 -1.0000 -1.0000 -1.0000
-0.7500 -0.7500 -0.7500 -0.7500 -0.7500 -0.7500 -0.7500 -0.7500 -0.7500
-0.5000 -0.5000 -0.5000 -0.5000 -0.5000 -0.5000 -0.5000 -0.5000 -0.5000
-0.2500 -0.2500 -0.2500 -0.2500 -0.2500 -0.2500 -0.2500 -0.2500 -0.2500
0 0 0 0 0 0 0 0 0
0.2500 0.2500 0.2500 0.2500 0.2500 0.2500 0.2500 0.2500 0.2500
0.5000 0.5000 0.5000 0.5000 0.5000 0.5000 0.5000 0.5000 0.5000
0.7500 0.7500 0.7500 0.7500 0.7500 0.7500 0.7500 0.7500 0.7500
1.0000 1.0000 1.0000 1.0000 1.0000 1.0000 1.0000 1.0000 1.0000
1.2500 1.2500 1.2500 1.2500 1.2500 1.2500 1.2500 1.2500 1.2500
1.5000 1.5000 1.5000 1.5000 1.5000 1.5000 1.5000 1.5000 1.5000
1.7500 1.7500 1.7500 1.7500 1.7500 1.7500 1.7500 1.7500 1.7500
2.0000 2.0000 2.0000 2.0000 2.0000 2.0000 2.0000 2.0000 2.0000
Columns 10 through 17:
-2.0000 -2.0000 -2.0000 -2.0000 -2.0000 -2.0000 -2.0000 -2.0000
-1.7500 -1.7500 -1.7500 -1.7500 -1.7500 -1.7500 -1.7500 -1.7500
-1.5000 -1.5000 -1.5000 -1.5000 -1.5000 -1.5000 -1.5000 -1.5000
-1.2500 -1.2500 -1.2500 -1.2500 -1.2500 -1.2500 -1.2500 -1.2500
-1.0000 -1.0000 -1.0000 -1.0000 -1.0000 -1.0000 -1.0000 -1.0000
-0.7500 -0.7500 -0.7500 -0.7500 -0.7500 -0.7500 -0.7500 -0.7500
-0.5000 -0.5000 -0.5000 -0.5000 -0.5000 -0.5000 -0.5000 -0.5000
-0.2500 -0.2500 -0.2500 -0.2500 -0.2500 -0.2500 -0.2500 -0.2500
0 0 0 0 0 0 0 0
0.2500 0.2500 0.2500 0.2500 0.2500 0.2500 0.2500 0.2500
0.5000 0.5000 0.5000 0.5000 0.5000 0.5000 0.5000 0.5000
0.7500 0.7500 0.7500 0.7500 0.7500 0.7500 0.7500 0.7500
1.0000 1.0000 1.0000 1.0000 1.0000 1.0000 1.0000 1.0000
1.2500 1.2500 1.2500 1.2500 1.2500 1.2500 1.2500 1.2500
1.5000 1.5000 1.5000 1.5000 1.5000 1.5000 1.5000 1.5000
1.7500 1.7500 1.7500 1.7500 1.7500 1.7500 1.7500 1.7500
2.0000 2.0000 2.0000 2.0000 2.0000 2.0000 2.0000 2.0000
octave:107> F
F =
Columns 1 through 9:
-0.0007 -0.0015 -0.0029 -0.0048 -0.0067 -0.0078 -0.0071 -0.0043 0
-0.0017 -0.0038 -0.0074 -0.0123 -0.0172 -0.0200 -0.0182 -0.0110 0
-0.0039 -0.0086 -0.0167 -0.0276 -0.0388 -0.0450 -0.0410 -0.0248 0
-0.0077 -0.0172 -0.0331 -0.0549 -0.0771 -0.0896 -0.0816 -0.0492 0
-0.0135 -0.0301 -0.0582 -0.0964 -0.1353 -0.1572 -0.1433 -0.0864 0
-0.0209 -0.0466 -0.0901 -0.1493 -0.2096 -0.2435 -0.2219 -0.1338 0
-0.0285 -0.0637 -0.1231 -0.2041 -0.2865 -0.3328 -0.3033 -0.1829 0
-0.0344 -0.0769 -0.1485 -0.2461 -0.3456 -0.4014 -0.3658 -0.2206 0
-0.0366 -0.0818 -0.1581 -0.2620 -0.3679 -0.4273 -0.3894 -0.2349 0
-0.0344 -0.0769 -0.1485 -0.2461 -0.3456 -0.4014 -0.3658 -0.2206 0
-0.0285 -0.0637 -0.1231 -0.2041 -0.2865 -0.3328 -0.3033 -0.1829 0
-0.0209 -0.0466 -0.0901 -0.1493 -0.2096 -0.2435 -0.2219 -0.1338 0
-0.0135 -0.0301 -0.0582 -0.0964 -0.1353 -0.1572 -0.1433 -0.0864 0
-0.0077 -0.0172 -0.0331 -0.0549 -0.0771 -0.0896 -0.0816 -0.0492 0
-0.0039 -0.0086 -0.0167 -0.0276 -0.0388 -0.0450 -0.0410 -0.0248 0
-0.0017 -0.0038 -0.0074 -0.0123 -0.0172 -0.0200 -0.0182 -0.0110 0
-0.0007 -0.0015 -0.0029 -0.0048 -0.0067 -0.0078 -0.0071 -0.0043 0
Columns 10 through 17:
0.0043 0.0071 0.0078 0.0067 0.0048 0.0029 0.0015 0.0007
0.0110 0.0182 0.0200 0.0172 0.0123 0.0074 0.0038 0.0017
0.0248 0.0410 0.0450 0.0388 0.0276 0.0167 0.0086 0.0039
0.0492 0.0816 0.0896 0.0771 0.0549 0.0331 0.0172 0.0077
0.0864 0.1433 0.1572 0.1353 0.0964 0.0582 0.0301 0.0135
0.1338 0.2219 0.2435 0.2096 0.1493 0.0901 0.0466 0.0209
0.1829 0.3033 0.3328 0.2865 0.2041 0.1231 0.0637 0.0285
0.2206 0.3658 0.4014 0.3456 0.2461 0.1485 0.0769 0.0344
0.2349 0.3894 0.4273 0.3679 0.2620 0.1581 0.0818 0.0366
0.2206 0.3658 0.4014 0.3456 0.2461 0.1485 0.0769 0.0344
0.1829 0.3033 0.3328 0.2865 0.2041 0.1231 0.0637 0.0285
0.1338 0.2219 0.2435 0.2096 0.1493 0.0901 0.0466 0.0209
0.0864 0.1433 0.1572 0.1353 0.0964 0.0582 0.0301 0.0135
0.0492 0.0816 0.0896 0.0771 0.0549 0.0331 0.0172 0.0077
0.0248 0.0410 0.0450 0.0388 0.0276 0.0167 0.0086 0.0039
0.0110 0.0182 0.0200 0.0172 0.0123 0.0074 0.0038 0.0017
0.0043 0.0071 0.0078 0.0067 0.0048 0.0029 0.0015 0.0007
octave:108> figure
octave:109> surf(A1, B1, F)
octave:110> figure
octave:111> mesh(A1, B1, F)
octave:112> close all
octave:113> help quiver
'quiver' is a function from the file /usr/share/octave/7.3.0/m/plot/draw/quiver.m
-- quiver (U, V)
-- quiver (X, Y, U, V)
-- quiver (..., S)
-- quiver (..., STYLE)
-- quiver (..., "filled")
-- quiver (HAX, ...)
-- H = quiver (...)
Plot a 2-D vector field with arrows.
Plot the (U, V) components of a vector field at the grid points
defined by (X, Y). If the grid is uniform then X and Y can be
specified as vectors and 'meshgrid' is used to create the 2-D grid.
If X and Y are not given they are assumed to be '(1:M, 1:N)' where
'[M, N] = size (U)'.
The optional input S is a scalar defining a scaling factor to use
for the arrows of the field relative to the mesh spacing. A value
of 1.0 will result in the longest vector exactly filling one grid
square. A value of 0 disables all scaling. The default value is
0.9.
The style to use for the plot can be defined with a line style
STYLE of the same format as the 'plot' command. If a marker is
specified then the markers are drawn at the origin of the vectors
(which are the grid points defined by X and Y). When a marker is
specified, the arrowhead is not drawn. If the argument "filled" is
given then the markers are filled.
If the first argument HAX is an axes handle, then plot into this
axes, rather than the current axes returned by 'gca'.
The optional return value H is a graphics handle to a quiver
object. A quiver object regroups the components of the quiver plot
(body, arrow, and marker), and allows them to be changed together.
Example:
[x, y] = meshgrid (1:2:20);
h = quiver (x, y, sin (2*pi*x/10), sin (2*pi*y/10));
set (h, "maxheadsize", 0.33);
See also: quiver3, compass, feather, plot.
Additional help for built-in functions and operators is
available in the online version of the manual. Use the command
'doc <topic>' to search the manual index.
Help and information about Octave is also available on the WWW
at https://www.octave.org and via the help@octave.org
mailing list.
octave:114> help quiver3
'quiver3' is a function from the file /usr/share/octave/7.3.0/m/plot/draw/quiver3.m
-- quiver3 (X, Y, Z, U, V, W)
-- quiver3 (Z, U, V, W)
-- quiver3 (..., S)
-- quiver3 (..., STYLE)
-- quiver3 (..., "filled")
-- quiver3 (HAX, ...)
-- H = quiver3 (...)
Plot a 3-D vector field with arrows.
Plot the (U, V, W) components of a vector field at the grid points
defined by (X, Y, Z). If the grid is uniform then X, Y, and Z can
be specified as vectors and 'meshgrid' is used to create the 3-D
grid.
If X and Y are not given they are assumed to be '(1:M, 1:N)' where
'[M, N] = size (U)'.
The optional input S is a scalar defining a scaling factor to use
for the arrows of the field relative to the mesh spacing. A value
of 1.0 will result in the longest vector exactly filling one grid
cube. A value of 0 disables all scaling. The default value is
0.9.
The style to use for the plot can be defined with a line style
STYLE of the same format as the 'plot' command. If a marker is
specified then the markers are drawn at the origin of the vectors
(which are the grid points defined by X, Y, Z). When a marker is
specified, the arrowhead is not drawn. If the argument "filled" is
given then the markers are filled.
If the first argument HAX is an axes handle, then plot into this
axes, rather than the current axes returned by 'gca'.
The optional return value H is a graphics handle to a quiver
object. A quiver object regroups the components of the quiver plot
(body, arrow, and marker), and allows them to be changed together.
[x, y, z] = peaks (25);
surf (x, y, z);
hold on;
[u, v, w] = surfnorm (x, y, z / 10);
h = quiver3 (x, y, z, u, v, w);
set (h, "maxheadsize", 0.33);
See also: quiver, compass, feather, plot.
Additional help for built-in functions and operators is
available in the online version of the manual. Use the command
'doc <topic>' to search the manual index.
Help and information about Octave is also available on the WWW
at https://www.octave.org and via the help@octave.org
mailing list.
octave:115> help feather
'feather' is a function from the file /usr/share/octave/7.3.0/m/plot/draw/feather.m
-- feather (U, V)
-- feather (Z)
-- feather (..., STYLE)
-- feather (HAX, ...)
-- H = feather (...)
Plot the '(U, V)' components of a vector field emanating from
equidistant points on the x-axis.
If a single complex argument Z is given, then 'U = real (Z)' and 'V
= imag (Z)'.
The style to use for the plot can be defined with a line style
STYLE of the same format as the 'plot' command.
If the first argument HAX is an axes handle, then plot into this
axes, rather than the current axes returned by 'gca'.
The optional return value H is a vector of graphics handles to the
line objects representing the drawn vectors.
phi = [0 : 15 : 360] * pi/180;
feather (sin (phi), cos (phi));
See also: plot, quiver, compass.
Additional help for built-in functions and operators is
available in the online version of the manual. Use the command
'doc <topic>' to search the manual index.
Help and information about Octave is also available on the WWW
at https://www.octave.org and via the help@octave.org
mailing list.
octave:116> figure
octave:117> imshow([1 0; 0 1])
octave:118> imshow(1:255)
octave:119> imshow([1 .5; .5 1])
octave:120> whos
Variables visible from the current scope:
variables in scope: top scope
Attr Name Size Bytes Class
octave:124> whos
octave:125> x = [1 0; 0 1]
x =
1 0
0 1
octave:126> whose
error: 'whose' undefined near line 1, column 1
octave:127> whos
Variables visible from the current scope:
variables in scope: top scope
Attr Name Size Bytes Class
==== ==== ==== ===== =====
x 2x2 32 double
Total is 4 elements using 32 bytes
octave:128> imshow(x)
octave:129> imshow(int(x))
error: 'int' undefined near line 1, column 8
octave:130> int
int16 int64 integral2 interp2 interpn intmin
int2str int8 integral3 interp3 intersect
int32 integral interp1 interpft intmax
octave:130> imshow(int8(x))
error: imshow: invalid data type for image
error: called from
imshow at line 199 column 9
octave:131> close all
octave:132> image = reshape(linspace(0, 1, 12), 2, 2, 3)
image =
ans(:,:,1) =
0 0.1818
0.0909 0.2727
ans(:,:,2) =
0.3636 0.5455
0.4545 0.6364
ans(:,:,3) =
0.7273 0.9091
0.8182 1.0000
octave:133> imshow(image)
octave:134> image(:, :, 3) = 0
image =
ans(:,:,1) =
0 0.1818
0.0909 0.2727
ans(:,:,2) =
0.3636 0.5455
0.4545 0.6364
ans(:,:,3) =
0 0
0 0
octave:135> imshow(image)
octave:136> image(:, :, 2) = 0
image =
ans(:,:,1) =
0 0.1818
0.0909 0.2727
ans(:,:,2) =
0 0
0 0
ans(:,:,3) =
0 0
0 0
octave:137> imshow(image)
octave:138> close all
octave:139>

152
lessons/lesson03/plotting.m Normal file
View File

@ -0,0 +1,152 @@
%% Lesson 5a: Plotting
%
% We are going to go through several plotting schemes, and explore how you
% can customize plotting. We would go through 2D plotting, surface
% plotting, subplot, stem plot and 3D plotting
%
% In this file the `command syntax` style of functions will be used when
% possible, just to get you familiar with the style.
clear; clc; close all;
%% 2D plotting: line graphs
% In general, always annotate your plots appropriately! Use a title,
% axis labels, legends, etc. as necessary. Set appropriate bounds,
% appropriate scaling (e.g., linear vs. logarithmic), and the correct
% type of plot. We'll start simple with line plots.
x = -10:0.1:10;
y = x.^3;
y2 = x.^2;
hold on; % plotting more than 1 plot on 1 figure rather than overwriting
plot(x, y, 'DisplayName', 'x^3');
plot(x, y2, 'DisplayName', 'x^2');
hold off;
xlabel 'x axis';
ylabel 'y axis';
title 'Example 1';
xlim([-10 10]);
ylim([-10 10]);
% axis([-10 10 -10 10]);
grid on;
legend show; % 'DisplayName does this
%% Example 2: Plotting sine and cosine
t = 0:.1:10;
d1 = sin(t);
d2 = cos(t);
figure;
% plot(t, [d1.' d2.']);
% plot(t, d1, t, d2);
hold on;
plot(t, d1);
plot(t, d2);
hold off;
title 'Trig Functions';
% We can use some LaTeX-like symbols like \mu, \beta, \pi, \leq, \infty.
% For full LaTeX support use the `Interpreter: latex` option
xlabel 'time (\mu)s';
ylabel voltage;
legend sin cos;
% Save to file; gcf() is "get current figure"
exportgraphics(gcf(), "sample_plot.png");
%% More plotting options
% Legends, axis ticks (and labels), LaTeX interpreter
figure;
% Options for changing line pattern and color.
% Don't need `hold on`/`hold off` if multiple lines plotted with a single
% `plot` function.
plot(t, d1, 'b-.', t, d2, 'rp');
title 'Trig Functions';
xlabel 'time ($\mu$s)' Interpreter latex
ylabel voltage;
legend('sin', 'cos');
xticks(0:pi/2:10);
xticklabels({'0', '\pi/2', '\pi', '3\pi/2', '2\pi', '5\pi/2', '3\pi'});
% Many other options availible for plotting. Check the documentation or
% search online for options.
%% Subplots
% Subplots exist for stylistic purposes. Let's say you have a signal and
% you want to plot the magnitude and phase of the signal itself. It would
% make more sense if the magnitude and phase plots exist in the same
% figure. There are several examples fo subplot below to explain how it
% works. Note that linear indexing of plots is different from normal linear
% indexing.
figure;
subplot(2,2,1); % subplot(# of rows, # of columns, index)
plot(t,d1);
hold on;
plot(t, d2);
title 'Normal plot';
subplot(2, 2, 2); % index runs down rows, not columns!
plot(t, d1, 'b-.', t, d2, 'rp');
title 'Customized plot';
%% Stem plots
% stem plots are particularly useful when you are representing digital
% signals, hence it is good (and necessary) to learn them too!
% subplot(2,2,[3 4]) % takes up two slots
subplot(2, 1, 2);
hold on;
stem(t, d1);
stem(t, d2);
hold off;
title 'Stem plots';
sgtitle Subplots;
%% Tiling -- like subplots but newer
figure;
tiledlayout(2, 2);
nexttile;
plot(t, d1);
nexttile;
plot(t, d2);
%% A 3-D parametric function
% A helix curve
t = linspace(0,10*pi);
figure;
plot3(sin(t), cos(t), t);
xlabel sin(t);
ylabel cos(t);
zlabel t;
text(0, 0, 0, 'origin');
grid on;
title Helix;
%% Surface plot
% A shaded look for 2-D functions
%
% $f(x) = x\exp -(x^2+y^2)$
a1 = -2:0.25:2;
b1 = a1;
[A1, B1] = meshgrid(a1);
F = A1.*exp(-A1.^2-B1.^2);
figure;
surf(A1,B1,F);
%% Mesh plot
% A wireframe look for 2-D functions
figure;
mesh(A1,B1,F);

View File

@ -0,0 +1,24 @@
classdef BasicClass
% BasicClass is a simple sample class definition
properties (Access = private)
vals % vector
end
methods
function obj = BasicClass(x)
% Construct an instance of this class
% Sets x to the object's vals property
obj.vals = x;
end
function z = getVals(obj)
z = obj.vals;
end
function z = findClosest(obj,n)
% Find closest entry in obj.vals to n
[~, ind] = min(abs(obj.vals - n));
z = obj.vals(ind);
end
end
end

View File

@ -0,0 +1,57 @@
%% Lesson 4b: Control Sequences
%
% Since it likes to play at being a general purpose programming language,
% MATLAB has control flow constructs (if, loops, etc.). Sometimes not
% everything is achievable with a linear set of instructions and vectorization,
% such as in particularly complex situations.
clear; clc; close all;
%% For loops (a review)
total=0;
for i=1:10
total = total + i;
end
total
%% If...Else Statements
gpa = 2.3;
if gpa < 2
fprintf('You are in DANGER!!!\n')
elseif gpa >= 2 && gpa < 3.5
fprintf('You are safe.\n')
elseif gpa >= 3.5 && gpa < 3.7
fprintf('Cum Laude\n')
elseif gpa >= 3.7 && gpa < 3.8
fprintf('Magna Cum Laude\n')
elseif gpa >= 3.8 && gpa < 4
fprintf('Summa Cum Laude\n')
else
fprintf("invalid gpa\n")
end
%% While loop
% Iterate while a condition is true, as opposed to iterating over a vector.
total = 0;
i = 0;
while i <= 10
total = total + i;
i = i+1;
end
total
%% Try/catch blocks
% Try and catch allow for error handling, which can be useful when using
% user-supplied input that may be invalid. See the documentation of any
% function to see what errors it may throw.
%
% It is also a good idea for you to validate input if writing a function
% intended to be used by other people. This is very common in all MATLAB
% builtin/toolbox functions.
try
a = [1 2; 3 4];
b = [1 2 3 4];
c = a*b % can't do this! not the right dimensions!
catch err
fprintf('Hey! Not allowed!\n');
end

View File

@ -0,0 +1,162 @@
%% Lesson 5b: Datatypes
% There are several basic data types in MATLAB:
%
% - single, double (floating pt. 32 and 64 bit respectively)
% - int8, int16, int32, int64 (different size integers)
% - uint8, uint16, uint32, uint64 (different size unsigned intergers)
% - logicals
% - char arrays, strings
% - cell arrays
clc; clear; close all;
%% What type is this?
% You can get the data type of a variable using the class function. Most
% of the time, values default to fp64, which is often good for
% scientific computing with high accuracy.
a = 10;
class(a);
b = int8(a);
class(b);
%% Data Type Sizes
% Different data types take up different amounts of space in your memory
% and hard drive. Let's take a look at some standard sizes in MATLAB.
A = randn(1, 'double');
B = randn(1, 'single');
C = true(1);
D = 'D';
% lists info of the variables in the current workspace
whos;
% If your data is getting too large, it can help to cast to smaller types.
% `single` is a smaller fp type, and uint8/uint16 are smaller
%% Different Interpretations
% Be careful with what data types you feed into built in functions.
% MATLAB will have different responses to different types.
% imshow with ints
imshow(uint8(rand(128, 128, 3)));
%%
% imshow with doubles
imshow(double(rand(128, 128, 3)));
%% Overflow and Underflow
% With floating point, we are trying to represent real numbers. Obviously
% there must be some spacing between representable numbers using a
% fixed-size representation. Let's take a look.
%
% eps() shows the error between a number and its true value given IEEE
% floating-point.
L = logspace(-400, 400, 4096);
loglog(L, eps(L), single(L), eps(single(L)));
% As the plot shows, doubles have a much larger range as well as higher
% precision at each point. Let's see how this applies in practice.
%% More examples examples of eps
eps(1);
(1 + 0.5001*eps(1)) - 1;
(1 + 0.4999*eps(1)) - 1;
eps(1e16);
1 + 1e16 == 1e16;
%% More examples of overflow/underflow
single(10^50);
single(10^-50);
uint8(256);
int8(-129);
%% Cell Arrays
% Matrices can only store values of the same type (homogenous data).
% Cell arrays can store heterogeneous (but still rectangular) data.
% However, they are relatively slow and should be used sparingly.
courses = {
'', 'Modern Physics', 'Signals and Systems', ...
'Complex Analysis', 'Drawing and Sketching for Engineers'; ...
'Grades', 70 + 3*randn(132,1), 80 + 3*randn(41,1), ...
40 + 3*randn(20,1), 100*ones(29,1); ...
'Teachers', {'Debroy'; 'Yecko'}, {'Fontaine'}, {'Smyth'}, {'Dell'}
};
%% Difference between {} and ()
% As we've seen before, () performs matrix indexing. A cell array behaves
% as a matrix of cell-arrays; indexing it using () will also produce a cell
% array.
%
% {} performs matrix indexing, and also extracts the values of the cell(s).
% Usually, this is what you want when immediately indexing a cell array.
%
% Confusingly (or not?) you can double-index cell arrays using `{}`, but
% you cannot double-index matrices using `()`.
courses(1,2);
courses{1,2};
courses{2,2}(3:5,1);
courses(3,2);
courses{3,2};
courses{3,2}{1}(1);
%% Objects and Classes
% MATLAB supports OOP programming. We saw a basic class definition last
% class. Classes are also used in all of MATLAB's toolboxes (e.g., ML,
% signal processing).
x = randn(10000, 1);
h = histogram(x); % h is a histogram class
properties(h);
methods(h);
% Check out the documentation for more info on the histogram class and
% other classes.
%% Structs and Objects
% MATLAB also supports `struct`s. Structs are like objects in that they
% can combine multiple values under the same variable (composite data),
% and use the same dot-indexing syntax. However, they are not defined by
% and constructed using a class, but rather using the `struct` constructor.
sfield1 = 'a'; svalue1 = 5;
sfield2 = 'b'; svalue2 = [3 6];
sfield3 = 'c'; svalue3 = "Hello World";
sfield4 = 'd'; svalue4 = {'cell array'};
s = struct( ...
sfield1, svalue1, ...
sfield2, svalue2, ...
sfield3, svalue3, ...
sfield4, svalue4 ...
);
s.a;
s.b(2);
%% Struct with cell array fields
% Cell arrays as struct fields may be used to generate an array of structs.
tfield1 = 'f1'; tvalue1 = zeros(1,10);
tfield2 = 'f2'; tvalue2 = {'a', 'b'};
tfield3 = 'f3'; tvalue3 = {pi, pi.^2};
tfield4 = 'f4'; tvalue4 = {'fourth'};
t = struct( ...
tfield1, tvalue1, ...
tfield2, tvalue2, ...
tfield3, tvalue3, ...
tfield4, tvalue4 ...
);
t(1);
t(2);
%% Adding fields to a struct
% Struct fields are not fixed; you can add fields to it after it is
% constructed using dot-indexing.
u = struct;
u.a = [1 3 5 7];
u.b = ["Hello","World!"];
u;

View File

@ -0,0 +1,19 @@
% In a file like this one (which only defines normal functions, and in which
% the first function is hononymous with the filename), the first function is a
% public function, and all other functions are local helper functions.
%
% Note that you DO NOT want to put clc; clear; close all; at the top of a file
% like this; it only makes sense to do this at the top of script files when you
% want to clean your workspace!
% Calculate Euclidean distance
% A public function, callable by other files and from the Command Window if
% this is in the MATLAB path.
function d = distance(x, y)
d = sqrt(sq(x) + sq(y));
end
% A local helper function. Only accessible within this file.
function x = sq(x)
x = x * x;
end

View File

@ -0,0 +1,34 @@
%% Lesson 2b: Control Sequence - For loops
% Similar to other languages, MATLAB have if, while and for control
% sequences. For loops are one of the commonly used control sequences in
% MATLAB. We will continue the discussion of if and while in the next
% lesson.
clear;
n = 1e7;
% D = zeros(1,n); % This is called pre-allocation
% try uncommenting this line to see the
% difference. Memory allocations are slow!
% Calculate fib(n). Hard to do vectorized unless we know Binet's formula.
% (Note that this will quickly overflow, but that's not our objective
% here.)
D(1) = 1;
D(2) = 2;
tic % start timer
for i = 3:n
D(i) = D(i-1) + D(i-2);
end
toc % print elapsed time since last tic
%% Be careful!
% For loops are considered the more inefficient type of operation in
% MATLAB. Performing operations on vectors is faster because your hardware
% can optimize vectorized instructions, and because the "for" construct
% exists in MATLAB's runtime, which is essentially a scripting language and
% thus is slow.
%
% However, things are changing, and things like parfor (parallel-for) and
% advanced JIT (just-in-time) compilation are improving the performance of
% loops. But vectorized operations are almost always faster and should
% be used where possible.

177
lessons/lesson04/funnnnnn.m Normal file
View File

@ -0,0 +1,177 @@
%% Lesson 4a: Functions
%
% Objectives:
% - Explore MATLAB's function-calling syntax and semantics.
% - Explore anonymous functions.
% - Explore local functions.
% - Explore regular functions.
clear; clc; close all;
%% Functions
% Functions in any programming language are the means of abstraction. In
% functional programming, they are a fundamental structure with the power to
% build any complex form. In imperative and scientific computing, functions are
% useful to prevent code duplication and improve maintainability.
%
% There are a few varieties of MATLAB, each of which has very different syntax
% and semantics, so buckle up!
%
% (Insider information from MathWorks: MATLAB is working on improving the
% support/accesibility of functional programming! So there may be some
% improvements in the near future!)
%
% Note: this lecture was heavily modified by a functional-programming fan!
%% Using functions
% All functions are called (invoked) in the same manner: by using the
% function's name followed by the list of parameters with which to invoke the
% function.
z = zeros(1, 3);
mean([1, 2, 3, 4, 5]);
% Functions may have optional parameters, and they may behave differently when
% called with different inputs (polymorphism) or when different numbers of
% outputs are expected. They may also return zero, one, or multiple values.
size1 = size(z);
size2 = size(z, 2); % optional second parameter
hist(1:10); % displays a historgram
a = hist(1:10); % stores a histogram into the variable a, and does
% not display a histogram
[r1, r2] = HelloWorld("Jon", "Lam"); % Function returning multiple
% values (HelloWorld defined later in
% file)
% There is a second way that you've seen to call functions, called "command
% syntax." These are translatable to the regular function syntax. Any textual
% arguments in this syntax will be interpreted as strings, which is similar to
% UNIX sh commands arguments (hence "command" syntax).
clear a b; % clear("a", "b")
close all; % close("all")
mkdir test; % mkdir("test")
rmdir test; % rmdir("test")
% Note that if a function takes no arguments, the parentheses may also be
% omitted. (This is not true for anonymous functions, as we will see.)
clc; % clc()
figure; % figure()
%% Anonymous functions
% Anonymous functions are defined with the following syntax:
%
% @(arg1, arg2, ...) fun_body
%
% These allow us to conveniently define functions inline, and perform some
% functional programming capabilities. In other programming languages, they may
% be known as "arrow functions" or "lambda functions."
cube = @(x) x.^3;
parabaloid = @(x, y) x.^2 + y.^2;
% Call these functions like any other function.
cube(3);
parabaloid(3, 4);
% As the name suggests, anonymous functions don't have to be assigned names; by
% themselves, they are "function values" or "function expressions" and can be
% handled like any other expression. (I.e., "first-class" functions). Usually,
% we assign it to a variable to name it, just as we do for most useful
% expressions.
@(x) x.^3;
cube_fnval = ans;
% Anonymous functions can capture variables from the surrounding scope. They
% may exist anywhere an expression may exist (e.g., within the body of another
% function).
outside_variable = 3;
capture_fn = @() outside_variable;
outside_variable = 4;
capture_fn; % What will this return?
capture_fn(); % What will this return?
% Lexical scoping and closures apply! This allows for some degree of functional
% programming (e.g., function currying).
curried_sum = @(x) @(y) x + y;
add_two = curried_sum(2);
add_two(5); % The binding x <- 2 is captured in
% add_two's lexical closure
% add_two(2)(5) % Can't do this due to MATLAB's syntax,
% just like how you can't double-index
% an expression
%% Example: Higher-order functions
% An example of passing functions around like any other variable. (Functions
% that accept other functions as parameters or return a function are called
% "higher-order functions.")
%
% In this example, compose is the function composition operator. compose(f,g)
% = (f o g). It is a HOF because it takes two functions as parameters, and it
% returns a function.
compose = @(f, g) @(x) f(g(x));
add_three = @(x) x + 3;
times_four = @(x) x * 4;
x_times_four_plus_three = compose(add_three, times_four);
x = 0:10;
y = x_times_four_plus_three(x);
plot(x, y);
grid on;
%% Normal Functions
% "Normal functions" (so-called because they were the first type of function in
% MATLAB) are defined using the syntax shown below, and are invoked in the same
% way as anonymous functions.
%
% Note that normal functions cannot be passed around as variables, and this
% makes a functional-programming style impossible using normal functions.
%
% Unlike anonymous functions, normal functions may include multiple statements,
% may return multiple values, are invoked if appearing in an expression without
% parentheses (unless you use a function handle), and do not capture variables
% from the surrounding scope/workspace.
%
% There are two types of normal functions: "public" normal functions, which
% must be placed at the beginning of a *.m file with the same name as the
% function, or local/private normal functions, which may appear at the end of a
% *.m file (after anything that is not a function). Both types of normal
% functions must appear after any statements in the file; in other words, a
% file defining a non-local function can only contain a list of function
% definitions, the first of is public and the rest of which are private. As the
% name suggests, local functions are only in scope in the file in which they
% are defined, whereas public functions may be accessible if they are on the
% MATLAB path.
%
% You don't need to understand all this right now; this brief explanation and
% the MATLAB documentation can serve as a reference for your future MATLAB
% endeavors.
%% The MATLAB Path
% In order to call a public function defined in another file, the function file
% must be in the current folder or on the MATLAB path.
matlabpath; % Print out MATLAB path
%% Invoking regular functions
% Note that this section is before the local function definition because the
% local function must be defined after all statements in the script.
%
% eye() is a builtin function. Here we call it with no arguments, so the first
% argument's value defaults to 1. distance() is a public function defined in
% the file distance.m HelloWorld() is a local function defined below
eye;
distance(3, 4);
HelloWorld("Jon", "Lam"); % Invoking HelloWorld and ignoring outputs
%% Defining a local function
function [res1, res2] = HelloWorld(name1, name2)
fprintf("Hello, world! %s %s\n", name1, name2);
res1 = 3;
res2 = [5 6];
end
%% Other fun stuff:
% Function handles
% `feval` on function handles and strings
% Double-indexing using functions
% Viewing source code using `edit`

View File

@ -0,0 +1,572 @@
octave:2> z = zeros(3)
z =
0 0 0
0 0 0
0 0 0
octave:3> mean(1:5)
ans = 3
octave:4> zeros(3)
ans =
0 0 0
0 0 0
0 0 0
octave:5> zeros(3, 1)
ans =
0
0
0
octave:6> help sum
'sum' is a built-in function from the file libinterp/corefcn/data.cc
-- sum (X)
-- sum (X, DIM)
-- sum (..., "native")
-- sum (..., "double")
-- sum (..., "extra")
Sum of elements along dimension DIM.
If DIM is omitted, it defaults to the first non-singleton
dimension.
The optional "type" input determines the class of the variable used
for calculations. By default, operations on floating point inputs
(double or single) are performed in their native data type, while
operations on integer, logical, and character data types are
performed using doubles. If the argument "native" is given, then
the operation is performed in the same type as the original
argument.
For example:
sum ([true, true])
=> 2
sum ([true, true], "native")
=> true
If "double" is given the sum is performed in double precision even
for single precision inputs.
For double precision inputs, the "extra" option will use a more
accurate algorithm than straightforward summation. For single
precision inputs, "extra" is the same as "double". For all other
data type "extra" has no effect.
See also: cumsum, sumsq, prod.
Additional help for built-in functions and operators is
available in the online version of the manual. Use the command
'doc <topic>' to search the manual index.
Help and information about Octave is also available on the WWW
at https://www.octave.org and via the help@octave.org
mailing list.
octave:7> sum(eye(3))
ans =
1 1 1
octave:8> eye(3)
ans =
Diagonal Matrix
1 0 0
0 1 0
0 0 1
octave:9> sum(eye(3))
ans =
1 1 1
octave:10> sum(eye(3), 2)
ans =
1
1
1
octave:11> sum(eye(3), 3)
ans =
1 0 0
0 1 0
0 0 1
octave:12> hold on
octave:13> close all
octave:14> close("all")
octave:15> hold("on")
octave:16> close("all")
octave:17> figure
octave:18> figure()
octave:19> close("all")
octave:20> hist(1:10)
octave:21> close all
octave:22> a = hist(1:10)
a =
1 1 1 1 1 1 1 1 1 1
octave:23> help find
'find' is a built-in function from the file libinterp/corefcn/find.cc
-- IDX = find (X)
-- IDX = find (X, N)
-- IDX = find (X, N, DIRECTION)
-- [i, j] = find (...)
-- [i, j, v] = find (...)
Return a vector of indices of nonzero elements of a matrix, as a
row if X is a row vector or as a column otherwise.
To obtain a single index for each matrix element, Octave pretends
that the columns of a matrix form one long vector (like Fortran
arrays are stored). For example:
find (eye (2))
=> [ 1; 4 ]
If two inputs are given, N indicates the maximum number of elements
to find from the beginning of the matrix or vector.
If three inputs are given, DIRECTION should be one of "first" or
"last", requesting only the first or last N indices, respectively.
However, the indices are always returned in ascending order.
If two outputs are requested, 'find' returns the row and column
indices of nonzero elements of a matrix. For example:
[i, j] = find (2 * eye (2))
=> i = [ 1; 2 ]
=> j = [ 1; 2 ]
If three outputs are requested, 'find' also returns a vector
containing the nonzero values. For example:
[i, j, v] = find (3 * eye (2))
=> i = [ 1; 2 ]
=> j = [ 1; 2 ]
=> v = [ 3; 3 ]
If X is a multi-dimensional array of size m x n x p x ..., J
contains the column locations as if X was flattened into a
two-dimensional matrix of size m x (n + p + ...).
Note that this function is particularly useful for sparse matrices,
as it extracts the nonzero elements as vectors, which can then be
used to create the original matrix. For example:
sz = size (a);
[i, j, v] = find (a);
b = sparse (i, j, v, sz(1), sz(2));
See also: nonzeros.
Additional help for built-in functions and operators is
available in the online version of the manual. Use the command
'doc <topic>' to search the manual index.
Help and information about Octave is also available on the WWW
at https://www.octave.org and via the help@octave.org
mailing list.
octave:24> cube = @(x) x.^3;
octave:25> cube
cube =
@(x) x .^ 3
octave:26> cube(3)
ans = 27
octave:27> paraboloid = @(x, y) x.^2 + y.^2;
octave:28> paraboloid(3, 4)
ans = 25
octave:29> @(x) x.^3
ans =
octave:35> a = 9
a = 9
octave:36> capture = @() a;
octave:37> capture
capture =
@() a
octave:38> capture()
ans = 9
octave:39> capture = @() 9
capture =
@() 9
octave:40> capture()
ans = 9
octave:41> capture = @() a;
octave:42> capture()
ans = 9
octave:43> a = 3
a = 3
octave:44> capture()
ans = 9
octave:45> n = 4
n = 4
octave:46> n = 2
n = 2
octave:47> pown = @(x) x.^n
pown =
@(x) x .^ n
octave:48> pown(3)
ans = 9
octave:49> n = 4
n = 4
octave:50> pown(3)
ans = 9
octave:51>
^[[200~compose = @(f, g) @(x) f(g(x));^[[201~octave:51>
octave:51>
octave:51>
octave:51>
octave:51> compose = @(f, g) @(x) f(g(x));
octave:52>
octave:52>
octave:52>
octave:52>
octave:52>
octave:52> add_three = @(x) x + 3;
times_four = @(x) x * 4;
x_times_four_plus_three = compose(add_three, times_four);
octave:55> x_times_four_plus_three
x_times_four_plus_three =
@(x) f (g (x))
octave:56> function y = times_four_plus_three(x)
> x2 = x.*4;
> y = x2 + 3;
> end
octave:57> times_four_plus_three(1)
ans = 7
octave:58> answer = times_four_plus_three(1)
answer = 7
octave:59> function [y, z] = mystery_math(p, q)
> y = p + q;
> z = p - q;
> disp('did the math!');
> end
octave:60> mystery_math(3, 4)
did the math!
ans = 7
octave:61> [val1, val2] = mystery_math(3, 4)
did the math!
val1 = 7
val2 = -1
octave:62>
[cat@lazarus:~/classes/ece210-materials/2024-van-west/lessons/lesson04]
$ ls
BasicClass.m datatypes.m for_loops.m lecture.txt
controlflow.m distance.m funnnnnn.m
[cat@lazarus:~/classes/ece210-materials/2024-van-west/lessons/lesson04]
$ cat distance.m
% In a file like this one (which only defines normal functions, and in which
% the first function is hononymous with the filename), the first function is a
% public function, and all other functions are local helper functions.
%
% Note that you DO NOT want to put clc; clear; close all; at the top of a file
% like this; it only makes sense to do this at the top of script files when you
% want to clean your workspace!
% Calculate Euclidean distance
% A public function, callable by other files and from the Command Window if
% this is in the MATLAB path.
function d = distance(x, y)
d = sqrt(sq(x) + sq(y));
end
% A local helper function. Only accessible within this file.
function x = sq(x)
x = x * x;
end
[cat@lazarus:~/classes/ece210-materials/2024-van-west/lessons/lesson04]
$ octave
GNU Octave, version 7.3.0
Copyright (C) 1993-2022 The Octave Project Developers.
This is free software; see the source code for copying conditions.
There is ABSOLUTELY NO WARRANTY; not even for MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. For details, type 'warranty'.
Octave was configured for "x86_64-pc-linux-gnu".
Additional information about Octave is available at https://www.octave.org.
Please contribute if you find this software useful.
For more information, visit https://www.octave.org/get-involved.html
Read https://www.octave.org/bugs.html to learn how to submit bug reports.
For information about changes from previous versions, type 'news'.
octave:1> who
octave:2> distance(3, 4)
ans = 5
octave:3> path
Octave's search path contains the following directories:
.
/usr/lib/x86_64-linux-gnu/octave/7.3.0/site/oct/x86_64-pc-linux-gnu
/usr/lib/x86_64-linux-gnu/octave/site/oct/api-v57/x86_64-pc-linux-gnu
/usr/lib/x86_64-linux-gnu/octave/site/oct/x86_64-pc-linux-gnu
/usr/share/octave/7.3.0/site/m
/usr/share/octave/site/api-v57/m
/usr/share/octave/site/m
/usr/share/octave/site/m/startup
/usr/lib/x86_64-linux-gnu/octave/7.3.0/oct/x86_64-pc-linux-gnu
/usr/share/octave/7.3.0/m
/usr/share/octave/7.3.0/m/audio
/usr/share/octave/7.3.0/m/deprecated
/usr/share/octave/7.3.0/m/elfun
/usr/share/octave/7.3.0/m/general
/usr/share/octave/7.3.0/m/geometry
/usr/share/octave/7.3.0/m/gui
/usr/share/octave/7.3.0/m/help
/usr/share/octave/7.3.0/m/image
/usr/share/octave/7.3.0/m/io
/usr/share/octave/7.3.0/m/java
/usr/share/octave/7.3.0/m/legacy
/usr/share/octave/7.3.0/m/linear-algebra
/usr/share/octave/7.3.0/m/miscellaneous
/usr/share/octave/7.3.0/m/ode
/usr/share/octave/7.3.0/m/optimization
/usr/share/octave/7.3.0/m/path
/usr/share/octave/7.3.0/m/pkg
/usr/share/octave/7.3.0/m/plot
/usr/share/octave/7.3.0/m/plot/appearance
/usr/share/octave/7.3.0/m/plot/draw
/usr/share/octave/7.3.0/m/plot/util
/usr/share/octave/7.3.0/m/polynomial
/usr/share/octave/7.3.0/m/prefs
/usr/share/octave/7.3.0/m/profiler
/usr/share/octave/7.3.0/m/set
/usr/share/octave/7.3.0/m/signal
/usr/share/octave/7.3.0/m/sparse
/usr/share/octave/7.3.0/m/specfun
/usr/share/octave/7.3.0/m/special-matrix
/usr/share/octave/7.3.0/m/startup
/usr/share/octave/7.3.0/m/statistics
/usr/share/octave/7.3.0/m/strings
/usr/share/octave/7.3.0/m/testfun
/usr/share/octave/7.3.0/m/time
/usr/share/octave/7.3.0/m/web
/usr/share/octave/7.3.0/data
octave:4> power_to_dB = @(p) 10*log10(p);
octave:5> dB_to_power = @(db) 10.^(db./10);
octave:6> power_to_dB(10)
ans = 10
octave:7> power_to_dB(1000)
ans = 30
octave:8> power_to_dB(100)
ans = 20
octave:9> dB_to_power(10)
ans = 10
octave:10> dB_to_power(-10)
ans = 0.1000
octave:11> for v = [1 2 5 7]
> v
> end
v = 1
v = 2
v = 5
v = 7
octave:12> for i = 1:10
> i + 3
> end
ans = 4
ans = 5
ans = 6
ans = 7
ans = 8
ans = 9
ans = 10
ans = 11
ans = 12
ans = 13
octave:13> total = 0
total = 0
octave:14> for i = 1:10
> total = total + i
> end
total = 1
total = 3
total = 6
total = 10
total = 15
total = 21
total = 28
total = 36
total = 45
total = 55
octave:15> sum(1:10)
ans = 55
octave:16> 1 < 2
ans = 1
octave:17> who
Variables visible from the current scope:
ans dB_to_power i power_to_dB total v
octave:18> whos
Variables visible from the current scope:
variables in scope: top scope
Attr Name Size Bytes Class
==== ==== ==== ===== =====
ans 1x1 1 logical
dB_to_power 1x1 0 function_handle
i 1x1 8 double
power_to_dB 1x1 0 function_handle
total 1x1 8 double
v 1x1 8 double
Total is 6 elements using 25 bytes
octave:19> if 1 < 2
> disp('math still works today');
> else
> disp('oh no');
> end
math still works today
octave:20> i = 0
i = 0
octave:21> while i < 10
> i = i + 1
> end
i = 1
i = 2
i = 3
i = 4
i = 5
i = 6
i = 7
i = 8
i = 9
i = 10
octave:22> try
> a = [1 2; 3 4];
> b = [1 2 3 4];
> c = a*b;
> catch err
> disp('yo! don't do that!')
error: parse error:
syntax error
>>> disp('yo! don't do that!')
^
octave:22> try
> a = [1 2; 3 4];
> b = [1 2 3 4];
> c = a*b;
> catch err
> disp('yo! do not do that!')
> end
yo! do not do that!
octave:23> a
a =
1 2
3 4
octave:24> b
b =
1 2 3 4
octave:25> a*b
error: operator *: nonconformant arguments (op1 is 2x2, op2 is 1x4)
octave:26> clear
octave:27> whos
octave:28> a = 10
a = 10
octave:29> class(a)
ans = double
octave:30> b = int8(a)
b = 10
octave:31> class(b)
ans = int8
octave:32> b + .5
ans = 11
octave:33> whos
Variables visible from the current scope:
variables in scope: top scope
Attr Name Size Bytes Class
==== ==== ==== ===== =====
a 1x1 8 double
ans 1x1 1 int8
b 1x1 1 int8
Total is 3 elements using 10 bytes
octave:34>
octave:34>
octave:34>
^[[200~imshow(uint8(rand(128, 128, 3)));^[[201~octave:34>
octave:34>
octave:34> imshow(uint8(rand(128, 128, 3)));
octave:35> close all
octave:36>
^[[200~imshow(double(rand(128, 128, 3)));^[[201~octave:36>
octave:36>
octave:36>
octave:36>
octave:36> imshow(double(rand(128, 128, 3)));
octave:37> close all
octave:38> imshow(uint8(rand(128, 128, 3)));
octave:39> close all
octave:40> imshow(uint8(rand(128, 128, 3)));
octave:40> eps
ans = 2.2204e-16
octave:41> eps(1)
ans = 2.2204e-16
octave:42> eps(.001)
ans = 2.1684e-19
octave:43> eps(10000)
ans = 1.8190e-12
octave:44> eps(1e100)
ans = 1.9427e+84
octave:45> 10^(10^10)
ans = Inf
octave:46> a = 5
a = 5
octave:47> b = "hello!"
b = hello!
octave:48> s = struct('a', 5, 'b', "hello!")
s =
scalar structure containing the fields:
a = 5
b = hello!
octave:49> s
s =
scalar structure containing the fields:
a = 5
b = hello!
octave:50> s.a
ans = 5
octave:51> s.b
ans = hello!
octave:52>

127
lessons/lesson05/indexing.m Normal file
View File

@ -0,0 +1,127 @@
%% Lesson 3b: Advanced Indexing
%
% Objectives:
% - Review basic vector indexing
% - Introduce multidimensional indexing and linear indexing
% - Introduce logical indexing
clear; clc; close all;
%% Review of basic vector indexing
% Indexed expressions can appear on the right-hand side of an assignment or the
% left-hand side (rvalues and lvalues in C).
x = [2 4 8 16 32 64 128];
x(3);
x(4:6);
x(:);
x(end);
x(2) = -4;
%% Vectors indexing vectors
% You can use a vector to index another vector. This can be useful if there is
% a specific index pattern you want from a vector.
x([1 3 5 7]); % Returns a vector with the 1st, 3rd, 5th, and 7th
% entries of x
x(1:2:7); % Same thing uses the colon operator to create the
% index vector
x([2:4 3:6]);
x([1:4]) = 7; % Changes the values from the 1st and 4th entries
% of x to 7
%% Indexing matrices with 2 subscripts
% You can index a matrix using two indices, separated by a comma.
A = [16 2 3 13; 5 11 10 8; 9 7 6 12; 4 14 15 1];
A(1,1); % Returns entry in first row and first column
A(1:3,1:2); % Returns the entries in the first three rows AND
% first two columns
A(end,:);
% What if I want to index the (2,1), (3,2), (4,4) entries?
A([2 3 4],[1 2 4]); % Will this work?
%% Linear Indexing
% Instead you should index linearly! Linear indexing only uses one
% subscript
A(:); % What does this return and in what form and order?
reshape(A, [], 1); % What about this?
A(14); % What value does this return?
%% Non-rectangular indices
% Now that we know about linear indexing, what values does this return?
A([2 7 16]);
% Luckily enough, MATLAB has a function that would calculate the linear
% index for you!
ind = sub2ind(size(A),[2 3 4],[1 2 4]);
A(ind);
% Note that sub2ind follows a common naming convention in MATLAB for converting
% one type to another. For example, there is also ind2sub, str2int, int2str,
% zp2tf, tf2zp, etc.
%% Logical Indexing
% Logical indexing allows us to use boolean logic to build more complex
% indices. This is based off of boolean logic: we have two boolean values TRUE
% (represented by 1) and FALSE (represented by 0), and the boolean operators
% AND, OR, and NOT.
%
% Logical scalar and matrix literals can be constructed from double and matrix
% literals using the logical() function, or they may be generated from other
% operations. (Note that logical and double values have different data types.)
B = eye(4); % Regular identity matrix
C = logical([1 1 1 1; 1 0 0 0; 1 0 0 0; 1 0 0 0]); % Logical entries
islogical(B);
islogical(C);
%% Some logical operators
B = logical(B); % Converts B into a logical array
B & C; % and(B,C) is equivalent to B&C
B | C; % or(B,C) is equivalent to B|C
~(B & C); % not(and(B,C)) is equivalent to ~(B&C)
not(B & C); % you can use both representations intermittenly
%% Functions that generate logical values
% The following functions are analogous to the ones() and zeros() functions
% for double matrices.
true(2,5); % creates a 2x5 logical matrix of trues(1s)
false(2,5);
%% Generating logical values from predicates
% Relational (comparison) operators generate logical values. Relational
% operators on matrices will perform the operation element-wise and return a
% logical matrix.
%
% This is not anything really special, since we've seen element-wise operations
% on matrices. The only change is that instead of functions that return
% numbers, we have functions that return booleans (predicates).
D = [1 2 3; 2 3 4; 3 4 5];
E = [1 5 6; 9 2 8; 7 3 4];
D == 3; % Returns true every place there is a 3.
D < E; % Elementwise comparison
D < 3; % Elementwise comparison against a scalar.
% (Note: this is broadcasting!)
D < [7; 4; 1]; % Another example of broadcasting: comparison
% of each row against a scalar.
%% Logical indexing
% Logical indexing uses a logical value as the index. Elements in the indexed
% matrix where the logical index is TRUE will be returned, and FALSE values
% will be disregarded. The returned matrix will always be a column vector,
% similar to indexing with (:).
A(A > 12); % returns entries of A which are greater
% than 12 in a column vector
% To return the linear indices of the TRUE values in a logical matrix.
find(A > 12);
A(find(A > 12)); % Gives the same results as above

View File

@ -0,0 +1,44 @@
%% Lesson 3a: Meshes & Broadcasting
%% Meshgrid
% Meshgrid is quite hard to understand. Think of it as a way to replicate
% arrays, like the following example:
a = 1:3;
b = 1:5;
[A,B] = meshgrid(a,b);
%% Using meshgrid for functions of multiple variables
% You have created two arrays A and B, note that in A, the vector a is copied
% row-wise, while the vector b is transposed and copied column-wise. This is
% useful, because when you lay one above the other, you essentially create a
% CARTESIAN PRODUCT, and it is useful when we need to plot a 3D graph.
%
% Here is a more complicated example to show you when meshgrid is useful
a1 = -2:0.25:2;
b1 = a1;
[A1,B1] = meshgrid(a1);
% Here we plot the surface of f(x) = x*exp^(x.^2+y.^2)
F = A1.*exp(-A1.^2-B1.^2);
surf(A1, B1, F);
%% Broadcasting: an alternative to meshgrid
% Broadcasting, like meshgrid, can be used as a way to write functions of
% multiple variables, without generating the intermediate matrices A and B.
% The way this works is that operations performed on a set of N orthogonal
% vectors will automatically generate an N-dimensional result.
%
% See the following example, which recreates the above example. Note that b1 is
% transposed.
F2 = a1.*exp(-a1.^2-(b1.').^2);
surf(A1, B1, F2);
% Check that this matches the previous result.
error = rms(F - F2, 'all');
% Note: broadcasting doesn't generate the domains A1 and B1, so meshgrid() is
% more useful when we need to supply the domain to a function like mesh() or
% surf(). But when we only need the result, broadcasting is somewhat simpler.
%
% For homework assignments that require functions of multiple variables, use
% whichever method is more intuitive to you.

File diff suppressed because it is too large Load Diff

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.

View File

@ -0,0 +1,35 @@
function Hd = bandstop2500
%BANDSTOP2500 Returns a discrete-time filter object.
% MATLAB Code
% Generated by MATLAB(R) 9.9 and Signal Processing Toolbox 8.5.
% Generated on: 24-Mar-2021 17:32:55
% Elliptic Bandstop filter designed using FDESIGN.BANDSTOP.
% All frequency values are in Hz.
Fs = 8192; % Sampling Frequency
Fpass1 = 2000; % First Passband Frequency
Fstop1 = 2300; % First Stopband Frequency
Fstop2 = 2700; % Second Stopband Frequency
Fpass2 = 3000; % Second Passband Frequency
Apass1 = 0.5; % First Passband Ripple (dB)
Astop = 60; % Stopband Attenuation (dB)
Apass2 = 1; % Second Passband Ripple (dB)
match = 'both'; % Band to match exactly
% Construct an FDESIGN object and call its ELLIP method.
h = fdesign.bandstop(Fpass1, Fstop1, Fstop2, Fpass2, Apass1, Astop, ...
Apass2, Fs);
Hd = design(h, 'ellip', 'MatchExactly', match);
% Get the transfer function values.
[b, a] = tf(Hd);
% Convert to a singleton filter.
Hd = dfilt.df2(b, a);
% [EOF]

View File

@ -0,0 +1,131 @@
%% Lesson 7a. Designing filters the modern way
% * Learn how to use `filterDesigner`
% * Learn how to use `fdesign`
close all; clear; clc;
%% Filter Overview
% Remember order = # of delay elements, want to minimize to meet
% some spec.
%
% There are 4 main types of filters:
% * Lowpass - passes low frequencies through
% * Highpass - passes high frequencies through
% * Bandpass - passes a specific band
% * Bandstop - stops a specific band from going through
%
% There are four primary implementations of filters that optimize
% different properties:
% * Butterworth - maxflat passband, monotonic passband & stopband
% * Chebychev I - equiripple passband, monotonic stopband
% * Chebychev II - monotonic passband, equiripple stopband
% * Elliptic - minimum order, equiripple passband & stopband
%
% In this lesson, you will be able to very clearly see these
% properties and filter types!
%% Filter design (GUI)
% Note: Ask Prof. Keene about `filterDesigner`, it'll make him
% very happy.
filterDesigner; % then export to workspace as numerator and
% denominator (not SOS for now)
%% Applying a GUI-designed filter
% Note that if a filter is generated using a `filterDesigner` function,
% it will be a filter object. You can apply a filter object using the
% `filter()` function. If your filter is given as an impulse response, you
% can either use the `filter()` function or convolve the impulse response
% and the input signal.
% Load handel again
load handel;
% Get a generated filter (this should decimate a narrow frequency band
% centered at 2.5kHz, assuming a 8192Hz sampling frequency).
flt = bandstop2500;
% Perform the filter
y1 = filter(flt, y);
%% Filter design via `fdesign`
% Filter specifications
Fsample = 44100;
Apass = 1;
Astop = 80;
Fpass = 1e3;
Fstop = 1e4;
% Use the appropriate `fdesign.*` object to create the filter; in this case,
% we're designing a lowpass filter.
specs = fdesign.lowpass(Fpass, Fstop, Apass, Astop, Fsample);
% Note: the arguments to `fdesign.*` can be altered by passing in a SPEC option
% -- the following call to `fdesign.lowpass` will produce the same filter. If
% you want to do more complex stuff (like setting the 3 dB point directly or
% setting the filter order), you can change this argument. See `doc
% fdesign.lowpass` for more info.
equivalent_specs = fdesign.lowpass('Fp,Fst,Ap,Ast', ...
Fpass, Fstop, Apass, Astop, Fsample);
% For a given filter type, there are a myriad of different ways to design it
% depending on what properties you want out of the filter (equiripple
% passband/stopband, monotonic passband/stopband, minimum-order, max-flat,
% etc.), which our lowpass filter object supports.
%
% Note: `'SystemObject'` should be set to `true` by Mathworks' recommendation
% for these calls, even though they will often work without it.
designmethods(specs, 'SystemObject', true);
% There are also various options we can set when designing the filter. In this
% example, we'll tell it to match the passband amplitude exactly.
designoptions(specs, 'butter', SystemObject=true);
% Finally, let's make this thing!
butter_filter = design(specs, 'butter', ...
MatchExactly='passband', SystemObject=true);
%% Examining a filter
% Filters can be visualized with `fvtool`, drawing a nice box around the
% transition zone and lines at the edge frequencies & important amplitudes:
h = fvtool(butter_filter); % note no call to `figure`!
% `measure` is another way to check:
measurements = measure(butter_filter);
% `h` is a handle to the graphics object we've created with `fvtool`, and we
% can change its properties (listed with `get(h)`) if we wish:
h.FrequencyScale = 'Log';
ax = h.Children(15); % the axes object, found by looking at `h.Children`
ax.YLim = [-60 10]; % in dB
%% Using a filter
% Filter objects have a lot of methods to them (things like `freqz`, `impz`,
% `islinphase`, `isallpass`, etc -- check `methods(butter_filter)` if you want
% the list) that are rather useful. One method they *don't* have is `filter`,
% so if you want to apply a filter to a signal, you do it like this:
load handel; % of course; loads `y` and `Fs` into the workspace
y1 = butter_filter(y); % use like a function!
sound(y, Fs);
sound(y1, Fs);
%% Plotting the result
% Obtain the FFT of the original and the filtered signal.
shifted_fft_mag = @(sig, len) fftshift(abs(fft(sig, len))) / len;
N = 2^15;
S1 = shifted_fft_mag(y, N);
S2 = shifted_fft_mag(y1, N);
F = linspace(-Fsample/2, Fsample/2, N); % not quite accurate but close
% Plot the FFTs.
figure;
subplot(2, 1, 1);
plot(F, S1);
title 'Fourier Transform of Original Audio';
xlabel 'Frequency (Hz)';
ylabel 'Magnitude';
subplot(2, 1, 2);
plot(F, S2);
title 'Fourier Transform of Filtered Audio';
xlabel 'Frequency (Hz)';
ylabel 'Magnitude';

View File

@ -0,0 +1,103 @@
%% Lesson 7c. Designing filters the old fashioned way
% (notes kept for historical reasons; the new notes are in `filter_design.m`.
%
% * Learn how to use the `filterDesigner` GUI.
% * Learn how to manually design a filter.
clc; clear; close all;
%% Filter Overview
% Remember order = # of delay elements, want to minimize to meet
% some spec.
%
% There are 4 main types of filters:
% * Lowpass - passes low frequencies through
% * Highpass - passes high frequencies through
% * Bandpass - passes a specific band
% * Bandstop - stops a specific band from going through
%
% There are four primary implementations of filters that optimize
% different properties:
% * Butterworth - maxflat passband, monotonic passband & stopband
% * Chebychev I - equiripple passband, monotonic stopband
% * Chebychev II - monotonic passband, equiripple stopband
% * Elliptic - minimum order, equiripple passband & stopband
%
% In this lesson, you will be able to very clearly see these
% properties and filter types!
%% Filter Design (GUI)
% Note: Ask Prof. Keene about `filterDesigner`, it'll make him
% very happy.
filterDesigner; % then export to workspace as numerator and
% denominator (not SOS for now)
%% Filter Design (Code)
% Manually specify specifications
Fs = 44100;
Apass = 1;
Astop = 80;
Fpass = 1e3;
Fstop = 1e4;
wpass = Fpass / (Fs/2); % normalized to nyquist freq.
wstop = Fstop / (Fs/2); % normalized to nyquist freq.
% Compute the minimum order for Butterworth filter
% that meets the specifications.
% Alternatively, see `butter1ord`, `cheby1ord`,
% `cheby2ord`, `ellipord`.
n = buttord(wpass, wstop, Apass, Astop);
% Generate Butterworth filter with order `n` (which is
% designed to meet the specification).
% Alternatively, see `cheby1`, `cheby2`, `ellip`.
[b, a] = butter(n, wpass);
[H, W] = freqz(b, a);
% Plot the frequency response. (At this point, recall that
% the frequency response is the FFT of the impulse response.
% Can you generate the frequency response without using
% the `freqz` function (instead using the `impz` and `fft`
% functions)?
f = W .* Fs/(2*pi);
figure;
semilogx(f, 20*log10(abs(H)));
xlim([1e2 1e5]);
ylim([-100 5]);
grid on;
title 'Butterworth Lowpass Filter';
xlabel 'Frequency (Hz)';
ylabel 'Magnitude (dB)';
%% Applying a filter
% Note that if a filter is generated using a `filterDesigner` function,
% it will be a filter object. You can apply a filter object using the
% `filter()` function. If your filter is given as an impulse response, you
% can either use the `filter()` function or convolve the impulse response
% and the input signal.
% Load handel again
load handel;
% Get a generated filter (this should decimate a narrow frequency band
% centered at 2.5kHz, assuming a 8192Hz sampling frequency).
flt = bandstop2500;
% Perform the filter
y1 = filter(flt, y);
%% How does it sound now?
sound(y1, Fs);
%% Plotting the result
% Obtain the FFT of the filtered signal.
N = 2^15;
S = fft(y1, N);
S = fftshift(abs(S)) / N;
F = linspace(-Fs/2, Fs/2, N);
% Plot the FFT.
figure;
plot(F, S);
title 'Fourier Transform of Audio';
xlabel 'Frequency (Hz)';
ylabel 'Magnitude';

View File

@ -0,0 +1,93 @@
%% Lesson 7c. Transfer function objects
close all; clear; clc;
%% Transfer function overview
% Transfer functions are abstract representations of LTI systems in terms of
% rational functions (numerator and denominator). We used to work with transfer
% functions in terms of MATLAB-style polynomials, but Mathworks has come up
% with a new, supposedly improved way: transfer function objects! These are
% created via `tf` in a variety of ways. For more info, see Mathworks'
% documentation -- these models are most helpful when working with cascades of
% systems, such as for controls modeling.
%% Digital transfer function objects
% To create a digital tf. object, specify a numerator, denominator, and
% sampling time (which may be set to -1 if you want to leave it undefined). The
% numerator and denominator are specified in decreasing power order, with s^0
% or z^0 on the right.
dig_num = [1]; % 1z = 1
dig_den = [2 -1]; % 2z¹ - 1z = 2z - 1
timestep = 0.1; % 0.1 s
dig_sys = tf(dig_num, dig_den, timestep);
%% Analog transfer function objects
% Analog transfer functions are created the same way as digital ones, just
% without the timestep.
an_num = [1 -1]; % 1s¹ - 1s = 1s - 1
an_den = [1 2 1]; % s² + 2s + 1
an_sys = tf(an_num, an_den);
%% Alternate ways of specifying
% MATLAB provides a syntax for creating transfer functions out of coded
% rational expressions, as this can be clearer:
s = tf('s'); % create an s variable that may then be used mathematically
an_sys_2 = (s - 1)/(s + 1)^2; % same as above
%% Investigating the transfer function
% One property of interest is the step response, which we can view thus:
figure;
stepplot(an_sys);
% MATLAB has a built-in function to get a Bode plot, too (though you should
% modify this in post if you want to highlight specific details in the plot).
figure;
bodeplot(an_sys);
%% One application
% This example is stolen from Mathworks' doc page "Control System Modeling with
% Model Objects," as it's an interesting perspective on what you can do with
% these. In it, we model the following system:
%
% x ---> F(s) ---> +( ) ---> C(s) ---> G(s) ---+---> y
% - |
% ^ |
% \---------- S(s) ---------/
% specify the components of a system
G = zpk([], [-1, -1], 1); % no zeroes, double pole at -1, analog
C = pid(2, 1.3, 0.3, 0.5); % PID controller object
S = tf(5, [1 4]);
F = tf(1, [1 1]);
% find the open-loop transfer function (by breaking the loop at the subtract)
open_loop = F*S*G*C; % multiplication in the "frequency" domain
% check out where the poles & zeroes are
figure;
pzplot(open_loop);
title('Open loop pole/zero plot');
xlim([-6 1]);
ylim([-2 2]);
% see what this thing does with a step input
figure;
stepplot(open_loop);
title('Open-loop system step response');
% note that this is *not* stable with a step input, as the PID controller loses
% its shit!
% find the closed-loop, whole_system response using `feedback` to specify a
% feedback connection
full_system = F*feedback(G*C, S);
% see what this thing looks like now in the s-plane
figure;
pzplot(full_system);
title('Full system pole/zero plot');
xlim([-6 1]);
ylim([-2 2]);
% now stable with a step input, as we have feedback
figure;
stepplot(full_system);
title('Full system step response');

View File

@ -0,0 +1,810 @@
octave:5> pkg load symbolic
octave:6> syms x z
Symbolic pkg v3.0.1: Python communication link active, SymPy v1.11.1.
octave:7> syms
Symbolic variables in current scope:
x
z
octave:8> x
x = (sym) x
octave:9> syms x_0
octave:10> xu-0
error: 'xu' undefined near line 1, column 1
octave:11> x_0
x_0 = (sym) x₀
octave:12> v = x + 2
v = (sym) x + 2
octave:13> w = x * z
w = (sym) x⋅z
octave:14> help subs
error: help: 'subs' not found
octave:15> help @sym/subs
'@sym/subs' is a function from the file /usr/share/octave/packages/symbolic-3.0.1/@sym
/subs.m
-- Method on @sym: subs (F, X, Y)
-- Method on @sym: subs (F, Y)
-- Method on @sym: subs (F)
Replace symbols in an expression with other expressions.
Example substituting a value for a variable:
syms x y
f = x*y;
subs(f, x, 2)
⇒ ans = (sym) 2⋅y
If X is omitted, symvar is called on F to determine an
appropriate variable.
X and Y can also be vectors or lists of syms to replace:
subs(f, {x y}, {sin(x) 16})
⇒ ans = (sym) 16⋅sin(x)
F = [x x*y; 2*x*y y];
subs(F, {x y}, [2 sym(pi)])
⇒ ans = (sym 2×2 matrix)
⎡ 2 2⋅π⎤
⎢ ⎥
⎣4⋅π π ⎦
With only one argument, subs(F) will attempt to find values for
each symbol in F by searching the workspace:
f = x*y
⇒ f = (sym) x⋅y
x = 42;
f
⇒ f = (sym) x⋅y
Here assigning a numerical value to the variable x did not change
the expression (because symbols are not the same as variables!)
However, we can automatically update f by calling:
subs(f)
⇒ ans = (sym) 42⋅y
*Warning*: subs cannot be easily used to substitute a double
matrix; it will cast Y to a sym. Instead, create a “function
handle” from the symbolic expression, which can be efficiently
evaluated numerically. For example:
syms x
f = exp(sin(x))
⇒ f = (sym)
sin(x)
fh = function_handle(f)
⇒ fh =
@(x) exp (sin (x))
fh(linspace(0, 2*pi, 700)')
⇒ ans =
1.0000
1.0090
1.0181
1.0273
1.0366
...
*Note*: Mixing scalars and matrices may lead to trouble. We
support the case of substituting one or more symbolic matrices in
for symbolic scalars, within a scalar expression:
f = sin(x);
g = subs(f, x, [1 sym('a'); pi sym('b')])
⇒ g = (sym 2×2 matrix)
⎡sin(1) sin(a)⎤
⎢ ⎥
⎣ 0 sin(b)⎦
When using multiple variables and matrix substitions, it may be
helpful to use cell arrays:
subs(y*sin(x), {x, y}, {3, [2 sym('a')]})
⇒ ans = (sym) [2⋅sin(3) a⋅sin(3)] (1×2 matrix)
subs(y*sin(x), {x, y}, {[2 3], [2 sym('a')]})
⇒ ans = (sym) [2⋅sin(2) a⋅sin(3)] (1×2 matrix)
*Caution*, multiple interdependent substitutions can be ambiguous
and results may depend on the order in which you specify them. A
cautionary example:
syms y(x) A B
u = y + diff(y, x)
⇒ u(x) = (symfun)
d
y(x) + ──(y(x))
dx
subs(u, {y, diff(y, x)}, {A, B})
⇒ ans = (sym) A
subs(u, {diff(y, x), y}, {B, A})
⇒ ans = (sym) A + B
Here it would be clearer to explicitly avoid the ambiguity by
calling subs twice:
subs(subs(u, diff(y, x), B), y, A)
⇒ ans = (sym) A + B
See also: @sym/symfun.
Additional help for built-in functions and operators is
available in the online version of the manual. Use the command
'doc <topic>' to search the manual index.
Help and information about Octave is also available on the WWW
at https://www.octave.org and via the help@octave.org
mailing list.
octave:16> syms r
octave:17> w
w = (sym) x⋅z
octave:18> subs(w, z, r)
ans = (sym) r⋅x
octave:19> solve(x + 3 == 5, x)
ans = (sym) 2
octave:20>
octave:20> syms a b c
octave:21> solve(a*x^2 + b*x + c, x)
ans = (sym 2×1 matrix)
⎡ _____________⎤
2 ⎥
⎢ b ╲╱ -4⋅a⋅c + b ⎥
⎢- ─── - ────────────────⎥
⎢ 2⋅a 2⋅a ⎥
⎢ ⎥
⎢ _____________⎥
2 ⎥
⎢ b ╲╱ -4⋅a⋅c + b ⎥
⎢- ─── + ────────────────⎥
⎣ 2⋅a 2⋅a ⎦
octave:22> help @sym/solve
'@sym/solve' is a function from the file /usr/share/octave/packages/symbolic-3.0.1/@sy
m/solve.m
-- Method on @sym: SOL = solve (EQN)
-- Method on @sym: SOL = solve (EQN, VAR)
-- Method on @sym: SOL = solve (EQN1, ..., EQNN)
-- Method on @sym: SOL = solve (EQN1, ..., EQNN, VAR1, ..., VARM)
-- Method on @sym: SOL = solve (EQNS, VARS)
-- Method on @sym: [S1, ..., SN] = solve (EQNS, VARS)
Symbolic solutions of equations, inequalities and systems.
Examples
syms x
solve(x == 2*x + 6, x)
⇒ ans = (sym) -6
solve(x^2 + 6 == 5*x, x);
sort(ans)
⇒ ans = (sym 2×1 matrix)
⎡2⎤
⎢ ⎥
⎣3⎦
Sometimes its helpful to assume an unknown is real:
syms x real
solve(abs(x) == 1, x);
sort(ans)
⇒ ans = (sym 2×1 matrix)
⎡-1⎤
⎢ ⎥
⎣1 ⎦
In general, the output will be a list of dictionaries. Each entry
of the list is one a solution, and the variables that make up that
solutions are keys of the dictionary (fieldnames of the struct).
syms x y
d = solve(x^2 == 4, x + y == 1);
% the first solution
d{1}.x
⇒ (sym) -2
d{1}.y
⇒ (sym) 3
% the second solution
d{2}.x
⇒ (sym) 2
d{2}.y
⇒ (sym) -1
But there are various special cases for the output (single versus
multiple variables, single versus multiple solutions, etc). FIXME:
provide a raw_output argument or something to always give the
general output.
Alternatively:
[X, Y] = solve(x^2 == 4, x + y == 1, x, y)
⇒ X = (sym 2×1 matrix)
⎡-2⎤
⎢ ⎥
⎣2 ⎦
⇒ Y = (sym 2×1 matrix)
⎡3 ⎤
⎢ ⎥
⎣-1⎦
You can solve inequalities and systems involving mixed inequalities
and equations. For example:
solve(x^2 == 4, x > 0)
⇒ ans = (sym) x = 2
syms x
solve(x^2 - 1 > 0, x < 10)
⇒ ans = (sym) (-∞ < x ∧ x < -1) (1 < x ∧ x < 10)
See also: @sym/eq, @sym/dsolve.
Additional help for built-in functions and operators is
available in the online version of the manual. Use the command
'doc <topic>' to search the manual index.
Help and information about Octave is also available on the WWW
at https://www.octave.org and via the help@octave.org
mailing list.
octave:23> eqs = [x + z == 14; x - z == 6]
<stdin>:7: SymPyDeprecationWarning:
non-Expr objects in a Matrix is deprecated. Matrix represents
a mathematical matrix. To represent a container of non-numeric
entities, Use a list of lists, TableForm, NumPy array, or some
other data structure instead.
See https://docs.sympy.org/latest/explanation/active-deprecations.html#deprecated-non-
expr-in-matrix
for details.
This has been deprecated since SymPy version 1.9. It
will be removed in a future version of SymPy.
eqs = (sym 2×1 matrix)
⎡x + z = 14⎤
⎢ ⎥
⎣x - z = 6 ⎦
octave:24> soln = solve(eqs, [x z])
soln =
scalar structure containing the fields:
x =
<class sym>
z =
<class sym>
octave:25> soln.x
ans = (sym) 10
octave:26> soln.z
ans = (sym) 4
octave:27> help subs
error: help: 'subs' not found
octave:28> help @sym/subs
'@sym/subs' is a function from the file /usr/share/octave/packages/symbolic-3.0.1/@sym
/subs.m
-- Method on @sym: subs (F, X, Y)
-- Method on @sym: subs (F, Y)
-- Method on @sym: subs (F)
Replace symbols in an expression with other expressions.
Example substituting a value for a variable:
syms x y
f = x*y;
subs(f, x, 2)
⇒ ans = (sym) 2⋅y
If X is omitted, symvar is called on F to determine an
appropriate variable.
X and Y can also be vectors or lists of syms to replace:
subs(f, {x y}, {sin(x) 16})
⇒ ans = (sym) 16⋅sin(x)
F = [x x*y; 2*x*y y];
subs(F, {x y}, [2 sym(pi)])
⇒ ans = (sym 2×2 matrix)
⎡ 2 2⋅π⎤
⎢ ⎥
⎣4⋅π π ⎦
With only one argument, subs(F) will attempt to find values for
each symbol in F by searching the workspace:
f = x*y
⇒ f = (sym) x⋅y
x = 42;
f
⇒ f = (sym) x⋅y
Here assigning a numerical value to the variable x did not change
the expression (because symbols are not the same as variables!)
However, we can automatically update f by calling:
subs(f)
⇒ ans = (sym) 42⋅y
*Warning*: subs cannot be easily used to substitute a double
matrix; it will cast Y to a sym. Instead, create a “function
handle” from the symbolic expression, which can be efficiently
evaluated numerically. For example:
syms x
f = exp(sin(x))
⇒ f = (sym)
sin(x)
fh = function_handle(f)
⇒ fh =
@(x) exp (sin (x))
fh(linspace(0, 2*pi, 700)')
⇒ ans =
1.0000
1.0090
1.0181
1.0273
1.0366
...
*Note*: Mixing scalars and matrices may lead to trouble. We
support the case of substituting one or more symbolic matrices in
for symbolic scalars, within a scalar expression:
f = sin(x);
g = subs(f, x, [1 sym('a'); pi sym('b')])
⇒ g = (sym 2×2 matrix)
⎡sin(1) sin(a)⎤
⎢ ⎥
⎣ 0 sin(b)⎦
When using multiple variables and matrix substitions, it may be
helpful to use cell arrays:
subs(y*sin(x), {x, y}, {3, [2 sym('a')]})
⇒ ans = (sym) [2⋅sin(3) a⋅sin(3)] (1×2 matrix)
subs(y*sin(x), {x, y}, {[2 3], [2 sym('a')]})
⇒ ans = (sym) [2⋅sin(2) a⋅sin(3)] (1×2 matrix)
*Caution*, multiple interdependent substitutions can be ambiguous
and results may depend on the order in which you specify them. A
cautionary example:
syms y(x) A B
u = y + diff(y, x)
⇒ u(x) = (symfun)
d
y(x) + ──(y(x))
dx
subs(u, {y, diff(y, x)}, {A, B})
⇒ ans = (sym) A
subs(u, {diff(y, x), y}, {B, A})
⇒ ans = (sym) A + B
Here it would be clearer to explicitly avoid the ambiguity by
calling subs twice:
subs(subs(u, diff(y, x), B), y, A)
⇒ ans = (sym) A + B
See also: @sym/symfun.
Additional help for built-in functions and operators is
available in the online version of the manual. Use the command
'doc <topic>' to search the manual index.
Help and information about Octave is also available on the WWW
at https://www.octave.org and via the help@octave.org
mailing list.
octave:29> eqn(1)
error: 'eqn' undefined near line 1, column 1
octave:30> eqs(1)
ans = (sym) x + z = 14
octave:31> subs(eqs(1), {x, z}, {soln.x, soln.z})
ans = (sym) True
octave:32> syms n
octave:33> solve(n^2 == 4, n)
ans = (sym 2×1 matrix)
⎡-2⎤
⎢ ⎥
⎣2 ⎦
octave:34> assume n positive
octave:35> assumptions
ans =
{
[1,1] = n: positive
}
octave:36> solve(n^2 == 4, n)
ans = (sym) 2
octave:37> assume n
error: assume: general algebraic assumptions are not supported
error: called from
assert at line 109 column 11
assume at line 65 column 3
octave:38> syms n
octave:39> assumptions
ans = {}(0x0)
octave:40> help @sym/assume
'@sym/assume' is a function from the file /usr/share/octave/packages/symbolic-3.0.1/@s
ym/assume.m
-- Method on @sym: X = assume (X, COND, COND2, ...)
-- Method on @sym: X = assume (X, 'clear')
-- Method on @sym: [X, Y] = assume ([X Y], ...)
-- Method on @sym: assume (X, COND, COND2, ...)
-- Method on @sym: assume (X, 'clear')
-- Method on @sym: assume ([X Y], ...)
New assumptions on a symbolic variable (replace old if any).
This function has two different behaviours depending on whether it
has an output argument or not. The first form is simpler; it
returns a new sym with assumptions given by COND, for example:
syms x
x1 = x;
x = assume(x, 'positive');
assumptions(x)
⇒ ans =
{
[1,1] = x: positive
}
assumptions(x1) % empty, x1 still has the original x
⇒ ans = {}(0x0)
Another example to help clarify:
x1 = sym('x', 'positive')
⇒ x1 = (sym) x
x2 = assume(x1, 'negative')
⇒ x2 = (sym) x
assumptions(x1)
⇒ ans =
{
[1,1] = x: positive
}
assumptions(x2)
⇒ ans =
{
[1,1] = x: negative
}
The second form—with no output argument—is different; it attempts
to find *all* instances of symbols with the same name as X and
replace them with the new version (with COND assumptions). For
example:
syms x
x1 = x;
f = sin(x);
assume(x, 'positive');
assumptions(x)
⇒ ans =
{
[1,1] = x: positive
}
assumptions(x1)
⇒ ans =
{
[1,1] = x: positive
}
assumptions(f)
⇒ ans =
{
[1,1] = x: positive
}
To clear assumptions on a variable use assume(x, 'clear'), for
example:
syms x positive
f = sin (x);
assume (x, 'clear')
isempty (assumptions (f))
⇒ ans = 1
*Warning*: the second form operates on the callers workspace via
evalin/assignin. So if you call this from other functions, it will
operate in your functions workspace (and not the base
workspace). This behaviour is for compatibility with other
symbolic toolboxes.
FIXME: idea of rewriting all sym vars is a bit of a hack, not well
tested (for example, with global vars.)
See also: @sym/assumeAlso, assume, assumptions, sym, syms.
Additional help for built-in functions and operators is
available in the online version of the manual. Use the command
'doc <topic>' to search the manual index.
Help and information about Octave is also available on the WWW
at https://www.octave.org and via the help@octave.org
mailing list.
octave:41> assume n positive
octave:42> assumptions
ans =
{
[1,1] = n: positive
}
octave:43> assume n clear
octave:44> assumptions
ans = {}(0x0)
octave:45> exp(log(x))
ans = (sym) x
octave:46> e^(log(x))
ans = (sym) x
octave:47> x + 3
ans = (sym) x + 3
octave:48> (x + 3)*(1/x + 3)
ans = (sym)
⎛ 1⎞
⎜3 + ─⎟⋅(x + 3)
⎝ x⎠
octave:49> (x + 3)*(1/(x + 3))
ans = (sym) 1
octave:50> help @sym/simplify
'@sym/simplify' is a function from the file /usr/share/octave/packages/symbolic-3.0.1/
@sym/simplify.m
-- Method on @sym: simplify (X)
Simplify an expression.
Example:
syms x
p = x^2 + x + 1
⇒ p = (sym)
2
x + x + 1
q = horner (p)
⇒ q = (sym) x⋅(x + 1) + 1
d = p - q
⇒ d = (sym)
2
x - x⋅(x + 1) + x
isAlways(p == q)
⇒ 1
simplify(p - q)
⇒ (sym) 0
Please note that simplify is not a well-defined mathematical
operation: its precise behaviour can change between software
versions (and certainly between different software packages!)
See also: @sym/isAlways, @sym/factor, @sym/expand, @sym/rewrite.
Additional help for built-in functions and operators is
available in the online version of the manual. Use the command
'doc <topic>' to search the manual index.
Help and information about Octave is also available on the WWW
at https://www.octave.org and via the help@octave.org
mailing list.
octave:51> (x + 3)^2 + (x + 3) + (x + 3)^2
ans = (sym)
2
x + 2⋅(x + 3) + 3
octave:52> simplify((x + 3)^2 + (x + 3) + (x + 3)^2)
ans = (sym)
2
x + 2⋅(x + 3) + 3
octave:53> expand((x + 3)^2 + (x + 3) + (x + 3)^2)
ans = (sym)
2
2⋅x + 13⋅x + 21
octave:54> collect((x + 3)^2 + (x + 3) + (x + 3)^2)
error: 'collect' undefined near line 1, column 1
octave:55> combine
error: 'combine' undefined near line 1, column 1
octave:56> factor
error: Invalid call to factor. Correct usage is:
-- PF = factor (Q)
-- [PF, N] = factor (Q)
Additional help for built-in functions and operators is
available in the online version of the manual. Use the command
'doc <topic>' to search the manual index.
Help and information about Octave is also available on the WWW
at https://www.octave.org and via the help@octave.org
mailing list.
octave:57> expand((x + 3)^2 + (x + 3) + (x + 3)^2)
ans = (sym)
2
2⋅x + 13⋅x + 21
octave:58> factor(ans)
ans = (sym) (x + 3)⋅(2⋅x + 7)
octave:59> partfrac
error: 'partfrac' undefined near line 1, column 1
octave:60> help @sym/partfrac
'@sym/partfrac' is a function from the file /usr/share/octave/packages/symbolic-3.0.1/
@sym/partfrac.m
-- Method on @sym: partfrac (F)
-- Method on @sym: partfrac (F, X)
Compute partial fraction decomposition of a rational function.
Examples:
syms x
f = 2/(x + 4)/(x + 1)
⇒ f = (sym)
2
───────────────
(x + 1)⋅(x + 4)
partfrac(f)
⇒ ans = (sym)
2 2
- ───────── + ─────────
3⋅(x + 4) 3⋅(x + 1)
Other examples:
syms x y
partfrac(y/(x + y)/(x + 1), x)
⇒ ans = (sym)
y y
- ─────────────── + ───────────────
(x + y)⋅(y - 1) (x + 1)⋅(y - 1)
partfrac(y/(x + y)/(x + 1), y)
⇒ ans = (sym)
x 1
- ─────────────── + ─────
(x + 1)⋅(x + y) x + 1
See also: @sym/factor.
Additional help for built-in functions and operators is
available in the online version of the manual. Use the command
'doc <topic>' to search the manual index.
Help and information about Octave is also available on the WWW
at https://www.octave.org and via the help@octave.org
mailing list.
octave:61>
octave:61>
octave:61>
octave:61>
octave:61>
octave:61> partfrac((x^7+x^2)/(x^3 - 3*x + 2))
ans = (sym)
4 2 124 25 2
x + 3⋅x - 2⋅x + 9 - ───────── + ───────── + ──────────
9⋅(x + 2) 9⋅(x - 1) 2
3⋅(x - 1)
octave:62> (x^7+x^2)/(x^3 - 3*x + 2)
ans = (sym)
7 2
x + x
────────────
3
x - 3⋅x + 2
octave:63> p = [1 2 3 4]
p =
1 2 3 4
octave:64> poly2sim(p, x)
error: 'poly2sim' undefined near line 1, column 1
octave:65> syms f(y)
octave:66> syms
Symbolic variables in current scope:
a
ans
b
c
eqs
f (symfun)
n
r
v
w
x
x_0
y
z
octave:67> f
f(y) = (symfun) f(y)
octave:68> f(y) = y^2
f(y) = (symfun)
2
y
octave:69> f
f(y) = (symfun)
2
y
octave:70> finverse
error: 'finverse' undefined near line 1, column 1
The 'finverse' function belongs to the symbolic package from Octave
Forge but has not yet been implemented.
Please read <https://www.octave.org/missing.html> to learn how you can
contribute missing functionality.
octave:71> syms t
octave:72> int(1/t, 1, x)
ans = (sym) log(x)
octave:73> int(1/t, .5, x)
warning: passing floating-point values to sym is dangerous, see "help sym"
warning: called from
double_to_sym_heuristic at line 50 column 7
sym at line 379 column 13
int at line 138 column 7
ans = (sym) log(x) + log(2)
octave:74> x^2
ans = (sym)
2
x
octave:75> x^2 + 5
ans = (sym)
2
x + 5
octave:76> diff(x^2 + 5)
ans = (sym) 2⋅x
octave:77> diff(x^2 + z^3 + 5)
ans = (sym) 2⋅x
octave:78> diff(x^2 + z^3 + 5, z)
ans = (sym)
2
3⋅z
octave:79> syms y(t) a
octave:80> diff(y) == a*y
ans = (sym)
d
──(y(t)) = a⋅y(t)
dt
octave:81> dsolve(diff(y) == a*y, t)
error: Python exception: AttributeError: 'Symbol' object has no attribute 'lhs'
occurred at line 7 of the Python code block:
ics = {ics.lhs: ics.rhs}
error: called from
pycall_sympy__ at line 179 column 7
dsolve at line 198 column 8
octave:82> dirac(x)
ans = (sym) δ(x)
octave:83> laplace(dirac(x))
ans = (sym) 1
octave:84> laplace(dirac(x - 1))
ans = (sym)
-s
octave:85> (1:5)(2)
ans = 2
octave:86>

Binary file not shown.

View File

@ -0,0 +1,183 @@
%% Symbolic Toolbox
% MATLAB is typically associated with computing *numerical* solutions
% (i.e., estimating solutions using floating point calculations), we
% may often want to compute *analytic* solutions (exact solutions,
% often represented by formulas).
%
% Wolfram Mathematica is a premier example of technical software with
% support for symbolic computation, but we can achieve many useful
% symbolic calculations in MATLAB using the *symbolic toolbox*.
%
% The symbolic toolbox is useful if you want to represent an abstract
% expression. You can think of a symbolic calculation as storing the
% structure of expressions to operate on rather than the values
% themselves.
clear; clc; close all;
%% Create symbolic variables
syms x z;
%% Creating expressions
v = x + 2;
w = x * z;
%% Substituting expressions into a symbolic expression
subs(v, x, 3);
% You can also substitute symbolic expressions, not only values.
syms r;
subs(w, z, r);
%% Solve a symbolic equation for a variable
% You may want to look at the documentation page for the `solve` function.
% If the expression cannot be solved analytically, MATLAB will default
% to using a numerical solver.
solve(x + 3 == 5, x);
syms a b c;
solve(a*x^2 + b*x + c, x);
% Solving multiple variables simultaneously
eqs = [x + z == 14, x - z == 6];
soln = solve(eqs, [x z]);
soln.x;
soln.z;
%% Set "assumptions" (constraints) on a variable
% This is the shorthand syntax for setting assumptions on symbolic objects.
% See also the `assume` function.
syms n positive;
solve(n^2 == 4, n);
%% Simplify an expression
% This attempts to simplify an expression using known
% mathematical identities.
simplify(exp(log(x)));
% See also `simplifyFraction` for more efficient simplification
% of fractions only.
%% Collect
% This collects coefficients of like terms together.
collect((x + 2) * (x + 3), x);
%% Combine
% Tries to rewrite products of powers in the expression as a single power
combine(x^4 * x^3);
% Has other options such as 'log' and 'sincos'
assume(x > 0);
combine(log(x) + log(2*x), 'log');
combine(sin(x)*cos(x), 'sincos');
%% Expand
% Similar to `collect`, but expands all variables. More or less the
% inverse of `combine`.
expand((x + 5)^3);
%% Partial fraction decomposition
partfrac((x^7+x^2)/(x^3 - 3*x + 2));
%% poly2sym and sym2poly
p = [1 2 3 4];
psym = poly2sym(p, x);
q = sym2poly(psym);
%% Symbolic functions
% Symbolic functions are like symbolic expressions but with a formal
% parameter rather than all free parameters. This may be useful for
% substituting for a symbolic variable or for differential equations.
syms f(y);
f(y) = y^2;
f(4);
%% Compose symbolic functions
syms g(y)
g(y) = sin(y);
h = compose(f, g);
%% Symbolic function inverse
f(y) = exp(y);
finverse(f)
%% Symbolic differentiation
% Note that this `diff` is different from the `diff` from before.
% This one is actually `sym.diff`.
syms x y z;
v = x^2 + 16*x + 5;
dvdx = diff(v);
dvdx_3 = subs(dvdx, x,3);
%% Partial differentiation
% This function assumes derivatives commute (i.e., second partials exist
% and are continuous).
w = -x^3 + x^2 + 3*y + 25*sin(x*y);
dwdx = diff(w, x);
dwdy = diff(w, y);
% third order derivative w.r.t. x
dw3dx3 = diff(w, x, 3);
% Vector operations exist as well such as: curl, divergence, gradient,
% laplacian, jacobian, hessian...
%% Differential equations
syms y(t) a;
dsolve(diff(y) == a*y, t);
dsolve(diff(y) == a*y, y(0) == 5); % with initial conditions
%% Symbolic integration
v = x^2 + 16*x + 5;
V = int(v);
%% Definite integral
syms a b;
Vab = int(v, a, b);
V01 = int(v, 0, 1);
%% z transform
syms a n z;
f = a^n;
ztrans(f);
%% Symbolic matrices
syms m;
n = 4;
A = m.^((0:n)'*(0:n));
D = diff(A);
%% Laplace Transform
syms t a s;
f = exp(-a*t);
laplace(f);
%% Inverse Laplace Transform
ilaplace(-4*s+8/(s^2+6*s+8));
%% Fourier Transform
f = dirac(x) + sin(x);
fourier(f);
%% Inverse Fourier Transform
syms w;
% fourier transform of cosine(t)
expr = dirac(w+1) + dirac(w-1);
ift = ifourier(expr);
simplify(ift);
%% Note: performance
syms x v;
v = x^3 + 5*x^2 - 3*x + 9;
t = 1:1e4;
tic;
X = t.^3 + 5*t.^2 - 3*t + 9;
toc;
tic;
Y = subs(v,x,t);
toc;
% Symbolic computation and data structures are relatively expensive
% when compared to numerical operations! Use sparingly!

182
lessons/lesson09/stoch.m Normal file
View File

@ -0,0 +1,182 @@
%% INTRODUCTION TO STOCHASTICITY
% Electrical engineers often use MATLAB to simulate random process, and the
% reason that it is so popular is that a lot of problems in EE are
% stochastic problems. What happens when there's random noise in a channel,
% what is the probability of corrupting a signal to the point that it
% cannot be recovered?
% Today, we are going to explore the idea of randomness with case studies.
% We are first going to show simple examples of stochastic processes, and
% will conclude with a more elaborate exploration of stochasticity in
% communication channels
clc; clear; close all;
%% EXAMPLE 1 : MONTY HALL
% The classic monty hall problem -- do you switch the door or not. The
% correct answer is you always switch. But why?? Let's find out
% Let's do a simulation to experimentally see the results, let's say there
% are two contestants, the first contestant never switches, the second
% contestant switches.
% There are different ways to do it. Let's assume that the prize is
% always behind door 3 and we choose at random which door the contestant
% chooses.
% If contestant 1 picks 3, then the contestant wins. For contestant 2, if
% the contestant chooses 3 then we choose one of the two other doors at
% random to show. If contestant 2 chose door 1 or 2, we show the
% contestant the other empty door.
N = 5e5;
choose_door = unidrnd(3,1,N);
result = zeros(2,N);
result(1, choose_door == 3) = 1;
% Inefficient but for readability. It's clear that contestant 2 has a 2/3
% success rate
for i = 1:N
if choose_door(i) == 3
choose_door(i) = unidrnd(2,1);
else
choose_door(i) = 3;
end
end
result(2, choose_door == 3) = 1;
% take the running mean
win_rate = cumsum(result, 2);
x = 1:1:N;
win_rate = win_rate ./ [x;x];
%% Plotting the results of example 1
figure;
hold on;
plot(x, win_rate(1,:), 'DisplayName', 'no switch');
plot(x, win_rate(2,:), 'DisplayName', 'switch');
hold off;
legend show;
title 'Monty Hall Problem Simulation Results';
%% EXAMPLE 2 : CASINO
% A casino offers a game in which a fair coin is tossed repeatedly until
% the first heads comes up, for a total of k+1 tosses. The casino will pay
% out k dollars
% Let's see how much money you are going to get if you play the game
N = 5e5;
num_tosses = zeros(1,N);
for i = 1:N
res = randi([0,1]);
while (res ~= 0)
num_tosses(i) = num_tosses(i) + 1;
res = randi([0,1]);
end
end
figure;
hold on;
histogram(num_tosses, unique(num_tosses));
hold off;
xlabel Frequency;
ylabel Winnings;
%% Radar/Signal Detection Example
N = 10000;
i = 1:N;
rdm = rand(1,N);
X = rdm > 0.5; % Signal: 0 or 1 equiprobable
N = randn(1,N); % Noise: standard normal
Y = X + N; % Recieved
% For each observation, either the sample comes from N(0,1) or N(1,1)
% To guess if the true signal for each observation, x_i is 0 or 1 we
% compute P[true = 0 | x_i] and P[true = 1 | x_i] and choose the larger
% one.
% By Bayes' Law,
% P[x_i | true = S]*P[true = S]
% P[true = S | x_i] = ----------------------------- , S = 0,1
% P[x_i]
% Since P[x_i] is common to both P[true = 0 | x_i] and P[true = 1 | x_i],
% we only have to maximize the numerator. Also since
% P[true = 0] = P[true = 1], we need to maximize P[x_i | true = S], S = 0,1
%% Showing the decision boundary visually
x = -5:0.001:5;
figure;
plot(x, [normpdf(x,0,1); normpdf(x,1,1)]);
xline(0.5, '--');
legend 'Sent 0', 'Sent 1';
xlabel 'Received value';
ylabel 'Likelihood';
%% Modeling the distribution boundary
prob0 = normpdf(Y, 0, 1);
prob1 = normpdf(Y, 1, 1);
decision = prob1 > prob0;
result = decision == X;
figure;
plot(i, cumsum(result)./i);
xlabel 'Number of Observations';
ylabel 'Percent Correct';
title 'Signal Detection';
%%
% What happens if the prior probabilities are not equal?
%
% If the priors are known, then we can multiply them to the probabilities
% we used earlier according to Bayes' Law. This technique is called MAP
% (Maximum a posteriori) estimation.
%
% But if the priors are NOT known, then we can assume equiprobable and use
% the same technique as before. This technique is called ML (Maximum
% likelihood) estimation. Clearly this performs worse than MAP if the
% priors are not equal, i.e., the equiprobable assumption is false.
P0 = 0.8;
X = rdm > P0; % Now the signal is 1 with probability 0.2
Y = X + N;
%% Graphing this new problem
figure;
subplot(211);
plot(x, [normpdf(x,0,1); normpdf(x,1,1)]);
xline(0.5, '--');
title ML;
xlabel 'Received value';
ylabel 'Likelihood';
subplot(212);
plot(x, [normpdf(x,0,1)*P0; normpdf(x,1,1)*(1 - P0)]);
xline(0.5 + log(P0/(1-P0)), '--');
title 'MAP';
xlabel 'Received value';
ylabel 'Likelihood';
%% MAP decision rule
% Now we include the priors
prob0MAP = normpdf(Y, 0, 1) * P0;
prob1MAP = normpdf(Y, 1, 1) * (1 - P0);
decisionMAP = prob1MAP > prob0MAP;
resultML = decision == X; % previous example was ML
resultMAP = decisionMAP == X; % current MAP estimate
figure;
plot(i, [cumsum(resultML)./i; cumsum(resultMAP)./i]);
xlabel 'Number of Observations';
ylabel 'Percent Correct';
title 'Signal Detection: MAP vs. ML';
legend ML MAP;

256
lessons/lesson10/chaos.m Normal file
View File

@ -0,0 +1,256 @@
%% Lesson 10, extra -- Chaos!
% Based on work for PH429: Chaos & Nonlinear Dynamics. The following was
% translated from the original NumPy/Matplotlib code. See Strogatz' Nonlinear
% Dynamics and Chaos (the source for much of this information) if you want to
% know more!
close all; clear; clc;
% Simple systems of nonlinear differential equations (also iterated nonlinear
% maps) often exhibit surprisingly complex behavior. Lorenz's "strange
% attractor," discovered in 1963, was an example of this: he discovered that an
% exceedingly simplified (and entirely deterministic!) model of the weather was
% still able to produce unpredictable fluctuations in temperature, wind speed,
% etc. -- the system exponentially amplified miniscule parameter changes, so
% every decimal place mattered. Further work with analog computers and the
% then-emerging digital computers led to the field we now call chaos theory.
% Chaos has much to do with fractal geometry, so we'll start by generating a
% few fractals. Because... why not?
%% The Chaos Game & Sierpinski Triangles
% The game is simple:
% 1. Place three vertices in the plane, corresponding to the vertices of an
% equilateral triangle.
% 2. Randomly choose a point P(0).
% 3. Each turn, choose a random vertex, and plot a point P(n) halfway between
% that vertex and point P(n - 1).
% Let's see what happens.
n1 = 5e5; % points
vertices = [0, 0; .5, .5*sqrt(3); 1, 0];
r = .5; % fraction of the way between points and vertices (here halfway)
% point coordinates
points = zeros(n1, 2);
choices = randi([1 3], n1, 1);
% randomly choose the first point somewhere in the plane
points(1, :) = 100*randn(1, 2);
% choose the rest
% note: the loop here is actually necessary, like it was in G-S -- each
% iteration depends upon the previous one.
for i = 2:n1
choice = choices(i);
vertex = vertices(choice, :);
last_point = points(i - 1, :);
points(i, :) = last_point + r*(vertex - last_point);
end
% plot the thing
figure;
scatter(points(:, 1), points(:, 2), 1);
xlim([-.1 1.1]);
ylim([-.2 1]);
xticks([]);
yticks([]);
pbaspect([1 1 1]); % make the plot box square
title('The Sierpinski Triangle, by Chance', 'Interpreter', 'latex');
% A rather important property of fractals is their fractional dimension -- this
% triangle, for example, is not quite two-dimensional but is clearly more than
% one-dimensional. So how do we measure this dimension?
% One simple measure, known as self-similarity dimension, is relatively easy to
% find for the Sierpinski triangle. The idea is we simply examine how many
% smaller versions of a given shape could fit into that shape, and what size
% they would be in relation. For example, a square with scale 1 can be made up
% of 4 smaller squares scaled by 1/2, or 9 smaller squares with scale 1/3:
% ----------------- -----------------
% | | | | |
% | | | 1/2 | 1/2 |
% | | | | |
% | 1 | = |-------|-------|
% | | | | |
% | | | 1/2 | 1/2 |
% | | | | |
% ----------------- -----------------
% A square thus has self-similarity dimension log4 = log9 = 2 (as one might
% expect). The Sierpinski triangle is composed of 3 copies of itself scaled by
% 1/2, and thus has self-similarity dimension log3 1.585.
% I wonder if we could have MATLAB calculate these...
%% Iterated Maps
% One way to create chaotic behavior is to iterate a nonlinear map: e.g., plot
% the set {x, sin(x), sin(sin(x)), sin(sin(sin(x))), ...}. The values will
% generally hop unpredictably around, but will often stay closer to some values
% than others...
% The following plot is a visual representation of these iterations, called a
% cobweb. Cobwebs are often used to qualitatively analyze nonlinear maps. The
% idea is, since the output of the map will be fed back into the input, we plot
% a point on the map's curve, translate horizontally to the line y = x, then
% translate vertically back to the map and repeat. This gives a visual
% representation of plugging the output back into the input.
% When you see this, think about which points on the map will "attract" the
% cobweb, which will "repel" it, and how one might go about making that
% distinction.
n2 = 10;
map = @(x) 2*sin(x);
% create the map curve and the center line
x = linspace(0, pi, 100).';
y_map = map(x);
y_line = x;
% create the cobweb
map_pts = zeros(2*n2 + 1, 2);
map_pts(1, :) = [.2, 0];
for i = 1:n2
last_pt = map_pts(2*i - 1, :);
mapped = [last_pt(1), map(last_pt(1))];
on_the_line = [mapped(2), mapped(2)];
map_pts(2*i, :) = mapped;
map_pts(2*i + 1, :) = on_the_line;
end
% plot it
figure;
hold on;
plot(x, y_map, 'b');
plot(x, y_line, 'k');
plot(map_pts(:, 1), map_pts(:, 2), 'r');
start = map_pts(1, :);
scatter(start(1), start(2), 'r');
text(start(1) + .03, start(2) + .03, 'Start Point');
xlim([0 pi]);
xticks([0 pi/2 pi]);
ylim([0 2.1]);
xticklabels({'0', '\pi/2', '\pi'});
title('Cobweb of \(2 \sin x\)', 'Interpreter', 'latex');
%% Orbit Diagrams
% The above example was... not too crazy. The map x α sin x *can* exhibit
% more complex behavior, but it requires α to be greater than π (so that we can
% escape the [0, π] interval). The map will first stay close to two points,
% then a few, then... altogether too many. This is usually plotted with what is
% called an orbit diagram, showing roughly how much time the map spends at
% certain values for a given α.
map_alpha = @(alpha, x) alpha.*sin(x);
n3 = 6e2; % iterations to go through
frames = 9e2; % run this many parallel alpha computations
toss = 2e2; % delete this many points from the start
min_alpha = 2.2;
max_alpha = 3.1;
alphas = linspace(min_alpha, max_alpha, frames);
% at least we can run the frames in parallel...
values = zeros(n3, frames);
values(1, :) = pi/4; % the first input each time
for i = 2:n3
values(i, :) = map_alpha(alphas, values(i - 1, :));
end
% plot this crazy thing
values = values((toss + 1):end, :);
figure;
scatter(alphas.', values, 1, [.7 0 0], 'MarkerEdgeAlpha', .3);
title('Orbit of \(\alpha \sin x\)', 'Interpreter', 'latex');
xlabel('\alpha');
ylabel('map value');
%% The Phase Plane
% In continuous time, we have differential equations rather than iterated maps.
% One way to analyze higher-order equations is using the so-called phase plane,
% which is a plot of our state variable and its derivative. The idea is that a
% second-order differential equation really acts like a system in two
% dimensions, and is best analyzed directly as such.
% We'll analyze the motion of an damped pendulum, which has the governing
% equation d²θ/dt² + b dθ/dt + (g/L) sin θ = 0. For simplicity (it won't change
% the qualitative behavior), we'll let g/L = 1. Then (the phase plane bit)
% we break this into two differential equations,
% * dθ/dt = ω and
% * dω/dt = -(sin θ + bω),
% and make a plot of the *vector* (dθ/dt, dω/dt) in θ-ω space. We can easily
% plot the vector field with `quiver`, and MATLAB's `streamline` is rather
% effective at plotting either single trajectories or a whole suite of possible
% solutions.
b = .2;
min_theta = -3*pi;
max_theta = 3*pi;
min_omega = -3*pi;
max_omega = 3*pi;
theta_range = linspace(min_theta, max_theta, 300);
omega_range = linspace(min_omega, max_omega, 200);
[theta, omega] = meshgrid(theta_range, omega_range);
theta_dot = omega;
omega_dot = -(sin(theta) + b*omega);
% to cut down on the # of points we plot
d = 10;
[sparse_x, sparse_y] = ...
meshgrid(d:d:length(theta_range), d:d:length(omega_range));
sparse = sub2ind(size(theta), sparse_y(:), sparse_x(:));
% plot this thing
figure;
hold on;
quiver(theta(sparse), omega(sparse), ...
theta_dot(sparse), omega_dot(sparse), 'm');
streamline(theta, omega, theta_dot, omega_dot, ...
theta(sparse_y, [1 end]), omega(sparse_y, [1 end]));
xlim([min_theta max_theta]);
xticks(linspace(min_theta, max_theta, 7));
ylim([min_omega max_omega]);
xlabel('pendulum angle');
ylabel('angular velocity');
title('Behavior of a Damped Pendulum', 'Interpreter', 'latex');
%% Strange Attractors
% I won't go into detail here -- suffice it to say the behavior of this system
% would be quite opaque without numerical integration. Fortunately, we have
% just that! Lorenz managed to prove analytically that this system had no
% closed cycles and yet all its trajectories eventually stayed within a bounded
% region of space, but beyond that... well, we'll see.
sigma = 10;
r = 28;
b = 8/3;
x_dot = @(x, y, z) sigma*(y - x);
y_dot = @(x, y, z) r*x - y - x.*z;
z_dot = @(x, y, z) x.*y - b*z;
[x, y, z] = meshgrid(linspace(-50, 50, 100));
u = x_dot(x, y, z);
v = y_dot(x, y, z);
w = z_dot(x, y, z);
figure;
hold on;
streamline(x, y, z, u, v, w, 0, 1, 0, [.1 2e4]);
scatter3(0, 1, 0);
view(3);
grid on;
text(0, 0, -2, 'Start Point');
xlabel('x');
ylabel('y');
zlabel('z');
title("Lorenz's Strange Attractor", 'Interpreter', 'latex');