Shannon entropy per window using Sturges-rule histogram.
376{
377 std::vector<double> out(n_windows);
378 std::vector<size_t> idx(n_windows);
379 std::iota(idx.begin(), idx.end(), 0);
380
381 Parallel::for_each(Parallel::par_unseq, idx.begin(), idx.end(),
382 [&](size_t i) {
383 const size_t start = i * hop_size;
384 auto w = data.subspan(start, std::min<size_t>(window_size, data.size() - start));
385 if (w.empty()) {
386 out[i] = 0.0;
387 return;
388 }
389 size_t bins = num_bins;
390 if (bins == 0) {
391 bins = std::clamp(
392 static_cast<size_t>(std::ceil(std::log2(static_cast<double>(w.size())) + 1.0)),
393 size_t { 1 }, w.size());
394 }
395 const auto [mn, mx] = std::ranges::minmax(w);
396 if (mx <= mn) {
397 out[i] = 0.0;
398 return;
399 }
400 const double bw = (mx - mn) / static_cast<double>(bins);
401 std::vector<size_t> counts(bins, 0);
402 for (double v : w) {
403 auto b =
static_cast<size_t>((v - mn) / bw);
404 counts[std::min(
b, bins - 1)]++;
405 }
406 double e = 0.0;
407 const auto n = static_cast<double>(w.size());
408 for (size_t c : counts) {
409 if (c > 0) {
410 const double p = static_cast<double>(c) / n;
411 e -= p * std::log2(p);
412 }
413 }
414 out[i] = e;
415 });
416
417 return out;
418}