Skip to content

Commit

Permalink
Merge pull request #266 from uvvpavel/test_py_ic
Browse files Browse the repository at this point in the history
testing ic against py_ic
  • Loading branch information
uvvpavel authored Jun 13, 2022
2 parents 7f69573 + 3a86fcb commit 6d85660
Show file tree
Hide file tree
Showing 14 changed files with 356 additions and 534 deletions.
29 changes: 28 additions & 1 deletion modules/lib_aec/src/aec_priv_impl.c
Original file line number Diff line number Diff line change
Expand Up @@ -819,6 +819,30 @@ void aec_priv_calc_inverse(
#endif
}


void bfp_new_add_scalar(
bfp_s32_t* a,
const bfp_s32_t* b,
const float_s32_t c)
{
#if (XS3_BFP_DEBUG_CHECK_LENGTHS) // See xs3_math_conf.h
assert(b->length == a->length);
assert(b->length != 0);
#endif

right_shift_t b_shr, c_shr;

xs3_vect_s32_add_scalar_prepare(&a->exp, &b_shr, &c_shr, b->exp, c.exp,
b->hr, HR_S32(c.mant));

int32_t cc = 0;
if (c_shr < 32)
cc = (c_shr >= 0)? (c.mant >> c_shr) : (c.mant << -c_shr);

a->hr = xs3_vect_s32_add_scalar(a->data, b->data, cc, b->length,
b_shr);
}

