93f7d51be979caa666079f50c63d257d5c949e37
[aubio.git] / python / tests / test_fft.py
1 #! /usr/bin/env python
2
3 from numpy.testing import TestCase
4 from numpy.testing import assert_equal, assert_almost_equal
5 from aubio import fvec, fft, cvec
6 from math import pi
7
8 class aubio_fft_test_case(TestCase):
9
10     def test_members(self):
11         """ check members are set correctly """
12         win_s = 2048
13         f = fft(win_s)
14         assert_equal (f.win_s, win_s)
15
16     def test_output_dimensions(self):
17         """ check the dimensions of output """
18         win_s = 1024
19         timegrain = fvec(win_s)
20         f = fft (win_s)
21         fftgrain = f (timegrain)
22         del f
23         assert_equal (fftgrain.norm.shape, (win_s/2+1,))
24         assert_equal (fftgrain.phas.shape, (win_s/2+1,))
25
26     def test_zeros(self):
27         """ check the transform of zeros is all zeros """
28         win_s = 512
29         timegrain = fvec(win_s)
30         f = fft (win_s)
31         fftgrain = f (timegrain)
32         assert_equal ( fftgrain.norm, 0 )
33         assert_equal ( fftgrain.phas, 0 )
34
35     def test_impulse(self):
36         """ check the transform of one impulse at a random place """
37         from random import random
38         from math import floor
39         win_s = 256
40         i = int(floor(random()*win_s))
41         impulse = pi * random()
42         f = fft(win_s)
43         timegrain = fvec(win_s)
44         timegrain[i] = impulse
45         fftgrain = f ( timegrain )
46         #self.plot_this ( fftgrain.phas )
47         assert_almost_equal ( fftgrain.norm, impulse, decimal = 6 )
48         assert_equal ( fftgrain.phas <= pi, True)
49         assert_equal ( fftgrain.phas >= -pi, True)
50
51     def test_impulse_negative(self):
52         """ check the transform of one impulse at a random place """
53         from random import random
54         from math import floor
55         win_s = 256
56         i = 0
57         impulse = -10.
58         f = fft(win_s)
59         timegrain = fvec(win_s)
60         timegrain[i] = impulse
61         fftgrain = f ( timegrain )
62         #self.plot_this ( fftgrain.phas )
63         assert_almost_equal ( fftgrain.norm, abs(impulse), decimal = 6 )
64         if impulse < 0:
65             # phase can be pi or -pi, as it is not unwrapped
66             assert_almost_equal ( abs(fftgrain.phas[1:-1]) , pi, decimal = 6 )
67             assert_almost_equal ( fftgrain.phas[0], pi, decimal = 6)
68             assert_almost_equal ( fftgrain.phas[-1], pi, decimal = 6)
69         else:
70             assert_equal ( fftgrain.phas[1:-1] == 0, True)
71             assert_equal ( fftgrain.phas[0] == 0, True)
72             assert_equal ( fftgrain.phas[-1] == 0, True)
73         # now check the resynthesis
74         synthgrain = f.rdo ( fftgrain )
75         #self.plot_this ( fftgrain.phas.T )
76         assert_equal ( fftgrain.phas <= pi, True)
77         assert_equal ( fftgrain.phas >= -pi, True)
78         #self.plot_this ( synthgrain - timegrain )
79         assert_almost_equal ( synthgrain, timegrain, decimal = 6 )
80
81     def test_impulse_at_zero(self):
82         """ check the transform of one impulse at a index 0 """
83         win_s = 1024
84         impulse = pi
85         f = fft(win_s)
86         timegrain = fvec(win_s)
87         timegrain[0] = impulse
88         fftgrain = f ( timegrain )
89         #self.plot_this ( fftgrain.phas )
90         assert_equal ( fftgrain.phas[0], 0)
91         # could be 0 or -0 depending on fft implementation (0 for fftw3, -0 for ooura)
92         assert_almost_equal ( fftgrain.phas[1], 0)
93         assert_almost_equal ( fftgrain.norm[0], impulse, decimal = 6 )
94
95     def test_rdo_before_do(self):
96         """ check running fft.rdo before fft.do works """
97         win_s = 1024
98         impulse = pi
99         f = fft(win_s)
100         fftgrain = cvec(win_s)
101         t = f.rdo( fftgrain )
102         assert_equal ( t, 0 )
103
104     def plot_this(self, this):
105         from pylab import plot, show
106         plot ( this )
107         show ()
108
109     def test_local_fftgrain(self):
110         """ check aubio.fft() result can be accessed after deletion """
111         def compute_grain(impulse):
112             win_s = 1024
113             timegrain = fvec(win_s)
114             timegrain[0] = impulse
115             f = fft(win_s)
116             fftgrain = f ( timegrain )
117             return fftgrain
118         impulse = pi
119         fftgrain = compute_grain(impulse)
120         assert_equal ( fftgrain.phas[0], 0)
121         assert_almost_equal ( fftgrain.phas[1], 0)
122         assert_almost_equal ( fftgrain.norm[0], impulse, decimal = 6 )
123
124     def test_local_reconstruct(self):
125         """ check aubio.fft.rdo() result can be accessed after deletion """
126         def compute_grain(impulse):
127             win_s = 1024
128             timegrain = fvec(win_s)
129             timegrain[0] = impulse
130             f = fft(win_s)
131             fftgrain = f ( timegrain )
132             r = f.rdo(fftgrain)
133             return r
134         impulse = pi
135         r = compute_grain(impulse)
136         assert_almost_equal ( r[0], impulse, decimal = 6)
137         assert_almost_equal ( r[1:], 0)
138
139     def test_large_input_timegrain(self):
140         win_s = 1024
141         f = fft(win_s)
142         t = fvec(win_s + 1)
143         with self.assertRaises(ValueError):
144             f(t)
145
146     def test_small_input_timegrain(self):
147         win_s = 1024
148         f = fft(win_s)
149         t = fvec(1)
150         with self.assertRaises(ValueError):
151             f(t)
152
153     def test_large_input_fftgrain(self):
154         win_s = 1024
155         f = fft(win_s)
156         s = cvec(win_s + 5)
157         with self.assertRaises(ValueError):
158             f.rdo(s)
159
160     def test_small_input_fftgrain(self):
161         win_s = 1024
162         f = fft(win_s)
163         s = cvec(16)
164         with self.assertRaises(ValueError):
165             f.rdo(s)
166
167 class aubio_fft_wrong_params(TestCase):
168
169     def test_wrong_buf_size(self):
170         win_s = -1
171         with self.assertRaises(ValueError):
172             fft(win_s)
173
174     def test_buf_size_not_power_of_two(self):
175         # when compiled with fftw3, aubio supports non power of two fft sizes
176         win_s = 320
177         try:
178             with self.assertRaises(RuntimeError):
179                 fft(win_s)
180         except AssertionError as e:
181             self.skipTest('creating aubio.fft with size %d did not fail' % win_s)
182
183     def test_buf_size_too_small(self):
184         win_s = 1
185         with self.assertRaises(RuntimeError):
186             fft(win_s)
187
188 if __name__ == '__main__':
189     from nose2 import main
190     main()