matlab: matlab is proprietary product of Mathworks. 1st version was released in 1984. It's full form is matrix laboratory, as it primarily dealt with matrix computations. MATLAB allows matrix manipulations, plotting of functions and data in 2D/3D, implementation of algorithms, interfacing with programs written in other languages, including C, Python, etc. Although MATLAB is intended primarily for numerical computing, an additional package Simulink, adds graphical multi-domain simulation. We learn matlab since we'll be using it a lot in signal processing, image/video processing, etc.

One of the best places to learn basic Matlab is from here: https://www.tutorialspoint.com/matlab/index.htm

Other useful resource is from matlab user uide or usinh help section of matlab product (click on help->Product_help on top bar after invoking matlab).

Invoking matlab: matlab needs to be installed on your m/c, before you can run it. Usually corporations/universities have licenses of Matlab, so you can use them there. Buying Matlab is expensive, isntead use open source equivalent.I'm presenting Matlab tutorial, since matlab syntax and feel is available in GNU Octave, which is open source equiv of Matlab. So, learning of Matlab can be used in Octave.


matlab -R2016a => starts matlab with version = R2016a. Every year matlab releases 2 versions a and b. Latest release is R2019a.
*.m file are matlab cmd files that can be run from cmdline in matlab. These are scripts that contain all matlab cmds.
ex: matlab_cmd1.m => just type matlab_cmd1 (without .m extension) on prompt of matlab
ex: matlab -nodisplay < cmd1.m => to run cmd1.m without opening gui

After starting matlab, we can start typing cmds on matlab command window. It has >> prompt for entering any cmds.

There is also a "workspace" window on top right, and "Command History" window on bottom right. Workspace window shows all var, while history window shows all cmds entered so far on prompt.

Matlab syntax:

spaces: Matlab is insensitive to spaces. It can parse code correctly even w/o spaces. spaces are not required b/w operators, but added for clarity.

comments: To comment out single line, use %. To comment out multiple lines use:
%{
 .... code ....
%}

format: format cmd changes precision of numbers. i.e format short;

Data types: Matlab is loosely typed, meaning we don't need to define dta type, matlab figures it out automatically.

1. Boolean: true(1) or false (0)

2. Numeric: Integer (signed/unsigned), floating point (single precision and double precision)

3. Text: char/string. string composed of array of char.

variables: A valid variable name starts with a letter, followed by letters, digits, or underscores. MATLAB is case sensitive, so A and a are not the same variable. In Matlab, all vars are arrays, and numeric var are of type double (i.e double precision).

>> a=1; => assigns value of 1 to var "a". If ";" not used at end of cmd, then results are displayed in cmd window (i.e a=1 will be displayed in cmd window). "a" is 1x1 array (array with 1 row and 1 column).  

>>5 => any cmd that returns an o/p val that is not assigned to a var, is assigned to reserved var "ans" (i.e answer). So, in this case, ans is assigned 5.

>> whos a => "whos" on any var shows it's attributes. here it shows "a" as 1x1 array of type "double". It shows 8 bytes are used to store this array "a" (since double precision requires 8 bytes). Just "whos" w/o any var will show info for all var.

>> B = [12, 62, 93, -8, 22; 16, 2, 87, 43, 91; -4, 17, -72, 95, 6] => creates 3x5 array (3 rows x 5 columns). Each row has 5 values. ; indicates end of row. After last row, no ; needed. [ ] indicates it's an array.

To get element from 2nd row, 3rd col of an array, we do B(2,3). NOTE: arrays are defined with square brackets, but accessed via round brackets. Curly brackets {} are 3rd kind of brackets used for creating cell array (explained later).

>> A=magic(5); => creates a 5x5 array with random entries in it.

>> C = [1,2,3] => an array with 1 row and 3 columns. C=[1;2;3] creates an array with 3 rows and 1 column.

>> Mystring = 'hello world'; => strings are char array of 1 row x n cols. single quotes used to store strings. Each char stored in 2 bytes, so this char array of 1x11 stored in 22 bytes.

>> A=ones(5)*4.7, B=magic(5); C=A/B; => multiple cmds can be entered on same line separated by , or ;. Commands that end with a comma display their results, while commands that end with a semicolon do not.

>> s= 1 -1/2 + ...

0.2 => gives result as 0.7. ellipses (...) allow continuation of stmt to next line

cell array: A cell array is a data type with indexed data containers called cells, where each cell can contain any type of data. Cell arrays commonly contain either lists of text, combinations of text and numbers, or numeric arrays of different sizes. Refer to sets of cells by enclosing indices in smooth parentheses (). Access the contents of cells by indexing with curly braces {}

ex: mycell = {'Mary', [3], 'summer', true}. To extract contents of mycell, we use {}. eg. mycell{1} gives Mary, mycell{2} or mycell{1,2} gives 3 and so on. When we use round brackets, we get cell array which is subset of cell array. i.e mycell(1) gives 'Mary' which is a 1x1 array, mycell(2) or mycell(1,2) gives [17] which is again 1x1 array, etc. NOTE: with curly braces, we got extracted values w/o any '..', or [..].

cell(3) => creates a 3x3 cell array of empty matrices.

cell arrays are very useful to store diff kind of data and then to access them in a loop to process them.

operators: 3 types of main operators:

1. Arithmetic operators: to perform numeric computations. +, -, .*(numeric multiplication), ./(numeric right division), .\(numeric left division), .^(numeric power), *(matrix multiplication), /(matrix right division), \(matrix left division), ^(matrix power), etc. Both operands must have same dimension. If one operand is scalar and the other is not, then MATLAB applies the scalar to every element of the other operand—this property is known as scalar expansion. right division (/ or ./) refers to regular division i.e if A=2, B=3, then A/B or A./B = 0.6667. left division (\ or .\) refers to inverted division - A\B or A.\B = B/A = 3/2 =1.5.

2. Relational operators: to compare operands. <, >, ==(equal to), ~=(not equal to), etc. Both operands must have same dimension. operation is applied to each element, and result is for each element, as o(false) or 1 (true). If one operand is scalar and the other is not, then MATLAB applies the scalar against every element of the other operand.

3. logical operators: these can be applied bit-wise, element wise or short circuit. &, |, ~, xor (i.e xor(A,B))

4. Assignment operator: = is an assignment operator as seen above.

5. colon operator (:) => most useful operator of matlab.

>>1:10 => creates a row vector, containing integers from 1 to 10, ans = [1 2 .... 10]

>>x=0:0.2:10 => creates an array with 1 row and 50 columns, with value of x going from 0 to 10 in crements of 0.2, i.e x=[0 0.2 0.4 0.8 .... 50]

: operator within round brackets used to extract specific rows/column entries from arrays. ex:

>> a(:,2) => extracts 2nd col of an array. This col retains it's structure, i.e final result is array with n rows and 1 column

>> a(3,:) => extracts 3rd row of an array. This row retains it's structure, i.e final result is array with 1 row and n columns

>> a(:,2:3) => extracts second and third column of array. final result is array with n rows and 2 columns

>> a(2:3,2:3) => extracts second and third rows and second and third columns. final result is array with 2 rows and 2 columns

Conditional Stmt: All conditional stmt end with keyword "end". 3 kinds:

1. if stmt => optional "elseif" "else" can also be used

ex: if a<30 disp 'small'; else disp 'large'; end => We should write it in multiple lines. If we write all of it in 1 line, we'll need ; to separate out multiple lines of "if"

2. case stmt: switch ..case ... end.

3. for loop => to loop specific num of times

ex: for n=2:6 x(n)=x(n-1); end => repeats with n=2,3,4,5,6

4. while loop => loops as long as condition is true. break (to exit) and continue (to skip to next iteration) stmt can be used from inside while loop.

ex: while fact<100 n=n+1;...; end

functions: can be called by typing name of func with appr args inside round brackets.

>> maxA = max(A,B); here max func is called with args A and B, both of which are arrays. o/p stored in var MaxA. If func returns more than 1 o/p, then we can store them by assigning them to separate var

>> helpFile = which('help');
>> [helpPath,name,ext] = fileparts(helpFile); => here fileparts func returns 3 o/p. We store them in 3 different var. To save memory space, we may want to ignore storing some o/p. We can do that by assigning ~ to that o/p. i.e [~,~,ext] = fileparts(helpFile);

Date functions => "date", "now", "calender", etc func display current date, etc.

import/export functions => to import/export data from external files.

1. importdata func: ex: filename = 'smile.jpg'; A = importdata(filename); image(A); => imports image file and then displays image in window

2. save func: ex: save my_data.out num_array -ascii => my_data.out is the delimited ASCII o/p data file created, num_array is i/p numeric array and −ascii is the specifier.

3. saveas: saveas(gcf,"plot_tmp"); saves graph generated as "plot_tmp".

misc functions:

1. ones, zeros: returns 1 or 0.

ex: y=ones; => returns scalar 1.

ex: y=ones(5); => returns 5x5 matrix with all entries as 1. We could also write it as y=ones(5,5);

ex: y=zeros(2,3) => returns 2x3 array of 0


print/display functions =>


