Coverage for emd/tests/test_sift.py: 98%

300 statements  

« prev     ^ index     » next       coverage.py v7.6.10, created at 2025-01-09 10:07 +0000

1"""Tests for single-cycle analyses in emd.cycles.""" 

2 

3import unittest 

4 

5import numpy as np 

6import pytest 

7 

8from ..imftools import is_imf 

9from ..sift import (complete_ensemble_sift, ensemble_sift, get_config, 

10 iterated_mask_sift, mask_sift, sift) 

11from ..simulate import abreu2010 

12 

13 

14class TestSiftDefaults(unittest.TestCase): 

15 """Ensure that all sift variants actually run with default options.""" 

16 

17 def setUp(self): 

18 """Set up data for testing.""" 

19 # Create core signal 

20 seconds = 5.1 

21 sample_rate = 2000 

22 f1 = 2 

23 f2 = 18 

24 time_vect = np.linspace(0, seconds, int(seconds * sample_rate)) 

25 

26 x = abreu2010(f1, .2, 0, sample_rate, seconds) 

27 self.x = x + np.cos(2.3 * np.pi * f2 * time_vect) + np.linspace(-.5, 1, len(time_vect)) 

28 

29 def test_sift_default(self): 

30 """Check basic sift runs with some simple settings.""" 

31 imf = sift(self.x) 

32 assert(imf.shape[0] == self.x.shape[0]) # just checking that it ran 

33 

34 def test_ensemble_sift_default(self): 

35 """Check ensemble sift runs with some simple settings.""" 

36 imf = ensemble_sift(self.x[:500], max_imfs=3) 

37 assert(imf.shape[0] == self.x[:500].shape[0]) # just checking that it ran 

38 

39 imf = ensemble_sift(self.x[:500], max_imfs=3, noise_mode='flip') 

40 assert(imf.shape[0] == self.x[:500].shape[0]) # just checking that it ran 

41 

42 def test_complete_ensemble_sift_default(self): 

43 """Check complete ensemble sift runs with some simple settings.""" 

44 imf = complete_ensemble_sift(self.x[:200]) 

45 assert(imf.shape[0] == self.x[:200].shape[0]) # just checking that it ran 

46 

47 def test_mask_sift_default(self): 

48 """Check mask sift runs with some simple settings.""" 

49 imf = mask_sift(self.x[:200], max_imfs=5, mask_freqs='zc') 

50 assert(imf.shape[0] == self.x[:200].shape[0]) # just checking that it ran 

51 

52 imf = mask_sift(self.x[:200], max_imfs=5, mask_freqs='if') 

53 assert(imf.shape[0] == self.x[:200].shape[0]) # just checking that it ran 

54 

55 imf = mask_sift(self.x[:200], max_imfs=5, mask_freqs=0.4) 

56 assert(imf.shape[0] == self.x[:200].shape[0]) # just checking that it ran 

57 

58 def test_iterated_mask_sift_default(self): 

59 """Check mask sift runs with some simple settings.""" 

60 imf = iterated_mask_sift(self.x[:200], max_imfs=5) 

61 assert(imf.shape[0] == self.x[:200].shape[0]) # just checking that it ran 

62 

63 

64class TestSiftEnsurance(unittest.TestCase): 

65 """Check that different inputs to sift work ok.""" 

66 

67 def setUp(self): 

68 """Set up signal for testing.""" 

69 # Create core signal 

70 seconds = 5.1 

71 sample_rate = 2000 

72 f1 = 2 

73 f2 = 18 

74 time_vect = np.linspace(0, seconds, int(seconds * sample_rate)) 

75 

76 x = abreu2010(f1, .2, 0, sample_rate, seconds) 

77 self.x = x + np.cos(2.3 * np.pi * f2 * time_vect) + np.linspace(-.5, 1, len(time_vect)) 

78 

79 def test_get_next_imf_ensurance(self): 

