Eksperymentowałem z algorytmem FFT. Używam NAudio wraz z działającym kodem algorytmu FFT z Internetu. W oparciu o moje obserwacje wydajności, wynikowa wysokość jest niedokładna.Niedokładność FFT dla C#
Co się dzieje, to że mam MIDI (generowane z GuitarPro) przekonwertowane na plik WAV (44,1 kHz, 16 bitów, mono), który zawiera progresję od E2 (najniższa nuta gitary) do około E6. Jakie są wyniki dla niższych dźwięków (wokół E2-B3) jest generalnie bardzo źle. Ale osiągnięcie C4 jest nieco poprawne, ponieważ widzisz już prawidłową progresję (następną nutą jest C# 4, a następnie D4 itd.) Jednak problem polega na tym, że wykrytą tonację jest o połowę nić niższa od rzeczywistej wysokości dźwięku (np. C4 powinno być notatką, ale wyświetlany jest D # 4).
Co Twoim zdaniem może być nie tak? W razie potrzeby mogę opublikować kod. Dziękuję bardzo! Nadal zaczynam rozumieć pole DSP.
Edycja: Tutaj jest szorstka zarysowanie co robię
byte[] buffer = new byte[8192];
int bytesRead;
do
{
bytesRead = stream16.Read(buffer, 0, buffer.Length);
} while (bytesRead != 0);
a następnie: (waveBuffer to po prostu klasa, która jest tam, aby przekonwertować byte [] do pływaka [], ponieważ funkcja przyjmuje tylko pływak [])
public int Read(byte[] buffer, int offset, int bytesRead)
{
int frames = bytesRead/sizeof(float);
float pitch = DetectPitch(waveBuffer.FloatBuffer, frames);
}
i wreszcie: (Smbpitchfft jest klasa, która ma FFT algo ... wierzę tam nic złego, że tak im nie umieszczenie go tutaj)
private float DetectPitch(float[] buffer, int inFrames)
{
Func<int, int, float> window = HammingWindow;
if (prevBuffer == null)
{
prevBuffer = new float[inFrames]; //only contains zeroes
}
// double frames since we are combining present and previous buffers
int frames = inFrames * 2;
if (fftBuffer == null)
{
fftBuffer = new float[frames * 2]; // times 2 because it is complex input
}
for (int n = 0; n < frames; n++)
{
if (n < inFrames)
{
fftBuffer[n * 2] = prevBuffer[n] * window(n, frames);
fftBuffer[n * 2 + 1] = 0; // need to clear out as fft modifies buffer
}
else
{
fftBuffer[n * 2] = buffer[n - inFrames] * window(n, frames);
fftBuffer[n * 2 + 1] = 0; // need to clear out as fft modifies buffer
}
}
SmbPitchShift.smbFft(fftBuffer, frames, -1);
}
I interpretacji wynik:
float binSize = sampleRate/frames;
int minBin = (int)(82.407/binSize); //lowest E string on the guitar
int maxBin = (int)(1244.508/binSize); //highest E string on the guitar
float maxIntensity = 0f;
int maxBinIndex = 0;
for (int bin = minBin; bin <= maxBin; bin++)
{
float real = fftBuffer[bin * 2];
float imaginary = fftBuffer[bin * 2 + 1];
float intensity = real * real + imaginary * imaginary;
if (intensity > maxIntensity)
{
maxIntensity = intensity;
maxBinIndex = bin;
}
}
return binSize * maxBinIndex;
Update (jeśli ktoś jest nadal zainteresowany):
Tak, jedną z odpowiedzi poniżej zaznaczono, że szczyt częstotliwości z FFT nie zawsze jest równoznaczne z boiska . Rozumiem, że. Ale chciałem spróbować czegoś dla siebie, jeśli tak było (przy założeniu, że są momenty, w których szczyt częstotliwości jest wynikiem). Zasadniczo otrzymałem 2 oprogramowanie (SpectraPLUS i FFTProperty wg DewResearch; kredyty do nich), które są w stanie wyświetlić domenę częstotliwości dla sygnałów audio.
Więc oto wyniki szczytów częstotliwości w dziedzinie czasu:
SpectraPLUS
i właściwości FFT:
Dokonano tego za pomocą wiadomości testowej A2 (około 110 Hz). Po obejrzeniu obrazów mają one wartości szczytowe częstotliwości w zakresie 102-112 Hz dla SpectraPLUS i 108 Hz dla właściwości FFT. Na moim kodzie dostaję 104Hz (używam 8192 bloków, a próbnik 44,1 khz ... 8192 jest podwajany, aby zrobić złożone wejście, więc w końcu otrzymuję około 5 Hz dla binsize, w porównaniu do 10Hz binsize z SpectraPLUS).
Teraz jestem trochę zdezorientowany, ponieważ w oprogramowaniu wydają się zwracać poprawny wynik, ale na moim kodzie zawsze dostaję 104 Hz (zauważ, że porównałem funkcję FFT, którą użyłem z innymi, takimi jak Math.Net i wydaje się być poprawne).
Czy uważasz, że problem może dotyczyć mojej interpretacji danych? Lub czy oprogramowanie robi jakieś inne rzeczy przed wyświetleniem częstotliwości-spektrum?Dzięki!
Witam! Wartość, którą otrzymuję dla maxBinIndex jest w bin 20 (około 100-104 Hz), co skutkuje około G #, który jest w połowie zapisany w dół od przypuszczalnego A. Jest to zgodne z innymi plikami .wav, czasami będącym krokiem całego na dół. – user488792
@eryksun Dzięki! Twój ostatni punkt jest interesujący. Spróbuję i zajrzę do tego. – user488792
@eryksun Cześć! Dziękuję Ci bardzo! To wydaje się być problemem. Mój kod działa teraz i zwraca poprawną częstotliwość. Wygląda na to, że przegapiłem to rozwiązanie z odpowiedzi Paula R., ponieważ w tamtym czasie nie robiłem zbyt wiele na temat FFT. Jednak wiele się nauczyłem dzięki waszej pomocy. Jeszcze raz dzięki! – user488792