首页 > 解决方案 > 智能迭代器同时迭代两个数组并执行返回自定义类型的操作

问题描述

我在 STL 中工作,例如仅标头DSP 库。今天我开始优化一些功能,我必须实现一个估计信号SNR的函数。

如果我们假设我们正在使用零均值信号,则方差等于功率,因此 SNR 是信号方差与噪声方差之比。

信噪比公式

在实践中,我们不知道噪声信号,它会随着时间不断变化。通常,我们可以将噪声近似为您的干净信号与记录信号之间的差异:

在此处输入图像描述

关于库的代码,已经存在估计方差的代码,所以作为第一种方法,我做了这样的事情:

const auto functor = [](const value_type left, const value_type right) {  
    return left - right; 
};

// Allocation of memory, O(N)
std::vector<float> noise(N);
std::transform(std::cbegin(recorded), std::cend(recorded), std::cbegin(signal), std::begin(noise), functor);

const auto var_ref   = statistics::variance(std::cbegin(recorded), std::cend(recorded));
const auto var_noise = statistics::variance(std::cbegin(noise), std::cend(noise));

const auto SNR = converter::pow2db(var_ref / var_noise);

这是实现的要求列表:

该代码违反了其中之一,因为它为噪声信号O(N)空间分配内存。

我确实设法找到了解决方案,但我不确定它是否是最优雅的解决方案。基本上,我zip在python中使用了函数的思想,我创建了一个迭代器,它同时迭代两个数组并在每次访问它时执行一个操作(延迟初始化)。

这是迭代器的代码:

template <class Iter1, class Iter2, class zip_functor>
class zip_iterator {
public:
    using first_type = typename std::iterator_traits<Iter1>::value_type;
    using second_type = typename std::iterator_traits<Iter2>::value_type;
    using iterator_category = std::input_iterator_tag;

    constexpr zip_iterator(Iter1 first1, Iter2 first2, zip_functor&& f) :
        first1_(first1),
        first2_(first2),
        functor_(f) {
    }

    constexpr auto operator !=(const zip_iterator& other) const {
        return this->first1_ != other.first1_ and
               this->first2_ != other.first2_;
    }

    constexpr auto operator ==(const zip_iterator& other) const {
        return this->first1_ == other.first1_ and
               this->first2_ == other.first2_;
    }

    constexpr zip_iterator& operator++() {
        first1_ = std::next(first1_);
        first2_ = std::next(first2_);
        return *this;
    }

    constexpr zip_iterator& operator--() {
        first1_ = std::prev(first1_);
        first2_ = std::prev(first2_);
        return *this;
    }

    constexpr auto operator*() {
        return functor_(*first1_, *first2_);
    }

private:
    Iter1 first1_;
    Iter2 first2_;
    zip_functor functor_;
};

随着新的实现,代码变为:

// Alias of the custom iterator
using first_iter = typename std::array<float, N>::const_iterator;
using second_iter = typename std::array<float, N>::const_iterator;
using zip_iter = zip_iterator<first_iter, second_iter,
        std::function<float(float, float)>>;

// This performs the estimation of the noise in each sample
const auto functor = [](const auto left, const auto right) {
        return left - right;
};

// Estimates the variance of the noise in O(1) space
auto start = zip_iter(std::cbegin(recorded), std::cbegin(signal), functor);
auto end = zip_iter(std::cend(recorded), std::cend(signal), functor);
const auto var_noise = edsp::statistics::variance(start, end);
const auto var_ref = edsp::statistics::variance(std::cbegin(recorded), std::cend(recorded));

const auto SNR = converter::pow2db(var_ref / var_noise);

这段代码符合要求,似乎很容易重用于信号处理中的其他常见应用程序,但我仍然在犹豫这是否是最优雅和最健壮的方式。

所以我的问题是:

有没有更优雅的方法来解决这个问题?任何处理这种情况的参考模式或成语?

标签: c++arraysstlc++14

解决方案


推荐阅读