fft — Векторы и матрицы в C ++ для генерации спектрограммы

Это моя первая попытка сгенерировать спектрограмму синусоидального сигнала с C ++.
Для генерации спектрограммы:

  1. Я разделил настоящий синусоидальный сигнал на B блоки

  2. Прикладное окно Хеннинга на каждом блоке (я предположил, что перекрытия нет). Это должно дать мне входные данные для fft, in[j][k] где k номер блока

  3. Применять fft на in[j][k] для каждого блока и хранить его.

Вот сценарий:

#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <fftw3.h>
#include <iostream>
#include <cmath>
#include <fstream>
using namespace std;

int main(){
int i;
int N = 500; // sampled
int Windowsize = 100;
double Fs = 200; // sampling frequency
double T = 1 / Fs; // sample time
double f = 50; // frequency
double *in;
fftw_complex *out;
double t[N]; // time vector
fftw_plan plan_forward;
std::vector<double> signal(N);
int B = N / Windowsize; //number of blocks
in = (double*)fftw_malloc(sizeof(double) * N);
out = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) * N);

//Generating the signal
for(int i = 0; i < = N; i++){
t[i] = i * T;
signal[i] = 0.7 * sin(2 * M_PI * f * t[i]);// generate sine waveform
}

//Applying the Hanning window function on each block B
for(int k = 0; i <= B; k++){
for(int j = 0; j <= Windowsize; j++){
double multiplier = 0.5 * (1 - cos(2 * M_PI * j / (N-1))); // Hanning Window
in[j][k] = multiplier * signal[j];
}
plan_forward = fftw_plan_dft_r2c_1d (Windowsize, in, out, FFTW_ESTIMATE );
fftw_execute(plan_forward);
v[j][k]=(20 * log(sqrt(out[i][0] * out[i][0] + out[i][1] * out[i][1]))) / N;
}

fftw_destroy_plan(plan_forward);
fftw_free(in);
fftw_free(out);
return 0;
}

Итак, вопрос: Как правильно объявить in[j][k] а также v[j][k] переменные.

Обновление: я объявил мой v [j] [k] в качестве матрицы: double v [5][249]; по данным этого сайта:http://www.cplusplus.com/doc/tutorial/arrays/ так что теперь мой сценарий выглядит так:

#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <fftw3.h>
#include <iostream>
#include <cmath>
#include <fstream>
using namespace std;
int main()
{
int i;
double y;
int N=500;//Number of pints acquired inside the window
double Fs=200;//sampling frequency
int windowsize=100;
double dF=Fs/N;
double  T=1/Fs;//sample time
double f=50;//frequency
double *in;
fftw_complex *out;
double t[N];//time vector
double tt[5];
double ff[N];
fftw_plan plan_forward;
double  v [5][249];
in = (double*) fftw_malloc(sizeof(double) * N);
out = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) * N);
plan_forward = fftw_plan_dft_r2c_1d ( N, in, out, FFTW_ESTIMATE );

for (int i=0; i<= N;i++)
{
t[i]=i*T;
in[i] =0.7 *sin(2*M_PI*f*t[i]);// generate sine waveform
}

for (int k=0; k< 5;k++){
for (int i = 0; i<windowsize; i++){
double multiplier = 0.5 * (1 - cos(2*M_PI*i/(windowsize-1)));//Hanning Window
in[i] = multiplier * in[i+k*windowsize];
fftw_execute ( plan_forward );
for (int i = 0; i<= (N/2); i++)
{
v[k][i]=(20*log10(sqrt(out[i][0]*out[i][0]+ out[i][1]*out[i]   [1])));//Here   I  have calculated the y axis of the spectrum in dB
}
}
}

for (int k=0; k< 5;k++)//Center time for each block
{
tt[k]=(2*k+1)*T*(windowsize/2);
}

fstream myfile;
myfile.open("example2.txt",fstream::out);
myfile << "plot '-' using 1:2" << std::endl;
for (int k=0; k< 5;k++){
for (int i = 0; i<= ((N/2)-1); i++)
{
myfile << v[k][i]<< " " << tt[k]<< std::endl;

}
}
myfile.close();
fftw_destroy_plan ( plan_forward );
fftw_free ( in );
fftw_free ( out );
return 0;
}

Я больше не получаю ошибок, но график спектрограммы не верен.

1

Решение

Как указано в Документация FFTW, размер вывода (out в вашем случае) при использовании fftw_plan_dft_r2c_1d не совпадает с размером ввода. Более конкретно для ввода N реальные образцы, выход состоит из N/2+1 сложные ценности. Затем вы можете выделить out с:

out = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) * (N/2 + 1));

Для вывода спектрограммы у вас будет аналогично (N/2+1) величины для каждого из B блоки, в результате чего в 2D массив:

