gonum.org/v1/gonum@v0.14.0/dsp/fourier/fourier_example_test.go (about) 1 // Copyright ©2018 The Gonum Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package fourier_test 6 7 import ( 8 "fmt" 9 "math" 10 "math/cmplx" 11 12 "gonum.org/v1/gonum/dsp/fourier" 13 "gonum.org/v1/gonum/floats/scalar" 14 "gonum.org/v1/gonum/mat" 15 ) 16 17 func ExampleFFT_Coefficients() { 18 // Samples is a set of samples over a given period. 19 samples := []float64{1, 0, 2, 0, 4, 0, 2, 0} 20 period := float64(len(samples)) 21 22 // Initialize an FFT and perform the analysis. 23 fft := fourier.NewFFT(len(samples)) 24 coeff := fft.Coefficients(nil, samples) 25 26 for i, c := range coeff { 27 fmt.Printf("freq=%v cycles/period, magnitude=%v, phase=%.4g\n", 28 fft.Freq(i)*period, cmplx.Abs(c), cmplx.Phase(c)) 29 } 30 31 // Output: 32 // 33 // freq=0 cycles/period, magnitude=9, phase=0 34 // freq=1 cycles/period, magnitude=3, phase=3.142 35 // freq=2 cycles/period, magnitude=1, phase=-0 36 // freq=3 cycles/period, magnitude=3, phase=3.142 37 // freq=4 cycles/period, magnitude=9, phase=0 38 } 39 40 func ExampleFFT_Coefficients_tone() { 41 // Tone is a set of samples over a second of a pure Middle C. 42 const ( 43 mC = 261.625565 // Hz 44 samples = 44100 45 ) 46 tone := make([]float64, samples) 47 for i := range tone { 48 tone[i] = math.Sin(mC * 2 * math.Pi * float64(i) / samples) 49 } 50 51 // Initialize an FFT and perform the analysis. 52 fft := fourier.NewFFT(samples) 53 coeff := fft.Coefficients(nil, tone) 54 55 var maxFreq, magnitude, mean float64 56 for i, c := range coeff { 57 m := cmplx.Abs(c) 58 mean += m 59 if m > magnitude { 60 magnitude = m 61 maxFreq = fft.Freq(i) * samples 62 } 63 } 64 fmt.Printf("freq=%v Hz, magnitude=%.0f, mean=%.4f\n", maxFreq, magnitude, mean/samples) 65 66 // Output: 67 // 68 // freq=262 Hz, magnitude=17296, mean=2.7835 69 } 70 71 func ExampleCmplxFFT_Coefficients() { 72 // Samples is a set of samples over a given period. 73 samples := []complex128{1, 0, 2, 0, 4, 0, 2, 0} 74 period := float64(len(samples)) 75 76 // Initialize a complex FFT and perform the analysis. 77 fft := fourier.NewCmplxFFT(len(samples)) 78 coeff := fft.Coefficients(nil, samples) 79 80 for i := range coeff { 81 // Center the spectrum. 82 i = fft.ShiftIdx(i) 83 84 fmt.Printf("freq=%v cycles/period, magnitude=%v, phase=%.4g\n", 85 fft.Freq(i)*period, cmplx.Abs(coeff[i]), cmplx.Phase(coeff[i])) 86 } 87 88 // Output: 89 // 90 // freq=-4 cycles/period, magnitude=9, phase=0 91 // freq=-3 cycles/period, magnitude=3, phase=3.142 92 // freq=-2 cycles/period, magnitude=1, phase=0 93 // freq=-1 cycles/period, magnitude=3, phase=3.142 94 // freq=0 cycles/period, magnitude=9, phase=0 95 // freq=1 cycles/period, magnitude=3, phase=3.142 96 // freq=2 cycles/period, magnitude=1, phase=0 97 // freq=3 cycles/period, magnitude=3, phase=3.142 98 } 99 100 func Example_fFT2() { 101 // This example shows how to perform a 2D fourier transform 102 // on an image. The transform identifies the lines present 103 // in the image. 104 105 // Image is a set of diagonal lines. 106 image := mat.NewDense(11, 11, []float64{ 107 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 108 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 109 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 110 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 111 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 112 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 113 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 114 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 115 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 116 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 117 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 118 }) 119 120 // Make appropriately sized real and complex FFT types. 121 r, c := image.Dims() 122 fft := fourier.NewFFT(c) 123 cfft := fourier.NewCmplxFFT(r) 124 125 // Only c/2+1 coefficients will be returned for 126 // the real FFT. 127 c = c/2 + 1 128 129 // Perform the first axis transform. 130 rows := make([]complex128, r*c) 131 for i := 0; i < r; i++ { 132 fft.Coefficients(rows[c*i:c*(i+1)], image.RawRowView(i)) 133 } 134 135 // Perform the second axis transform, storing 136 // the result in freqs. 137 freqs := mat.NewDense(c, c, nil) 138 column := make([]complex128, r) 139 for j := 0; j < c; j++ { 140 for i := 0; i < r; i++ { 141 column[i] = rows[i*c+j] 142 } 143 cfft.Coefficients(column, column) 144 for i, v := range column[:c] { 145 freqs.Set(i, j, scalar.Round(cmplx.Abs(v), 1)) 146 } 147 } 148 149 fmt.Printf("%v\n", mat.Formatted(freqs)) 150 151 // Output: 152 // 153 // ⎡ 40 0.4 0.5 1.4 3.2 1.1⎤ 154 // ⎢ 0.4 0.5 0.7 1.8 4 1.2⎥ 155 // ⎢ 0.5 0.7 1.1 2.8 5.9 1.7⎥ 156 // ⎢ 1.4 1.8 2.8 6.8 14.1 3.8⎥ 157 // ⎢ 3.2 4 5.9 14.1 27.5 6.8⎥ 158 // ⎣ 1.1 1.2 1.7 3.8 6.8 1.6⎦ 159 160 } 161 162 func Example_cmplxFFT2() { 163 // Image is a set of diagonal lines. 164 image := mat.NewDense(11, 11, []float64{ 165 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 166 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 167 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 168 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 169 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 170 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 171 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 172 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 173 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 174 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 175 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 176 }) 177 178 // Make appropriately sized complex FFT. 179 // Rows and columns are the same, so the same 180 // CmplxFFT can be used for both axes. 181 r, c := image.Dims() 182 cfft := fourier.NewCmplxFFT(r) 183 184 // Perform the first axis transform. 185 rows := make([]complex128, r*c) 186 for i := 0; i < r; i++ { 187 row := rows[c*i : c*(i+1)] 188 for j, v := range image.RawRowView(i) { 189 row[j] = complex(v, 0) 190 } 191 cfft.Coefficients(row, row) 192 } 193 194 // Perform the second axis transform, storing 195 // the result in freqs. 196 freqs := mat.NewDense(c, c, nil) 197 column := make([]complex128, r) 198 for j := 0; j < c; j++ { 199 for i := 0; i < r; i++ { 200 column[i] = rows[i*c+j] 201 } 202 cfft.Coefficients(column, column) 203 for i, v := range column { 204 // Center the frequencies. 205 freqs.Set(cfft.UnshiftIdx(i), cfft.UnshiftIdx(j), scalar.Round(cmplx.Abs(v), 1)) 206 } 207 } 208 209 fmt.Printf("%v\n", mat.Formatted(freqs)) 210 211 // Output: 212 // 213 // ⎡ 1.6 6.8 3.8 1.7 1.2 1.1 1.1 1.4 2.6 3.9 1.1⎤ 214 // ⎢ 6.8 27.5 14.1 5.9 4 3.2 3 3 3.9 3.2 3.9⎥ 215 // ⎢ 3.8 14.1 6.8 2.8 1.8 1.4 1.2 1.1 1.4 3.9 2.6⎥ 216 // ⎢ 1.7 5.9 2.8 1.1 0.7 0.5 0.5 0.5 1.1 3 1.4⎥ 217 // ⎢ 1.2 4 1.8 0.7 0.5 0.4 0.4 0.5 1.2 3 1.1⎥ 218 // ⎢ 1.1 3.2 1.4 0.5 0.4 40 0.4 0.5 1.4 3.2 1.1⎥ 219 // ⎢ 1.1 3 1.2 0.5 0.4 0.4 0.5 0.7 1.8 4 1.2⎥ 220 // ⎢ 1.4 3 1.1 0.5 0.5 0.5 0.7 1.1 2.8 5.9 1.7⎥ 221 // ⎢ 2.6 3.9 1.4 1.1 1.2 1.4 1.8 2.8 6.8 14.1 3.8⎥ 222 // ⎢ 3.9 3.2 3.9 3 3 3.2 4 5.9 14.1 27.5 6.8⎥ 223 // ⎣ 1.1 3.9 2.6 1.4 1.1 1.1 1.2 1.7 3.8 6.8 1.6⎦ 224 225 }