Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 /* | 1 /* |
| 2 * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved. | 2 * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved. |
| 3 * | 3 * |
| 4 * Use of this source code is governed by a BSD-style license | 4 * Use of this source code is governed by a BSD-style license |
| 5 * that can be found in the LICENSE file in the root of the source | 5 * that can be found in the LICENSE file in the root of the source |
| 6 * tree. An additional intellectual property rights grant can be found | 6 * tree. An additional intellectual property rights grant can be found |
| 7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may |
| 8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. |
| 9 */ | 9 */ |
| 10 | 10 |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 22 #include "webrtc/modules/audio_processing/beamformer/covariance_matrix_generator .h" | 22 #include "webrtc/modules/audio_processing/beamformer/covariance_matrix_generator .h" |
| 23 | 23 |
| 24 namespace webrtc { | 24 namespace webrtc { |
| 25 namespace { | 25 namespace { |
| 26 | 26 |
| 27 // Alpha for the Kaiser Bessel Derived window. | 27 // Alpha for the Kaiser Bessel Derived window. |
| 28 const float kKbdAlpha = 1.5f; | 28 const float kKbdAlpha = 1.5f; |
| 29 | 29 |
| 30 const float kSpeedOfSoundMeterSeconds = 343; | 30 const float kSpeedOfSoundMeterSeconds = 343; |
| 31 | 31 |
| 32 // For both target and interference angles, PI / 2 is perpendicular to the | |
| 33 // microphone array, facing forwards. The positive direction goes | |
| 34 // counterclockwise. | |
| 35 // The angle at which we amplify sound. | |
| 36 // TODO(aluebs): Make the target angle dynamically settable. | |
| 37 const float kTargetAngleRadians = static_cast<float>(M_PI) / 2.f; | |
| 38 | |
| 39 // The minimum separation in radians between the target direction and a | 32 // The minimum separation in radians between the target direction and a |
| 40 // interferer scenario. | 33 // interferer scenario. |
| 41 const float kMinAwayRadians = 0.2f; | 34 const float kMinAwayRadians = 0.2f; |
| 42 | 35 |
| 43 // The separation between the target direction and the closest interferer | 36 // The separation between the target direction and the closest interferer |
| 44 // scenario is proportional to this constant. | 37 // scenario is proportional to this constant. |
| 45 const float kAwaySlope = 0.008f; | 38 const float kAwaySlope = 0.008f; |
| 46 | 39 |
| 47 // When calculating the interference covariance matrix, this is the weight for | 40 // When calculating the interference covariance matrix, this is the weight for |
| 48 // the weighted average between the uniform covariance matrix and the angled | 41 // the weighted average between the uniform covariance matrix and the angled |
| (...skipping 143 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 192 for (size_t j = i + 1; j < array_geometry.size(); ++j) { | 185 for (size_t j = i + 1; j < array_geometry.size(); ++j) { |
| 193 float distance = Distance(array_geometry[i], array_geometry[j]); | 186 float distance = Distance(array_geometry[i], array_geometry[j]); |
| 194 if (distance < mic_spacing) { | 187 if (distance < mic_spacing) { |
| 195 mic_spacing = distance; | 188 mic_spacing = distance; |
| 196 } | 189 } |
| 197 } | 190 } |
| 198 } | 191 } |
| 199 return mic_spacing; | 192 return mic_spacing; |
| 200 } | 193 } |
| 201 | 194 |
| 195 float DotProduct(std::vector<float> a, std::vector<float> b) { | |
|
Andrew MacDonald
2015/10/14 22:12:30
const references.
Andrew MacDonald
2015/10/20 03:00:08
Looks like you missed the remainder of the comment
aluebs-webrtc
2015/10/21 01:41:40
I totally missed them, sorry about that. Addressin
aluebs-webrtc
2015/10/21 01:41:40
Done.
| |
| 196 RTC_DCHECK_EQ(a.size(), b.size()); | |
| 197 float dot_product = 0.f; | |
| 198 for (size_t i = 0u; i < a.size(); ++i) { | |
| 199 dot_product += a[i] * b[i]; | |
| 200 } | |
| 201 return dot_product; | |
| 202 } | |
| 203 | |
| 204 float NormalizedDotProduct(std::vector<float> a, std::vector<float> b) { | |
|
Andrew MacDonald
2015/10/14 22:12:31
const references.
aluebs-webrtc
2015/10/21 01:41:40
Removed this function.
| |
| 205 const float kMinNorm = 1e-6f; | |
| 206 float norm_a = DotProduct(a, a); | |
|
Andrew MacDonald
2015/10/14 22:12:30
You're repeatedly computing this for first_pair_di
aluebs-webrtc
2015/10/21 01:41:40
I removed the NormalizedDotProduct and did the nor
| |
| 207 float norm_b = DotProduct(b, b); | |
| 208 if (norm_a > kMinNorm && norm_b > kMinNorm) { | |
| 209 return DotProduct(a, b) / std::sqrt(norm_a * norm_b); | |
| 210 } else { | |
| 211 return 0.f; | |
| 212 } | |
| 213 } | |
| 214 | |
| 215 bool IsGeometryLinear(std::vector<Point> array_geometry) { | |
| 216 const float kMinDotProduct = 0.9999f; | |
| 217 bool is_geometry_linear = true; | |
| 218 std::vector<float> directiona; | |
|
Andrew MacDonald
2015/10/14 22:12:31
first_pair_direction
aluebs-webrtc
2015/10/21 01:41:39
Done.
| |
| 219 directiona.push_back(array_geometry[1].x() - array_geometry[0].x()); | |
| 220 directiona.push_back(array_geometry[1].y() - array_geometry[0].y()); | |
| 221 directiona.push_back(array_geometry[1].z() - array_geometry[0].z()); | |
|
Andrew MacDonald
2015/10/14 22:12:31
Write a helper for this, something like:
std::vect
aluebs-webrtc
2015/10/21 01:41:40
I though about using Point, but I thought it was s
| |
| 222 for (size_t i = 2u; i < array_geometry.size(); ++i) { | |
| 223 std::vector<float> directionb; | |
| 224 directionb.push_back(array_geometry[i].x() - array_geometry[i - 1].x()); | |
|
Andrew MacDonald
2015/10/14 22:12:31
pair_direction
aluebs-webrtc
2015/10/21 01:41:40
Done.
| |
| 225 directionb.push_back(array_geometry[i].y() - array_geometry[i - 1].y()); | |
| 226 directionb.push_back(array_geometry[i].z() - array_geometry[i - 1].z()); | |
| 227 is_geometry_linear &= | |
| 228 std::abs(NormalizedDotProduct(directiona, directionb)) > kMinDotProduct; | |
|
Andrew MacDonald
2015/10/14 22:12:31
Instead, short circuit:
if (std::abs(Normalized
aluebs-webrtc
2015/10/21 01:41:40
I believe that function with only one return state
| |
| 229 } | |
| 230 return is_geometry_linear; | |
| 231 } | |
| 232 | |
| 202 } // namespace | 233 } // namespace |
| 203 | 234 |
| 204 // static | 235 // static |
| 205 const size_t NonlinearBeamformer::kNumFreqBins; | 236 const size_t NonlinearBeamformer::kNumFreqBins; |
| 206 | 237 |
| 207 NonlinearBeamformer::NonlinearBeamformer( | 238 NonlinearBeamformer::NonlinearBeamformer( |
| 208 const std::vector<Point>& array_geometry) | 239 const std::vector<Point>& array_geometry, |
| 240 float target_angle_radians) | |
| 209 : num_input_channels_(array_geometry.size()), | 241 : num_input_channels_(array_geometry.size()), |
| 210 array_geometry_(GetCenteredArray(array_geometry)), | 242 array_geometry_(GetCenteredArray(array_geometry)), |
| 211 mic_spacing_(GetMinimumSpacing(array_geometry)) { | 243 mic_spacing_(GetMinimumSpacing(array_geometry)), |
| 244 target_angle_radians_(target_angle_radians) { | |
| 212 WindowGenerator::KaiserBesselDerived(kKbdAlpha, kFftSize, window_); | 245 WindowGenerator::KaiserBesselDerived(kKbdAlpha, kFftSize, window_); |
| 213 } | 246 } |
| 214 | 247 |
| 215 void NonlinearBeamformer::Initialize(int chunk_size_ms, int sample_rate_hz) { | 248 void NonlinearBeamformer::Initialize(int chunk_size_ms, int sample_rate_hz) { |
| 216 chunk_length_ = | 249 chunk_length_ = |
| 217 static_cast<size_t>(sample_rate_hz / (1000.f / chunk_size_ms)); | 250 static_cast<size_t>(sample_rate_hz / (1000.f / chunk_size_ms)); |
| 218 sample_rate_hz_ = sample_rate_hz; | 251 sample_rate_hz_ = sample_rate_hz; |
| 219 InitFrequencyCorrectionRanges(); | |
| 220 | 252 |
| 221 high_pass_postfilter_mask_ = 1.f; | 253 high_pass_postfilter_mask_ = 1.f; |
| 222 is_target_present_ = false; | 254 is_target_present_ = false; |
| 223 hold_target_blocks_ = kHoldTargetSeconds * 2 * sample_rate_hz / kFftSize; | 255 hold_target_blocks_ = kHoldTargetSeconds * 2 * sample_rate_hz / kFftSize; |
| 224 interference_blocks_count_ = hold_target_blocks_; | 256 interference_blocks_count_ = hold_target_blocks_; |
| 225 | 257 |
| 226 lapped_transform_.reset(new LappedTransform(num_input_channels_, | 258 lapped_transform_.reset(new LappedTransform(num_input_channels_, |
| 227 1, | 259 1, |
| 228 chunk_length_, | 260 chunk_length_, |
| 229 window_, | 261 window_, |
| 230 kFftSize, | 262 kFftSize, |
| 231 kFftSize / 2, | 263 kFftSize / 2, |
| 232 this)); | 264 this)); |
| 233 for (size_t i = 0; i < kNumFreqBins; ++i) { | 265 for (size_t i = 0; i < kNumFreqBins; ++i) { |
| 234 time_smooth_mask_[i] = 1.f; | 266 time_smooth_mask_[i] = 1.f; |
| 235 final_mask_[i] = 1.f; | 267 final_mask_[i] = 1.f; |
| 236 float freq_hz = (static_cast<float>(i) / kFftSize) * sample_rate_hz_; | 268 float freq_hz = (static_cast<float>(i) / kFftSize) * sample_rate_hz_; |
| 237 wave_numbers_[i] = 2 * M_PI * freq_hz / kSpeedOfSoundMeterSeconds; | 269 wave_numbers_[i] = 2 * M_PI * freq_hz / kSpeedOfSoundMeterSeconds; |
| 238 } | 270 } |
| 239 | 271 |
| 240 // Initialize all nonadaptive values before looping through the frames. | 272 InitLowFrequencyCorrectionRanges(); |
| 241 InitInterfAngles(); | 273 InitDifuseCovMats(); |
|
Andrew MacDonald
2015/10/14 22:12:31
Diffuse
aluebs-webrtc
2015/10/21 01:41:40
Done.
| |
| 242 InitDelaySumMasks(); | 274 SteerBeam(target_angle_radians_); |
| 243 InitTargetCovMats(); | |
| 244 InitInterfCovMats(); | |
| 245 | |
| 246 for (size_t i = 0; i < kNumFreqBins; ++i) { | |
| 247 rxiws_[i] = Norm(target_cov_mats_[i], delay_sum_masks_[i]); | |
| 248 rpsiws_[i].clear(); | |
| 249 for (size_t j = 0; j < interf_angles_radians_.size(); ++j) { | |
| 250 rpsiws_[i].push_back(Norm(*interf_cov_mats_[i][j], delay_sum_masks_[i])); | |
| 251 } | |
| 252 } | |
| 253 } | 275 } |
| 254 | 276 |
| 255 void NonlinearBeamformer::InitFrequencyCorrectionRanges() { | 277 // These bin indexes determine the regions over which a mean is taken. This is |
| 278 // applied as a constant value over the adjacent end "frequency correction" | |
| 279 // regions. | |
| 280 // | |
| 281 // low_mean_start_bin_ high_mean_start_bin_ | |
| 282 // v v constant | |
| 283 // |----------------|--------|----------------|-------|----------------| | |
| 284 // constant ^ ^ | |
| 285 // low_mean_end_bin_ high_mean_end_bin_ | |
| 286 // | |
| 287 void NonlinearBeamformer::InitLowFrequencyCorrectionRanges() { | |
| 288 low_mean_start_bin_ = Round(kLowMeanStartHz * kFftSize / sample_rate_hz_); | |
| 289 low_mean_end_bin_ = Round(kLowMeanEndHz * kFftSize / sample_rate_hz_); | |
| 290 | |
| 291 RTC_DCHECK_GT(low_mean_start_bin_, 0U); | |
| 292 RTC_DCHECK_LT(low_mean_start_bin_, low_mean_end_bin_); | |
| 293 } | |
| 294 | |
| 295 void NonlinearBeamformer::InitHighFrequencyCorrectionRanges() { | |
| 256 const float kAliasingFreqHz = | 296 const float kAliasingFreqHz = |
| 257 kSpeedOfSoundMeterSeconds / | 297 kSpeedOfSoundMeterSeconds / |
| 258 (mic_spacing_ * (1.f + std::abs(std::cos(kTargetAngleRadians)))); | 298 (mic_spacing_ * (1.f + std::abs(std::cos(target_angle_radians_)))); |
| 259 const float kHighMeanStartHz = std::min(0.5f * kAliasingFreqHz, | 299 const float kHighMeanStartHz = std::min(0.5f * kAliasingFreqHz, |
| 260 sample_rate_hz_ / 2.f); | 300 sample_rate_hz_ / 2.f); |
| 261 const float kHighMeanEndHz = std::min(0.75f * kAliasingFreqHz, | 301 const float kHighMeanEndHz = std::min(0.75f * kAliasingFreqHz, |
| 262 sample_rate_hz_ / 2.f); | 302 sample_rate_hz_ / 2.f); |
| 263 | |
| 264 low_mean_start_bin_ = Round(kLowMeanStartHz * kFftSize / sample_rate_hz_); | |
| 265 low_mean_end_bin_ = Round(kLowMeanEndHz * kFftSize / sample_rate_hz_); | |
| 266 high_mean_start_bin_ = Round(kHighMeanStartHz * kFftSize / sample_rate_hz_); | 303 high_mean_start_bin_ = Round(kHighMeanStartHz * kFftSize / sample_rate_hz_); |
| 267 high_mean_end_bin_ = Round(kHighMeanEndHz * kFftSize / sample_rate_hz_); | 304 high_mean_end_bin_ = Round(kHighMeanEndHz * kFftSize / sample_rate_hz_); |
| 268 // These bin indexes determine the regions over which a mean is taken. This | 305 |
| 269 // is applied as a constant value over the adjacent end "frequency correction" | |
| 270 // regions. | |
| 271 // | |
| 272 // low_mean_start_bin_ high_mean_start_bin_ | |
| 273 // v v constant | |
| 274 // |----------------|--------|----------------|-------|----------------| | |
| 275 // constant ^ ^ | |
| 276 // low_mean_end_bin_ high_mean_end_bin_ | |
| 277 // | |
| 278 RTC_DCHECK_GT(low_mean_start_bin_, 0U); | |
| 279 RTC_DCHECK_LT(low_mean_start_bin_, low_mean_end_bin_); | |
| 280 RTC_DCHECK_LT(low_mean_end_bin_, high_mean_end_bin_); | 306 RTC_DCHECK_LT(low_mean_end_bin_, high_mean_end_bin_); |
| 281 RTC_DCHECK_LT(high_mean_start_bin_, high_mean_end_bin_); | 307 RTC_DCHECK_LT(high_mean_start_bin_, high_mean_end_bin_); |
| 282 RTC_DCHECK_LT(high_mean_end_bin_, kNumFreqBins - 1); | 308 RTC_DCHECK_LT(high_mean_end_bin_, kNumFreqBins - 1); |
| 283 } | 309 } |
| 284 | 310 |
| 285 | |
| 286 void NonlinearBeamformer::InitInterfAngles() { | 311 void NonlinearBeamformer::InitInterfAngles() { |
| 287 const float kAway = | 312 const float kAway = |
| 288 std::min(static_cast<float>(M_PI), | 313 std::min(static_cast<float>(M_PI), |
| 289 std::max(kMinAwayRadians, | 314 std::max(kMinAwayRadians, |
| 290 kAwaySlope * static_cast<float>(M_PI) / mic_spacing_)); | 315 kAwaySlope * static_cast<float>(M_PI) / mic_spacing_)); |
| 291 | 316 |
| 292 interf_angles_radians_.clear(); | 317 interf_angles_radians_.clear(); |
| 293 // TODO(aluebs): When the target angle is settable, make sure the interferer | 318 if (IsGeometryLinear(array_geometry_)) { |
| 294 // scenarios aren't reflected over the target one for linear geometries. | 319 if (target_angle_radians_ - kAway >= 0.f) { |
|
Andrew MacDonald
2015/10/14 22:12:30
These values depend on the array being parallel wi
aluebs-webrtc
2015/10/21 01:41:40
Great Point. Now I generalized it.
| |
| 295 interf_angles_radians_.push_back(kTargetAngleRadians - kAway); | 320 interf_angles_radians_.push_back(target_angle_radians_ - kAway); |
| 296 interf_angles_radians_.push_back(kTargetAngleRadians + kAway); | 321 } else { |
| 322 interf_angles_radians_.push_back(M_PI); | |
| 323 } | |
| 324 if (target_angle_radians_ + kAway <= M_PI) { | |
| 325 interf_angles_radians_.push_back(target_angle_radians_ + kAway); | |
| 326 } else { | |
| 327 interf_angles_radians_.push_back(0.f); | |
| 328 } | |
| 329 } else { | |
| 330 interf_angles_radians_.push_back(target_angle_radians_ - kAway); | |
| 331 interf_angles_radians_.push_back(target_angle_radians_ + kAway); | |
| 332 } | |
| 297 } | 333 } |
| 298 | 334 |
| 299 void NonlinearBeamformer::InitDelaySumMasks() { | 335 void NonlinearBeamformer::InitDelaySumMasks() { |
| 300 for (size_t f_ix = 0; f_ix < kNumFreqBins; ++f_ix) { | 336 for (size_t f_ix = 0; f_ix < kNumFreqBins; ++f_ix) { |
| 301 delay_sum_masks_[f_ix].Resize(1, num_input_channels_); | 337 delay_sum_masks_[f_ix].Resize(1, num_input_channels_); |
| 302 CovarianceMatrixGenerator::PhaseAlignmentMasks(f_ix, | 338 CovarianceMatrixGenerator::PhaseAlignmentMasks(f_ix, |
| 303 kFftSize, | 339 kFftSize, |
| 304 sample_rate_hz_, | 340 sample_rate_hz_, |
| 305 kSpeedOfSoundMeterSeconds, | 341 kSpeedOfSoundMeterSeconds, |
| 306 array_geometry_, | 342 array_geometry_, |
| 307 kTargetAngleRadians, | 343 target_angle_radians_, |
| 308 &delay_sum_masks_[f_ix]); | 344 &delay_sum_masks_[f_ix]); |
| 309 | 345 |
| 310 complex_f norm_factor = sqrt( | 346 complex_f norm_factor = sqrt( |
| 311 ConjugateDotProduct(delay_sum_masks_[f_ix], delay_sum_masks_[f_ix])); | 347 ConjugateDotProduct(delay_sum_masks_[f_ix], delay_sum_masks_[f_ix])); |
| 312 delay_sum_masks_[f_ix].Scale(1.f / norm_factor); | 348 delay_sum_masks_[f_ix].Scale(1.f / norm_factor); |
| 313 normalized_delay_sum_masks_[f_ix].CopyFrom(delay_sum_masks_[f_ix]); | 349 normalized_delay_sum_masks_[f_ix].CopyFrom(delay_sum_masks_[f_ix]); |
| 314 normalized_delay_sum_masks_[f_ix].Scale(1.f / SumAbs( | 350 normalized_delay_sum_masks_[f_ix].Scale(1.f / SumAbs( |
| 315 normalized_delay_sum_masks_[f_ix])); | 351 normalized_delay_sum_masks_[f_ix])); |
| 316 } | 352 } |
| 317 } | 353 } |
| 318 | 354 |
| 319 void NonlinearBeamformer::InitTargetCovMats() { | 355 void NonlinearBeamformer::InitTargetCovMats() { |
| 320 for (size_t i = 0; i < kNumFreqBins; ++i) { | 356 for (size_t i = 0; i < kNumFreqBins; ++i) { |
| 321 target_cov_mats_[i].Resize(num_input_channels_, num_input_channels_); | 357 target_cov_mats_[i].Resize(num_input_channels_, num_input_channels_); |
| 322 TransposedConjugatedProduct(delay_sum_masks_[i], &target_cov_mats_[i]); | 358 TransposedConjugatedProduct(delay_sum_masks_[i], &target_cov_mats_[i]); |
| 323 } | 359 } |
| 324 } | 360 } |
| 325 | 361 |
| 362 void NonlinearBeamformer::InitDifuseCovMats() { | |
| 363 for (size_t i = 0; i < kNumFreqBins; ++i) { | |
| 364 uniform_cov_mat_[i].Resize(num_input_channels_, num_input_channels_); | |
| 365 CovarianceMatrixGenerator::UniformCovarianceMatrix(wave_numbers_[i], | |
| 366 array_geometry_, | |
| 367 &uniform_cov_mat_[i]); | |
| 368 complex_f normalization_factor = uniform_cov_mat_[i].elements()[0][0]; | |
| 369 uniform_cov_mat_[i].Scale(1.f / normalization_factor); | |
| 370 uniform_cov_mat_[i].Scale(1 - kBalance); | |
| 371 } | |
| 372 } | |
| 373 | |
| 326 void NonlinearBeamformer::InitInterfCovMats() { | 374 void NonlinearBeamformer::InitInterfCovMats() { |
| 327 for (size_t i = 0; i < kNumFreqBins; ++i) { | 375 for (size_t i = 0; i < kNumFreqBins; ++i) { |
| 328 ComplexMatrixF uniform_cov_mat(num_input_channels_, num_input_channels_); | |
| 329 CovarianceMatrixGenerator::UniformCovarianceMatrix(wave_numbers_[i], | |
| 330 array_geometry_, | |
| 331 &uniform_cov_mat); | |
| 332 complex_f normalization_factor = uniform_cov_mat.elements()[0][0]; | |
| 333 uniform_cov_mat.Scale(1.f / normalization_factor); | |
| 334 uniform_cov_mat.Scale(1 - kBalance); | |
| 335 interf_cov_mats_[i].clear(); | 376 interf_cov_mats_[i].clear(); |
| 336 for (size_t j = 0; j < interf_angles_radians_.size(); ++j) { | 377 for (size_t j = 0; j < interf_angles_radians_.size(); ++j) { |
| 337 interf_cov_mats_[i].push_back(new ComplexMatrixF(num_input_channels_, | 378 interf_cov_mats_[i].push_back(new ComplexMatrixF(num_input_channels_, |
| 338 num_input_channels_)); | 379 num_input_channels_)); |
| 339 ComplexMatrixF angled_cov_mat(num_input_channels_, num_input_channels_); | 380 ComplexMatrixF angled_cov_mat(num_input_channels_, num_input_channels_); |
| 340 CovarianceMatrixGenerator::AngledCovarianceMatrix( | 381 CovarianceMatrixGenerator::AngledCovarianceMatrix( |
| 341 kSpeedOfSoundMeterSeconds, | 382 kSpeedOfSoundMeterSeconds, |
| 342 interf_angles_radians_[j], | 383 interf_angles_radians_[j], |
| 343 i, | 384 i, |
| 344 kFftSize, | 385 kFftSize, |
| 345 kNumFreqBins, | 386 kNumFreqBins, |
| 346 sample_rate_hz_, | 387 sample_rate_hz_, |
| 347 array_geometry_, | 388 array_geometry_, |
| 348 &angled_cov_mat); | 389 &angled_cov_mat); |
| 349 // Normalize matrices before averaging them. | 390 // Normalize matrices before averaging them. |
| 350 normalization_factor = angled_cov_mat.elements()[0][0]; | 391 complex_f normalization_factor = angled_cov_mat.elements()[0][0]; |
| 351 angled_cov_mat.Scale(1.f / normalization_factor); | 392 angled_cov_mat.Scale(1.f / normalization_factor); |
| 352 // Weighted average of matrices. | 393 // Weighted average of matrices. |
| 353 angled_cov_mat.Scale(kBalance); | 394 angled_cov_mat.Scale(kBalance); |
| 354 interf_cov_mats_[i][j]->Add(uniform_cov_mat, angled_cov_mat); | 395 interf_cov_mats_[i][j]->Add(uniform_cov_mat_[i], angled_cov_mat); |
| 355 } | 396 } |
| 356 } | 397 } |
| 357 } | 398 } |
| 399 | |
| 400 void NonlinearBeamformer::NormalizeCovMats() { | |
| 401 for (size_t i = 0; i < kNumFreqBins; ++i) { | |
| 402 rxiws_[i] = Norm(target_cov_mats_[i], delay_sum_masks_[i]); | |
| 403 rpsiws_[i].clear(); | |
| 404 for (size_t j = 0; j < interf_angles_radians_.size(); ++j) { | |
| 405 rpsiws_[i].push_back(Norm(*interf_cov_mats_[i][j], delay_sum_masks_[i])); | |
| 406 } | |
| 407 } | |
| 408 } | |
| 358 | 409 |
| 359 void NonlinearBeamformer::ProcessChunk(const ChannelBuffer<float>& input, | 410 void NonlinearBeamformer::ProcessChunk(const ChannelBuffer<float>& input, |
| 360 ChannelBuffer<float>* output) { | 411 ChannelBuffer<float>* output) { |
| 361 RTC_DCHECK_EQ(input.num_channels(), num_input_channels_); | 412 RTC_DCHECK_EQ(input.num_channels(), num_input_channels_); |
| 362 RTC_DCHECK_EQ(input.num_frames_per_band(), chunk_length_); | 413 RTC_DCHECK_EQ(input.num_frames_per_band(), chunk_length_); |
| 363 | 414 |
| 364 float old_high_pass_mask = high_pass_postfilter_mask_; | 415 float old_high_pass_mask = high_pass_postfilter_mask_; |
| 365 lapped_transform_->ProcessChunk(input.channels(0), output->channels(0)); | 416 lapped_transform_->ProcessChunk(input.channels(0), output->channels(0)); |
| 366 // Ramp up/down for smoothing. 1 mask per 10ms results in audible | 417 // Ramp up/down for smoothing. 1 mask per 10ms results in audible |
| 367 // discontinuities. | 418 // discontinuities. |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 379 // averaging). | 430 // averaging). |
| 380 float sum = 0.f; | 431 float sum = 0.f; |
| 381 for (int k = 0; k < input.num_channels(); ++k) { | 432 for (int k = 0; k < input.num_channels(); ++k) { |
| 382 sum += input.channels(i)[k][j]; | 433 sum += input.channels(i)[k][j]; |
| 383 } | 434 } |
| 384 output->channels(i)[0][j] = sum / input.num_channels() * smoothed_mask; | 435 output->channels(i)[0][j] = sum / input.num_channels() * smoothed_mask; |
| 385 } | 436 } |
| 386 } | 437 } |
| 387 } | 438 } |
| 388 | 439 |
| 440 void NonlinearBeamformer::SteerBeam(float target_angle_radians) { | |
| 441 target_angle_radians_ = target_angle_radians; | |
| 442 InitHighFrequencyCorrectionRanges(); | |
| 443 InitInterfAngles(); | |
| 444 InitDelaySumMasks(); | |
| 445 InitTargetCovMats(); | |
| 446 InitInterfCovMats(); | |
| 447 NormalizeCovMats(); | |
| 448 } | |
| 449 | |
| 389 bool NonlinearBeamformer::IsInBeam(const SphericalPointf& spherical_point) { | 450 bool NonlinearBeamformer::IsInBeam(const SphericalPointf& spherical_point) { |
| 390 // If more than half-beamwidth degrees away from the beam's center, | 451 // If more than half-beamwidth degrees away from the beam's center, |
| 391 // you are out of the beam. | 452 // you are out of the beam. |
| 392 return fabs(spherical_point.azimuth() - kTargetAngleRadians) < | 453 return fabs(spherical_point.azimuth() - target_angle_radians_) < |
| 393 kHalfBeamWidthRadians; | 454 kHalfBeamWidthRadians; |
| 394 } | 455 } |
| 395 | 456 |
| 396 void NonlinearBeamformer::ProcessAudioBlock(const complex_f* const* input, | 457 void NonlinearBeamformer::ProcessAudioBlock(const complex_f* const* input, |
| 397 int num_input_channels, | 458 int num_input_channels, |
| 398 size_t num_freq_bins, | 459 size_t num_freq_bins, |
| 399 int num_output_channels, | 460 int num_output_channels, |
| 400 complex_f* const* output) { | 461 complex_f* const* output) { |
| 401 RTC_CHECK_EQ(num_freq_bins, kNumFreqBins); | 462 RTC_CHECK_EQ(num_freq_bins, kNumFreqBins); |
| 402 RTC_CHECK_EQ(num_input_channels, num_input_channels_); | 463 RTC_CHECK_EQ(num_input_channels, num_input_channels_); |
| (...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 547 new_mask_ + high_mean_end_bin_ + 1); | 608 new_mask_ + high_mean_end_bin_ + 1); |
| 548 if (new_mask_[quantile] > kMaskTargetThreshold) { | 609 if (new_mask_[quantile] > kMaskTargetThreshold) { |
| 549 is_target_present_ = true; | 610 is_target_present_ = true; |
| 550 interference_blocks_count_ = 0; | 611 interference_blocks_count_ = 0; |
| 551 } else { | 612 } else { |
| 552 is_target_present_ = interference_blocks_count_++ < hold_target_blocks_; | 613 is_target_present_ = interference_blocks_count_++ < hold_target_blocks_; |
| 553 } | 614 } |
| 554 } | 615 } |
| 555 | 616 |
| 556 } // namespace webrtc | 617 } // namespace webrtc |
| OLD | NEW |