Этот ответ состоит из нескольких частей. Я основываю этот ответ на характеристиках алгоритма FFT. Я не знаком с конкретной реализацией LTSpice, но поведение, о котором вы сообщаете, именно то, что я ожидал.
Наиболее распространенные реализации FFT работают с целочисленной степенью 2 точек данных. Таким образом, большинство реализаций будет дополнять ваши 1 000 000 точек данных до 1 048 576 точек данных и выполнять FFT для этого. Обратите внимание, что эта длина не является целым числом синусоидальных волн.
Существуют альтернативные методы преобразования Фурье, которые по-разному разбивают данные. Обычно они называются методами дискретного преобразования Фурье (DFT), и они медленнее и значительно сложнее в реализации. Я почти никогда не сталкивался с ними в практических приложениях. FFT - это конкретная реализация DFT, которая требует, чтобы количество точек данных было целочисленной степенью 2 (или иногда целочисленной степенью 4).
Итак, я предполагаю, что LTSpice дополняет ваши данные до 1 048 576 точек данных, добавленные 48 576 значений данных в конце содержат константу.
Теперь вы можете увидеть проблему: ваш буфер из 1 048 576 сэмплов содержит 1000 синусоид, каждая из 1000 сэмплов, за которыми следуют 48 576 постоянных значений. Это не может быть представлено суммой синусоидальных волн с частотой 1 кГц. Вместо этого результаты FFT показывают дополнительные высокочастотные значения, необходимые для восстановления вашего сигнала.
Чтобы определить, является ли это проблемой, создайте буфер из 1 048 576 выборок, содержащий синусоидальную волну с периодом 1024 выборки. Высокие частоты должны быть значительно уменьшены по величине.
Теперь, что касается применения окна:
Алгоритм БПФ концептуально «оборачивает» данные, поэтому за последней точкой входных данных следует первая точка входных данных. То есть БПФ вычисляется так, как если бы данные были бесконечными, повторялись по кругу как вектор с последовательностью: x [0], x [1], ..., x [1048574], x [1048575], x [ 0], х [1], ...
Эта упаковка может привести к переходу между последней точкой в буфере данных и первой точкой. Этот шаговый переход генерирует результаты БПФ с большим (ложным) вкладом от высоких частот. Цель окна - устранить эту проблему. Оконная функция обнуляется с обоих концов, поэтому в вашем случае w [0] и w [999999] будут равны нулю. Когда данные умножаются на окно, значения становятся равными нулю в начале и в конце, поэтому при переносе переходов не происходит.
Применяемая вами оконная функция изменяет частоту содержимого буфера, вы выбираете функцию, которая представляет приемлемый компромисс. Гауссиан является хорошей отправной точкой. Для любого практического применения, в котором вы не можете точно управлять частотным содержимым данных, вам придется применить оконную функцию, чтобы исключить подразумеваемый шаговый переход из-за длины данных.
Остаточные проблемы:
Существует еще один потенциальный источник высокочастотного спектрального шума в БПФ. Эффект увеличивается с длиной БПФ, и это может быть что-то, что вы можете увидеть в некоторых случаях на 1 000 000 точек данных.
Внутренний цикл алгоритма FFT использует точки вокруг окружности в комплексной плоскости: e ^ (i * theta), где алгоритм повторяет 'theta' от 0 до 2 * pi последовательно более мелкими шагами, вплоть до количества точек в FFT. То есть, если вы вычислите БПФ на 1 048 576 сэмплов, на одной из итераций внешнего цикла внутренний цикл будет вычислять e ^ (i * theta), где theta = 2 * pi * n / N, где N равно 1 048 576 итерации от 0 до 1 048 575. Это делается очевидным методом последовательного умножения на e ^ (i * 2 * pi / N).
Вы видите проблему: когда N становится большим, e ^ (i * 2 * pi / N) становится очень близким к 1, и оно умножается на N раз. С плавающей точкой двойной точности ошибки невелики, но я думаю, что вы можете увидеть получаемый минимальный уровень шума, если внимательно посмотрите. С плавающей запятой одинарной точности на 1000000 точек данных само вычисление БПФ создает значительный минимальный уровень шума.
Существуют альтернативные методы вычисления e ^ (i * theta), которые устраняют эту проблему, но реализация является более сложной. Мне нужно было создать такую реализацию только один раз.