void aec_priv_calc_inv_X_energy_denom(
bfp_s32_t *inv_X_energy_denom,
const bfp_s32_t *X_energy,
Expand Down Expand Up @@ -853,7 +877,9 @@ void aec_priv_calc_inv_X_energy_denom(

bfp_s32_convolve_same(inv_X_energy_denom, &norm_denom, &taps_q30[0], 5, PAD_MODE_REFLECT);

bfp_s32_add_scalar(inv_X_energy_denom, inv_X_energy_denom, delta);
//bfp_s32_add_scalar(inv_X_energy_denom, inv_X_energy_denom, delta);
bfp_new_add_scalar(inv_X_energy_denom, inv_X_energy_denom, delta);

}
else
{
Expand Down Expand Up @@ -884,6 +910,7 @@ void aec_priv_calc_inv_X_energy_denom(

//Option 2 (1528 cycles for the bfp_s32_min() call. Haven't profiled when min.mant == 0 is true
float_s32_t min = bfp_s32_min(inv_X_energy_denom);

if(min.mant == 0) {
/** The presence of delta even when it's zero in bfp_s32_add_scalar(inv_X_energy_denom, X_energy, delta); above
* ensures that bfp_s32_max(inv_X_energy_denom) always has a headroom of 1, making sure that t is not right shifted as part
Expand Down
52 changes: 45 additions & 7 deletions modules/lib_ic/src/ic_low_level.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
#include "aec_api.h"
#include "aec_priv.h"


///Delay y input w.r.t. x input
void ic_delay_y_input(ic_state_t *state,
int32_t y_data[IC_FRAME_ADVANCE]){
Expand Down Expand Up @@ -246,6 +245,43 @@ void ic_filter_adapt(ic_state_t *state){
aec_priv_filter_adapt(state->H_hat_bfp[y_ch], state->X_fifo_1d_bfp, T_ptr, IC_X_CHANNELS, IC_FILTER_PHASES);
}

static inline int32_t ashr32(int32_t x, right_shift_t shr)
{
if(shr >= 0)
return x >> shr;

int64_t tmp = ((int64_t)x) << -shr;

if(tmp > INT32_MAX) return INT32_MAX;
else if(tmp < INT32_MIN) return INT32_MIN;
else return tmp;
}

float_s32_t float_s32_add_fix(
const float_s32_t x,
const float_s32_t y)
{
float_s32_t res;

const headroom_t x_hr = HR_S32(x.mant);
const headroom_t y_hr = HR_S32(y.mant);

const exponent_t x_min_exp = x.exp - x_hr;
const exponent_t y_min_exp = y.exp - y_hr;

res.exp = MAX(x_min_exp, y_min_exp) + 1;

const right_shift_t x_shr = res.exp - x.exp;
const right_shift_t y_shr = res.exp - y.exp;

int32_t x_mant = (x_shr >= 32) ? 0 : ashr32(x.mant, x_shr);
int32_t y_mant = (y_shr >= 32) ? 0 : ashr32(y.mant, y_shr);

res.mant = x_mant + y_mant;

return res;
}

//Python port
void ic_adaption_controller(ic_state_t *state, uint8_t vad){
ic_adaption_controller_state_t *ad_state = &state->ic_adaption_controller_state;
Expand All @@ -257,7 +293,10 @@ void ic_adaption_controller(ic_state_t *state, uint8_t vad){

const float_s32_t one = {1, 0};
const float_s32_t zero = {0, 0};
const float_s32_t delta = {1100, -40}; //1100 * 2**-40 = 0.000000001 (from stage_b.py)
//const float_s32_t delta = {1100, -40}; //1100 * 2**-40 = 0.000000001 (from stage_b.py)
// in some test cases delta = 1e-9 was not small enough comparing to the denominator
// this is also changed in stage_b test python
const float_s32_t delta = {352, -45}; //352 * 2**-45 ~ 0.00000000001

exponent_t q0_8_exp = -8;
float_s32_t vad_float = {vad, q0_8_exp}; //convert to float between 0 and 0.99609375
Expand All @@ -272,9 +311,8 @@ void ic_adaption_controller(ic_state_t *state, uint8_t vad){
//noise_mu = 1.0 - self.smoothed_voice_chance
float_s32_t noise_mu = float_s32_sub(one, ad_state->smoothed_voice_chance);


//noise_mu = noise_mu * min(1.0, np.sqrt(np.sqrt(self.output_energy/(self.input_energy + 0.000000001))))
float_s32_t input_plus_delta = float_s32_add(ad_state->input_energy_slow, delta);
//noise_mu = noise_mu * min(1.0, np.sqrt(np.sqrt(self.output_energy/(self.input_energy + delta))))
float_s32_t input_plus_delta = float_s32_add_fix(ad_state->input_energy_slow, delta);
float_s32_t ratio = float_s32_div(ad_state->output_energy_slow, input_plus_delta);
ratio = float_s32_sqrt(ratio);
ratio = float_s32_sqrt(ratio);
Expand All @@ -290,8 +328,8 @@ void ic_adaption_controller(ic_state_t *state, uint8_t vad){
}
}

//fast_ratio = self.output_energy0 / (self.input_energy0 + 0.000000001)
input_plus_delta = float_s32_add(ad_state->input_energy_fast, delta);
//fast_ratio = self.output_energy0 / (self.input_energy0 + delta)
input_plus_delta = float_s32_add_fix(ad_state->input_energy_fast, delta);
float_s32_t fast_ratio = float_s32_div(ad_state->output_energy_fast, input_plus_delta);

// if fast_ratio > 1.0:
Expand Down
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -48,3 +48,4 @@ tensorflow_model_optimization==0.7.2
# setup.py file, e.g., '-e .' or '-e ./python' (without the quotes).
-e ./../audio_test_tools/python
-e ./../py_vnr
-e ./../py_ic/py_ic
53 changes: 23 additions & 30 deletions test/lib_ic/characterise_c_py/characterise_c_py.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,12 @@
# This Software is subject to the terms of the XMOS Public Licence: Version 1.
from __future__ import division
from __future__ import print_function
from builtins import str
from builtins import range
import sys
import os
import shutil
import tempfile

package_dir = os.path.dirname(os.path.abspath(__file__))
att_path = os.path.join(package_dir,'../../../audio_test_tools/python/')
py_ic_path = os.path.join(package_dir,'../../../../lib_interference_canceller/python')

sys.path.append(att_path)
sys.path.append(py_ic_path)

from audio_generation import get_band_limited_noise, write_data
import subprocess
from audio_generation import get_band_limited_noise
import time
import numpy as np
import scipy.io.wavfile as wavfile
Expand All @@ -27,19 +17,15 @@
import scipy

try:
import test_wav_ic
import test_wav_ic as twic
except ModuleNotFoundError:
print(f"Please install lib_interference_canceller at root of project to support model testing")
print(f"Please install py_ic at root of project to support model testing")

import xtagctl, xscope_fileio

NOISE_FLOOR_dBFS = -63.0
SIGMA2_AWGN = ((10 ** (float(NOISE_FLOOR_dBFS)/20)) * np.iinfo(np.int32).max) ** 2

PHASES = 10
FRAME_ADVANCE = 240
PROC_FRAME_LENGTH = 512

SAMPLE_RATE = 16000
SAMPLE_COUNT = 160080

Expand Down Expand Up @@ -101,10 +87,13 @@ def generate_test_audio(filename, audio_dir, max_freq, db, angle_theta, rt60, sa
scipy.io.wavfile.write(file_path, SAMPLE_RATE, output)


def process_py(input_file, output_file, x_channel_delay, audio_dir="."):
test_wav_ic.test_file(os.path.join(audio_dir, input_file),
def process_py(input_file, output_file, audio_dir="."):

config_file = '../../shared/config/ic_conf_big_delta.json'

twic.test_file(os.path.join(audio_dir, input_file),
os.path.join(audio_dir, output_file),
PHASES, x_channel_delay, FRAME_ADVANCE, PROC_FRAME_LENGTH, verbose=False)
config_file)


def process_c(input_file, output_file, audio_dir="."):
Expand Down Expand Up @@ -132,33 +121,37 @@ def get_attenuation(input_file, output_file, audio_dir="."):
out_wav_data, out_channel_count, out_file_length = awu.parse_audio(out_wav_file)

# Calculate EWM of audio power in 1s window
in_power_l = np.power(in_wav_data[0, :], 2)
in_power_r = np.power(in_wav_data[1, :], 2)
out_power = np.power(out_wav_data[0, :], 2)
#print(input_file, ' has ', in_channel_count, ' channels and ', in_wav_data.shape, 'shape')
#print(output_file, ' has ', out_channel_count, 'channels and ', out_wav_data.shape, 'shape')
in_power = np.power(in_wav_data[0, :], 2)
if len(out_wav_data.shape) > 1:
out_power = np.power(out_wav_data[0, :], 2)
else:
out_power = np.power(out_wav_data, 2)
#out_power = np.power(out_wav_data[0, :], 2)

attenuation = []

for i in range(len(in_power_l) // SAMPLE_RATE):
for i in range(len(in_power) // SAMPLE_RATE):
window_start = i*SAMPLE_RATE
window_end = window_start + SAMPLE_RATE
av_in_power_l = np.mean(in_power_l[window_start:window_end])
av_in_power_r = np.mean(in_power_r[window_start:window_end])
av_in_power = (av_in_power_l + av_in_power_r) / 2

av_in_power = np.mean(in_power[window_start:window_end])

av_out_power = np.mean(out_power[window_start:window_end])
new_atten = 10 * np.log10(av_in_power / av_out_power) if av_out_power != 0 else 1000
attenuation.append(new_atten)

return attenuation

def get_attenuation_c_py(test_id, noise_band, noise_db, angle_theta, rt60, x_channel_delay):
def get_attenuation_c_py(test_id, noise_band, noise_db, angle_theta, rt60):
input_file = "input_{}.wav".format(test_id) # Required by test_wav_suppression.xe
output_file_py = "output_{}_py.wav".format(test_id)
output_file_c = "output_{}_c.wav".format(test_id)

audio_dir = test_id
generate_test_audio(input_file, audio_dir, noise_band, noise_db, angle_theta, rt60)
process_py(input_file, output_file_py, x_channel_delay, audio_dir)
process_py(input_file, output_file_py, audio_dir)
process_c(input_file, output_file_c, audio_dir)

attenuation_py = get_attenuation(input_file, output_file_py, audio_dir)
Expand Down Expand Up @@ -199,7 +192,7 @@ def main():
start_time = time.time()
args = parse_arguments()
angle_theta = args.angle * np.pi/180
get_attenuation_c_py("test", args.noise_band, args.noise_level, angle_theta, args.rt60, args.ic_delay)
get_attenuation_c_py("test", args.noise_band, args.noise_level, angle_theta, args.rt60)
print("--- {0:.2f} seconds ---".format(time.time() - start_time))


Expand Down
2 changes: 1 addition & 1 deletion test/lib_ic/characterise_c_py/get_polar_response.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ def get_polar_response(test_id, angle_roi, step_size, noise_band, noise_db,

angle_radians = angle * np.pi / 180
generate_test_audio(input_file, audio_dir, noise_band, noise_db, angle_radians, rt60)
process_py(input_file, output_file_py, x_channel_delay, audio_dir)
process_py(input_file, output_file_py, audio_dir)
attenuation_py = get_attenuation(input_file, output_file_py, audio_dir)
results_py.append(attenuation_py[-2])

Expand Down
2 changes: 1 addition & 1 deletion test/lib_ic/py_c_frame_compare/ic_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@

ic_state_t ic_state;


void test_init(void){
ic_init(&ic_state);
//Custom setup for testing
Expand All @@ -14,6 +13,7 @@ void test_init(void){
}

ic_state_t test_get_state(void){

return ic_state;
}

Expand Down
Loading

0 comments on commit 6d85660

Please sign in to comment.