DFT Example Software Implementation

This section demonstrates the implementation of a previously solved example in MATLAB, Python, and C. It reconstructs the input signal - comprising a DC component and two sinusoidal components, computes its Discrete Fourier Transform, analyzes the resulting frequency components (amplitudes and phases), and visualizes the results.

MATLAB#


%% Create Input Signal

% Define input components: DC and two sinusoidal signals
A   = [-1   3    2];  % Amplitudes (V)
f   = [0    1    3];  % Frequencies (Hz)
phi = [pi/2 pi/4 0];  % Phases (rad)

T   = 1;   % Signal duration (s)
fs  = 8;   % Sampling frequency (Hz)

% Create sampled signal
N = T * fs;         % Number of samples
n = (0 : N-1)';     % Sample indices

% Initialize signal array
x = zeros(N, 1);  

% Construct the signal as a sum of sinusoids
for i = 1 : length(A)
    x = x + A(i) * sin(2 * pi * f(i) * n / fs + phi(i));
end

%% Compute DFT
[a, b] = dft(x);  % Compute DFT

% Set very small values to 0 to mitigate numerical errors
threshold = 1e-10;
a(abs(a) < threshold) = 0;
b(abs(b) < threshold) = 0;

%% Analyze Frequency Components
Amp = sqrt(a.^2 + b.^2);   % Compute amplitude of signal components
Amp(1) = a(1) / 2;         % DC component amplitude correction

phase = atan(a./b);         % Compute phase (corrected formula)
phase(1) = NaN;             % Set DC component phase to NaN

% Frequency axis adjustment for visualization
frq = (-N/2 : N/2-1) / N * fs; 
Amp = fftshift(Amp);       % Rearrange amplitudes for proper frequency order
phase = fftshift(phase);   % Rearrange phases for proper frequency order

%% Plot Amplitude and Phase Spectra
figure;
subplot(2,1,1);
stem(frq, Amp, 'filled');
xlabel('Frequency (Hz)'); ylabel('Amplitude (V)');
title('Amplitude Spectrum'); grid on;

subplot(2,1,2);
stem(frq, phase, 'filled');
xlabel('Frequency (Hz)'); ylabel('Phase (rad)');
title('Phase Spectrum'); grid on;

