% Written by: Daniel Llamocca (2013)
% Indexing Discrete-time signals in MATLAB:
clear all; close all ; clc;

% We first show how we generated a sampled sinusoid and why working out
% most operations on the sinusoid does not create any problems.

% Generating vector of samples:
  n = -20:20; % [-20 -19.... 20]

% Creating the input signal x[n]:
  x = sin(n/10); % 'n/10' instead of 'n' already explained
  % we have x[n] = (sin(-20/10) sin(-19/10) sin(-18/10) ... sin(20/10))  
  %   for     n  =      -20          -19        -18     ...     20
  
  figure; stem (n,x,'b.');
  
% MATLAB does NOT allow signal's indices lower than 1!!!!
% 'stem' displays it correctly, because 'n' and 'x' are considered simple
% vectors plotted one against the other

% We cannot make x(-20)! --> try it
% The signal 'x' has indices from 1 to length(n)
% Then for a certain 'n', x[n] is in MATLAB actually x(n+L), where L is the
% number of samples whose n is < 1, i.e. L = 21
% disp (x); % see how it appears in the MATLAB command window
  
% If we would like to do time shifting, we just replace 'n' by 'n-m'
  m = 8;
  y = sin((n-m)/10); % it works for values < 0, since 'sin' is a function
                     % defined for all real numbers, we are not indexing any vector here
  figure; stem (n,x,'b.');

  
% ***********************************************************************
%  Dealing with the fact ahat MATLAB does not allow indices lower than 1
% ***********************************************************************

% What if we want to create a signal by specifying it point by point?
  n = -4:4; % [-4 -3 -2 -1 0 1 2 3 4]
  x = [0 0 3 2 1 2 3 0 0]; % x[n] is defined only for integer numbers
  figure; stem (n,x,'r.'); title ('x[n]');

% What if we want y[n] = n*x[n]?
  % Notice that:  L = 5 (# of samples whose n is < 1)
  % n    : -4  -3   -2   -1    0    1    2    3    4
  % x[n] :  0   0    3    2    1    2    3    0    0
  %       x(1) x(2) x(3) x(4) x(5) x(6) x(7) x(8) x(9)  (in MATLAB)
  
  % So, x(n+5) (MATLAB) is equivalent to x[n] (our definition)

  %y = n*x(n); % This WILL NOT work!... x(-4), .. x(0) are not defined in MATLAB
  y = n.*x(n+5); % n*x(n+5) is equivalent to n*x[n]
                 % The operator .* means multiplying a vector element-wise
  
  figure; stem (n,y,'b.'); title ('n*x[n]');
  
  
% A more complicated case: What if we now want z[n] = x[k*n - m]?
% =======================
% As in the case of y[n]=n*x[n], this problem seems like it could easily
% be solved by: z = x(n*k + m + 5)

% However, the main problem is that x[n] is of finite-size duration.
% When computing x[k*n-m], we will generate indices that are outside of the
% range of 'x'. This is true even if we are only either shifting (x[n-m])
% or scaling (x[k*n])

% The most common workaround is to assume that 'x' at the indices outside 
% of the range are zero.
% So, it seems that we can just pad more zeros into 'x'. However, x[k*n +m]
% guarantees that there will always be indices outside of the range of 'x'.
% Thus, the problem has to be dealt with in a different (though cumbersome
% manner). This will apply to any computation that requires the shifted
% versions of 'x':

% Shifting and scaling: First shifting, then Scaling
% Thus, we generate 'v[n] = x[n-m]' and 'z[n]=v[k*n]' one after the other.

% Shifting x[n] by m: We will get v[n] = x[n-m]
  m = 2; % we picked this value so that when shifting, we don't lose any
         % value in our 9-sample input (x[n], n=-4:4). We could have picked
         % any value actually.

  % n      : -4  -3   -2   -1    0    1    2    3    4
  % x[n]   :  0   0    3    2    1    2    3    0    0
  %         x(1) x(2) x(3) x(4) x(5) x(6) x(7) x(8) x(9)  (in MATLAB)
  %
  % x[n-2] :  0   0    0    0    3    2    1    2    3 
  % v[n]   :  0   0    0    0    3    2    1    2    3
  %   n    : -4  -3   -2   -1    0    1    2    3    4 
  %         v(1) v(2) v(3) v(4) v(5) v(6) v(7) v(8) v(9)  (in MATLAB)
  
  k = 2;
  % The values outside the range of the input signal are assigned zero.
  for i = 1:length(n)
      if (n(i) + 5 + m > n(length(n)) + 5)
          v(i) = 0;
      else
          v(i) = x(n(i) + 5 + m); % We are always off by '+5'
          % If we shift by 'm', we move 'm' samples to the right
      end
  end
  for i = 1:length(n)    
      if (n(i)*k + 5 < 1) || (n(i)*k + 5 > n(length(n)) + 5)
          z(i) = 0;
      else
          z(i) = v(n(i)*k + 5); % We are always off by '+5'
          % Example:  n(i) = -2 --> z[-2] = v[-2*2] = v[-4]
          %                However: v[-4] = v(-4+5) = v(1)
          %                         z[-2] = z(-2+5) = z(3)
          
      end
  end 
  
  figure; stem(n,z,'k.'); title ('x[k*n +m]');
