0% found this document useful (0 votes)
30 views6 pages

Analyze CSI Data for Activity Recognition

The document outlines a MATLAB script that processes channel state information (CSI) data from multiple files to extract features for activity recognition. It calculates average amplitude and phase for different transmitter-receiver combinations, normalizes these values, and trains a multi-class SVM model to classify activities such as standing, sitting, lying, and moving in and out. Finally, it evaluates the model's accuracy and displays a confusion matrix for the predictions.

Uploaded by

armtanium
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
30 views6 pages

Analyze CSI Data for Activity Recognition

The document outlines a MATLAB script that processes channel state information (CSI) data from multiple files to extract features for activity recognition. It calculates average amplitude and phase for different transmitter-receiver combinations, normalizes these values, and trains a multi-class SVM model to classify activities such as standing, sitting, lying, and moving in and out. Finally, it evaluates the model's accuracy and displays a confusion matrix for the predictions.

Uploaded by

armtanium
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd

% Get the cell names from the workspace

cell_names = who;

% Define the wrapPhase function


wrapPhase = @(phase) mod(phase + pi, 2*pi) - pi;

% Initialize feature and label arrays


numFiles = length(cell_names); % Number of files to process
target_num_subcarriers = 0; % Initialize target_num_subcarriers

% Determine the maximum number of subcarriers across all files


for i = 1:numFiles
cell_data = eval(cell_names{i});
if iscell(cell_data)
for CSI_data_index = 1:length(cell_data)
subcarrier_indices = cell_data{CSI_data_index}.[Link];
target_num_subcarriers = max(target_num_subcarriers,
length(subcarrier_indices));
end
end
end

numFeatures = 3 * target_num_subcarriers; % Number of features for each file

% Preallocate memory for feature and label arrays


features = nan(numFiles, numFeatures);
labels = strings(numFiles, 1);

% Define the list of possible activity labels


activity_labels = {'standing', 'sitting', 'lying', 'movinginandout'};

% Loop through each cell name


for i = 1:numFiles
% Load the CSI data for the current cell
cell_data = eval(cell_names{i});

% Initialize cumulative sums and counts for each Tx-Rx combination (amplitude,
phase, and wrapped phase) with NaNs
cumulative_sum_tx1_rx1_amp = zeros(target_num_subcarriers, 1);
cumulative_sum_tx1_rx2_amp = zeros(target_num_subcarriers, 1);
cumulative_sum_tx2_rx1_amp = zeros(target_num_subcarriers, 1);
cumulative_sum_tx2_rx2_amp = zeros(target_num_subcarriers, 1);
count_tx1_rx1_amp = zeros(target_num_subcarriers, 1);
count_tx1_rx2_amp = zeros(target_num_subcarriers, 1);
count_tx2_rx1_amp = zeros(target_num_subcarriers, 1);
count_tx2_rx2_amp = zeros(target_num_subcarriers, 1);

cumulative_sum_tx1_rx1_phase = zeros(target_num_subcarriers, 1);


cumulative_sum_tx1_rx2_phase = zeros(target_num_subcarriers, 1);
cumulative_sum_tx2_rx1_phase = zeros(target_num_subcarriers, 1);
cumulative_sum_tx2_rx2_phase = zeros(target_num_subcarriers, 1);
count_tx1_rx1_phase = zeros(target_num_subcarriers, 1);
count_tx1_rx2_phase = zeros(target_num_subcarriers, 1);
count_tx2_rx1_phase = zeros(target_num_subcarriers, 1);
count_tx2_rx2_phase = zeros(target_num_subcarriers, 1);

cumulative_sum_tx1_rx1_wrapped_phase = zeros(target_num_subcarriers, 1);


cumulative_sum_tx1_rx2_wrapped_phase = zeros(target_num_subcarriers, 1);
cumulative_sum_tx2_rx1_wrapped_phase = zeros(target_num_subcarriers, 1);
cumulative_sum_tx2_rx2_wrapped_phase = zeros(target_num_subcarriers, 1);
count_tx1_rx1_wrapped_phase = zeros(target_num_subcarriers, 1);
count_tx1_rx2_wrapped_phase = zeros(target_num_subcarriers, 1);
count_tx2_rx1_wrapped_phase = zeros(target_num_subcarriers, 1);
count_tx2_rx2_wrapped_phase = zeros(target_num_subcarriers, 1);

% Process each CSI entry


