Median absolute deviation per window.
502{
503 std::vector<double> out(n_windows);
504 std::vector<size_t> idx(n_windows);
505 std::iota(idx.begin(), idx.end(), 0);
506
507 Parallel::for_each(Parallel::par_unseq, idx.begin(), idx.end(),
508 [&](size_t i) {
509 const size_t start = i * hop_size;
510 auto w = data.subspan(start, std::min<size_t>(window_size, data.size() - start));
511 if (w.empty()) {
512 out[i] = 0.0;
513 return;
514 }
515 std::vector<double> buf(w.begin(), w.end());
516 const size_t mid = buf.size() / 2;
517 std::nth_element(buf.begin(), buf.begin() + static_cast<ptrdiff_t>(mid), buf.end());
518 const double med = (buf.size() % 2 != 0)
519 ? buf[mid]
520 : [&] {
521 const double upper = buf[mid];
522 std::nth_element(buf.begin(), buf.begin() + static_cast<ptrdiff_t>(mid - 1), buf.begin() + static_cast<ptrdiff_t>(mid));
523 return (buf[mid - 1] + upper) / 2.0;
524 }();
525
526 std::vector<double> dev;
527 dev.reserve(w.size());
528 for (double v : w)
529 dev.push_back(
std::abs(v - med));
530
531 const size_t dm = dev.size() / 2;
532 std::nth_element(dev.begin(), dev.begin() + static_cast<ptrdiff_t>(dm), dev.end());
533 out[i] = (dev.size() % 2 != 0)
534 ? dev[dm]
535 : [&] {
536 const double upper = dev[dm];
537 std::nth_element(dev.begin(), dev.begin() + static_cast<ptrdiff_t>(dm - 1), dev.begin() + static_cast<ptrdiff_t>(dm));
538 return (dev[dm - 1] + upper) / 2.0;
539 }();
540 });
541
542 return out;
543}