@@ -5,32 +5,46 @@ const fft = require('fft-js').fft;
55const fftUtil = require ( 'fft-js' ) . util ;
66const windowing = require ( 'fft-windowing' ) ;
77const Fili = require ( 'fili' ) ;
8+ var ft = require ( 'fourier-transform' ) ;
9+ var db = require ( 'decibels' ) ;
810// Smoothing and Plots
911const smoothed_z_score = require ( "@joe_six/smoothed-z-score-peak-signal-detection" ) ;
1012const detect_peaks = require ( "@joe_six/duarte-watanabe-peak-detection" )
11- const { plot, Plot } = require ( "nodeplotlib" ) ;
13+ const { plot, Plot} = require ( "nodeplotlib" ) ;
1214
13- const fftAnalysis = ( rawRecordedData , sampleRate ) => {
14- var windowedRecordedData = windowing . hann ( rawRecordedData ) ;
15- var phasors = fft ( windowedRecordedData . slice ( 0 , 262144 ) ) ; // 48000 > samples
16- var frequencies = fftUtil . fftFreq ( phasors , sampleRate ) ; // Sample rate and coef is just used for length, and frequency step
17- var magnitudes = fftUtil . fftMag ( phasors ) ;
15+ const fftAnalysis = ( rawData , sampleRate , fftData ) => {
16+ let N = 32768 ;
17+ let win = windowing . hann ( rawData . slice ( 0 , N ) , N ) ; //rawData.slice(0, N),
18+ let spectrum = fft ( win ) ; // 48000 > samples
19+ let frequencies = fftUtil . fftFreq ( spectrum , sampleRate ) ; // Sample rate and coef is just used for length, and frequency step
20+ let magnitudes = fftUtil . fftMag ( spectrum ) ;
21+ let spectrum2 = ft ( rawData . slice ( 0 , N ) ) ;
22+ let decibels = spectrum2 . map ( ( value ) => db . fromGain ( value ) )
1823
24+ console . log ( "##### META-DATA ON FFT-JS #####" ) ;
1925 console . log ( "Sample Rate: " + sampleRate ) ;
20- console . log ( "Length of raw data: " + rawRecordedData . length ) ;
21- console . log ( "Length of windowed data: " + windowedRecordedData . length ) ;
22- console . log ( "Length of phasors: " + phasors . length ) ;
26+ console . log ( "Length of raw data: " + rawData . length ) ;
27+ console . log ( "Length of windowed data: " + win . length ) ;
28+ console . log ( "Length of phasors: " + spectrum . length ) ;
2329 console . log ( "Length of frequencies: " + frequencies . length ) ;
2430 console . log ( "Length of magnitudes: " + magnitudes . length ) ;
2531 console . log ( "" ) ;
32+
33+ let fftFreq = new Float32Array ( fftData . length ) ;
34+ for ( let i = 0 ; i < fftData . length ; i ++ ) {
35+ fftFreq [ i ] = i * ( ( sampleRate / 2 ) / ( fftData . length ) ) ;
36+ }
37+
38+ graphFrequencySpectrum ( fftFreq , fftData , { title : "AnalyserNode Frequency Spectrum" } ) ; //{"logFreq": true}
39+ graphFrequencySpectrum ( frequencies , magnitudes , { title : "FFT-JS Frequency Spectrum" } ) ; //{"scaleMagnitude": true, "logFreq": true}
40+ graphFrequencySpectrum ( frequencies , decibels , { title : "FFT-ASM Frequency Spectrum" } ) ;
2641 return firFilterTaps ( frequencies , magnitudes , sampleRate ) ;
2742}
2843
2944const firFilterTaps = ( frequencies , magnitudes , sampleRate ) => {
3045 // TO-DO: Continue testing smoothing methods, for now electing Watanabe method
3146 //const peaksSmoothed = smoothed_z_score(magnitudes, {lag: 40, threshold: 4.5, influence: 0.2});
32-
33- const noiseTaps = noiseRemoval ( frequencies , magnitudes , 101 , sampleRate ) ;
47+ const noiseTaps = noiseRemoval ( frequencies , magnitudes , 101 , sampleRate , 150 ) ;
3448 return noiseTaps ;
3549}
3650
@@ -41,25 +55,58 @@ const identifyPeaks = (magnitudes, mpdVal) => {
4155}
4256
4357// Helper function for graphing/testing
44- const graphFrequencies = ( frequencies , magnitudes , logScale , plotType ) => {
45- let logFrequencies = [ ] ;
46- if ( logScale == true ) {
47- for ( let i = 0 ; i < frequencies . length ; i ++ ) {
48- logFrequencies . push ( Math . log10 ( frequencies [ i ] ) ) ;
58+ const graphFrequencySpectrum = ( frequencies , magnitudes , params = { } ) => {
59+
60+ if ( frequencies . length != magnitudes . length ) {
61+ console . log ( "Frequency bins length mismatches magnitude length" )
62+ return
63+ }
64+
65+ let length = frequencies . length ;
66+ let xaxisType = params [ "logFreq" ] || "log" ;
67+ let scaleMagnitude = params [ "scaleMagnitude" ] || false ;
68+ let fftSize = params [ "fftSize" ] || 32768 ;
69+ let title = params [ "title" ] || "Frequency Spectrum" ;
70+ let plotType = 'scatter' ;
71+
72+ let graphFrequencies = new Array ( length ) ;
73+ let graphMagnitudes = new Array ( length ) ;
74+
75+
76+ for ( let i = 0 ; i < length ; i ++ ) {
77+ graphFrequencies [ i ] = frequencies [ i ] ;
78+ }
79+
80+ if ( scaleMagnitude == true ) {
81+ for ( let i = 0 ; i < length ; i ++ ) {
82+ graphMagnitudes [ i ] = 20 * Math . log10 ( 2 * magnitudes [ i ] / fftSize ) ;
4983 }
5084 } else {
51- logFrequencies = frequencies ;
85+ for ( let i = 0 ; i < length ; i ++ ) {
86+ graphMagnitudes [ i ] = magnitudes [ i ] ;
87+ }
5288 }
5389
5490 const data = [
5591 {
56- x : logFrequencies ,
57- y : magnitudes ,
92+ x : graphFrequencies ,
93+ y : graphMagnitudes ,
5894 type : plotType
59- } ,
95+ }
6096 ] ;
97+
98+ const layout = {
99+ title : title ,
100+ xaxis : {
101+ title : "Frequency [Hz]" ,
102+ type : xaxisType
103+ } ,
104+ yaxis : {
105+ title : "Magnitude [dBFS]"
106+ }
107+ } ;
61108
62- plot ( data ) ;
109+ plot ( data , layout ) ;
63110}
64111
65112const bandstopTaps = ( filterOrder , sampleRate , lowerFreq , upperFreq , attenuation ) => {
@@ -74,30 +121,34 @@ const bandstopTaps = (filterOrder, sampleRate, lowerFreq, upperFreq, attenuation
74121 return firFilterCoeffsK ;
75122}
76123
77- const noiseRemoval = ( frequencies , magnitudes , filterOrder , sampleRate ) => {
124+ const noiseRemoval = ( frequencies , magnitudes , filterOrder , sampleRate , limit ) => {
78125 const peaksWatanabeIndices = identifyPeaks ( magnitudes , 50 ) ;
79- let noisyFrequencies = [ ] ;
126+ let strongLowerFreq = [ ] ;
80127 for ( let i = 0 ; i < peaksWatanabeIndices . length ; i ++ ) {
81- if ( frequencies [ peaksWatanabeIndices [ i ] ] < 80 ) {
82- noisyFrequencies . push ( Math . round ( frequencies [ peaksWatanabeIndices [ i ] ] ) ) ;
128+ if ( frequencies [ peaksWatanabeIndices [ i ] ] < limit ) {
129+ strongLowerFreq . push ( Math . round ( frequencies [ peaksWatanabeIndices [ i ] ] ) ) ;
83130 }
84131 }
85132
86133
87134 let bands = [ ] ;
88- for ( let i = 0 ; i < noisyFrequencies . length ; i ++ ) {
89- if ( noisyFrequencies [ i ] > 5 ) {
90- bands . push ( bandstopTaps ( filterOrder , sampleRate , noisyFrequencies [ i ] - 5 , noisyFrequencies [ i ] + 5 , 5 ) ) ; //Attenuate by 5 dB, order of 101
135+ for ( let i = 0 ; i < strongLowerFreq . length ; i ++ ) {
136+ if ( strongLowerFreq [ i ] > 5 ) { //Greater than 5Hz
137+ bands . push ( bandstopTaps ( filterOrder , sampleRate , strongLowerFreq [ i ] - 5 , strongLowerFreq [ i ] + 5 , 5 ) ) ; //Attenuate by 5 dB, order of 101
91138 } else {
92- bands . push ( bandstopTaps ( filterOrder , sampleRate , 0 , noisyFrequencies [ i ] + 5 , 5 ) ) ; //Attenuate by 5 dB, order of 101
139+ bands . push ( bandstopTaps ( filterOrder , sampleRate , 0 , strongLowerFreq [ i ] + 5 , 5 ) ) ; //Attenuate by 5 dB, order of 101
93140 }
94141 }
95142
96- // Safely assume independence of bands
97- var sum = ( r , a ) => r . map ( ( b , i ) => a [ i ] + b ) ;
98- let noisyTaps = bands . reduce ( sum ) ;
99-
100- return noisyTaps ;
143+ console . log ( strongLowerFreq ) ;
144+ if ( bands . length > 0 ) {
145+ // Safely assume independence of bands
146+ var sum = ( r , a ) => r . map ( ( b , i ) => a [ i ] + b ) ;
147+ let noisyTaps = bands . reduce ( sum ) ;
148+ return noisyTaps ;
149+ }
150+ return [ ] ;
151+
101152}
102153
103154const generalAnalysis = ( frequencies , magnitudes ) => {
0 commit comments