80 """Ensure that get_next_imf works with expected inputs and errors.""" 

81 from ..sift import get_next_imf 

82 

83 # Check that various inputs to get_next_imf work or don't work 

84 # check 1d input ok 

85 imf, _ = get_next_imf(self.x) 

86 assert(imf.shape == (self.x.shape[0], 1)) 

87 

88 # check 1d+singleton is ok 

89 imf, _ = get_next_imf(self.x[:, np.newaxis]) 

90 assert(imf.shape == (self.x.shape[0], 1)) 

91 

92 # check nd trailing singletons is ok 

93 imf, _ = get_next_imf(self.x[:, np.newaxis, np.newaxis]) 

94 assert(imf.shape == (self.x.shape[0], 1)) 

95 

96 # check 2d raises error 

97 with pytest.raises(ValueError): 

98 xx = np.tile(self.x[:, np.newaxis], (1, 2)) 

99 imf, _ = get_next_imf(xx) 

100 

101 # check 3d raises error 

102 with pytest.raises(ValueError): 

103 xx = np.tile(self.x[:, np.newaxis, np.newaxis], (1, 2, 3)) 

104 imf, _ = get_next_imf(xx) 

105 

106 

107class BaseTestSiftBehaviour(object): 

108 """Base class for testing basic sift behaviour. 

109 

110 Base class doesn't inherit from unittest so tests within it aren't run - 

111 use multiple inheritance in child classes to add unittest 

112 

113 This class implements 5 tests (four from: https://doi.org/10.1016/j.ymssp.2007.11.028) 

114 1) The sift should be a complete decomposition 

115 2) The sift of a signal multiplied by a constant should just scale the IMFs by that constant 

116 3) The sift of a signal with a constant added should only affect the final 

117 IMF, and should only increase it by the scalar 

118 4) The sift of an IMF should just return the IMF 

119 5) The sift of a time-reversed signal should return time-reversed but otherwise identical IMFs 

120 

121 """ 

122 

123 def setUpClass(self): 

124 """Create signals for testing. 

125 

126 This should create at least: 

127 

128 self.x 

129 self.imf1 

130 self.imf_kwargs 

131 self.envelope_kwargs 

132 self.extrema_kwargs 

133 """ 

134 raise NotImplementedError 

135 

136 def test_complete_decomposition(self): 

137 """Ensure complete decomposition.""" 

138 assert(np.allclose(self.imf1.sum(axis=1), self.x)) 

139 

140 def test_sift_multiplied_by_constant(self): 

141 """Ensure constant scaling only scales IMFs.""" 

142 const = 3 

143 imf2 = sift(self.x*const, imf_opts=self.imf_kwargs, 

144 envelope_opts=self.envelope_kwargs, 

145 extrema_opts=self.extrema_kwargs) 

146 assert(np.allclose(self.imf1, imf2/const)) 

147 assert(np.allclose(imf2.sum(axis=1)/const, self.x)) 

148 

149 def test_sift_plus_constant(self): 

150 """Ensure adding constant only affects final IMF.""" 

151 const = 3 

152 imf2 = sift(self.x+const, imf_opts=self.imf_kwargs, 

153 envelope_opts=self.envelope_kwargs, 

154 extrema_opts=self.extrema_kwargs) 

155 assert(np.allclose(self.imf1[:, :2], imf2[:, :2])) 

156 assert(np.allclose(self.imf1[:, 2]+const, imf2[:, 2])) 

157 

158 def test_sift_of_imf(self): 

159 """Ensure sift of an IMF is that same IMF.""" 

160 # Test sift of an IMF - Need to relax criteria as edges effects can be 

161 # amplified by repeated sifting 

162 imf2 = sift(self.imf1[:, 0], imf_opts=self.imf_kwargs, 

163 envelope_opts=self.envelope_kwargs, 

164 extrema_opts=self.extrema_kwargs) 

