Алгоритм быстрого преобразования Фурье: от теории к графам

Курс посвящен детальному изучению алгоритма Кули-Тьюки, переходу от ДПФ к БПФ и методике построения графов потоков данных («бабочек») для подготовки к контрольной работе.

1. Математические основы: переход от ДПФ к БПФ

Математические основы: переход от ДПФ к БПФ

Представьте, что вам нужно обработать аудиосигнал длительностью всего в одну секунду, оцифрованный с частотой 44100 Гц. Если использовать стандартное определение дискретного преобразования Фурье (ДПФ), компьютеру придется выполнить около двух миллиардов операций умножения. Для мобильного телефона или встраиваемого процессора это непосильная задача, которая превратит воспроизведение музыки в бесконечное ожидание. Именно здесь на сцену выходит быстрое преобразование Фурье (БПФ) — алгоритм, который не просто ускоряет вычисления, а меняет саму сложность задачи с квадратичной на логарифмическую.

Сущность дискретного преобразования Фурье

Прежде чем ускорять процесс, необходимо зафиксировать «точку старта». Дискретное преобразование Фурье — это математический инструмент, который переводит сигнал из временной области (где мы видим амплитуду в каждый момент времени) в частотную область (где мы видим, из каких синусоид состоит этот сигнал). Математически ДПФ для последовательности из комплексных чисел определяется как:

Здесь — спектральные коэффициенты, а — это комплексный экспоненциальный множитель, называемый поворачивающим коэффициентом (twiddle factor). Он определяется формулой:

Поворачивающий коэффициент представляет собой вектор на комплексной плоскости, который вращается по единичной окружности. При вычислении одного значения нам нужно выполнить комплексных умножений и комплексных сложений. Поскольку нам нужно найти таких значений (от до ), общая сложность составляет операций.

> Инсайт: Квадратичная сложность означает, что при увеличении объема данных в 10 раз время вычислений вырастет в 100 раз. Это «вычислительный тупик» для систем реального времени.

Вычислительная избыточность и симметрия

Почему ДПФ работает так медленно? Ответ кроется в избыточности. Посмотрите на множитель . Из-за периодичности тригонометрических функций многие значения этого множителя повторяются. Например, . Существует также свойство симметрии:

Это означает, что половина вычислений в обычном ДПФ — это просто повторение уже найденных значений с противоположным знаком. Если мы найдем способ переиспользовать результаты промежуточных вычислений, мы сможем радикально сократить нагрузку на процессор. Именно на этом принципе основан алгоритм Кули-Тьюки, предложенный в 1965 году, хотя зачатки этой идеи встречались еще в трудах Гаусса.

Рассмотрим пример с . Для вычисления по определению нам нужно 16 умножений. Однако . Заметьте, что — это просто . Если мы правильно сгруппируем слагаемые, нам не придется умножать на отдельно, достаточно просто вычесть результат, полученный для .

Стратегия «Разделяй и властвуй»

Основная идея перехода от ДПФ к БПФ заключается в рекурсивном разбиении одной большой задачи размерностью на несколько задач меньшей размерности. Если — четное число, мы можем разделить исходную последовательность на две части: одну с четными индексами () и одну с нечетными ().

Подставим это разделение в формулу ДПФ:

Заметим, что . Это ключевой момент: сумма для четных индексов превращается в ДПФ размерностью . Аналогично поступим со второй суммой, вынеся общий множитель :

Обозначим первую сумму как , а вторую как . Обе они являются ДПФ длиной . Теперь расчет выглядит так:

Поскольку и периодичны с периодом , для второй половины спектра () формула примет вид:

Это и есть знаменитая структура «бабочка». Вместо операций мы теперь тратим около . Для разница колоссальная: вместо миллиона операций нам потребуется всего около десяти тысяч.

Пошаговый разбор перехода для N=4

Давайте проследим, как математика превращается в алгоритм на конкретных числах. Пусть у нас есть сигнал .

