%% Getting Started with MATLAB (18-491/18-691)
%  Carlos Taveras
%  1/30/2021

% If you are a beginner to MATLAB, this tutorial aims to help get you
% accustomed to some of the commands that you will have to use on the
% computer problems in this course. Feel free to play around with this
% script. Also feel free to post any MATLAB related questions you may have
% on Piazza.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% Two equivalent ways of defining linearly spaced row vectors
lower = -5; upper = 5; numPoints = 101; 
spacing = (upper-lower)/(numPoints-1);

n1 = (linspace(lower, upper, numPoints));
n2 = (lower:spacing:upper);

% Transpose row vectors to column vectors
n1 = n1'; n2 = n2';
%% Vector/Matrix Manipulation and Common Operations

% Create matrix by joining vectors
M1 = [n1 n2];

% Create column vector by abutting several column vectors
nLong = [n1; n2];

% Inner (dot) product:
inner = n1' * n2;

% Outer product:
outer = n1 * n2';

% Element-wise multiplication (also called a Hadamard Product)
prod = n1 .* n2;

% Caution: Whenever using element-wise operations, ensure that the
% dimensions of your vectors/matrices match up. A common type of error that
% can arise from this kind of dimension mismatch is when you element-wise
% multiply a row vector with a column vector. This will result in a
% matrix (the outer product in fact), instead of a vector as desired.

badMult = n1 .* n2'; % outer product not element-wise multiplication,

% Note: Choose a vector convention and stick with it! Also, use of certain 
% MATLAB functions may result in a change in the orientation of your 
% vectors which will affect calculations down the line. It is worthwile to
% read through the help files of functions you are unfamilar with for
% information like the set of possible inputs and outputs along with their
% respective dimensions.

% Functions you may want to keep in mind for later:
% help freqz, help roots, help residuez


% Initialize zero matrix/vector:
zeroVec = zeros(numPoints, 1); % zero column vector
zeroMat = zeros(numPoints); % zero square matrix 

% Initialize ones matrix/vector:
onesVec = ones(numPoints, 1); % ones column vector
onesMat = ones(numPoints); % ones square matrix


%% Common functions and Plotting

n = (-100:100)';
% We can define exponential functions using exp (base e):
exp1 = exp(n);

% Or equivalently using element wise exponentiation:
exp2 = exp(1).^(n);

% We frequently use complex exponentials in this course, which we can
% define like so:
frequency = pi/25;
cExp1 = exp(1i * frequency * n); % where 1i = j = sqrt(-1)

% Using Euler's formula, we can also define complex exponentials like this:
cExp2 = cos(pi*n) + 1i * sin(pi*n);

% To extract the real and imaginary parts of a complex number,
% respectively, we can do the following:
cExpReal = real(cExp1);
cExpImag = imag(cExp1);

% Let's plot the real and imaginary parts of the complex exponential we
% defined:
figure; subplot(311);
stem(n, cExpReal);
title("Real Part"); 
xlabel("n");
ylabel("Amplitude");

subplot(312); 
stem(n, cExpImag);
title("Imaginary Part"); 
xlabel("n");
ylabel("Amplitude");

% We can also plot several functions on the same grid:
subplot(313); hold on; 
title("Real and Imaginary parts of complex exponential")
stem(n, cExpReal);
stem(n, cExpImag);
legend("Real", "Imaginary");
xlabel("n");
ylabel("Amplitude");
hold off;

% Complex numbers are also commonly characterized by their magnitude and
% phase:
cExpMag = abs(cExp1); % Magnitude
cExpPhase = angle(cExp1); % Phase

figure; 
subplot(211);
stem(n, cExpMag);
title("Magnitude of Complex Exponential"); 
xlabel("n");
ylabel("Magnitude");
ylim([-0.5 1.5])

subplot(212); 
stem(n, cExpPhase/pi);
title("Wrapped Phase of Complex Exponential"); 
xlabel("n");
ylabel("Phase in Normalized Frequency (\omega/\pi)");