%% DFT Function Implementation
function [a, b] = dft(x)
% Compute the Discrete Fourier Transform (DFT) of a real input signal
    N = length(x);         % Number of samples
    n = 0 : N-1;           % Sample indices
    phi = 2 * pi * (n' * n) / N;  % Compute angles for DFT matrix  

    % Compute cosine and sine frequency components
    a = (2 / N) * cos(phi) * x;  
    b = (2 / N) * sin(phi) * x;  
end

Python#


import numpy as np
import matplotlib.pyplot as plt

# Create Input Signal

# Define input components: DC and two sinusoidal signals
A = np.array([-1, 3, 2])     # Amplitudes (V)
f = np.array([0, 1, 3])      # Frequencies (Hz)
phi = np.array([np.pi/2, np.pi/4, 0])  # Phases (rad)

T = 1    # Signal duration (s)
fs = 8   # Sampling frequency (Hz)

# Create sampled signal
N = int(T * fs)    # Number of samples
n = np.arange(N)   # Sample indices

# Initialize signal array
x = np.zeros(N)

# Construct the signal as a sum of sinusoids
for i in range(len(A)):
    x += A[i] * np.sin(2 * np.pi * f[i] * n / fs + phi[i])

# Compute DFT
def dft(x):
    """ Compute the Discrete Fourier Transform (DFT) of a real input signal. """
    N = len(x)
    n = np.arange(N).reshape(1, N) # Create row vector
    phi = 2 * np.pi * n.T * n / N  # Compute angles for DFT matrix

    # Compute cosine and sine frequency components
    a = (2 / N) * np.dot(np.cos(phi), x)
    b = (2 / N) * np.dot(np.sin(phi), x)
    return a, b

a, b = dft(x)  # Compute DFT

# Set very small values to 0 to mitigate numerical errors
threshold = 1e-10
a[np.abs(a) < threshold] = 0
b[np.abs(b) < threshold] = 0

# Analyze Frequency Components
Amp = np.sqrt(a**2 + b**2)   # Compute amplitude of signal components
Amp[0] = a[0] / 2            # DC component amplitude correction

phase = np.arctan(a/b)       # Compute phase (corrected formula)
phase[0] = np.nan            # Set DC component phase to NaN

# Frequency axis adjustment for visualization
frq = np.fft.fftfreq(N, d=1/fs)  # Compute frequency axis
frq = np.fft.fftshift(frq)       # Rearrange for plotting
Amp = np.fft.fftshift(Amp)       # Rearrange amplitudes
phase = np.fft.fftshift(phase)   # Rearrange phases

# Plot Amplitude and Phase Spectra
plt.figure(figsize=(10, 6))

plt.subplot(2, 1, 1)
markerline, stemline, baseline = plt.stem(frq, Amp, linefmt='b', markerfmt='bo', basefmt="k-")
plt.xlabel('Frequency (Hz)')
plt.ylabel('Amplitude (V)')
plt.title('Amplitude Spectrum')
plt.grid()

plt.subplot(2, 1, 2)
markerline, stemline, baseline = plt.stem(frq, phase, linefmt='r', markerfmt='ro', basefmt="k-")
plt.xlabel('Frequency (Hz)')
plt.ylabel('Phase (rad)')
plt.title('Phase Spectrum')
plt.grid()

plt.tight_layout()
plt.show()


C#

The C code was developed using the Code::Blocks IDE as a Console Application. The results are stored in .dat files, which can be visualized using GNUplot for analysis and comparison.


#include <stdio.h>
#include <stdlib.h.h>
#include <math.h>

#define PI 3.14159265358979323846
#define FS 8        // Sampling frequency (Hz)
#define T 1         // Signal duration (s)
//#define N (FS * T)  // Number of samples


// DFT Function
void dft(double x[], double a[], double b[], int N) {
    // Compute DFT of a real input signal
    for (int k = 0; k < N; k++) {
        a[k] = 0.0;
        b[k] = 0.0;
        for (int n = 0; n < N; n++) {
            double phi = 2 * PI * k * n / N;
            a[k] += (2.0 / N) * x[n] * cos(phi);
            b[k] += (2.0 / N) * x[n] * sin(phi);
        }
    }
}

// FFT Shift (Rearrange Frequency Components)
void fftshift(double arr[], int N) {
    int half = N / 2;
    double temp;

    for (int i = 0; i < half; i++) {
        temp = arr[i];
        arr[i] = arr[i + half];
        arr[i + half] = temp;
    }
}

int main() {
    int N = FS * T; // Number of samples
    int L;          // Number of input signals

    // Define input components: DC and two sinusoidal signals
    double A[] = {-1, 3, 2};          // Amplitudes (V)
    double f[] = {0, 1, 3};           // Frequencies (Hz)
    double phi[] = {PI/2, PI/4, 0};   // Phases (rad)

    double x[N];                      // Sampled signal array
    double a[N], b[N];                // DFT cosine and sine coefficients
    double Amp[N], phase[N], frq[N];  // Amplitude and phase spectra

    // Generate sampled signal
    L = sizeof(A) / sizeof(A[0]);
    for (int n = 0; n < N; n++) {
        x[n] = 0;
        for (int i = 0; i < L; i++) {
            x[n] += A[i] * sin(2 * PI * f[i] * n / FS + phi[i]);
        }
    }

    // Compute DFT
    dft(x, a, b, N);

    // Eliminate very small numerical errors
    for (int k = 0; k < N; k++) {
        if (fabs(a[k]) < 1e-10) a[k] = 0;
        if (fabs(b[k]) < 1e-10) b[k] = 0;
    }

    // Compute amplitude and phase spectra
    for (int k = 0; k < N; k++) {
        Amp[k] = sqrt(a[k] * a[k] + b[k] * b[k]);  // Magnitude
        if (k == 0) {
            Amp[k] = a[k] / 2;  // DC component correction
            phase[k] = 0;       // DC phase is undefined
        } else {
            if (b[k] == 0) {
                phase[k] = 0;   // Division by 0
            } else {
                phase[k] = atan(a[k]/b[k]);  // Compute phase
            }
        }
    }

    // Frequency axis
    for (int k = 0; k < N; k++) {
        frq[k] = ((k - N / 2) * FS) / (double)N;
    }

    // Apply FFT Shift to rearrange amplitude and phase spectra
    fftshift(Amp, N);
    fftshift(phase, N);



    // Print results
    printf("Amplitude values:\n");
    for (int i = 0; i < N; i++) {
        printf("Amplitude[%d] = %f\n", i, Amp[i]);
    }

    printf("\nPhase values:\n");
    for (int i = 0; i < N; i++) {
        printf("Phase[%d] = %f\n", i, phase[i]);
    }

    printf("\nFrequencies:\n");
    for (int i = 0; i < N; i++) {
        printf("Frequency[%d] = %f\n", i, frq[i]);
    }

    // Save data to files for later visualization
    FILE *amp_file = fopen("amplitude_spectrum.dat", "w");
    FILE *phase_file = fopen("phase_spectrum.dat", "w");

    for (int k = 0; k < N; k++) {
        fprintf(amp_file, "%lf %lf\n", frq[k], Amp[k]);
        fprintf(phase_file, "%lf %lf\n", frq[k], phase[k]);
    }

    fclose(amp_file);
    fclose(phase_file);

    // visualize
    printf("\nUse GNUplot to visualize:\n");
    printf("gnuplot -e \"plot 'amplitude_spectrum.dat' with linespoints title 'Amplitude Spectrum'\"\n");
    printf("gnuplot -e \"plot 'phase_spectrum.dat' with linespoints title 'Phase Spectrum'\"\n");

    return 0;
}

Visualization

  1. Open command prompt (Windows)
  2. Check if GNUplot is installed using:
  3. 
    where gnuplot
    

    or

    
    gnuplot --version
    

    If GNUplot is not installed, download and install it, ensuring the "Add to system PATH" option is selected during installation.

  4. Navigate to the folder with '.dat' files using 'cd' command:
  5. 
    cd C:\path\to\your\folder
    

    Replace 'C:\path\to\your\folder' with the actual folder path.

  6. If the folder is on a different drive (e.g., D:), first switch to that drive:
  7. D:
    
    cd path\to\your\folder
    

  8. Verify the files exist by listing them:
  9. dir
    

  10. Open GNUplot by running:
  11. gnuplot
    

    This should open the GNUplot command-line interface.

  12. To plot the Amplitude Spectrum, type inside the GNUplot interface:
  13. set xlabel 'Frequency (Hz)'
    set ylabel 'Amplitude (V)'
    set grid
    plot 'amplitude_spectrum.dat' with impulses title 'Amplitude Spectrum'
    
    Amplitude Spectrum
  14. To plot the Phase Spectrum, type inside the GNUplot interface:
  15. set xlabel 'Frequency (Hz)'
    set ylabel 'Phase (rad)'
    set grid
    plot 'phase_spectrum.dat' with impulses title 'Amplitude Spectrum'
    
    Phase Spectrum
  16. To plot both graphs in one window:
  17. set multiplot layout 2,1 title "DFT Analysis"
    set xlabel 'Frequency (Hz)'
    set ylabel 'Amplitude (V)'
    set grid
    plot 'amplitude_spectrum.dat' with impulses title 'Amplitude Spectrum'
    
    set xlabel 'Frequency (Hz)'
    set ylabel 'Phase (rad)'
    set grid
    plot 'phase_spectrum.dat' with impulses title 'Phase Spectrum'
    unset multiplot
    
    Amplitude and Phase Spectrum
  18. To save the Amplitude Spectrum in the current directory, type inside the GNUplot interface:
  19. set terminal png
    set output 'amplitude_spectrum.png'
    set xlabel 'Frequency (Hz)'
    set ylabel 'Amplitude (V)'
    set grid
    plot 'amplitude_spectrum.dat' with impulses title 'Amplitude Spectrum'
    set output
    

  20. To exit GNUplot, type:
  21. quit