Loading lib_com/ivas_filters_fx.c +97 −0 Original line number Diff line number Diff line Loading @@ -43,6 +43,7 @@ *------------------------------------------------------------------------------------------*/ static void ivas_iir_2_filter_fx( ivas_filters_process_state_t *filter_state, Word32 *pIn_Out_fx, const Word16 length, const Word16 stage, Word16 *pIn_Out_e ); static void ivas_iir_2_filter_fixed_fx( ivas_filters_process_state_t *filter_state, Word32 *pIn_Out_fx, const Word16 length, const Word16 stage, Word16 *pIn_Out_e ); /*-----------------------------------------------------------------------------------------* Loading Loading @@ -145,6 +146,10 @@ void ivas_filters_init_fx( move16(); } #ifdef OPT_2239_IVAS_FILTER_PROCESS filter_state->q_diff = 0; #endif return; } Loading Loading @@ -285,3 +290,95 @@ static void ivas_iir_2_filter_fx( return; } void ivas_filter_process_fixed_fx( ivas_filters_process_state_t *filter_state, /* i/o: filter state handle */ Word32 *pIn_Out_fx, /* i/o: signal subject to filtering (exp[i] : pIn_out_e[i]) */ const Word16 length, /* i : filter order */ Word16 *q_in_out ) { SWITCH( filter_state->order ) { case IVAS_FILTER_ORDER_1: ivas_iir_2_filter_fixed_fx( filter_state, pIn_Out_fx, length, IVAS_FILTER_STAGE_0, q_in_out ); /* Scale pIn_Out_fx back to input Q */ BREAK; case IVAS_FILTER_ORDER_4: /* biquad-1 */ ivas_iir_2_filter_fixed_fx( filter_state, pIn_Out_fx, length, IVAS_FILTER_STAGE_0, q_in_out ); /* biquad-2 */ ivas_iir_2_filter_fixed_fx( filter_state, pIn_Out_fx, length, IVAS_FILTER_STAGE_1, q_in_out ); /* Scale pIn_Out_fx back to input Q */ BREAK; default: BREAK; } return; } static void ivas_iir_2_filter_fixed_fx( ivas_filters_process_state_t *filter_state, Word32 *pIn_Out_fx, // Q(31-*pIn_Out_e) const Word16 length, const Word16 stage, Word16 *q_in_out ) { Word16 i, j; Word32 *pIn_fx = pIn_Out_fx; Word32 *pOut_fx = pIn_Out_fx; Word32 tmp_pIn_buf_i_fx; Word16 tmp_pIn_buf_i_e; Word32 L_tmp_prod, L_tmp; Word16 L_prod_e, L_tmp_e; Word16 exp; Word16 q_in = *q_in_out; Word16 q_out = add( filter_state->q_diff, q_in ); *q_in_out = q_out; FOR( i = 0; i < length; i++ ) { tmp_pIn_buf_i_fx = pIn_fx[i]; move32(); tmp_pIn_buf_i_e = q_in; move16(); L_tmp_prod = Mpy_32_32( filter_state->num_fx[stage][0], pIn_fx[i] ); // Q31 -(q_in+ filter_state->num_e[stage][0]) L_prod_e = add( q_in, filter_state->num_e[stage][0] ); pOut_fx[i] = BASOP_Util_Add_Mant32Exp( filter_state->state_fx[stage][0], filter_state->state_e[stage][0], L_tmp_prod, L_prod_e, &exp ); // Q31 - pIn_Out_e[i] move32(); FOR( j = 1; j < filter_state->filt_len; j++ ) { L_tmp_prod = Mpy_32_32( filter_state->num_fx[stage][j], tmp_pIn_buf_i_fx ); // Q31-L_prod_e L_prod_e = add( filter_state->num_e[stage][j], tmp_pIn_buf_i_e ); L_tmp = BASOP_Util_Add_Mant32Exp( filter_state->state_fx[stage][j], filter_state->state_e[stage][j], L_tmp_prod, L_prod_e, &L_tmp_e ); // Q31 - L_tmp_e L_tmp_prod = Mpy_32_32( filter_state->den_fx[stage][j], pOut_fx[i] ); // Q31 - ( pIn_Out_e[i]+filter_state->den_e[stage][j] ) L_prod_e = add( exp, filter_state->den_e[stage][j] ); filter_state->state_fx[stage][j - 1] = BASOP_Util_Add_Mant32Exp( L_tmp, L_tmp_e, L_negate( L_tmp_prod ), L_prod_e, &filter_state->state_e[stage][j - 1] ); // Q31 - filter_state->state_e[stage][j - 1] move32(); /*In case when exponent is less than -31 the value is very small and negligible hence resetting it to zero to avoid exponent overflow*/ IF( LT_16( filter_state->state_e[stage][j - 1], -31 ) ) { filter_state->state_fx[stage][j - 1] = 0; move32(); filter_state->state_e[stage][j - 1] = 0; move16(); } } Word16 shift = ( 31 - exp ) - q_out; pOut_fx[i] = L_shr_r_sat( pOut_fx[i], shift ); move32(); } return; } lib_com/ivas_prot_fx.h +7 −0 Original line number Diff line number Diff line Loading @@ -3817,6 +3817,13 @@ void ivas_filter_process_exp_fx( Word16 *pIn_Out_e ); void ivas_filter_process_fixed_fx( ivas_filters_process_state_t *filter_state, /* i/o: filter state handle */ Word32 *pIn_Out_fx, /* i/o: signal subject to filtering (exp[i] : pIn_out_e[i]) */ const Word16 length, /* i : filter order */ Word16 *q_in_out ); ivas_error ivas_osba_enc_open_fx( Encoder_Struct *st_ivas /* i/o: IVAS encoder handle */ ); Loading lib_com/ivas_stat_com.h +4 −0 Original line number Diff line number Diff line Loading @@ -661,6 +661,10 @@ typedef struct ivas_filters_process_state_t Word16 den_e[IVAS_FILTER_MAX_STAGES][IVAS_BIQUAD_FILT_LEN]; Word16 state_e[IVAS_FILTER_MAX_STAGES][IVAS_BIQUAD_FILT_LEN]; #ifdef OPT_2239_IVAS_FILTER_PROCESS Word16 q_diff; // q_diff = q_out - q_in -> q_out = q_diff + q_in #endif } ivas_filters_process_state_t; Loading lib_com/ivas_transient_det_fx.c +76 −1 Original line number Diff line number Diff line Loading @@ -382,7 +382,6 @@ void ivas_td_decorr_get_ducking_gains_fx( { Word16 i; Word32 e_fast_fx[L_FRAME48k], e_slow_fx[L_FRAME48k]; Word16 e_fast_e[L_FRAME48k], e_slow_e[L_FRAME48k]; Word32 in_duck_gain = hTranDet->in_duck_gain; /*Q30*/ move32(); Word32 out_duck_gain = hTranDet->out_duck_gain; /*Q30*/ Loading @@ -396,6 +395,80 @@ void ivas_td_decorr_get_ducking_gains_fx( Copy32( pIn_pcm, e_fast_fx, frame_len ); /*Q11*/ #ifdef OPT_2239_IVAS_FILTER_PROCESS /* env hpf */ Word16 q_fast = Q11; ivas_filter_process_fixed_fx( &hTranDet->env_hpf, e_fast_fx, frame_len, &q_fast ); Word32 env_eps_fx = IVAS_TDET_PARM_ENV_EPS_fx; Word16 env_eps_q = Q31; Word16 q_diff = sub( q_fast, env_eps_q ); q_fast = s_min( q_fast, env_eps_q ); if ( q_diff >= 0 ) { for ( i = 0; i < frame_len; i++ ) { e_fast_fx[i] = L_add( L_abs( L_shr( e_fast_fx[i], q_diff ) ), env_eps_fx ); move32(); e_slow_fx[i] = e_fast_fx[i]; move32(); } } else { env_eps_fx = L_shl( env_eps_fx, q_diff ); for ( i = 0; i < frame_len; i++ ) { e_fast_fx[i] = L_add( L_abs( e_fast_fx[i] ), env_eps_fx ); move32(); e_slow_fx[i] = e_fast_fx[i]; move32(); } } Word16 q_slow = q_fast; /* env fast*/ ivas_filter_process_fixed_fx( &hTranDet->env_fast, e_fast_fx, frame_len, &q_fast ); /* env slow */ ivas_filter_process_fixed_fx( &hTranDet->env_slow, e_slow_fx, frame_len, &q_slow ); IF( tdet_flag ) { FOR( i = 0; i < frame_len; i++ ) { in_duck_gain = ivas_calc_duck_gain_fx( in_duck_gain, in_duck_coeff, e_slow_fx[i], 31 - q_slow, e_fast_fx[i], 31 - q_fast, duck_mult_fac ); /*Q30*/ pIn_duck_gains[i] = in_duck_gain; /*Q30*/ move32(); } hTranDet->in_duck_gain = in_duck_gain; /*Q30*/ move32(); } ELSE { FOR( i = 0; i < frame_len; i++ ) { in_duck_gain = ivas_calc_duck_gain_fx( in_duck_gain, in_duck_coeff, e_slow_fx[i], 31 - q_slow, e_fast_fx[i], 31 - q_fast, duck_mult_fac ); /*Q30*/ pIn_duck_gains[i] = in_duck_gain; /*Q30*/ move32(); out_duck_gain = ivas_calc_duck_gain_fx( out_duck_gain, out_duck_coeff, e_fast_fx[i], 31 - q_fast, e_slow_fx[i], 31 - q_slow, duck_mult_fac ); /*Q30*/ pOut_duck_gains[i] = out_duck_gain; /*Q30*/ move32(); } hTranDet->in_duck_gain = in_duck_gain; /*Q30*/ move32(); hTranDet->out_duck_gain = out_duck_gain; /*Q30*/ move32(); } #else Word16 e_fast_e[L_FRAME48k], e_slow_e[L_FRAME48k]; set16_fx( e_fast_e, 31 - Q11, L_FRAME48k ); /* env hpf */ Loading Loading @@ -446,6 +519,8 @@ void ivas_td_decorr_get_ducking_gains_fx( hTranDet->out_duck_gain = out_duck_gain; /*Q30*/ move32(); } #endif return; } lib_com/ivas_transient_det_fx.py 0 → 100644 +98 −0 Original line number Diff line number Diff line import numpy as np from scipy import signal import matplotlib.pyplot as plt def generate_biquad_butterworth_coeffs(cutoff_freq, fs, order=2, ftype='lowpass', output='ba'): Wn = cutoff_freq if output == 'sos': sos_coeffs = signal.butter(order, Wn, btype=ftype, analog=False, output='sos', fs=fs) return sos_coeffs elif output == 'ba': b_coeffs, a_coeffs = signal.butter(order, Wn, btype=ftype, analog=False, output='ba', fs=fs) return b_coeffs, a_coeffs else: raise ValueError("Output format must be 'sos' or 'ba'") def plot_biquad_frequency_response(b, a, fs): w, h = signal.freqz(b, a, fs=fs) magnitude_db = 20 * np.log10(np.abs(h)) phase_degrees = np.unwrap(np.angle(h)) * 180 / np.pi fig, (ax1, ax2) = plt.subplots(2, 1, sharex=True, tight_layout=True) ax1.plot(w, magnitude_db, 'b') ax1.set_ylabel('Magnitude (dB)', color='b') ax1.set_xlabel('Frequency (Hz)') ax1.grid() ax2.plot(w, phase_degrees, 'g') ax2.set_ylabel('Phase (degrees)', color='g') ax2.set_xlabel('Frequency (Hz)') ax2.grid() plt.show() def max_abs_output_biquad(b, a, n_samples=10000): if a[0] != 1.0: b = np.array(b) / a[0] a = np.array(a) / a[0] a[0] = 1.0 impulse_input = np.zeros(n_samples) impulse_input[0] = 1.0 impulse_response = signal.lfilter(b, a, impulse_input) max_gain = np.sum(np.abs(impulse_response)) return max_gain # sampling_rate = 44100.0 # Hz # cutoff_frequency = 5000.0 # Hz # b_coeffs,a_coeffs = generate_biquad_butterworth_coeffs(cutoff_frequency, sampling_rate) # plot_biquad_frequency_response(b_coeffs, a_coeffs, sampling_rate) # # Calculate the maximum gain # gain = max_abs_output_biquad(b_coeffs, a_coeffs) # print(f"Numerator coefficients (b): {b_coeffs}") # print(f"Denominator coefficients (a): {a_coeffs}") # print(f"Maximum possible time-domain gain (L1 norm): {gain:.4f}") IVAS_C_HPF_48k = 0.675231906655777 IVAS_C_HPF_32k = 0.554854910159853 IVAS_C_HPF_16k = 0.307863971328499 IVAS_C_FAST_48k = 0.995842001845110 IVAS_C_FAST_32k = 0.993769490623395 IVAS_C_FAST_16k = 0.987577800493881 IVAS_C_SLOW_48k = 0.999739617238810 IVAS_C_SLOW_32k = 0.999609451284012 IVAS_C_SLOW_16k = 0.999219055096324 #env_hpf sampling_rate = 48000.0 # Hz b_coeffs = [ +IVAS_C_HPF_48k, -IVAS_C_HPF_48k, 0.0 ] a_coeffs = [ 1.0, -IVAS_C_HPF_48k, 0.0 ] plot_biquad_frequency_response(b_coeffs, a_coeffs, sampling_rate) gain = max_abs_output_biquad(b_coeffs, a_coeffs) print(f"Maximum possible time-domain gain (L1 norm): {gain:.4f}") #env_fast sampling_rate = 48000.0 # Hz b_coeffs = [ 1.0 - IVAS_C_FAST_48k, 0.0, 0.0 ] a_coeffs = [ 1.0, -IVAS_C_FAST_48k, 0.0 ] plot_biquad_frequency_response(b_coeffs, a_coeffs, sampling_rate) gain = max_abs_output_biquad(b_coeffs, a_coeffs) print(f"Maximum possible time-domain gain (L1 norm): {gain:.4f}") #env_slow sampling_rate = 48000.0 # Hz b_coeffs = [ 1.0 - IVAS_C_SLOW_48k, 0.0, 0.0 ] a_coeffs = [ 1.0, -IVAS_C_SLOW_48k, 0.0 ] plot_biquad_frequency_response(b_coeffs, a_coeffs, sampling_rate) gain = max_abs_output_biquad(b_coeffs, a_coeffs) print(f"Maximum possible time-domain gain (L1 norm): {gain:.4f}") Loading
lib_com/ivas_filters_fx.c +97 −0 Original line number Diff line number Diff line Loading @@ -43,6 +43,7 @@ *------------------------------------------------------------------------------------------*/ static void ivas_iir_2_filter_fx( ivas_filters_process_state_t *filter_state, Word32 *pIn_Out_fx, const Word16 length, const Word16 stage, Word16 *pIn_Out_e ); static void ivas_iir_2_filter_fixed_fx( ivas_filters_process_state_t *filter_state, Word32 *pIn_Out_fx, const Word16 length, const Word16 stage, Word16 *pIn_Out_e ); /*-----------------------------------------------------------------------------------------* Loading Loading @@ -145,6 +146,10 @@ void ivas_filters_init_fx( move16(); } #ifdef OPT_2239_IVAS_FILTER_PROCESS filter_state->q_diff = 0; #endif return; } Loading Loading @@ -285,3 +290,95 @@ static void ivas_iir_2_filter_fx( return; } void ivas_filter_process_fixed_fx( ivas_filters_process_state_t *filter_state, /* i/o: filter state handle */ Word32 *pIn_Out_fx, /* i/o: signal subject to filtering (exp[i] : pIn_out_e[i]) */ const Word16 length, /* i : filter order */ Word16 *q_in_out ) { SWITCH( filter_state->order ) { case IVAS_FILTER_ORDER_1: ivas_iir_2_filter_fixed_fx( filter_state, pIn_Out_fx, length, IVAS_FILTER_STAGE_0, q_in_out ); /* Scale pIn_Out_fx back to input Q */ BREAK; case IVAS_FILTER_ORDER_4: /* biquad-1 */ ivas_iir_2_filter_fixed_fx( filter_state, pIn_Out_fx, length, IVAS_FILTER_STAGE_0, q_in_out ); /* biquad-2 */ ivas_iir_2_filter_fixed_fx( filter_state, pIn_Out_fx, length, IVAS_FILTER_STAGE_1, q_in_out ); /* Scale pIn_Out_fx back to input Q */ BREAK; default: BREAK; } return; } static void ivas_iir_2_filter_fixed_fx( ivas_filters_process_state_t *filter_state, Word32 *pIn_Out_fx, // Q(31-*pIn_Out_e) const Word16 length, const Word16 stage, Word16 *q_in_out ) { Word16 i, j; Word32 *pIn_fx = pIn_Out_fx; Word32 *pOut_fx = pIn_Out_fx; Word32 tmp_pIn_buf_i_fx; Word16 tmp_pIn_buf_i_e; Word32 L_tmp_prod, L_tmp; Word16 L_prod_e, L_tmp_e; Word16 exp; Word16 q_in = *q_in_out; Word16 q_out = add( filter_state->q_diff, q_in ); *q_in_out = q_out; FOR( i = 0; i < length; i++ ) { tmp_pIn_buf_i_fx = pIn_fx[i]; move32(); tmp_pIn_buf_i_e = q_in; move16(); L_tmp_prod = Mpy_32_32( filter_state->num_fx[stage][0], pIn_fx[i] ); // Q31 -(q_in+ filter_state->num_e[stage][0]) L_prod_e = add( q_in, filter_state->num_e[stage][0] ); pOut_fx[i] = BASOP_Util_Add_Mant32Exp( filter_state->state_fx[stage][0], filter_state->state_e[stage][0], L_tmp_prod, L_prod_e, &exp ); // Q31 - pIn_Out_e[i] move32(); FOR( j = 1; j < filter_state->filt_len; j++ ) { L_tmp_prod = Mpy_32_32( filter_state->num_fx[stage][j], tmp_pIn_buf_i_fx ); // Q31-L_prod_e L_prod_e = add( filter_state->num_e[stage][j], tmp_pIn_buf_i_e ); L_tmp = BASOP_Util_Add_Mant32Exp( filter_state->state_fx[stage][j], filter_state->state_e[stage][j], L_tmp_prod, L_prod_e, &L_tmp_e ); // Q31 - L_tmp_e L_tmp_prod = Mpy_32_32( filter_state->den_fx[stage][j], pOut_fx[i] ); // Q31 - ( pIn_Out_e[i]+filter_state->den_e[stage][j] ) L_prod_e = add( exp, filter_state->den_e[stage][j] ); filter_state->state_fx[stage][j - 1] = BASOP_Util_Add_Mant32Exp( L_tmp, L_tmp_e, L_negate( L_tmp_prod ), L_prod_e, &filter_state->state_e[stage][j - 1] ); // Q31 - filter_state->state_e[stage][j - 1] move32(); /*In case when exponent is less than -31 the value is very small and negligible hence resetting it to zero to avoid exponent overflow*/ IF( LT_16( filter_state->state_e[stage][j - 1], -31 ) ) { filter_state->state_fx[stage][j - 1] = 0; move32(); filter_state->state_e[stage][j - 1] = 0; move16(); } } Word16 shift = ( 31 - exp ) - q_out; pOut_fx[i] = L_shr_r_sat( pOut_fx[i], shift ); move32(); } return; }
lib_com/ivas_prot_fx.h +7 −0 Original line number Diff line number Diff line Loading @@ -3817,6 +3817,13 @@ void ivas_filter_process_exp_fx( Word16 *pIn_Out_e ); void ivas_filter_process_fixed_fx( ivas_filters_process_state_t *filter_state, /* i/o: filter state handle */ Word32 *pIn_Out_fx, /* i/o: signal subject to filtering (exp[i] : pIn_out_e[i]) */ const Word16 length, /* i : filter order */ Word16 *q_in_out ); ivas_error ivas_osba_enc_open_fx( Encoder_Struct *st_ivas /* i/o: IVAS encoder handle */ ); Loading
lib_com/ivas_stat_com.h +4 −0 Original line number Diff line number Diff line Loading @@ -661,6 +661,10 @@ typedef struct ivas_filters_process_state_t Word16 den_e[IVAS_FILTER_MAX_STAGES][IVAS_BIQUAD_FILT_LEN]; Word16 state_e[IVAS_FILTER_MAX_STAGES][IVAS_BIQUAD_FILT_LEN]; #ifdef OPT_2239_IVAS_FILTER_PROCESS Word16 q_diff; // q_diff = q_out - q_in -> q_out = q_diff + q_in #endif } ivas_filters_process_state_t; Loading
lib_com/ivas_transient_det_fx.c +76 −1 Original line number Diff line number Diff line Loading @@ -382,7 +382,6 @@ void ivas_td_decorr_get_ducking_gains_fx( { Word16 i; Word32 e_fast_fx[L_FRAME48k], e_slow_fx[L_FRAME48k]; Word16 e_fast_e[L_FRAME48k], e_slow_e[L_FRAME48k]; Word32 in_duck_gain = hTranDet->in_duck_gain; /*Q30*/ move32(); Word32 out_duck_gain = hTranDet->out_duck_gain; /*Q30*/ Loading @@ -396,6 +395,80 @@ void ivas_td_decorr_get_ducking_gains_fx( Copy32( pIn_pcm, e_fast_fx, frame_len ); /*Q11*/ #ifdef OPT_2239_IVAS_FILTER_PROCESS /* env hpf */ Word16 q_fast = Q11; ivas_filter_process_fixed_fx( &hTranDet->env_hpf, e_fast_fx, frame_len, &q_fast ); Word32 env_eps_fx = IVAS_TDET_PARM_ENV_EPS_fx; Word16 env_eps_q = Q31; Word16 q_diff = sub( q_fast, env_eps_q ); q_fast = s_min( q_fast, env_eps_q ); if ( q_diff >= 0 ) { for ( i = 0; i < frame_len; i++ ) { e_fast_fx[i] = L_add( L_abs( L_shr( e_fast_fx[i], q_diff ) ), env_eps_fx ); move32(); e_slow_fx[i] = e_fast_fx[i]; move32(); } } else { env_eps_fx = L_shl( env_eps_fx, q_diff ); for ( i = 0; i < frame_len; i++ ) { e_fast_fx[i] = L_add( L_abs( e_fast_fx[i] ), env_eps_fx ); move32(); e_slow_fx[i] = e_fast_fx[i]; move32(); } } Word16 q_slow = q_fast; /* env fast*/ ivas_filter_process_fixed_fx( &hTranDet->env_fast, e_fast_fx, frame_len, &q_fast ); /* env slow */ ivas_filter_process_fixed_fx( &hTranDet->env_slow, e_slow_fx, frame_len, &q_slow ); IF( tdet_flag ) { FOR( i = 0; i < frame_len; i++ ) { in_duck_gain = ivas_calc_duck_gain_fx( in_duck_gain, in_duck_coeff, e_slow_fx[i], 31 - q_slow, e_fast_fx[i], 31 - q_fast, duck_mult_fac ); /*Q30*/ pIn_duck_gains[i] = in_duck_gain; /*Q30*/ move32(); } hTranDet->in_duck_gain = in_duck_gain; /*Q30*/ move32(); } ELSE { FOR( i = 0; i < frame_len; i++ ) { in_duck_gain = ivas_calc_duck_gain_fx( in_duck_gain, in_duck_coeff, e_slow_fx[i], 31 - q_slow, e_fast_fx[i], 31 - q_fast, duck_mult_fac ); /*Q30*/ pIn_duck_gains[i] = in_duck_gain; /*Q30*/ move32(); out_duck_gain = ivas_calc_duck_gain_fx( out_duck_gain, out_duck_coeff, e_fast_fx[i], 31 - q_fast, e_slow_fx[i], 31 - q_slow, duck_mult_fac ); /*Q30*/ pOut_duck_gains[i] = out_duck_gain; /*Q30*/ move32(); } hTranDet->in_duck_gain = in_duck_gain; /*Q30*/ move32(); hTranDet->out_duck_gain = out_duck_gain; /*Q30*/ move32(); } #else Word16 e_fast_e[L_FRAME48k], e_slow_e[L_FRAME48k]; set16_fx( e_fast_e, 31 - Q11, L_FRAME48k ); /* env hpf */ Loading Loading @@ -446,6 +519,8 @@ void ivas_td_decorr_get_ducking_gains_fx( hTranDet->out_duck_gain = out_duck_gain; /*Q30*/ move32(); } #endif return; }
lib_com/ivas_transient_det_fx.py 0 → 100644 +98 −0 Original line number Diff line number Diff line import numpy as np from scipy import signal import matplotlib.pyplot as plt def generate_biquad_butterworth_coeffs(cutoff_freq, fs, order=2, ftype='lowpass', output='ba'): Wn = cutoff_freq if output == 'sos': sos_coeffs = signal.butter(order, Wn, btype=ftype, analog=False, output='sos', fs=fs) return sos_coeffs elif output == 'ba': b_coeffs, a_coeffs = signal.butter(order, Wn, btype=ftype, analog=False, output='ba', fs=fs) return b_coeffs, a_coeffs else: raise ValueError("Output format must be 'sos' or 'ba'") def plot_biquad_frequency_response(b, a, fs): w, h = signal.freqz(b, a, fs=fs) magnitude_db = 20 * np.log10(np.abs(h)) phase_degrees = np.unwrap(np.angle(h)) * 180 / np.pi fig, (ax1, ax2) = plt.subplots(2, 1, sharex=True, tight_layout=True) ax1.plot(w, magnitude_db, 'b') ax1.set_ylabel('Magnitude (dB)', color='b') ax1.set_xlabel('Frequency (Hz)') ax1.grid() ax2.plot(w, phase_degrees, 'g') ax2.set_ylabel('Phase (degrees)', color='g') ax2.set_xlabel('Frequency (Hz)') ax2.grid() plt.show() def max_abs_output_biquad(b, a, n_samples=10000): if a[0] != 1.0: b = np.array(b) / a[0] a = np.array(a) / a[0] a[0] = 1.0 impulse_input = np.zeros(n_samples) impulse_input[0] = 1.0 impulse_response = signal.lfilter(b, a, impulse_input) max_gain = np.sum(np.abs(impulse_response)) return max_gain # sampling_rate = 44100.0 # Hz # cutoff_frequency = 5000.0 # Hz # b_coeffs,a_coeffs = generate_biquad_butterworth_coeffs(cutoff_frequency, sampling_rate) # plot_biquad_frequency_response(b_coeffs, a_coeffs, sampling_rate) # # Calculate the maximum gain # gain = max_abs_output_biquad(b_coeffs, a_coeffs) # print(f"Numerator coefficients (b): {b_coeffs}") # print(f"Denominator coefficients (a): {a_coeffs}") # print(f"Maximum possible time-domain gain (L1 norm): {gain:.4f}") IVAS_C_HPF_48k = 0.675231906655777 IVAS_C_HPF_32k = 0.554854910159853 IVAS_C_HPF_16k = 0.307863971328499 IVAS_C_FAST_48k = 0.995842001845110 IVAS_C_FAST_32k = 0.993769490623395 IVAS_C_FAST_16k = 0.987577800493881 IVAS_C_SLOW_48k = 0.999739617238810 IVAS_C_SLOW_32k = 0.999609451284012 IVAS_C_SLOW_16k = 0.999219055096324 #env_hpf sampling_rate = 48000.0 # Hz b_coeffs = [ +IVAS_C_HPF_48k, -IVAS_C_HPF_48k, 0.0 ] a_coeffs = [ 1.0, -IVAS_C_HPF_48k, 0.0 ] plot_biquad_frequency_response(b_coeffs, a_coeffs, sampling_rate) gain = max_abs_output_biquad(b_coeffs, a_coeffs) print(f"Maximum possible time-domain gain (L1 norm): {gain:.4f}") #env_fast sampling_rate = 48000.0 # Hz b_coeffs = [ 1.0 - IVAS_C_FAST_48k, 0.0, 0.0 ] a_coeffs = [ 1.0, -IVAS_C_FAST_48k, 0.0 ] plot_biquad_frequency_response(b_coeffs, a_coeffs, sampling_rate) gain = max_abs_output_biquad(b_coeffs, a_coeffs) print(f"Maximum possible time-domain gain (L1 norm): {gain:.4f}") #env_slow sampling_rate = 48000.0 # Hz b_coeffs = [ 1.0 - IVAS_C_SLOW_48k, 0.0, 0.0 ] a_coeffs = [ 1.0, -IVAS_C_SLOW_48k, 0.0 ] plot_biquad_frequency_response(b_coeffs, a_coeffs, sampling_rate) gain = max_abs_output_biquad(b_coeffs, a_coeffs) print(f"Maximum possible time-domain gain (L1 norm): {gain:.4f}")