165 assert(np.allclose(imf2[:, 0], self.imf1[:, 0], atol=0.02)) 

166 

167 imf2 = sift(self.imf1[:, 1], imf_opts=self.imf_kwargs, 

168 envelope_opts=self.envelope_kwargs, 

169 extrema_opts=self.extrema_kwargs) 

170 assert(np.allclose(imf2[:, 0], self.imf1[:, 1], atol=0.02)) 

171 

172 def test_sift_of_reversed_signal(self): 

173 """Ensure sift of time-reversed signal returns reversed-but-identical IMFs.""" 

174 # Test sift of reversed signal - very much increased criteria 

175 extrema_kwargs = self.extrema_kwargs.copy() 

176 extrema_kwargs['method'] = 'numpypad' # Rilling not working here for some reason 

177 imf2 = sift(self.x[::-1], imf_opts=self.imf_kwargs, 

178 envelope_opts=self.envelope_kwargs, 

179 extrema_opts=extrema_kwargs) 

180 assert(np.allclose(self.imf1, imf2[::-1, :], atol=0.1)) 

181 

182 # Should be fine in the middle though... 

183 assert(np.allclose(self.imf1[3000:7000, :], 

184 imf2[::-1, :][3000:7000, :], 

185 atol=0.02)) 

186 

187 

188class TestSiftBehaviour(unittest.TestCase, BaseTestSiftBehaviour): 

189 """Test sift behaviour on simple signal.""" 

190 

191 @classmethod 

192 def setUpClass(cls): 

193 """Set up data and IMFs for testing.""" 

194 # Create core signal 

195 seconds = 5.1 

196 sample_rate = 2000 

197 f1 = 2 

198 f2 = 18 

199 time_vect = np.linspace(0, seconds, int(seconds * sample_rate)) 

200 

201 x = abreu2010(f1, .2, 0, sample_rate, seconds) 

202 cls.x = x + np.cos(2.3 * np.pi * f2 * time_vect) + np.linspace(-.5, 1, len(time_vect)) 

203 

204 cls.imf_kwargs = {} 

205 cls.envelope_kwargs = {'interp_method': 'splrep'} 

206 cls.extrema_kwargs = {} 

207 cls.imf1 = sift(cls.x, imf_opts=cls.imf_kwargs, 

208 envelope_opts=cls.envelope_kwargs, 

209 extrema_opts=cls.extrema_kwargs) 

210 

211 

212class TestMaskSiftBehaviour(unittest.TestCase): 

213 """Ensure that sifted IMFs meet certain criteria.""" 

214 

215 def get_resid(self, x, x_bar): 

216 """Get residual from signal and IMF.""" 

217 ss_orig = np.power(x, 2).sum() 

218 ss_resid = np.power(x - x_bar, 2).sum() 

219 return (ss_orig - ss_resid) / ss_orig 

220 

221 def check_diff(self, val, target, eta=1e-3): 

222 """Assess difference between two signals.""" 

223 return np.abs(val - target) < eta 

224 

225 @classmethod 

226 def setUpClass(cls): 

227 """Set up data and IMFs for testing.""" 

228 # Create core signal 

229 seconds = 5.1 

230 cls.sample_rate = 2000 

231 f1 = 2 

232 f2 = 17 # Has exact division into 5.1 seconds 

233 time_vect = np.linspace(0, seconds, int(seconds * cls.sample_rate)) 

234 

235 x = abreu2010(f1, .2, 0, cls.sample_rate, seconds) 

236 cls.x = x + np.cos(2 * np.pi * f2 * time_vect) + np.linspace(-.5, 1, len(time_vect)) 

237 

238 cls.imf_kwargs = {} 

239 cls.envelope_opts = {'interp_method': 'splrep'} 

240 cls.imf = sift(cls.x, imf_opts=cls.imf_kwargs, envelope_opts=cls.envelope_opts) 

241 

242 # Test mask sifts 

243 def test_get_next_imf_mask(self): 