% Step functions and one-sided exponentials will also be used extensively: 
stepFunc = @(x) x >= 0; % Anonymous function
decay = 0.05;
sidedExp = exp(-decay*n) .* stepFunc(n);

figure; hold on;
stem(n, stepFunc(n));
stem(n, sidedExp);
hold off;
title("Step Function and One-sided Exponential");
xlabel("n");
ylabel("Amplitude");
legend("Step Function", "One-sided Exponential");
ylim([-0.5 1.5])

%% Convolution and Frequency Response
f1 = 20;
box = stepFunc(n) - stepFunc(n-20); % a[n] = u[n] - u[n-20]
sinc1 = sinc(n/f1);                 % b[n] = f1 * ( sin(pi/f1 n) / (pi n) )
y = conv(box, sinc1, 'full');       % y[n] = a[n] * b[n] 

[H1, F1] = freqz(box, 1);           % A(e^jw)
[H2, F2] = freqz(sinc1, 1);         % B(e^jw)
[H3, F3] = freqz(y, 1);             % Y(e^jw) = A(e^jw)B(e^jw)

figure;
subplot(311);
stem(n, box);
xlabel('n','fontsize', 12);
ylabel('a[n]','fontsize', 12);
title('Box Function','fontweight','bold','fontsize', 12);

subplot(312);
stem(n, sinc1);
xlabel('n','fontsize', 12);
ylabel('b[n]','fontsize', 12);
title('Sinc Function','fontweight','bold','fontsize', 12);

% Length of conv 'full' is N + M - 1 where N = len(a[n]), M = len(b[n])
nConv = (-(length(y)-1)/2:(length(y)-1)/2)';

subplot(313);
stem(nConv, y);
xlabel('n','fontsize', 12);
ylabel('y[n]','fontsize', 12);
title('Sinc Convolved With Box','fontweight','bold','fontsize', 12);

figure;
subplot(411);
plot(F1/pi, abs(H1), 'LineWidth', 2);
ylabel('|A(e^{j\omega})|','fontsize', 12);
xlabel('Normalized Frequency (\omega/\pi)','fontsize', 12);
title('Frequency Reponse of Box', 'fontsize', 12);

subplot(412);
plot(F2/pi, abs(H2), 'LineWidth', 2);
ylabel('|B(e^{j\omega})|','fontsize', 12);
xlabel('Normalized Frequency (\omega/\pi)','fontsize', 12);
title('Frequency Response of Sinc', 'fontsize', 12);


subplot(413);
plot(F2/pi, abs(H1.*H2), 'LineWidth', 2);
ylabel('|A(e^{j\omega})B(e^{j\omega})|','fontsize', 12);
xlabel('Normalized Frequency (\omega/\pi)','fontsize', 12);
title('Product of Frequency Responses', 'fontsize', 12);


subplot(414);
plot(F3/pi, abs(H3), 'LineWidth', 2);
ylabel('|Y(e^{j\omega})|','fontsize', 12);
xlabel('Normalized Frequency (\omega/\pi)','fontsize', 12);
title('Frequency Response of Sinc Convolved w/ Box', 'fontsize', 12);

%% Defining Functions

% There several ways to define functions in MATLAB. One way is to create a
% dedicated file for that particular function which will have the same name
% as the function. This is done most easily by creating a new function file
% by right clicking on your current folder, scrolling to New then to
% function.

% If you want to keep all of your code on a single script, you can define
% helper functions at the end of your script. These functions will only be
% defined in the scope of your script, though, so if it is a function you
% plan on reusing often, you may want to define it in its own file.

% Finally, you can use what are called an anonymous functions to define
% short, one-liners. These functions are usually used to make your code
% more modular and improve its readability. The step function defined in
% common functions and plotting is an example.

f();

function [greatCourse] = f()

greatCourse = "18-491/18-691";
fprintf("We hope you enjoy %s!\n", greatCourse);

end

