MATLAB made me feel like a GOD

Forgive me for the caption, but I am aware of MATLAB's reputation being everyone's favorite, ( MATLAB is favored by only 20% of it's users ) but I have been using it heavily in my Electronics Engineering courses. { MATLAB is so bad that even Hashnode didn't provide syntax highlighting for it's codes }

Problem

I was transmitting 5 unique signals and receiving them through a speaker kept at a distance of 3m, then 5m, then 7m. So I had a total of 15 audio signals received and had them all names as :-

  • "3_r1.wav"

  • "3_r2.wav"

  • "3_r3.wav"

  • "3_r4.wav"

  • "3_r5.wav"

and so on for the other 2 sets of audio files.

So this is what I had to do, for each of the 15 signals :-

Get a figure with subplots of

  1. Transmitted signal's time domain representation

  2. Transmitted signal's frequency profile

  3. Received signal's entire time domain representation

  4. Received signal's frequency profile

  5. Received signal's time domain but magnified

  6. Generate an EPS file for report

The plot for this transmitted signal when received at a distance of 3m is given below.

$$y = 0.8 \times \text{sawtooth}(2 \pi \times 2000 \times t)$$

I had to do this for each of the 15 signals.

And the code that I wrote to d0 this ( apart from being ugly and cluttered, since this was done in a hurry ) had too many places where I need to make to change to generate the figure of next signal.

( You don't have to read this to understand the solution, that I got ; The intent was only to show it was pretty hard to get figure of one single figure )

clc ;
clear;
close all ;


% DO THIS FOR EACH OF SIGNALS FIRST
$ - change the file_name of audio.wav
% - change y
% - change color of plot
% - change y_interval
% - chagne the title of each subplot accordingly


fs_ = 48000;
duration_ = 10;
t__ = linspace(0,duration_ ,fs_ * duration_);
y = 0.8*sawtooth(2 * pi * 2000 * t__, 0.5);


% Define the time interval for clearer visualization
start_time = 5;  
end_time = 5.005;
duration = end_time - start_time; 

% Generate time vector for the specified interval
t_interval = linspace(start_time, end_time, fs_ * duration);
y_interval = 0.8*sawtooth(2 * pi * 2000 * t_interval, 0.5);

% Load the WAV file
[y, fs] = audioread('./DSP project/3_r4.wav');% Calculate the time axis
num_samples = length(y);
time_axis = (0:num_samples-1) / fs;


Y = fftshift(fft(y));
f_axis = -fs/2:fs/(length(Y)-1):fs/2;
f_axis = f_axis';


% Convert start and end times to sample indices 
start_index = round(start_time * fs) + 1;
end_index = round(end_time * fs);

% Extract samples from the specified time range
y_subset = y(start_index:end_index);
time_subset = time_axis(start_index:end_index);


figure('NumberTitle', 'off', 'Name', 'This is the figure title');

subplot(5,1,1);
plot(t_interval, y_interval, 'm');
title('Time Domain - Signal 1');
xlabel('Time (s)');
ylabel('Amplitude');
title('Time-domain representation of Transmitted signal');

% Plot the frequency-domain representation
subplot(5,1,2);
Y1 = fftshift(fft(y));
frequencies = linspace(-fs/2, fs/2, length(Y1));
plot(frequencies, abs(Y1), 'm');
title('Frequency Domain - Signal 1');
xlabel('Frequency (Hz)');
ylabel('Magnitude');
title('Frequency-domain representation of Transmitted signal');


% Plot the time-domain representation
subplot(5,1,3);
plot(time_axis, y,'k');
xlabel('Time (seconds)');
ylabel('Amplitude');
title('Time-domain representation of Recieved signal at 3m');


% Plot the frequency-domain representation
subplot(5,1,4);
plot(f_axis, abs(Y),'k');
xlabel('Frequency (Hz)');
ylabel('Magnitude');
title('Frequency-domain representation of Recieved signal at 3m');

% Plot the subset of the time signal
subplot(5,1,5);
plot(time_subset, y_subset,'k');
xlabel('Time (seconds)');
ylabel('Amplitude');
title('A very small subset of time domain signal for clarity');

print(gcf, '-depsc', '3_4.eps');

I ran the code for first 2 signals and it took 20 minutes. But I had fixed all the bugs and had the code pretty much all-set with changes having to only at the below 4 places.

Friction created

% DO THIS FOR EACH OF SIGNALS FIRST

$ - change the file_name of audio.wav
% - change y
% - change color of plot
% - change y_interval
% - chagne the title of each subplot accordingly

It would have only taken 5 minutes to get the remaining 13 figures.

But,

I am an engineer,

that means I gotta :-

Spend another half an hour trying to automate something that would only take me one-third of the time trying to figure out how to automate.

So I spend next half an hour trying to automate the entire process.

Solution : Power of Array of Anonymous functions

My computer science undergrad peers and other tech influencers love to talk about this coding principle :-

DRY : Don't repeat yourself

The solution that I came up ( totally not using Chat-GPT ) upholds that very principle ( but not in the way it's traditionally implemented with the functional blocks, etc. )


% 3 automation magic :-

% 1
signals = {@(t) 1*cos(2*pi*5000*t), ...
           @(t) 0.9*sin(2*pi*1000*t), ...
           @(t) 0.5*sin(2*pi*3000*t)+0.3*cos(2*pi*6000*t), ...
           @(t) 0.8*sawtooth(2 * pi * 2000 * t, 0.5), ...
           @(t) 0.3*cos(2*pi*5000*t) + 0.1 * randn(size(t))};

% 2
colors = {'r', 'g', 'b', 'm', 'c'};


% 3
received_files = {'./DSP_PROJECT/3_r1.wav', ...
                  './DSP_PROJECT/3_r2.wav', ...
                  './DSP_PROJECT/3_r3.wav', ...
                  './DSP_PROJECT/3_r4.wav', ...
                  './DSP_PROJECT/3_r5.wav'};

Signals is an array of anonymous functions.

Now I could -

    y = signals{i}(t);

and get it's corresponding color by :-

plot(frequencies, abs(Y), colors{i});

And string manipulate in titles according to the value of `i`

So here is the code that made me feel like God :-

clc;
clear;
close all;

% 3 automation magic :-

% 1
signals = {@(t) 1*cos(2*pi*5000*t), ...
           @(t) 0.9*sin(2*pi*1000*t), ...
           @(t) 0.5*sin(2*pi*3000*t)+0.3*cos(2*pi*6000*t), ...
           @(t) 0.8*sawtooth(2 * pi * 2000 * t, 0.5), ...
           @(t) 0.3*cos(2*pi*5000*t) + 0.1 * randn(size(t))};

% 2
colors = {'r', 'g', 'b', 'm', 'c'};


% 3
received_files = {'./DSP_PROJECT__1/3_r1.wav', ...
                  './DSP_PROJECT__1/3_r2.wav', ...
                  './DSP_PROJECT__1/3_r3.wav', ...
                  './DSP_PROJECT__1/3_r4.wav', ...
                  './DSP_PROJECT__1/3_r5.wav'};


for i = 1:numel(signals)

    fs_generated = 48000;
    duration_ = 10;
    t = linspace(0,duration_ ,fs_generated * duration_);
    y1 = signals{i}(t);


    % Time interval for clearer Visualization
    start_time = 4;  
    end_time = 4.002;
    duration = end_time - start_time; 

    % Generating time vector for THAT specified interval
    t1_interval = linspace(start_time, end_time, fs_generated * duration);
    y1_interval = signals{i}(t1_interval);

    % Define subplot title according to signal
    subplot_title = sprintf('Signal - %d', i);

    % Plot time-domain representation of TRANSMITTED SIGNAL
    figure;
    subplot(5, 1, 1);
    plot(t1_interval, y1_interval, colors{i});
    title(['Time Domain - ' subplot_title]);
    xlabel('Time (s)');
    ylabel('Amplitude');


    % Plot frequency-domain representation of TRANSMITTED SIGNAL
    subplot(5, 1, 2);

    Y1 = fftshift(fft(y1));
    frequencies = linspace(-fs_generated/2, fs_generated/2, length(Y1));

    plot(frequencies, abs(Y1), colors{i});
    title(['Frequency Domain - ' subplot_title]);
    xlabel('Frequency (Hz)');
    ylabel('Magnitude');


    % Read received signal and extract subset
    [y_received, fs_received] = audioread(received_files{i});
    num_samples = length(y_received);
    time_axis_received = (0:num_samples-1) / fs_received;

    % Plot time domain of RECEIVED SIGNAL
    subplot(5, 1, 3);
    plot(time_axis_received, y_received, 'k');
    xlabel('Time (s)');
    ylabel('Amplitude');
    title(['Time-domain representation of Received signal at 3m - ' subplot_title]);


    Y_received = fftshift(fft(y_received));
    f_axis_received = -fs_received/2 : fs_received/(length(Y_received)-1) : fs_received/2;
    f_axis_received = f_axis_received';

    subplot(5, 1, 4);
    plot(f_axis_received, abs(Y_received), 'k');
    xlabel('Frequency (Hz)');
    ylabel('Magnitude');
    title(['Frequency-domain representation of Received signal at 3m - ' subplot_title]);


    % Indexes corresponding to start and end time
    start_index = round(start_time * fs_received ) + 1;
    end_index = round(end_time * fs_received );

    % Extract samples from the specified time range
    y_subset = y_received(start_index:end_index);
    time_subset = time_axis_received(start_index:end_index);   

    subplot(5, 1, 5);
    plot(time_subset, y_subset, 'k');
    xlabel('Time (s)');
    ylabel('Amplitude');
    title(['Subset of Received signal for clarity - ' subplot_title]);


    % Save figure as EPS file
    print(gcf, '-depsc', sprintf('1_%d.eps', i));


end

This was my first blog and I realize it was pretty bad.

The intent of this Diary is purely to keep a public journal of my growth, I need to put in way more effort if my aim was to contribute something meaningful, and I believe I have a long way still to go. But let's see how long I can keep this up.

Any correction, or comments are appreciated,

Thank you for reading my dumpster fire.