244 """Test that get_next_imf_mask works as expected.""" 

245 from ..sift import get_next_imf_mask 

246 

247 # sift with mask above signal should return zeros 

248 # mask has to be waaay above signal in a noiseless time-series 

249 next_imf, continue_flag = get_next_imf_mask(self.imf[:, 0, None], 0.25, 1) 

250 mask_power = np.sum(np.power(next_imf, 2)) 

251 

252 assert(mask_power < 1) 

253 

254 # sift with mask below signal should return original signal 

255 next_imf, continue_flag = get_next_imf_mask(self.imf[:, 0, None], 0.0001, 1) 

256 power = np.sum(np.power(self.imf[:, 0], 2)) 

257 mask_power = np.sum(np.power(next_imf, 2)) 

258 

259 assert(power - mask_power < 1) 

260 

261 def test_get_mask_freqs(self): 

262 """Test API of get_mask_freqs.""" 

263 from ..sift import get_mask_freqs 

264 

265 # Values outside of 0 <= x < 0.5 raise an error 

266 self.assertRaises(ValueError, get_mask_freqs, self.x, 0.55) 

267 self.assertRaises(ValueError, get_mask_freqs, self.x, 5) 

268 self.assertRaises(ValueError, get_mask_freqs, self.x, -1) 

269 

270 # Values within 0 <= x < 0.5 return themselves 

271 assert(get_mask_freqs(self.x, first_mask_mode=0.1) == 0.1) 

272 assert(get_mask_freqs(self.x, first_mask_mode=0.45894) == 0.45894) 

273 

274 # ZC of sinusoid should return pretty much sinusoid freq 

275 target = 2 / self.sample_rate 

276 assert(np.allclose(get_mask_freqs(self.imf[:, 1], 'zc'), target, atol=1e-3)) 

277 

278 target = 17 / self.sample_rate 

279 assert(np.allclose(get_mask_freqs(self.imf[:, 0], 'zc'), target, atol=1e-3)) 

280 

281 # IF of sinusoid should return pretty much sinusoid freq 

282 target = 2 / self.sample_rate 

283 assert(np.allclose(get_mask_freqs(self.imf[:, 1], 'if'), target, atol=1e-3)) 

284 

285 target = 17 / self.sample_rate 

286 assert(np.allclose(get_mask_freqs(self.imf[:, 0], 'if'), target, atol=1e-3)) 

287 

288 

289class TestSecondLayerSift(unittest.TestCase): 

290 """Check second layer sifting is behaving itself.""" 

291 

292 @classmethod 

293 def setUpClass(cls): 

294 """Housekeeping and preparation.""" 

295 cls.seconds = 10 

296 cls.sample_rate = 200 

297 cls.t = np.linspace(0, cls.seconds, cls.seconds*cls.sample_rate) 

298 

299 cls.f_slow = 5 # Frequency of slow oscillation 

300 cls.f_slow_am = 0.5 # Frequency of slow amplitude modulation 

301 cls.a_slow_am = 0.5 # Amplitude of slow amplitude modulation 

302 

303 cls.f_fast = 37 # Frequency of fast oscillation 

304 cls.a_fast = 0.5 # Amplitude of fast oscillation 

305 cls.f_fast_am = 5 # Frequency of fast amplitude modulation 

306 cls.a_fast_am = 0.5 # Amplitude of fast amplitude modulation 

307 

308 # First we create a slow 4.25Hz oscillation with a 0.5Hz amplitude modulation 

309 cls.slow_am = (cls.a_slow_am+(np.cos(2*np.pi*cls.f_slow_am*cls.t)/2)) 

310 cls.slow = cls.slow_am * np.sin(2*np.pi*cls.f_slow*cls.t) 

311 

312 # Second, we create a faster 37Hz oscillation that is amplitude modulated by the first. 

313 cls.fast_am = (cls.a_fast_am+(np.cos(2*np.pi*cls.f_fast_am*cls.t)/2)) 

