├── jAverageEnergy.m ├── jSkewness.m ├── jKurtosis.m ├── jCoefficientOfVariation.m ├── jMeanValueOfTheSquareRoot.m ├── jVariance.m ├── jAbsoluteValueOfTheSummationOfExpRoot.m ├── jAbsoluteValueOfTheSummationOfSquareRoot.m ├── jStandardDeviation.m ├── jMeanAbsoluteValue.m ├── jIntegratedEMG.m ├── jSimpleSquareIntegral.m ├── jInterquartileRange.m ├── jVarianceOfEMG.m ├── jWaveformLength.m ├── jLogDetector.m ├── jAverageAmplitudeChange.m ├── jLogCoefficientOfVariation.m ├── jRootMeanSquare.m ├── jMaximumFractalLength.m ├── jMeanAbsoluteDeviation.m ├── jDifferenceVarianceValue.m ├── jTemporalMoment.m ├── jLogDifferenceAbsoluteMeanValue.m ├── jVOrder.m ├── jLogTeagerKaiserEnergyOperator.m ├── jLogDifferenceAbsoluteStandardDeviationValue.m ├── jAutoRegressiveModel.m ├── jModifiedMeanAbsoluteValue.m ├── jEnhancedWaveLength.m ├── jDifferenceAbsoluteMeanValue.m ├── jEnhancedMeanAbsoluteValue.m ├── jMyopulsePercentageRate.m ├── jWillisonAmplitude.m ├── jNewZeroCrossing.m ├── jDifferenceAbsoluteStandardDeviationValue.m ├── jModifiedMeanAbsoluteValue2.m ├── jZeroCrossing.m ├── jCardinality.m ├── jSlopeSignChange.m ├── LICENSE ├── A_Main.m ├── jfemg.m └── README.md /jAverageEnergy.m: -------------------------------------------------------------------------------- 1 | 2 | function ME = jAverageEnergy(X,~) 3 | ME = mean(X .^ 2); 4 | end -------------------------------------------------------------------------------- /jSkewness.m: -------------------------------------------------------------------------------- 1 | 2 | function SKEW = jSkewness(X,~) 3 | SKEW = skewness(X); 4 | end 5 | 6 | -------------------------------------------------------------------------------- /jKurtosis.m: -------------------------------------------------------------------------------- 1 | 2 | function KURT = jKurtosis(X,~) 3 | % Kurtosis 4 | KURT = kurtosis(X); 5 | end 6 | -------------------------------------------------------------------------------- /jCoefficientOfVariation.m: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JingweiToo/EMG-Feature-Extraction-Toolbox/HEAD/jCoefficientOfVariation.m -------------------------------------------------------------------------------- /jMeanValueOfTheSquareRoot.m: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JingweiToo/EMG-Feature-Extraction-Toolbox/HEAD/jMeanValueOfTheSquareRoot.m -------------------------------------------------------------------------------- /jVariance.m: -------------------------------------------------------------------------------- 1 | 2 | function VAR = jVariance(X,~) 3 | N = length(X); 4 | mu = mean(X); 5 | VAR = (1 / (N - 1)) * sum((X - mu) .^ 2); 6 | end 7 | -------------------------------------------------------------------------------- /jAbsoluteValueOfTheSummationOfExpRoot.m: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JingweiToo/EMG-Feature-Extraction-Toolbox/HEAD/jAbsoluteValueOfTheSummationOfExpRoot.m -------------------------------------------------------------------------------- /jAbsoluteValueOfTheSummationOfSquareRoot.m: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JingweiToo/EMG-Feature-Extraction-Toolbox/HEAD/jAbsoluteValueOfTheSummationOfSquareRoot.m -------------------------------------------------------------------------------- /jStandardDeviation.m: -------------------------------------------------------------------------------- 1 | 2 | function SD = jStandardDeviation(X,~) 3 | N = length(X); 4 | mu = mean(X); 5 | SD = sqrt((1 / (N - 1)) * sum((X - mu) .^ 2)); 6 | end 7 | 8 | -------------------------------------------------------------------------------- /jMeanAbsoluteValue.m: -------------------------------------------------------------------------------- 1 | %[1993]-"A New Strategy for Multifunction Myoelectric Control" (1) 2 | 3 | function MAV = jMeanAbsoluteValue(X,~) 4 | MAV = mean(abs(X)); 5 | end 6 | 7 | -------------------------------------------------------------------------------- /jIntegratedEMG.m: -------------------------------------------------------------------------------- 1 | %[2012]-"Feature reduction and selection for EMG signal classification" 2 | %(1) 3 | 4 | function IEMG = jIntegratedEMG(X,~) 5 | IEMG = sum(abs(X)); 6 | end 7 | 8 | -------------------------------------------------------------------------------- /jSimpleSquareIntegral.m: -------------------------------------------------------------------------------- 1 | %[2012]-"Feature reduction and selection for EMG signal classification" 2 | %(5) 3 | 4 | function SSI = jSimpleSquareIntegral(X,~) 5 | SSI = sum(X .^ 2); 6 | end 7 | 8 | -------------------------------------------------------------------------------- /jInterquartileRange.m: -------------------------------------------------------------------------------- 1 | %[2020]-"Detecting Neuromuscular Disorders Using EMG Signals Based on TQWT 2 | %Features" (7) 3 | 4 | function IQR = jInterquartileRange(X,~) 5 | % Interquartile range 6 | IQR = iqr(X); 7 | end 8 | 9 | -------------------------------------------------------------------------------- /jVarianceOfEMG.m: -------------------------------------------------------------------------------- 1 | %[2010]-"Study of stability of time-domain features for electromyographic 2 | %pattern recognition" (6) 3 | 4 | function VAR = jVarianceOfEMG(X,~) 5 | N = length(X); 6 | VAR = (1 / (N - 1)) * sum(X .^ 2); 7 | end 8 | -------------------------------------------------------------------------------- /jWaveformLength.m: -------------------------------------------------------------------------------- 1 | %[1993]-"A New Strategy for Multifunction Myoelectric Control" (5) 2 | 3 | function WL = jWaveformLength(X,~) 4 | N = length(X); 5 | WL = 0; 6 | for k = 2:N 7 | WL = WL + abs(X(k) - X(k-1)); 8 | end 9 | end 10 | 11 | -------------------------------------------------------------------------------- /jLogDetector.m: -------------------------------------------------------------------------------- 1 | %[2010]-"Study of stability of time-domain features for 2 | %electromyographic pattern recognition" (7) 3 | 4 | function LD = jLogDetector(X,~) 5 | N = length(X); 6 | Y = 0; 7 | for k = 1:N 8 | Y = Y + log(abs(X(k))); 9 | end 10 | LD = exp(Y / N); 11 | end 12 | 13 | -------------------------------------------------------------------------------- /jAverageAmplitudeChange.m: -------------------------------------------------------------------------------- 1 | %[2012]-"Feature reduction and selection for EMG signal classification" 2 | %(15) 3 | 4 | function AAC = jAverageAmplitudeChange(X,~) 5 | N = length(X); 6 | Y = 0; 7 | for i = 1 : N - 1 8 | Y = Y + abs(X(i + 1) - X(i)); 9 | end 10 | AAC = Y / N; 11 | end 12 | 13 | -------------------------------------------------------------------------------- /jLogCoefficientOfVariation.m: -------------------------------------------------------------------------------- 1 | %[2017]-"A framework of temporal-spatial descriptors based feature 2 | %extraction for improved myoelectric pattern recognition" (10) 3 | 4 | function LCOV = jLogCoefficientOfVariation(X,~) 5 | mu = mean(X); 6 | sd = std(X); 7 | LCOV = log(sd / mu); 8 | end 9 | 10 | -------------------------------------------------------------------------------- /jRootMeanSquare.m: -------------------------------------------------------------------------------- 1 | %[2011]-"2011 Comparison of k-nearest neighbor, quadratic discriminant 2 | %and linear discriminant analysis in classification of electromyogram 3 | %signals based on the wrist-motion directions" (9) 4 | 5 | function RMS = jRootMeanSquare(X,~) 6 | RMS = sqrt(mean(X .^ 2)); 7 | end 8 | 9 | -------------------------------------------------------------------------------- /jMaximumFractalLength.m: -------------------------------------------------------------------------------- 1 | %[2012]-"Fractal analysis features for weak and single-channel 2 | %upper-limb EMG signals" (6) 3 | 4 | function MFL = jMaximumFractalLength(X,~) 5 | N = length(X); 6 | Y = 0; 7 | for n = 1 : N - 1 8 | Y = Y + (X(n+1) - X(n)) ^ 2; 9 | end 10 | MFL = log10(sqrt(Y)); 11 | end 12 | 13 | -------------------------------------------------------------------------------- /jMeanAbsoluteDeviation.m: -------------------------------------------------------------------------------- 1 | %[2020]-"Detecting Neuromuscular Disorders Using EMG Signals Based on 2 | %TQWT Features" (6) 3 | 4 | function MAD = jMeanAbsoluteDeviation(X,~) 5 | N = length(X); 6 | % Mean value 7 | mu = mean(X); 8 | % Mean absolute deviation 9 | MAD = (1 / N) * sum(abs(X - mu)); 10 | end 11 | 12 | -------------------------------------------------------------------------------- /jDifferenceVarianceValue.m: -------------------------------------------------------------------------------- 1 | %[2014]-"Feature extraction of the first difference of EMG time series 2 | %for EMG pattern recognition" (Table 1) 3 | 4 | function DVARV = jDifferenceVarianceValue(X,~) 5 | N = length(X); 6 | Y = 0; 7 | for i = 1 : N - 1 8 | Y = Y + (X(i+1) - X(i)) ^ 2; 9 | end 10 | DVARV = Y / (N - 2); 11 | end 12 | 13 | -------------------------------------------------------------------------------- /jTemporalMoment.m: -------------------------------------------------------------------------------- 1 | %[2012]-"Feature reduction and selection for EMG signal classification" 2 | %(7-9) 3 | 4 | function TM = jTemporalMoment(X,opts) 5 | % Parameter 6 | order = 3; % order 7 | 8 | if isfield(opts,'order'), order = opts.order; end 9 | 10 | N = length(X); 11 | TM = abs((1 / N) * sum(X .^ order)); 12 | end 13 | 14 | -------------------------------------------------------------------------------- /jLogDifferenceAbsoluteMeanValue.m: -------------------------------------------------------------------------------- 1 | %[2014]-"Feature extraction of the first difference of EMG time series 2 | %for EMG pattern recognition" (7) 3 | 4 | function LDAMV = jLogDifferenceAbsoluteMeanValue(X,~) 5 | N = length(X); 6 | Y = 0; 7 | for t = 1 : N - 1 8 | Y = Y + abs((X(t+1) - X(t))); 9 | end 10 | LDAMV = log(Y / N); 11 | end 12 | 13 | -------------------------------------------------------------------------------- /jVOrder.m: -------------------------------------------------------------------------------- 1 | %[2012]-"Feature reduction and selection for EMG signal classification" 2 | %(12) 3 | 4 | function VO = jVOrder(X,opts) 5 | % Parameter 6 | order = 2; % order 7 | 8 | if isfield(opts,'order'), order = opts.order; end 9 | 10 | N = length(X); 11 | Y = (1 / N) * sum(X .^ order); 12 | VO = Y ^ (1 / order); 13 | end 14 | 15 | -------------------------------------------------------------------------------- /jLogTeagerKaiserEnergyOperator.m: -------------------------------------------------------------------------------- 1 | %[2017]-"A framework of temporal-spatial descriptors based feature 2 | %extraction for improved myoelectric pattern recognition" (11) 3 | 4 | function LTKEO = jLogTeagerKaiserEnergyOperator(X,~) 5 | N = length(X); 6 | Y = 0; 7 | for j = 2 : N - 1 8 | Y = Y + ((X(j) ^ 2) - X(j-1) * X(j+1)); 9 | end 10 | LTKEO = log(Y); 11 | end 12 | 13 | -------------------------------------------------------------------------------- /jLogDifferenceAbsoluteStandardDeviationValue.m: -------------------------------------------------------------------------------- 1 | %[2014]-"Feature extraction of the first difference of EMG time series 2 | %for EMG pattern recognition" (8) 3 | 4 | function LDASDV = jLogDifferenceAbsoluteStandardDeviationValue(X,~) 5 | N = length(X); 6 | Y = 0; 7 | for t = 1 : N - 1 8 | Y = Y + (X(t+1) - X(t)) ^ 2; 9 | end 10 | LDASDV = log(sqrt(Y / (N - 1))); 11 | end 12 | 13 | -------------------------------------------------------------------------------- /jAutoRegressiveModel.m: -------------------------------------------------------------------------------- 1 | %[2012]-"Classification of EMG signals using combined features and 2 | %soft computing techniques" (1-2) 3 | 4 | function AR = jAutoRegressiveModel(X,opts) 5 | % Parameter 6 | order = 4; % order 7 | 8 | if isfield(opts,'order'), order = opts.order; end 9 | 10 | Y = arburg(X,order); 11 | % First index is meaningless 12 | AR = Y(2 : order + 1); 13 | end 14 | 15 | -------------------------------------------------------------------------------- /jModifiedMeanAbsoluteValue.m: -------------------------------------------------------------------------------- 1 | %[2012]-"Feature reduction and selection for EMG signal classification" 2 | %(3) 3 | 4 | function MMAV = jModifiedMeanAbsoluteValue(X,~) 5 | N = length(X); 6 | Y = 0; 7 | for i = 1:N 8 | if i >= 0.25 * N && i <= 0.75 * N 9 | w = 1; 10 | else 11 | w = 0.5; 12 | end 13 | Y = Y + (w * abs(X(i))); 14 | end 15 | MMAV = (1 / N) * Y; 16 | end 17 | 18 | -------------------------------------------------------------------------------- /jEnhancedWaveLength.m: -------------------------------------------------------------------------------- 1 | %[2019]-"Classification of Hand Movements based on Discrete Wavelet 2 | %Transform and Enhanced Feature Extraction" (18) 3 | 4 | function EWL = jEnhancedWaveLength(X,~) 5 | L = length(X); 6 | EWL = 0; 7 | for i = 2:L 8 | if i >= 0.2 * L && i <= 0.8 * L 9 | p = 0.75; 10 | else 11 | p = 0.5; 12 | end 13 | EWL = EWL + abs((X(i) - X(i-1)) ^ p); 14 | end 15 | end 16 | 17 | -------------------------------------------------------------------------------- /jDifferenceAbsoluteMeanValue.m: -------------------------------------------------------------------------------- 1 | %[2011]-"Comparison of k-nearest neighbor, quadratic discriminant and 2 | %linear discriminant analysis in classification of electromyogram 3 | %signals based on wrist motion directions" (5) 4 | 5 | function DAMV = jDifferenceAbsoluteMeanValue(X,~) 6 | N = length(X); 7 | Y = 0; 8 | for i = 1 : N - 1 9 | Y = Y + abs(X(i+1) - X(i)); 10 | end 11 | DAMV = Y / (N - 1); 12 | end 13 | 14 | 15 | -------------------------------------------------------------------------------- /jEnhancedMeanAbsoluteValue.m: -------------------------------------------------------------------------------- 1 | %[2019]-"Classification of Hand Movements based on Discrete Wavelet 2 | %Transform and Enhanced Feature Extraction" (17) 3 | 4 | function EMAV = jEnhancedMeanAbsoluteValue(X,~) 5 | L = length(X); 6 | Y = 0; 7 | for i = 1:L 8 | if i >= 0.2 * L && i <= 0.8 * L 9 | p = 0.75; 10 | else 11 | p = 0.5; 12 | end 13 | Y = Y + abs(X(i) ^ p); 14 | end 15 | EMAV = Y / L; 16 | end 17 | 18 | -------------------------------------------------------------------------------- /jMyopulsePercentageRate.m: -------------------------------------------------------------------------------- 1 | %[2012]-"Feature reduction and selection for EMG signal classification" 2 | %(18) 3 | 4 | 5 | function MYOP = jMyopulsePercentageRate(X,opts) 6 | % Parameter 7 | thres = 0.016; % threshold 8 | 9 | if isfield(opts,'thres'), thres = opts.thres; end 10 | 11 | N = length(X); 12 | Y = 0; 13 | for i = 1:N 14 | if abs(X(i)) >= thres 15 | Y = Y + 1; 16 | end 17 | end 18 | MYOP = Y / N; 19 | end 20 | 21 | -------------------------------------------------------------------------------- /jWillisonAmplitude.m: -------------------------------------------------------------------------------- 1 | %[2010]-"Study of stability of time-domain features for 2 | %electromyographic pattern recognition" (5) 3 | 4 | function WA = jWillisonAmplitude(X,opts) 5 | % Parameter 6 | thres = 0.01; % threshold 7 | 8 | if isfield(opts,'thres'), thres = opts.thres; end 9 | 10 | N = length(X); 11 | WA = 0; 12 | for k = 1 : N - 1 13 | if abs(X(k) - X(k+1)) > thres 14 | WA = WA + 1; 15 | end 16 | end 17 | end 18 | 19 | -------------------------------------------------------------------------------- /jNewZeroCrossing.m: -------------------------------------------------------------------------------- 1 | %[2020]-"A Study of Computing Zero Crossing Methods and an Improved 2 | %Proposal for EMG Signals" 3 | 4 | function FZC = jNewZeroCrossing(X,~) 5 | L = length(X); 6 | FZC = 0; 7 | % Compute T (21) 8 | T = 4 * ((1/10) * sum(X(1 : 10))); 9 | % Compute proposed zero crossing (20) 10 | for i = 1 : L - 1 11 | if (X(i) > T && X(i+1) < T) || (X(i) < T && X(i+1) > T) 12 | FZC = FZC + 1; 13 | end 14 | end 15 | end 16 | 17 | -------------------------------------------------------------------------------- /jDifferenceAbsoluteStandardDeviationValue.m: -------------------------------------------------------------------------------- 1 | %[2011]-"2011 Comparison of k-nearest neighbor, quadratic discriminant 2 | %and linear discriminant analysis in classification of electromyogram 3 | %signals based on the wrist-motion directions" (8) 4 | 5 | function DASDV = jDifferenceAbsoluteStandardDeviationValue(X,~) 6 | N = length(X); 7 | Y = 0; 8 | for i = 1 : N - 1 9 | Y = Y + (X(i+1) - X(i)) ^ 2; 10 | end 11 | DASDV = sqrt(Y / (N - 1)); 12 | end 13 | 14 | -------------------------------------------------------------------------------- /jModifiedMeanAbsoluteValue2.m: -------------------------------------------------------------------------------- 1 | %[2012]-"Feature reduction and selection for EMG signal classification" 2 | %(4) 3 | 4 | function MMAV2 = jModifiedMeanAbsoluteValue2(X,~) 5 | N = length(X); 6 | Y = 0; 7 | for i = 1:N 8 | if i >= 0.25 * N && i <= 0.75 * N 9 | w = 1; 10 | elseif i < 0.25 * N 11 | w = (4 * i) / N; 12 | else 13 | w = 4 * (i - N) / N; 14 | end 15 | Y = Y + (w * abs(X(i))); 16 | end 17 | MMAV2 = (1 / N) * Y; 18 | end 19 | 20 | -------------------------------------------------------------------------------- /jZeroCrossing.m: -------------------------------------------------------------------------------- 1 | %[1993]-"A New Strategy for Multifunction Myoelectric Control" (3) 2 | 3 | function ZC = jZeroCrossing(X,opts) 4 | % Parameter 5 | thres = 0.01; % threshold 6 | 7 | if isfield(opts,'thres'), thres = opts.thres; end 8 | 9 | N = length(X); 10 | ZC = 0; 11 | for k = 1 : N - 1 12 | if ((X(k) > 0 && X(k+1) < 0) || (X(k) < 0 && X(k+1) > 0)) ... 13 | && (abs(X(k) - X(k+1)) >= thres) 14 | 15 | ZC = ZC + 1; 16 | end 17 | end 18 | end 19 | 20 | -------------------------------------------------------------------------------- /jCardinality.m: -------------------------------------------------------------------------------- 1 | %[2018]-"Effect of threshold values on the combination of EMG time 2 | %domain features: Surface versus intramuscular EMG" (Table 1) 3 | 4 | function CARD = jCardinality(X,opts) 5 | % Parameter 6 | thres = 0.01; % threshold 7 | 8 | if isfield(opts,'thres'), thres = opts.thres; end 9 | 10 | N = length(X); 11 | % Sort data 12 | Y = sort(X); 13 | Z = zeros(1, N-1); 14 | for n = 1 : N - 1 15 | Z(n) = abs(Y(n) - Y(n+1)) > thres; 16 | end 17 | CARD = sum(Z); 18 | end 19 | 20 | -------------------------------------------------------------------------------- /jSlopeSignChange.m: -------------------------------------------------------------------------------- 1 | %[1993]-"A New Strategy for Multifunction Myoelectric Control" (4) 2 | 3 | function SSC = jSlopeSignChange(X,opts) 4 | % Parameter 5 | thres = 0.01; % threshold 6 | 7 | if isfield(opts,'thres'), thres = opts.thres; end 8 | 9 | N = length(X); 10 | SSC = 0; 11 | for k = 2 : N - 1 12 | if ((X(k) > X(k-1) && X(k) > X(k+1)) || (X(k) < X(k-1) && ... 13 | X(k) < X(k+1))) && ((abs(X(k) - X(k+1)) >= thres) || ... 14 | (abs(X(k) - X(k-1)) >= thres)) 15 | 16 | SSC = SSC + 1; 17 | end 18 | end 19 | end 20 | 21 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2020, Jingwei Too 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | 1. Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | 2. Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | 3. Neither the name of the copyright holder nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /A_Main.m: -------------------------------------------------------------------------------- 1 | % Electromyography (EMG) Feature Extraction toolbox 2 | 3 | %---Input------------------------------------------------------------- 4 | % X : EMG signal (1 x samples) 5 | % opts : parameter settings 6 | % 7 | 8 | %---Output------------------------------------------------------------ 9 | % feat: Feature vector 10 | %--------------------------------------------------------------------- 11 | 12 | 13 | %% Generate a sample random signal X 14 | fs = 1000; % Sampling frequency 15 | Ts = 1 / fs; % Period 16 | t = 0 : Ts : 0.25; 17 | X = 0.01 * (cos(2 * pi * fs * t) + randn(1, length(t))); 18 | 19 | % Plot sample signal 20 | plot(t,X); grid on 21 | xlabel('Number of samples'); 22 | ylabel('Amplitude'); 23 | 24 | 25 | %% Example 1 : Extract 5 normal features (without parameters) 26 | % Generate a sample random signal X 27 | fs = 1000; % Sampling frequency 28 | Ts = 1 / fs; % Period 29 | t = 0 : Ts : 0.25; 30 | X = 0.01 * (cos(2 * pi * fs * t) + randn(1, length(t))); 31 | 32 | % Enhanced Mean Absolute Value 33 | f1 = jfemg('emav', X); 34 | % Average Amplitude Change 35 | f2 = jfemg('aac', X); 36 | % Waveform Length 37 | f3 = jfemg('wl', X); 38 | % Maximum Fractal Length 39 | f4 = jfemg('mfl', X); 40 | % Root Mean Square 41 | f5 = jfemg('rms', X); 42 | 43 | % Feature vector 44 | feat = [f1, f2, f3, f4, f5]; 45 | 46 | 47 | %% Example 2 : Extract 3 features with parameter 48 | % Generate a sample random signal X 49 | fs = 1000; % Sampling frequency 50 | Ts = 1 / fs; % Period 51 | t = 0 : Ts : 0.25; 52 | X = 0.01 * (cos(2 * pi * fs * t) + randn(1, length(t))); 53 | 54 | % Generate a sample random signal X 55 | fs = 1000; % Sampling frequency 56 | Ts = 1 / fs; % Period 57 | t = 0 : Ts : 0.25; 58 | X = 0.01 * (cos(2 * pi * fs * t) + randn(1, length(t))); 59 | 60 | % Zeros Crossing 61 | opts.thres = 0.01; 62 | f1 = jfemg('zc', X, opts); 63 | % Slope Sign Change 64 | opts.thres = 0.01; 65 | f2 = jfemg('ssc', X, opts); 66 | % Temporal Moment 67 | opts.order = 3; 68 | f3 = jfemg('tm', X, opts); 69 | 70 | % Feature vector 71 | feat = [f1, f2, f3]; 72 | 73 | -------------------------------------------------------------------------------- /jfemg.m: -------------------------------------------------------------------------------- 1 | % Feature Extraction Toolbox by Jingwei Too 2 | 3 | function feat = jfemg(type,X,opts) 4 | switch type 5 | case 'fzc' ; fun = @jNewZeroCrossing; 6 | case 'ewl' ; fun = @jEnhancedWaveLength; 7 | case 'emav' ; fun = @jEnhancedMeanAbsoluteValue; 8 | case 'asm' ; fun = @jAbsoluteValueOfTheSummationOfExpRoot; 9 | case 'ass' ; fun = @jAbsoluteValueOfTheSummationOfSquareRoot; 10 | case 'msr' ; fun = @jMeanValueOfTheSquareRoot; 11 | case 'ltkeo' ; fun = @jLogTeagerKaiserEnergyOperator; 12 | case 'lcov' ; fun = @jLogCoefficientOfVariation; 13 | case 'card' ; fun = @jCardinality; 14 | case 'ldasdv' ; fun = @jLogDifferenceAbsoluteStandardDeviationValue; 15 | case 'ldamv' ; fun = @jLogDifferenceAbsoluteMeanValue; 16 | case 'dvarv' ; fun = @jDifferenceVarianceValue; 17 | case 'mfl' ; fun = @jMaximumFractalLength; 18 | case 'myop' ; fun = @jMyopulsePercentageRate; 19 | case 'ssi' ; fun = @jSimpleSquareIntegral; 20 | case 'vo' ; fun = @jVOrder; 21 | case 'tm' ; fun = @jTemporalMoment; 22 | case 'aac' ; fun = @jAverageAmplitudeChange; 23 | case 'mmav' ; fun = @jModifiedMeanAbsoluteValue; 24 | case 'mmav2' ; fun = @jModifiedMeanAbsoluteValue2; 25 | case 'iemg' ; fun = @jIntegratedEMG; 26 | case 'dasdv' ; fun = @jDifferenceAbsoluteStandardDeviationValue; 27 | case 'damv' ; fun = @jDifferenceAbsoluteMeanValue; 28 | case 'rms' ; fun = @jRootMeanSquare; 29 | case 'vare' ; fun = @jVarianceOfEMG; 30 | case 'wa' ; fun = @jWillisonAmplitude; 31 | case 'ld' ; fun = @jLogDetector; 32 | case 'ar' ; fun = @jAutoRegressiveModel; 33 | case 'mav' ; fun = @jMeanAbsoluteValue; 34 | case 'zc' ; fun = @jZeroCrossing; 35 | case 'ssc' ; fun = @jSlopeSignChange; 36 | case 'wl' ; fun = @jWaveformLength; 37 | case 'mad' ; fun = @jMeanAbsoluteDeviation; 38 | case 'iqr' ; fun = @jInterquartileRange; 39 | case 'kurt' ; fun = @jKurtosis; 40 | case 'skew' ; fun = @jSkewness; 41 | case 'cov' ; fun = @jCoefficientOfVariation; 42 | case 'sd' ; fun = @jStandardDeviation; 43 | case 'var' ; fun = @jVariance; 44 | case 'ae' ; fun = @jAverageEnergy; 45 | end 46 | if nargin < 3 47 | opts = []; 48 | end 49 | feat = fun(X,opts); 50 | end 51 | 52 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Jx-EMGT : Electromyography ( EMG ) Feature Extraction Toolbox 2 | 3 | [![View EMG Feature Extraction Toolbox on File Exchange](https://www.mathworks.com/matlabcentral/images/matlab-file-exchange.svg)](https://www.mathworks.com/matlabcentral/fileexchange/71514-emg-feature-extraction-toolbox) 4 | [![License](https://img.shields.io/badge/license-BSD_3-yellow.svg)](https://github.com/JingweiToo/EMG-Feature-Extraction-Toolbox/blob/master/LICENSE) 5 | [![GitHub release](https://img.shields.io/badge/release-1.4-green.svg)](https://github.com/JingweiToo/EMG-Feature-Extraction-Toolbox) 6 | 7 | --- 8 | > "Toward Talent Scientist: Sharing and Learning Together" 9 | > --- [Jingwei Too](https://jingweitoo.wordpress.com/) 10 | --- 11 | 12 | ![Wheel](https://www.mathworks.com/matlabcentral/mlc-downloads/downloads/db6a0e07-32ec-4811-b2f8-55a80e53165e/23065655-7c83-43ba-93d5-2f4ad98c54a7/images/screenshot.PNG) 13 | 14 | 15 | ## Introduction 16 | 17 | * This toolbox offers 40 types of EMG features 18 | * The `A_Main` file demos how the feature extraction methods can be applied using generated sample signal. 19 | 20 | 21 | ## Input 22 | * *`X`* : signal ( 1 *x* samples ) 23 | * *`opts`* : parameter settings ( some methods have parameters: refer [here](/README.md#list-of-available-feature-extraction-methods) ) 24 | 25 | 26 | ## Output 27 | * *`feat`* : feature vector ( you may use other name like *f1* or etc. ) 28 | 29 | 30 | ## Usage 31 | The main function `jfemg` is adopted to perform feature extraction. You may switch the method by changing the `'mav'` to [other abbreviations](/README.md#list-of-available-feature-extraction-methods) 32 | * If you wish to extract mean absolute value ( MAV ) then you may write 33 | ```code 34 | feat = jfemg('mav', X); 35 | ``` 36 | * If you want to extract enhanced wavelenght ( EWL ) then you may write 37 | ```code 38 | feat = jfemg('ewl', X); 39 | ``` 40 | 41 | 42 | ### Example 1 : Extract 5 normal features ( without parameter ) 43 | ```code 44 | % Generate a sample random signal X 45 | fs = 1000; % Sampling frequency 46 | Ts = 1 / fs; % Period 47 | t = 0 : Ts : 0.25; 48 | X = 0.01 * (cos(2 * pi * fs * t) + randn(1, length(t))); 49 | 50 | % Plot sample signal 51 | plot(t,X); grid on 52 | xlabel('Number of samples'); 53 | ylabel('Amplitude'); 54 | 55 | % Enhanced Mean Absolute Value 56 | f1 = jfemg('emav', X); 57 | % Average Amplitude Change 58 | f2 = jfemg('aac', X); 59 | % Waveform Length 60 | f3 = jfemg('wl', X); 61 | % Maximum Fractal Length 62 | f4 = jfemg('mfl', X); 63 | % Root Mean Square 64 | f5 = jfemg('rms', X); 65 | 66 | % Feature vector 67 | feat = [f1, f2, f3, f4, f5]; 68 | 69 | % Display features 70 | disp(feat) 71 | ``` 72 | 73 | 74 | ### Example 2 : Extract 3 features with parameter 75 | ```code 76 | % Generate a sample random signal X 77 | fs = 1000; % Sampling frequency 78 | Ts = 1 / fs; % Period 79 | t = 0 : Ts : 0.25; 80 | X = 0.01 * (cos(2 * pi * fs * t) + randn(1, length(t))); 81 | 82 | % Zeros Crossing 83 | opts.thres = 0.01; 84 | f1 = jfemg('zc', X, opts); 85 | % Slope Sign Change 86 | opts.thres = 0.01; 87 | f2 = jfemg('ssc', X, opts); 88 | % Temporal Moment 89 | opts.order = 3; 90 | f3 = jfemg('tm', X, opts); 91 | 92 | % Feature vector 93 | feat = [f1, f2, f3]; 94 | 95 | % Display features 96 | disp(feat) 97 | ``` 98 | 99 | 100 | ## List of available feature extraction methods 101 | * Some methods contain parameter to be adjusted. If you do not set the parameter then the feature will be extracted using default setting 102 | * For convenience, you may extract the feature with parameter using default setting as following. That is, you don't have to set the *`opts`* 103 | ```code 104 | feat = jfemg('zc', X); 105 | ``` 106 | * You can use *`opts`* to set the parameter 107 | + *`thres`* : threshold 108 | + *`order`* : the number of orders 109 | 110 | 111 | | No. | Abbreviation | Name | Parameter ( default ) | 112 | |-----|--------------|----------------------------------------------|-------------------------| 113 | | 40 | `'emav'` | Enhanced Mean absolute value | - | 114 | | 39 | `'ewl'` | Enhanced Wavelength | - | 115 | | 38 | `'fzc'` | New Zero Crossing | - | 116 | | 37 | `'asm'` | Absolute Value of Summation of *exp* root | - | 117 | | 36 | `'ass'` | Absolute Value of Summation of Square Root | - | 118 | | 35 | `'msr'` | Mean Value of Square Root | - | 119 | | 34 | `'ltkeo'` | Log Teager Kaiser Energy Operator | - | 120 | | 33 | `'lcov'` | Log Coefficient of Variation | - | 121 | | 32 | `'card'` | Cardinality | opts.thres = 0.01 | 122 | | 31 | `'ldasdv'` | Log Difference Absolute Standard Deviation | - | 123 | | 30 | `'ldamv'` | Log Difference Absolute Mean Value | - | 124 | | 29 | `'dvarv'` | Difference Variance Value | - | 125 | | 28 | `'vo'` | V-Order | opts.order = 2 | 126 | | 27 | `'tm'` | Temporal Moment | opts.order = 3 | 127 | | 26 | `'damv'` | Difference Absolute Mean Value | - | 128 | | 25 | `'ar'` | Auto-Regressive Model | opts.order = 4 | 129 | | 24 | `'mad'` | Mean Absolute Deviation | - | 130 | | 23 | `'iqr'` | Interquartile Range | - | 131 | | 22 | `'skew'` | Skewness | - | 132 | | 21 | `'kurt'` | Kurtosis | - | 133 | | 20 | `'cov'` | Coefficient of Variation | - | 134 | | 19 | `'sd'` | Standard Deviation | - | 135 | | 18 | `'var'` | Variance | - | 136 | | 17 | `'ae'` | Average Energy | - | 137 | | 16 | `'iemg'` | Integrated EMG | - | 138 | | 15 | `'mav'` | Mean Absolute Value | - | 139 | | 14 | `'ssc'` | Slope Sign Change | opts.thres = 0.01 | 140 | | 13 | `'zc'` | Zero Crossing | opts.thres = 0.01 | 141 | | 12 | `'wl'` | Waveform Length | - | 142 | | 11 | `'rms'` | Root Mean Square | - | 143 | | 10 | `'aac'` | Average Amplitude Change | - | 144 | | 09 | `'dasdv'` | Difference Absolute Standard Deviation Value | - | 145 | | 08 | `'ld'` | Log Detector | - | 146 | | 07 | `'mmav'` | Modified Mean Absolute Value | - | 147 | | 06 | `'mmav2'` | Modified Mean Absolute Value 2 | - | 148 | | 05 | `'myop'` | Myopulse Percentage Rate | opts.thres = 0.016 | 149 | | 04 | `'ssi'` | Simple Square Integral | - | 150 | | 03 | `'vare'` | Variance of EMG | - | 151 | | 02 | `'wa'` | Willison Amplitude | opts.thres = 0.01 | 152 | | 01 | `'mfl'` | Maximum Fractal Length | - | 153 | 154 | 155 | ## Cite As 156 | ```code 157 | @article{too2019classification, 158 | title={Classification of hand movements based on discrete wavelet transform and enhanced feature extraction}, 159 | author={Too, Jingwei and Abdullah, Abdul Rahim and Saad, Norhashimah Mohd}, 160 | journal={International Journal of Advanced Computer Science and Applications}, 161 | volume={10}, 162 | number={6}, 163 | pages={83--89}, 164 | year={2019} 165 | } 166 | 167 | 168 | @article{too2019emg, 169 | title={EMG feature selection and classification using a Pbest-guide binary particle swarm optimization}, 170 | author={Too, Jingwei and Abdullah, Abdul Rahim and Mohd Saad, Norhashimah and Tee, Weihown}, 171 | journal={Computation}, 172 | volume={7}, 173 | number={1}, 174 | pages={12}, 175 | year={2019}, 176 | publisher={Multidisciplinary Digital Publishing Institute} 177 | } 178 | ``` 179 | 180 | --------------------------------------------------------------------------------