% Activity:  Structural Vibration Analysis: Student Activity Guide 🏗️

% 🏗️ Structural Vibration Analysis: Student Activity Guide 🏗️?
% 📝 Author: Edwin Marte
% 🚧

% Objective:
% In this activity, you will analyze sensor data from a structure (such as a bridge or building) to detect and visualize vibration patterns. You will calculate key metrics such as natural frequency, damping ratio, and vibration modes to assess the structure's performance and identify potential issues. 🚧
%
% 💡 Why This Activity?
% ✅ Hands-on experience in signal processing.
% ✅ No machine learning required—perfect for understanding practical applications in structural engineering.
% ✅ Real-world applications in civil engineering.
% ✅ Critical skills development in data analysis and interpretation.
% 🕒 Activity Overview:
% Load Vibration Data
% Data Preprocessing & Exploration
% Time-Domain Analysis
% Frequency-Domain Analysis
% Vibration Mode Analysis
% Conclusion & Discussion
% 📊 Data File:  vibration_data.csv
% 📊 Student Template (for your analysis)
%
% 🔬 Student Activity:
% 1. Data Preprocessing:
% Fill Missing Data: (Use interpolation, average, or forward fill as appropriate.)
% Outliers:     Identify and handle outliers (e.g., values above/below a specific threshold).
% 2. Visualize Vibration Patterns:
% Plot time vs. sensor data for each sensor (Sensor1, Sensor2, etc.).
% 3. Time-Domain Analysis:
%
% . Frequency-Domain Analysis:
% Apply FFT to get the frequency spectrum.
% Identify dominant frequencies and compare with natural frequency values.
% 5. Vibration Mode Analysis:
% Analyze the mode shapes and determine the vibration modes.
% Compare with theoretical mode shapes or known values.
% 📂 Step 1: Load Data 📊

clc; clear; close all;
% Load vibration data
data = readtable('vibration_data.csv'); % Replace with your file path


%

% 🔍 Display first few rows
head(data)

%
% 📊 Step 2: Data Preprocessing & Exploration
%  Handle Missing Data: In Matlab, you can use fillmissing() to handle missing values (e.g., fill with previous or next data point).

% Fill missing data using previous value
data.Sensor1 = fillmissing(data.Sensor1, 'previous');
data.Sensor2 = fillmissing(data.Sensor2, 'previous');
data.Sensor3 = fillmissing(data.Sensor3, 'previous');


%  Visualize Vibration Patterns:

%Plot vibration patterns for each sensor
figure;
plot(data.Time, data.Sensor1, 'DisplayName', 'Sensor 1');
hold on;
plot(data.Time, data.Sensor2, 'DisplayName', 'Sensor 2');
plot(data.Time, data.Sensor3, 'DisplayName', 'Sensor 3');
xlabel('Time (s)');
ylabel('Acceleration (m/s²)');
title('Vibration Patterns for Each Sensor');
legend;
grid on;

%
% 🛠 Step 3: Time-Domain Analysis ⏱️
% Calculate Key Features:
% Mean
% Standard Deviation
% Peak-to-Peak Amplitude
% RMS Value ️

% Mean
mean_sensor1 = mean(data.Sensor1);
mean_sensor2 = mean(data.Sensor2);
mean_sensor3 = mean(data.Sensor3);

% Standard Deviation
std_sensor1 = std(data.Sensor1);
std_sensor2 = std(data.Sensor2);
std_sensor3 = std(data.Sensor3);

% Peak-to-Peak Amplitude
peak_to_peak_sensor1 = max(data.Sensor1) - min(data.Sensor1);
peak_to_peak_sensor2 = max(data.Sensor2) - min(data.Sensor2);
peak_to_peak_sensor3 = max(data.Sensor3) - min(data.Sensor3);

% RMS Value
rms_sensor1 = sqrt(mean(data.Sensor1.^2));
rms_sensor2 = sqrt(mean(data.Sensor2.^2));
rms_sensor3 = sqrt(mean(data.Sensor3.^2));