1A. disp(x) => display value of any var (array, string, etc).
ex: A[10 20]; S='Hello'; name='alice', age=12; S=['my name', name,'age',num2str(age)]; => everything in S needs to be string
    disp(A); disp(S); disp('Hello'); => When arg of any function is a text string, we enclose it in single quotes ' ... '. disp 'hello' => is equally valid as we can use cmd syntax instead of func syntax.

1B. sprintf => used to create text. can be stored in a var.
ex: name='alice', age=12; S=sprintf('my name %s age %d', name,age);
    disp(S);

1C. fprintf => used to directly display the text without creating a variable. Always put \n at end. fscanf/fprintf works like C scanf/printf cmds.
ex: fprintf('my name %s age %d \n', name,age); => directly displays this without needing disp

Ploting: Ploting 2D/3D graphs is the most useful feature in Matlab, and used a lot.

1. plot: plot(x,y) plots y against x

ex: x = [-100:5:100]; y = x.^2; plot(x, y) => this plots 2D graph with y=x^2 on y axis and x from -100 to +100 (in increments of 5) on x axis. If increment reduced to 1, then graph becomes smoother as there are more points.

We can add title, labels along the x-axis and y-axis, grid lines and also to adjust the axes to spruce up the graph.

plot(x, y), xlabel('x'), ylabel('x^2'), title('sqaure Graph'), grid on, axis equal, axis ([-20, 20, 0,400]); => this plots x,y graph with label on x axis (as x), y axis (as y^2) and then a title on top of graph. It also adds grid lines on graph. "axis equal" causes equal spacing on both x and y axis (i.e linear plot). axis ([...]) sets min/max values for x,y axis. Here, xmin=-20, xmax=+20, ymin=0, ymax=400.

To plot multiple graphs on same plot, do plot(x1,y1, x2,y2, ...). ex: y = sin(x); g = cos(x); plot(x, y, x, g);

To have separate colors for each graph, add attr in plot(x,y, attr). For color attr, use r=red, g=green, b=blue, w=white, k=black, etc. ex: plot(x, y, 'r', x, g, 'g'); For diif line style, do: plot(x, y1, 'r', x, y2, 'b--o'); => creates lines as --o--o--o--

We can also have legends for graph (using legend cmd). We can print text on graph using text cmd

ex: text(10,-50, 'my custome text'); => prints the given text at x=10,y=-50 on graph. NOTE: x,y are coords in whatever unit is there on axis. If x is in freq(log scale) and y is in db, then x=10Hz,y=-50db is where the text printing starts.

ex: plot(y); => plots data in y verses index of each value. If y is a vector, then the x-axis scale ranges from 1 to length(y). ex:

subplot: With same figure, we can have various plots called subplots. We specify positions of various subplots using subplot cmd. First, specify subplot position for 1st graph, using subplot, then use plot(x,y) to plot 1st graph, then specify position for 2nd graph using subplot, then use plot(x,y) to plot 2nd graph, and so on ...

2. Bar: bar(x,y) plots bar chart for y against x.

3. Contour: A contour line of a function of two variables is a curve along which the function has a constant value. To draw contour map for given func g=f(x,y), first we need to create a meshgrid which defines a set of (x,y) points over domain of func. meshgrid defines x,y range over which we plot function g. Then, we use contour func: contour(x,y,g);

4. surf: Used to create 3D surface plot. Instead of contour, we draw 3D plot of func g=f(x,y). Here again we create meshgrid, then use surf func.

ex: [x,y] = meshgrid(-2:.2:2, -3:0.1:3); g = x .* exp(-x.^2 - y.^2); surf(x, y, g); => Here, func g is plotted on z axis. range of x is from -2 to +2, while y is -3 to +3.

5. ezplot: plot a given func, over range of values specified

ex: ezplot('x^2',[-1,2]) => plots square of x, over range of x=-1 to x=2.

ex: ezplot('x^2 - y^4') => plots x^2-y^4=0 over range x,y=-2Π to +2Π. This is the default range, when range is not specified.

Solving Equations: matlab can solve polynomial eqns using solve func:

ex: solve('(x-3)^2*(x-7)=0') => This solves the cubic eqn, and produces result as ans=[3; 3; 7] = 3x1 array. "=0" iin eqn s optional, as it's understood.

ex: eq = 'y^4 - 7*y^3 + 3*y^2 - 5*y + 9 = 0'; s = solve(eq,'y'); Now s becomes a 4x1 array. Each root can be accessed via s(0), s(1), s(2) and s(3), or as an array s. By default, eqn is solved for x, but to solve for other var, specify that var "y" in solve func.

We can also solve system of eqn.

ex: s = solve('5*x + 9*y = 5','3*x - 6*y = 4'); s.x; s.y; => displays soln for x,y

Calculus: Calc limit, solve differential/integral.

1. limit func: Calculates limit of func. The limit function falls in the realm of symbolic computing. Symbolic computing means using symbols as "x", etc in the o/p instead of getting numerical results. You need to use the syms function to tell MATLAB which symbolic variables you are using. You will get an error, if the function expects symbolic values, and you omit "syms" func for that var.

ex: syms x; limit((x^3 + 5)/(x^4 + 7),2); => 1st arg of limit func is the function, and 2nd arg is what the variable tends to i.e limit x-> a. Here we calc limit for this func, as x approaches 2. If 2nd arg not given, it's assumed to be 0.

2. differential: compute symbolic derivative using func diff().

ex: syms t; f = 3*t^2 + 2*t^(-2); diff(f,2); => this gives derivative as "6 - 12/t^2" (in symbols instead of numerical value). 2nd arg "2" in diff implies 2nd derivative (F''). If 2nd arg not provided, it's assumed to be 1 (1st derivative, F').

We can solve diff eqn symbolically using dsolve. ex: dsolve('D2y - y = 0','y(0) = -1','Dy(0) = 2')

3. integral: inverse of differentiation. "int" cmd calculates indefinite integral of any expression

ex: syms x; int(2*x); => this returns integral as x^2, though in reality integral is x^2+c, where c is arbitrary constant

ex: int(2*x,4,9) => This calculates definite integral with low limit=4, and hi limit=9. Since this yields numerical result, and not in symbols, we don't define x as symbol (i.e syms x; not used here)

Polynomial: To evaluate polynomial at any value, we use polyval func

ex: p = [1 7 0 -5 9]; polyval(p,4); Here p is defined as an array. When used inside polyval func, it represents polynomial P(x)=x^4+7*x^3-5*x+9. It's value is evaluated at x=4, which yields 693.

polyvalm evaluates matrix polynomial.

roots func calculates roots of poly. ex: p = [1 7 0 -5 9]; r = roots(p) => calc 4 roots of the poly eqn, and stores in var "r"

poly func => inverse of roots func, and returns polynomial coefficients

polyfit func => finds coeff of polynomial that fits a set of data in least square sense. We provide numerical values, x and y=f(x), and try to get poly func with max degree "n" that fits y over given values of x.

ex: x = [1 2 3 4 5 6]; y = [5.5 43.1 128 290.7 498.4 978.67]; p = polyfit(x,y,4); => here we ask matlab for poly with max degree "4". It returns 5 coeff for x^4, x^3, ...

Transform: Transform functions are ones that maps one domain to other domain. Depending on func used to do transform, it can be quite complex. matlab computes symbolic results.

1. Laplace transform: laplace transform converts f(t) in "t" domain into L{f(t)} in "s" domain. func laplace used for this.

ex: syms s t a w; laplace(a); laplace(t^2); laplace(sin(w*t)) => here we define s, t, a, w as symbols. "s" is for laplace transform o/p var, while others are i/p var going into laplace func. gives results as 1/s^2, 2/s^3 and w/(s^2+w^2)

2. inverse Laplace transform: ilaplace func used. Converts from s domain to t domain.

ex: syms s t ; ilaplace(s/(s^2+4)) => gives cos(2*t) as o/p

3. z transform:

4. Inverse z transform:

5. Fourier transform: converts from time domain to freq domain. freq domain expressed in radians(ω) or hertz(2Πf).

F=fourier(f,u,v); => calculates FT of f(u) as F(v), i.e F(v) = ∫ f(u) e-jvu du. By default, if we omit u,v (i.e F=fourier(f)), then i/p func f is taken as f(x), and o/p func F is given as F(w), i.e F(w) = ∫ f(x) e-jwx dx. Here, w is freq. F=fourier(f,w) imples f(x) and F(w). We have to declare u, v as syms (symbols), else fourier function will give an error as it expects symbols as it's inputs.

Generally, we use function syms fourier(f,t,w) which yields F(w)=  ∫ f(t) e-jwt dt

 ex: syms x; f = exp(-2*x^2); FT = fourier(f); ezplot(FT); => shows FT = (2^(1/2)*pi^(1/2)*exp(-w^2/8))/2, and displays it on graph, with w=-2Π to +2Π.

6. Inverse Fourier transform: converts from freq domain to time domain. ifourier func used

ex: f = ifourier(-2*exp(-abs(w))); => gives result as f = -2/(pi*(x^2 + 1))

7. Fourier series: There is no function for calculating FS of periodic func. Instead, we directly compute terms Ck using integral in matlab and plot them. However, better way is to plot FT. Since FT is a superset of FS, we can look at FT values at distinct freq and get FS from that. Most of the times, FT suffices.

 

 

Generating basic signals: We can generate signals by using built in func. Basic code is:

