@@ -148,7 +148,7 @@ GraphSpectrumCalc._dataLoadFrequencyVsX = function(vsFieldNames, minValue = Infi
148148 const fftChunkLength = Math . round ( this . _blackBoxRate * FREQ_VS_THR_CHUNK_TIME_MS / 1000 ) ;
149149 const fftChunkWindow = Math . round ( fftChunkLength / FREQ_VS_THR_WINDOW_DIVISOR ) ;
150150 const fftBufferSize = Math . pow ( 2 , Math . ceil ( Math . log2 ( fftChunkLength ) ) ) ;
151-
151+ const magnitudeLength = Math . floor ( fftBufferSize / 2 ) ;
152152 let maxNoise = 0 ; // Stores the maximum amplitude of the fft over all chunks
153153 // Matrix where each row represents a bin of vs values, and the columns are amplitudes at frequencies
154154 const matrixFftOutput = new Array ( NUM_VS_BINS ) . fill ( null ) . map ( ( ) => new Float64Array ( fftBufferSize * 2 ) ) ;
@@ -176,13 +176,14 @@ GraphSpectrumCalc._dataLoadFrequencyVsX = function(vsFieldNames, minValue = Infi
176176 fft . simple ( fftOutput , fftInput , 'real' ) ;
177177
178178 fftOutput = fftOutput . slice ( 0 , fftBufferSize ) ; // The fft output contains two side spectrum, we use the first part only to get one side
179-
180- // TODO: This is wrong spectrum magnitude calculation as abs of separate complex Re, Im values.
181- // We should use hypot(Re, Im) instead of and return divide by 2 (fftOutput.length / 4) arrays size
182- // Use only abs values
183- for ( let i = 0 ; i < fftBufferSize ; i ++ ) {
184- fftOutput [ i ] = Math . abs ( fftOutput [ i ] ) ;
185- maxNoise = Math . max ( fftOutput [ i ] , maxNoise ) ;
179+ const magnitudes = new Float64Array ( magnitudeLength ) ;
180+
181+ // Compute magnitude
182+ for ( let i = 0 ; i < magnitudeLength ; i ++ ) {
183+ const re = fftOutput [ 2 * i ] ,
184+ im = fftOutput [ 2 * i + 1 ] ;
185+ magnitudes [ i ] = Math . hypot ( re , im ) ;
186+ maxNoise = Math . max ( magnitudes [ i ] , maxNoise ) ;
186187 }
187188
188189 // calculate a bin index and put the fft value in that bin for each field (e.g. eRPM[0], eRPM[1]..) sepparately
@@ -196,12 +197,12 @@ GraphSpectrumCalc._dataLoadFrequencyVsX = function(vsFieldNames, minValue = Infi
196197 const avgVsValue = sumVsValues / fftChunkLength ;
197198 let vsBinIndex = Math . round ( NUM_VS_BINS * ( avgVsValue - flightSamples . minValue ) / ( flightSamples . maxValue - flightSamples . minValue ) ) ;
198199 // ensure that avgVsValue == flightSamples.maxValue does not result in an out of bounds access
199- if ( vsBinIndex == = NUM_VS_BINS ) { vsBinIndex = NUM_VS_BINS - 1 ; }
200+ if ( vsBinIndex > = NUM_VS_BINS ) { vsBinIndex = NUM_VS_BINS - 1 ; }
200201 numberSamples [ vsBinIndex ] ++ ;
201202
202203 // add the output from the fft to the row given by the vs value bin index
203- for ( let i = 0 ; i < fftOutput . length ; i ++ ) {
204- matrixFftOutput [ vsBinIndex ] [ i ] += fftOutput [ i ] ;
204+ for ( let i = 0 ; i < magnitudeLength ; i ++ ) {
205+ matrixFftOutput [ vsBinIndex ] [ i ] += magnitudes [ i ] ;
205206 }
206207 }
207208 }
@@ -222,7 +223,7 @@ GraphSpectrumCalc._dataLoadFrequencyVsX = function(vsFieldNames, minValue = Infi
222223 const fftData = {
223224 fieldIndex : this . _dataBuffer . fieldIndex ,
224225 fieldName : this . _dataBuffer . fieldName ,
225- fftLength : fftBufferSize ,
226+ fftLength : magnitudeLength ,
226227 fftOutput : matrixFftOutput ,
227228 maxNoise : maxNoise ,
228229 blackBoxRate : this . _blackBoxRate ,
@@ -393,7 +394,7 @@ GraphSpectrumCalc._getFlightSamplesFreqVsX = function(vsFieldNames, minValue = I
393394 }
394395
395396 // Calculate min max average of the VS values in the chunk what will used by spectrum data definition
396- const fftChunkLength = this . _blackBoxRate * FREQ_VS_THR_CHUNK_TIME_MS / 1000 ;
397+ const fftChunkLength = Math . round ( this . _blackBoxRate * FREQ_VS_THR_CHUNK_TIME_MS / 1000 ) ;
397398 const fftChunkWindow = Math . round ( fftChunkLength / FREQ_VS_THR_WINDOW_DIVISOR ) ;
398399 for ( let fftChunkIndex = 0 ; fftChunkIndex + fftChunkLength < samplesCount ; fftChunkIndex += fftChunkWindow ) {
399400 for ( const vsValueArray of vsValues ) {
@@ -503,28 +504,33 @@ GraphSpectrumCalc._fft = function(samples, type) {
503504GraphSpectrumCalc . _normalizeFft = function ( fftOutput ) {
504505 // The fft output contains two side spectrum, we use the first part only to get one side
505506 const fftLength = fftOutput . length / 2 ;
506- // Make all the values absolute, and calculate some useful values (max noise, etc.)
507+
508+ // The fft output contains complex values (re, im pairs) of two-side spectrum
509+ // Compute magnitudes for one spectrum side
510+ const magnitudeLength = Math . floor ( fftLength / 2 ) ;
507511 const maxFrequency = ( this . _blackBoxRate / 2.0 ) ;
508- const noiseLowEndIdx = 100 / maxFrequency * fftLength ;
512+ const noiseLowEndIdx = 100 / maxFrequency * magnitudeLength ;
513+ const magnitudes = new Float64Array ( magnitudeLength ) ;
509514 let maxNoiseIdx = 0 ;
510515 let maxNoise = 0 ;
511- // TODO: This is wrong spectrum magnitude calculation as abs of separate complex Re, Im values.
512- // We should use hypot(Re, Im) instead of and return divide by 2 (fftOutput.length / 4) arrays size
513- for ( let i = 0 ; i < fftLength ; i ++ ) {
514- fftOutput [ i ] = Math . abs ( fftOutput [ i ] ) ;
515- if ( i > noiseLowEndIdx && fftOutput [ i ] > maxNoise ) {
516- maxNoise = fftOutput [ i ] ;
516+
517+ for ( let i = 0 ; i < magnitudeLength ; i ++ ) {
518+ const re = fftOutput [ 2 * i ] ,
519+ im = fftOutput [ 2 * i + 1 ] ;
520+ magnitudes [ i ] = Math . hypot ( re , im ) ;
521+ if ( i > noiseLowEndIdx && magnitudes [ i ] > maxNoise ) {
522+ maxNoise = magnitudes [ i ] ;
517523 maxNoiseIdx = i ;
518524 }
519525 }
520526
521- maxNoiseIdx = maxNoiseIdx / fftLength * maxFrequency ;
527+ maxNoiseIdx = maxNoiseIdx / magnitudeLength * maxFrequency ;
522528
523529 const fftData = {
524530 fieldIndex : this . _dataBuffer . fieldIndex ,
525531 fieldName : this . _dataBuffer . fieldName ,
526- fftLength : fftLength ,
527- fftOutput : fftOutput ,
532+ fftLength : magnitudeLength ,
533+ fftOutput : magnitudes ,
528534 maxNoiseIdx : maxNoiseIdx ,
529535 blackBoxRate : this . _blackBoxRate ,
530536 } ;
0 commit comments