% Display the results
disp('Mean values:');
disp([mean_sensor1, mean_sensor2, mean_sensor3]);

disp('Standard Deviation values:');
disp([std_sensor1, std_sensor2, std_sensor3]);

disp('Peak-to-Peak Amplitude values:');
disp([peak_to_peak_sensor1, peak_to_peak_sensor2, peak_to_peak_sensor3]);

disp('RMS values:');
disp([rms_sensor1, rms_sensor2, rms_sensor3]);

% Filter Out Noise (Low-pass filter): For noise filtering, apply a low-pass filter to smooth the signals.

% Define filter parameters
Fs = 1000; % Sampling frequency (replace with actual)
cutoff = 10; % Cutoff frequency in Hz

% Design a low-pass filter
[b, a] = butter(4, cutoff / (Fs / 2), 'low');

% Filter the data
filtered_sensor1 = filter(b, a, data.Sensor1);
filtered_sensor2 = filter(b, a, data.Sensor2);
filtered_sensor3 = filter(b, a, data.Sensor3);

% Plot filtered signals
figure;
plot(data.Time, filtered_sensor1, 'DisplayName', 'Filtered Sensor 1');
hold on;
plot(data.Time, filtered_sensor2, 'DisplayName', 'Filtered Sensor 2');
plot(data.Time, filtered_sensor3, 'DisplayName', 'Filtered Sensor 3');
xlabel('Time (s)');
ylabel('Acceleration (m/s²)');
title('Filtered Vibration Patterns');
legend;
grid on;

% 🤖 Step 4: Frequency-Domain Analysis 🎶
% Apply FFT (Fast Fourier Transform):

% Compute FFT for Sensor 1
N = length(data.Time);
T = data.Time(2) - data.Time(1); % Time step
f = (0:N-1)*(1/(N*T)); % Frequency vector
Y = fft(filtered_sensor1); % FFT of the filtered signal

% Only consider the positive frequencies
f_pos = f(1:N/2);
Y_pos = Y(1:N/2);

% Plot the frequency spectrum
figure;
plot(f_pos, abs(Y_pos));
xlabel('Frequency (Hz)');
ylabel('Magnitude');
title('Frequency Spectrum of Sensor 1');
grid on;

%  Identify Dominant Frequencies: The peaks in the FFT plot correspond to the dominant frequencies of the structure. You can find these using Matlab's findpeaks function.

% Find dominant frequencies
[peaks, locs] = findpeaks(abs(Y_pos), 'MinPeakHeight', 0.1); % Adjust threshold
dominant_frequencies = f_pos(locs);

disp('Dominant Frequencies (Hz):');
disp(dominant_frequencies);

% 🤖 Step 5: Vibration Mode Analysis ⚙️
% Determine Vibration Modes: For simplicity, let's calculate the mode shape as a weighted sum of sensor signals.

% Calculate a simplified mode shape (combining signals from all sensors)
mode_shape = (filtered_sensor1 + filtered_sensor2 + filtered_sensor3) / 3;

% Plot the mode shape
figure;
plot(data.Time, mode_shape);
xlabel('Time (s)');
ylabel('Mode Shape Amplitude');
title('Average Vibration Mode Shape');
grid on;

%  Compare with Theoretical Values: To compare with theoretical values, you will need the expected mode shapes or frequencies of the structure. This can be done by comparing the mode shapes and frequencies identified from the data with those from theory.
%
% 6. Conclusion & Discussion 💬
% Key Findings:
% By examining the identified dominant frequencies and damping ratios, we can assess whether the structure is prone to resonance. If the natural frequencies are close to the operational frequencies, this can lead to large oscillations, potentially damaging the structure.
% A low damping ratio might indicate that the structure does not efficiently dissipate energy, making it more vulnerable to vibrations.
% Suggestions for Improvements:
%
% If the damping ratios are low, adding damping materials (like viscoelastic dampers) or changing structural materials may help improve the stability.
% If any dominant frequencies are too close to expected or operating frequencies, the structure’s design may need to be adjusted to avoid resonance.
%