diff carfac/ear.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 d08c02c8e26f
children 3f01a136c537
line wrap: on
line diff
--- a/carfac/ear.cc	Fri May 31 21:46:48 2013 +0000
+++ b/carfac/ear.cc	Tue Jun 04 18:30:22 2013 +0000
@@ -23,48 +23,40 @@
 #include <assert.h>
 #include "ear.h"
 
-// The 'InitEar' function takes a set of model parameters and initializes the
-// design coefficients and model state variables needed for running the model
-// on a single audio channel.
-void Ear::InitEar(const int n_ch, const FPType fs, const CARCoeffs& car_coeffs,
-                  const IHCCoeffs& ihc_coeffs,
-                  const std::vector<AGCCoeffs>& agc_coeffs) {
-  // The first section of code determines the number of channels that will be
-  // used in the model on the basis of the sample rate and the CAR parameters
-  // that have been passed to this function.
-  n_ch_ = n_ch;
+void Ear::Init(const int num_channels, const CARCoeffs& car_coeffs,
+               const IHCCoeffs& ihc_coeffs,
+               const std::vector<AGCCoeffs>& agc_coeffs) {
+  num_channels_ = num_channels;
   car_coeffs_ = car_coeffs;
   ihc_coeffs_ = ihc_coeffs;
   agc_coeffs_ = agc_coeffs;
-  // Once the coefficients have been determined, we can initialize the state
-  // variables that will be used during runtime.
   InitCARState();
   InitIHCState();
   InitAGCState();
 }
 
 void Ear::InitCARState() {
-  car_state_.z1_memory.setZero(n_ch_);
-  car_state_.z2_memory.setZero(n_ch_);
-  car_state_.za_memory.setZero(n_ch_);
+  car_state_.z1_memory.setZero(num_channels_);
+  car_state_.z2_memory.setZero(num_channels_);
+  car_state_.za_memory.setZero(num_channels_);
   car_state_.zb_memory = car_coeffs_.zr_coeffs;
-  car_state_.dzb_memory.setZero(n_ch_);
-  car_state_.zy_memory.setZero(n_ch_);
+  car_state_.dzb_memory.setZero(num_channels_);
+  car_state_.zy_memory.setZero(num_channels_);
   car_state_.g_memory = car_coeffs_.g0_coeffs;
-  car_state_.dg_memory.setZero(n_ch_);
+  car_state_.dg_memory.setZero(num_channels_);
 }
 
 void Ear::InitIHCState() {
-  ihc_state_.ihc_accum = FloatArray::Zero(n_ch_);
+  ihc_state_.ihc_accum = ArrayX::Zero(num_channels_);
   if (! ihc_coeffs_.just_half_wave_rectify) {
-    ihc_state_.ac_coupler.setZero(n_ch_);
-    ihc_state_.lpf1_state.setConstant(n_ch_, ihc_coeffs_.rest_output);
-    ihc_state_.lpf2_state.setConstant(n_ch_, ihc_coeffs_.rest_output);
+    ihc_state_.ac_coupler.setZero(num_channels_);
+    ihc_state_.lpf1_state.setConstant(num_channels_, ihc_coeffs_.rest_output);
+    ihc_state_.lpf2_state.setConstant(num_channels_, ihc_coeffs_.rest_output);
     if (ihc_coeffs_.one_capacitor) {
-      ihc_state_.cap1_voltage.setConstant(n_ch_, ihc_coeffs_.rest_cap1);
+      ihc_state_.cap1_voltage.setConstant(num_channels_, ihc_coeffs_.rest_cap1);
     } else {
-      ihc_state_.cap1_voltage.setConstant(n_ch_, ihc_coeffs_.rest_cap1);
-      ihc_state_.cap2_voltage.setConstant(n_ch_, ihc_coeffs_.rest_cap2);
+      ihc_state_.cap1_voltage.setConstant(num_channels_, ihc_coeffs_.rest_cap1);
+      ihc_state_.cap2_voltage.setConstant(num_channels_, ihc_coeffs_.rest_cap2);
     }
   }
 }
@@ -74,8 +66,8 @@
   agc_state_.resize(n_agc_stages);
   for (auto& stage_state : agc_state_) {
     stage_state.decim_phase = 0;
-    stage_state.agc_memory.setZero(n_ch_);
-    stage_state.input_accum.setZero(n_ch_);
+    stage_state.agc_memory.setZero(num_channels_);
+    stage_state.input_accum.setZero(num_channels_);
   }
 }
 