314 cls.fast = cls.fast_am * np.sin(2*np.pi*cls.f_fast*cls.t) 

315 

316 # We create our signal by summing the oscillation and adding some noise 

317 cls.x = cls.slow+cls.fast 

318 

319 def test_second_layer_mask_sift_slow(self): 

320 """Check that carrier and am frequencies of slower component can be found.""" 

321 from ..sift import mask_sift, mask_sift_second_layer 

322 from ..spectra import frequency_transform 

323 

324 # Just checking slow component for now 

325 imf, masks = mask_sift(self.slow, max_imfs=4, ret_mask_freq=True) 

326 IP, IF, IA = frequency_transform(imf, self.sample_rate, 'hilbert') 

327 

328 # Only checking for ballpark accuracy here 

329 assert(np.allclose(np.average(IF[:, 0], weights=IA[:, 0]), self.f_slow, atol=1)) 

330 

331 # Sift the first level IMFs 

332 self.imf2 = mask_sift_second_layer(IA, masks, sift_args={'max_imfs': 3}) 

333 self.IP2, self.IF2, self.IA2 = frequency_transform(self.imf2, self.sample_rate, 'hilbert') 

334 

335 assert(np.allclose(np.average(self.IF2[:, 0], weights=self.IA2[:, 0]), self.f_slow_am, atol=1)) 

336 

337 def test_second_layer_mask_sift_fast(self): 

338 """Check that carrier and am frequencies of faster component can be found.""" 

339 from ..sift import mask_sift, mask_sift_second_layer 

340 from ..spectra import frequency_transform 

341 

342 # Just checking fast component for now 

343 imf, masks = mask_sift(self.fast, max_imfs=4, ret_mask_freq=True, mask_amp_mode='ratio_imf') 

344 IP, IF, IA = frequency_transform(imf, self.sample_rate, 'hilbert') 

345 

346 # Only checking for ballpark accuracy here 

347 assert(np.allclose(np.average(IF[:, 0], weights=IA[:, 0]), self.f_fast, atol=1)) 

348 

349 # Sift the first level IMFs 

350 self.imf2 = mask_sift_second_layer(IA, masks, sift_args={'max_imfs': 3, 'mask_amp_mode': 'ratio_imf'}) 

351 self.IP2, self.IF2, self.IA2 = frequency_transform(self.imf2, self.sample_rate, 'hilbert') 

352 

353 assert(np.allclose(np.average(self.IF2[:, 0], weights=self.IA2[:, 0]), self.f_fast_am, atol=1)) 

354 

355 

356class TestSiftConfig(unittest.TestCase): 

357 """Ensure that sift configs work properly.""" 

358 

359 def test_config(self): 

360 """Check SiftConfig creation and editing.""" 

361 # Get sift config 

362 conf = get_config('sift') 

363 # Check a couple of options 

364 assert(conf['max_imfs'] is None) 

365 assert(conf['extrema_opts/pad_width'] == 2) 

366 assert(conf['extrema_opts/loc_pad_opts/mode'] == 'reflect') 

367 

368 # Get ensemble sift config 

369 conf = get_config('ensemble_sift') 

370 # Check a couple of options 

371 assert(conf['max_imfs'] is None) 

372 assert(conf['extrema_opts/pad_width'] == 2) 

373 assert(conf['extrema_opts/loc_pad_opts/mode'] == 'reflect') 

374 

375 # Get mask sift config 

376 conf = get_config('ensemble_sift') 

377 # Check a couple of options 

378 assert(conf['nensembles'] == 4) 

379 assert(conf['max_imfs'] is None) 

380 assert(conf['extrema_opts/pad_width'] == 2) 

381 assert(conf['extrema_opts/loc_pad_opts/mode'] == 'reflect') 

382 

383 def test_sift_config_saveload_yaml(self): 

384 """Check SiftConfig saving and loading.""" 

