6. Алгоритм std::accumulate
std::accumulat
e на каждом шаге вызывает бинарную функцию. Первым параметром данной функции будет текущее значение части суммы, которая уже была подсчитана на предыдущих шагах, а второй параметр — следующее значение диапазона. Мы выполняем поиск значения сигнала s
в текущей позиции и умножаем его на комплексный множитель, pol
. Затем возвращаем новую частичную сумму. Бинарная функция обернута в j
при каждом вызове алгоритма accumulate
. Поскольку этот алгоритм цикла двумерный, внутреннее лямбда-выражение применяется для внутреннего цикла, а внешнее — для внешнего. auto sum_up ([=, &s] (size_t j) {
return [=, &s] (cmplx c, size_t k) {
return c + s[k] *
polar(1.0, pol * k * j / double(s.size()));
};
});
7. Внутренняя часть преобразования Фурье теперь выполняется алгоритмом std::accumulate
j
, подсчитываем сумму всех слагаемых для позиций auto to_ft ([=, &s](size_t j){
return accumulate(num_iterator{0},
num_iterator{s.size()},
cmplx{},
sum_up(j))
/div;
});
8. До этого момента мы не выполняли код самого преобразования Фурье. Мы лишь подготовили множество вспомогательного кода, который сейчас и задействуем. Вызов std::transform
transform(num_iterator{0}, num_iterator{s.size()},
begin(t), to_ft);
return t;
}
9. Реализуем отдельные функции, которые позволяют создать объекты функций для генерации сигналов. Первая из них представляет собой генератор косинусоидального сигнала. Она возвращает лямбда-выражение, способное сгенерировать косинусоидальный сигнал на основе заданной длины периода. Сам сигнал может иметь произвольную длину, но его длина периода будет фиксированной. Длина периода
static auto gen_cosine (size_t period_len){
return [period_len, n{0}] () mutable {
return cos(double(n++) * 2.0 * M_PI / period_len);
};
}
10. Вторым сигналом будет прямоугольная волна. Она колеблется между значениями –1
+1
и не имеет других значений. Формула выглядит сложной, но она попросту преобразует линейное увеличивающееся значение n
в +1
или –1
, а изменяющаяся длина периода равна period_len
.Обратите внимание: в этот раз мы инициализируем n значением, не равным 0
+1
.static auto gen_square_wave (size_t period_len)
{
return [period_len, n{period_len*7/4}] () mutable {
return ((n++ * 2 / period_len) % 2) * 2 - 1.0;
};
}
11. Сгенерировать сам сигнал с помощью указанных генераторов можно, выделив память для нового вектора и заполнив его значениями, сгенерированными на основе повторяющихся вызовов функции-генератора. Это делает функция std::generate
*it = gen()
. Обернув данный код в функцию, мы легко сможем сгенерировать векторы сигналов.template
static csignal signal_from_generator(size_t len, F gen)
{
csignal r (len);
generate(begin(r), end(r), gen);
return r;
}