# Statistical analysis of IVAS Reverb Characterization testing
This project is used to analyze the result logs for the multiple renderer preference testing carried out as part of the IVAS characterization testing.
# Prerequisites
## Data Structure
The code assumes that all results files are stored in same folder, and conform to the specification for ARL Step result files. That is, a tab separated list, with the header of:
```
Lab Listener Session File Sig Sys Score
```
The folder must also contain the `RoomAcoustics.asi` file, detailing for each test item the files used for each renderer condition. This conforms to the `mushra` style session file of ARL Step.
## Python
The project uses `uv` ro manage the python dependencies. `uv` can be installed with your favorite package manager. For more information, have a look at
[the installation instructions](https://docs.astral.sh/uv/getting-started/installation/). With python already installed on your system it should be sufficient to run `pip install uv` from a command prompt.
# Running the code
With UV installed it is sufficient to call the function with
```
uv run statistical_analysis.py <path-to-results-directory>
```
On the first instance of running `uv` it will create a virtual environment and populate it with the requirements as specified in `pyproject.toml`. If you make changes to the code which change the dependencies use `uv sync` to update your virtual environment.
Teo optional arguments can be given `--show_plots` and `--store_plots` to either show the plots in the web browser, or to store the plots as PNG files into the results folder. See the help for more information:
results_folder Path to the directory containing the results files
options:
-h, --help show this help message and exit
--show_plots Shows the plots in the web browser.
--save_plots Stores the plots into the results folder, note: requires Chrome / Chromeium to be installed on the local machine.
```
# Interpreting the output
The code optionally generates two graphics, one showing the results per signal type, and one averaged across all signals. For the example data contained in `./example_data/` these are:


In the plot averaged across all signals the markers above the plots show pairwise comparisons that are considered statistically significant (p < 0.05).
The code performs two startisical analysis, firstly a 2-way ANOVA, and then a Tukey Honest Squares Difference (HSD) post-hoc test. The output of both is stored into `stats.csv` in the input results folder.
## ANOVA
Three effects are analysed, `Signal`, `Renderer`, and the interaction of the two. The results for the example data are shown below:
In this data `Signal` is considered to be non-significant (p>0.05 and a small F-value), while the effect of `Renderer` is highly significant (p<0.05 and a large F-value). There is no interaction effect of `signal` and `renderer`. This means that all of the variance of the data is assumed to come from the `Renderer` only. To understand the interaction between the different renderers a post-hoc test must be performed.
## Tukey HSD post-hoc
Tukey Honest Squares Difference post-hoc test makes pairwise comparisons between all groups, and determines whether the mean difference is significantly different from zero. If the mean difference between groups is different from zero then you can reject the null hypothesis, meaning that that pair are considered to be different from each other.
In the example data given below the first 3 comparisons are considered to be significant, while the second three are non-significant. This translates to all other renderers being different from `IVAS_Binaural`, and not different from each other. This is shown by the markers in the plot above.
parser.add_argument("results_folder",help="Path to the directory containing the results files",type=str)
parser.add_argument("--show_plots",action="store_true",help="Shows the plots in the web browser.")
parser.add_argument("--save_plots",action="store_true",help="Stores the plots into the results folder, note: requires Chrome / Chromeium to be installed on the local machine.")
args=parser.parse_args()
ifnotos.path.isdir(args.results_folder):
raiseIsADirectoryError(f"Given path is not a valid directory.")