385 import tempfile 

386 

387 from ..sift import SiftConfig 

388 

389 # Get sift config 

390 config = get_config('mask_sift') 

391 

392 config_file = tempfile.NamedTemporaryFile(prefix="ExampleSiftConfig_").name 

393 

394 # Save the config into yaml format 

395 config.to_yaml_file(config_file) 

396 

397 # Load the config back into a SiftConfig object for use in a script 

398 new_config = SiftConfig.from_yaml_file(config_file) 

399 

400 assert(new_config.sift_type == 'mask_sift') 

401 

402 

403class TestIsIMF(unittest.TestCase): 

404 """Ensure that we can validate IMFs.""" 

405 

406 def setUp(self): 

407 """Set up data for testing.""" 

408 # Create core signal 

409 seconds = 5.1 

410 sample_rate = 2000 

411 f1 = 2 

412 f2 = 18 

413 time_vect = np.linspace(0, seconds, int(seconds * sample_rate)) 

414 

415 x = abreu2010(f1, .2, 0, sample_rate, seconds) 

416 self.x = x + np.cos(2.3 * np.pi * f2 * time_vect) + np.linspace(-.5, 1, len(time_vect)) 

417 

418 self.y = np.sin(2 * np.pi * 5 * time_vect) 

419 

420 def test_is_imf_on_sinusoid(self): 

421 """Make sure a pure sinusoid is an IMF.""" 

422 out = is_imf(self.y) 

423 

424 # Should be true on both criteria 

425 assert(np.all(out)) 

426 

427 def test_is_imf_on_abreu(self): 

428 """Make sure the Abreu signal is an IMF.""" 

429 imf = sift(self.x) 

430 out = is_imf(imf) 

431 

432 # Should be true on both criteria 

433 assert(np.all(out[0, :])) 

434 

435 # Should be true on both criteria 

436 assert(np.all(out[1, :])) 

437 

438 # Trend is not an IMF, should be false on both criteria 

439 assert(np.all(out[2, :] == False)) # noqa: E712 

440 

441 

442class TestSiftUtils(unittest.TestCase): 

443 """Ensure envelopes and extrema are behaving.""" 

444 

445 def setUp(self): 

446 """Set up data for testing.""" 

447 sample_rate = 1280 

448 seconds = 10 

449 

450 time_vect = np.linspace(0, seconds, seconds*sample_rate) 

451 f = 5 

452 

453 self.X = np.zeros((len(time_vect), 5)) 

454 self.X[:, 0] = np.sin(2*np.pi*f*time_vect) 

455 self.X[:, 1] = np.sin(2*np.pi*f*time_vect+np.pi/3) 

456 self.X[:, 2] = np.sin(2*np.pi*f*time_vect+np.pi*1.63) 

457 self.X[:, 3] = np.cos(2*np.pi*f*2*time_vect+np.pi/2) 

458 self.X[:, 4] = np.sin(2*np.pi*f*5*time_vect) 

459 

460 def test_num_extrema(self): 

461 """Check that various methods find correct number of extrema.""" 

462 from ..sift import get_padded_extrema 

463 

464 # Check extrema without padding 

465 extr = [50, 50, 50, 100, 250] 

466 for ii in range(5): 

467 l, m = get_padded_extrema(self.X[:, ii], pad_width=0, mode='peaks', method='numpypad') 

468 assert(len(l) == extr[ii]) 

469 assert(len(m) == extr[ii]) 

470 

471 for ii in range(5): 

472 l, m = get_padded_extrema(self.X[:, ii], pad_width=0, mode='troughs', method='numpypad') 

473 assert(len(l) == extr[ii]) 

474 assert(len(m) == extr[ii]) 

475 

476 # Check extrema without padding - both at once 

477 extr = [50, 50, 50, 100, 250] 

478 for ii in range(5): 

