fromscipy.signalimportfind_peaksdefdetect_heel_strikes(heel_z:np.ndarray,rate:float)->np.ndarray:# 매 heel marker 의 vertical low + GRF onset 의 aligninverted=-heel_zpeaks,_=find_peaks(inverted,distance=int(rate*0.5))returnpeaks# frame indicesheel_strikes=detect_heel_strikes(heel_z,rate)stride_times=np.diff(heel_strikes)/ratecadence=60.0/np.mean(stride_times)
defankle_moment(grf:np.ndarray,cop:np.ndarray,ankle:np.ndarray,segment_mass:float,segment_com:np.ndarray,segment_acc:np.ndarray,g:float=9.81)->np.ndarray:# 매 simplified — full 3D 매 segment inertia tensor 의 requirer=cop-ankleM_grf=np.cross(r,grf)inertia_term=segment_mass*(segment_acc+np.array([0,0,g]))M_inertia=np.cross(segment_com-ankle,inertia_term)returnM_grf-M_inertia
Markerless (OpenPose / OpenCap-style)
# 매 multi-view 2D keypoints → 3D triangulationdeftriangulate(kp_views:list,P_views:list)->np.ndarray:"""
kp_views: [n_views] of (n_joints, 2)
P_views: [n_views] of (3, 4) projection matrices
"""A=[]forkp,Pinzip(kp_views,P_views):forj,(u,v)inenumerate(kp):A.append(u*P[2]-P[0])A.append(v*P[2]-P[1])A=np.array(A)_,_,Vt=np.linalg.svd(A)X=Vt[-1]returnX[:3]/X[3]
Gait deviation index (GDI)
defgait_deviation_index(subject_kinematics:np.ndarray,reference_pcs:np.ndarray,reference_mean:np.ndarray)->float:# GDI: 매 subject 의 normal-database 의 PCA-distance 의 measurecentered=subject_kinematics.flatten()-reference_meanscores=reference_pcs@centeredraw_distance=np.linalg.norm(scores[:15])return100*np.exp(-(raw_distance-REFERENCE_MEAN)/REFERENCE_STD)
매 결정 기준
상황
Approach
Clinical CP / stroke
Vicon Plug-in Gait + force plates + EMG
Field sports screening
IMU + markerless video (OpenCap)
VR locomotion authoring
Mocap → IK retargeting + ML smoothing
Exergame user calibration
Single-IMU + heuristic (no full lab needed)
Research-grade longitudinal
Marker-based + standardized protocol
기본값: 매 marker-based optical + force plates 매 gold standard, markerless 매 augmenting.