if iscell(cell_data)
for CSI_data_index = 1:length(cell_data)
% Extract the relevant CSI data
amplitude = cell_data{CSI_data_index}.[Link];
phase = cell_data{CSI_data_index}.[Link];
subcarrier_indices = cell_data{CSI_data_index}.[Link];

% Check the dimensions of the amplitude and phase data


[num_subcarriers, num_tx, num_rx] = size(amplitude);

% Initialize the padded amplitude and phase matrices with NaNs


amplitude_padded = nan(target_num_subcarriers, 2, 2);
phase_padded = nan(target_num_subcarriers, 2, 2);

% Assign the existing amplitude and phase data to the padded matrices
amplitude_padded(1:num_subcarriers, 1:num_tx, 1:num_rx) = amplitude;
phase_padded(1:num_subcarriers, 1:num_tx, 1:num_rx) = phase;

% Initialize vectors for each Tx-Rx combination (amplitude and phase)


amplitude_tx1_rx1 = amplitude_padded(:, 1, 1);
amplitude_tx1_rx2 = amplitude_padded(:, 1, 2);
amplitude_tx2_rx1 = amplitude_padded(:, 2, 1);
amplitude_tx2_rx2 = amplitude_padded(:, 2, 2);

phase_tx1_rx1 = phase_padded(:, 1, 1);


phase_tx1_rx2 = phase_padded(:, 1, 2);
phase_tx2_rx1 = phase_padded(:, 2, 1);
phase_tx2_rx2 = phase_padded(:, 2, 2);

% Wrap phase values before updating cumulative sums for wrapped phase
wrapped_phase_tx1_rx1 = wrapPhase(phase_tx1_rx1);
wrapped_phase_tx1_rx2 = wrapPhase(phase_tx1_rx2);
wrapped_phase_tx2_rx1 = wrapPhase(phase_tx2_rx1);
wrapped_phase_tx2_rx2 = wrapPhase(phase_tx2_rx2);

% Update cumulative sums and counts for each Tx-Rx combination


(amplitude, phase, and wrapped phase)
for j = 1:target_num_subcarriers
if ~isnan(amplitude_tx1_rx1(j))
cumulative_sum_tx1_rx1_amp(j) = cumulative_sum_tx1_rx1_amp(j) +
amplitude_tx1_rx1(j);
count_tx1_rx1_amp(j) = count_tx1_rx1_amp(j) + 1;
end
if ~isnan(amplitude_tx1_rx2(j))
cumulative_sum_tx1_rx2_amp(j) = cumulative_sum_tx1_rx2_amp(j) +
amplitude_tx1_rx2(j);
count_tx1_rx2_amp(j) = count_tx1_rx2_amp(j) + 1;
end
if ~isnan(amplitude_tx2_rx1(j))
cumulative_sum_tx2_rx1_amp(j) = cumulative_sum_tx2_rx1_amp(j) +
amplitude_tx2_rx1(j);
count_tx2_rx1_amp(j) = count_tx2_rx1_amp(j) + 1;
end
if ~isnan(amplitude_tx2_rx2(j))
cumulative_sum_tx2_rx2_amp(j) = cumulative_sum_tx2_rx2_amp(j) +
amplitude_tx2_rx2(j);
count_tx2_rx2_amp(j) = count_tx2_rx2_amp(j) + 1;
end

if ~isnan(phase_tx1_rx1(j))
cumulative_sum_tx1_rx1_phase(j) =
cumulative_sum_tx1_rx1_phase(j) + phase_tx1_rx1(j);
count_tx1_rx1_phase(j) = count_tx1_rx1_phase(j) + 1;
end
if ~isnan(phase_tx1_rx2(j))
cumulative_sum_tx1_rx2_phase(j) =
cumulative_sum_tx1_rx2_phase(j) + phase_tx1_rx2(j);
count_tx1_rx2_phase(j) = count_tx1_rx2_phase(j) + 1;
end
if ~isnan(phase_tx2_rx1(j))
cumulative_sum_tx2_rx1_phase(j) =
cumulative_sum_tx2_rx1_phase(j) + phase_tx2_rx1(j);
count_tx2_rx1_phase(j) = count_tx2_rx1_phase(j) + 1;
end
if ~isnan(phase_tx2_rx2(j))
cumulative_sum_tx2_rx2_phase(j) =
cumulative_sum_tx2_rx2_phase(j) + phase_tx2_rx2(j);
count_tx2_rx2_phase(j) = count_tx2_rx2_phase(j) + 1;
end

