324 lines
10 KiB
Matlab
324 lines
10 KiB
Matlab
display("functions")
|
|
source("settings.m");
|
|
|
|
function files = getDataFiles(clsName, trainsetPerClass)
|
|
|
|
global setDataDir;
|
|
|
|
dir = strcat(setDataDir, clsName, "/");
|
|
lst = readdir(dir);
|
|
files = {};
|
|
cnt = 0;
|
|
for i = 1:numel(lst)
|
|
filename = lst{i};
|
|
if (regexp(filename, ".m$")) # use only files ending with .m
|
|
file = strcat(dir, filename);
|
|
files = [files file];
|
|
++cnt;
|
|
if (cnt >= trainsetPerClass) # use only x input files
|
|
break;
|
|
endif
|
|
endif
|
|
end
|
|
|
|
end
|
|
|
|
function samples = getSamplesForClass(clsName, trainsetPerClass, start, percent)
|
|
files = getDataFiles(clsName, trainsetPerClass); #load Data files - thanks franke
|
|
samples = {};
|
|
start = start / 10; #start is given in ms and our raw input data has an fixed update-intervall of 10ms
|
|
for i = 1 : numel(files)
|
|
source(files{i});
|
|
lengthSamples = length(Magnet); # length/number of all available samples
|
|
pEnd = lengthSamples * percent; # how many samples do we want?
|
|
raw = {Gyro(start:pEnd,:), Accel(start:pEnd,:), Magnet(start:pEnd,:)}; # create cell array of the wanted samples
|
|
samples{i}.raw = raw; # write them into cell array for each Class
|
|
end
|
|
disp(strcat("training data for '", clsName, "': ", num2str(length(samples)), " samples"));
|
|
end
|
|
|
|
function data = getRawTrainData()
|
|
|
|
#global trainsetPerClass;
|
|
global signalStart;
|
|
global signalEnd;
|
|
|
|
data = {};
|
|
data{1}.samples = getSamplesForClass("forwardbend", 9, signalStart, signalEnd);
|
|
data{2}.samples = getSamplesForClass("kneebend", 11, signalStart, signalEnd);
|
|
data{3}.samples = getSamplesForClass("pushups", 11, signalStart, signalEnd);
|
|
data{4}.samples = getSamplesForClass("situps", 8, signalStart, signalEnd);
|
|
data{5}.samples = getSamplesForClass("jumpingjack", 13, signalStart, signalEnd);
|
|
end
|
|
|
|
function plotData(data,outPath)
|
|
|
|
for k = 1:numel(data)
|
|
for j = 1:numel(data{k}.samples)
|
|
for i = 1:numel(data{k}.samples{j}.raw)
|
|
mat = data{k}.samples{j}.raw{i};
|
|
#subplot(6, 3, idx);
|
|
plot(mat);
|
|
legend("x","y","z");
|
|
print( gcf, '-dpng', fullfile(outPath, sprintf('img_%d_%d_%d.png', k, j, i) ) );
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
function filteredData = filterData(data)
|
|
pkg load signal;
|
|
filteredData = {};
|
|
for k = 1:numel(data)
|
|
for j = 1:numel(data{k}.samples)
|
|
for i = 1:numel(data{k}.samples{j}.raw)
|
|
mat = data{k}.samples{j}.raw{i};
|
|
[b, a] = butter(16, 0.2);
|
|
filteredData{k}.samples{j}.raw{i} = filtfilt(b, a, mat); #filtfilt extends the signal at beginning so we have no phaseshift
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
function win = window(rawVec, posMS)
|
|
|
|
global setWindowSize;
|
|
pos = posMS / 10;
|
|
|
|
#only full windows are accepted.
|
|
if length(rawVec) <= pos+(setWindowSize/2)-1
|
|
win = [];
|
|
else
|
|
win = rawVec(pos-(setWindowSize/2):pos+(setWindowSize/2)-1,:); #100*10 ms is half the window size.
|
|
endif
|
|
end
|
|
|
|
function out = getMagnitude(data)
|
|
|
|
out = [];
|
|
for i = 1:length(data)
|
|
tmp = sqrt(data(i,1)^2 + data(i,2)^2 + data(i,3)^2);
|
|
out = [out; tmp];
|
|
end
|
|
|
|
end
|
|
|
|
function windowedData = windowData(data)
|
|
|
|
global setWindowSize;
|
|
global setWindowSliding;
|
|
windowedData = {};
|
|
|
|
global setMagnet;
|
|
global setAccel;
|
|
global setGyro;
|
|
global useSignalPCA;
|
|
global useSignalMG;
|
|
|
|
for k = 1:numel(data)
|
|
for j = 1:numel(data{k}.samples)
|
|
|
|
#init
|
|
winsAccelX = {};
|
|
winsAccelY = {};
|
|
winsAccelZ = {};
|
|
winsGyroX = {};
|
|
winsGyroY = {};
|
|
winsGyroZ = {};
|
|
winsMagnetX = {};
|
|
winsMagnetY = {};
|
|
winsMagnetZ = {};
|
|
|
|
winsAccelPCA = {};
|
|
winsGyroPCA = {};
|
|
winsMagnetPCA = {};
|
|
|
|
winsAccelMG = {};
|
|
winsGyroMG = {};
|
|
winsMagnetMG = {};
|
|
|
|
winEnd = length(data{k}.samples{j}.raw{1}) * 10; # *10ms
|
|
winBuffer = ((setWindowSize/2)+1) * 10;
|
|
|
|
for i = winBuffer:setWindowSliding:winEnd-winBuffer #steps for sliding/overlapping windows
|
|
|
|
if setAccel == true
|
|
#accel
|
|
winAccel = window(data{k}.samples{j}.raw{1}, i);
|
|
winsAccelX = [winsAccelX winAccel(:,1)];
|
|
winsAccelY = [winsAccelY winAccel(:,2)];
|
|
winsAccelZ = [winsAccelZ winAccel(:,3)];
|
|
|
|
if useSignalPCA == true
|
|
[coeff1, score1] = princomp(winAccel');
|
|
winsAccelPCA = [winsAccelPCA score1(:,1)]; #choose the first axis (eigvec with the biggest eigvalue)
|
|
endif
|
|
|
|
if useSignalMG == true
|
|
winAccelMG = getMagnitude(winAccel);
|
|
winsAccelMG = [winsAccelMG winAccelMG];
|
|
endif
|
|
|
|
endif
|
|
|
|
if setGyro == true
|
|
#gyro
|
|
winGyro = window(data{k}.samples{j}.raw{2}, i);
|
|
winsGyroX = [winsGyroX winGyro(:,1)];
|
|
winsGyroY = [winsGyroY winGyro(:,2)];
|
|
winsGyroZ = [winsGyroZ winGyro(:,3)];
|
|
|
|
if useSignalPCA == true
|
|
[coeff2, score2] = princomp(winGyro');
|
|
winsGyroPCA = [winsGyroPCA score2(:,1)];
|
|
endif
|
|
|
|
if useSignalMG == true
|
|
winGyroMG = getMagnitude(winGyro);
|
|
winsGyroMG = [winsGyroMG winGyroMG];
|
|
endif
|
|
|
|
endif
|
|
|
|
if setMagnet == true
|
|
#magnet
|
|
winMagnet = window(data{k}.samples{j}.raw{3}, i);
|
|
winsMagnetX = [winsMagnetX winMagnet(:,1)];
|
|
winsMagnetY = [winsMagnetY winMagnet(:,2)];
|
|
winsMagnetZ = [winsMagnetZ winMagnet(:,3)];
|
|
|
|
if useSignalPCA == true
|
|
[coeff3, score3] = princomp(winMagnet');
|
|
winsMagnetPCA = [winsMagnetPCA score3(:,1)];
|
|
endif
|
|
|
|
if useSignalMG == true
|
|
winMagnetMG = getMagnitude(winMagnet);
|
|
winsMagnetMG = [winsMagnetMG winMagnetMG];
|
|
endif
|
|
|
|
endif
|
|
|
|
end
|
|
|
|
#write back data
|
|
windowedData{k}.samples{j}.raw = [winsAccelX; winsAccelY; winsAccelZ; winsGyroX; winsGyroY; winsGyroZ; winsMagnetX; winsMagnetY; winsMagnetZ; winsAccelPCA; winsGyroPCA; winsMagnetPCA; winsAccelMG; winsGyroMG; winsMagnetMG];
|
|
|
|
end
|
|
end
|
|
end
|
|
|
|
function features = featureCalculation(data)
|
|
|
|
global setAutocorrelationBinSize;
|
|
global setPSDBinSize;
|
|
features = [];
|
|
|
|
global setAutoCorr;
|
|
global setRMS;
|
|
global setPSD;
|
|
global setStatistic;
|
|
global setPCA;
|
|
|
|
for k = 1:numel(data)
|
|
for j = 1:numel(data{k}.samples)
|
|
for i = 1:size(data{k}.samples{j}.raw, 1)
|
|
for m = 1:size(data{k}.samples{j}.raw, 2)
|
|
currentWindow = data{k}.samples{j}.raw{i, m};
|
|
|
|
if setAutoCorr == true
|
|
#autocorrelation on window. split into 5 evenly spaced bins (amplitudes are evenly spaced, not number of values ;) ) and calculate mean of bin.
|
|
[autoCorr] = xcorr(currentWindow);
|
|
[binNum, binCenter] = hist(autoCorr, setAutocorrelationBinSize); #define bins for the data.
|
|
binSize = abs(binCenter(end-1) - binCenter(end));
|
|
binEdges = linspace(binCenter(1)-(binSize/2), binCenter(end)+(binSize/2), setAutocorrelationBinSize+1);
|
|
[binNumc, binIdx] = histc(autoCorr, binEdges);
|
|
binMeans = getBinMean(autoCorr, binIdx, setAutocorrelationBinSize);
|
|
|
|
endif
|
|
|
|
if setRMS == true
|
|
#calculate the root-mean-square (RMS) of the signal
|
|
rms = sqrt(mean(currentWindow.^2));
|
|
endif
|
|
|
|
if setPSD == true
|
|
#power bands 0.5 to 25hz (useful if the windows are greater then 4s and window sizes to 256, 512..)
|
|
[powerBand, w] = periodogram(currentWindow); #fills up fft with zeros
|
|
powerEdges = logspace(log10(0.5), log10(25), setPSDBinSize + 2); #logarithmic bin spaces for 10 bins
|
|
triFilter = getTriangularFunction(powerEdges, length(powerBand)*2 - 2);
|
|
for l = 1:numel(triFilter)
|
|
filteredBand = triFilter{l} .* powerBand;
|
|
psd(l) = sum(filteredBand); #sum freq (no log and no dct)
|
|
end
|
|
endif
|
|
|
|
if setStatistic == true
|
|
#statistical features
|
|
windowMean = mean(currentWindow);
|
|
windowSTD = std(currentWindow); #standard deviation
|
|
windowVariance = var(currentWindow);
|
|
windowKurtosis = kurtosis(currentWindow); #(ger. Wölbung)
|
|
windowIQR = iqr(currentWindow); #interquartile range
|
|
endif
|
|
|
|
pcaFeature = [];
|
|
if setPCA == true
|
|
#pca on windows
|
|
[coeff, score] = princomp(currentWindow');
|
|
pcaFeature = currentWindow' * coeff(:, 1:10); #10 pca feature
|
|
endif
|
|
|
|
#put everything together
|
|
classLabel = k; #what class?
|
|
sampleLabel = j; #what sample?
|
|
features = [features; sampleLabel, classLabel, binMeans, rms, psd, windowMean, windowSTD, windowVariance, windowKurtosis, windowIQR, pcaFeature];
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
function value = getBinMean(data, idx, numBins)
|
|
|
|
#search for an idx == numBins+1. this index occurs if a value == lastEdge, thanks histc...
|
|
isSix = find(idx == numBins+1);
|
|
if isSix != 0
|
|
idx(isSix) = numBins;
|
|
endif
|
|
|
|
value = [];
|
|
for i = 1:numBins
|
|
flagBinMembers = (idx == i);
|
|
binMembers = data(flagBinMembers);
|
|
|
|
if length(binMembers) == 0
|
|
value(i) = 0;
|
|
else
|
|
value(i) = sum(binMembers);
|
|
endif
|
|
end
|
|
end
|
|
|
|
#triangular functions. (edges of the triangles; num fft values -> nfft.)
|
|
function triFilter = getTriangularFunction(edges, nfft)
|
|
|
|
global samplerateHZ;
|
|
|
|
#get idx of the edges within the samples. thanks to fft each sample represents a frequency.
|
|
# idx * samplerate / nfft = hertz of that idx
|
|
for i = 1:length(edges)
|
|
edgesByIdx(i) = floor((nfft + 1) * edges(i)/samplerateHZ);
|
|
end
|
|
|
|
#generate the triangle filters
|
|
triFilter = {};
|
|
for i = 1:length(edgesByIdx)-2
|
|
diffCnt = edgesByIdx(i+2) - edgesByIdx(i) + 1;
|
|
tmp = zeros(nfft/2 + 1, 1);
|
|
triVec = triang(diffCnt);
|
|
tmp(edgesByIdx(i):edgesByIdx(i+2)) = triVec;
|
|
triFilter{i} = tmp;
|
|
end
|
|
end
|