2014-07-26 2 views
3

Я работаю над приложением для Google Glass, которое отображает максимальную пиковую пиковую частоту в реальном времени (ish) с момента ее записи. Моя текущая проблема заключается в том, что частотная отчетность меняется очень быстро, поэтому ее трудно определить частоту, и я не уверен, что мой формат NumberFormat будет правильным, поскольку он когда-либо достигнет «00.000». Мне может понадобиться немного помощи с окнами, но мое понимание этого есть.Jtransforms, ouput freq неточно.

Спасибо!

public class RTAactivity extends Activity { 

private static final int SAMPLING_RATE = 44100; 

private TextView tvfreq; 
private TextView tvdb; 

private RecordingThread mRecordingThread; 
private int mBufferSize; 
private short[] mAudioBuffer; 
private String mDecibelFormat; 
private double mFreqFormat = 0.0; 
private int blockSize = 1024; //4096 
private DoubleFFT_1D fft; 
private int[] bufferDouble, bufferDouble2; 



@Override 
protected void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.rta_view); 
    getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); 

    tvfreq = (TextView) findViewById(R.id.tv_freq); 
    tvdb = (TextView) findViewById(R.id.tv_decibels); 

    // Compute the minimum required audio buffer size and allocate the buffer. 
    mBufferSize = AudioRecord.getMinBufferSize(SAMPLING_RATE, AudioFormat.CHANNEL_IN_MONO, 
      AudioFormat.ENCODING_PCM_16BIT); 
    mAudioBuffer = new short[mBufferSize/2]; 
    bufferDouble2 = new int[mBufferSize /2]; 
    bufferDouble = new int[(blockSize-1) * 2 ]; 

    mDecibelFormat = getResources().getString(R.string.decibel_format); 
} 

@Override 
protected void onResume() { 
    super.onResume(); 

    mRecordingThread = new RecordingThread(); 
    mRecordingThread.start(); 
} 

@Override 
protected void onPause() { 
    super.onPause(); 

    if (mRecordingThread != null) { 
     mRecordingThread.stopRunning(); 
     mRecordingThread = null; 
    } 
} 
private class RecordingThread extends Thread{ 

    private boolean mShallContinue = true; 

    @Override 
    public void run() { 
     android.os.Process.setThreadPriority(Process.THREAD_PRIORITY_AUDIO); 

     AudioRecord record = new AudioRecord(AudioSource.MIC, SAMPLING_RATE, AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT, mBufferSize); 

     short[] buffer = new short[blockSize]; 
     double[] audioDataDoubles = new double[(blockSize * 2)]; 
     double[] re = new double[blockSize]; 
     double[] im = new double[blockSize]; 
     double[] magnitude = new double[blockSize]; 

     //start collecting data 
     record.startRecording(); 



     DoubleFFT_1D fft = new DoubleFFT_1D(blockSize); 

     while (shallContinue()) { 

      /**decibels */ 
      record.read(mAudioBuffer, 0, mBufferSize/2); 
      updateDecibelLevel(); 

      /**frequency */ 
       ///windowing!? 
      for(int i=0;i<mAudioBuffer.length;i++) { 
       bufferDouble2[i] = (int) mAudioBuffer[i]; 
      } 

      for(int i=0;i<blockSize-1;i++){ 
       double x=-Math.PI+2*i*(Math.PI/blockSize); 
       double winValue=(1+Math.cos(x))/2.0; 
       bufferDouble[i]= (int) (bufferDouble2[i]*winValue); } 

       // bufferDouble[2*i]=bufferDouble2[i]; 
       // bufferDouble[2*i+1] = (int) 0.0;} 


      int bufferReadResult = record.read(buffer, 0, blockSize); 

      // Read in the data from the mic to the array 
      for (int i = 0; i < blockSize && i < bufferReadResult; i++) { 
       audioDataDoubles[2 * i] = (double) buffer[i]/32768.0; // signed 16 bit 
       audioDataDoubles[(2 * i) + 1] = 0.0; 
      } 

     //audiodataDoubles now holds data to work with 
     fft.complexForward(audioDataDoubles); //complexForward 


     // Calculate the Real and imaginary and Magnitude. 

     for (int i = 0; i < blockSize; i++) { 
      double real = audioDataDoubles[2 * i]; 
      double imag = audioDataDoubles[2 * i + 1]; 
      magnitude[i] = Math.sqrt((real * real) + (imag * imag)); 
     } 
     for (int i = 0; i < blockSize; i++) { 
      // real is stored in first part of array 
      re[i] = audioDataDoubles[i * 2]; 
      // imaginary is stored in the sequential part 
      im[i] = audioDataDoubles[(i * 2) + 1]; 
      // magnitude is calculated by the square root of (imaginary^2 + real^2) 
      magnitude[i] = Math.sqrt((re[i] * re[i]) + (im[i] * im[i])); 
     } 

     double peak = -1.0; 
     // Get the largest magnitude peak 
     for (int i = 0; i < blockSize; i++) { 
      peak = magnitude[i]; 
     } 

     // calculated the frequency 
     mFreqFormat = (SAMPLING_RATE * peak)/blockSize; 
     updateFrequency(); 

    } 

     record.stop(); //stop recording please. 
     record.release(); // Deystroy the recording, PLEASE! 
    } 