double** v = new double*[B];
for (int i = 0; i < B; i++){
v[i] = new double[(N/2+1)];
}

Также обратите внимание, что вы можете повторно использовать входной буфер in для каждой итерации (заполняя ее данными для нового блока). Однако, так как вы решили вычислить NТочка БПФ и будет хранить меньшие блоки Windowsize образцы (в этом случае N=500 а также Windowsize=100), не забудьте инициализировать оставшиеся образцы нулями:

in = (double*)fftw_malloc(sizeof(double) * N);
for (int i = 0; i < N; i++){
in[i] = 0;
}

Обратите внимание, что в дополнение к объявлению и распределению in а также v переменных, код, который вы разместили, страдает от нескольких дополнительных проблем:

  • При вычислении Окно Ханнинга, вы должны разделить на Windowsize-1 не N-1 (так как в вашем случае N соответствуют размеру БПФ).
  • Вы берете БПФ того же блока signal снова и снова, так как вы всегда индексируете j в [0,Windowsize] спектр. Скорее всего, вы захотите добавить смещение каждый раз, когда обрабатываете другой блок.
  • Поскольку размер БПФ не изменяется, вам нужно создать план только один раз. По крайней мере, если вы собираетесь создавать свой план на каждой итерации, вы должны аналогичным образом уничтожить его (с fftw_destroy_plan) на каждой итерации.

И несколько дополнительных моментов, которые могут потребовать некоторых мыслей:

  • Масштабирование масштабируемых по логарифму величин путем деления на N может не делать то, что вы думаете. Вы, скорее всего, захотите масштабировать линейные масштабы (т.е. разделите величину, прежде чем брать логарифм). Обратите внимание, что это приведет к постоянному смещению кривой спектра, что для многих приложений не столь существенно. Если масштабирование важно для вашего приложения, вы можете взглянуть на другой мой ответ Больше подробностей.
  • Общая формула 20*log10(x) обычно используется для преобразования линейного масштаба в децибел использует логарифм основания-10 вместо естественного log (база e~2.7182) функция, которую вы использовали. Это приведет к мультипликативному масштабированию (растяжению), которое может или не может быть значительным в зависимости от вашего приложения.

Подводя итог, следующий код может более соответствовать тому, что вы пытаетесь сделать:

// Allocate & initialize buffers
in = (double*)fftw_malloc(sizeof(double) * N);
for (int i = 0; i < N; i++){
in[i] = 0;
}
out = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) * (N/2 + 1));
v = new (double*)[B];
for (int i = 0; i < B; i++){
v[i] = new double[(N/2+1)];
}

// Generate the signal
...

// Create the plan once
plan_forward = fftw_plan_dft_r2c_1d (Windowsize, in, out, FFTW_ESTIMATE);

// Applying the Hanning window function on each block B
for(int k = 0; k < B; k++){
for(int j = 0; j < Windowsize; j++){
// Hanning Window
double multiplier = 0.5 * (1 - cos(2 * M_PI * j / (Windowsize-1)));
in[j] = multiplier * signal[j+k*Windowsize];
}
fftw_execute(plan_forward);
for (int j = 0; j <= N/2; j++){
// Factor of 2 is to account for the fact that we are only getting half
// the spectrum (the other half is not return by a R2C plan due to symmetry)
v[k][j] = 2*(out[j][0] * out[j][0] + out[j][1] * out[j][1])/(N*N);
}
// DC component and at Nyquist frequency do not have a corresponding symmetric
// value, so should not have been doubled up above. Correct those special cases.
v[k][0]   *= 0.5;
v[k][N/2] *= 0.5;
// Convert to decibels
for (int j = 0; j <= N/2; j++){
// 20*log10(sqrt(x)) is equivalent to 10*log10(x)
// also use some small epsilon (e.g. 1e-5) to avoid taking the log of 0
v[k][j] = 10 * log10(v[k][j] + epsilon);
}
}

// Clean up
fftw_destroy_plan(plan_forward);
fftw_free(in);
fftw_free(out);
// Delete this last one after you've done something useful with the spectrogram
for (int i = 0; i < B; i++){
delete[] v[i];
}
delete[] v;
2

Другие решения

Похоже, что вы пропустили начальное объявление для ‘v’ в целом, а ‘in’ не объявлено должным образом.

Увидеть этот страница для связанного вопроса о создании 2D массивов в C ++. Как я понимаю, fftw_malloc () в основном new () или malloc (), но правильно выравнивает переменную для алгоритма FFTW.

Поскольку вы не поставляете ‘v’ для чего-либо, связанного с FFTW, вы можете использовать для этого стандартный malloc ().

1

По вопросам рекламы [email protected]