So there's an extra factor of 2 that is multiplied to X_energy to do norm_denom = **2**X_energy + sigma_xxgamma.
When I add this multiplication by 2 factor in sw_avona lib_aec, the ADEC tests pass. If I remove this factor of 2 from 3610, lib_aec code, I see the 3 ADEC tests failures in lib_audio_pipelines as well.
I'm not sure how this discrepancy wrt python model got implemented in the first place. I don't recall adding an extra multiplication while implementing 3610 lib_aec and I maybe the python itself had the factor of 2 at some point?
When I run lib_audio_pipelines full keyword tests with and without this factor of 2 multiplication the results don't show any significant difference so both implementations seem okay.
While debugging these failing ADEC tests, here's what I found:
The failures happen because there's an early (frame 48) transition to DE mode in C code which doesn't happen on python.
The ERLE curve for C follows python (atleast to begin with, before they diverge due to different shadow resets, copy etc.) but at a lower ERLE on C than python. This lower ERLE triggers DE on frame 48 in C code. This happens on both the sw_avona and 3610 AEC code and is most likely because of limited fixed point precision and not a bug in the C code.
Because of the 48th frame DE transition, the small_mic_increase and delay_at_start tests fail with an extra false positive.
The rapid_changes test is interesting. While the early DE transition has happened and AEC is in DE mode, an actual delay change happens in the stream where the mic signal becomes early wrt reference. This delay change happens too late and before the AEC filter can converge to the new peak, we transition out of DE mode with the wrong measured delay. Since the actual delay is in fact, mic early, post this the filters never converge. This means that the initial shadow -> main filter copy never happens, which means ADEC doesn't run its logic anymore, since ADEC waits for the shadow->main filter copy before monitoring AEC performance. As a result we get false_negatives for this test case.
There's a watchdog in ADEC that is supposed to force trigger DE in consistently bad AEC case, but the watchdog check itself is within the has_shadow_copy_happened check so never gets triggered.
Conclusion:
I think getting ADEC to work with compare_filters logic needs more work. This is already an item acoustic team's backlog.
I've decided to introduce the factor of 2 multiplication in sw_avona lib_aec as well to get adec tests passing and also because it doesn't seem to degrade anything.
AEC performance parameters like ERLE, peak to average ratio etc. that are used to make decisions in compare_filters and ADEC algorithms are different in C vs python. So using the C code to tune these algorithms would perhaps make more sense. Also, debugging various reported issues in future on C rather than python would be useful.
In the pipeline example, I'm going to only demonstrate ADEC configured in initial delay estimation mode (same as 3610 default setting) since I'm not sure of robustness of ADEC in automatic DE control mode.
While testing sw_avona adec module using the ADEC tests ported from lib_audio_pipelines (https://github.com/xmos/lib_audio_pipelines/tree/develop/tests/test_delay_estimator_controller), I found some issues that I've described here.
I have 3 failing tests on sw_avona ADEC. rapid_changes - False negatives small_mic_increase - False positives delay_at_start - False positives.
While debugging these failures, I realised that 3610 lib_aec calculates inverse_X_energy normDenom in a slightly different way than the python model. 3610 lib_aec: https://github.com/xmos/lib_aec/blob/develop/lib_aec/src/aec_calc_inv_energy_params.xc#L59 python model: https://github.com/xmos/py_aec/blob/develop/py_aec/aec.py#L581
So there's an extra factor of 2 that is multiplied to X_energy to do norm_denom = **2**X_energy + sigma_xxgamma. When I add this multiplication by 2 factor in sw_avona lib_aec, the ADEC tests pass. If I remove this factor of 2 from 3610, lib_aec code, I see the 3 ADEC tests failures in lib_audio_pipelines as well.
I'm not sure how this discrepancy wrt python model got implemented in the first place. I don't recall adding an extra multiplication while implementing 3610 lib_aec and I maybe the python itself had the factor of 2 at some point?
When I run lib_audio_pipelines full keyword tests with and without this factor of 2 multiplication the results don't show any significant difference so both implementations seem okay.
While debugging these failing ADEC tests, here's what I found:
Conclusion: