test_analogsignal.py 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710
  1. # -*- coding: utf-8 -*-
  2. """
  3. Tests of the neo.core.analogsignal.AnalogSignal class and related functions
  4. """
  5. # needed for python 3 compatibility
  6. from __future__ import division
  7. import os
  8. import pickle
  9. try:
  10. import unittest2 as unittest
  11. except ImportError:
  12. import unittest
  13. import numpy as np
  14. import quantities as pq
  15. try:
  16. from IPython.lib.pretty import pretty
  17. except ImportError as err:
  18. HAVE_IPYTHON = False
  19. else:
  20. HAVE_IPYTHON = True
  21. from numpy.testing import assert_array_equal
  22. from neo.core.analogsignal import AnalogSignal, _get_sampling_rate
  23. from neo.core.channelindex import ChannelIndex
  24. from neo.core import Segment
  25. from neo.test.tools import (assert_arrays_almost_equal,
  26. assert_neo_object_is_compliant,
  27. assert_same_sub_schema)
  28. from neo.test.generate_datasets import (get_fake_value, get_fake_values,
  29. fake_neo, TEST_ANNOTATIONS)
  30. class Test__generate_datasets(unittest.TestCase):
  31. def setUp(self):
  32. np.random.seed(0)
  33. self.annotations = dict([(str(x), TEST_ANNOTATIONS[x]) for x in
  34. range(len(TEST_ANNOTATIONS))])
  35. def test__fake_neo__cascade(self):
  36. self.annotations['seed'] = None
  37. obj_type = AnalogSignal
  38. cascade = True
  39. res = fake_neo(obj_type=obj_type, cascade=cascade)
  40. self.assertTrue(isinstance(res, AnalogSignal))
  41. assert_neo_object_is_compliant(res)
  42. self.assertEqual(res.annotations, self.annotations)
  43. def test__fake_neo__nocascade(self):
  44. self.annotations['seed'] = None
  45. obj_type = 'AnalogSignal'
  46. cascade = False
  47. res = fake_neo(obj_type=obj_type, cascade=cascade)
  48. self.assertTrue(isinstance(res, AnalogSignal))
  49. assert_neo_object_is_compliant(res)
  50. self.assertEqual(res.annotations, self.annotations)
  51. class TestAnalogSignalConstructor(unittest.TestCase):
  52. def test__create_from_list(self):
  53. data = range(10)
  54. rate = 1000*pq.Hz
  55. signal = AnalogSignal(data, sampling_rate=rate, units="mV")
  56. assert_neo_object_is_compliant(signal)
  57. self.assertEqual(signal.t_start, 0*pq.ms)
  58. self.assertEqual(signal.t_stop, len(data)/rate)
  59. self.assertEqual(signal[9, 0], 9000*pq.uV)
  60. def test__create_from_np_array(self):
  61. data = np.arange(10.0)
  62. rate = 1*pq.kHz
  63. signal = AnalogSignal(data, sampling_rate=rate, units="uV")
  64. assert_neo_object_is_compliant(signal)
  65. self.assertEqual(signal.t_start, 0*pq.ms)
  66. self.assertEqual(signal.t_stop, data.size/rate)
  67. self.assertEqual(signal[9, 0], 0.009*pq.mV)
  68. def test__create_from_quantities_array(self):
  69. data = np.arange(10.0) * pq.mV
  70. rate = 5000*pq.Hz
  71. signal = AnalogSignal(data, sampling_rate=rate)
  72. assert_neo_object_is_compliant(signal)
  73. self.assertEqual(signal.t_start, 0*pq.ms)
  74. self.assertEqual(signal.t_stop, data.size/rate)
  75. self.assertEqual(signal[9, 0], 0.009*pq.V)
  76. def test__create_from_array_no_units_ValueError(self):
  77. data = np.arange(10.0)
  78. self.assertRaises(ValueError, AnalogSignal, data,
  79. sampling_rate=1 * pq.kHz)
  80. def test__create_from_quantities_array_inconsistent_units_ValueError(self):
  81. data = np.arange(10.0) * pq.mV
  82. self.assertRaises(ValueError, AnalogSignal, data,
  83. sampling_rate=1 * pq.kHz, units="nA")
  84. def test__create_without_sampling_rate_or_period_ValueError(self):
  85. data = np.arange(10.0) * pq.mV
  86. self.assertRaises(ValueError, AnalogSignal, data)
  87. def test__create_with_None_sampling_rate_should_raise_ValueError(self):
  88. data = np.arange(10.0) * pq.mV
  89. self.assertRaises(ValueError, AnalogSignal, data, sampling_rate=None)
  90. def test__create_with_None_t_start_should_raise_ValueError(self):
  91. data = np.arange(10.0) * pq.mV
  92. rate = 5000 * pq.Hz
  93. self.assertRaises(ValueError, AnalogSignal, data,
  94. sampling_rate=rate, t_start=None)
  95. def test__create_inconsistent_sampling_rate_and_period_ValueError(self):
  96. data = np.arange(10.0) * pq.mV
  97. self.assertRaises(ValueError, AnalogSignal, data,
  98. sampling_rate=1 * pq.kHz, sampling_period=5 * pq.s)
  99. def test__create_with_copy_true_should_return_copy(self):
  100. data = np.arange(10.0) * pq.mV
  101. rate = 5000*pq.Hz
  102. signal = AnalogSignal(data, copy=True, sampling_rate=rate)
  103. data[3] = 99*pq.mV
  104. assert_neo_object_is_compliant(signal)
  105. self.assertNotEqual(signal[3, 0], 99*pq.mV)
  106. def test__create_with_copy_false_should_return_view(self):
  107. data = np.arange(10.0) * pq.mV
  108. rate = 5000*pq.Hz
  109. signal = AnalogSignal(data, copy=False, sampling_rate=rate)
  110. data[3] = 99*pq.mV
  111. assert_neo_object_is_compliant(signal)
  112. self.assertEqual(signal[3, 0], 99*pq.mV)
  113. def test__create2D_with_copy_false_should_return_view(self):
  114. data = np.arange(10.0) * pq.mV
  115. data = data.reshape((5, 2))
  116. rate = 5000*pq.Hz
  117. signal = AnalogSignal(data, copy=False, sampling_rate=rate)
  118. data[3, 0] = 99*pq.mV
  119. assert_neo_object_is_compliant(signal)
  120. self.assertEqual(signal[3, 0], 99*pq.mV)
  121. def test__create_with_additional_argument(self):
  122. signal = AnalogSignal([1, 2, 3], units="mV", sampling_rate=1*pq.kHz,
  123. file_origin='crack.txt', ratname='Nicolas')
  124. assert_neo_object_is_compliant(signal)
  125. self.assertEqual(signal.annotations, {'ratname': 'Nicolas'})
  126. # This one is universally recommended and handled by BaseNeo
  127. self.assertEqual(signal.file_origin, 'crack.txt')
  128. # signal must be 1D - should raise Exception if not 1D
  129. class TestAnalogSignalProperties(unittest.TestCase):
  130. def setUp(self):
  131. self.t_start = [0.0*pq.ms, 100*pq.ms, -200*pq.ms]
  132. self.rates = [1*pq.kHz, 420*pq.Hz, 999*pq.Hz]
  133. self.rates2 = [2*pq.kHz, 290*pq.Hz, 1111*pq.Hz]
  134. self.data = [np.arange(10.0)*pq.nA,
  135. np.arange(-100.0, 100.0, 10.0)*pq.mV,
  136. np.random.uniform(size=100)*pq.uV]
  137. self.signals = [AnalogSignal(D, sampling_rate=r, t_start=t,
  138. testattr='test')
  139. for r, D, t in zip(self.rates,
  140. self.data,
  141. self.t_start)]
  142. def test__compliant(self):
  143. for signal in self.signals:
  144. assert_neo_object_is_compliant(signal)
  145. def test__t_stop_getter(self):
  146. for i, signal in enumerate(self.signals):
  147. self.assertEqual(signal.t_stop,
  148. self.t_start[i] + self.data[i].size/self.rates[i])
  149. def test__duration_getter(self):
  150. for signal in self.signals:
  151. self.assertAlmostEqual(signal.duration,
  152. signal.t_stop - signal.t_start,
  153. delta=1e-15)
  154. def test__sampling_rate_getter(self):
  155. for signal, rate in zip(self.signals, self.rates):
  156. self.assertEqual(signal.sampling_rate, rate)
  157. def test__sampling_period_getter(self):
  158. for signal, rate in zip(self.signals, self.rates):
  159. self.assertEqual(signal.sampling_period, 1 / rate)
  160. def test__sampling_rate_setter(self):
  161. for signal, rate in zip(self.signals, self.rates2):
  162. signal.sampling_rate = rate
  163. assert_neo_object_is_compliant(signal)
  164. self.assertEqual(signal.sampling_rate, rate)
  165. self.assertEqual(signal.sampling_period, 1 / rate)
  166. def test__sampling_period_setter(self):
  167. for signal, rate in zip(self.signals, self.rates2):
  168. signal.sampling_period = 1 / rate
  169. assert_neo_object_is_compliant(signal)
  170. self.assertEqual(signal.sampling_rate, rate)
  171. self.assertEqual(signal.sampling_period, 1 / rate)
  172. def test__sampling_rate_setter_None_ValueError(self):
  173. self.assertRaises(ValueError, setattr, self.signals[0],
  174. 'sampling_rate', None)
  175. def test__sampling_rate_setter_not_quantity_ValueError(self):
  176. self.assertRaises(ValueError, setattr, self.signals[0],
  177. 'sampling_rate', 5.5)
  178. def test__sampling_period_setter_None_ValueError(self):
  179. signal = self.signals[0]
  180. assert_neo_object_is_compliant(signal)
  181. self.assertRaises(ValueError, setattr, signal, 'sampling_period', None)
  182. def test__sampling_period_setter_not_quantity_ValueError(self):
  183. self.assertRaises(ValueError, setattr, self.signals[0],
  184. 'sampling_period', 5.5)
  185. def test__t_start_setter_None_ValueError(self):
  186. signal = self.signals[0]
  187. assert_neo_object_is_compliant(signal)
  188. self.assertRaises(ValueError, setattr, signal, 't_start', None)
  189. def test__times_getter(self):
  190. for i, signal in enumerate(self.signals):
  191. targ = np.arange(self.data[i].size)
  192. targ = targ/self.rates[i] + self.t_start[i]
  193. assert_neo_object_is_compliant(signal)
  194. assert_arrays_almost_equal(signal.times, targ, 1e-12*pq.ms)
  195. def test__duplicate_with_new_array(self):
  196. signal1 = self.signals[1]
  197. signal2 = self.signals[2]
  198. data2 = self.data[2]
  199. signal1b = signal1.duplicate_with_new_array(data2)
  200. assert_arrays_almost_equal(np.asarray(signal1b),
  201. np.asarray(signal2/1000.), 1e-12)
  202. self.assertEqual(signal1b.t_start, signal1.t_start)
  203. self.assertEqual(signal1b.sampling_rate, signal1.sampling_rate)
  204. # def test__children(self):
  205. # signal = self.signals[0]
  206. #
  207. # segment = Segment(name='seg1')
  208. # segment.analogsignals = [signal]
  209. # segment.create_many_to_one_relationship()
  210. #
  211. # rchan = RecordingChannel(name='rchan1')
  212. # rchan.analogsignals = [signal]
  213. # rchan.create_many_to_one_relationship()
  214. #
  215. # self.assertEqual(signal._single_parent_objects,
  216. # ('Segment', 'RecordingChannel'))
  217. # self.assertEqual(signal._multi_parent_objects, ())
  218. #
  219. # self.assertEqual(signal._single_parent_containers,
  220. # ('segment', 'recordingchannel'))
  221. # self.assertEqual(signal._multi_parent_containers, ())
  222. #
  223. # self.assertEqual(signal._parent_objects,
  224. # ('Segment', 'RecordingChannel'))
  225. # self.assertEqual(signal._parent_containers,
  226. # ('segment', 'recordingchannel'))
  227. #
  228. # self.assertEqual(len(signal.parents), 2)
  229. # self.assertEqual(signal.parents[0].name, 'seg1')
  230. # self.assertEqual(signal.parents[1].name, 'rchan1')
  231. #
  232. # assert_neo_object_is_compliant(signal)
  233. def test__repr(self):
  234. for i, signal in enumerate(self.signals):
  235. prepr = repr(signal)
  236. targ = '<AnalogSignal(%s, [%s, %s], sampling rate: %s)>' % \
  237. (repr(self.data[i].reshape(-1, 1)),
  238. self.t_start[i],
  239. self.t_start[i] + len(self.data[i])/self.rates[i],
  240. self.rates[i])
  241. self.assertEqual(prepr, targ)
  242. @unittest.skipUnless(HAVE_IPYTHON, "requires IPython")
  243. def test__pretty(self):
  244. for i, signal in enumerate(self.signals):
  245. prepr = pretty(signal)
  246. targ = (('AnalogSignal with %d channels of length %d; units %s; datatype %s \n' %
  247. (signal.shape[1], signal.shape[0], signal.units.dimensionality.unicode, signal.dtype)) +
  248. ('annotations: %s\n' % signal.annotations) +
  249. ('sampling rate: %s\n' % signal.sampling_rate) +
  250. ('time: %s to %s' % (signal.t_start, signal.t_stop)))
  251. self.assertEqual(prepr, targ)
  252. class TestAnalogSignalArrayMethods(unittest.TestCase):
  253. def setUp(self):
  254. self.data1 = np.arange(10.0)
  255. self.data1quant = self.data1 * pq.nA
  256. self.signal1 = AnalogSignal(self.data1quant, sampling_rate=1*pq.kHz,
  257. name='spam', description='eggs',
  258. file_origin='testfile.txt', arg1='test')
  259. self.signal1.segment = 1
  260. self.signal1.channel_index = ChannelIndex(index=[0])
  261. def test__compliant(self):
  262. assert_neo_object_is_compliant(self.signal1)
  263. def test__slice_should_return_AnalogSignalArray(self):
  264. # slice
  265. result = self.signal1[3:8, 0]
  266. self.assertIsInstance(result, AnalogSignal)
  267. assert_neo_object_is_compliant(result)
  268. self.assertEqual(result.name, 'spam') # should slicing really preserve name and description?
  269. self.assertEqual(result.description, 'eggs') # perhaps these should be modified to indicate the slice?
  270. self.assertEqual(result.file_origin, 'testfile.txt')
  271. self.assertEqual(result.annotations, {'arg1': 'test'})
  272. self.assertEqual(result.size, 5)
  273. self.assertEqual(result.sampling_period, self.signal1.sampling_period)
  274. self.assertEqual(result.sampling_rate, self.signal1.sampling_rate)
  275. self.assertEqual(result.t_start,
  276. self.signal1.t_start+3*result.sampling_period)
  277. self.assertEqual(result.t_stop,
  278. result.t_start + 5*result.sampling_period)
  279. assert_array_equal(result.magnitude, self.data1[3:8].reshape(-1, 1))
  280. # Test other attributes were copied over (in this case, defaults)
  281. self.assertEqual(result.file_origin, self.signal1.file_origin)
  282. self.assertEqual(result.name, self.signal1.name)
  283. self.assertEqual(result.description, self.signal1.description)
  284. self.assertEqual(result.annotations, self.signal1.annotations)
  285. def test__slice_should_let_access_to_parents_objects(self):
  286. result = self.signal1.time_slice(1*pq.ms,3*pq.ms)
  287. self.assertEqual(result.segment, self.signal1.segment)
  288. self.assertEqual(result.channel_index, self.signal1.channel_index)
  289. def test__slice_should_change_sampling_period(self):
  290. result1 = self.signal1[:2, 0]
  291. result2 = self.signal1[::2, 0]
  292. result3 = self.signal1[1:7:2, 0]
  293. self.assertIsInstance(result1, AnalogSignal)
  294. assert_neo_object_is_compliant(result1)
  295. self.assertEqual(result1.name, 'spam')
  296. self.assertEqual(result1.description, 'eggs')
  297. self.assertEqual(result1.file_origin, 'testfile.txt')
  298. self.assertEqual(result1.annotations, {'arg1': 'test'})
  299. self.assertIsInstance(result2, AnalogSignal)
  300. assert_neo_object_is_compliant(result2)
  301. self.assertEqual(result2.name, 'spam')
  302. self.assertEqual(result2.description, 'eggs')
  303. self.assertEqual(result2.file_origin, 'testfile.txt')
  304. self.assertEqual(result2.annotations, {'arg1': 'test'})
  305. self.assertIsInstance(result3, AnalogSignal)
  306. assert_neo_object_is_compliant(result3)
  307. self.assertEqual(result3.name, 'spam')
  308. self.assertEqual(result3.description, 'eggs')
  309. self.assertEqual(result3.file_origin, 'testfile.txt')
  310. self.assertEqual(result3.annotations, {'arg1': 'test'})
  311. self.assertEqual(result1.sampling_period, self.signal1.sampling_period)
  312. self.assertEqual(result2.sampling_period,
  313. self.signal1.sampling_period * 2)
  314. self.assertEqual(result3.sampling_period,
  315. self.signal1.sampling_period * 2)
  316. assert_array_equal(result1.magnitude, self.data1[:2].reshape(-1, 1))
  317. assert_array_equal(result2.magnitude, self.data1[::2].reshape(-1, 1))
  318. assert_array_equal(result3.magnitude, self.data1[1:7:2].reshape(-1, 1))
  319. def test__slice_should_modify_linked_channelindex(self):
  320. n = 8 # number of channels
  321. signal = AnalogSignal(np.arange(n * 100.0).reshape(100, n),
  322. sampling_rate=1*pq.kHz,
  323. units="mV")
  324. self.assertEqual(signal.shape, (100, n))
  325. signal.channel_index = ChannelIndex(index=np.arange(n, dtype=int),
  326. channel_names=["channel{0}".format(i) for i in range(n)])
  327. odd_channels = signal[:, 1::2]
  328. self.assertEqual(odd_channels.shape, (100, n//2))
  329. assert_array_equal(odd_channels.channel_index.index, np.arange(n//2, dtype=int))
  330. assert_array_equal(odd_channels.channel_index.channel_names, ["channel{0}".format(i) for i in range(1, n, 2)])
  331. assert_array_equal(signal.channel_index.channel_names, ["channel{0}".format(i) for i in range(n)])
  332. def test__copy_should_let_access_to_parents_objects(self):
  333. ##copy
  334. result = self.signal1.copy()
  335. self.assertEqual(result.segment, self.signal1.segment)
  336. self.assertEqual(result.channel_index, self.signal1.channel_index)
  337. ## deep copy (not fixed yet)
  338. #result = copy.deepcopy(self.signal1)
  339. #self.assertEqual(result.segment, self.signal1.segment)
  340. #self.assertEqual(result.channel_index, self.signal1.channel_index)
  341. def test__getitem_should_return_single_quantity(self):
  342. result1 = self.signal1[0, 0]
  343. result2 = self.signal1[9, 0]
  344. self.assertIsInstance(result1, pq.Quantity)
  345. self.assertFalse(hasattr(result1, 'name'))
  346. self.assertFalse(hasattr(result1, 'description'))
  347. self.assertFalse(hasattr(result1, 'file_origin'))
  348. self.assertFalse(hasattr(result1, 'annotations'))
  349. self.assertIsInstance(result2, pq.Quantity)
  350. self.assertFalse(hasattr(result2, 'name'))
  351. self.assertFalse(hasattr(result2, 'description'))
  352. self.assertFalse(hasattr(result2, 'file_origin'))
  353. self.assertFalse(hasattr(result2, 'annotations'))
  354. self.assertEqual(result1, 0*pq.nA)
  355. self.assertEqual(result2, 9*pq.nA)
  356. def test__getitem_out_of_bounds_IndexError(self):
  357. self.assertRaises(IndexError, self.signal1.__getitem__, (10, 0))
  358. def test_comparison_operators(self):
  359. assert_array_equal(self.signal1 >= 5*pq.nA,
  360. np.array([False, False, False, False, False,
  361. True, True, True, True, True]).reshape(-1, 1))
  362. assert_array_equal(self.signal1 >= 5*pq.pA,
  363. np.array([False, True, True, True, True,
  364. True, True, True, True, True]).reshape(-1, 1))
  365. def test__comparison_with_inconsistent_units_should_raise_Exception(self):
  366. self.assertRaises(ValueError, self.signal1.__gt__, 5*pq.mV)
  367. def test__simple_statistics(self):
  368. self.assertEqual(self.signal1.max(), 9*pq.nA)
  369. self.assertEqual(self.signal1.min(), 0*pq.nA)
  370. self.assertEqual(self.signal1.mean(), 4.5*pq.nA)
  371. def test__rescale_same(self):
  372. result = self.signal1.copy()
  373. result = result.rescale(pq.nA)
  374. self.assertIsInstance(result, AnalogSignal)
  375. assert_neo_object_is_compliant(result)
  376. self.assertEqual(result.name, 'spam')
  377. self.assertEqual(result.description, 'eggs')
  378. self.assertEqual(result.file_origin, 'testfile.txt')
  379. self.assertEqual(result.annotations, {'arg1': 'test'})
  380. self.assertEqual(result.units, 1*pq.nA)
  381. assert_array_equal(result.magnitude, self.data1.reshape(-1, 1))
  382. assert_same_sub_schema(result, self.signal1)
  383. def test__rescale_new(self):
  384. result = self.signal1.copy()
  385. result = result.rescale(pq.pA)
  386. self.assertIsInstance(result, AnalogSignal)
  387. assert_neo_object_is_compliant(result)
  388. self.assertEqual(result.name, 'spam')
  389. self.assertEqual(result.description, 'eggs')
  390. self.assertEqual(result.file_origin, 'testfile.txt')
  391. self.assertEqual(result.annotations, {'arg1': 'test'})
  392. self.assertEqual(result.units, 1*pq.pA)
  393. assert_arrays_almost_equal(np.array(result), self.data1.reshape(-1, 1)*1000., 1e-10)
  394. def test__rescale_new_incompatible_ValueError(self):
  395. self.assertRaises(ValueError, self.signal1.rescale, pq.mV)
  396. def test_as_array(self):
  397. sig_as_arr = self.signal1.as_array()
  398. self.assertIsInstance(sig_as_arr, np.ndarray)
  399. assert_array_equal(self.data1, sig_as_arr.flat)
  400. def test_as_quantity(self):
  401. sig_as_q = self.signal1.as_quantity()
  402. self.assertIsInstance(sig_as_q, pq.Quantity)
  403. assert_array_equal(self.data1, sig_as_q.magnitude.flat)
  404. class TestAnalogSignalEquality(unittest.TestCase):
  405. def test__signals_with_different_data_complement_should_be_not_equal(self):
  406. signal1 = AnalogSignal(np.arange(10.0), units="mV",
  407. sampling_rate=1*pq.kHz)
  408. signal2 = AnalogSignal(np.arange(10.0), units="mV",
  409. sampling_rate=2*pq.kHz)
  410. assert_neo_object_is_compliant(signal1)
  411. assert_neo_object_is_compliant(signal2)
  412. self.assertNotEqual(signal1, signal2)
  413. class TestAnalogSignalCombination(unittest.TestCase):
  414. def setUp(self):
  415. self.data1 = np.arange(10.0)
  416. self.data1quant = self.data1 * pq.mV
  417. self.signal1 = AnalogSignal(self.data1quant,
  418. sampling_rate=1*pq.kHz,
  419. name='spam', description='eggs',
  420. file_origin='testfile.txt',
  421. arg1='test')
  422. def test__compliant(self):
  423. assert_neo_object_is_compliant(self.signal1)
  424. self.assertEqual(self.signal1.name, 'spam')
  425. self.assertEqual(self.signal1.description, 'eggs')
  426. self.assertEqual(self.signal1.file_origin, 'testfile.txt')
  427. self.assertEqual(self.signal1.annotations, {'arg1': 'test'})
  428. def test__add_const_quantity_should_preserve_data_complement(self):
  429. result = self.signal1 + 0.065*pq.V
  430. self.assertIsInstance(result, AnalogSignal)
  431. assert_neo_object_is_compliant(result)
  432. self.assertEqual(result.name, 'spam')
  433. self.assertEqual(result.description, 'eggs')
  434. self.assertEqual(result.file_origin, 'testfile.txt')
  435. self.assertEqual(result.annotations, {'arg1': 'test'})
  436. assert_array_equal(result.magnitude.flatten(), self.data1 + 65)
  437. self.assertEqual(self.signal1[9, 0], 9*pq.mV)
  438. self.assertEqual(result[9, 0], 74*pq.mV)
  439. self.assertEqual(self.signal1.t_start, result.t_start)
  440. self.assertEqual(self.signal1.sampling_rate, result.sampling_rate)
  441. def test__add_quantity_should_preserve_data_complement(self):
  442. data2 = np.arange(10.0, 20.0).reshape(-1, 1)
  443. data2quant = data2*pq.mV
  444. result = self.signal1 + data2quant
  445. self.assertIsInstance(result, AnalogSignal)
  446. assert_neo_object_is_compliant(result)
  447. self.assertEqual(result.name, 'spam')
  448. self.assertEqual(result.description, 'eggs')
  449. self.assertEqual(result.file_origin, 'testfile.txt')
  450. self.assertEqual(result.annotations, {'arg1': 'test'})
  451. targ = AnalogSignal(np.arange(10.0, 30.0, 2.0), units="mV",
  452. sampling_rate=1*pq.kHz,
  453. name='spam', description='eggs',
  454. file_origin='testfile.txt', arg1='test')
  455. assert_neo_object_is_compliant(targ)
  456. assert_array_equal(result, targ)
  457. assert_same_sub_schema(result, targ)
  458. def test__add_two_consistent_signals_should_preserve_data_complement(self):
  459. data2 = np.arange(10.0, 20.0)
  460. data2quant = data2*pq.mV
  461. signal2 = AnalogSignal(data2quant, sampling_rate=1*pq.kHz)
  462. assert_neo_object_is_compliant(signal2)
  463. result = self.signal1 + signal2
  464. self.assertIsInstance(result, AnalogSignal)
  465. assert_neo_object_is_compliant(result)
  466. self.assertEqual(result.name, 'spam')
  467. self.assertEqual(result.description, 'eggs')
  468. self.assertEqual(result.file_origin, 'testfile.txt')
  469. self.assertEqual(result.annotations, {'arg1': 'test'})
  470. targ = AnalogSignal(np.arange(10.0, 30.0, 2.0), units="mV",
  471. sampling_rate=1*pq.kHz,
  472. name='spam', description='eggs',
  473. file_origin='testfile.txt', arg1='test')
  474. assert_neo_object_is_compliant(targ)
  475. assert_array_equal(result, targ)
  476. assert_same_sub_schema(result, targ)
  477. def test__add_signals_with_inconsistent_data_complement_ValueError(self):
  478. self.signal1.t_start = 0.0*pq.ms
  479. assert_neo_object_is_compliant(self.signal1)
  480. signal2 = AnalogSignal(np.arange(10.0), units="mV",
  481. t_start=100.0*pq.ms, sampling_rate=0.5*pq.kHz)
  482. assert_neo_object_is_compliant(signal2)
  483. self.assertRaises(ValueError, self.signal1.__add__, signal2)
  484. def test__subtract_const_should_preserve_data_complement(self):
  485. result = self.signal1 - 65*pq.mV
  486. self.assertIsInstance(result, AnalogSignal)
  487. assert_neo_object_is_compliant(result)
  488. self.assertEqual(result.name, 'spam')
  489. self.assertEqual(result.description, 'eggs')
  490. self.assertEqual(result.file_origin, 'testfile.txt')
  491. self.assertEqual(result.annotations, {'arg1': 'test'})
  492. self.assertEqual(self.signal1[9, 0], 9*pq.mV)
  493. self.assertEqual(result[9, 0], -56*pq.mV)
  494. assert_array_equal(result.magnitude.flatten(), self.data1 - 65)
  495. self.assertEqual(self.signal1.sampling_rate, result.sampling_rate)
  496. def test__subtract_from_const_should_return_signal(self):
  497. result = 10*pq.mV - self.signal1
  498. self.assertIsInstance(result, AnalogSignal)
  499. assert_neo_object_is_compliant(result)
  500. self.assertEqual(result.name, 'spam')
  501. self.assertEqual(result.description, 'eggs')
  502. self.assertEqual(result.file_origin, 'testfile.txt')
  503. self.assertEqual(result.annotations, {'arg1': 'test'})
  504. self.assertEqual(self.signal1[9, 0], 9*pq.mV)
  505. self.assertEqual(result[9, 0], 1*pq.mV)
  506. assert_array_equal(result.magnitude.flatten(), 10 - self.data1)
  507. self.assertEqual(self.signal1.sampling_rate, result.sampling_rate)
  508. def test__mult_by_const_float_should_preserve_data_complement(self):
  509. result = self.signal1*2
  510. self.assertIsInstance(result, AnalogSignal)
  511. assert_neo_object_is_compliant(result)
  512. self.assertEqual(result.name, 'spam')
  513. self.assertEqual(result.description, 'eggs')
  514. self.assertEqual(result.file_origin, 'testfile.txt')
  515. self.assertEqual(result.annotations, {'arg1': 'test'})
  516. self.assertEqual(self.signal1[9, 0], 9*pq.mV)
  517. self.assertEqual(result[9, 0], 18*pq.mV)
  518. assert_array_equal(result.magnitude.flatten(), self.data1*2)
  519. self.assertEqual(self.signal1.sampling_rate, result.sampling_rate)
  520. def test__divide_by_const_should_preserve_data_complement(self):
  521. result = self.signal1/0.5
  522. self.assertIsInstance(result, AnalogSignal)
  523. assert_neo_object_is_compliant(result)
  524. self.assertEqual(result.name, 'spam')
  525. self.assertEqual(result.description, 'eggs')
  526. self.assertEqual(result.file_origin, 'testfile.txt')
  527. self.assertEqual(result.annotations, {'arg1': 'test'})
  528. self.assertEqual(self.signal1[9, 0], 9*pq.mV)
  529. self.assertEqual(result[9, 0], 18*pq.mV)
  530. assert_array_equal(result.magnitude.flatten(), self.data1/0.5)
  531. self.assertEqual(self.signal1.sampling_rate, result.sampling_rate)
  532. class TestAnalogSignalFunctions(unittest.TestCase):
  533. def test__pickle(self):
  534. signal1 = AnalogSignal([1, 2, 3, 4], sampling_period=1*pq.ms,
  535. units=pq.S)
  536. signal1.annotations['index'] = 2
  537. signal1.channel_index = ChannelIndex(index=[0])
  538. fobj = open('./pickle', 'wb')
  539. pickle.dump(signal1, fobj)
  540. fobj.close()
  541. fobj = open('./pickle', 'rb')
  542. try:
  543. signal2 = pickle.load(fobj)
  544. except ValueError:
  545. signal2 = None
  546. assert_array_equal(signal1, signal2)
  547. assert_array_equal(signal2.channel_index.index, np.array([0]))
  548. fobj.close()
  549. os.remove('./pickle')
  550. class TestAnalogSignalSampling(unittest.TestCase):
  551. def test___get_sampling_rate__period_none_rate_none_ValueError(self):
  552. sampling_rate = None
  553. sampling_period = None
  554. self.assertRaises(ValueError, _get_sampling_rate,
  555. sampling_rate, sampling_period)
  556. def test___get_sampling_rate__period_quant_rate_none(self):
  557. sampling_rate = None
  558. sampling_period = pq.Quantity(10., units=pq.s)
  559. targ_rate = 1/sampling_period
  560. out_rate = _get_sampling_rate(sampling_rate, sampling_period)
  561. self.assertEqual(targ_rate, out_rate)
  562. def test___get_sampling_rate__period_none_rate_quant(self):
  563. sampling_rate = pq.Quantity(10., units=pq.Hz)
  564. sampling_period = None
  565. targ_rate = sampling_rate
  566. out_rate = _get_sampling_rate(sampling_rate, sampling_period)
  567. self.assertEqual(targ_rate, out_rate)
  568. def test___get_sampling_rate__period_rate_equivalent(self):
  569. sampling_rate = pq.Quantity(10., units=pq.Hz)
  570. sampling_period = pq.Quantity(0.1, units=pq.s)
  571. targ_rate = sampling_rate
  572. out_rate = _get_sampling_rate(sampling_rate, sampling_period)
  573. self.assertEqual(targ_rate, out_rate)
  574. def test___get_sampling_rate__period_rate_not_equivalent_ValueError(self):
  575. sampling_rate = pq.Quantity(10., units=pq.Hz)
  576. sampling_period = pq.Quantity(10, units=pq.s)
  577. self.assertRaises(ValueError, _get_sampling_rate,
  578. sampling_rate, sampling_period)
  579. def test___get_sampling_rate__period_none_rate_float_TypeError(self):
  580. sampling_rate = 10.
  581. sampling_period = None
  582. self.assertRaises(TypeError, _get_sampling_rate,
  583. sampling_rate, sampling_period)
  584. def test___get_sampling_rate__period_array_rate_none_TypeError(self):
  585. sampling_rate = None
  586. sampling_period = np.array(10.)
  587. self.assertRaises(TypeError, _get_sampling_rate,
  588. sampling_rate, sampling_period)
  589. if __name__ == "__main__":
  590. unittest.main()