Movement is measured in many modalities — joint
kinematics, kinetics (forces),
EMG, IMU — and the scientifically
interesting question is usually not any one of them but what they
share. PhysioCrossModal provides a family of
multi-modal fusion methods that take several
time-aligned modality blocks and answer complementary questions:
jive(),
multipleFactorAnalysis()cca(), plsBlocks()coupledNMF()rvCoefficient(), distanceCorrelation(),
representationalSimilarity()multimodalGaitIndex(), fuseBlocks(),
crossBlockFactor()Every method takes a list of matrices that share the observation dimension (rows = the same subjects, or gait-cycle points, or time samples), with each modality contributing its own columns (features).
Canonical correlation finds the linear combinations of two modalities whose scores are maximally correlated (auto-regularised when features exceed observations); two-block PLS maximises covariance instead, and is robust in high dimensions.
When two non-negative modalities share a latent
drive (e.g. EMG envelopes and a kinematic-speed envelope driven by the
same temporal command), coupledNMF() estimates one shared
factor W with modality-specific loadings.
rvCoefficient() is a multivariate correlation between
two blocks; distanceCorrelation() also captures
non-linear dependence (zero iff independent);
representationalSimilarity() compares each modality’s
geometry of observations (RSA). All offer permutation
p-values.
rvCoefficient(kinematics, kinetics, permutations = 1000)$rv
distanceCorrelation(kinematics, kinetics, permutations = 1000)$dcor
representationalSimilarity(list(kin = kinematics, kinet = kinetics))$similarityA low RV with a high canonical correlation means the coupling is real but low-dimensional — read several lenses together.
A composite multi-modal gait index (Gait-Deviation-Index style, but spanning modalities) scores how far a subject’s multi-modal feature vector lies from a normative reference, with a per-modality breakdown:
reference <- matrix(rnorm(300 * 20), 300, 20) # controls
subjects <- matrix(rnorm(10 * 20), 10, 20)
blocks <- list(kinematics = 1:8, kinetics = 9:14, emg = 15:20)
idx <- multimodalGaitIndex(subjects, reference, blocks = blocks)
idx$index # ~100 = typical; lower = more deviant
idx$by_modality # which modality drives each subject's deviationfuseBlocks() produces a single block-balanced design
matrix for downstream multi-view machine learning, and
crossBlockFactor() fits a common-factor model that flags
which latent factors are shared across modalities vs
modality-specific.
| question | method |
|---|---|
| what is shared vs modality-specific? | jive() |
| block-balanced shared factors | multipleFactorAnalysis() |
| which directions co-vary? (correlation / covariance) | cca() / plsBlocks() |
| a common non-negative drive | coupledNMF() |
| whole-block association (linear / non-linear / geometry) | rvCoefficient() / distanceCorrelation() /
representationalSimilarity() |
| one composite deviation score | multimodalGaitIndex() |
| feature-level fusion for ML | fuseBlocks() |
| shared vs specific latent factors | crossBlockFactor() |
These methods are cross-validated against independent,
established implementations — cca() vs base
cancor, distanceCorrelation() vs
energy::dcor, rvCoefficient() vs
FactoMineR::coeffRV, multipleFactorAnalysis()
vs FactoMineR::MFA,
representationalSimilarity() vs vegan::mantel,
crossBlockFactor() vs stats::factanal, and
jive() against its exact algebraic identity — agreeing to
machine precision, in addition to the packaged unit tests.
vignette("coupling-analysis", package = "PhysioCrossModal")
— pairwise cross-modal coupling (coherence, phase, PAC, Granger).MultiPhysioExperiment container for storing and
aligning modalities.