Electrophysiological Signatures of Sarcopenia: A Systematic Review of sEMG Features, Fatigue Indices and AI-Based Classifiers.
The 4 matches
- [1] § 2. Materials and Methods › 2.6. Clinical Reference Test Hand Grip Associated with Sensorimotor Response ↔ MetaEvaluation/MetaAnalysis_groups_final.m, lines 1–35 · score 0.74 · DerSimonian, Elderly Female, Elderly Male, Laird, subgroups, meta
- [2] § 3. Results › 3.3. Hand Grip-Based Clinical Reference for sEMG Assessment ↔ MetaEvaluation/validation_metafor.R, lines 194–255 · score 0.68 · prespecified independent subgroups, elderly females, elderly males, meta, REML
- [3] § 2. Materials and Methods › 2.6. Clinical Reference Test Hand Grip Associated with Sensorimotor Response ↔ MetaEvaluation/validation_metafor.R, lines 194–255 · score 0.62 · Elderly Female, Elderly Male, subgroups, meta, variance, Hu
- [4] § 2. Materials and Methods › 2.6. Clinical Reference Test Hand Grip Associated with Sensorimotor Response ↔ MetaEvaluation/MetaAnalysis_groups_final.m, lines 1–35 · score 0.58 · Elderly Female, Elderly Male, subgroup, interval, rows, DL
Paper
Loaded from Europe PMC by your browser, not stored by OSCR: doi.org · Europe PMC
The paper is loaded when this pane is shown.
The authors' code
MATLAB · 1,383 lines · 32 KB · no license · 2 matches
- %% MetaAnalysis_groups_final.m
- % MATLAB R2024b compatible
- %
- % Meta-analysis of Mean Differences (MD)
- % Random-effects models:
- % 1) DerSimonian-Laird (DL)
- % 2) REML
- %
- % Three prespecified subgroup-specific meta-analyses:
- % - Elderly_Female: k = 2
- % - Elderly_Male: k = 2
- % - Elderly: k = 4
- %
- % IMPORTANT:
- % No overall pooled estimate is calculated across the 8 rows because
- % some studies contribute to more than one subgroup analysis.
- %
- % Prediction intervals:
- % - Calculated only when k >= 3
- % - Not calculated for k < 3
- % - Results with k < 5 should be interpreted cautiously.
- %
- % Sensitivity analysis:
- % - Exclude Hu(2021) from Elderly group.
- %
- % Effect direction:
- % MD = Mean_Control - Mean_Sarcopenia
- % Positive MD = higher value in controls than in sarcopenia.
- %
- % MATLAB R2024b
- % -------------------------------------------------------------------------
- clear;
- close all;
- clc;
- %% ========================================================================
- % DATA
- % Each row:
- % {StudyName, GroupLabel, nControl, meanControl, sdControl,
- % nCase, meanCase, sdCase}
- % ========================================================================
- T = {
- 'He(2024)_F', 'Elderly_Female', 68, 20.4, 3.6, 36, 14.8, 2.6;
- 'Li(2024)_F', 'Elderly_Female', 29, 22.4, 3.0, 31, 14.4, 2.8;
- 'He(2024)_M', 'Elderly_Male', 30, 32.1, 5.3, 19, 24.1, 2.9;
- 'Li(2024)_M', 'Elderly_Male', 16, 34.1, 5.4, 17, 23.8, 2.2;
- 'Sepulveda(2025)','Elderly', 22, 24.5, 7.4, 13, 19.8, 5.9;
- 'He(2024)', 'Elderly', 98, 23.9, 7.0, 55, 18.0, 5.2;
- 'Li(2024)', 'Elderly', 45, 26.6, 6.9, 48, 17.7, 5.2;
- 'Hu(2021)', 'Elderly', 5, 29.6, 8.88, 5, 20.0, 3.74;
- };
- %% ========================================================================
- % CONVERT DATA
- % ========================================================================
- studies = T(:,1);
- groups = T(:,2);
- nC = cell2mat(T(:,3));
- mC = cell2mat(T(:,4));
- sdC = cell2mat(T(:,5));
- nT = cell2mat(T(:,6));
- mT = cell2mat(T(:,7));
- sdT = cell2mat(T(:,8));
- %% ========================================================================
- % STUDY-LEVEL EFFECT SIZES
- % ========================================================================
- % Mean Difference:
- % Control - Sarcopenia
- MD = mC - mT;
- % Within-study variance of the MD
- var_within = (sdC.^2)./nC + (sdT.^2)./nT;
- % Standard error
- se_within = sqrt(var_within);
- %% ========================================================================
- % OUTPUT DIRECTORY
- % ========================================================================
- outdir = fullfile(pwd,'outputs');
- if ~exist(outdir,'dir')
- mkdir(outdir);
- end
- %% ========================================================================
- % STUDY-LEVEL TABLE
- % ========================================================================
- T_out = table( ...
- studies(:), ...
- groups(:), ...
- nC(:), ...
- nT(:), ...
- MD(:), ...
- se_within(:), ...
- var_within(:), ...
- 'VariableNames', ...
- {'Study','Subgroup','nControl','nCase','MD','SE','Var'});
- writetable( ...
- T_out, ...
- fullfile(outdir,'per_study_table_allrows.xlsx'));
- %% ========================================================================
- % PROCESS EACH PREDEFINED GROUP
- % ========================================================================
- uniqueGroups = unique(groups,'stable');
- OutGroups = struct();
- summary_rows = {};
- for ig = 1:numel(uniqueGroups)
- grp = uniqueGroups{ig};
- fprintf('\n============================================================\n');
- fprintf('Processing group: %s\n',grp);
- fprintf('============================================================\n');
- %% ---------------------------------------------------------------
- % Select studies belonging to this subgroup
- % ---------------------------------------------------------------
- idx = find(strcmp(groups,grp));
- y = MD(idx)';
- v = var_within(idx)';
- k = numel(y);
- fprintf('Number of studies: k = %d\n',k);
- if k == 0
- warning('No studies found for group %s. Skipping.',grp);
- continue;
- end
- %% ---------------------------------------------------------------
- % FIXED-EFFECT WEIGHTS
- % ---------------------------------------------------------------
- w_fixed = 1 ./ v;
- theta_fixed = ...
- sum(w_fixed .* y) / sum(w_fixed);
- %% ---------------------------------------------------------------
- % COCHRAN Q
- % ---------------------------------------------------------------
- Q = sum( ...
- w_fixed .* ...
- (y - theta_fixed).^2);
- df_Q = k - 1;
- %% ---------------------------------------------------------------
- % DL CONSTANT C
- % ---------------------------------------------------------------
- C = ...
- sum(w_fixed) - ...
- (sum(w_fixed.^2) / sum(w_fixed));
- %% ---------------------------------------------------------------
- % DER SIMONIAN-LAIRD TAU^2
- % ---------------------------------------------------------------
- if k > 1 && C > 0
- tau2_DL = max( ...
- 0, ...
- (Q - df_Q) / C);
- else
- tau2_DL = 0;
- end
- %% ---------------------------------------------------------------
- % DL POOLED EFFECT
- % ---------------------------------------------------------------
- [theta_DL,var_theta_DL] = ...
- pooled_given_tau(y,v,tau2_DL);
- se_theta_DL = sqrt(var_theta_DL);
- ci_DL = ...
- theta_DL + ...
- norminv([0.025 0.975]) .* se_theta_DL;
- %% ---------------------------------------------------------------
- % DL WEIGHTS
- % ---------------------------------------------------------------
- wi_DL = 1 ./ (v + tau2_DL);
- weights_pct_DL = ...
- 100 .* wi_DL ./ sum(wi_DL);
- %% ---------------------------------------------------------------
- % I2
- % ---------------------------------------------------------------
- if Q > 0 && k > 1
- I2 = max( ...
- 0, ...
- ((Q - df_Q) / Q) * 100);
- else
- I2 = 0;
- end
- %% =================================================================
- % REML ESTIMATION
- % =================================================================
- % ============================================================
- % REML estimation of tau^2
- % ============================================================
- opt = optimset( ...
- 'TolX', 1e-10, ...
- 'MaxIter', 1000, ...
- 'Display', 'off');
- % Conservative upper bound for tau^2
- upper = max([ ...
- 100 * max(v), ...
- 100 * var(y), ...
- 1]);
- fun = @(t) restrictedLogLik(t, y, v);
- try
- tau2_REML = fminbnd(fun, 0, upper, opt);
- % Numerical protection
- tau2_REML = max(0, tau2_REML);
- catch ME
- warning( ...
- 'REML optimization failed for group %s: %s. tau2_REML set to 0.', ...
- grp, ME.message);
- tau2_REML = 0;
- end
- %% ---------------------------------------------------------------
- % REML POOLED EFFECT
- % ---------------------------------------------------------------
- [theta_REML,var_theta_REML] = ...
- pooled_given_tau( ...
- y,v,tau2_REML);
- se_theta_REML = sqrt(var_theta_REML);
- ci_REML = ...
- theta_REML + ...
- norminv([0.025 0.975]) .* se_theta_REML;
- %% ---------------------------------------------------------------
- % REML WEIGHTS
- % ---------------------------------------------------------------
- wi_REML = ...
- 1 ./ (v + tau2_REML);
- weights_pct_REML = ...
- 100 .* wi_REML ./ sum(wi_REML);
- %% =================================================================
- % PREDICTION INTERVALS
- % =================================================================
- %
- % PI is NOT calculated for k < 3.
- %
- % For k >= 3:
- %
- % PI = theta +/- t_(k-2,0.975)
- % * sqrt(SE_theta^2 + tau^2)
- %
- % NOTE:
- % Prediction intervals with very small k remain highly uncertain.
- % A warning is generated when k < 5.
- % =================================================================
- PI_DL = [NaN NaN];
- PI_REML = [NaN NaN];
- PI_status = "Not calculated";
- if k >= 3
- if k < 5
- warning( ...
- ['Prediction interval for group %s is based on only ' ...
- 'k=%d studies and should be interpreted cautiously.'], ...
- grp,k);
- PI_status = "Calculated with k<5; interpret cautiously";
- else
- PI_status = "Calculated";
- end
- df_PI = k - 2;
- tcrit = tinv(0.975,df_PI);
- %% DL PI
- PI_se_DL = ...
- sqrt(var_theta_DL + tau2_DL);
- PI_DL = ...
- theta_DL + ...
- [-1 1] .* tcrit .* PI_se_DL;
- %% REML PI
- PI_se_REML = ...
- sqrt(var_theta_REML + tau2_REML);
- PI_REML = ...
- theta_REML + ...
- [-1 1] .* tcrit .* PI_se_REML;
- end
- %% =================================================================
- % STORE GROUP RESULTS
- % =================================================================
- G = struct();
- G.group = grp;
- G.k = k;
- G.idx = idx;
- G.studies = studies(idx);
- G.y = y;
- G.v = v;
- G.Q = Q;
- G.df_Q = df_Q;
- G.I2 = I2;
- % DL
- G.tau2_DL = tau2_DL;
- G.theta_DL = theta_DL;
- G.se_theta_DL = se_theta_DL;
- G.ci_DL = ci_DL;
- G.weights_pct_DL = weights_pct_DL;
- % REML
- G.tau2_REML = tau2_REML;
- G.theta_REML = theta_REML;
- G.se_theta_REML = se_theta_REML;
- G.ci_REML = ci_REML;
- G.weights_pct_REML = weights_pct_REML;
- % Prediction intervals
- G.PI_DL = PI_DL;
- G.PI_REML = PI_REML;
- G.PI_status = PI_status;
- %% Store structure
- fieldName = ...
- matlab.lang.makeValidName(grp);
- OutGroups.(fieldName) = G;
- %% =================================================================
- % SUMMARY TABLE
- % =================================================================
- summary_rows(end+1,:) = { ...
- grp, ...
- k, ...
- theta_DL, ...
- ci_DL(1), ...
- ci_DL(2), ...
- PI_DL(1), ...
- PI_DL(2), ...
- tau2_DL, ...
- theta_REML, ...
- ci_REML(1), ...
- ci_REML(2), ...
- PI_REML(1), ...
- PI_REML(2), ...
- tau2_REML, ...
- Q, ...
- df_Q, ...
- I2, ...
- PI_status};
- %% =================================================================
- % FOREST PLOTS
- % =================================================================
- makeForestGroup( ...
- 'DL', ...
- G, ...
- outdir);
- makeForestGroup( ...
- 'REML', ...
- G, ...
- outdir);
- %% =================================================================
- % CONSOLE OUTPUT
- % =================================================================
- fprintf('\nGroup: %s\n',grp);
- fprintf('k = %d\n',k);
- fprintf( ...
- 'DL : theta = %.3f [%.3f, %.3f], tau2 = %.4f\n', ...
- theta_DL, ...
- ci_DL(1), ...
- ci_DL(2), ...
- tau2_DL);
- fprintf( ...
- 'REML : theta = %.3f [%.3f, %.3f], tau2 = %.4f\n', ...
- theta_REML, ...
- ci_REML(1), ...
- ci_REML(2), ...
- tau2_REML);
- fprintf( ...
- 'Q = %.3f, df = %d, I2 = %.2f%%\n', ...
- Q,df_Q,I2);
- if k >= 3
- fprintf( ...
- 'DL PI = [%.3f, %.3f]\n', ...
- PI_DL(1),PI_DL(2));
- fprintf( ...
- 'REML PI = [%.3f, %.3f]\n', ...
- PI_REML(1),PI_REML(2));
- else
- fprintf( ...
- 'Prediction intervals: NOT calculated (k < 3)\n');
- end
- end
- %% ========================================================================
- % SUMMARY TABLE
- % ========================================================================
- Tsum = cell2table( ...
- summary_rows, ...
- 'VariableNames',{ ...
- 'Group', ...
- 'k', ...
- 'Theta_DL', ...
- 'CIlo_DL', ...
- 'CIhi_DL', ...
- 'PIlo_DL', ...
- 'PIhi_DL', ...
- 'tau2_DL', ...
- 'Theta_REML', ...
- 'CIlo_REML', ...
- 'CIhi_REML', ...
- 'PIlo_REML', ...
- 'PIhi_REML', ...
- 'tau2_REML', ...
- 'Q', ...
- 'df', ...
- 'I2', ...
- 'PI_status'});
- writetable( ...
- Tsum, ...
- fullfile(outdir,'summary_by_group.xlsx'));
- %% ========================================================================
- % SAVE MATLAB RESULTS
- % ========================================================================
- save( ...
- fullfile(outdir, ...
- 'MetaAnalysis_groups_results.mat'), ...
- 'OutGroups', ...
- 'T_out', ...
- 'Tsum');
- %% ========================================================================
- % SENSITIVITY ANALYSIS
- % EXCLUDE HU(2021) FROM ELDERLY GROUP
- % ========================================================================
- groupName = 'Elderly';
- fieldName = ...
- matlab.lang.makeValidName(groupName);
- if ~isfield(OutGroups,fieldName)
- warning( ...
- 'Group %s not found. Sensitivity analysis skipped.', ...
- groupName);
- else
- S = OutGroups.(fieldName);
- idx = S.idx;
- %% ---------------------------------------------------------------
- % Locate Hu(2021)
- % ---------------------------------------------------------------
- hu_label = 'Hu(2021)';
- hu_global_idx = ...
- find(strcmp(studies,hu_label),1);
- if isempty(hu_global_idx)
- warning( ...
- 'Hu(2021) was not found.');
- elseif ~ismember(hu_global_idx,idx)
- warning( ...
- 'Hu(2021) is not part of the Elderly group.');
- else
- %% -----------------------------------------------------------
- % Dataset without Hu
- % -----------------------------------------------------------
- idx_no_hu = ...
- idx(idx ~= hu_global_idx);
- y_s = MD(idx_no_hu)';
- v_s = var_within(idx_no_hu)';
- k_s = numel(y_s);
- fprintf('\n============================================================\n');
- fprintf('Sensitivity analysis: Excluding Hu(2021)\n');
- fprintf('Original k = %d\n',numel(idx));
- fprintf('Without Hu k = %d\n',k_s);
- fprintf('============================================================\n');
- %% -----------------------------------------------------------
- % DL
- % -----------------------------------------------------------
- w_fixed_s = 1 ./ v_s;
- theta_fixed_s = ...
- sum(w_fixed_s .* y_s) / ...
- sum(w_fixed_s);
- Q_s = ...
- sum(w_fixed_s .* ...
- (y_s - theta_fixed_s).^2);
- df_s = k_s - 1;
- C_s = ...
- sum(w_fixed_s) - ...
- sum(w_fixed_s.^2) / ...
- sum(w_fixed_s);
- if k_s > 1 && C_s > 0
- tau2_DL_s = max( ...
- 0, ...
- (Q_s - df_s) / C_s);
- else
- tau2_DL_s = 0;
- end
- [theta_DL_s,var_theta_DL_s] = ...
- pooled_given_tau( ...
- y_s,v_s,tau2_DL_s);
- se_DL_s = sqrt(var_theta_DL_s);
- ci_DL_s = ...
- theta_DL_s + ...
- norminv([0.025 0.975]) .* se_DL_s;
- if Q_s > 0 && k_s > 1
- I2_s = max( ...
- 0, ...
- ((Q_s-df_s)/Q_s)*100);
- else
- I2_s = 0;
- end
- % ============================================================
- % REML for sensitivity analysis
- % ============================================================
- if k_s >= 1
- opt = optimset( ...
- 'TolX', 1e-10, ...
- 'MaxIter', 1000, ...
- 'Display', 'off');
- upper_bound_s = max([ ...
- 100 * max(v_s), ...
- 100 * var(y_s), ...
- 1]);
- fun_s = @(t) restrictedLogLik(t, y_s, v_s);
- try
- tau2_REML_s = fminbnd( ...
- fun_s, ...
- 0, ...
- upper_bound_s, ...
- opt);
- tau2_REML_s = max(0, tau2_REML_s);
- catch ME
- warning( ...
- 'REML sensitivity optimization failed: %s. tau2_REML_s set to 0.', ...
- E.message);
- tau2_REML_s = 0;
- end
- [theta_REML_s, var_theta_REML_s] = ...
- pooled_given_tau(y_s, v_s, tau2_REML_s);
- se_theta_REML_s = sqrt(var_theta_REML_s);
- ci_REML_s = theta_REML_s + ...
- norminv([0.025 0.975]) * se_theta_REML_s;
- else
- tau2_REML_s = NaN;
- theta_REML_s = NaN;
- ci_REML_s = [NaN NaN];
- end
- [theta_REML_s,var_theta_REML_s] = ...
- pooled_given_tau( ...
- y_s,v_s,tau2_REML_s);
- se_REML_s = ...
- sqrt(var_theta_REML_s);
- ci_REML_s = ...
- theta_REML_s + ...
- norminv([0.025 0.975]) .* se_REML_s;
- %% -----------------------------------------------------------
- % Prediction intervals after excluding Hu
- % -----------------------------------------------------------
- PI_DL_s = [NaN NaN];
- PI_REML_s = [NaN NaN];
- if k_s >= 3
- if k_s < 5
- warning( ...
- ['Sensitivity PI uses only k=%d studies. ' ...
- 'Interpret cautiously.'],k_s);
- end
- df_PI_s = k_s - 2;
- tcrit_s = ...
- tinv(0.975,df_PI_s);
- PI_DL_s = ...
- theta_DL_s + ...
- [-1 1] .* ...
- tcrit_s .* ...
- sqrt(var_theta_DL_s + tau2_DL_s);
- PI_REML_s = ...
- theta_REML_s + ...
- [-1 1] .* ...
- tcrit_s .* ...
- sqrt(var_theta_REML_s + tau2_REML_s);
- end
- %% -----------------------------------------------------------
- % Sensitivity table
- % -----------------------------------------------------------
- sens_rows = { ...
- 'Original_with_Hu_DL', ...
- theta_DL, ...
- S.ci_DL(1), ...
- S.ci_DL(2), ...
- S.PI_DL(1), ...
- S.PI_DL(2), ...
- S.tau2_DL, ...
- S.Q, ...
- S.I2;
- 'Original_with_Hu_REML', ...
- theta_REML, ...
- S.ci_REML(1), ...
- S.ci_REML(2), ...
- S.PI_REML(1), ...
- S.PI_REML(2), ...
- S.tau2_REML, ...
- NaN, ...
- NaN;
- 'Exclude_Hu_DL', ...
- theta_DL_s, ...
- ci_DL_s(1), ...
- ci_DL_s(2), ...
- PI_DL_s(1), ...
- PI_DL_s(2), ...
- tau2_DL_s, ...
- Q_s, ...
- I2_s;
- 'Exclude_Hu_REML', ...
- theta_REML_s, ...
- ci_REML_s(1), ...
- ci_REML_s(2), ...
- PI_REML_s(1), ...
- PI_REML_s(2), ...
- tau2_REML_s, ...
- NaN, ...
- NaN};
- T_sens = cell2table( ...
- sens_rows, ...
- 'VariableNames',{ ...
- 'Scenario', ...
- 'Theta', ...
- 'CI_lo', ...
- 'CI_hi', ...
- 'PI_lo', ...
- 'PI_hi', ...
- 'tau2', ...
- 'Q', ...
- 'I2'});
- writetable( ...
- T_sens, ...
- fullfile( ...
- outdir, ...
- 'sensitivity_exclude_Hu2021.xlsx'));
- %% -----------------------------------------------------------
- % Percentage change
- % -----------------------------------------------------------
- PercentChange = table( ...
- {'Theta_DL'; ...
- 'tau2_DL'; ...
- 'I2_DL'; ...
- 'Theta_REML'; ...
- 'tau2_REML'}, ...
- [ ...
- 100*(theta_DL_s-S.theta_DL)/S.theta_DL; ...
- 100*(tau2_DL_s-S.tau2_DL)/S.tau2_DL; ...
- 100*(I2_s-S.I2)/S.I2; ...
- 100*(theta_REML_s-S.theta_REML)/S.theta_REML; ...
- 100*(tau2_REML_s-S.tau2_REML)/S.tau2_REML], ...
- 'VariableNames', ...
- {'Metric','PercentChange'});
- writetable( ...
- PercentChange, ...
- fullfile( ...
- outdir, ...
- 'sensitivity_percent_change_Hu2021.xlsx'));
- %% -----------------------------------------------------------
- % Console
- % -----------------------------------------------------------
- fprintf('\nSensitivity results:\n');
- fprintf( ...
- 'DL original : %.3f [%.3f, %.3f]\n', ...
- S.theta_DL,S.ci_DL(1),S.ci_DL(2));
- fprintf( ...
- 'DL no Hu : %.3f [%.3f, %.3f]\n', ...
- theta_DL_s,ci_DL_s(1),ci_DL_s(2));
- fprintf( ...
- 'REML original : %.3f [%.3f, %.3f]\n', ...
- S.theta_REML,S.ci_REML(1),S.ci_REML(2));
- fprintf( ...
- 'REML no Hu : %.3f [%.3f, %.3f]\n', ...
- theta_REML_s,ci_REML_s(1),ci_REML_s(2));
- fprintf('\n');
- fprintf( ...
- 'DL tau2: %.6f -> %.6f\n', ...
- S.tau2_DL,tau2_DL_s);
- fprintf( ...
- 'REML tau2: %.6f -> %.6f\n', ...
- S.tau2_REML,tau2_REML_s);
- %% -----------------------------------------------------------
- % Forest plots without Hu
- % -----------------------------------------------------------
- S_s = struct();
- S_s.group = 'Elderly_noHu';
- S_s.k = k_s;
- S_s.studies = studies(idx_no_hu);
- S_s.y = y_s(:);
- S_s.v = v_s(:);
- S_s.theta_DL = theta_DL_s;
- S_s.ci_DL = ci_DL_s;
- S_s.tau2_DL = tau2_DL_s;
- S_s.theta_REML = theta_REML_s;
- S_s.ci_REML = ci_REML_s;
- S_s.tau2_REML = tau2_REML_s;
- S_s.PI_DL = PI_DL_s;
- S_s.PI_REML = PI_REML_s;
- S_s.weights_pct_DL = ...
- 100*(1./(v_s+tau2_DL_s)) ./ ...
- sum(1./(v_s+tau2_DL_s));
- S_s.weights_pct_REML = ...
- 100*(1./(v_s+tau2_REML_s)) ./ ...
- sum(1./(v_s+tau2_REML_s));
- makeForestGroup( ...
- 'DL', ...
- S_s, ...
- outdir);
- makeForestGroup( ...
- 'REML', ...
- S_s, ...
- outdir);
- end
- end
- %% ========================================================================
- % FINISH
- % ========================================================================
- fprintf('\n============================================================\n');
- fprintf('META-ANALYSIS COMPLETED\n');
- fprintf('Results saved in:\n%s\n',outdir);
- fprintf('============================================================\n');
- %% ========================================================================
- % LOCAL FUNCTION 1. ajustada por el tipo de analisis
- % REML RESTRICTED LOG-LIKELIHOOD
- % ========================================================================
- function nll = restrictedLogLik(tau2, y, v)
- % ============================================================
- % Restricted log-likelihood for REML estimation of tau^2
- % Random-effects meta-analysis with a single pooled intercept
- %
- % y = study-level effect estimates
- % v = within-study sampling variances
- % tau2 = between-study variance
- %
- % The function returns the NEGATIVE restricted log-likelihood,
- % because fminbnd performs minimization.
- % ============================================================
- % Ensure column vectors
- y = y(:);
- v = v(:);
- % Invalid values
- if tau2 < 0 || any(v <= 0) || any(~isfinite(v)) || any(~isfinite(y))
- nll = Inf;
- return;
- end
- % Total variance for each study
- sigma2 = v + tau2;
- % Random-effects weights
- w = 1 ./ sigma2;
- % Sum of weights
- W = sum(w);
- % Estimated pooled effect for this value of tau2
- mu_hat = sum(w .* y) / W;
- % Weighted residual sum of squares
- residuals = y - mu_hat;
- Q_tau = sum(w .* residuals.^2);
- % Restricted negative log-likelihood
- %
- % REML for a model with one fixed effect (the pooled mean):
- %
- % -2 log L_REML =
- % sum(log(sigma2))
- % + log(W)
- % + Q_tau
- %
- % Constants independent of tau2 are omitted.
- nll = 0.5 * ( ...
- sum(log(sigma2)) + ...
- log(W) + ...
- Q_tau );
- % Numerical protection
- if ~isfinite(nll)
- nll = Inf;
- end
- end
- % function out = restrictedLogLik_REML(tau2,y,v)
- %
- % % Ensure non-negative tau2
- % tau2 = max(tau2,0);
- %
- % % Total variance
- % vi = v + tau2;
- %
- % if any(~isfinite(vi)) || any(vi <= 0)
- %
- % out = Inf;
- % return;
- %
- % end
- %
- % % Random-effects weights
- % w = 1 ./ vi;
- %
- % % Sum of weights
- % W = sum(w);
- %
- % if ~isfinite(W) || W <= 0
- %
- % out = Inf;
- % return;
- %
- % end
- %
- % % Weighted pooled estimate
- % theta = ...
- % sum(w .* y) / W;
- %
- % % Weighted residual heterogeneity
- % Q_tau = ...
- % sum(w .* (y-theta).^2);
- %
- % k = numel(y);
- %
- % % Need at least 2 studies
- % if k < 2 || Q_tau <= 0
- %
- % out = Inf;
- % return;
- %
- % end
- %
- % % REML objective function
- % %
- % % Constants independent of tau2 are omitted.
- % %
- % % -2 log L_REML =
- % % sum(log(vi))
- % % + log(sum(w))
- % % + (k-1)*log(Q_tau)
- %
- % out = 0.5 * ( ...
- % sum(log(vi)) + ...
- % log(W) + ...
- % (k-1)*log(Q_tau) );
- %
- % if ~isfinite(out)
- %
- % out = Inf;
- %
- % end
- %
- % end
- %
- %
- %% ========================================================================
- % LOCAL FUNCTION 2
- % POOLED EFFECT GIVEN TAU2
- % ========================================================================
- function [theta,var_theta] = ...
- pooled_given_tau(y,v,tau2)
- w = 1 ./ (v + tau2);
- theta = ...
- sum(w .* y) / sum(w);
- var_theta = ...
- 1 / sum(w);
- end
- %% ========================================================================
- % LOCAL FUNCTION 3
- % FOREST PLOT
- % ========================================================================
- function makeForestGroup(method,G,outdir)
- studies = G.studies;
- y = G.y(:);
- v = G.v(:);
- k = G.k;
- %% ---------------------------------------------------------------
- % Select estimator
- % ---------------------------------------------------------------
- if strcmpi(method,'DL')
- theta = G.theta_DL;
- ci = G.ci_DL;
- tau2 = G.tau2_DL;
- if isfield(G,'weights_pct_DL')
- weights_pct = ...
- G.weights_pct_DL;
- else
- weights_pct = ...
- 100*(1./(v+tau2)) ./ ...
- sum(1./(v+tau2));
- end
- else
- theta = G.theta_REML;
- ci = G.ci_REML;
- tau2 = G.tau2_REML;
- if isfield(G,'weights_pct_REML')
- weights_pct = ...
- G.weights_pct_REML;
- else
- weights_pct = ...
- 100*(1./(v+tau2)) ./ ...
- sum(1./(v+tau2));
- end
- end
- %% ---------------------------------------------------------------
- % Figure
- % ---------------------------------------------------------------
- fig = figure( ...
- 'Visible','off', ...
- 'Units','pixels', ...
- 'Position',[100 100 1100 650]);
- ax = axes('Parent',fig);
- hold(ax,'on');
- %% ---------------------------------------------------------------
- % Plot study effects
- % ---------------------------------------------------------------
- ypos = (1:k)';
- max_w = max(weights_pct);
- if max_w <= 0
- max_w = 1;
- end
- for i = 1:k
- xi = y(i);
- sei = sqrt(v(i));
- ci_low = ...
- xi - 1.96*sei;
- ci_high = ...
- xi + 1.96*sei;
- % Confidence interval
- plot( ...
- ax, ...
- [ci_low ci_high], ...
- [ypos(i) ypos(i)], ...
- 'k-', ...
- 'LineWidth',1.4);
- % Study marker
- sz = ...
- max(25, ...
- 150*weights_pct(i)/max_w);
- scatter( ...
- ax, ...
- xi, ...
- ypos(i), ...
- sz, ...
- 'k', ...
- 'filled');
- end
- %% ---------------------------------------------------------------
- % X limits
- % ---------------------------------------------------------------
- xleft = ...
- min([y - 3*sqrt(v); ci(1)]);
- xright = ...
- max([y + 3*sqrt(v); ci(2)]);
- if ~isfinite(xleft) || ...
- ~isfinite(xright) || ...
- xleft == xright
- xleft = min(y)-1;
- xright = max(y)+1;
- end
- xmargin = ...
- 0.12*(xright-xleft);
- if xmargin == 0
- xmargin = ...
- max(1,0.1*abs(xright));
- end
- xlim(ax, ...
- [xleft-xmargin xright+xmargin]);
- %% ---------------------------------------------------------------
- % Null line
- % ---------------------------------------------------------------
- yl = [0 k+1];
- plot( ...
- ax, ...
- [0 0], ...
- yl, ...
- '--', ...
- 'Color',[0.5 0.5 0.5], ...
- 'LineWidth',1);
- %% ---------------------------------------------------------------
- % Pooled diamond
- % ---------------------------------------------------------------
- diamond_y = 0.35;
- diamond_h = 0.45;
- patch_x = [ ...
- ci(1), ...
- theta, ...
- ci(2), ...
- theta];
- patch_y = ...
- diamond_y + ...
- [-diamond_h/2, ...
- 0, ...
- diamond_h/2, ...
- 0];
- patch( ...
- ax, ...
- patch_x, ...
- patch_y, ...
- 'k', ...
- 'FaceAlpha',0.4, ...
- 'EdgeColor','k');
- %% ---------------------------------------------------------------
- % Y-axis
- % ---------------------------------------------------------------
- set( ...
- ax, ...
- 'YTick',ypos, ...
- 'YTickLabel',studies, ...
- 'YDir','reverse');
- %% ---------------------------------------------------------------
- % Pooled annotation
- % ---------------------------------------------------------------
- txtPooled = sprintf( ...
- 'Pooled = %.2f [%.2f, %.2f]', ...
- theta,ci(1),ci(2));
- text( ...
- ax, ...
- mean(ci), ...
- diamond_y+0.55, ...
- txtPooled, ...
- 'HorizontalAlignment','center', ...
- 'FontWeight','bold');
- %% ---------------------------------------------------------------
- % Study estimates and weights
- % ---------------------------------------------------------------
- xlims = xlim(ax);
- xtext = ...
- xlims(2) - ...
- 0.015*range(xlims);
- for i = 1:k
- txt = sprintf( ...
- '%.2f [%.2f, %.2f] (%.1f%%)', ...
- y(i), ...
- y(i)-1.96*sqrt(v(i)), ...
- y(i)+1.96*sqrt(v(i)), ...
- weights_pct(i));
- text( ...
- ax, ...
- xtext, ...
- ypos(i), ...
- txt, ...
- 'HorizontalAlignment','right', ...
- 'FontSize',9);
- end
- %% ---------------------------------------------------------------
- % Labels
- % ---------------------------------------------------------------
- xlabel( ...
- ax, ...
- 'Mean Difference (Control - Sarcopenia)');
- if isfield(G,'group')
- groupTitle = G.group;
- else
- groupTitle = 'Meta-analysis';
- end
- title( ...
- ax, ...
- sprintf('%s - %s', ...
- groupTitle,upper(method)), ...
- 'Interpreter','none');
- grid(ax,'on');
- %% ---------------------------------------------------------------
- % Save
- % ---------------------------------------------------------------
- safeGroup = ...
- matlab.lang.makeValidName(groupTitle);
- fname = fullfile( ...
- outdir, ...
- sprintf( ...
- 'Forest_%s_%s', ...
- safeGroup, ...
- upper(method)));
- try
- exportgraphics( ...
- fig, ...
- [fname '.png'], ...
- 'Resolution',300, ...
- 'ContentType','image');
- exportgraphics( ...
- fig, ...
- [fname '.pdf'], ...
- 'ContentType','vector');
- catch
- saveas( ...
- fig, ...
- [fname '.png']);
- saveas( ...
- fig, ...
- [fname '.pdf']);
- end
- close(fig);
- end
MetaAnalysis_groups_final.m at commit 4825af5, no license · at the source
Overview
- Instituto Politécnico Nacional, Unidad Profesional Interdisciplinaria en Ingeniería y Tecnologías Avanzadas (UPIITA), Mexico City 07340, Mexico; (K.-V.V.-D.-L.); (L.-I.G.-J.); (B.-A.R.-J.)
- Instituto Politécnico Nacional, Escuela Superior de Medicina (ESM), Mexico City 07738, Mexico
- Tecnologico de Monterrey, Escuela de Ingeniería y Ciencias, Monterrey 64849, Mexico; (J.M.A.); (O.M.-M.)
Abstract
Age-related sarcopenia involves structural and functional neuromuscular changes. Electrophysiological measures from surface electromyography (sEMG) capture activation dynamics, spectral fatigue indices and motor unit properties that may constitute objective signatures of sarcopenia. The objective of this work is to systematically review sEMG features, fatigability metrics and AI-based classification/
Reproduced under the paper's license (CC BY), from the paper cited above.
Repository
Its files are read in the Code ↔ Paper reader above, with 4 matches between paragraphs and lines of code.
c4macho/LIPS_ARTICULOS
4825af5b7c14c232dbfb4e9eaead3cbfaa7d3cc8, 30 July 2026Availability: 1 check, the latest on 27 September 2026: the link answers
- 27 September 2026: the link answers
3 files
- Concordance_Evaluation/
ConcordanceMetrics.m , MATLAB, 90 lines - MetaEvaluation/
MetaAnalysis_groups_fina , MATLAB, 1,383 lines, 2 matchesl.m - MetaEvaluation/
validation_metafor.R , R, 369 lines, 2 matches
The paper's code and data availability statement is in the Data section.
Tracing map
Proposed by the machine: these links were found in the paper and verified at the source, without human review. The map will receive a Zenodo DOI once one of the paper's authors has validated it with their ORCID.
What the map holds:
- 1 repository of the authors' code, each at its verified commit, with its license and how the link was found in the paper;
- 3 scripts, each with its path and the digest of its content;
- 4 matches between paragraphs of the paper and lines of the code (method lexical-v1);
- neither the text of the paper nor the code itself.
Its JSON (tracing-map.json) is deposited on Zenodo with its DOI once the map is validated.
Data
No dataset and no data link were found in the paper.
Data Availability Statement
The source code and Supplementary Material are available in the GitHub repository: https://
Reproduced under the paper's license (CC BY), from the paper cited above.
Versions
The history of this record: each version stored by the harvester or made by a correction of its authors or of the maintainers of its code, and what changed in its facts. The texts of the paper (its abstract, its availability statements) are not part of it; versions that changed only those are not listed.
Version 1, 27 September 2026: the first record
Recorded: type, language, journal, volume, issue, pages, dates, 7 authors, 8 keywords, 5 MeSH terms, 1 funder, 39 references.
Cite
This paper
Villanueva-De-Luna, K.-V., Garay-Jimenez, L.-I., Lomelí-González, J., Antelis, J. M., Mendoza-Montoya, O., Rico-Jiménez, B.-A., & Tovar-Corona, B. (2026). Electrophysiological Signatures of Sarcopenia: A Systematic Review of sEMG Features, Fatigue Indices and AI-Based Classifiers. Sensors (Basel, Switzerland), 26(16), 5121. https://
BibTeX
@article{villanuevadelun
author = {Villanueva-De-Luna, Karen-Victoria and Garay-Jimenez, Laura-Ivoone and Lomelí-González, Joel and Antelis, Javier M and Mendoza-Montoya, Omar and Rico-Jiménez, Blanca-Alicia and Tovar-Corona, Blanca},
title = {{Electrophysiological Signatures of Sarcopenia: A Systematic Review of sEMG Features, Fatigue Indices and AI-Based Classifiers}},
journal = {Sensors (Basel, Switzerland)},
year = {2026},
month = aug,
volume = {26},
number = {16},
pages = {5121},
publisher = {Multidisciplinary Digital Publishing Institute (MDPI)},
issn = {1424-8220},
doi = {10.3390/
url = {https://
pmid = {42655431},
pmcid = {PMC13517259}
}
RIS
TY - JOUR
AU - Villanueva-De-Luna, Karen-Victoria
AU - Garay-Jimenez, Laura-Ivoone
AU - Lomelí-González, Joel
AU - Antelis, Javier M
AU - Mendoza-Montoya, Omar
AU - Rico-Jiménez, Blanca-Alicia
AU - Tovar-Corona, Blanca
TI - Electrophysiological Signatures of Sarcopenia: A Systematic Review of sEMG Features, Fatigue Indices and AI-Based Classifiers
T2 - Sensors (Basel, Switzerland)
J2 - Sensors (Basel)
PY - 2026
DA - 2026/
VL - 26
IS - 16
SP - 5121
SN - 1424-8220
PB - Multidisciplinary Digital Publishing Institute (MDPI)
DO - 10.3390/
UR - https://
LA - en
ER -
CSL-JSON
{
"id": "10.3390/
"type": "article-journal",
"title": "Electrophysiological Signatures of Sarcopenia: A Systematic Review of sEMG Features, Fatigue Indices and AI-Based Classifiers",
"container-title": "Sensors (Basel, Switzerland)",
"author": [
{
"family": "Villanueva-De-Luna",
"given": "Karen-Victoria"
},
{
"family": "Garay-Jimenez",
"given": "Laura-Ivoone"
},
{
"family": "Lomelí-González",
"given": "Joel"
},
{
"family": "Antelis",
"given": "Javier M"
},
{
"family": "Mendoza-Montoya",
"given": "Omar"
},
{
"family": "Rico-Jiménez",
"given": "Blanca-Alicia"
},
{
"family": "Tovar-Corona",
"given": "Blanca"
}
],
"container-title-short":
"volume": "26",
"issue": "16",
"page": "5121",
"DOI": "10.3390/
"PMID": "42655431",
"PMCID": "PMC13517259",
"ISSN": "1424-8220",
"publisher": "Multidisciplinary Digital Publishing Institute (MDPI)",
"URL": "https://
"language": "en",
"issued": {
"date-parts": [
[
2026,
8,
13
]
]
}
}
The tracing map gets a citation of its own once an author has validated it and it has a DOI.
Similar papers
The papers with a page that share the most with this one: the tools found in their code, their categories, datasets, cited references and authors, the rarest counting most.
- [1] doi:10.3390/nu18172887
- Unmetabolized Folic Acid: Biology, Epidemiology, and Clinical Consequences: A Systematic Review.Journal: NutrientsIn common: 4 references
- [2] doi:10.1128/msystems.00416-26 [code]
- Integrative multicohort analysis reveals consistent sex differences in gut microbiota of multiple sclerosis patients.Journal: mSystemsIn common: metafor, 2 references
- [3] doi:10.1002/epi.70254
- Use of artificial intelligence in magnetic resonance imaging across the epileptic patient's journey: A meta-analysis of four clinical applications.Journal: EpilepsiaIn common: 3 references
- [4] doi:10.1038/s41467-026-74565-0 [code]
- The functional neurobiology of dispositions towards negative emotions.Journal: Nature communicationsIn common: metafor, Statistics and Machine Learning Toolbox
- [5] doi:10.1159/000551193
- Intracranial Arterial Calcification on Computed Tomography and Risk of Cognitive Impairment or Dementia: A Systematic Review and Meta-Analysis.Journal: Cerebrovascular diseases (Basel, Switzerland)In common: other, 2 references
- [6] doi:10.2196/83790
- Explainable and Interpretable AI for Voice and Speech Analysis in Clinical Care: Systematic Review.Journal: Journal of medical Internet researchIn common: 2 references
- [7] doi:10.1007/s10072-026-09234-7
- Creative thinking in Parkinson's disease: A systematic review and meta-analysis.Journal: Neurological sciences : official journal of the Italian Neurological Society and of the Italian Society of Clinical NeurophysiologyIn common: 2 references
- [8] doi:10.1002/gps3.70042 [code]
- Effects of single-session transcranial direct current stimulation on response inhibition in stop-signal task performance: A meta-analysis and systematic review.Journal: General psychiatryIn common: metafor, other
- [9] doi:10.3390/diseases14080268 [code]
- Common Inflammatory Pathways Between Periodontal Disease and Multiple Sclerosis: A Systematic Review.Journal: Diseases (Basel, Switzerland)In common: 2 references
- [10] doi:10.1186/s12911-026-03552-8
- Artificial intelligence for brain-to-speech decoding in paralysis: a systematic review.Journal: BMC medical informatics and decision makingIn common: 2 references
Contribute
The authors of this paper can claim it, correct its record and validate its tracing map, and the maintainers of its code (its owner, or a public member of its organization) correct what it says of their repository; anyone signed in can ask for its removal. Every request goes to OSCR's own machine, which answers it; your account page follows them.
Sign in with ORCID to claim this paper as one of its authors, correct its record or validate its tracing map: when the paper's metadata lists your ORCID iD, you are recognized at once. Maintainers of its code: sign in with GitHub, then claim the repository on your account page.
Claim this paper
Correct its record
Say what each link of this record is, remove the ones that are not the paper's, add the ones that are missing. The correction becomes a new version of the record, in its Versions section.
Validate its tracing map
You validate the map as this page shows it: 1 repository of the authors' code, each at its verified commit and with its license, 3 scripts, and 4 matches between paragraphs and code (see the Code and Map sections). It then receives a DOI on Zenodo, with you (your ORCID iD) and OSCR as its creators; the code itself is not deposited.
The map's fingerprint: sha256:5a031760bd159803…
Add the badge to its README
The badge links the code to this page. Copy one of these into the README of the paper's code: only you decide where it goes, and nothing is changed for you.
Markdown
[, paste the snippet at the top, then “Commit changes…” and, to review it first, “Create a new branch and start a pull request”. You open the pull request; OSCR asks for no permission.
Request its removal
To ask OSCR to remove this record, the copies of its authors' scripts or its tracing map, use the removal request page: signed in, you say who you are, what to remove and why, then review and confirm the request. Published rules decide every request (how).
Discussion, reproductions, activity
Discussion: questions and error reports about this paper and its code, from signed-in readers and its authors. It opens with sign-in.
Reproductions: reports from readers who ran the authors' code: what they reproduced, with which environment, commit and data. It opens with sign-in.
Activity: what happens around this paper: new versions of its record, its map's validation, discussions and reproductions. It opens with sign-in.