if ~isnan(wrapped_phase_tx1_rx1(j))
cumulative_sum_tx1_rx1_wrapped_phase(j) =
cumulative_sum_tx1_rx1_wrapped_phase(j) + wrapped_phase_tx1_rx1(j);
count_tx1_rx1_wrapped_phase(j) = count_tx1_rx1_wrapped_phase(j)
+ 1;
end
if ~isnan(wrapped_phase_tx1_rx2(j))
cumulative_sum_tx1_rx2_wrapped_phase(j) =
cumulative_sum_tx1_rx2_wrapped_phase(j) + wrapped_phase_tx1_rx2(j);
count_tx1_rx2_wrapped_phase(j) = count_tx1_rx2_wrapped_phase(j)
+ 1;
end
if ~isnan(wrapped_phase_tx2_rx1(j))
cumulative_sum_tx2_rx1_wrapped_phase(j) =
cumulative_sum_tx2_rx1_wrapped_phase(j) + wrapped_phase_tx2_rx1(j);
count_tx2_rx1_wrapped_phase(j) = count_tx2_rx1_wrapped_phase(j)
+ 1;
end
if ~isnan(wrapped_phase_tx2_rx2(j))
cumulative_sum_tx2_rx2_wrapped_phase(j) =
cumulative_sum_tx2_rx2_wrapped_phase(j) + wrapped_phase_tx2_rx2(j);
count_tx2_rx2_wrapped_phase(j) = count_tx2_rx2_wrapped_phase(j)
+ 1;
end
end
end
end

% Calculate the average amplitude and phase for each Tx-Rx combination
mean_tx1_rx1_amp = cumulative_sum_tx1_rx1_amp ./ count_tx1_rx1_amp;
mean_tx1_rx2_amp = cumulative_sum_tx1_rx2_amp ./ count_tx1_rx2_amp;
mean_tx2_rx1_amp = cumulative_sum_tx2_rx1_amp ./ count_tx2_rx1_amp;
mean_tx2_rx2_amp = cumulative_sum_tx2_rx2_amp ./ count_tx2_rx2_amp;

mean_tx1_rx1_phase = cumulative_sum_tx1_rx1_phase ./ count_tx1_rx1_phase;


mean_tx1_rx2_phase = cumulative_sum_tx1_rx2_phase ./ count_tx1_rx2_phase;
mean_tx2_rx1_phase = cumulative_sum_tx2_rx1_phase ./ count_tx2_rx1_phase;
mean_tx2_rx2_phase = cumulative_sum_tx2_rx2_phase ./ count_tx2_rx2_phase;

% Calculate the average wrapped phase for each Tx-Rx combination


mean_tx1_rx1_wrapped_phase = cumulative_sum_tx1_rx1_wrapped_phase ./
count_tx1_rx1_wrapped_phase;
mean_tx1_rx2_wrapped_phase = cumulative_sum_tx1_rx2_wrapped_phase ./
count_tx1_rx2_wrapped_phase;
mean_tx2_rx1_wrapped_phase = cumulative_sum_tx2_rx1_wrapped_phase ./
count_tx2_rx1_wrapped_phase;
mean_tx2_rx2_wrapped_phase = cumulative_sum_tx2_rx2_wrapped_phase ./
count_tx2_rx2_wrapped_phase;

% Normalize the mean_tx_rx_amp datasets by the largest value found in all Tx-Rx
datasets for amplitude (handling NaNs)
max_value = nanmax([mean_tx1_rx1_amp; mean_tx1_rx2_amp; mean_tx2_rx1_amp;
mean_tx2_rx2_amp]);

% Normalize each Tx-Rx amplitude dataset by the maximum value


mean_tx1_rx1_amp = mean_tx1_rx1_amp / max_value;
mean_tx1_rx2_amp = mean_tx1_rx2_amp / max_value;
mean_tx2_rx1_amp = mean_tx2_rx1_amp / max_value;
mean_tx2_rx2_amp = mean_tx2_rx2_amp / max_value;

% Optional: Handle edge cases where the max_value is zero to avoid division by
zero
if max_value == 0
mean_tx1_rx1_amp = zeros(size(mean_tx1_rx1_amp));
mean_tx1_rx2_amp = zeros(size(mean_tx1_rx2_amp));
mean_tx2_rx1_amp = zeros(size(mean_tx2_rx1_amp));
mean_tx2_rx2_amp = zeros(size(mean_tx2_rx2_amp));
end