479 l, m, l2, m2 = get_padded_extrema(self.X[:, ii], pad_width=0, mode='both', method='numpypad') 

480 assert(len(l) == extr[ii]) 

481 assert(len(m) == extr[ii]) 

482 assert(len(l2) == extr[ii]) 

483 assert(len(m2) == extr[ii]) 

484 

485 def test_numpypad_padding(self): 

486 """Check that numpypad options are working.""" 

487 from ..sift import get_padded_extrema 

488 

489 pads = [0, 1, 5, 10] 

490 extr = 50 

491 for ii in range(len(pads)): 

492 l, m = get_padded_extrema(self.X[:, 0], pad_width=pads[ii], mode='peaks', method='numpypad') 

493 assert(len(l) == extr+2*pads[ii]) 

494 assert(len(m) == extr+2*pads[ii]) 

495 

496 def test_rilling_padding(self): 

497 """Check that numpypad options are working.""" 

498 from ..sift import get_padded_extrema 

499 

500 # Rilling method returns peaks and troughs in both mode 

501 out = get_padded_extrema(self.X[:, 0], pad_width=3, mode='both', method='rilling') 

502 assert(len(out) == 4) 

503 

504 # Rilling method returns only peaks when only peaks are requested 

505 out = get_padded_extrema(self.X[:, 0], pad_width=3, mode='peaks', method='rilling') 

506 assert(len(out) == 2) 

507 

508 pads = [0, 1, 5, 10] 

509 extr = 50 

510 for ii in range(len(pads)): 

511 lp, mp, lt, mt = get_padded_extrema(self.X[:, 0], pad_width=pads[ii], mode='both', method='rilling') 

512 assert(len(lp) == extr+2*pads[ii]) 

513 assert(len(mp) == extr+2*pads[ii]) 

514 

515 def test_envelope_interpolation(self): 

516 """Ensure envelope interpolation is sensible.""" 

517 from ..sift import interp_envelope 

518 

519 env = interp_envelope(self.X[:, 2]) 

520 # Envelope shapes match input 

521 assert(env[0].shape[0] == self.X.shape[0]) 

522 assert(env[1].shape[0] == self.X.shape[0]) 

523 

524 # Envelopes are sufficiently close to +/-1 

525 assert(np.sum((1-env[0])**2) < 1e-3) 

526 assert(np.sum((1+env[1])**2) < 1e-3) 

527 

528 def test_zero_crossing_count(self): 

529 """Ensure we're finding right number of zero crossings.""" 

530 # Use different sinusoids for this one 

531 from ..sift import zero_crossing_count 

532 seconds = 5.1 

533 sample_rate = 1000 

534 time_vect = np.linspace(0, seconds, int(seconds*sample_rate)) 

535 

536 x = np.sin(2*np.pi*2*time_vect) 

537 assert(zero_crossing_count(x) == 21) 

538 

539 x = np.sin(2*np.pi*17*time_vect) 

540 assert(zero_crossing_count(x) == 174) 

541 

542 

543class TestSiftStopping(unittest.TestCase): 

544 """Ensure that sift stopping methods behave.""" 

545 

546 @classmethod 

547 def setUpClass(cls): 

548 """Set up data for testing.""" 

549 # Create core signal 

550 #cls = cls() 

551 seconds = 5.1 

552 sample_rate = 2000 

553 cls.time_vect = np.linspace(0, seconds, int(seconds * sample_rate)) 

554 

555 f1 = 2 

556 cls.x = abreu2010(f1, .2, 0, sample_rate, seconds) 

557 cls.y = np.sin(2*np.pi*5*cls.time_vect) 

558 cls.y2 = cls.y + np.sin(2*np.pi*21*cls.time_vect) 

559 cls.z = np.random.randn(*cls.x.shape) 

560 

561 def test_max_imfs_stop(self): 

562 from ..sift import check_sift_continue 

563 

564 assert(check_sift_continue(self.x, self.x, 3, max_imfs=5))