x=[0:0.005:0.2]; % choose x axis points here
y=func(x); % generate y axis points by applying func to x
plot(x,y); % plot it

1. impulse function: y=dirac(x). Since dirac is a limiting func, whose value is 0 at x≠0, but infinity at x=0 (for continuous function), matlab draws dirac func with missing value at x=0, and 0 everywhere else.

2. sine wave: y=sin(x).

ex: create sine wave of 10Hz freq, T=0.1sec
t=[0:0.005:0.2]; => time is from 0s to 0.2s in steps of 5ms
Amp=1; freq=10; => Amplitude=1, freq=10Hz,
y=Amp*sin(2*pi*freq*t); => plots 2 full waves in 0.2sec, since 10Hz freq => T=0.1sec =10 sine wave/sec
plot(t,y); => plots t on x axis and sine o/p on y axis. plots over range of t from 0 to 0.2sec. plot is little choppy, but can be made smooth by choosing finer steps of 1ms, i.e t=[0:0.001:0.2]

If we choose freq=1000, then sine func argument=2*pi*1000*0.005*n=10*pi*n. So y=0 for all values of n. Then plot(t,y) should be 0 everywhere, since we don't have enough samples to sample any value other than 0. However, what we observe in reality is a choppy plot with y=very small value (10^-13 or so) and it bonces around 0. This is because sin(2*pi)=0 in theory, but computers calculate pi to finite digits only. That results in sin(2*pi) close to 0, but not exactly 0. Whenever you get weird plots like this, always check to make sure you have enough sample points.

ex: create sum of 2 sine waves of 10Hz freq, 

t=[0:0.005:0.2]; => time is from 0s to 0.2s in steps of 5ms
A=1;f1=10;f2=20 => freq=10Hz,20Hz
y=A*sin(2*pi*f1*t) + A*sin(2*pi*f2*t) ; => adds 2 sine waves
plot(t,y) => plots sum of 2 waves, amplitude of final "y" goes from -2 to +2

ex: show gibbs phenomemon in constructing square wave from sine waves (taken from mathworks website)

t = 0:.02:6.28; % t is 1Xn array
y = zeros(10,length(t)); %y is 10Xn array
x = zeros(size(t)); % x is 1Xn array
for k = 1:2:19
   x = x + sin(k*t)/k;
   y((k+1)/2,:) = x;
