Mercurial > hg > aimc
diff carfac/carfac.cc @ 643:8b70f4cf00c7
Additional changes to C++ CARFAC on the basis of ronw's comments on r289. Moved CARFAC::Design to CARFAC::CARFAC and CARFAC::Reset(), moved carfac_common.h to common.h, CARFACDetect to carfac_util.h/cc, FloatArray and Float2dArray to ArrayX and ArrayXX, improved variable naming, made a start on improved commenting documentation.
| author | alexbrandmeyer |
|---|---|
| date | Tue, 04 Jun 2013 18:30:22 +0000 |
| parents | fe8ac95fcf9e |
| children | 16dfff1de47a |
line wrap: on
line diff
--- a/carfac/carfac.cc Fri May 31 21:46:48 2013 +0000 +++ b/carfac/carfac.cc Tue Jun 04 18:30:22 2013 +0000 @@ -21,41 +21,49 @@ // limitations under the License. #include <assert.h> + #include "carfac.h" + using std::vector; -void CARFAC::Design(const int n_ears, const FPType fs, +CARFAC::CARFAC(const int num_ears, const FPType sample_rate, const CARParams& car_params, const IHCParams& ihc_params, const AGCParams& agc_params) { - n_ears_ = n_ears; - fs_ = fs; - ears_.resize(n_ears_); - n_ch_ = 0; - FPType pole_hz = car_params.first_pole_theta * fs / (2 * kPi); - while (pole_hz > car_params.min_pole_hz) { - ++n_ch_; - pole_hz = pole_hz - car_params.erb_per_step * - ERBHz(pole_hz, car_params.erb_break_freq, car_params.erb_q); + num_ears_ = num_ears; + sample_rate_ = sample_rate; + ears_.resize(num_ears_); + car_params_ = car_params; + ihc_params_ = ihc_params; + agc_params_ = agc_params; + Reset(); +} + +void CARFAC::Reset() { + num_channels_ = 0; + FPType pole_hz = car_params_.first_pole_theta * sample_rate_ / (2 * kPi); + while (pole_hz > car_params_.min_pole_hz) { + ++num_channels_; + pole_hz = pole_hz - car_params_.erb_per_step * + ERBHz(pole_hz, car_params_.erb_break_freq, car_params_.erb_q); } - pole_freqs_.resize(n_ch_); - pole_hz = car_params.first_pole_theta * fs / (2 * kPi); - for (int ch = 0; ch < n_ch_; ++ch) { - pole_freqs_(ch) = pole_hz; - pole_hz = pole_hz - car_params.erb_per_step * - ERBHz(pole_hz, car_params.erb_break_freq, car_params.erb_q); + pole_freqs_.resize(num_channels_); + pole_hz = car_params_.first_pole_theta * sample_rate_ / (2 * kPi); + for (int channel = 0; channel < num_channels_; ++channel) { + pole_freqs_(channel) = pole_hz; + pole_hz = pole_hz - car_params_.erb_per_step * + ERBHz(pole_hz, car_params_.erb_break_freq, car_params_.erb_q); } max_channels_per_octave_ = log(2) / log(pole_freqs_(0) / pole_freqs_(1)); CARCoeffs car_coeffs; IHCCoeffs ihc_coeffs; std::vector<AGCCoeffs> agc_coeffs; - DesignCARCoeffs(car_params, fs, pole_freqs_, &car_coeffs); - DesignIHCCoeffs(ihc_params, fs, &ihc_coeffs); + DesignCARCoeffs(car_params_, sample_rate_, pole_freqs_, &car_coeffs); + DesignIHCCoeffs(ihc_params_, sample_rate_, &ihc_coeffs); // This code initializes the coefficients for each of the AGC stages. - DesignAGCCoeffs(agc_params, fs, &agc_coeffs); + DesignAGCCoeffs(agc_params_, sample_rate_, &agc_coeffs); // Once we have the coefficient structure we can design the ears. for (auto& ear : ears_) { - ear.InitEar(n_ch_, fs_, car_coeffs, ihc_coeffs, - agc_coeffs); + ear.Init(num_channels_, car_coeffs, ihc_coeffs, agc_coeffs); } } @@ -65,21 +73,22 @@ // A nested loop structure is used to iterate through the individual samples // for each ear (audio channel). bool updated; // This variable is used by the AGC stage. - for (int32_t i = 0; i < length; ++i) { - for (int j = 0; j < n_ears_; ++j) { + for (int32_t timepoint = 0; timepoint < length; ++timepoint) { + for (int audio_channel = 0; audio_channel < num_ears_; ++audio_channel) { // First we create a reference to the current Ear object. - Ear& ear = ears_[j]; + Ear& ear = ears_[audio_channel]; // This stores the audio sample currently being processed. - FPType input = sound_data[j][start+i]; + FPType input = sound_data[audio_channel][start + timepoint]; + // Now we apply the three stages of the model in sequence to the current // audio sample. ear.CARStep(input); ear.IHCStep(ear.car_out()); updated = ear.AGCStep(ear.ihc_out()); } - seg_output->StoreOutput(ears_); + seg_output->AppendOutput(ears_); if (updated) { - if (n_ears_ > 1) { + if (num_ears_ > 1) { CrossCouple(); } if (! open_loop) { @@ -90,19 +99,19 @@ } void CARFAC::CrossCouple() { - for (int stage = 0; stage < ears_[0].agc_nstages(); ++stage) { + for (int stage = 0; stage < ears_[0].agc_num_stages(); ++stage) { if (ears_[0].agc_decim_phase(stage) > 0) { break; } else { FPType mix_coeff = ears_[0].agc_mix_coeff(stage); if (mix_coeff > 0) { - FloatArray stage_state; - FloatArray this_stage_values = FloatArray::Zero(n_ch_); + ArrayX stage_state; + ArrayX this_stage_values = ArrayX::Zero(num_channels_); for (auto& ear : ears_) { stage_state = ear.agc_memory(stage); this_stage_values += stage_state; } - this_stage_values /= n_ears_; + this_stage_values /= num_ears_; for (auto& ear : ears_) { stage_state = ear.agc_memory(stage); ear.set_agc_memory(stage, stage_state + mix_coeff * @@ -115,7 +124,7 @@ void CARFAC::CloseAGCLoop() { for (auto& ear: ears_) { - FloatArray undamping = 1 - ear.agc_memory(0); + ArrayX undamping = 1 - ear.agc_memory(0); // This updates the target stage gain for the new damping. ear.set_dzb_memory((ear.zr_coeffs() * undamping - ear.zb_memory()) / ear.agc_decimation(0)); @@ -124,51 +133,52 @@ } } -void CARFAC::DesignCARCoeffs(const CARParams& car_params, const FPType fs, - const FloatArray& pole_freqs, +void CARFAC::DesignCARCoeffs(const CARParams& car_params, + const FPType sample_rate, + const ArrayX& pole_freqs, CARCoeffs* car_coeffs) { - n_ch_ = pole_freqs.size(); + num_channels_ = pole_freqs.size(); car_coeffs->velocity_scale = car_params.velocity_scale; car_coeffs->v_offset = car_params.v_offset; - car_coeffs->r1_coeffs.resize(n_ch_); - car_coeffs->a0_coeffs.resize(n_ch_); - car_coeffs->c0_coeffs.resize(n_ch_); - car_coeffs->h_coeffs.resize(n_ch_); - car_coeffs->g0_coeffs.resize(n_ch_); + car_coeffs->r1_coeffs.resize(num_channels_); + car_coeffs->a0_coeffs.resize(num_channels_); + car_coeffs->c0_coeffs.resize(num_channels_); + car_coeffs->h_coeffs.resize(num_channels_); + car_coeffs->g0_coeffs.resize(num_channels_); FPType f = car_params.zero_ratio * car_params.zero_ratio - 1.0; - FloatArray theta = pole_freqs * ((2.0 * kPi) / fs); + ArrayX theta = pole_freqs * ((2.0 * kPi) / sample_rate); car_coeffs->c0_coeffs = theta.sin(); car_coeffs->a0_coeffs = theta.cos(); FPType ff = car_params.high_f_damping_compression; - FloatArray x = theta / kPi; + ArrayX x = theta / kPi; car_coeffs->zr_coeffs = kPi * (x - (ff * (x*x*x))); FPType max_zeta = car_params.max_zeta; FPType min_zeta = car_params.min_zeta; car_coeffs->r1_coeffs = (1.0 - (car_coeffs->zr_coeffs * max_zeta)); - FloatArray erb_freqs(n_ch_); - for (int ch=0; ch < n_ch_; ++ch) { - erb_freqs(ch) = ERBHz(pole_freqs(ch), car_params.erb_break_freq, + ArrayX erb_freqs(num_channels_); + for (int channel = 0; channel < num_channels_; ++channel) { + erb_freqs(channel) = ERBHz(pole_freqs(channel), car_params.erb_break_freq, car_params.erb_q); } - FloatArray min_zetas = min_zeta + (0.25 * ((erb_freqs / pole_freqs) - + ArrayX min_zetas = min_zeta + (0.25 * ((erb_freqs / pole_freqs) - min_zeta)); car_coeffs->zr_coeffs *= max_zeta - min_zetas; car_coeffs->h_coeffs = car_coeffs->c0_coeffs * f; - FloatArray relative_undamping = FloatArray::Ones(n_ch_); - FloatArray r = car_coeffs->r1_coeffs + (car_coeffs->zr_coeffs * + ArrayX relative_undamping = ArrayX::Ones(num_channels_); + ArrayX r = car_coeffs->r1_coeffs + (car_coeffs->zr_coeffs * relative_undamping); car_coeffs->g0_coeffs = (1.0 - (2.0 * r * car_coeffs->a0_coeffs) + (r*r)) / (1 - (2 * r * car_coeffs->a0_coeffs) + (car_coeffs->h_coeffs * r * car_coeffs->c0_coeffs) + (r*r)); } -void CARFAC::DesignIHCCoeffs(const IHCParams& ihc_params, const FPType fs, - IHCCoeffs* ihc_coeffs) { +void CARFAC::DesignIHCCoeffs(const IHCParams& ihc_params, + const FPType sample_rate, IHCCoeffs* ihc_coeffs) { if (ihc_params.just_half_wave_rectify) { ihc_coeffs->just_half_wave_rectify = ihc_params.just_half_wave_rectify; } else { // This section calculates conductance values using two pre-defined scalars. - FloatArray x(1); + ArrayX x(1); FPType conduct_at_10, conduct_at_0; x(0) = 10.0; x = CARFACDetect(x); @@ -185,9 +195,9 @@ FPType current = 1 / (ri + r0); ihc_coeffs->cap1_voltage = 1 - (current * ri); ihc_coeffs->just_half_wave_rectify = false; - ihc_coeffs->lpf_coeff = 1 - exp( -1 / (ihc_params.tau_lpf * fs)); - ihc_coeffs->out1_rate = ro / (ihc_params.tau1_out * fs); - ihc_coeffs->in1_rate = 1 / (ihc_params.tau1_in * fs); + ihc_coeffs->lpf_coeff = 1 - exp( -1 / (ihc_params.tau_lpf * sample_rate)); + ihc_coeffs->out1_rate = ro / (ihc_params.tau1_out * sample_rate); + ihc_coeffs->in1_rate = 1 / (ihc_params.tau1_in * sample_rate); ihc_coeffs->one_capacitor = ihc_params.one_capacitor; ihc_coeffs->output_gain = 1 / (saturation_output - current); ihc_coeffs->rest_output = current / (saturation_output - current); @@ -204,11 +214,11 @@ ihc_coeffs->cap1_voltage = 1 - (current * r1); ihc_coeffs->cap2_voltage = ihc_coeffs->cap1_voltage - (current * r2); ihc_coeffs->just_half_wave_rectify = false; - ihc_coeffs->lpf_coeff = 1 - exp(-1 / (ihc_params.tau_lpf * fs)); - ihc_coeffs->out1_rate = 1 / (ihc_params.tau1_out * fs); - ihc_coeffs->in1_rate = 1 / (ihc_params.tau1_in * fs); - ihc_coeffs->out2_rate = ro / (ihc_params.tau2_out * fs); - ihc_coeffs->in2_rate = 1 / (ihc_params.tau2_in * fs); + ihc_coeffs->lpf_coeff = 1 - exp(-1 / (ihc_params.tau_lpf * sample_rate)); + ihc_coeffs->out1_rate = 1 / (ihc_params.tau1_out * sample_rate); + ihc_coeffs->in1_rate = 1 / (ihc_params.tau1_in * sample_rate); + ihc_coeffs->out2_rate = ro / (ihc_params.tau2_out * sample_rate); + ihc_coeffs->in2_rate = 1 / (ihc_params.tau2_in * sample_rate); ihc_coeffs->one_capacitor = ihc_params.one_capacitor; ihc_coeffs->output_gain = 1 / (saturation_output - current); ihc_coeffs->rest_output = current / (saturation_output - current); @@ -216,17 +226,18 @@ ihc_coeffs->rest_cap2 = ihc_coeffs->cap2_voltage; } } - ihc_coeffs->ac_coeff = 2 * kPi * ihc_params.ac_corner_hz / fs; + ihc_coeffs->ac_coeff = 2 * kPi * ihc_params.ac_corner_hz / sample_rate; } -void CARFAC::DesignAGCCoeffs(const AGCParams& agc_params, const FPType fs, +void CARFAC::DesignAGCCoeffs(const AGCParams& agc_params, + const FPType sample_rate, vector<AGCCoeffs>* agc_coeffs) { - agc_coeffs->resize(agc_params.n_stages); + agc_coeffs->resize(agc_params.num_stages); FPType previous_stage_gain = 0.0; FPType decim = 1.0; - for (int stage = 0; stage < agc_params.n_stages; ++stage) { + for (int stage = 0; stage < agc_params.num_stages; ++stage) { AGCCoeffs& agc_coeff = agc_coeffs->at(stage); - agc_coeff.n_agc_stages = agc_params.n_stages; + agc_coeff.num_agc_stages = agc_params.num_stages; agc_coeff.agc_stage_gain = agc_params.agc_stage_gain; vector<FPType> agc1_scales = agc_params.agc1_scales; vector<FPType> agc2_scales = agc_params.agc2_scales; @@ -238,8 +249,9 @@ FPType tau = time_constants[stage]; agc_coeff.decim = decim; agc_coeff.decim *= agc_coeff.decimation; - agc_coeff.agc_epsilon = 1 - exp((-1 * agc_coeff.decim) / (tau * fs)); - FPType n_times = tau * (fs / agc_coeff.decim); + agc_coeff.agc_epsilon = 1 - exp((-1 * agc_coeff.decim) / + (tau * sample_rate)); + FPType n_times = tau * (sample_rate / agc_coeff.decim); FPType delay = (agc2_scales[stage] - agc1_scales[stage]) / n_times; FPType spread_sq = (pow(agc1_scales[stage], 2) + pow(agc2_scales[stage], 2)) / n_times; @@ -317,10 +329,15 @@ agc_coeff.agc_spatial_fir_right = fir_right; total_dc_gain += pow(agc_coeff.agc_stage_gain, stage); agc_coeff.agc_mix_coeffs = stage == 0 ? 0 : mix_coeff / - (tau * (fs / agc_coeff.decim)); + (tau * (sample_rate / agc_coeff.decim)); agc_coeff.agc_gain = total_dc_gain; agc_coeff.detect_scale = 1 / total_dc_gain; previous_stage_gain = agc_coeff.agc_gain; decim = agc_coeff.decim; } } + +FPType CARFAC::ERBHz (const FPType center_frequency_hz, + const FPType erb_break_freq, const FPType erb_q) { + return (erb_break_freq + center_frequency_hz) / erb_q; +} \ No newline at end of file
