This is an old revision of the document!
Table of Contents
Effects of Fatigue During Basketball Free Throws Using Statistical Analysis
Abstract
This tutorial demonstrates how to use Virtual3D and Sift as tools to examine the effects of fatigue on lower body joint kinematics, specifically at the ankle, knee, and hip during basketball free throws. Using MLSE's markerless motion capture data, joint angles were computed across the trials to assess how movement changed as fatigue develops. Statistical analysis was done using SPM and ANOVA, the results revealed a consistent decrease in hip and knee flexion, along with reduced ankle dorsiflexion as the trials progressed. These changes suggest a diminished contribution from the lower body during the shooting motion under fatigue. Further analysis could explore potential compensations in upper-body joints. Follow along below to learn how this dataset was processed, visualized, and analyzed using Virtual3D and Sift.
What are the effects of fatigue on hip, knee, and ankle joint kinematics throughout 125 consecutive basketball free throw attempts?
Dataset & Relevant Links
This tutorial will be using the public dataset made available by MLSE, it includes 125 trials of one non-professional athlete completing free throws within the span of 2-3 hours. The data was collected by MLSE's Sports Performance Lab using markerless motion capture. This dataset was made available to the public with the goal to inspire the future release of more biomechanical data from other organizations to drive further advancement in the field.
Dataset is available at the following link:Dataset
In github navigate to basketball/freethrow and download the data/P001 folder which contains the dataset.
The trials in the dataset are organized as JSON files (“BB_FT_P0001_T000X.json”), where x refers to the trial ID. Each ID represents one free-throw that took place within the single session by one participant. The pose keypoints and the ball are shown in xyz positions measured in feet (in accordance with measurements in the NBA handbook). Within the README.md file there is an in-depth explanation of the court coordinate system and the 27 pose marker positions used.
The XYZ Cardan Sequence coordinate system was used to capture the complexity of the free throw motion. Using this sequence aids in not only seeing the joint angles change throughout the free throw motion but the ball trajectory as well. An in depth explanation about the Cardan Sequence can be seen here, Cardan Rotation. [1].
Processing Data in Visual3D
Below are the steps required to build and execute the single pipeline needed to process the raw dataset. The final pipeline is rather lengthy, it can be downloaded here if needed, Completed Pipeline. The pipeline is designed to automate specific commands that need to be applied across multiple files, streamlining the processing. Ultimately, all steps below should be combined and executed within one pipeline in Visual3D.
Converting Between .json and .cmz
1. Open up the Pipeline Workshop
2. Select 'Set_Pipeline_Parameter_To_Folder_Path' by clicking on the '»' in the workshop. This command selects the correct folder in your computer's directory. Change the PARAMETER_VALUE to the downloaded dataset within your own directory.
Set_Pipeline_Parameter_To_Folder_Path /PARAMETER_NAME=FOLDER /PARAMETER_VALUE=C:\...\Introductory_Project_August_2025\SPL-Open-Data-main\basketball\freethrow\data\P0001\ ! /FROM_MOTION_FILE_IN_WORKSPACE= ! /PARAMETER_VALUE_SEARCH_FOR= ! /PARAMETER_VALUE_REPLACE_WITH= ! /PARAMETER_VALUE_APPEND= ! /SET_PROMPT=Select a directory ! /ALPHABETIZE=TRUE ;
3. Select 'Set_Pipeline_Parameter_To_List_Of_Files' by clicking on the '»' in the workshop. This command selects all the files within FOLDER which have the file type .json. In this case, that is every file in the folder.
Set_Pipeline_Parameter_To_List_Of_Files /PARAMETER_NAME= FILES /FOLDER= ::FOLDER ! /SEARCH_SUBFOLDERS=FALSE /FILE_MASK=*.json ! /ALPHABETIZE=TRUE ! /RETURN_FOLDER_NAMES=FALSE ! /RETURN_RELATIVE_FILENAMES=FALSE ;
4. With all the files loaded into the pipeline, the next step is to run the for-loop that converts all the .json to .cmz files. This requires 5 commands: “For_Each”, “File_New”, “File_Open”, “File_Save_As”, “End_For_Each”.
For_Each /ITERATION_PARAMETER_NAME= INDEX /ITERATION_PARAMETER_COUNT_NAME=COUNT /ITEMS= ::FILES ; File_New ; File_Open /FILE_NAME= ::INDEX ! /FILE_PATH= ! /SEARCH_SUBFOLDERS=FALSE ! /SUFFIX= ! /SET_PROMPT=File_Open ! /ON_FILE_NOT_FOUND=PROMPT ! /FILE_TYPES_ON_PROMPT= ; File_Save_As /FILE_NAME=TRIAL&::COUNT /FOLDER=C:\HAS_Motion\Introductory_Project_August_2025\SPL-Open-Data-main\basketball\freethrow\data\CMZ_Trials\ ! /SET_PROMPT=Save CMZ file as ! /SAVE_EMBEDDED_GRAPHICS=FALSE ! /CREATE_FOLDER_PATH=FALSE ; End_For_Each /ITERATION_PARAMETER_NAME= INDEX ;
This pipeline itself will convert all the .json files to workspaces(.cmz) and can be run individually. But for consistency, the following commands will all be added to the for-loop, after 'File_Open' and before 'File_Save_As'
Assigning Tags
In this dataset, the primary variables analyzed are whether the subject made or missed the shot and the quarter of the session in which the free throw trial occurred. Tags are assigned to each trial for easier processing in Sift.
Many of the tag commands are repeated in the pipeline, so each command will be shown here once and the order of the pipeline will be provided so that it can be built manually. If you are having difficulty recreating the pipeline, the complete pipeline is given at the beginning of this section of the tutorial.
1. 'Select_Active_File' command. This command is run first to select the file to be tagged.
Select_Active_File /FILE_NAME=ALL_FILES ! /QUERY= ! /SUBJECT_TAGS=NO_SUBJECT ;
2. To assign a tag the 'Assign_Tags_To_Files' command is used.
Assign_Tags_To_Files /MOTION_FILE_NAMES =ALL_FILES /QUERY= PARAMETERS::MLSE::RESULTS="missed" ! change this to "made" to collect the made shots /TAGS= missed ! change the tag to 'made' as well when collecting the made shots ;
3.This subject completed 125 trials in total. To address the primary research question related to fatigue, the trials are divided into four sections (quarters), allowing each quarter to be analyzed independently and compared over time. Conditional statements are used to mark which quarter the trial took place. The quarters are: Q1 (Trial 1-31), Q2 (Trial 32-63), Q3 (Trial 64-94), Q4 (Trial 95-125).
a. For Q1 and Q4, the conditional statements are relatively simple and the expression is true if the iteration count is greater or less than the quarter number.
Conditional_Statement /ITERATION_PARAMETER_NAME= QuarterOne /EXPRESSION= &::COUNT& <= 31 ! /AS_INTEGER=TRUE ; Assign_Tags_To_Files /MOTION_FILE_NAMES = ALL_FILES !/QUERY= /TAGS= Q1 ; Conditional_Statement_End /ITERATION_PARAMETER_NAME= QuarterOne ;
b. For Q2 and Q3, nested conditional statements must be used to satisfy the lower and upper bounds.
Conditional_Statement /ITERATION_PARAMETER_NAME= QuarterTwo /EXPRESSION= &::COUNT& >= 32 ! /AS_INTEGER=TRUE ; Conditional_Statement /ITERATION_PARAMETER_NAME= QuarterTwoIn /EXPRESSION= &::COUNT& <= 63 ! /AS_INTEGER=TRUE ; Assign_Tags_To_Files /MOTION_FILE_NAMES= ALL_FILES ! /QUERY= /TAGS= Q2 ; Conditional_Statement_End /ITERATION_PARAMETER_NAME= QuarterTwoIn ; Conditional_Statement_End /ITERATION_PARAMETER_NAME= QuarterTwo ;
4. The order of the pipeline in its current state:
- Set_Pipeline_Parameter_To_Folder_Path
- Set_Pipeline_Parameter_To_List_Of_Files
- For_Each
- File_New
- File_Open
- Select_Active_File
- Assign_Tags_To_Files
- Assign_Tags_To_Files
- Conditional_Statement
- Assign_Tags_To_Files
- Conditional_Statement_End
- Conditional_Statement
- Conditional_Statement
- Assign_Tags_To_Files
- Conditional_Statement_End
- Conditional_Statement_End
- Conditional_Statement
- Conditional_Statement
- Assign_Tags_To_Files
- Conditional_Statement_End
- Conditional_Statement_End
- Conditional_Statement
- Assign_Tags_To_Files
- Conditional_Statement_End
- File_Save_As
- End_For_Each
Event Tags
In biomechanical data analysis it is necessary to have defined events such as 'start' and 'stop' where the movements are consistent and the data can be normalized within those events. In this free throw dataset, a large portion of the time-series data is spent with the subject catching the pass and walking to the free throw line. This is not important data to answer the research question so it is cut out in this section. The right hand center of gravity position was used as the event indicator. The start of the free throw was defined as the point when the right hand reached its lowest position in the z-direction (up from the floor), and the end of the follow-through was marked by the right hand reaching its highest point, this is a repeatable motion used for consistent analysis across all trials. See the gif below for a visual and graph of the start and end of the repeatable free throw motion.
1. Add 'Event_Global_Minimum' captures the global minimum center of gravity position of the right hand.
Event_Global_Minimum ! name the event /RESULT_EVENT_NAME=START /SIGNAL_TYPES=KINETIC_KINEMATIC ! right hand /SIGNAL_FOLDER=P0001:RHA ! center of gravity /SIGNAL_NAMES=CGPOS ! z-component /SIGNAL_COMPONENTS=Z ! /FRAME_OFFSET=0 ! /TIME_OFFSET= ! /EVENT_SEQUENCE= ! /EXCLUDE_EVENTS= ! /EVENT_SEQUENCE_INSTANCE=0 ! /EVENT_SUBSEQUENCE= ! /SUBSEQUENCE_EXCLUDE_EVENTS= ! /EVENT_SUBSEQUENCE_INSTANCE=0 ! /THRESHOLD= ;
2. Add 'Event_Global_Maximum' captures the global maximum center of gravity position of the right hand.
Event_Global_Maximum /RESULT_EVENT_NAME=END /SIGNAL_TYPES=KINETIC_KINEMATIC /SIGNAL_FOLDER=P0001:RHA /SIGNAL_NAMES=CGPOS /SIGNAL_COMPONENTS=Z ! /FRAME_OFFSET=0 ! /TIME_OFFSET= ! /EVENT_SEQUENCE= ! /EXCLUDE_EVENTS= ! /EVENT_SEQUENCE_INSTANCE=0 ! /EVENT_SUBSEQUENCE= ! /SUBSEQUENCE_EXCLUDE_EVENTS= ! /EVENT_SUBSEQUENCE_INSTANCE=0 ! /THRESHOLD= ;
3. This step isn't required, but for interest, an event between can be added that will put an event at the midpoint between the start and end events.
Event_Between /NEW_EVENT_NAME=MIDSHOT ! /RANGE_INSTANCE=0 !includes all events /EVENT_SEQUENCE=START+END ! /EXCLUDE_EVENTS= ! /FRAME_OFFSET=0 ! /TIME_OFFSET= ! /PERCENT_OFFSET= ;
4. All 3 of these event commands can be added in order after the last 'Conditional_Statement_End' and before the 'File_Save_As' in the pipeline.
Visualization of the START and END events can be seen below:
Computing Joint Angles
Now that all the tags and events are created, the final step is to calculate kinematic variables and specifically in this case, joint angles. The joint angles for the lower limb model will be calculated (ankle, knee, and hip joint).
1. Select Model Based Data Computation add “Compute_Model_Based_Data” to find each joint angle (ankle, knee, and hip).
Compute_Model_Based_Data /RESULT_NAME=Right Ankle Angle /SUBJECT_TAG=ALL_SUBJECTS /FUNCTION=JOINT_ANGLE /SEGMENT=RFT /REFERENCE_SEGMENT=RSK /RESOLUTION_COORDINATE_SYSTEM= ! /USE_CARDAN_SEQUENCE=FALSE ! /NORMALIZATION=FALSE ! /NORMALIZATION_METHOD= ! /NORMALIZATION_METRIC= ! /NEGATEX=FALSE ! /NEGATEY=FALSE ! /NEGATEZ=FALSE ! /AXIS1=X ! /AXIS2=Y ! /AXIS3=Z ! /TREADMILL_DATA=FALSE ! /TREADMILL_DIRECTION=UNIT_VECTOR(0,1,0) ! /TREADMILL_SPEED=0.0 ;
Below is a table with all the “Compute_Model_Based_Data” commands that will be needed to compute all angles needed. More on reference segments can be found here, Visual3D Reference Segments.
Compute_Model_Based_Data | Segment | Reference Segment |
---|---|---|
Right Ankle Angle | RFT | RSK |
Left Ankle Angle | LFT | LSK |
Right Hip Angle | RTH | RPV |
Left Hip Angle | LTH | RPV |
Right Knee Angle | RSK | RTH |
Left Knee Angle | LSK | LTH |
Completed Pipleline
The pipeline should now have the following components:
- Set_Pipeline_Parameter_To_Folder_Path
- Set_Pipeline_Parameter_To_List_Of_Files
- For_Each
- File_New
- File_Open
- Select_Active_File
- Assign_Tags_To_Files
- Assign_Tags_To_Files
- Conditional_Statement
- Assign_Tags_To_Files
- Conditional_Statement_End
- Conditional_Statement
- Conditional_Statement
- Assign_Tags_To_Files
- Conditional_Statement_End
- Conditional_Statement_End
- Conditional_Statement
- Conditional_Statement
- Assign_Tags_To_Files
- Conditional_Statement_End
- Conditional_Statement_End
- Conditional_Statement
- Assign_Tags_To_Files
- Conditional_Statement_End
- Event_Global_Minimum
- Event_Global_Maximum
- Compute_Model_Based_Data
- Compute_Model_Based_Data
- Compute_Model_Based_Data
- Compute_Model_Based_Data
- Compute_Model_Based_Data
- Compute_Model_Based_Data
- File_Save_As
- End_For_Each
Analysis & Visualization in Sift
Open a blank workspace in Sift, the processed cmz files created from Virtual3D will be used to analyze the ankle, knee, and hip joint angles to see the effects of fatigue. Sift will produce visualizations to be able to better understand the results.
Load "ProcessedFiles" & Build Query Definitions
To load the processed files into sift, select Load Library. Select the folder with the contained processed files, ProcessedFiles.
Since there are numerous queries needed, the following file can be used Completed Queries. Instead of manually doing the process below for all, click Load Query Definitions at the top of the dialog box and select the downloaded file and click Calculate All Queries.
If completing manually, when the files are loaded navigate to the Explore tab on the left and select the Query Builder
The analysis requires the ankle, knee, and hip angles in all directions (X,Y,Z) and separated into four groups based on fatigue levels (Q1, Q2, Q3, Q4) made into separate queries. Below is an example on how to manually create one of these queries.
1. Click the plus sign beside “Queries” to add a new query definition and name it “Q1 Ankle Angle X”, click save.
2. Name the condition “Left X”
a. Under the “Signals” tab select the following below. This command will find the left ankle angle in the x direction for all cmz files (each trial) and store the data in “Q1 Ankle Angle X”.
b. Under the “Events” tab select the following below. To add an event to the sequence, click the right hand arrow. By adding the event sequence = START and END, only the left ankle angles within the START and END events will be stored. Ensure Normalize Data Points is checked, as well as a Cubic spline type with 101 points.
c. Under the “Refinement” tab select the following below. Since only the made shots are being analyzed, the made tag is selected as well as the Q1 tag since only the beginning shots are needed for this query.
d. Click Save at the bottom of the dialog box to save the query.
e. To finish this query, the right ankle needs to have a condition within the Q1 Ankle Angle X query. Select the plus sign beside Conditions and repeat the above process. Only difference is ensuring “P0001: Right Ankle Angle” is selected as the Signal Name in the Signals tab.
f. Click Calculate All Queries at the bottom of the dialog box to load all data.
Registering the Curves
In order to produce accurate results, the curves must be registered to a global or local maximum or minimum event. This will show a better representation of amplitude variation. To learn more about curve registration, reference Sift Curve Registration
The following curves need to be registered:
-Q1, Q2, Q3, Q4 Ankle Angle X
-Q1, Q2, Q3, Q4 Knee Angle X
-Q1, Q2, Q3, Q4 Hip Angle X
Select Register Curves, to register a global maximum or minimum follow:
Select Register Curves, to register a local maximum or minimum follow:
Groups | Registration Type |
---|---|
Q1, Q2, Q3, Q4 Ankle Angle X | Global Max |
Q1, Q2, Q3, Q4 Knee Angle X | Global Min |
Q1, Q2, Q3, Q4 Hip Angle X | Local Max between 20-40 |
Plotting in Sift
To view the effects of fatigue, Q1 and Q4 data of the ankle, knee, and hip angles will be plotted.
- In the Explore tab, right click on both Q1AnkleAngleX_Registered and Q4AnkleAngleX_Registered in the Plotting Controls.
- Select All Workspaces above the Workspaces box.
- In the Plotting Controls_ tab, select Plot Group Mean and Plot Group Dispersion.
Repeat this process for the knee and hip. To change the style of the plot, refer to Visualization in Sift to learn more about altering the plot settings.
The plots should look similar to below:
Statistical Parametric Mapping (SPM) & ANOVA Analysis
SPM is a statistical analysis method that will show if there are significant statistical differences in the processed dataset. To learn more about SPM, SPM in Biomechanics
1. Control-right click on the two registered groups being analyzed, navigate to the Analyze tab and select the Mapping tab at the bottom of the INFO box and select Crete GLM. Follow the below image for the ankle, knee, and hip.
2. Navigate to the Statistics tab at the bottom of the INFO box and select Compute SPM - follow the image below.
The above steps can be followed for the ankle, knee, and hip to see if there are statistically significant differences in each joint as fatigue increases.
A one way ANOVA test can be conducted on all four sections of free throws (Q1, Q2, Q3, Q4). The ANOVA test compares the means of the four groups to determine if there is statistically significant difference between them. In order to do this, follow the above SPM steps but instead of selecting Two Sample T-Test, select One-Way ANOVA. Compute the SPM using the ANOVA GLM.
Results
After analyzing the motion capture data, clear changes in lower-body joint kinematics were observed across all trials. The null hypothesis, that mean joint angles remain consistent before and after fatigue was rejected following statistical analysis. Specifically, there was a reduction in hip and knee flexions along with decreased dorsiflexion in the ankle. This suggests an overall decline in lower-body usage as fatigue developed. To statistically find the relevance of these outcomes, SPM and ANOVA tests were conducted and are shown below. These tests confirmed the significant differences in joint angles as the trials progressed.
SPM Results
The SPM results for all three joints are shown below. The associated t-values for each SPM for the ankle, knee, and hip respectively are: 2.72, 2.83, and 2.83
The ankle SPM showed a significant reduction in ankle dorsiflexion between Q1 and Q4, this can be seen in the “Plotting in Sift” section. A significant cluster can be seen between 15% and 30% of the free throw movement, where the SPM t-value threshold was exceeded. The maximum t-value was 2.72 showing a significant difference in joint angle consistent with fatigue-related motion changes.
Similarly, the knee and hip both showed significant reduction in flexion as the trials progressed. Both have t-values of 2.83 and occurred between 12-80% for the knee and 12-75% for the hip. Since the clusters were continuous and large this suggests a consistent change in lower body mechanics over majority of the free throw motion as fatigue progressed.
To better visualize the section of the movement where there is a significant difference in flexion, reference the yellow line on the graphs in the second row below.
ANOVA
The ANOVA tests can be seen below with F values for the ankle, knee, and hip; 4.76, 4.97, and 4.92 respectively. A larger F-value indicates that the group means have more variance relative to variability within each group. These results indicate that all three joints showed significant changes in the movement pattern over time with a consistent reduction in flexion observed in later trials. To further understand the concept of an ANOVA test, reference Understanding one-way ANOVA using conceptual figures.
Conclusions
This tutorial demonstrated that fatigue significantly impacts lower body joint kinematics during repeated basketball free throw attempts in one session. Motion capture data, curtesy of MLSE, revealed a consistent reduction in ankle, hip, and knee flexion as fatigue developed. SPM and ANOVA tests were used to identify that there is significant clusters of reduced joint angles across the motion for the hip and knee, and a smaller reduction seen in the ankle. The ANOVA test confirmed the SPM test results.
These results suggests the importance of lower-body endurance in being able to maintain consistent free throw mechanics. Further research could investigate if upper body joints compensate for the reduction in flexion in the lower body. This could aid in the creation of strategies to reduce fatigue-related performance decline.