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  }