Шаг 1: Разделение на четные и нечетные. Формируем две последовательности длиной 2:

  • Четные:
  • Нечетные:
  • Шаг 2: Вычисление ДПФ для малых последовательностей. Для формулы предельно просты, так как и :

    Шаг 3: Объединение результатов (Синтез). Используем поворачивающие коэффициенты и :

    В этом процессе мы выполнили всего 4 комплексных умножения (на самом деле меньше, так как умножение на 1 тривиально). По определению нам бы понадобилось 16. Экономия очевидна даже на таком малом масштабе.

    Анализ вычислительной эффективности

    Чтобы понять, почему БПФ — это стандарт индустрии, сравним количество операций. В классическом ДПФ количество комплексных умножений , а сложений .

    В БПФ по основанию 2 (когда — степень двойки) количество этапов деления равно . На каждом этапе выполняется операций типа «бабочка». Каждая «бабочка» требует одного комплексного умножения и двух сложений.

    | N (точек) | Умножений ДПФ () | Умножений БПФ () | Ускорение (раз) | | :--- | :--- | :--- | :--- | | 16 | 256 | 32 | 8 | | 256 | 65 536 | 1 024 | 64 | | 1024 | 1 048 576 | 5 120 | 204 | | 4096 | 16 777 216 | 24 576 | 682 |

    Важно понимать, что комплексное умножение — самая «дорогая» операция для процессора. Оно состоит из четырех умножений вещественных чисел и двух сложений. Сокращая количество комплексных умножений, мы напрямую снижаем энергопотребление устройства и время отклика системы.

    Часто возникает вопрос: а что если не является степенью двойки? В таких случаях используют алгоритм Кули-Тьюки для смешанных оснований. Если , мы можем представить данные в виде матрицы , выполнить ДПФ по строкам, умножить на промежуточные коэффициенты и выполнить ДПФ по столбцам. Это обобщение позволяет эффективно вычислять БПФ для любых составных чисел, например, или .

    Если из этой главы запомнить три вещи — это: БПФ не меняет результат ДПФ, а лишь устраняет избыточность; ключевым механизмом является рекурсивное разделение сигнала на четные и нечетные отсчеты; математическая магия происходит в момент переиспользования результатов и для вычисления двух разных коэффициентов спектра одновременно.

    2. Алгоритмы Кули-Тьюки: методы прореживания по времени и частоте

    Алгоритмы Кули-Тьюки: методы прореживания по времени и частоте

    В предыдущей главе мы увидели, как математическое разделение суммы ДПФ на две части позволяет сократить количество вычислений. Однако на практике алгоритм Кули-Тьюки реализуется в двух принципиально разных формах: прореживание по времени (Decimation-in-Time, DIT) и прореживание по частоте (Decimation-in-Frequency, DIF). Несмотря на то что оба метода приводят к одному и тому же результату и имеют одинаковую сложность , их внутренняя логика и структура графов различаются. Понимание этих различий критически важно для проектирования эффективных цифровых устройств.

    Прореживание по времени (DIT)

    Метод прореживания по времени — это именно тот подход, который мы начали разбирать в основах. Здесь мы разделяем входную последовательность на подпоследовательности. Если мы работаем по основанию 2, мы делим сигнал на «четную» и «нечетную» части.

    Представьте, что у вас есть ряд данных. Вы берете каждый второй элемент и формируете из них новый массив. Затем из оставшихся элементов — еще один. Этот процесс повторяется рекурсивно, пока мы не дойдем до двухточечных блоков.

    Ключевая особенность DIT заключается в том, что умножение на поворачивающий коэффициент происходит до сложения в структуре «бабочки». Формула «бабочки» для DIT выглядит так: 1. 2.

    Здесь — результат из «четной» ветки, а — из «нечетной». Обратите внимание: входные данные для DIT-алгоритма должны подаваться в специальном, «перетасованном» порядке (двоично-инверсная перестановка), чтобы на выходе мы получили спектр в естественном порядке. Если вы подадите на вход DIT-графа, на выходе вы получите хаос. Чтобы получить , на вход нужно подать .

    Прореживание по частоте (DIF)

    Метод прореживания по частоте работает «от обратного». Вместо того чтобы разделять входные отсчеты на четные и нечетные, мы разделяем выходные коэффициенты спектра .

    В DIF мы сначала берем первую половину входного сигнала и вторую половину, комбинируем их, а затем уже применяем поворачивающие коэффициенты. Формула «бабочки» для DIF: 1. 2.

    > Важное отличие: В DIF-алгоритме умножение на выполняется после сложения/вычитания.

    Это приводит к зеркальной ситуации с порядком данных. В DIF-алгоритме входные данные подаются в естественном порядке (), но на выходе коэффициенты спектра оказываются в двоично-инверсном порядке.

    | Характеристика | Прореживание по времени (DIT) | Прореживание по частоте (DIF) | | :--- | :--- | :--- | | Разделение | Входной сигнал (четные/нечетные) | Выходной спектр (четные/нечетные) | | Умножение на | До сложения («бабочка» на входе) | После сложения («бабочка» на выходе) | | Входной порядок | Двоично-инверсный | Естественный | | Выходной порядок | Естественный | Двоично-инверсный |

    Алгоритм для составных N (Случай N = N1 * N2)

    Алгоритм Кули-Тьюки не ограничен только степенями двойки. В инженерной практике часто встречаются задачи, где . В этом случае мы используем факторизацию. Пусть . Мы можем представить одномерный массив данных как двумерную таблицу.

    Например, для и разбиения :

  • Записываем данные в таблицу .
  • Вычисляем 4 ДПФ по 5 точек каждое (строки).
  • Умножаем каждый элемент на специфический поворачивающий коэффициент .
  • Вычисляем 5 ДПФ по 4 точки каждое (столбцы).
  • Этот метод позволяет использовать БПФ даже тогда, когда длина сигнала не «идеальна». Если — это степень двойки (например, 4 или 8), мы можем применить быстрый алгоритм с «бабочками» для этого этапа, а для использовать обычное ДПФ или алгоритм Винограда.

    Пошаговый разбор вычисления для N=20 (N1=4, N2=5)

    Рассмотрим, как распределяются операции в смешанном алгоритме. Это классическая задача из контрольных работ.

    Шаг 1: Индексация. Мы представляем индекс как . Для : , где . Это значит, что в первую строку таблицы попадут элементы .

    Шаг 2: Внутренние ДПФ. Вычисляем 4 блока ДПФ по 5 точек. Количество умножений здесь: . Количество сложений: .

    Шаг 3: Поворачивающие множители. После первого этапа каждый элемент умножается на . Всего 20 элементов, но умножений меньше, так как при или множитель равен 1.

    Шаг 4: Внешние ДПФ. Вычисляем 5 блоков ДПФ по 4 точки. Если 4-точечное ДПФ делать методом БПФ (через «бабочки»), то на каждый блок уйдет всего 4 умножения. Итого: умножений.

    Итоговый расчет: Суммарно для мы получили около 140 комплексных умножений. В обычном ДПФ их было бы . Эффективность выросла почти в 3 раза.

    Двоично-инверсная перестановка (Bit-Reversal)

    Почему в DIT-алгоритме данные «перепутываются»? Это следствие многократного разделения на четные и нечетные индексы. Возьмем . Индексы в двоичном виде: 0 (000), 1 (001), 2 (010), 3 (011), 4 (100), 5 (101), 6 (110), 7 (111).

    После первого разделения на чет/нечет: Группа А (четные): 0, 2, 4, 6. Группа Б (нечетные): 1, 3, 5, 7.

    После второго разделения группы А: А1 (четные от А): 0, 4. А2 (нечетные от А): 2, 6.

    Если мы запишем финальный порядок: 0, 4, 2, 6, 1, 5, 3, 7. А теперь посмотрим на их двоичные индексы «задом наперед»: 0 (000) 000 (0) 4 (100) 001 (1) 2 (010) 010 (2) 6 (110) 011 (3) Это и есть двоичная инверсия. Программная реализация БПФ часто начинается именно с этой перестановки массива, чтобы затем выполнять вычисления «на месте» (in-place), не создавая копий данных.

    Если из этой главы запомнить три вещи — это: DIT требует перепутанного входа, но дает ровный выход; DIF принимает ровный вход, но выдает перепутанный спектр; для любого составного можно построить БПФ, разбив его на множители и используя промежуточные поворачивающие коэффициенты.

    3. Графы вычислений и топология структуры «бабочки»

    Графы вычислений и топология структуры «бабочки»

    Граф алгоритма БПФ — это не просто красивая схема, это «дорожная карта» данных. Для инженера умение читать и рисовать такой граф равносильно умению читать электрические схемы. Граф показывает, как входные числа перемещаются, где они складываются, а где умножаются на коэффициенты. В этой главе мы разберем анатомию графа БПФ, научимся строить его для разных и поймем, почему базовая операция получила название «бабочка».

    Анатомия «бабочки»

    «Бабочка» — это элементарный кирпичик, из которого строится всё здание БПФ. Свое название она получила из-за характерного перекрестия линий на схеме.

    В методе прореживания по времени (DIT) «бабочка» имеет два входа () и два выхода ().

  • Вход идет на верхний и нижний выходы без изменений.
  • Вход сначала умножается на поворачивающий коэффициент .
  • На верхнем выходе получается сумма: .
  • На нижнем выходе получается разность: .
  • На графе это рисуется так: две горизонтальные линии, соединенные крест-накрест. Точка соединения линий означает операцию сложения. Наклонная линия, идущая снизу вверх, обычно несет на себе множитель , а линия, идущая сверху вниз, часто помечается знаком «минус» (или ) перед узлом сложения.

    > Важный нюанс: В современных реализациях часто используют «оптимизированную бабочку», где умножение на заменяется просто вычитанием в АЛУ процессора, что экономит один цикл вычислений.

    Топология графа для N=8

    Построение графа для всегда подчиняется строгому порядку. Количество каскадов (этапов) графа равно . Для у нас будет 3 каскада.

  • Первый каскад: Состоит из 4 маленьких «бабочек» размером 2. Они соединяют соседние элементы (после bit-reversal перестановки). Здесь используются только простейшие коэффициенты .
  • Второй каскад: Состоит из 2 «бабочек» размером 4. Каждая такая бабочка соединяет элементы через один. Коэффициенты здесь — и .
  • Третий каскад: Одна гигантская «бабочка» размером 8, соединяющая верхнюю четверку элементов с нижней четверкой. Здесь используются коэффициенты .
  • Расстояние между «крыльями» бабочки на каждом этапе удваивается: 1 2 4. Это свойство позволяет очень легко программировать циклы в алгоритме: внешний цикл идет по каскадам, средний — по группам бабочек, внутренний — по самим бабочкам внутри группы.

    Построение графа для составного N=6 (2 x 3)

    Когда не является степенью двойки, граф становится асимметричным, но сохраняет логику слоев. Рассмотрим , разложенное как (БПФ-часть) и (ДПФ-часть).

    Этап 1: ДПФ-3. Мы делим 6 точек на две группы по 3 точки (например, четные и нечетные). Для каждой тройки рисуем блок 3-точечного ДПФ. Внутри этого блока каждая точка соединяется со всеми тремя выходами. Это уже не «бабочка», а «звезда» или полный граф .

    Этап 2: Поворачивающие множители. На линиях, выходящих из второй группы (нечетной), ставятся множители .

    Этап 3: БПФ-2. Теперь мы соединяем соответствующие выходы первой и второй групп парами, образуя обычные 2-точечные «бабочки».

  • Выход 0 первой группы соединяется с выходом 0 второй группы.
  • Выход 1 первой — с выходом 1 второй, и так далее.
  • В итоге получается структура, где сначала идут «плотные» узлы ДПФ, а затем — разреженные линии объединения.

    Правила отрисовки графа на контрольной работе

    Если вам нужно нарисовать граф БПФ вручную, следуйте этому алгоритму, чтобы не запутаться:

  • Определите количество точек и тип прореживания. Если DIT — пишите входные данные в bit-reversal порядке (). Если DIF — пишите по порядку.
  • Нарисуйте горизонтальных линий. Это оси времени/частоты.
  • Разбейте на каскады. Проведите вертикальные пунктирные линии, разделяющие этапы.
  • Расставьте коэффициенты. Помните, что в DIT коэффициенты стоят перед узлом бабочки (слева), а в DIF — после (справа).
  • Проверьте знаки. В нижней ветви каждой бабочки всегда должен быть минус перед сумматором.
  • Пример ошибки: часто забывают, что в DIT-алгоритме для на втором каскаде коэффициенты повторяются дважды (для верхней четверки и для нижней), а не идут сплошным списком . Сплошной список — это прерогатива только последнего каскада.

    Геометрия данных и In-place вычисления

    Граф БПФ обладает уникальным свойством: для вычисления пары значений на выходе каскада нужны только два значения с того же места на входе. Это значит, что нам не нужен дополнительный массив памяти. Мы берем и , считаем их «бабочку» и записываем результат обратно в те же ячейки и .

    На графе это выглядит как идеальная симметрия. Если вы видите, что линии одного каскада пересекаются с линиями другого хаотично — значит, в топологии ошибка. В правильном графе зоны влияния бабочек всегда локализованы внутри своих блоков.

    Если из этой главы запомнить три вещи — это: «бабочка» — это сумма и разность с умножением; в DIT-графе расстояние между узлами бабочки растет от каскада к каскаду; умение строить граф для смешанных оснований (например, ) требует понимания того, как блоки ДПФ меньшего порядка вкладываются в общую структуру.

    4. Оптимизация вычислений и принципы программной реализации

    Оптимизация вычислений и принципы программной реализации

    Знать математику БПФ и уметь рисовать графы — это лишь половина дела. Когда дело доходит до написания кода, который должен работать на реальном процессоре, возникают новые вызовы. Как избежать лишних вычислений синусов и косинусов? Как эффективно использовать кэш-память? В этой главе мы разберем «кухню» оптимизации БПФ, которая превращает теоретический алгоритм в высокопроизводительный инструмент.

    Табличная оптимизация (Look-up Tables)

    Самая дорогая операция в БПФ — это не само умножение, а вычисление поворачивающих коэффициентов . Если вы будете вызывать функции sin() и cos() внутри циклов БПФ, ваш алгоритм будет работать медленнее, чем обычное ДПФ.

    Профессиональные реализации используют таблицы предвычисленных значений (Look-up Tables, LUT). Перед началом работы алгоритма все необходимые значения вычисляются один раз и сохраняются в памяти.

  • Для нам нужно хранить всего 512 комплексных чисел (так как используется только половина окружности).
  • Благодаря свойствам симметрии (), размер таблицы можно сократить еще в два-четыре раза.
  • > Пример: Для вычисления нам не нужно считать косинус. Мы знаем, что это повернутый на 90 градусов, что соответствует значению .

    Эффективная реализация Bit-Reversal

    Перестановка данных в двоично-инверсном порядке — слабое место многих новичков. Наивный алгоритм с переводом числа в строку, реверсом строки и переводом обратно работает крайне медленно. В программной инженерии используются быстрые алгоритмы «инверсии битов». Один из самых популярных — алгоритм Голдстайна-Ридера, который использует инкремент с переносом бита влево вместо вправо.

    На современных процессорах (например, ARM или DSP) существуют специальные инструкции или режимы адресации, которые выполняют bit-reversal аппаратно за ноль тактов. Если же вы пишете на C++, часто выгоднее один раз создать таблицу индексов перестановки, если размер фиксирован.

    Оптимизация «бабочки» и вещественные данные

    В классическом БПФ мы работаем с комплексными числами. Каждое комплексное умножение требует 4 вещественных умножения и 2 сложения. Однако в большинстве реальных задач (звук, датчики) входной сигнал является чисто вещественным.

    Если мы просто подставим вещественные числа в комплексное БПФ, мы будем тратить половину ресурсов впустую (мнимая часть будет заполнена нулями). Существует два способа оптимизации:

  • Упаковка двух вещественных сигналов в один комплексный. Мы кладем первый сигнал в вещественную часть, а второй — в мнимую. После одного прохода БПФ мы разделяем результаты с помощью свойств симметрии.
  • Специализированное вещественное БПФ (Real FFT). Оно использует тот факт, что спектр вещественного сигнала симметричен (), и вычисляет только половину коэффициентов, работая почти в два раза быстрее.
  • Проблема кэш-памяти (Cache-oblivious FFT)

    При очень больших (миллионы точек) данные перестают помещаться в кэш процессора. Когда алгоритм БПФ начинает обращаться к элементам, которые находятся далеко друг от друга (например, на последнем каскаде), процессор постоянно простаивает, ожидая данных из медленной оперативной памяти.

    Для решения этой проблемы применяют блочные алгоритмы. Вместо того чтобы проходить весь каскад целиком, мы разбиваем данные на блоки, которые целиком помещаются в кэш L1/L2, обрабатываем их, а затем объединяем. Алгоритм Кули-Тьюки идеально подходит для этого благодаря своей рекурсивной природе.

    Пошаговая структура кода (псевдокод)

    Типичная программная реализация БПФ по основанию 2 выглядит так:

    В этом коде критически важно вынести w *= wm или использование LUT во внутренний цикл правильно, чтобы избежать лишних вычислений.

    Если из этой главы запомнить три вещи — это: никогда не считайте синусы внутри БПФ (пользуйтесь таблицами); для вещественных сигналов используйте специальные версии алгоритма, чтобы сэкономить 50% времени; при написании кода всегда стремитесь к вычислениям «на месте», чтобы экономить память и кэш.

    5. Практикум: проектирование алгоритмов и решение типовых задач

    Практикум: проектирование алгоритмов и решение типовых задач

    Мы прошли путь от абстрактных сумм Фурье до оптимизированного программного кода. Теперь пришло время применить все эти знания для решения конкретных инженерных задач, которые часто встречаются в контрольных работах и реальном проектировании. Мы разберем, как спроектировать БПФ для «неудобных» чисел и как правильно подсчитать количество операций, чтобы доказать эффективность выбранного метода.

    Задача 1: Проектирование для N=24

    Допустим, нам нужно построить алгоритм БПФ для 24 точек. Число 24 не является степенью двойки, поэтому чистый алгоритм «бабочки» здесь не применим.

    Шаг 1: Факторизация. Разложим 24 на множители. Оптимальный вариант — . Почему именно так? Потому что для 8 точек мы можем использовать максимально эффективный 3-каскадный граф с «бабочками», а для 3 точек применить прямое ДПФ.

    Шаг 2: Выбор вида прореживания. Пусть по заданию нам нужно прореживание по времени (DIT). Это значит:

  • Формируем таблицу .
  • Входные данные записываем так: . Первая строка: .
  • Вычисляем 8 ДПФ по 3 точки.
  • Умножаем на поворачивающие коэффициенты .
  • Вычисляем 3 БПФ по 8 точек (каждое — 3 каскада «бабочек»).
  • Шаг 3: Подсчет операций.

  • Для 3-точечного ДПФ: . Всего 8 таких блоков .
  • Поворачивающие множители: 24 умножения.
  • Для 8-точечного БПФ: . Всего 3 таких блока .
  • Итого: 132 комплексных умножения. (Для сравнения: обычное ДПФ-24 потребовало бы ).
  • Задача 2: Анализ эффективности для N=640

    Это типичная задача повышенной сложности. можно разложить как . В свою очередь . Таким образом, структура алгоритма будет иерархической:

  • Внешний слой: .
  • Внутренний слой для 40: .
  • Здесь важно уметь строить «вложенные» оценки. Сначала мы считаем сложность 5-точечного блока, затем 8-точечного, объединяем их в 40-точечный и только потом выходим на уровень 640. Такой подход называется алгоритмом смешанного основания (Mixed-radix FFT).

    Как не ошибиться в расчетах операций

    При подсчете количества операций в БПФ (особенно в контрольных) студенты часто путают комплексные и вещественные операции. Запомните золотое правило: если не указано иное, считаем комплексные операции.

  • Комплексное умножение (M): В «бабочке» DIT оно одно. В ДПФ-N их .
  • Комплексное сложение (A): В «бабочке» их два (сумма и разность). В ДПФ-N их .
  • Если вы используете алгоритм Кули-Тьюки для , общая формула сложности:

    (Примечание: в умножениях — это поворачивающие коэффициенты между этапами).

    Построение графа «на лету» для N=12 (4 x 3)

    Если на экзамене вас просят нарисовать граф для , не паникуйте.

  • Нарисуйте 12 линий.
  • Сгруппируйте их в 4 блока по 3 линии. В каждом блоке нарисуйте «звезду» 3-точечного ДПФ.
  • На каждой линии поставьте индекс .
  • После этого объедините линии из разных блоков в 4-точечные БПФ. 4-точечное БПФ — это два каскада обычных «бабочек».
  • Такая визуализация сразу показывает преподавателю, что вы понимаете иерархию алгоритма, а не просто зазубрили схему для .

    Заключительные рекомендации по применению

    Алгоритм БПФ — это фундамент современной цивилизации. Он работает в вашем смартфоне, когда тот ловит 4G/5G сигнал (технология OFDM напрямую основана на БПФ), он работает в МРТ-сканерах и в системах сжатия изображений JPEG.

    Если из этого курса вы запомните три вещи — это: БПФ — это не магия, а математическое устранение избыточности; граф «бабочки» — это визуальный код алгоритма; а выбор правильной стратегии разбиения (факторизации) позволяет эффективно обрабатывать сигналы любой длины, экономя колоссальное количество энергии и времени.