2012-06-18 123 views
1

我知道它曾被問過一千次,但我仍然找不到解決方案。 在SO中搜索,我確實找到了它的算法,但缺乏真正理解它所需的數學知識,我無可奈何地失去了!創建頻譜圖時出現問題

從一開始,我的目標是計算一個完整的光譜圖並將其保存到圖像中,以便將其用於可視化工具。

我試過使用Sound.computeSpectrum,但是這需要播放聲音並等待它結束,我想以比需要收聽所有歌曲更短的時間來計算頻譜圖。我有2小時長的MP3。

我現在正在做的是從Sound對象讀取字節,將其分成兩個Vectors(。);然後使用定時器,在每個100毫秒I調用一個函數(步驟1),其中我有算法的實現,如下所示:

  1. 每個矢量(每一個用於一個信道)我應用漢恩功能到要素;
  2. 爲每個I抵消虛部矢量(I具有該二次矢量)用於I申請FFT
  3. 每個矢量中的每個矢量
  4. 我找到用於第一N/2個元素
  5. 爲幅度每個向量I平方幅度轉換爲dB刻度
  6. 結束。

但我只得到負值,只有30的成績%的可能是有用的(在的方式,其餘的都是相同的)

我會後的代碼只有一個通道擺脫掉「每個矢量」部分。

private var N:Number = 512; 
private function step1() : void 
{ 
    var xReLeft:Vector.<Number> = new Vector.<Number>(N); 
    var xImLeft:Vector.<Number> = new Vector.<Number>(N); 

    var leftA:Vector.<Number> = new Vector.<Number>(N); 

    // getting sample range 
    leftA = this.channels.left.slice(step * N, step * (N) + (N)); 

    if (leftA.length < N) 
    { 
     stepper.removeEventListener(TimerEvent.TIMER, getFreq100ms); 
     return; 
    } 
    else if (leftA.length == 0) 
    { 
     stepper.removeEventListener(TimerEvent.TIMER, getFreq100ms); 
     return; 
    } 

    var i:int; 

    // hann window function init 
     m_win = new Vector.<Number>(N); 
     for (var i:int = 0; i < N; i++) 
      m_win[i] = (4.0/N) * 0.5 * (1 - Math.cos(2 * Math.PI * i/N)); 

    // applying hann window function 
    for (i = 0; i < N; i++) 
    { 
     xReLeft[i] = m_win[i]*leftA[i]; 
     //xReRight[i] = m_win[i]*rightA[i]; 
    } 

    // nullify the imaginary part 
    for (i = 0; i < N; i++) 
    { 
     xImLeft[i] = 0.0; 
     //xImRight[i] = 0.0; 
    } 

    var magnitutel:Vector.<Number> = new Vector.<Number>(N); 

    fftl.run(xReLeft, xImLeft); 

    current = xReLeft; 
    currf = xImLeft; 

    for (i = 0; i < N/2; i++) 
    { 
     var re:Number = xReLeft[i]; 
     var im:Number = xImLeft[i]; 
     magnitutel[i] = Math.sqrt(re * re + im * im); 
    } 

    const SCALE:Number = 20/Math.LN10; 
    var l:uint = this.total.length; 
    for (i = 0; i < N/2; i++) 
    { 
     magnitutel[i] = SCALE * Math.log(magnitutel[i] + Number.MIN_VALUE); 
    } 

    var bufferl:Vector.<Number> = new Vector.<Number>(); 

    for (i = 0; i < N/2 ; i++) 
    { 
     bufferl[i] = magnitutel[i]; 
    } 

    var complete:Vector.<Vector.<Number>> = new Vector.<Vector.<Number>>(); 
    complete[0] = bufferl; 
    this.total[step] = complete; 

    this.step++; 
} 

該函數在定時器(步進器)調度的事件中執行。 很明顯,我做錯了一些事情,正如我所說的,我只有負值,更多的值在1到7000之間(至少)。

我想事先感謝您的幫助。

恕我直言, 保羅

+0

負值都可以 - 對於dB量級來說,您可能預計數值會在0到-100之間變化。 –

+0

@PaulR好吧,我得到絕對荒謬的值,如-6494!縮放之後...我做對了嗎? – khael

+0

我建議你稍微打破這個問題 - 確保你可以做一個已知信號(例如全尺度正弦波)的FFT,並在頻域中得到合理的結果 - 一旦你有了這個工作,你就可以建立起來譜圖。試圖做到這一切使得同時調試各種問題非常棘手。 –

回答

0

負分貝值確定。只需添加一個常數(表示音量控制),直到您想要着色的點數變爲正值。保持負值的剩餘值通常僅在頻譜圖中顯示或着色爲黑色。不管它有多麼負面(因爲它們可能只是FFT的數字噪聲,這可能是一個巨大的負dB數,甚至是NaN或-Inf(對於log(0))。

+0

謝謝你,在研究了一下FFT並清理了我的代碼之後,我得出了結論,我所做的確是對的。而且我認爲你對FFT數字噪聲也是正確的。 – khael