Конвертировать FFT в PCM
У меня есть некоторые данные FFT, 257 измерений, каждые 10 мс, со 121 кадром, т.е. 1,21 секунды. Я думаю, что первое измерение, вероятно, является чем-то другим, а остальные, я думаю, являются коэффициентами БПФ. Это, вероятно, просто данные спектрограммы. Из комментария о данных БПФ можно было бы применить sqrt10 и среднее отклонение-нормализация.
Оттуда я хочу вычислить обратно некоторый сигнал PCM для 44,1 Гц, чтобы я мог воспроизвести звук. Я задал тот же вопрос более математически, но, возможно, Stackru - лучшее место, потому что я действительно хочу это реализовать. Я также задавал тот же вопрос о теории здесь, на DSP SE.
Как бы я это сделал? Может быть, мне нужно больше информации (которую я должен как-то выяснить) - что? Может быть, эту недостающую информацию можно как-то догадаться?
Этот вопрос касается как теории, так и практической реализации. Реализация тривиальная, я думаю. Но конкретный пример на каком-то языке был бы полезен для понимания теории. Может быть, C++ с FFTW? Я пропустил документы FFTW, но я не понимаю всей терминологии и некоторого фона, например, здесь. Почему это от сложного к реальному или другому, я хочу только от реального к реальному. Что это за РЕДФТ? Что такое DCT, DFT, DST? FFTW_HC2R?
Я прочитал все данные БПФ, т.е. 121 * 257 с плавающей точкой, в вектор freq_bins
,
std::vector<float32_t> freq_bins; // FFT data
int freq_bins_count = 257;
size_t len = 121;
std::vector<float32_t> pcm; // output, PCM data
int N = freq_bins_count;
std::vector<double> out(N), orig_in(N);
// inspiration: https://stackru.com/questions/2459295/invertible-stft-and-istft-in-python/6891772#6891772
for(int f = 0; f < len; ++f) {
size_t pos = freq_bins_count * f;
for(int i = 0; i < N; ++i)
out[i] = pow(freq_bins[pos + i] + offset, 10); // fft was sqrt10 + mvn
fftw_plan q = fftw_plan_r2r_1d(N, &out[0], &orig_in[0], FFTW_REDFT00, FFTW_ESTIMATE);
fftw_execute(q);
fftw_destroy_plan(q);
// naive overlap-and-add
auto start_frame = size_t(f * dt * sampleRate);
for(int i = 0; i < N; ++i) {
sample_t frame = orig_in[i] * scale / (2 * (N - 1));
size_t idx = start_frame + i;
while(idx >= pcm.size())
pcm.push_back(0);
pcm[idx] += frame;
}
}
Но это неправильно, я думаю. Я просто вывожу мусор.
С этим может быть связан этот вопрос. Или это.
2 ответа
Если у вас есть реальные данные, то у вас, скорее всего, есть данные спектрограммы, а если данные, которые вы получаете, являются сложными, то у вас, скорее всего, есть необработанные данные кратковременного преобразования Фурье (STFT) (см. Диаграмму в этом посте, чтобы увидеть как создаются данные STFT/ спектрограммы). Данные спектрограммы получаются путем взятия квадрата величины данных STFT и, следовательно, необратимы, поскольку вся фазовая информация в аудиосигнале потеряна, но необработанные данные STFT являются обратимыми, поэтому, если это то, что у вас есть, вы можете искать библиотека, которая выполняет обратную функцию STFT и попробуйте использовать это.
Что касается вопроса о том, что представляют собой измерения БПФ в ваших данных, я считаю, что 257 точек данных, которые вы получаете каждые 10 мс, являются результатом 512-точечного БПФ, используемого в процессе STFT. Первая выборка - это частота 0 Гц, а остальные из 256 точек данных - это одна половина спектра БПФ (другая половина данных БПФ была отброшена, потому что входные данные для БПФ действительны, и поэтому одна половина данных БПФ является просто комплексным сопряжением другой половины).
В дополнение к этому, я хотел бы отметить, что то, что вы получаете данные FFT каждые 10 мс 121 раз, не означает, что аудиосигнал равен 1,21. STFT обычно создается с использованием перекрывающихся окон, поэтому ваш аудиосигнал может быть короче. чем 1,21 с.
Вы бы просто передали эти данные через обратное преобразование Фурье. Все библиотеки FFT предлагают функции прямого и обратного преобразования.