DFT spektrumu +/- 2 Hz frekans kayması problemi

Başlatan ziyaretci, 11 Mayıs 2019, 22:45:58

ziyaretci

Hayırlı akşamlar.

Telefonumda mikrofondan dijital veri okuyup DFT'sini alarak ekrana basıyorum. Mikrofona online bir platformdan 0-500Hz aralığında ses girişi veriyorum. Platformda örneğin ses(sinüsoidal) frekansı 350Hz iken ben oluşturduğum grafikte 349-350-351 Hz arasında salınım alıyorum.

Başka bir uygulama ile test için playstore'dan spektrum uygulaması indirdim, onunla test ediyorum o tamamen hangi frekansta giriş verdiysem o frekansı grafiğe döküyor ve sağa sola frekans kayması olmuyor, çok stabil.

Karşılaştığım bu sorunun nedeni ne olabilir? Şu sıralar geliştirilmiş FFT algoritmasını anlamaya çalışıyorum, birde onunla deneyeceğim.

Ses girişi aldığım kaynak: https://www.szynalski.com/tone-generator/

ADC: short 16bit
Örnekleme frekansım: 8kHz
Dijital veri buffer'ı: short 320(40ms)








while (true) 
{
   if(start>0)                       
   {

      record.read(audioBuffer, 0, audioBuffer.length);
      for(int i =0;i<audioBuffer.length;i++)
      {
        cache[i] = (int)(audioBuffer[i]*0.01);
      }

   }


     for (int f = 0; f < 500; f++) 
     {
        double dft_reel = 0;
        double dft_sanal = 0;
            for (int i = 0; i < audioBuffer.length; i+=4) 
            {
              double temp_1 = ((f + 1) * (i + 1) * (kat_sayi));
              dft_reel += (((cache[i] )) * Math.cos(temp_1));
              dft_sanal += (-1)*(((cache[i] )) * Math.sin(temp_1));
            }
        dft_f[f] = (Math.sqrt((Math.pow(dft_reel, 2) + Math.pow(dft_sanal, 2))));
        myPaint1.setColor(Color.WHITE);
        tempCanvas.drawLine(f , 0, f , 300, myPaint1);
        myPaint1.setColor(Color.RED);
        tempCanvas.drawLine(f , 0, f , (float) ((dft_f[f])), myPaint1);

        }
                       
 }

devrecii

Bulduğun değerleri toplayıp ortalamasını almalısın bence.

(349+350+351)/3=350

ziyaretci

#2
Alıntı yapılan: iboibo - 11 Mayıs 2019, 23:29:15Bulduğun değerleri toplayıp ortalamasını almalısın bence.

(349+350+351)/3=350

Onu denedim hocam, 10, hatta 20 değeri alıp ortalamasını aldım en fazla salınımın periyodu uzadı.

devrecii

500 sample almışsın ama gelen telefonun verdiği sample tahminen saniyede 22500 dür sen bunun 500 ünü almışsın 500hz dalganın onda birini bile vermiyor bu.

Tahminen en az 500000 sample üzerinden işlem yap


ziyaretci

#4
Demek istediğinizi anladım, deneyeceğim.

Telefonumda desteklenen hangi örnekleme frekanda işlem yaparsam yapayım, donanım bana 40ms 'lik çerçevede bilgi sunuyor. Her çerçeveyi alıp birleştirsem, bu seferde real-time sıkıntısı ortaya çıkıyor.

Örneğin;
>>8kHz seçersem donanım 640 byte buffer sunuyor. 16 bitlik çözünürlük olduğundan short 320 oluyor(40ms).
>>44.1kHz seçersem 3528 byte buffer sunuyor. 16 bitlik çözünürlük olduğundan short 1764 oluyor(40ms).

Ek:
Yukarıda 500 sample almadım, audiobuffer.length(320) kadar örnek aldım.

Güncelleme 2:
Aldığım örnekleri birer birer işleme soktuğumda salınım +/-10Hz'i aşıyor. Ama 4'er örnek ara ile işleme soktuğumda salınım +/-1Hz oluyor.

ziyaretci

#5
Sorunun nedeni;
1- @iboibo hocamın dediği gibi az örnek alıp işleme sokulması. Donanım bana 40ms'lik örnek veriyor demiştim, bu 40ms'lik örneklerin 3'ünü birleştirip(120ms) işleme soktum, kararlı bir frekans çıkışı aldım.
 
2- Örnekleme periyodunu kaçırıyor olmam.Yani buffer'a aldığım ilk örnekleri hesaplayamadan ikinci örnek çerçevesi buffer'a yerleştirildiğinden, aralarda süreksiz bölgeler oluşuyor(sinüs sinyali ile deniyorum). O da salınım yaptırıyor.

Aşağıdaki bağlantıda, periyodik kesme yapısını kullanarak bufferdaki verileri işleme soktum.


@iboibo hocam verdiğiniz bilgi için teşekkür ederim.

https://stackoverflow.com/questions/15804903/android-dev-audiorecord-without-blocking-or-threads

Alıntı Yaprecorder.setRecordPositionUpdateListener(mRecordListener);
recorder.setPositionNotificationPeriod(periodInFrames);


Real-time problemi halen var ama salınımın nedeni daha önemliydi. Zaten FFT ile yapacağım artık real-time için.