end
plot(y(1:2:9,:)')

 

------------------


1D. print text on graph
text_to_print = ['SNDR (in db) =',num2str(SNDR1),char(10),'SFDR (in db) =',num2str(SFDR1)]; => char(10) is needed to introduce newline. \n doesn't work.
text(10,-50,text_to_print); => prints the text above on graph.
saveas(gcf,"plot_tmp");

4. matlab native fft function are fft() and inverse is ifft(). To compute fft:
Y = fft(X) => computes the discrete Fourier transform (DFT) of X using a fast Fourier transform (FFT) algorithm. FFT is just bunch of points, it doesn't have any frequency info. We get this frequency info from sampling rate.
Y = fft(X,n) returns the n-point DFT. If no value is specified, Y is the same size as X. If X is a vector and the length of X is less than n, then X is padded with trailing zeros to length n. This is equiv to taking DFT of signal multiplied with a rectangular window. NOTE: for n-point dft, Y is also n point, i.e Y[0] to Y[n-1]. It's periodic with period n, so, only n points reported for Y.

4. PSD of signal
pxx = pwelch(x) => returns PSD of signal x using Welch's overlapped segment averaging estimator. If x is real-valued, pxx is a one-sided PSD estimate. If x is complex-valued, pxx is a two-sided PSD estimate.
[pxx,f] = pwelch(x,window,noverlap,f,fs) returns the two-sided Welch PSD estimates at the frequencies specified in the vector, f.

5. plotspec( ) => This function is defined as below (not std function of matlab). It computes the PSD of a signal, and plots Power in db on Y axis and freq on X axis (log scale).
 
plotspec.m script => uses pwelch signal and then draws plot
------
function [P,F]=PlotSpec(Signal,Fs,Navg,EnFig,color)
 FftLength=round(length(Signal)/Navg);
 Win=window(@blackmanharris,FftLength);

 if FftLength>length(Signal),
  warning('FftLength is greater than the signal length.')
 end

 [Ps,F] = pwelch( sin([0:FftLength-1]'*2*pi/16),Win, floor(3*FftLength/4), FftLength,Fs);
 norm=max(Ps(:,1));
 [P,F] = pwelch( Signal,Win, 0, FftLength,Fs); => note: P is not in db here.
 P=P(:,1)/norm;

if (EnFig==1)
    semilogx(F,10*log10(abs(P)),color,'LineWidth',2);
elseif (EnFig==2)
    plot(F,10*log10(abs(P)),color,'LineWidth',2);
end
    grid on;
    ylabel('Mag (dB)','FontSize',13);
    xlabel('Frequency (Hz)','FontSize',13);

end
-----
ex: [P,F]= PlotSpec(signal, Fs,1,1,'k'); => In John's script
ex: plotspec(signal,Fs,'on',[1 100]); => sampling freq=Fs, freq range on x axis = 1Hz to 100Hz. we can also specify limits separately in other cmd.
ex: [magnitudes, frequencies] = plotspec(signal,Fs,'off'); => instead of plotting, we can also store values in variables


----------------------
Fs1 = 8388608;
digin1 = dlmread('data1.csv'); => reads csv file, put 1 data in each row
figure('Color','w','Name','SDMout-Dec (SV)','WindowStyle','docked');
%PlotSpec(digin1,Fs2,1,1,'k'); => comment starts with %
PlotSpec(digin1,Fs1,1,1,'k');
ylim([-140 0]); => y db limit
xlim([0 Fs1/2]); => x freq limit
------------------------
ex: create sine wave
t=[0:0.005:0.2]; => time is from 0s to 0.2s in steps of 5ms
A=1;f1=10000;f2=50000 => freq=10kHz,50Khz
y=A*sin(2*pi*f1*t) + A*sin(2*pi*f2*t) ; => adds 2 sine waves
plot(t,y) => plots t on x axis and y on y axis

ex: plot fft of sine wave:
f0 = 307;    //sinusoid freq
Fs = 44100; //Sampling frequency in Hz:
Ts = 1/Fs; //Sampling time:
M = 1500; //1500 samples of sinusoid => think of this as the length of a rectangular window that multiplies our infinitely long sinusoid sequence.
n = 0:(M-1); //array of num from 0 to 1499
y = cos(2*pi*f0*Ts*n); //y[n]=cos[2*pi*f*t*n] => draws approx 10 full cosine waveforms = f0/Fs*1500=10. do "plot(n,y);" to see it
Y = fft(y); //computes M point fft since there are M points in y
f = (0:(M-1))*Fs/M; //compute freq points. from 0 to Fs in 1500 steps
plot(f,abs(Y),'*') //plot f on x-axis and mag of Y on y axis, with * as discrete points
xlim([0 Fs/2])
title('Magnitude of DFT')
xlabel('Frequency (Hz)')

-----------------------
ex: save plots in loop
sdm_files = {
         'adc_data_out_ram_raw_k4_b.txt',
         'adc_data_out_ram_raw_k5_b.txt',
         'adc_data_out_ram_raw_k6_b.txt'};

freq=8388608;
%freq=(8384, 789, 123); => makes it an array with integer values accessed thru freq{k}

for k = 1:3
   sdm_file_name = strcat(path, sdm_files{k});
   display(sprintf('Processing %s', sdm_file_name));
   sdm_output = dlmread(sdm_file_name);
   title = sprintf('SDM Ouput k=%d', k+3);
   figure('Color','w','Name', title,'WindowStyle','docked');
   PlotSpec(sdm_output, SDM_freq,1,1,'k');
   ylim([-160 0]);
   xlim([0 SDM_freq/2]);
   out_file_name = strcat(k, '_filt_fbw.jpg');
   saveas(gcf,out_file_name);
end

---------------------------------
end


Signal processing refers to processing any i/p signal to generate a transformed o/p signal. The black box that does this transformation may be analog or digital circuit. The i/p, o/p signals may be continuous or discrete.

In Signal theory, we refer to signals as varying in time, (i.e signal F(t)). However signals can be function of any var "x" (i.e signal F(x)). It so happens that for any signal of interest in real scenario, x happens to be time "t". Although "t" is real, it can be complex too. Thus signal F(x) can be real or complex, with x itself being real or complex. As you can guess, in real world life scenario, signal F(x) is real.

Joseph Fourier proved that any periodic continuous function can be represented exactly via infinite sum of discrete sine and cosine waveforms. This series came to be known as Fourier series (FS). For non-periodic continuous signals, instead of discrete freq components of sine and cosine, it was a continuous freq spectrum, and came to be known as Fourier Transform (FT). This was very important discovery of 18th/19th century by Joseph Fourier, who introduced it for purpose of solving heat equations in a metal plate.

These are some good links for learning Fourier:

http://www.thefouriertransform.com/ => Superb explanation of fourier

Few imp formula before we get into FS:

1. freq in radian (ω) = 2Π*F = 2Π/T, where F = freq in hertz, T=time period in sec. Ex: linear freq of 1 Hz = 1 rotation/sec = 2*pi radians/sec = 6.28 radians/sec. This is very important formula to remember, as many textbooks compute Fourier in F, while many do it in ω. There is a constant factor 2Π that appears depending on whether you are dealing in Hz or radians.

2. Euler's formula: eix = cos(x) + i sin(x) => This is regarded as most remarkable formula in mathematics, as it establishes relationship b/w trignometric functions and complex exponential functions. "i" is defined as square root of -1 ( i = √-1 ) In maths, we use "i", but in physics, we use "j". Euler's formula can be proved easily, by writing taylor's expansion of exponential, and then separating it in 2 series, with 1 series corresponding to sin(x), while other series corresponding to cos(x). But it was Euler who saw it first.

3. Euler identity is Euler's formula with x=Π: e = cos(Π) + i sin(Π) = -1. For x=0 or 2Π, e= ei2π = cos(2Π) + i sin(2Π) = 1. From this, it implies that e0T0 = ei2π = 1.

4. Complex number: Any complex number c=a+ib can be represented in magnitude and phase form. a+ib = mag.ewhere mag = √(a2 + b2), and tan(θ) = b/a. So, c=|c|.ei∠c. This is how we'll represent complex numbers in signal theory.

5. Impulse function or delta dirac function: This is a hypothetical function which is 1 at t=0, but is 0 everywhere else. This can be thought of as a gaussian function, with limit t->0. i.e Limit t->0 ∫ x(t) dt =1, where x(t) is gaussian function. This impulse function is used extensively in signal theory, since mathematically impulse function allows conversion from cont domain to discrete domain. NOTE: x(t) is a continuous func. The resulting integral is the area of that func, and thus is a cont func of "t". As t->0, in continuous form, the value at t=0 approaches ∞ for impulse function, as base "x" axis time scale reduces to 0, to keep area = 1. in discrete form, impulse function is defined as x[n]=1 which is 1 at n=0, and 0 everywhere else.

Impulse function δ(x) defined as limit x->0 ∫ δ(x) dx =1

Just as we define impulse func at x=0, we can define it at any x=x0. limit x->0 ∫ δ(x-x0) dx =1. Here δ(x) is 1 at x=x0, but 0 everywhere else. So, the gaussian func is just shifted from being centered at x=0, to being centered at x=x0.

Few Sine/Cosine formula:

0. cos(x) = (eix + e-ix )/2 ; sin(x) = (eix - e-ix )/2i => derived by using Euler's formula above

1. sin(x) = cos(x-Π/2)

2. ∫ sin(2Πnt)*sin(2Πmt)dt = 0 for n≠m, and ∫ sin(2Πnt)*sin(2Πmt)dt = 1/2 for n=m. Here n, m are both integers, and limit of t is from 0 to 1

3. ∫ cos(2Πnt)*cos(2Πmt)dt = 0 for n≠m, and ∫ cos(2Πnt)*cos(2Πmt)dt = 1/2 for n=m. Here n, m are both integers, and limit of t is from 0 to 1

4. ∫ cos(2Πnt)*sin(2Πmt)dt = 0 for any n, m. Here n, m are both integers, and limit of t is from 0 to 1. These 3 eqn are used in proof of FS later.

Continuous time (CT) signals: here F(x) is a continuous function over all values of x, where -∞ < x < ∞. Fourier series or Fourier transform of CT signals is always aperiodic in freq domain.

1. Continuous Time Fourier Series (CTFS): For continuous and periodic signals in time domain, we can compute CTFS. This CTFS is discrete and aperiodic in freq domain.

Any cont periodic signal is represented as infinite summation of cos and sine functions. This is called FS representation of function. CTFS is the fundamental eqn, and all other series/transform for cont/discrete waveforms are derived from CTFS. CTFS is what was derived by Fourier, and is surprisingly very easy to prove.

x(t) = a0 + ∑ ak * cos(ω0kt) + ∑ bk * sin(ω0kt) , where k = 1 to ∞. Here feq ω0 = 2Π / T0, where T0 is the freq of periodic signal (1/T0 = f0). Here a0 is the DC freq component, while ω0 = fundamental or 1st harmonic, 2ω0 = second harmonic and so on. Coefficients a0, ak, bk are called Fourier coefficents, and are computed as follows. Integral is taken over 1 period of the periodic signal.

a0 = 1/T0 ∫ x(t) dt,

ak = 1/T0 ∫ x(t) cos(2Πkt/T0) dt

bk = 1/T0 ∫ x(t) sin(2Πkt/T0) dt

NOTE: This series contains only real terms, and is called real FS. k above is +ve, and goes from 1 to infinity. In reality, k = 0 to ∞. It just so happens, that for k=0, cos(2Πkt/T0) =1, while sin(2Πkt/T0) = 0. So, a0 = 1/T0 ∫ x(t) dt, while b0 = 0.  No -ve k allowed. From now on, we'll refer to FS coeff as {ak, bk} with k from 0 to ∞. The motivation for a0 is to provide dc offset, since all sine/cosine functions are always centered around X-axis with y=0 (i.e no dc offset, they start from 0 and go back to 0 over 1 cycle). In order to represent any offset from x-axis, we need a constant, which is what a0 provides.

Also, x(t+T) = x(t) is true when calc thru FS, as ω0T0 = 2Π.

Proof: We can prove FS above very easily. Proof is presented very nicely here:  http://faculty.olin.edu/bstorey/Notes/Fourier.pdf.

Let's assume that FS is true, and we can indeed rep any function as sum of sine and cosine.

x(t) = a0 + ∑ ak * cos(ω0kt) + ∑ bk * sin(ω0kt)

Multiply both sides of eqn by sin(2Πmt), and then integrating over limit 0 to 1, we get values of a0, ak and bk. So that implies that eqn above is true since we can get coeff which satisfy this eqn.

We can make above series simpler. We put, ak = dk cos(θk), bk = dk sin(θk). We can do this since any 2 numbers on x and y axis can be represented on a circle with a certain radius and angle.

x(t) = ∑ dk cos(θk) * cos(ω0kt) + ∑ dk sin(θk) * sin(ω0kt)  = ∑ dk cos(θk0kt)  where dk = √(ak2 + bk2), and tan(θk) = bk /ak , with k = 0 to ∞.

Above eqn is easier to work with. It shows that any function can be rep as cosine series only with different magnitude and offset for each freq component. This seems logical, since sine can be converted to cosine with 90 degree phase offset. Instead of representing series in cosine series only, we could represent it in sine series only (as it's just phase shift of 90 degrees). Though above series, whether in sine or cosine, is ok to work in maths, we prefer to work in complex exponential in physics. This makes it easier to solve them. So, we try to get it in Euler's form.

We use the formula: cos(θ) = (e + e-)/2 to convert real numbers to complex numbers. We also note that subscript k can be both +ve/-ve value. Substituting this, we get the below form:

x(t) = ∑ Ck * e0kt ( -∞ < k < ∞ ),  Here Ck is complex number = dk/2 * ek = 1/2 * {dk cos(θk) + dk j.sin(θk)}.

Ck = 1/T0 ∫ x(t) e-0kt dt, Integral is taken over 1 period of the periodic signal.

Magnitude of this complex number Ck is dk/2 = √(ak2 + bk2)/2, while phase is θk where tan(θk) = bk /ak ,

NOTE: This series contains complex terms, and is called complex FS. Here k is both -ve and +ve, so we have freq spectrum on both sides of x axis (while FS terms were only on +ve x axis). This is why we have a 1/2 multiplier factor when going from real FS to complex FS, to account for it existing on both sides (we half the magnitude on both sides, when converting cosine to complex exponential). Also, FS coeff have -ve term in exponent, while inverse FS (i.e reconstruction of original signal) has +ve term in exponent. This is going to be true in all series and transforms as we'll see later (though it could have been other way around too, this is just a convention ?? FIXME?).

From now on, we will work with complex FS only. It's easy to represent, as we can draw magnitude and phase plot of this one complex number (instead of having 2 real numbers ak and bk). This plot runs over all values of k, so we see this plot on both sides of x axis. The magnitude plot of Ck is symmetrical around x=0 axis, while phase plot of Ck is -ve of each other on 2 sides of x-axis. Note that even though Ck is complex, the fourier series sum can still yield real function.

We can calculate FS coefficients for a variety of periodic signals, and observe many interesting things about sinusoidal wave, square wave, triangular wave, etc. We'll discuss those later.

2. Continuous Time Fourier Transform (CTFT): For continuous and aperiodic signals in time domain, we can compute CTFT. This CTFT is continuous and aperiodic in freq domain. Non periodic signal can be considered as a special case of a periodic signal, where Time period T0 is expanded to infinity, and we consider only 1 cycle of periodic signal.

We can derive FS for aperiodic signals (attach proof, FIXME). On deriving, we come up with below eqn: NOTE: factor T0 goes away and gets replaced by (2Π) when deriving this.

x(t) = 1/(2Π) ∫ X(ω) ejωt dω, where X(ω) is the CTFT of x(t). Integral is taken over full -∞ < ω < ∞. Only difference compared to CTFS is that ω0k is replaced by ω, and infinite summation is replaced by integral. This is also called inverse CTFT.

X(ω) = ∫ x(t) e-jωt dt, Integral is taken over full time of the aperiodic signal -∞ < t < ∞. Note: this looks similar to Ck for periodic signals, except that Ck for aperiodic signals has become continuous now. Also, 1/T0  is absent, as we folded that factor 1/(2Π) outside the integral in x(t) eqn above, so that it is no longer a part of FT. This is the forward CTFT. We can also write X(ω)  as X(jω) so as to be explicit that ω is complex.

So, to conclude, we see that CT periodic signals have discrete freq at +/-ω0, +/-2ω0, +/-3ω0 and so on. But CT aperiodic signals have a continuum of freq from -∞ < ω < ∞. Other way to see is that freq is kω0 for both periodic and aperiodic. But for periodic, k can take integer values only (i.e 0,1,2,3, ..), but for aperiodic signals, k can take all real values (i.e, 0, 0.001, 0.002, ....). CTFT is a superset of CTFS, as we can calculate CTFT of both periodic and aperiodic signals. There is nothing that prohibits taking CTFT of periodic signals. CTFT of aperiodic signals yields cont freq spectrum as we saw above. However, for periodic signals, we saw that we get discrete values for Ck. Since CTFT is derived from CTFS, CTFT should also yield same answer. However, we saw that CTFT is cont, and integral can never yield non cont discrete values. Dirac delta function comes to our rescue here, as they allow discrete values to be represented as the limiting case of gaussian func. So, CTFT of periodic signals will yield impulse or dirac delta at discrete freq, so that the func remains cont. So CTFT will serve us well for all kinds of waveforms (both periodic and aperiodic). Going forward, we'll learn CTFT only.

NOTE: we derived FT in terms of ω, which gives us a factor of (2Π). If we derive FT in terms of f, then we get rid of (2Π).

X(2Πf) = ∫ x(t) e-j(2Πf)t dt => X(f) = ∫ x(t) e-j(2Πf)t dt => remains same as X(ω), as integral is done over "t" and not "f"

x(t) = 1/(2Π) ∫ X(2Πf) ej(2Πf)t d(2Πf) = 1/(2Π) * (2Π) ∫ X(2Πf) ej(2Πf)t d(f) = ∫ X(2Πf) ej(2Πf)t df => x(t) = ∫ X(f) ej(2Πf)t df => gets rid of factor 2Π compared to X(ω), as integral is over "f".

3. Laplace transform: LT is defined for CT signals, in exactly same way as FT is defined for CT signals. In LT, complex var "s" has both real and imaginary parts (s = σ + jω). FT happens to a special case of LT, with σ=0, so s=jω. LT and FT are kind of same. When dealing with signals, we use FT, while when dealing with systems, we use LT. LT allows us to solve ordinary differential eqn encountered in RLC ckt, in an easier way by transforming it from time domain to laplace "s" domain (we can solve it equally easily by transforming it to Fourier "jω" domain). We eventually end up substituting s with jω, so both LT and FT end up same.

LT[x(t)] = X(s) = ∫ x(t) e-st dt, Integral is taken over full time of the aperiodic signal -∞ < t < ∞. This is called two sided LT. Since most signals are 0 for t<0, we usually evaluate integral from 0 < t < ∞. This is called one sided LT. Note: this looks similar to FT eqn above, except that jω is replaced by s.

 

Discrete time (DT) signals: here F{x[n]} is a discrete function over all values of n, where x[n] is the input signal with n=0, +/-1, +/-2, ... ∞. Fourier series or Fourier transform of DT signals is always periodic in freq domain. This is the main diff b/w CT and DT. Otherwise DT are similar to CT.

1. Discrete Time Fourier Series (DTFS): For discrete and periodic signals in time domain, we can compute DTFS. This DTFS is discrete and periodic in freq domain. It's similar to it's CT counterpart CTFS.

We can derive DTFS from CTFS.

First let's derive x[n] from x[(t):

For CTFS, x(t) = ∑ Ck * e0kt ( -∞ < k < ∞ ). However, now x(t) is not continuous, but has discrete values. Assume N samples for x(t) equally spaced by T0/N intervals, from t=0*T0/N to t=(N-1)*T0/N. So samples are x(0) to x((N-1)*T0/N). 

x(t=n*T0/N) = ∑ Ck * ej(2Π/T0)k(n*T0/N) ( -∞ < k < ∞ ).

Represent discrete x(t) as x[n], where x[n] = x(n*T0/N), and n = 0 to N-1.

x[n] = ∑ Ck * ej(2Π/N)kn,  Here summation is over 1 period of Ck (Need to find out how summation went from ∞ to one period). Since Ck is periodic with period N (as we'll see below), we choose k as 0 < k < N-1. It doesn't matter what values of k we take, as long as it represents one full cycle over N values. So, Ck may have total N samples from C0  to CN-1 . i.e 0 < k < N-1, or C1 to CN , i.e 1 < k < N, or any other period. This looks similar to CTFS, except that it has period ω0 replaced by 2Π/N. T0 = 2Π / ω0 = N.

Now, let's derive Ck for x[n] from Ck for x[(t):

For CTFS, Ck = 1/T0 ∫ x(t) e-0kt dt, However, since x(t) is not continuous any more, but has discrete values, we can't calculate integral. However, we can make approximation of this integral, by taking only those "t" for which values of x(t) is known.

Then we use same value of x(t) for interval T0/N. So, x(t) at any time t is x(n*T0/N) where n = 0 to N-1.

Ck = 1/T0 ∫ x(t) e-0kt dt ≈  1/T0 ∑ x(n*T0/N) e-0kn*T0/N  * T0/N, where t=n*T0/N, ans summation is over n=0 to N-1. We approximate each integral piece as a rectangular box with height=x(n*T0/N) and width=T0/N.

=> Ck = 1/N ∑ x(n*T0/N) e-j(2Π/T0)kn*T0/N = 1/N  ∑ x[n] e-j(2Π/N)kn, where x[n] = x(n*T0/N), and n = 0 to N-1.

Ck = 1/N  ∑ x[n] e-j(2Π/N)kn, summation is over 1 period of the periodic input signal with period=N samples, i.e 0 < n < N-1. Ck is complex number, and is periodic. with 0 < k < N-1. Ck is periodic can be deduced from the fact that for k=0 or k=N, C= CN as ej(0) = ej(2Π) . This looks similar to CTFS, except that it has summation instead of integral and Ck is periodic with period N.

Proof here: https://www.math.ubc.ca/~feldman/m267/dft.pdf

2. Discrete Time Fourier Transform (DTFT or DTF): For discrete and aperiodic signals in time domain, we can compute DTFT. This DTFT is continuous and periodic in freq domain. It's similar to it's CT counterpart CTFT.

We can derive DTFT from DTFS, the same way we derived CTFT from CTFS (by treating summation as integral when T -> ∞)

x[n] = 1/(2Π) ∫ X(ω) ejωn dω, where X(ω) is the DTFT of x[n]. Integral is taken over 1 cycle of ω, i.e λ < ω < λ+2Π. Only difference compared to CTFT is that t is replaced by n, and integral over all values of ω, is replaced by integral over 1 cycle of ω. This is also called inverse DTFT.

X(ω) = ∑ x[n] e-jωn, summation is taken over all samples of the aperiodic signal -∞ < n < ∞. Note: this looks similar to CTFT, except that t is replaced by n, and integral is replaced by summation, Also, X(ω) is periodic now, since X(ω+2Π) = X(ω). This is also called forward DTFT.

Since, same X(ω) notation is used for both CTFT and DTFT, it can cause confusion, as to whose FT is it representing (discrete or continuous). So, we for DTFT, we write it as X(Ω) or X(e), while for CTFT, we write it as X(ω) or X(jω).

CTFT: X(ω) or X(jω) = |X(jω)|ei∠X(jw).

DTFT: X(Ω) or X(e) = |X(e)|ei∠X(ejω).

3. z transform (ZT): ZT is defined for DT signals, in exactly same way as LT is defined for CT signals. It is same as DTFT, except that complex var "z" is of form Ae. DTFT is special case of ZT, where complex var "Ω" is of form e (i.e z with unit magnitude only).

ZT{x[n]} = X(z) = ∑ x[n] z-n,  -∞ < n < ∞. This is same as DTFT with z=e.

ZT is used to solve discrete diff eqn in time domain. Concept is same as that of LT for solving cont diff eqn in time domain.

----

Discrete Fourier Transform (DFT):

This is a very popular topic in any signals theory. When we talk about anything in DSP (digital signal processing), DFT is what we are talking about. As we saw above, we can take DTFT of discrete signals which are not periodic. Since in real life, most signals are not periodic and are sampled, DTFT is what we use mostly for discrete signals (instead of DTFS). Computers can work with discrete signals (samples of analog signals at discrete times), and process them to generate DTFT of those samples. However, DTFT that we get above is itself continuous, and that is a problem for machines that deal with discrete samples only. Computers can't generate analog DTFT waveform. They can generate samples of DTFT. We can generate samples of DTFT so close by that we can approximate analog DTFT signal. Those samples of DTFT are called DFT.

DTFT of x[n] = X(Ω) = ∑ x[n] e-jωn,

DFT of x[n] = Xk or X[k] = samples of X(Ω) at discrete freq =  X(Ω) | ω=2Πk/N where 0 <= k <= N-1. Here we are taking N samples, X0 to XN-1

But discrete freq components implies periodic x[n], since only periodic signals can have discrete freq components. As we saw above, DTFS has discrete freq components, while DTFT has continuous freq spectrum. Basically as signal becomes aperiodic (or T -> ∞), more and more freq components start showing up, until it becomes continuous freq spectrum.

So, if we try to reconstruct original signal x[n] by taking inverse DFT of Xk , we'll not get original x[n], but periodic x[n]. As we have more and more samples of Xk, we'll get more and more original values of x[n] with larger period (i.e T starts going to ∞). So, DFT of x[n] is basically same as taking DTFS of periodic x[n].

DTFS of x[n] = Ck = 1/N  ∑ x[n] e-j(2Π/N)kn

DFT of x[n] = Xk or X[k] = 1/N  ∑ x[n] e-j(2Π/N)kn = 1/N  ∑ x[n] e-kn , where ωk =2Πk/N where 0 <= k <= N-1. 

Thus DFT of x[n] can be calculated by either of 2 ways:

1. Compute DTFT of x[n]. Then take samples of DTFT at discrete freq  ωk =2Πk/N where 0 <= k <= N-1. 

2. Compute DTFS of x[n]. This DTFS gives same result as 1 (taking DTFT samples) above.

Inverse DFT of Xk = x[n] = ∑ Xk ekn, where ωk =2Πk/N where 0 <= k <= N-1. 

This is same as inverse DTFS = x[n] = ∑ Ck * ej(2Π/N)kn,  where 0 <= k <= N-1. 

Thus from now on, we'll treat DFT the same as DTFS. So, when we say DFT, we mean DTFS, and not DTFT.

 

 

 

vlsi digital standards

There are many standards for diffeent files used in vlsi. We talk about some standards and their formats:

LEF:

DEF:

UVM:

...

Webserver: Any website that you access, goes to a computer on internet. On that computer is a program running (for linux it's apache) which allows that computer to return the response back to the client. This computer is called a webserver. Before we get into webserver program, let's get some basics.

IP addr:

Each device connected to internet is assigned a unique 32 bit IP addr. These are written as 4 octets(each octet is 8 bits) - e.g. 18.251.48.77. IP addresses can go from 0.0.0.0 to 255.255.255.255. However, IP adr are divided into 5 classes based on addr range:

class A: 1.0.0.0 - 127.255.255.255 => Top 8 bits are Net ID. Bottom 24 bits are Node ID.

class B: 128.0.0.0 - 191.255.255.255 => Top 16 bits are Net ID. Bottom 16 bits are Node ID.

class C: 192.0.0.0 - 223.255.255.255 => Top 24 bits are Net ID. Bottom 8 bits are Node ID.

class D: 224.0.0.0 - 239.255.255.255 => multicast. Top 4 MSB are "1110". Remaining 28 bits are Multicast ID.

class E: 240.0.0.0 - 255.255.255.255 => experimental, reserved for future use

Public vs Private: IP addr can be public or private.

The following ranges are reserved by the Internet Assigned Numbers Authority (IANA) for use as private IP addresses:

  • 10.0.0.0 to 10.255.255.255 => from class A
  • 172.16.0.0 to 172.31.255.255 => from class B
  • 192.168.0.0 to 192.168.255.255 => from class C. All of the 192.x addr are not registered publically, so they can only be used behind a router as private IP addresses. This range is where most private IP addresses fall, which is why the default IP address for most Linksys, D-Link, Cisco, and NETGEAR routers is an IP within this set.

Any other addr besides the private ones listed above are available for use as public IP addr. Public IP addr are the ones that can be accessed by any device connected to internet. Each device connected to internet has 1 uniue public IP addr. A device finds some other device on internet by knowing their public IP addr, and using routers to route to that device. private addresses are non-routable — hardware devices on the internet are programmed to prevent devices with a private IP address from communicating directly with any other IP beyond the router that they're connected to. Private IP addr are not unique. Devices in my home and neighbours home can have same private IP addr.

Home Router:

Home routers have 2 or more n/w i/f (or port) each with it's own IP addr. One i/f connects to Wired internet lines coming to your house. There is usually a modem inbuilt in the router which provides this i/f. This i/f has public IP addr that can be seen by the whole world. This public ip addr is assigned to your router by your ISP provider (AT&T, Spectrum, etc). The ISP provider usually keeps on changing this public addr assigned to your router. That is why you may see diff IP addr of your router on diff days. All other i/f of router are the wired or wireless i/f with their private ip addr. All computers in the house also have their own private IP addr. Thus, behind the router, all devices talk to each other using their private IP addr. These same private ip addr can also be present behind your neighbour's routers. But since when trying to connect to private ip addr, the router never allows the traffic for private ip addr to leave the router, there is no source of confusion b/w your home's private n/w traffic and your neighbor's private n/w traffic, since none of this traffic ever leave their respective router, if it's meant for a device on same n/w.

If you try to find IP addr of your computer, use the "ifconfig" cmd on a terminal in Linux.

ifconfig: interface configuration. Used to view and change the configuration of the network interfaces on your system. It is run at startup to configure network interfaces of your computer. Usually, there are 3 n/w i/f for your computer = wired ethernet, wireless and loopback. Ethernet i/f has name "eth", loopback has "lo" while wireless has "wlan". Names may differ for diff Linux distro. All i/f show 32 bit IP v4 address, and 48 bit IP v6 address / 48 bit mac physical address. If Ethernet i/f is connected, we'll see ip addr assigned as 192.168.1.57.  Loopback i/f shows ip addr as 127.0.0.1. If we have a web server running on our computer, and if we type 127.0.0.1 in our browser, it doesn't goto any other computer, but loops back on same computer and shows main index page (this is useful in debug). Wireless i/f shows IP addr as "inet: 192.168.1.70". NOTE: ethernet i/ and wireless i/f have their own IP addr, which are not same. So, depending on which IP addr you use, you connect via ethernet or wireless to that device.

NOTE: ethernet and wireless i/f show that the computer is assigned a private ip addr from class C, while loopback i/f shows private ip addr from class A. Both addr are private addr. So, if we have webserver running on our computer, we could type 192.168.1.70 in our browser, and it will behave same as loopback, i.e it will show http main index page on our own computer,

On CentOS, you may see more than 1 wireless n/w i/f even though the computer has 1 n/w card. These are virtual n/w switch/bridge with names as virbr0 (virtual bridge 0), etc. These are used by certain applications on your m/c. These virtual i/f can be disabled or removed w/o any effect (except for the pgm using it).

Note: What we got above is the private ip addr of our computer. We don't know the ip addr of other devices talking to our computer. Next, let's try to find IP addr of our modem/router:

route: route cmd shows the kernel routing table entries, and also allows us to edit the table. This is the table that is used by OS for static routing. It's primary use is to set up static routes to specific hosts or networks via an interface after it was configured with the ifconfig program.

> route => route cmd shows below o/p. The flag U indicates that route is up and G indicates that it is gateway. 
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
default         homeportal                 0.0.0.0         UG    600    0        0 wlp3s0
192.168.1.0     0.0.0.0         255.255.255.0       U     600     0         0 wlp3s0
192.168.122.0   0.0.0.0         255.255.255.0     U     0         0         0 virbr0

route -n => this shows gateway IP addr number instead of names.
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         192.168.1.254   0.0.0.0                UG    600    0        0 wlp3s0
192.168.1.0     0.0.0.0         255.255.255.0      U     600    0        0 wlp3s0
192.168.122.0   0.0.0.0         255.255.255.0   U        0      0        0 virbr0
 
From above o/p, we see that if a packet comes into the system (i.e this laptop) and has a destination in the range 192.168.1.0 through 192.168.1.255, then it is forwarded to the gateway 0.0.0.0 (also represented as * on some systems) — a special address which represents an invalid or non-existant destination. So, in this case, our system will not route these packets. Same is the case with ip addr 192.168.122.0 to 192.168.122.255.

If the destination is not in this IP address range, it is forwarded to the default gateway (in this case, 192.168.1.254 which is the router), and that system will determine how to forward the traffic on to the next step towards its destination. 192.168.1.254 is the private IP addr of the router (router has public ip addr also, which is on the other i/f). If we type this addr in browser, 192.168.1.254, we'll see out login menu for the router show up (this page is the http index page of router that it's shipped with).

 

C Shell (csh) or tcsh:

C shell was created by Bill Joy of UCB in 1978, shortly after release of sh shell. It was developed to make coding style similar to C language (since C was the most used language for programming at that time), and make it easier to use. Later a improved version of csh called tcsh was developed which borrowed a lot of useful concepts from Tenex systems, hence the "t". On most linux systems, tcsh is the shell used (even though it says csh, it's actually tcsh, as csh is usually a soft link to tcsh binary).

NOTE: Even though we say csh everywhere, it's really tcsh that we are talking about. Extensions still say *.csh. We'll call it csh even though we mean tcsh.

This is  offcial website for tcsh: https://www.tcsh.org/

This is good website for all shell/linux related stuff: (The guy lists a lot of reasons on why csh shouldn't be used): https://www.grymoire.com/Unix/Csh.html

Bill Joy's csh intro paper here: http://www.kitebird.com/csh-tcsh-book/csh-intro.pdf

csh syntax: https://www.mkssoftware.com/docs/man1/csh.1.asp

NOTE: C shell is not recommended shell for usage. Bash is the one that should be used. Almost all of linux scripts, that you find in your linux distro, are in bash. Csh is introduced here, since some scripts in corporate IT world are still written in csh, which you may need to work on from time to time. Csh is ripe with bugs, and you can find a lot of articles as to why Csh should not be used. One reason why csh is so buggy and unpredictable is because it doesn't have a true parser like other shells. Bill Joy famously admitted that he wasn't a very good programmer when he wrote csh. To make matters worse, there is no elaborate documentation of csh (unlike bash, which has very detailed documentation on tldp.org website). The only doc that shows up most frequently on internet searches is that "bill Joy's csh" paper, whiich is like decades old (shown in link above). This makes it hard to systematically learn csh. What I've documented below is just bits and pieces from diff websites, as well as my own trial and error with csh cmds. In spite of all this, csh became so popular, which just bewilders me. Hope, I've convinced you enough not to read thru the csh doc below.

Csh startup files: uses 3 startup files:

1. .cshrc: It's sourced everytime a new C shell starts. The shell does a "source .cshrc". csh scripts also source this file, unless "-f" (i.e fast) option is used on cmd line or on 1st line of csh script

ex: #!/bin/csh -f => -f option as 1st line of script causes csh to startup in fast mode, i.e it reads nether the .cshrc nor the .login

2. .login: If you are in a login shell, then this file is the 2nd file sourced. after the .cshrc file.

3. .logout: This is the last executed on logging out (only from a login shell)

Simple csh script example: similar to bash, except for 1st line. Save it as test.csh.

#!/bin/csh -f

echo "hello"; => this cmd followed by args. Each line of csh is "cmd followed by args"

Run this script by doing "chmod 755 test.csh", and then typing ./test.csh.

csh itself has many options that can be provided on cmdline that controls it's behaviour.

ex: csh -f -v -x ... => many more options possible. -x is an important option that echoes cmds immediately before execution (this is useful for debug)

Csh Syntax:

csh is very similar to C in syntax. Similar to bash, we'll look at reserved keywords/cmds, variables and special char. On a single line, different tokens are separated by whitespace (tab, space or blank line). The following char don't need space to be identified as a separate token: &, &&, |, ||, <, <<, >, >>, ;, (, ). That's why many special char such as + need space around them since w/o a space, csh is not able to parse it into a token.

As in bash, each line in csh is a cmd followed by args for that cmd. Separate lines are separated by newline (enter key), semicolon (;) or control characters (similar to bash).

A. Commands: similar to bash, csh may have simple or complex cmds.

1. simple cmd: just as in bash, they can be built in or external cmd. Few ex:

  • alias: same as in bash, but syntax little different. Alias are usually put in initialization files like ~/.cshrc etc so that the shell sees all the aliases (instead of typing them each time or sourcing the alias file). One caveat to note is that Aliases are not inherited by child processes, so any csh script that you run will not inherit these alias until you redefine these alias again in your script.
    • ex: alias e 'emacs'. => NOTE no "=" sign here (diff than bash where we had = sign). Now we can type "e" on cmd line and it will get replaced by emacs and so emacs will open.

2. complex/compound cmd: They are cmds as if-else, while, etc. They are explained later.

B. Variable: csh needs "set" cmd to set variables, unlike bash which just uses "=". Everything else is same. $ is used to get value of a variable assigned previously. There are 2 kinds of var: global and local var

1. local var: local vars are assigned using set and "=" sign, i.e set var = value. NOTE: we can use spaces around = sign, unlike bash where no spaces were allowed. This is because "set" keyword is the assignment cmd, and rest is arg, so spaces don't matter. In bash, the whole assignment thing was a cmd.

set libsdir = "/sim/proj/"$USER"/digtop_$1" => spaces around = sign. $ inside double quotes or outside, is always expanded.
echo "myincalibs = " $libsdir => prints: myincalibs = /sim/proj/ashish/digtop_abcd

2. global var: For global var, we need to use "setenv" and no = sign. i.e: setenv HOME /home/ashish. No separate "export" cmd needed (as in bash). setenv cmd by itself does export too, so that the var is accessible to subshells. To see list of global var, we can use cmd "setenv" by itself with no args (we can also use env and printenv cmds from bash). Most of the global vars such as HOME, PATH, etc are same as those in bash.

setenv RTL_FILES "${DIGWORK}_user/design/svfiles.f" => {} allows the var inside braces only to be used for $ subs. NOTE: no = sign. setenv (rather than set) is used for global var (we used setenv so that this variable can be used in other scripts running from same shell).

$? => this checks for existence of a var. i.e $?HOME will return 1 (implying var exists), while $?temp123 will return 0 (implying var doesn't exist). This has different meaning in bash, where it expands to exit staus of most recently executed foreground pipeline. So, $?HOME will return 0HOME if the cmd run just before this was a success, or return 127HOME if cmd run just before this was in error, where 127 is the error code

prompt: Terminals with csh usually show a "%" sign as prompt. setting prompt in csh is same as setting other global vars. To set prompt in csh, we use keyword prompt instead of PS1. However, prompt keyword itself doesn't work in many c shells.

echo $prompt => on my centos laptop when in csh, it shows "%%[%n@%m %c]%#"
set prompt = " $cwd %h$ " => doesn't work at some corporations, as csh is actually tcsh (even though echo says its /bin/csh, installed pkg are always tcsh as tcsh is improved version of csh, and csh is just a soft link to tcsh), so use tcsh cmds. tcsh is backward compatible with csh, but somehow this cmd doesn't work. So, correct way would be:
set prompt = "[%/] > " => this worked on  m/c, but not guaranteed to work on others.

Data types: variables can be of diff data types. Looks like as in bash, primitive data types here are char string.

1. String: Everything is char string. It's internally interpreted as integer numbers depending on context.

ex: set a=12; set b=13; @ c= $a + $b; echo $c will print 12 +13=25 since it will treat those 2 var as integer. @ is special cmd used to assign a calculated value. For + to be treated as an arithmetic operator, there has to be space on both sides of +, else it will error out. NOTE: it doesn't use "set" cmd to assign a arithmetic calculated value.

ex: set a=12; set b=13; set c=$a+$b; echo $c will print "12+13", since it will treat the whole thing on RHS as a string (those 2 var and + are all string). NOTE: it uses "set" cmd here for string assignment.

ex: set d=jim => this assigns a string "jim" to var "d" even though it's not enclosed in double quotes. We would have needed to use single or double quotes if we had special char inside the RHS string as space, $, etc.

2. array: array contains multiple values. syntax same as in bash. However, here index start from 1 instead of 0 (in bash, index start from 0). Also, assciative array don't seem to work in csh.

ex: my_array=(one two three) => this assigns my_array[1]=one, my_array[2]=two and so on.

ex: echo $my_array[2] => this prints "two" even though curly braces are not used. Not sure why this works. NOTE: in bash, echo ${my_array[2]} was needed to print correctly. So, to be on safe side, always use curly braces around var to remove ambiguity.  "echo $my_array[0]" would print nothing as there is no index 0.

ex: echo $my_array => this would print all array, i.e "one two three", unlike bash, where it prints just the 1st element of array, i.e "one"

ex: set my_array[2]=one => If we do "echo $my_array[2]" it will print "one" as the array got overwritten at index=2.

ex: set me[1]="pat" => this doesn't work, as arrays can only be assigned via ( ... ). We can later change the value of any index of array using this syntax, but we can't define a new array using this. If we do "echo ${me[1]}" then it gives an error "me: Undefined variable" as csh looks for array "me" defined using parenthesis ( ... ) and tries to get value for index=0. In this case, "me" was never defined to be an array

ex: my_array[name]='ajay'; => associative array don't work in csh

C. Special Characters or metacharacters: This is mostly same as in bash. cmd line editing in bash was basically taken from csh, so all cmd line edit keys from bash work in csh.

special character usage:  special char are mostly same as in bash.

1. # => comment. This is single line comment. If you want to comment multiple lines, use "if" cmd explained later. As explained in "bash" scripting section, comment line is not completely ignored in csh, in contrast to bash. The "\" character at the end of comment line is looked at to figure out if the newline at the end of comment should be escaped or not. Comment is still ignored. So, very important to carefully look at any comment line, and put a backslash at end of it, if a regular cmd there would have needed a backslash. Look at backslash description in bullet 2 below. Let's look at an ex below:

ex: foreach dirname ( dir1 \

dir2 \

#dir3 \

)

In above ex, dir3 is commented out and has a "\" at end. So, the whole line until "\" is ignored. "\" at end escapes newline, so contents of next line are treated as part of same line. This is how it looks after expanding:

foreach dirname ( dir1 dir2 ) => Here "dir3" is completely ignored as it's in comment except for "\" which causes continuation of line 4 (closing barces) on line 3 itself. NOTE: \ at end is NOT continuation of comment, i.e it's not like this: foreach dirname ( dir1 dir2 #dir3 ) => this would have caused an error as closing brackets won't be seen by csh interpreter. This is not what happens in csh.

ex: The below ex causes a syntax error "Too many ('s". This is because closing bracket ) is seen on another line, so it's like this foreach dirname ( dir1 dir2 => so ) is not on same line resulting in error.

foreach dirname ( dir1 \

dir2 \

#dir3

)

 

2. " ' \ => same as in bash, they hide special char from shell.

I. Double Quotes " " : weak quoting

II. Single Quotes ' ': strong quoting

III. Backslash \ : hides all special characters from the shell, but it can hide only one character at a time. So, it can be used to hide newline character at end of line by putting backslash at end of line (this allows next line to be seen as part of current line). There is slight variation to this for the comment line as shown in example above (backslash at end of comment line is not seen as continuation of comment line).

3. End of cmd: Same as in bash, a newline character (by pressing enter/return) is used to denote end of 1 cmd line. For multiple cmds on same line, semicolon (;) can be used to separate multiple cmd. There has to be a space after semicolon, else parser will not see ; as a token.

Control operators: Same as in bash. Pipe cmd and list work same way.

4. source or . cmd: same as in bash

5. backquote or backtick (`): same as in bash. However, the o/p here is stored in an array, instead of a simple string

ex: a=`ls`; echo $a; => This will print the array a (as o/p of this is stored in array). To see individual elements of array, we can do $a[1], $a[2]. etc (NOTE: $a[0] is not valid as arrays start with index=1 in csh)

6A. user interaction: All languages provide some way of getting i/p from a user and dumping o/p. In bash, we can use these builtin cmds to do this:

Output cmds: echo cmd supported.

Input cmds: csh has "$<" for reading i/p.

ex: below cmd reads i/p from terminal and prints the o/p

echo -n Input your number:

set input = $<

echo You entered $input

6B.  IO redirection: same as in bash.

7. Brackets [ ] , braces { } and parenthesis ( ) : same as in bash. [] and {} are used in pattern matching using glob. All [], {}, () are used in pattern matching in BRE/ERE. See in regular expression section. However, they are used in other ways also:

I. single ( ) { } [ ]:

( ) { } => these are used to group cmds, to be executed as a single unit. parenthesis (list) causes all cmds in list to be executed in separate subshell, while curly braces { list; } causes them to be executed in same shell.

{ } => Braces { } are also used to unambiguously identify variables. They protect the var within {} as one var. { ..} is optional for simple parameter expansion (i.e $name is actually simplified form of ${name})

{ } can also be used for separate out a block of code. spaces should be used here. ex: a=3; { c=95; .... } echo $c;

[ ] => square brackets are used for globbing as explained above.

[ ] are also used to denote array elements as explained in array section above.

arithmetic operators: One of the most useful feature of csh, which is missing in bash, is that csh allows direct arithmetic operations. No "expr" cmd needed to do numeric arithmetic. These arithmetic operations can appear in @, if, while and exit cmds. Many of these operators below return boolean "true" or "false", but there is no inbuilt boolean type. i.e if (true) ... is invalid. An expr has to be used that evaluates to true or false.

  • number arithmetic: +, -, *, /, %, **(exponent), id++/id-- (post inc/dec), ++id/--id (pre inc/dec)
  • bitwise: &, |, ^(bitwise xor), ~(bitwise negation), <<(left shift), >>(right shift). ~ is also used as expansion to home dir name.
  • logical: &&, ||, !(logical negation)
  • string comparison: ==(equality), !=(inequality),  These are not arithmetic comparisons but lexicographical (alphabetic) comparisons on strings, based on ASCII numbering. Here RHS has to be a string and not a pattern.
  • <=, >=, < ,>. => these operate on numbers (unlike bash, where these operate on string, and -lt, -ge, etc were used instead to compare numbers)
  • assignment: =(assigns RHS to LHS), *=, /= %= += -= <<= >>= &= ^= |= => these are assigments where RHS is operated on by the operator before =, and then assigned to LHS (i.e a*=b; is same as a=a*b.
  • matching: =~ this is a matching operator (similar to perl syntax) where string on RHS is considered ERE, and is matched with string on LHS. ex: [ $line =~ *?(a)b ] => returns true if string contains the pattern
    • seems like .* for ERE is not honored, but rather just plain * as used in glob. ex: $name =~ raj_.* doesn't match raj_kumar, but $name =~ raj_* (w/o the dot) does match raj_kumar
  • non matching: !~ this is non matching operator, where string on RHS is considered ERE. returns true  if strings doesn't contain the pattern.
  • condional  evaluation: expr ? expr1 : expr2 => similar to C if else stmt
  • comma : comma is used as separator b/w expr

ex: @ c=$a + $b; => @ needed to do arithmetc. No "set" cmd needed.

ex: @ num = 2 => this assigns numeric value 2 to num. If we used "set num = 2" then it assigns num to string 2. It may then still be interpreted as num or string depending on how it's used later.

ex: @ i++ => increments var i by 1

ex: if ($a < $b) echo "a < b"

II. double (( )) {{ }} [[ ]] => no known usage in csh

8. pattern matching: same as in bash

9. looping constructs: These 2 cmds used to form loops: foreach and while. "break" and "continue" builins are used to control loop execution, and have same behaviour as in bash. break exits the loop, not the script. continue continues the loop w/o going thru the remaining stmt in loop that are after continue.

  • foreach: It's a loop where the variable name is successively set to each member of wordlist and the sequence of commands until the matching end statement are executed. Both foreach and end must appear alone on separate lines.  syntax:
    • foreach name (wordlist)
               commands
           end
    • ex:
      foreach color (red orange yellow green blue)
              echo $color
           end
  • while: Just like foreach, it's a loop Statements within the while/end loop are conditionally executed based upon the evaluation of the expression. Both while and end must appear alone on separate lines.syntax:
    • while (expression)
               commands
           end
    • ex: set word = "anything"
           while ($word != "")
             echo -n "Enter a word to check (Return to exit): "
             set word = $<
             if ($word != "") grep $word /usr/share/dict/words
           end
  • break / continue: these are used in foreach or while loop statements above. "break" terminates execution of loop, and transfers control to stmt after the end stmt, while "continue" transfers control to the end stmt. So, "break" forces the pgm to exit the loop, while "continue" keeps on continuing with next iteration of loop (while skipping stmt in the loop that come after continue).
    • foreach number (one two three exit four)
             if ($number == exit) then
               echo reached an exit
               break (or use continue. break takes ctl to stmt right after "end" stmt, while continue takes it back to beginning of loop, to start with next iteration)
             endif
             echo $number
           end

10. Conditional constructs: same as in bash, syntax slightly different. Also these are closer to C lang in syntax, and have switch.

  • if-else: There are 2 variants of if cmd: A. if without else B. if with else
    •  if => if (expr) command [arguments] => here cmd must be a simple cmd, not piped cmds. There is no else clause.
      • ex: if ($#argv == 0) echo There are no arguments => all in one line
      • ex: if (-d $dirname) echo "dir exists" => this checks for existence of dir. options supported for existence of files/dir are same as those in bash
    •  if-then-else => if (expr) then (cmd1) else (cmd2) endif . There may be multiple else clauses here. "then" and "endif" are required in this form of if-else.
      • ex: if ($number < 0) then  
                   @ class = 0  
                else if (0 <= $number && $number < 100) then  
                   @ class = 1      
                else  
                   @ class = 3  
                endif
      • if ($dat == $vrfir) then => Note no semicolon used. == used (as in C)
          echo foo
        else => optional
          echo bar!
        endif
      • if-then may be used for multi line comments. ex: set debug=1; if ($debug == 1) then ........ endif
      • if (!(-e ${AMS_DIR}/net.v)) then ... else ... endif => checks for existence of a file. same options as in bash.
  • switch case: The switch structure permits you to set up a series of tests and conditionally executed commands based upon the value of a string. If none of the labels match before a `default' label is found, then the execution begins after the default label.  Each case has "breaksw" cmd at end of case that causes execution to continue after the endsw. Otherwise control may fall through case labels and default label may execute if there is no "breaksw". Also, the patterns for each case may contain ? and * to match groups of characters or specific characters. syntax is as follows:
    • switch (string)
        case pattern1:
          commands...
          breaksw
        case pattern2:
          commands...
          breaksw
        default:
          commands...
          breaksw
      endsw
    • ex: if ($#argv == 0 ) then
              echo "No arguments supplied...exiting"
              exit 1
           else 
              switch ($argv[1])
              case [yY][eE][sS]:
                echo Argument one is yes.
                breaksw
              case [nN][oO]:
                echo Argument one is no.
                breaksw
              default:
                echo Argument one is neither yes nor no.
                breaksw
              endsw
           endif
  • goto: The goto statement transfers control to the statement beginning with label:
    •      if ($#argv != 1) goto error1
           goto OK
           error1:
             echo "Invalid - wrong number or no arguments"
             echo "Quitting"
             exit 1
           OK:
             echo "Argument = $argv[1]"
             exit 1
    • if (.$RUN == ams) goto ams_run
      ....
      ams_run: => control transferred here
      ....
      exit

    •  goto is usually used to print usage info of a script when number of args is insufficient
      if ($#argv < 3) then
      goto usage
      else ... endif => process cmd line args
      usage:
      echo " shows usage of cmd" => This prints usage info for that script when cmd is typed
      exit

 
Advanced csh cmds: Read on csh links on top for more on this.