@@ -86,16 +78,15 @@
   car_state_.zb_memory = car_state_.zb_memory + car_state_.dzb_memory;
   // This updates the nonlinear function of 'velocity' along with zA, which is
   // a delay of z2.
-  FloatArray nonlinear_fun(n_ch_);
-  FloatArray velocities = car_state_.z2_memory - car_state_.za_memory;
+  ArrayX nonlinear_fun(num_channels_);
+  ArrayX velocities = car_state_.z2_memory - car_state_.za_memory;
   OHCNonlinearFunction(velocities, &nonlinear_fun);
   // Here, zb_memory_ * nonlinear_fun is "undamping" delta r.
-  FloatArray r = car_coeffs_.r1_coeffs + (car_state_.zb_memory *
-                                           nonlinear_fun);
+  ArrayX r = car_coeffs_.r1_coeffs + (car_state_.zb_memory * nonlinear_fun);
   car_state_.za_memory = car_state_.z2_memory;
   // Here we reduce the CAR state by r and rotate with the fixed cos/sin coeffs.
-  FloatArray z1  = r * ((car_coeffs_.a0_coeffs * car_state_.z1_memory) -
-                        (car_coeffs_.c0_coeffs * car_state_.z2_memory));
+  ArrayX z1  = r * ((car_coeffs_.a0_coeffs * car_state_.z1_memory) -
+                    (car_coeffs_.c0_coeffs * car_state_.z2_memory));
   car_state_.z2_memory = r *
     ((car_coeffs_.c0_coeffs * car_state_.z1_memory) +
      (car_coeffs_.a0_coeffs * car_state_.z2_memory));
@@ -103,11 +94,12 @@
   // This section ripples the input-output path, to avoid delay...
   // It's the only part that doesn't get computed "in parallel":
   FPType in_out = input;
-  for (int ch = 0; ch < n_ch_; ch++) {
-    z1(ch) = z1(ch) + in_out;
+  for (int channel = 0; channel < num_channels_; channel++) {
+    z1(channel) = z1(channel) + in_out;
     // This performs the ripple, and saves the final channel outputs in zy.
-    in_out = car_state_.g_memory(ch) * (in_out + car_state_.zy_memory(ch));
-    car_state_.zy_memory(ch) = in_out;
+    in_out = car_state_.g_memory(channel) *
+      (in_out + car_state_.zy_memory(channel));
+    car_state_.zy_memory(channel) = in_out;
   }
   car_state_.z1_memory = z1;
 }
@@ -115,8 +107,8 @@
 // We start with a quadratic nonlinear function, and limit it via a
 // rational function. This makes the result go to zero at high
 // absolute velocities, so it will do nothing there.