% Convert unwrapped phase to degrees


mean_tx1_rx1_phase_deg = mean_tx1_rx1_phase * (180 / pi);
mean_tx1_rx2_phase_deg = mean_tx1_rx2_phase * (180 / pi);
mean_tx2_rx1_phase_deg = mean_tx2_rx1_phase * (180 / pi);
mean_tx2_rx2_phase_deg = mean_tx2_rx2_phase * (180 / pi);

% Min-Max Scaling for amplitude, unwrapped phase, and wrapped phase


min_val_amp = min([mean_tx1_rx1_amp; mean_tx1_rx2_amp; mean_tx2_rx1_amp;
mean_tx2_rx2_amp]);
max_val_amp = max([mean_tx1_rx1_amp; mean_tx1_rx2_amp; mean_tx2_rx1_amp;
mean_tx2_rx2_amp]);
normalized_amp = (mean_tx1_rx1_amp - min_val_amp) / (max_val_amp -
min_val_amp);

min_val_phase = min([mean_tx1_rx1_phase_deg; mean_tx1_rx2_phase_deg;


mean_tx2_rx1_phase_deg; mean_tx2_rx2_phase_deg]);
max_val_phase = max([mean_tx1_rx1_phase_deg; mean_tx1_rx2_phase_deg;
mean_tx2_rx1_phase_deg; mean_tx2_rx2_phase_deg]);
normalized_phase = (mean_tx1_rx1_phase_deg - min_val_phase) / (max_val_phase -
min_val_phase);
min_val_wrapped_phase = min([mean_tx1_rx1_wrapped_phase;
mean_tx1_rx2_wrapped_phase; mean_tx2_rx1_wrapped_phase;
mean_tx2_rx2_wrapped_phase]);
max_val_wrapped_phase = max([mean_tx1_rx1_wrapped_phase;
mean_tx1_rx2_wrapped_phase; mean_tx2_rx1_wrapped_phase;
mean_tx2_rx2_wrapped_phase]);
normalized_wrapped_phase = (mean_tx1_rx1_wrapped_phase - min_val_wrapped_phase)
/ (max_val_wrapped_phase - min_val_wrapped_phase);

% Create feature vector


feature_vector = [normalized_amp; normalized_phase; normalized_wrapped_phase];
features(i, :) = feature_vector'; % Store in the preallocated matrix

% Extract activity label based on the provided naming convention


filename = cell_names{i};
lower_filename = lower(filename); % Convert to lowercase for case-insensitive
matching
lower_filename = strrep(lower_filename, '-', ''); % Remove dashes
activity_label = '';

% Use regular expressions to match activity labels in concatenated filenames


if contains(lower_filename, 'standing')
activity_label = 'standing';
elseif contains(lower_filename, 'sitting')
activity_label = 'sitting';
elseif contains(lower_filename, 'lying')
activity_label = 'lying';
elseif contains(lower_filename, 'movinginandout') || contains(lower_filename,
'movinginout') || contains(lower_filename, 'moving_in_and_out')
activity_label = 'moving in and out';
else
error('Activity label not found in filename: %s', filename);
end

labels(i) = activity_label;
end

% Convert labels to categorical if needed


labels = categorical(labels);

% Split data into training and testing sets


cv = cvpartition(labels, 'HoldOut', 0.3); % 70% training, 30% testing
trainingData = features(training(cv), :);
trainingLabels = labels(training(cv));
testData = features(test(cv), :);
testLabels = labels(test(cv));

% Define the template for the base SVM learner


template = templateSVM('KernelFunction', 'linear', 'Standardize', true);

% Train a multi-class SVM model using fitcecoc


SVMModel = fitcecoc(trainingData, trainingLabels, 'Learners', template);

% Predict on the test set


predictedLabels = predict(SVMModel, testData);

% Evaluate the model


accuracy = sum(predictedLabels == testLabels) / length(testLabels);
disp(['Accuracy: ', num2str(accuracy)]);
% Confusion matrix
confMat = confusionmat(testLabels, predictedLabels);
disp('Confusion Matrix:');
disp(confMat);

% Plot the confusion matrix for visualization


figure;
confusionchart(testLabels, predictedLabels);
title('Confusion Matrix');

You might also like