    /**true if the thread should continue running or false if it should stop 
    */ 
    private synchronized boolean shallContinue() {return mShallContinue; } 

    /** Notifies the thread that it should stop running at the next opportunity. */ 
    private synchronized void stopRunning() { mShallContinue = false; } 


    private void updateDecibelLevel() { 
     // Compute the root-mean-squared of the sound buffer and then apply the formula for 
     // computing the decibel level, 20 * log_10(rms). This is an uncalibrated calculation 
     // that assumes no noise in the samples; with 16-bit recording, it can range from 
     // -90 dB to 0 dB. 
     double sum = 0; 

     for (short rawSample : mAudioBuffer) { 
      double sample = rawSample/32768.0; 
      sum += sample * sample; 
     } 

     double rms = Math.sqrt(sum/mAudioBuffer.length); 
     final double db = 20 * Math.log10(rms); 

     // Update the text view on the main thread. 
     tvdb.post(new Runnable() { 
      @Override 
      public void run() { 
       tvdb.setText(String.format(mDecibelFormat, db)); 
      } 
     }); 
    } 

    } 
      /// post the output frequency to TextView 
private void updateFrequency() { 
    tvfreq.post(new Runnable() { 
     @Override 
     public void run() { 
      NumberFormat nM = NumberFormat.getNumberInstance(); 
      tvfreq.setText(nM.format(mFreqFormat) + " hz"); 
     } 
    }); 


} 

}

+0

Вы должны рассмотреть ваш код - по какой-то причине вы вычисляете величину дважды (безвредный, но бессмысленный), но гораздо важнее то, что ваш пиковый контур полностью разрушен. –

ответ

1

Есть несколько проблем с кодом, но наиболее важным является то, что ваш цикл пик находка полностью нарушена - изменение:

double peak = -1.0; 
    // Get the largest magnitude peak 
    for (int i = 0; i < blockSize; i++) { 
     peak = magnitude[i]; 
    } 

к:

double peak_val = magnitude[0]; // init magnitude of peak 
    peak = 0;       // init index of peak 
    for (int i = 1; i < blockSize; i++) { 
     double val = magnitude[i]; 
     if (val > peak_val) { 
      peak_val = val;   // update magnitude of peak 
      peak = i;     // update index of peak 
     } 
    } 
+1

СПАСИБО ВАМ PAUL R! Я должен сказать, что я становлюсь для вас настоящим поклонником, создавая это и узнал больше всего из ваших постов здесь, на SO. Я выполнил ваше исправление, как указано выше, и, похоже, решил мою проблему, теперь я читаю 440hz, когда воспроизвожу его через мои колонки с поддержкой Klipsch! Я заметил одну странную вещь, которая случается, хотя считывание иногда подскакивает до 43,281hz? Также, если вы хотите указать на несколько других проблем, которые я дал себе, которые будут оценены. Еще раз спасибо за Ваш ответ. – Kjacksonmusic

+0

Прошу прощения, что на самом деле я читаю о 10hz, когда я играю в 440hz, я читаю 430hz, плохо проверяю мои расчеты и завтра на другой набор динамиков. Больше идей было бы здорово. Благодаря! – Kjacksonmusic

+1

Рад, что это по крайней мере частично работает сейчас. Обратите внимание, что разрешение вашего FFT составляет только 44100/1024 = 43 Гц, поэтому вы, вероятно, видите свой пик 440 Гц в бункере 10, который дает вам предполагаемую частоту 430 Гц. Что касается других проблем с кодом, я уже упомянул избыточные расчеты величин в комментариях, но я еще раз посмотрю, есть ли что-нибудь еще. –

1

Добавлено: Частотное разрешение просто используя пик величину бункер БПФ будет установлен (квантуется) с частотой дискретизации, деленной на длину FFT (44100/1024 Гц для ваши параметры). Для короткого БПФ 430 Гц может быть ближайшим битом результата FFT до 440. Чтобы сделать лучше, вам нужно интерполировать, использовать более длинный БПФ или использовать другой алгоритм оценки частоты.

Если вы пытаетесь отобразить частоту шага (музыкальный шаг или вокальный танец), это очень часто не совпадает с пиковой спектральной частотой от результата FFT. Посмотрите методы определения/оценки высоты тона (многие научные статьи по этой теме), поскольку для этого обычно требуется более сложный и надежный алгоритм, чем вычисление пика величины FFT.

+0

Хотя это верно, и OP, вероятно, нужно делать больше исследований, он не затрагивает непосредственную проблему (ошибки в коде), поэтому скорее всего это скорее комментарий, чем ответ. –

+0

Моя цель - просто найти резонансные частоты. Я звукоинженер, создаю звуковые системы и звоню им - это то, что я делаю ежедневно. Я потратил много времени на исследование, чтобы донести меня до сих пор, если у вас есть какие-либо документы, которые вы бы рекомендовали, чтобы помочь мне понять, что было бы очень полезно! – Kjacksonmusic

Смежные вопросы