-void Ear::OHCNonlinearFunction(const FloatArray& velocities,
-                               FloatArray* nonlinear_fun) {
+void Ear::OHCNonlinearFunction(const ArrayX& velocities,
+                               ArrayX* nonlinear_fun) {
   *nonlinear_fun = (1 + ((velocities * car_coeffs_.velocity_scale) +
                          car_coeffs_.v_offset).square()).inverse();
 }
@@ -124,19 +116,19 @@
 // This step is a one sample-time update of the inner-hair-cell (IHC) model,
 // including the detection nonlinearity and either one or two capacitor state
 // variables.
-void Ear::IHCStep(const FloatArray& car_out) {
-  FloatArray ac_diff = car_out - ihc_state_.ac_coupler;
+void Ear::IHCStep(const ArrayX& car_out) {
+  ArrayX ac_diff = car_out - ihc_state_.ac_coupler;
   ihc_state_.ac_coupler = ihc_state_.ac_coupler +
     (ihc_coeffs_.ac_coeff * ac_diff);
   if (ihc_coeffs_.just_half_wave_rectify) {
-    FloatArray output(n_ch_);
-    for (int ch = 0; ch < n_ch_; ++ch) {
-      FPType a = (ac_diff(ch) > 0.0) ? ac_diff(ch) : 0.0;
-      output(ch) = (a < 2) ? a : 2;
+    ArrayX output(num_channels_);
+    for (int channel = 0; channel < num_channels_; ++channel) {
+      FPType a = (ac_diff(channel) > 0.0) ? ac_diff(channel) : 0.0;
+      output(channel) = (a < 2) ? a : 2;
     }
     ihc_state_.ihc_out = output;
   } else {
-    FloatArray conductance = CARFACDetect(ac_diff);
+    ArrayX conductance = CARFACDetect(ac_diff);
     if (ihc_coeffs_.one_capacitor) {
       ihc_state_.ihc_out = conductance * ihc_state_.cap1_voltage;
       ihc_state_.cap1_voltage = ihc_state_.cap1_voltage -
@@ -164,15 +156,15 @@
   ihc_state_.ihc_accum += ihc_state_.ihc_out;
 }
 
-bool Ear::AGCStep(const FloatArray& ihc_out) {
+bool Ear::AGCStep(const ArrayX& ihc_out) {
   int stage = 0;
-  int n_stages = agc_coeffs_[0].n_agc_stages;
-  FPType detect_scale = agc_coeffs_[n_stages - 1].detect_scale;
+  int num_stages = agc_coeffs_[0].num_agc_stages;
+  FPType detect_scale = agc_coeffs_[num_stages - 1].detect_scale;
   bool updated = AGCRecurse(stage, detect_scale * ihc_out);
   return updated;
 }
 
-bool Ear::AGCRecurse(const int stage, FloatArray agc_in) {
+bool Ear::AGCRecurse(const int stage, ArrayX agc_in) {
   bool updated = true;
   const auto& agc_coeffs = agc_coeffs_[stage];
   auto& agc_state = agc_state_[stage];
@@ -191,7 +183,7 @@
     // decimated at the next stage.
     agc_in = agc_state.input_accum / decim;
     // This resets the accumulator.
-    agc_state.input_accum = FloatArray::Zero(n_ch_);
+    agc_state.input_accum = ArrayX::Zero(num_channels_);
     if (stage < (agc_coeffs_.size() - 1)) {
       // Now we recurse to evaluate the next stage(s).
       updated = AGCRecurse(stage + 1, agc_in);
@@ -212,25 +204,27 @@
 }
 
 void Ear::AGCSpatialSmooth(const AGCCoeffs& agc_coeffs,
-                           FloatArray* stage_state) {
-  int n_iterations = agc_coeffs.agc_spatial_iterations;
+                           ArrayX* stage_state) {
+  int num_iterations = agc_coeffs.agc_spatial_iterations;
   bool use_fir;
-  use_fir = (n_iterations < 4) ? true : false;
+  use_fir = (num_iterations < 4) ? true : false;
   if (use_fir) {
     FPType fir_coeffs_left = agc_coeffs.agc_spatial_fir_left;
     FPType fir_coeffs_mid = agc_coeffs.agc_spatial_fir_mid;
     FPType fir_coeffs_right = agc_coeffs.agc_spatial_fir_right;
-    FloatArray ss_tap1(n_ch_);
-    FloatArray ss_tap2(n_ch_);
-    FloatArray ss_tap3(n_ch_);
-    FloatArray ss_tap4(n_ch_);
+    ArrayX ss_tap1(num_channels_);
+    ArrayX ss_tap2(num_channels_);
+    ArrayX ss_tap3(num_channels_);
+    ArrayX ss_tap4(num_channels_);
     int n_taps = agc_coeffs.agc_spatial_n_taps;
     // This initializes the first two taps of stage state, which are used for
     // both possible cases.
     ss_tap1(0) = (*stage_state)(0);
-    ss_tap1.block(1, 0, n_ch_ - 1, 1) = stage_state->block(0, 0, n_ch_ - 1, 1);
-    ss_tap2(n_ch_ - 1) = (*stage_state)(n_ch_ - 1);
-    ss_tap2.block(0, 0, n_ch_ - 1, 1) = stage_state->block(1, 0, n_ch_ - 1, 1);
+    ss_tap1.block(1, 0, num_channels_ - 1, 1) =
+      stage_state->block(0, 0, num_channels_ - 1, 1);
+    ss_tap2(num_channels_ - 1) = (*stage_state)(num_channels_ - 1);
+    ss_tap2.block(0, 0, num_channels_ - 1, 1) =
+      stage_state->block(1, 0, num_channels_ - 1, 1);
     switch (n_taps) {
       case 3:
         *stage_state = (fir_coeffs_left * ss_tap1) +
@@ -241,12 +235,12 @@
         // for the 5-tap case.
         ss_tap3(0) = (*stage_state)(0);
         ss_tap3(1) = (*stage_state)(1);
-        ss_tap3.block(2, 0, n_ch_ - 2, 1) =
-          stage_state->block(0, 0, n_ch_ - 2, 1);
-        ss_tap4(n_ch_ - 2) = (*stage_state)(n_ch_ - 1);
-        ss_tap4(n_ch_ - 1) = (*stage_state)(n_ch_ - 2);
-        ss_tap4.block(0, 0, n_ch_ - 2, 1) =
-        stage_state->block(2, 0, n_ch_ - 2, 1);
+        ss_tap3.block(2, 0, num_channels_ - 2, 1) =
+          stage_state->block(0, 0, num_channels_ - 2, 1);
+        ss_tap4(num_channels_ - 2) = (*stage_state)(num_channels_ - 1);
+        ss_tap4(num_channels_ - 1) = (*stage_state)(num_channels_ - 2);
+        ss_tap4.block(0, 0, num_channels_ - 2, 1) =
+        stage_state->block(2, 0, num_channels_ - 2, 1);
         *stage_state = (fir_coeffs_left * (ss_tap3 + ss_tap1)) +
           (fir_coeffs_mid * *stage_state) +
           (fir_coeffs_right * (ss_tap2 + ss_tap4));
@@ -261,30 +255,31 @@
   }
 }
 
-void Ear::AGCSmoothDoubleExponential(const FPType pole_z1,  const FPType pole_z2,
-                                FloatArray* stage_state) {
-  int32_t n_pts = stage_state->size();
+void Ear::AGCSmoothDoubleExponential(const FPType pole_z1,
+                                     const FPType pole_z2,
+                                     ArrayX* stage_state) {
+  int32_t num_points = stage_state->size();
   FPType input;
   FPType state = 0.0;
   // TODO (alexbrandmeyer): I'm assuming one dimensional input for now, but this
   // should be verified with Dick for the final version
-  for (int i = n_pts - 11; i < n_pts; ++i) {
+  for (int i = num_points - 11; i < num_points; ++i) {
     input = (*stage_state)(i);
     state = state + (1 - pole_z1) * (input - state);
   }
-  for (int i = n_pts - 1; i > -1; --i) {
+  for (int i = num_points - 1; i > -1; --i) {
     input = (*stage_state)(i);
     state = state + (1 - pole_z2) * (input - state);
   }
-  for (int i = 0; i < n_pts; ++i) {
+  for (int i = 0; i < num_points; ++i) {
     input = (*stage_state)(i);
     state = state + (1 - pole_z1) * (input - state);
     (*stage_state)(i) = state;
   }
 }
 
-FloatArray Ear::StageGValue(const FloatArray& undamping) {
-  FloatArray r = car_coeffs_.r1_coeffs + car_coeffs_.zr_coeffs * undamping;
+ArrayX Ear::StageGValue(const ArrayX& undamping) {
+  ArrayX r = car_coeffs_.r1_coeffs + car_coeffs_.zr_coeffs * undamping;
   return (1 - 2 * 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));