From 8f07189c5fb9581bf33d6a9b52b21efd357395bc Mon Sep 17 00:00:00 2001 From: yahym Date: Wed, 13 Dec 2017 10:18:01 +0200 Subject: [PATCH 001/117] fix codacy errors --- test/test_mdf3.py | 2 -- test/test_mdf4.py | 2 -- test/utils.py | 3 --- 3 files changed, 7 deletions(-) diff --git a/test/test_mdf3.py b/test/test_mdf3.py index b853d183a..d69042324 100644 --- a/test/test_mdf3.py +++ b/test/test_mdf3.py @@ -1,6 +1,4 @@ #!/usr/bin/env python -import os -import sys import unittest from utils import get_test_data diff --git a/test/test_mdf4.py b/test/test_mdf4.py index 7ff789722..89f2a89c4 100644 --- a/test/test_mdf4.py +++ b/test/test_mdf4.py @@ -1,6 +1,4 @@ #!/usr/bin/env python -import os -import sys import unittest from utils import get_test_data diff --git a/test/utils.py b/test/utils.py index 3dd2fb86d..fdb491b14 100644 --- a/test/utils.py +++ b/test/utils.py @@ -1,8 +1,5 @@ #!/usr/bin/env python import os -import sys - -here = os.path.dirname(os.path.dirname(os.path.realpath(__file__))) def get_test_data(filename=""): From 22d679c81bcb279ffc3ce2034a228135ffa7966b Mon Sep 17 00:00:00 2001 From: yahym Date: Wed, 13 Dec 2017 23:37:36 +0200 Subject: [PATCH 002/117] - fix return value of test results, to reflect the real build status - fix typo in test methods naming --- test/run_all.py | 2 +- test/test_mdf2.py | 4 ++-- test/test_mdf3.py | 2 +- test/test_mdf4.py | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/test/run_all.py b/test/run_all.py index 049bf13be..adcb84373 100644 --- a/test/run_all.py +++ b/test/run_all.py @@ -16,7 +16,7 @@ def main(): tests = unittest.TestLoader().discover('.', 'test_*.py') testResult = xmlrunner.XMLTestRunner(output='test-reports').run(tests) - return not testResult.wasSuccessful() + return int(not testResult.wasSuccessful()) if __name__ == '__main__': sys.exit(main()) \ No newline at end of file diff --git a/test/test_mdf2.py b/test/test_mdf2.py index 77fcf8714..191a9632c 100644 --- a/test/test_mdf2.py +++ b/test/test_mdf2.py @@ -8,9 +8,9 @@ -class TestMDF3(unittest.TestCase): +class TestMDF2(unittest.TestCase): - def test_measurement(self): + def test_mdf2_exists(self): self.assertTrue(MDF2) def test_read_mdf2_00(self): diff --git a/test/test_mdf3.py b/test/test_mdf3.py index 57e056797..67eb5b940 100644 --- a/test/test_mdf3.py +++ b/test/test_mdf3.py @@ -8,7 +8,7 @@ class TestMDF3(unittest.TestCase): - def test_measurement(self): + def test_mdf3_exists(self): self.assertTrue(MDF3) def test_read_mdf3_00(self): diff --git a/test/test_mdf4.py b/test/test_mdf4.py index 89f2a89c4..b078a3cdc 100644 --- a/test/test_mdf4.py +++ b/test/test_mdf4.py @@ -7,7 +7,7 @@ class TestMDF4(unittest.TestCase): - def test_measurement(self): + def test_mdf4_exists(self): self.assertTrue(MDF4) def test_read_mdf4_00(self): From b0ff63e3465e1faa7daee83dc423a57dc208900c Mon Sep 17 00:00:00 2001 From: yahym Date: Wed, 13 Dec 2017 23:47:07 +0200 Subject: [PATCH 003/117] - move pylint to after_success to have the build failed if tests are failed - it seems that travis does not accumulate the returned values --- .travis.yml | 4 ++-- test/run_all.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 00643019c..7e67fc226 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,7 +13,7 @@ script: - python --version - python -m coverage run test/run_all.py - python -m coverage xml -i --include *\\asammdf\\* - - python -m pylint --rcfile pylint.cfg -f parseable asammdf || exit 0 - + after_success: - coveralls + - python -m pylint --rcfile pylint.cfg -f parseable asammdf diff --git a/test/run_all.py b/test/run_all.py index adcb84373..049bf13be 100644 --- a/test/run_all.py +++ b/test/run_all.py @@ -16,7 +16,7 @@ def main(): tests = unittest.TestLoader().discover('.', 'test_*.py') testResult = xmlrunner.XMLTestRunner(output='test-reports').run(tests) - return int(not testResult.wasSuccessful()) + return not testResult.wasSuccessful() if __name__ == '__main__': sys.exit(main()) \ No newline at end of file From 384f55bffd361e248a0b85345605a9d2b5bc1d4b Mon Sep 17 00:00:00 2001 From: yahym Date: Thu, 14 Dec 2017 01:07:43 +0200 Subject: [PATCH 004/117] - `set -e` is used to fail the build immediate --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 7e67fc226..01fef6cd9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,6 +10,7 @@ install: - pip install -r pip_requirements_tests.txt # command to run tests script: + - set -e - python --version - python -m coverage run test/run_all.py - python -m coverage xml -i --include *\\asammdf\\* From 9572293d4ff0e30704359ff125348cb46b45358c Mon Sep 17 00:00:00 2001 From: yahym Date: Thu, 14 Dec 2017 23:00:44 +0200 Subject: [PATCH 005/117] it seems that path is os dependent or? I do not explain the failed build. --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 01fef6cd9..8d1221b80 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,7 +13,7 @@ script: - set -e - python --version - python -m coverage run test/run_all.py - - python -m coverage xml -i --include *\\asammdf\\* + - python -m coverage xml -i --include */asammdf/* after_success: - coveralls From 4676ad7bdff2db70d5f2cbc02fc493619f221793 Mon Sep 17 00:00:00 2001 From: yahym Date: Thu, 14 Dec 2017 23:28:55 +0200 Subject: [PATCH 006/117] comment out coveralls, need to be configured first --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 8d1221b80..4c02d982f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -16,5 +16,5 @@ script: - python -m coverage xml -i --include */asammdf/* after_success: - - coveralls - python -m pylint --rcfile pylint.cfg -f parseable asammdf +# - coveralls From 5dfb94fedb877bcc27e6ffebd643851aadf9cc02 Mon Sep 17 00:00:00 2001 From: yahym Date: Thu, 14 Dec 2017 23:31:17 +0200 Subject: [PATCH 007/117] ERROR: An error occured while trying to fetch your .travis.yml file. very complicated for me - this travis-ci stuff :( --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 4c02d982f..96d54a1d1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -17,4 +17,3 @@ script: after_success: - python -m pylint --rcfile pylint.cfg -f parseable asammdf -# - coveralls From 677ac262f1aa553c866f76429c89e6a6b43a73a8 Mon Sep 17 00:00:00 2001 From: yahym Date: Thu, 14 Dec 2017 23:37:32 +0200 Subject: [PATCH 008/117] - pylint exits with 0 to avoid fail job for now - it seems that after_success fail the build if script exit with != 0 - is it in combination with set -e command? --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 96d54a1d1..427093954 100644 --- a/.travis.yml +++ b/.travis.yml @@ -16,4 +16,4 @@ script: - python -m coverage xml -i --include */asammdf/* after_success: - - python -m pylint --rcfile pylint.cfg -f parseable asammdf + - python -m pylint --rcfile pylint.cfg -f parseable asammdf || exit 0 From 9a75ab2dc38264613f2d4b06a1340cce7dce13d1 Mon Sep 17 00:00:00 2001 From: yahym Date: Fri, 15 Dec 2017 01:14:55 +0200 Subject: [PATCH 009/117] - add tests based on provided examples within docs - why not creating tests and reference them into documentation to shoot two rabbits... rhetorical --- test/test_mdf.py | 43 +++++++++++++++++++++++++++++ test/test_mdf2.py | 3 +- test/test_mdf3.py | 70 ++++++++++++++++++++++++++++++++++++++++++++++- test/test_mdf4.py | 49 ++++++++++++++++++++++++++++++++- test/utils.py | 2 +- test/vectors.py | 31 +++++++++++++++++++++ 6 files changed, 193 insertions(+), 5 deletions(-) create mode 100644 test/test_mdf.py create mode 100644 test/vectors.py diff --git a/test/test_mdf.py b/test/test_mdf.py new file mode 100644 index 000000000..23bf41172 --- /dev/null +++ b/test/test_mdf.py @@ -0,0 +1,43 @@ +# -*- coding: utf-8 -*- +import os +import sys +import unittest +import numpy as np + +from utils import get_test_data +from asammdf import MDF + +from vectors import s_uint8, s_int32, s_float64, signals + + +class TestMDF(unittest.TestCase): + + def setUp(self): + # mdf3_20 + mdf3_20 = MDF(version='3.20') + mdf3_20.append(signals, 'mdf3_20') + mdf3_20.save('mdf3_20.mdf', overwrite=True) + mdf3_20.close() + + def tearDown(self): + try: + # mdf3_20 + if os.path.isfile('mdf3_20.mdf'): + os.remove('mdf3_20.mdf') + # mdf4_10 + if os.path.isfile('mdf4_10.mf4'): + os.remove('mdf4_10.mf4') + except: + pass + + def test_mdf_exists(self): + self.assertTrue(MDF) + + # convert from mdf3 to mdf4 + def test_convert_from_mdf3_20_to_mdf4_10(self): + meas = MDF('mdf3_20.mdf') + converted = meas.convert(to='4.10', memory='minimum') + self.assertEqual(converted.version, '4.10') + +if __name__ == '__main__': + unittest.main() diff --git a/test/test_mdf2.py b/test/test_mdf2.py index 191a9632c..7e7390f4d 100644 --- a/test/test_mdf2.py +++ b/test/test_mdf2.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +# -*- coding: utf-8 -*- import os import sys import unittest @@ -7,7 +7,6 @@ from asammdf import MDF2 - class TestMDF2(unittest.TestCase): def test_mdf2_exists(self): diff --git a/test/test_mdf3.py b/test/test_mdf3.py index 67eb5b940..aa91cb230 100644 --- a/test/test_mdf3.py +++ b/test/test_mdf3.py @@ -1,16 +1,56 @@ -#!/usr/bin/env python +# -*- coding: utf-8 -*- +import os +import sys import unittest +import numpy as np from utils import get_test_data from asammdf import MDF3 +from vectors import s_uint8, s_int32, s_float64, signals class TestMDF3(unittest.TestCase): + def setUp(self): + # mdf3_00 + mdf3_00 = MDF3(version='3.00') + mdf3_00.append(signals, 'mdf3_00') + mdf3_00.save('mdf3_00.mdf', overwrite=True) + mdf3_00.close() + + # mdf3_10 + mdf3_10 = MDF3(version='3.10') + mdf3_10.append(signals, 'mdf3_10') + mdf3_10.save('mdf3_10.mdf', overwrite=True) + mdf3_10.close() + + # mdf3_20 + mdf3_20 = MDF3(version='3.20') + mdf3_20.append(signals, 'mdf3_20') + mdf3_20.save('mdf3_20.mdf', overwrite=True) + mdf3_20.close() + + def tearDown(self): + try: + # mdf3_00 + if os.path.isfile('mdf3_00.mdf'): + os.remove('mdf3_00.mdf') + + # mdf3_10 + if os.path.isfile('mdf3_10.mdf'): + os.remove('mdf3_10.mdf') + + # mdf3_20 + if os.path.isfile('mdf3_20.mdf'): + os.remove('mdf3_20.mdf') + except: + pass + def test_mdf3_exists(self): self.assertTrue(MDF3) + # read mdf3 def test_read_mdf3_00(self): self.assertTrue(MDF3(get_test_data('test_meas_3.00.mdf'))) @@ -20,6 +60,34 @@ def test_read_mdf3_10(self): def test_read_mdf3_20(self): self.assertTrue(MDF3(get_test_data('test_meas_3.20.mdf'))) + # create mdf3 + def test_create_mdf3_00(self): + meas = MDF3('mdf3_00.mdf') + + self.assertEqual(s_uint8, meas.get(s_uint8.name)) + self.assertEqual(s_uint8.unit, meas.get(s_uint8.name).unit) + # self.assertEqual(s_uint8.info, meas.get(s_uint8.name).info) + # self.assertEqual(s_uint8.comment, meas.get(s_uint8.name).comment) + + def test_create_mdf3_10(self): + meas = MDF3('mdf3_10.mdf') + + self.assertEqual(s_int32, meas.get(s_int32.name)) + self.assertEqual(s_int32.unit, meas.get(s_int32.name).unit) + + # tests below are failed + # self.assertEqual(s_int32.info, meas.get(s_int32.name).info) + # self.assertEqual(s_int32.comment, meas.get(s_int32.name).comment) + + def test_create_mdf3_20(self): + meas = MDF3('mdf3_20.mdf') + self.assertEqual(s_float64, meas.get(s_float64.name), 'signal == channel') + self.assertEqual(s_float64.unit, meas.get(s_float64.name).unit, 'unit') + + # tests below are failed + # self.assertEqual(s_float64.info, meas.get(s_float64.name).info, 'info') + # self.assertEqual(s_float64.comment, meas.get(s_float64.name).comment, 'comment') + if __name__ == '__main__': unittest.main() diff --git a/test/test_mdf4.py b/test/test_mdf4.py index b078a3cdc..be765e361 100644 --- a/test/test_mdf4.py +++ b/test/test_mdf4.py @@ -1,12 +1,41 @@ -#!/usr/bin/env python +# -*- coding: utf-8 -*- +import os import unittest +import numpy as np from utils import get_test_data from asammdf import MDF4 +from vectors import s_uint8, s_int32, s_float64, signals + class TestMDF4(unittest.TestCase): + def setUp(self): + # mdf4_00 + mdf4_00 = MDF4(version='4.00') + mdf4_00.append(signals, 'mdf4_00') + mdf4_00.save('mdf4_00.mf4', overwrite=True) + mdf4_00.close() + + # mdf4_10 + mdf4_10 = MDF4(version='4.10') + mdf4_10.append(signals, 'mdf4_10') + mdf4_10.save('mdf4_10.mf4', overwrite=True) + mdf4_10.close() + + def tearDown(self): + try: + # mdf4_00 + if os.path.isfile('mdf4_00.mf4'): + os.remove('mdf4_00.mf4') + + # mdf4_10 + if os.path.isfile('mdf4_10.mf4'): + os.remove('mdf4_10.mf4') + except: + pass + def test_mdf4_exists(self): self.assertTrue(MDF4) @@ -16,6 +45,24 @@ def test_read_mdf4_00(self): def test_read_mdf4_10(self): self.assertTrue(MDF4(get_test_data('test_meas_4.10.mf4'))) + # create mdf4 + def test_create_mdf4_00(self): + meas = MDF4('mdf4_00.mf4') + + self.assertEqual(s_uint8, meas.get(s_uint8.name)) + self.assertEqual(s_uint8.unit, meas.get(s_uint8.name).unit) + # self.assertEqual(s_uint8.info, meas.get(s_uint8.name).info) + # self.assertEqual(s_uint8.comment, meas.get(s_uint8.name).comment) + + def test_create_mdf4_10(self): + meas = MDF4('mdf4_10.mf4') + + self.assertEqual(s_int32, meas.get(s_int32.name)) + self.assertEqual(s_int32.unit, meas.get(s_int32.name).unit) + + # tests below are failed + # self.assertEqual(s_int32.info, meas.get(s_int32.name).info) + # self.assertEqual(s_int32.comment, meas.get(s_int32.name).comment) if __name__ == '__main__': unittest.main() diff --git a/test/utils.py b/test/utils.py index fdb491b14..ca584189a 100644 --- a/test/utils.py +++ b/test/utils.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +# -*- coding: utf-8 -*- import os diff --git a/test/vectors.py b/test/vectors.py new file mode 100644 index 000000000..20acd9fcc --- /dev/null +++ b/test/vectors.py @@ -0,0 +1,31 @@ +# -*- coding: utf-8 -*- +import numpy as np +from asammdf.signal import Signal +# create 3 Signal objects +timestamps = np.array([0.1, 0.2, 0.3, 0.4, 0.5], dtype=np.float32) + +# unit8 +s_uint8 = Signal(samples=np.array([0, 1, 2, 3, 4], dtype=np.uint8), + timestamps=timestamps, + name='Uint8_Signal', + unit='u1', + info='s_uint8 info', + comment='s_uint8 comment') +# int32 +s_int32 = Signal(samples=np.array([-20, -10, 0, 10, 20], dtype=np.int32), + timestamps=timestamps, + name='Int32_Signal', + unit='i4', + info='s_int32 info', + comment='s_int32 comment') + +# float64 +s_float64 = Signal(samples=np.array([-20, -10, 0, 10, 20], dtype=np.float64), + timestamps=timestamps, + name='Float64_Signal', + unit='f8', + info='s_float64 info', + comment='s_float64 comment') + +# create signal list +signals = [s_uint8, s_int32, s_float64] From 0c92293ebadd8a6e5afe095de37930e771ff449a Mon Sep 17 00:00:00 2001 From: yahym Date: Fri, 15 Dec 2017 01:25:39 +0200 Subject: [PATCH 010/117] fix codacy errors - you can't live with it, you can't leave without it --- test/test_mdf.py | 7 +------ test/test_mdf3.py | 3 +-- test/test_mdf4.py | 3 +-- test/vectors.py | 3 +++ 4 files changed, 6 insertions(+), 10 deletions(-) diff --git a/test/test_mdf.py b/test/test_mdf.py index 23bf41172..8796b1ba2 100644 --- a/test/test_mdf.py +++ b/test/test_mdf.py @@ -1,14 +1,9 @@ # -*- coding: utf-8 -*- import os -import sys import unittest -import numpy as np -from utils import get_test_data from asammdf import MDF -from vectors import s_uint8, s_int32, s_float64, signals - class TestMDF(unittest.TestCase): @@ -27,7 +22,7 @@ def tearDown(self): # mdf4_10 if os.path.isfile('mdf4_10.mf4'): os.remove('mdf4_10.mf4') - except: + except Exception as ex: pass def test_mdf_exists(self): diff --git a/test/test_mdf3.py b/test/test_mdf3.py index aa91cb230..82e236ed2 100644 --- a/test/test_mdf3.py +++ b/test/test_mdf3.py @@ -2,7 +2,6 @@ import os import sys import unittest -import numpy as np from utils import get_test_data from asammdf import MDF3 @@ -44,7 +43,7 @@ def tearDown(self): # mdf3_20 if os.path.isfile('mdf3_20.mdf'): os.remove('mdf3_20.mdf') - except: + except Exception as ex: pass def test_mdf3_exists(self): diff --git a/test/test_mdf4.py b/test/test_mdf4.py index be765e361..158981577 100644 --- a/test/test_mdf4.py +++ b/test/test_mdf4.py @@ -1,7 +1,6 @@ # -*- coding: utf-8 -*- import os import unittest -import numpy as np from utils import get_test_data from asammdf import MDF4 @@ -33,7 +32,7 @@ def tearDown(self): # mdf4_10 if os.path.isfile('mdf4_10.mf4'): os.remove('mdf4_10.mf4') - except: + except Exception as ex: pass def test_mdf4_exists(self): diff --git a/test/vectors.py b/test/vectors.py index 20acd9fcc..23c980b44 100644 --- a/test/vectors.py +++ b/test/vectors.py @@ -1,6 +1,9 @@ # -*- coding: utf-8 -*- import numpy as np + from asammdf.signal import Signal + + # create 3 Signal objects timestamps = np.array([0.1, 0.2, 0.3, 0.4, 0.5], dtype=np.float32) From 3adf2c446075e4103ea9ecdd2411b5371cfe774d Mon Sep 17 00:00:00 2001 From: yahym Date: Fri, 15 Dec 2017 01:31:36 +0200 Subject: [PATCH 011/117] add back the signals - too much clean will kill you --- test/test_mdf.py | 1 + 1 file changed, 1 insertion(+) diff --git a/test/test_mdf.py b/test/test_mdf.py index 8796b1ba2..1c72ddbaa 100644 --- a/test/test_mdf.py +++ b/test/test_mdf.py @@ -3,6 +3,7 @@ import unittest from asammdf import MDF +from vectors import signals class TestMDF(unittest.TestCase): From d6495130836e1b1efcb2e646cc5d7fab12f5d2b2 Mon Sep 17 00:00:00 2001 From: yahym Date: Fri, 15 Dec 2017 01:46:50 +0200 Subject: [PATCH 012/117] - fix codacy again - if is there any way to check it locally will be great to be documented on this repo somehow. - remove test related packages from pip_requirements_readthedocs.txt --- pip_requirements_readthedocs.txt | 6 +----- test/test_mdf.py | 2 +- test/test_mdf3.py | 2 +- test/test_mdf4.py | 4 ++-- 4 files changed, 5 insertions(+), 9 deletions(-) diff --git a/pip_requirements_readthedocs.txt b/pip_requirements_readthedocs.txt index dc921e98b..275a95098 100644 --- a/pip_requirements_readthedocs.txt +++ b/pip_requirements_readthedocs.txt @@ -5,8 +5,4 @@ pandas matplotlib wheel sphinx-argparse -# test -coveralls -coverage -pylint -xmlrunner + diff --git a/test/test_mdf.py b/test/test_mdf.py index 1c72ddbaa..d7ad6dad3 100644 --- a/test/test_mdf.py +++ b/test/test_mdf.py @@ -23,7 +23,7 @@ def tearDown(self): # mdf4_10 if os.path.isfile('mdf4_10.mf4'): os.remove('mdf4_10.mf4') - except Exception as ex: + except Exception: pass def test_mdf_exists(self): diff --git a/test/test_mdf3.py b/test/test_mdf3.py index 82e236ed2..4c5397613 100644 --- a/test/test_mdf3.py +++ b/test/test_mdf3.py @@ -43,7 +43,7 @@ def tearDown(self): # mdf3_20 if os.path.isfile('mdf3_20.mdf'): os.remove('mdf3_20.mdf') - except Exception as ex: + except Exception: pass def test_mdf3_exists(self): diff --git a/test/test_mdf4.py b/test/test_mdf4.py index 158981577..25c34a705 100644 --- a/test/test_mdf4.py +++ b/test/test_mdf4.py @@ -5,7 +5,7 @@ from utils import get_test_data from asammdf import MDF4 -from vectors import s_uint8, s_int32, s_float64, signals +from vectors import s_uint8, s_int32, signals class TestMDF4(unittest.TestCase): @@ -32,7 +32,7 @@ def tearDown(self): # mdf4_10 if os.path.isfile('mdf4_10.mf4'): os.remove('mdf4_10.mf4') - except Exception as ex: + except Exception: pass def test_mdf4_exists(self): From 2603c95c1c1be9a98785d297f2f50b5eb3b34c23 Mon Sep 17 00:00:00 2001 From: yahym Date: Fri, 15 Dec 2017 02:10:25 +0200 Subject: [PATCH 013/117] - fix codacy exception error - mdf.covert test is failed in py3.4 and will be skipped in the next push --- test/test_mdf.py | 2 +- test/test_mdf3.py | 2 +- test/test_mdf4.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/test/test_mdf.py b/test/test_mdf.py index d7ad6dad3..1befeda29 100644 --- a/test/test_mdf.py +++ b/test/test_mdf.py @@ -23,7 +23,7 @@ def tearDown(self): # mdf4_10 if os.path.isfile('mdf4_10.mf4'): os.remove('mdf4_10.mf4') - except Exception: + except FileNotFoundError: pass def test_mdf_exists(self): diff --git a/test/test_mdf3.py b/test/test_mdf3.py index 4c5397613..3692ba641 100644 --- a/test/test_mdf3.py +++ b/test/test_mdf3.py @@ -43,7 +43,7 @@ def tearDown(self): # mdf3_20 if os.path.isfile('mdf3_20.mdf'): os.remove('mdf3_20.mdf') - except Exception: + except FileNotFoundError: pass def test_mdf3_exists(self): diff --git a/test/test_mdf4.py b/test/test_mdf4.py index 25c34a705..91a25b8a6 100644 --- a/test/test_mdf4.py +++ b/test/test_mdf4.py @@ -32,7 +32,7 @@ def tearDown(self): # mdf4_10 if os.path.isfile('mdf4_10.mf4'): os.remove('mdf4_10.mf4') - except Exception: + except FileNotFoundError: pass def test_mdf4_exists(self): From 70914c7474d4fce67fddb6638aafcafe1a8410d2 Mon Sep 17 00:00:00 2001 From: yahym Date: Fri, 15 Dec 2017 03:01:40 +0200 Subject: [PATCH 014/117] - fix codacy - I almost start to like it :( - remove code redundancy used in documentation and in tests (I am not sure is always a good idea) - append path to be able to generate sphinx docs locally - ignore `_build/` folder generated by sphinx - add files with vectors for mdf and for signals --- .gitignore | 2 + documentation/conf.py | 8 +-- documentation/examples.rst | 78 ++++++++++------------------- test/test_mdf.py | 3 +- test/test_mdf3.py | 2 +- test/test_mdf4.py | 2 +- test/{vectors.py => vectors_mdf.py} | 0 test/vectors_signal.py | 28 +++++++++++ 8 files changed, 66 insertions(+), 57 deletions(-) rename test/{vectors.py => vectors_mdf.py} (100%) create mode 100644 test/vectors_signal.py diff --git a/.gitignore b/.gitignore index af07ffeb9..d22186bee 100644 --- a/.gitignore +++ b/.gitignore @@ -102,3 +102,5 @@ ENV/ test-reports/ canape*.ini + +_build/ \ No newline at end of file diff --git a/documentation/conf.py b/documentation/conf.py index fad8408f7..04cf1a381 100644 --- a/documentation/conf.py +++ b/documentation/conf.py @@ -18,8 +18,9 @@ # documentation root, use os.path.abspath to make it absolute, like shown here. # import os -# import sys -# sys.path.insert(0, os.path.abspath('.')) +import sys +BASE_DIR = os.path.abspath('..') +sys.path.insert(0, BASE_DIR) with open(os.path.join('..', 'asammdf', 'version.py'), 'r') as f: for line in f: @@ -43,9 +44,10 @@ 'sphinx.ext.autosummary', 'sphinx.ext.imgmath', 'sphinx.ext.githubpages', + 'sphinx.ext.viewcode', 'matplotlib.sphinxext.plot_directive', 'sphinxarg.ext', - 'numpydoc'] + 'numpydoc'] # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] diff --git a/documentation/examples.rst b/documentation/examples.rst index 7ae7b674e..8e26e26d7 100644 --- a/documentation/examples.rst +++ b/documentation/examples.rst @@ -7,7 +7,7 @@ - + .. role:: red .. role:: blue .. role:: green @@ -23,8 +23,19 @@ Examples Working with MDF ---------------- +Test vectors below are considered in examples below (extracted from ``test/vectors_mdf.py``): + +.. literalinclude:: ../test/vectors_mdf.py + :language: python + :emphasize-lines: 7,33 + :linenos: + :lines: 7-34 + +Examples (add code above after imports): + .. code-block:: python - + :linenos: + from __future__ import print_function, division from asammdf import MDF, Signal, configure import numpy as np @@ -35,32 +46,10 @@ Working with MDF configure(split_data_blocks=True, split_threshold=10*1024) - # create 3 Signal objects - - timestamps = np.array([0.1, 0.2, 0.3, 0.4, 0.5], dtype=np.float32) - - # unit8 - s_uint8 = Signal(samples=np.array([0, 1, 2, 3, 4], dtype=np.uint8), - timestamps=timestamps, - name='Uint8_Signal', - unit='u1') - # int32 - s_int32 = Signal(samples=np.array([-20, -10, 0, 10, 20], dtype=np.int32), - timestamps=timestamps, - name='Int32_Signal', - unit='i4') - - # float64 - s_float64 = Signal(samples=np.array([-20, -10, 0, 10, 20], dtype=np.float64), - timestamps=timestamps, - name='Float64_Signal', - unit='f8') - # create empty MDf version 4.00 file mdf4 = MDF(version='4.10') # append the 3 signals to the new file - signals = [s_uint8, s_int32, s_float64] mdf4.append(signals, 'Created by Python') # save new file @@ -87,41 +76,28 @@ Working with MDF # save using zipped transpose deflate blocks mdf4.save('out.mf4', compression=2, overwrite=True) - - + + Working with Signal ------------------- - -.. code-block:: python +Test vectors below are considered in the examples below (extracted from ``test/vectors_signal.py``): +.. literalinclude:: ../test/vectors_signal.py + :language: python + :emphasize-lines: 7,33 + :linenos: + :lines: 7-34 + +Examples (add code above after imports): + +.. code-block:: python + :linenos: + from __future__ import print_function, division from asammdf import Signal import numpy as np - # create 3 Signal objects with different time stamps - - # unit8 with 100ms time raster - timestamps = np.array([0.1 * t for t in range(5)], dtype=np.float32) - s_uint8 = Signal(samples=np.array([t for t in range(5)], dtype=np.uint8), - timestamps=timestamps, - name='Uint8_Signal', - unit='u1') - - # int32 with 50ms time raster - timestamps = np.array([0.05 * t for t in range(10)], dtype=np.float32) - s_int32 = Signal(samples=np.array(list(range(-500, 500, 100)), dtype=np.int32), - timestamps=timestamps, - name='Int32_Signal', - unit='i4') - - # float64 with 300ms time raster - timestamps = np.array([0.3 * t for t in range(3)], dtype=np.float32) - s_float64 = Signal(samples=np.array(list(range(2000, -1000, -1000)), dtype=np.int32), - timestamps=timestamps, - name='Float64_Signal', - unit='f8') - # map signals xs = np.linspace(-1, 1, 50) ys = np.linspace(-1, 1, 50) diff --git a/test/test_mdf.py b/test/test_mdf.py index 1befeda29..c5b7a03d3 100644 --- a/test/test_mdf.py +++ b/test/test_mdf.py @@ -3,7 +3,7 @@ import unittest from asammdf import MDF -from vectors import signals +from vectors_mdf import signals class TestMDF(unittest.TestCase): @@ -30,6 +30,7 @@ def test_mdf_exists(self): self.assertTrue(MDF) # convert from mdf3 to mdf4 + @unittest.skip def test_convert_from_mdf3_20_to_mdf4_10(self): meas = MDF('mdf3_20.mdf') converted = meas.convert(to='4.10', memory='minimum') diff --git a/test/test_mdf3.py b/test/test_mdf3.py index 3692ba641..f8c000781 100644 --- a/test/test_mdf3.py +++ b/test/test_mdf3.py @@ -6,7 +6,7 @@ from utils import get_test_data from asammdf import MDF3 -from vectors import s_uint8, s_int32, s_float64, signals +from vectors_mdf import s_uint8, s_int32, s_float64, signals class TestMDF3(unittest.TestCase): diff --git a/test/test_mdf4.py b/test/test_mdf4.py index 91a25b8a6..ae318499c 100644 --- a/test/test_mdf4.py +++ b/test/test_mdf4.py @@ -5,7 +5,7 @@ from utils import get_test_data from asammdf import MDF4 -from vectors import s_uint8, s_int32, signals +from vectors_mdf import s_uint8, s_int32, signals class TestMDF4(unittest.TestCase): diff --git a/test/vectors.py b/test/vectors_mdf.py similarity index 100% rename from test/vectors.py rename to test/vectors_mdf.py diff --git a/test/vectors_signal.py b/test/vectors_signal.py new file mode 100644 index 000000000..fcd077214 --- /dev/null +++ b/test/vectors_signal.py @@ -0,0 +1,28 @@ +# -*- coding: utf-8 -*- +import numpy as np + +from asammdf.signal import Signal + + +# create 3 Signal objects with different time stamps + +# unit8 with 100ms time raster +timestamps = np.array([0.1 * t for t in range(5)], dtype=np.float32) +s_uint8 = Signal(samples=np.array([t for t in range(5)], dtype=np.uint8), + timestamps=timestamps, + name='Uint8_Signal', + unit='u1') + +# int32 with 50ms time raster +timestamps = np.array([0.05 * t for t in range(10)], dtype=np.float32) +s_int32 = Signal(samples=np.array(list(range(-500, 500, 100)), dtype=np.int32), + timestamps=timestamps, + name='Int32_Signal', + unit='i4') + +# float64 with 300ms time raster +timestamps = np.array([0.3 * t for t in range(3)], dtype=np.float32) +s_float64 = Signal(samples=np.array(list(range(2000, -1000, -1000)), dtype=np.int32), + timestamps=timestamps, + name='Float64_Signal', + unit='f8') From b95b82e5558b20432707b4dd53fbab4ce78efd6b Mon Sep 17 00:00:00 2001 From: yahym Date: Fri, 15 Dec 2017 03:27:03 +0200 Subject: [PATCH 015/117] - test for mdf.convert is activated - this PR will stay failed as long as py34 will get updated some how or? --- documentation/examples.rst | 4 ++-- test/test_mdf.py | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/documentation/examples.rst b/documentation/examples.rst index 8e26e26d7..79832dad9 100644 --- a/documentation/examples.rst +++ b/documentation/examples.rst @@ -23,7 +23,7 @@ Examples Working with MDF ---------------- -Test vectors below are considered in examples below (extracted from ``test/vectors_mdf.py``): +Test vectors are considered in examples below (extracted from ``test/vectors_mdf.py``): .. literalinclude:: ../test/vectors_mdf.py :language: python @@ -80,7 +80,7 @@ Examples (add code above after imports): Working with Signal ------------------- -Test vectors below are considered in the examples below (extracted from ``test/vectors_signal.py``): +Test vectors are considered in the examples below (extracted from ``test/vectors_signal.py``): .. literalinclude:: ../test/vectors_signal.py :language: python diff --git a/test/test_mdf.py b/test/test_mdf.py index c5b7a03d3..8a3f0866a 100644 --- a/test/test_mdf.py +++ b/test/test_mdf.py @@ -30,7 +30,6 @@ def test_mdf_exists(self): self.assertTrue(MDF) # convert from mdf3 to mdf4 - @unittest.skip def test_convert_from_mdf3_20_to_mdf4_10(self): meas = MDF('mdf3_20.mdf') converted = meas.convert(to='4.10', memory='minimum') From abe5cd3f502b055d091be2afbc9c3ec1c94fb420 Mon Sep 17 00:00:00 2001 From: yahym Date: Sat, 16 Dec 2017 01:04:40 +0200 Subject: [PATCH 016/117] - try [configuring-git-large-file-storage](https://help.github.com/articles/configuring-git-large-file-storage/) - should be a better alternative of keeping test vectors to issues - add .gitattributes --- .gitattributes | 2 ++ test/data/ASAP2_Demo_V161_2.00.mdf | 3 +++ test/data/ASAP2_Demo_V161_2.14.mf4 | 3 +++ test/data/ASAP2_Demo_V161_3.00.mdf | 3 +++ test/data/ASAP2_Demo_V161_3.10.mdf | 3 +++ test/data/ASAP2_Demo_V161_3.20.mdf | 3 +++ test/data/ASAP2_Demo_V161_3.30.mf4 | 3 +++ test/data/ASAP2_Demo_V161_4.00.mf4 | 3 +++ test/data/ASAP2_Demo_V161_4.10.mf4 | 3 +++ test/data/test_meas_2.00.mdf | Bin 18925 -> 130 bytes test/data/test_meas_3.00.mdf | Bin 18945 -> 130 bytes test/data/test_meas_3.10.mdf | Bin 18945 -> 130 bytes test/data/test_meas_3.20.mdf | Bin 18993 -> 130 bytes test/data/test_meas_4.00.mf4 | Bin 19856 -> 130 bytes test/data/test_meas_4.10.mf4 | Bin 19856 -> 130 bytes 15 files changed, 26 insertions(+) create mode 100644 .gitattributes create mode 100644 test/data/ASAP2_Demo_V161_2.00.mdf create mode 100644 test/data/ASAP2_Demo_V161_2.14.mf4 create mode 100644 test/data/ASAP2_Demo_V161_3.00.mdf create mode 100644 test/data/ASAP2_Demo_V161_3.10.mdf create mode 100644 test/data/ASAP2_Demo_V161_3.20.mdf create mode 100644 test/data/ASAP2_Demo_V161_3.30.mf4 create mode 100644 test/data/ASAP2_Demo_V161_4.00.mf4 create mode 100644 test/data/ASAP2_Demo_V161_4.10.mf4 diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 000000000..f4778fca8 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +*.mdf filter=lfs diff=lfs merge=lfs -text +*.mf4 filter=lfs diff=lfs merge=lfs -text diff --git a/test/data/ASAP2_Demo_V161_2.00.mdf b/test/data/ASAP2_Demo_V161_2.00.mdf new file mode 100644 index 000000000..c8b4b19d6 --- /dev/null +++ b/test/data/ASAP2_Demo_V161_2.00.mdf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:db77ff2ff680806201afe61fa2cd8bc4cd652e3f9ea6ff004a05e47e652e885c +size 54488 diff --git a/test/data/ASAP2_Demo_V161_2.14.mf4 b/test/data/ASAP2_Demo_V161_2.14.mf4 new file mode 100644 index 000000000..02cbdd28a --- /dev/null +++ b/test/data/ASAP2_Demo_V161_2.14.mf4 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:aed8dbcd2d357a6fa9b684f624cae07e5b032d37b6a9e7d301dfaadfb156f8f0 +size 56882 diff --git a/test/data/ASAP2_Demo_V161_3.00.mdf b/test/data/ASAP2_Demo_V161_3.00.mdf new file mode 100644 index 000000000..51a2d7a98 --- /dev/null +++ b/test/data/ASAP2_Demo_V161_3.00.mdf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b5360a6b2b701cc67187fbb0c6d5581bbe8c95c50a1143e3ad736490174685e1 +size 54259 diff --git a/test/data/ASAP2_Demo_V161_3.10.mdf b/test/data/ASAP2_Demo_V161_3.10.mdf new file mode 100644 index 000000000..8801077c4 --- /dev/null +++ b/test/data/ASAP2_Demo_V161_3.10.mdf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:fae528d0a6ea4b8e2add17a8b4bea78352e05b8c6d365b45ca3fc4ba072de294 +size 54259 diff --git a/test/data/ASAP2_Demo_V161_3.20.mdf b/test/data/ASAP2_Demo_V161_3.20.mdf new file mode 100644 index 000000000..3a292acc9 --- /dev/null +++ b/test/data/ASAP2_Demo_V161_3.20.mdf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:393d17b6d8ef3b35800f32ba29700acf30f064a7651144b7bdca0c0a1f418efa +size 54319 diff --git a/test/data/ASAP2_Demo_V161_3.30.mf4 b/test/data/ASAP2_Demo_V161_3.30.mf4 new file mode 100644 index 000000000..079dd8238 --- /dev/null +++ b/test/data/ASAP2_Demo_V161_3.30.mf4 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d766c68816c0ead2068d9cf36c1c7db2f3b8f67036707d88f4e06e9e9f1f7f5c +size 57116 diff --git a/test/data/ASAP2_Demo_V161_4.00.mf4 b/test/data/ASAP2_Demo_V161_4.00.mf4 new file mode 100644 index 000000000..4418a4080 --- /dev/null +++ b/test/data/ASAP2_Demo_V161_4.00.mf4 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ef3be65088500ce1e727e1d338e9ffe94d6f304d948f9e4de47b7ecdced1dbe5 +size 58616 diff --git a/test/data/ASAP2_Demo_V161_4.10.mf4 b/test/data/ASAP2_Demo_V161_4.10.mf4 new file mode 100644 index 000000000..45cee2e65 --- /dev/null +++ b/test/data/ASAP2_Demo_V161_4.10.mf4 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e67e0a571e71d76b50f8b6417c7ffcf82d799387f6d80c9f411e57060ab21005 +size 132144 diff --git a/test/data/test_meas_2.00.mdf b/test/data/test_meas_2.00.mdf index a9338a6209bc9bcc29a6e822fae495b36535bc81..34dcd88a69b2297ce59b0071fc9382a3f9102f70 100644 GIT binary patch literal 130 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 diff --git a/test/data/test_meas_3.00.mdf b/test/data/test_meas_3.00.mdf index fb9ecbb958690e9b5f16aed41a89a1d956aef60b..cde7a3ccd1dcf0e5055406e613b1619f5258a1b3 100644 GIT binary patch literal 130 zcmWN`Ne;sx3_#I6r{Dq&vB3YoJNb*W>33k2nHC9qd7=J1RW4CrIi77a5{kFLd7#r OPq2#Kep!MKhQuG4C?(_o literal 18945 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 diff --git a/test/data/test_meas_3.20.mdf b/test/data/test_meas_3.20.mdf index c668c637f1cf46bb76e3c2431789dacc91f621a6..ab2d7f6eab7856edcbc1dc96025b3b38db5a7d6d 100644 GIT binary patch literal 130 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
49ntU^jCgrpC`?twq~WYWzYrS1lN) z#;?4OeL7iv~n6t;Qc@VL+I-8iRP>erAChfAYT9eW@CQ z$p)WxE7cf6Hu@E=RbwdGyyDp=HU8rM+=lIH3}X)-vPX^KY<-P`YK$QJriUL@VGfmZax=oK`HmMMt0MnjQeYKdTCHj)&@rR)1ZQzQI`g5 zP)YWAGG~MaRb=z=PGdBv<~~+DQG*(?uFM-}4VEDbTei7suq@eF)yZ9h<;aGrR&z91 zo@_3RnWw=DWM9eUMH;NgePi!s8nhq_rcSFhSc$B)m2S{rW$r7#-J-!N+;`Z%Q-hXd z-JwzYG+32vK5lhbgVnfc5O-XI)!BWnoY7znvaiS7iyEv+_VMm~O@p<_+J(~F8m!ID zcmI1DtV1>*+3`q&b;-t4qn~NeiYz45d#%BGWZkv6cN(yr(B zU4k{(fNT`x;Tmj6*3Iyb)?g!U&hAXmU}N4dk4e>F6W-IUGd0+hT{Xe1!DeKiM^_6q z*qqGo$J2uR`+bZ0JN|x>7=M5Iw-1M2j(^?{r>t7_`<=q*9dUm9f4;SigG=dK;!N`P zn(pCgZP%r2$(vA>Zq6?HNuFN6-*N0e_mcP2nNjjaRR1~7@t*w8_`ke~PRaG!{qvQT He7*k<{fv5w diff --git a/test/data/test_meas_4.10.mf4 b/test/data/test_meas_4.10.mf4 index de0b49093a06200f4182095d37d1955621752acb..5d6054ba7fb52dd4fc6020289f3791ca42f706ce 100644 GIT binary patch literal 130 zcmWN?OA^8$3;@u5Pr(H&5W=swDKrsgR5}K`@bvmN@1nQ#@ltKhQ#P&decm1{>;LvC zYaLH5CslpfW%NTy+rfto69e!;skmIhvBlyeP^nyjAcq|tdjtyEBx|B62+?6R&Hx9D NagqKdWpnaj`2pa$CanMf literal 19856 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 F{{gn0dp`gG From 0f828227b65f4cfe577b568859d02477b9e4fd28 Mon Sep 17 00:00:00 2001 From: yahym Date: Sat, 16 Dec 2017 21:46:24 +0200 Subject: [PATCH 017/117] urllib.request does not exist in py27 build failed with error: ``` File "/home/travis/build/danielhrisca/asammdf/test/test_mdf.py", line 7, in import urllib.request ImportError: No module named request ``` --- .gitignore | 3 ++- pip_requirements_readthedocs.txt | 1 - test/test_mdf.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index d22186bee..e3af7f8b1 100644 --- a/.gitignore +++ b/.gitignore @@ -103,4 +103,5 @@ ENV/ test-reports/ canape*.ini -_build/ \ No newline at end of file +_build/ +debug/ diff --git a/pip_requirements_readthedocs.txt b/pip_requirements_readthedocs.txt index 275a95098..eb41925ed 100644 --- a/pip_requirements_readthedocs.txt +++ b/pip_requirements_readthedocs.txt @@ -5,4 +5,3 @@ pandas matplotlib wheel sphinx-argparse - diff --git a/test/test_mdf.py b/test/test_mdf.py index b18eb4161..4cd15b74c 100644 --- a/test/test_mdf.py +++ b/test/test_mdf.py @@ -4,7 +4,7 @@ import sys import unittest import shutil -import urllib.request +import urllib from zipfile import ZipFile import numpy as np From e6581bfce55934ba9ac28f4825a8d060f6dd9dae Mon Sep 17 00:00:00 2001 From: yahym Date: Sat, 16 Dec 2017 22:08:46 +0200 Subject: [PATCH 018/117] fix test archive handling - ZipFile cannot handle &zip, `lzma` compression - py27 tests are failing with `NotImplementedError: compression type 14 (lzma)` --- pip_requirements_tests.txt | 1 + test/test_mdf.py | 11 ++++++++--- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/pip_requirements_tests.txt b/pip_requirements_tests.txt index 1be17d299..e87a8f2c8 100644 --- a/pip_requirements_tests.txt +++ b/pip_requirements_tests.txt @@ -3,3 +3,4 @@ coverage pylint xmlrunner numpy>=1.13.1 +pyunpack \ No newline at end of file diff --git a/test/test_mdf.py b/test/test_mdf.py index 4cd15b74c..435804fe9 100644 --- a/test/test_mdf.py +++ b/test/test_mdf.py @@ -5,10 +5,16 @@ import unittest import shutil import urllib -from zipfile import ZipFile import numpy as np +PYVERSION = sys.version_info[0] +if PYVERSION == 2: + from pyunpack import Archive as ZipFile +else: + from zipfile import ZipFile + + from utils import MEMORY from asammdf import MDF, SUPPORTED_VERSIONS @@ -22,14 +28,13 @@ def test_measurement(self): @classmethod def setUpClass(cls): - PYVERSION = sys.version_info[0] url = 'https://github.com/danielhrisca/asammdf/files/1562572/test.files.zip' if PYVERSION == 3: urllib.request.urlretrieve(url, 'test.zip') else: urllib.urlretrieve(url, 'test.zip') - ZipFile(r'test.zip').extractall('tmpdir') + ZipFile(r'd:\uidl9955\gh\umihai1@yahoo.com\asammdf\debug\debug.zip').extractall('tmpdir') @classmethod def tearDownClass(cls): From def2bba2d4772174b2f793461a0e296026da89d0 Mon Sep 17 00:00:00 2001 From: yahym Date: Sat, 16 Dec 2017 22:20:07 +0200 Subject: [PATCH 019/117] - remove debug file - what can I say ... very smart to consume a commit like this. --- test/test_mdf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_mdf.py b/test/test_mdf.py index 435804fe9..6853bf73d 100644 --- a/test/test_mdf.py +++ b/test/test_mdf.py @@ -34,7 +34,7 @@ def setUpClass(cls): urllib.request.urlretrieve(url, 'test.zip') else: urllib.urlretrieve(url, 'test.zip') - ZipFile(r'd:\uidl9955\gh\umihai1@yahoo.com\asammdf\debug\debug.zip').extractall('tmpdir') + ZipFile(r'test.zip').extractall('tmpdir') @classmethod def tearDownClass(cls): From 62d320cfa9fb10aacc77cd3f88cab027fc31631a Mon Sep 17 00:00:00 2001 From: yahym Date: Sat, 16 Dec 2017 22:51:32 +0200 Subject: [PATCH 020/117] remove pyunpack, pylint, coveralls temporarry add a zip file without lzma comprassion to prove the tests are working in py 27 (locally are working) --- .travis.yml | 4 +--- pip_requirements_tests.txt | 6 +----- test/test_mdf.py | 10 +++------- 3 files changed, 5 insertions(+), 15 deletions(-) diff --git a/.travis.yml b/.travis.yml index 427093954..b75e3ec34 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,8 +12,6 @@ install: script: - set -e - python --version - - python -m coverage run test/run_all.py - - python -m coverage xml -i --include */asammdf/* + - python -m test/run_all.py after_success: - - python -m pylint --rcfile pylint.cfg -f parseable asammdf || exit 0 diff --git a/pip_requirements_tests.txt b/pip_requirements_tests.txt index e87a8f2c8..bc25967f5 100644 --- a/pip_requirements_tests.txt +++ b/pip_requirements_tests.txt @@ -1,6 +1,2 @@ -coveralls -coverage -pylint xmlrunner -numpy>=1.13.1 -pyunpack \ No newline at end of file +numpy>=1.13.1 \ No newline at end of file diff --git a/test/test_mdf.py b/test/test_mdf.py index 6853bf73d..be4e79713 100644 --- a/test/test_mdf.py +++ b/test/test_mdf.py @@ -7,12 +7,7 @@ import urllib import numpy as np - -PYVERSION = sys.version_info[0] -if PYVERSION == 2: - from pyunpack import Archive as ZipFile -else: - from zipfile import ZipFile +from zipfile import ZipFile from utils import MEMORY @@ -29,7 +24,8 @@ def test_measurement(self): @classmethod def setUpClass(cls): - url = 'https://github.com/danielhrisca/asammdf/files/1562572/test.files.zip' + url = 'https://github.com/danielhrisca/asammdf/files/1565090/test.files.zip' + PYVERSION = sys.version_info[0] if PYVERSION == 3: urllib.request.urlretrieve(url, 'test.zip') else: From 2b14f2ed151dd5f5fd3e593b412f52d5d6ed8ef2 Mon Sep 17 00:00:00 2001 From: yahym Date: Sat, 16 Dec 2017 22:53:40 +0200 Subject: [PATCH 021/117] fix typo --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index b75e3ec34..c58d32c9b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,6 +12,6 @@ install: script: - set -e - python --version - - python -m test/run_all.py + - python test/run_all.py after_success: From 529b0618f013e46ada1f3410b4fb129ab34cf2af Mon Sep 17 00:00:00 2001 From: yahym Date: Sat, 16 Dec 2017 23:31:25 +0200 Subject: [PATCH 022/117] clean PR and prepare for review --- documentation/conf.py | 8 ++--- documentation/examples.rst | 68 ++++++++++++++++++++++++++------------ pip_requirements_tests.txt | 2 +- test/test_mdf.py | 4 +-- test/vectors_mdf.py | 34 ------------------- test/vectors_signal.py | 28 ---------------- 6 files changed, 52 insertions(+), 92 deletions(-) delete mode 100644 test/vectors_mdf.py delete mode 100644 test/vectors_signal.py diff --git a/documentation/conf.py b/documentation/conf.py index 04cf1a381..fad8408f7 100644 --- a/documentation/conf.py +++ b/documentation/conf.py @@ -18,9 +18,8 @@ # documentation root, use os.path.abspath to make it absolute, like shown here. # import os -import sys -BASE_DIR = os.path.abspath('..') -sys.path.insert(0, BASE_DIR) +# import sys +# sys.path.insert(0, os.path.abspath('.')) with open(os.path.join('..', 'asammdf', 'version.py'), 'r') as f: for line in f: @@ -44,10 +43,9 @@ 'sphinx.ext.autosummary', 'sphinx.ext.imgmath', 'sphinx.ext.githubpages', - 'sphinx.ext.viewcode', 'matplotlib.sphinxext.plot_directive', 'sphinxarg.ext', - 'numpydoc'] + 'numpydoc'] # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] diff --git a/documentation/examples.rst b/documentation/examples.rst index 79832dad9..9d4182f0d 100644 --- a/documentation/examples.rst +++ b/documentation/examples.rst @@ -23,18 +23,7 @@ Examples Working with MDF ---------------- -Test vectors are considered in examples below (extracted from ``test/vectors_mdf.py``): - -.. literalinclude:: ../test/vectors_mdf.py - :language: python - :emphasize-lines: 7,33 - :linenos: - :lines: 7-34 - -Examples (add code above after imports): - .. code-block:: python - :linenos: from __future__ import print_function, division from asammdf import MDF, Signal, configure @@ -46,10 +35,32 @@ Examples (add code above after imports): configure(split_data_blocks=True, split_threshold=10*1024) + # create 3 Signal objects + + timestamps = np.array([0.1, 0.2, 0.3, 0.4, 0.5], dtype=np.float32) + + # unit8 + s_uint8 = Signal(samples=np.array([0, 1, 2, 3, 4], dtype=np.uint8), + timestamps=timestamps, + name='Uint8_Signal', + unit='u1') + # int32 + s_int32 = Signal(samples=np.array([-20, -10, 0, 10, 20], dtype=np.int32), + timestamps=timestamps, + name='Int32_Signal', + unit='i4') + + # float64 + s_float64 = Signal(samples=np.array([-20, -10, 0, 10, 20], dtype=np.float64), + timestamps=timestamps, + name='Float64_Signal', + unit='f8') + # create empty MDf version 4.00 file mdf4 = MDF(version='4.10') # append the 3 signals to the new file + signals = [s_uint8, s_int32, s_float64] mdf4.append(signals, 'Created by Python') # save new file @@ -80,24 +91,37 @@ Examples (add code above after imports): Working with Signal ------------------- -Test vectors are considered in the examples below (extracted from ``test/vectors_signal.py``): - -.. literalinclude:: ../test/vectors_signal.py - :language: python - :emphasize-lines: 7,33 - :linenos: - :lines: 7-34 - -Examples (add code above after imports): .. code-block:: python - :linenos: - + from __future__ import print_function, division from asammdf import Signal import numpy as np + # create 3 Signal objects with different time stamps + + # unit8 with 100ms time raster + timestamps = np.array([0.1 * t for t in range(5)], dtype=np.float32) + s_uint8 = Signal(samples=np.array([t for t in range(5)], dtype=np.uint8), + timestamps=timestamps, + name='Uint8_Signal', + unit='u1') + + # int32 with 50ms time raster + timestamps = np.array([0.05 * t for t in range(10)], dtype=np.float32) + s_int32 = Signal(samples=np.array(list(range(-500, 500, 100)), dtype=np.int32), + timestamps=timestamps, + name='Int32_Signal', + unit='i4') + + # float64 with 300ms time raster + timestamps = np.array([0.3 * t for t in range(3)], dtype=np.float32) + s_float64 = Signal(samples=np.array(list(range(2000, -1000, -1000)), dtype=np.int32), + timestamps=timestamps, + name='Float64_Signal', + unit='f8') + # map signals xs = np.linspace(-1, 1, 50) ys = np.linspace(-1, 1, 50) diff --git a/pip_requirements_tests.txt b/pip_requirements_tests.txt index bc25967f5..84a446792 100644 --- a/pip_requirements_tests.txt +++ b/pip_requirements_tests.txt @@ -1,2 +1,2 @@ xmlrunner -numpy>=1.13.1 \ No newline at end of file +numpy>=1.13.1 diff --git a/test/test_mdf.py b/test/test_mdf.py index be4e79713..d6e1b2906 100644 --- a/test/test_mdf.py +++ b/test/test_mdf.py @@ -5,10 +5,9 @@ import unittest import shutil import urllib - -import numpy as np from zipfile import ZipFile +import numpy as np from utils import MEMORY from asammdf import MDF, SUPPORTED_VERSIONS @@ -25,6 +24,7 @@ def test_measurement(self): def setUpClass(cls): url = 'https://github.com/danielhrisca/asammdf/files/1565090/test.files.zip' + PYVERSION = sys.version_info[0] if PYVERSION == 3: urllib.request.urlretrieve(url, 'test.zip') diff --git a/test/vectors_mdf.py b/test/vectors_mdf.py deleted file mode 100644 index 23c980b44..000000000 --- a/test/vectors_mdf.py +++ /dev/null @@ -1,34 +0,0 @@ -# -*- coding: utf-8 -*- -import numpy as np - -from asammdf.signal import Signal - - -# create 3 Signal objects -timestamps = np.array([0.1, 0.2, 0.3, 0.4, 0.5], dtype=np.float32) - -# unit8 -s_uint8 = Signal(samples=np.array([0, 1, 2, 3, 4], dtype=np.uint8), - timestamps=timestamps, - name='Uint8_Signal', - unit='u1', - info='s_uint8 info', - comment='s_uint8 comment') -# int32 -s_int32 = Signal(samples=np.array([-20, -10, 0, 10, 20], dtype=np.int32), - timestamps=timestamps, - name='Int32_Signal', - unit='i4', - info='s_int32 info', - comment='s_int32 comment') - -# float64 -s_float64 = Signal(samples=np.array([-20, -10, 0, 10, 20], dtype=np.float64), - timestamps=timestamps, - name='Float64_Signal', - unit='f8', - info='s_float64 info', - comment='s_float64 comment') - -# create signal list -signals = [s_uint8, s_int32, s_float64] diff --git a/test/vectors_signal.py b/test/vectors_signal.py deleted file mode 100644 index fcd077214..000000000 --- a/test/vectors_signal.py +++ /dev/null @@ -1,28 +0,0 @@ -# -*- coding: utf-8 -*- -import numpy as np - -from asammdf.signal import Signal - - -# create 3 Signal objects with different time stamps - -# unit8 with 100ms time raster -timestamps = np.array([0.1 * t for t in range(5)], dtype=np.float32) -s_uint8 = Signal(samples=np.array([t for t in range(5)], dtype=np.uint8), - timestamps=timestamps, - name='Uint8_Signal', - unit='u1') - -# int32 with 50ms time raster -timestamps = np.array([0.05 * t for t in range(10)], dtype=np.float32) -s_int32 = Signal(samples=np.array(list(range(-500, 500, 100)), dtype=np.int32), - timestamps=timestamps, - name='Int32_Signal', - unit='i4') - -# float64 with 300ms time raster -timestamps = np.array([0.3 * t for t in range(3)], dtype=np.float32) -s_float64 = Signal(samples=np.array(list(range(2000, -1000, -1000)), dtype=np.int32), - timestamps=timestamps, - name='Float64_Signal', - unit='f8') From cd4d22e3718e11053ec882c7482e7ba5c9f13dc5 Mon Sep 17 00:00:00 2001 From: yahym Date: Sun, 17 Dec 2017 17:55:00 +0200 Subject: [PATCH 023/117] add coverage, it seems that codacy needs it after all --- .travis.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index c58d32c9b..18e5741ba 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,6 +12,7 @@ install: script: - set -e - python --version - - python test/run_all.py + - python -m coverage run test/run_all.py + - python -m coverage xml -i --include */asammdf/* after_success: From 6d96c46387af393c0864af2b5e1e9e2fcbe107be Mon Sep 17 00:00:00 2001 From: yahym Date: Sun, 17 Dec 2017 18:11:47 +0200 Subject: [PATCH 024/117] first try with codacy and coverage integration on yahym fork --- .travis.yml | 1 + pip_requirements_tests.txt | 2 ++ 2 files changed, 3 insertions(+) diff --git a/.travis.yml b/.travis.yml index d424bdabf..3ce855c2b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,5 +13,6 @@ script: - python --version - python -m coverage run test/run_all.py - python -m coverage xml -i --include */asammdf/* + - python-codacy-coverage -r coverage.xml after_success: diff --git a/pip_requirements_tests.txt b/pip_requirements_tests.txt index 84a446792..eb43dbca6 100644 --- a/pip_requirements_tests.txt +++ b/pip_requirements_tests.txt @@ -1,2 +1,4 @@ xmlrunner +coverage +codacy-coverage numpy>=1.13.1 From 4b1225774d7352c5aef91952f2c8fb863d7441a6 Mon Sep 17 00:00:00 2001 From: yahym Date: Sun, 17 Dec 2017 18:36:14 +0200 Subject: [PATCH 025/117] add codacy coverage on README.md - link to codacy coverage must be updated with official link. --- README.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 2d90a91bf..23607c5a1 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,8 @@ -[![PyPI version](https://badge.fury.io/py/asammdf.svg)](https://badge.fury.io/py/asammdf) [![Documentation Status](http://readthedocs.org/projects/asammdf/badge/?version=master)](http://asammdf.readthedocs.io/en/development/?badge=stable) [![Codacy Badge](https://api.codacy.com/project/badge/Grade/a3da21da90ca43a5b72fc24b56880c99)](https://www.codacy.com/app/danielhrisca/asammdf?utm_source=github.com&utm_medium=referral&utm_content=danielhrisca/asammdf&utm_campaign=badger) - [![Build Status](https://travis-ci.org/danielhrisca/asammdf.svg?branch=development)](https://travis-ci.org/danielhrisca/asammdf) +[![PyPI version](https://badge.fury.io/py/asammdf.svg)](https://badge.fury.io/py/asammdf) +[![Documentation Status](http://readthedocs.org/projects/asammdf/badge/?version=master)](http://asammdf.readthedocs.io/en/development/?badge=stable) +[![Codacy Badge](https://api.codacy.com/project/badge/Grade/a3da21da90ca43a5b72fc24b56880c99)](https://www.codacy.com/app/danielhrisca/asammdf?utm_source=github.com&utm_medium=referral&utm_content=danielhrisca/asammdf&utm_campaign=badger) +[![Codacy Badge](https://api.codacy.com/project/badge/Coverage/0f91740b9c504ad397e3f9405788021e)](https://www.codacy.com/app/yahym/asammdf?utm_source=github.com&utm_medium=referral&utm_content=yahym/asammdf&utm_campaign=Badge_Coverage) *asammdf* is a fast parser/editor for ASAM (Associtation for Standardisation of Automation and Measuring Systems) MDF (Measurement Data Format) files. From 7fd24aabade31f13a0a5acc02c2fa7dd4e4ffc91 Mon Sep 17 00:00:00 2001 From: danielhrisca Date: Mon, 18 Dec 2017 15:37:20 +0200 Subject: [PATCH 026/117] start 2.8.2 development --- README.md | 10 +++++----- README.rst | 6 +++--- asammdf/version.py | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 8e63541ed..740e63fa0 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ -[![PyPI version](https://badge.fury.io/py/asammdf.svg)](https://badge.fury.io/py/asammdf) [![Documentation Status](http://readthedocs.org/projects/asammdf/badge/?version=master)](http://asammdf.readthedocs.io/en/master/?badge=stable) [![Codacy Badge](https://api.codacy.com/project/badge/Grade/a3da21da90ca43a5b72fc24b56880c99)](https://www.codacy.com/app/danielhrisca/asammdf?utm_source=github.com&utm_medium=referral&utm_content=danielhrisca/asammdf&utm_campaign=badger) +[![PyPI version](https://badge.fury.io/py/asammdf.svg)](https://badge.fury.io/py/asammdf) [![Documentation Status](http://readthedocs.org/projects/asammdf/badge/?version=development)](http://asammdf.readthedocs.io/en/development/?badge=stable) [![Codacy Badge](https://api.codacy.com/project/badge/Grade/a3da21da90ca43a5b72fc24b56880c99)](https://www.codacy.com/app/danielhrisca/asammdf?utm_source=github.com&utm_medium=referral&utm_content=danielhrisca/asammdf&utm_campaign=badger) -[![Build Status](https://travis-ci.org/danielhrisca/asammdf.svg?branch=master)](https://travis-ci.org/danielhrisca/asammdf) +[![Build Status](https://travis-ci.org/danielhrisca/asammdf.svg?branch=development)](https://travis-ci.org/danielhrisca/asammdf) *asammdf* is a fast parser/editor for ASAM (Associtation for Standardisation of Automation and Measuring Systems) MDF (Measurement Data Format) files. @@ -94,11 +94,11 @@ Usage ``` Check the *examples* folder for extended usage demo, or the documentation -http://asammdf.readthedocs.io/en/master/examples.html +http://asammdf.readthedocs.io/en/development/examples.html Documentation ============= -http://asammdf.readthedocs.io/en/master +http://asammdf.readthedocs.io/en/development Installation ============ @@ -130,5 +130,5 @@ optional dependencies needed for exports Benchmarks ========== -http://asammdf.readthedocs.io/en/master/benchmarks.html +http://asammdf.readthedocs.io/en/development/benchmarks.html diff --git a/README.rst b/README.rst index 07d16ae5b..ea4eb63b3 100644 --- a/README.rst +++ b/README.rst @@ -90,11 +90,11 @@ Usage Check the *examples* folder for extended usage demo, or the documentation -http://asammdf.readthedocs.io/en/master/examples.html +http://asammdf.readthedocs.io/en/development/examples.html Documentation ============= -http://asammdf.readthedocs.io/en/master +http://asammdf.readthedocs.io/en/development Installation ============ @@ -128,7 +128,7 @@ optional dependencies needed for exports Benchmarks ========== -Graphical results can be seen here at http://asammdf.readthedocs.io/en/master/benchmarks.html +Graphical results can be seen here at http://asammdf.readthedocs.io/en/development/benchmarks.html Python 3 x86 diff --git a/asammdf/version.py b/asammdf/version.py index cd118a5ef..52be6e575 100644 --- a/asammdf/version.py +++ b/asammdf/version.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- """ asammdf version module """ -__version__ = '2.8.1' +__version__ = '2.8.2dev' From fd1c9f441c34042fa6f10ba8d2fa47f308e09252 Mon Sep 17 00:00:00 2001 From: yahym Date: Mon, 18 Dec 2017 21:56:12 +0200 Subject: [PATCH 027/117] filter codacy coverage for master branch --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 220751145..a48dca01d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,7 +13,7 @@ script: - python --version - python -m coverage run test/run_all.py - python -m coverage xml -i --include */asammdf/* - - python-codacy-coverage -r coverage.xml + - $TRAVIS_BRANCH == "master" && python-codacy-coverage -r coverage.xml - python -m sphinx -nW -b html documentation documentation/_build/html after_success: From aad07b3eef30813e81a23947ef351b743c18ef70 Mon Sep 17 00:00:00 2001 From: yahym Date: Mon, 18 Dec 2017 22:01:55 +0200 Subject: [PATCH 028/117] fix syntax for branch filter --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index a48dca01d..d449c4c9c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,7 +13,7 @@ script: - python --version - python -m coverage run test/run_all.py - python -m coverage xml -i --include */asammdf/* - - $TRAVIS_BRANCH == "master" && python-codacy-coverage -r coverage.xml + - if [ "$TRAVIS_BRANCH" = "master" ]; then python-codacy-coverage -r coverage.xml - python -m sphinx -nW -b html documentation documentation/_build/html after_success: From a511a5b85f106f0171f0cdd68f2e0eb9a6321c13 Mon Sep 17 00:00:00 2001 From: yahym Date: Mon, 18 Dec 2017 22:17:52 +0200 Subject: [PATCH 029/117] fix syntax for branch selection (peaty travis does not have a replay to test the syntax) --- .travis.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index d449c4c9c..e0778df58 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,8 +12,9 @@ script: - set -e - python --version - python -m coverage run test/run_all.py - - python -m coverage xml -i --include */asammdf/* - - if [ "$TRAVIS_BRANCH" = "master" ]; then python-codacy-coverage -r coverage.xml + - test $TRAVIS_PULL_REQUEST = false \ + && python-codacy-coverage -r coverage.xml + - python -m sphinx -nW -b html documentation documentation/_build/html after_success: From 837eeec0889aaca8286b773a6eb9737af77e9f64 Mon Sep 17 00:00:00 2001 From: yahym Date: Mon, 18 Dec 2017 22:29:15 +0200 Subject: [PATCH 030/117] fix syntax - missed the `; fi` --- .travis.yml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index e0778df58..f547a3d9e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,9 +12,8 @@ script: - set -e - python --version - python -m coverage run test/run_all.py - - test $TRAVIS_PULL_REQUEST = false \ - && python-codacy-coverage -r coverage.xml - + - python -m coverage xml -i --include */asammdf/* + - if [[ "$TRAVIS_PULL_REQUEST" = "false" ]]; then python-codacy-coverage -r coverage.xml; fi - python -m sphinx -nW -b html documentation documentation/_build/html after_success: From c34ff179e49fcb49822d2af1dcad8acc56aa1a8b Mon Sep 17 00:00:00 2001 From: danielhrisca Date: Wed, 20 Dec 2017 12:18:11 +0200 Subject: [PATCH 031/117] fix rational conversion bug in mdf versions 2 and 3 --- asammdf/v2blocks.py | 6 +- asammdf/v3blocks.py | 6 +- benchmarks/bench.py | 62 +- test/test_mdf.py | 1521 ++++++++++++++++++++++++++++++++++++++++++- 4 files changed, 1561 insertions(+), 34 deletions(-) diff --git a/asammdf/v2blocks.py b/asammdf/v2blocks.py index ec51cb909..3310edfb0 100644 --- a/asammdf/v2blocks.py +++ b/asammdf/v2blocks.py @@ -369,7 +369,11 @@ def __init__(self, **kargs): self['P3'], self['P4'], self['P5'], - self['P6']) = unpack_from('<6d', block) + self['P6']) = unpack_from( + '<6d', + block, + v2c.CC_COMMON_SHORT_SIZE, + ) elif conv_type in ( v2c.CONVERSION_TYPE_EXPO, diff --git a/asammdf/v3blocks.py b/asammdf/v3blocks.py index 58ddd4cca..dae60a661 100644 --- a/asammdf/v3blocks.py +++ b/asammdf/v3blocks.py @@ -349,7 +349,11 @@ def __init__(self, **kargs): self['P3'], self['P4'], self['P5'], - self['P6']) = unpack_from('<6d', block) + self['P6']) = unpack_from( + '<6d', + block, + v3c.CC_COMMON_SHORT_SIZE, + ) elif conv_type in ( v3c.CONVERSION_TYPE_EXPO, diff --git a/benchmarks/bench.py b/benchmarks/bench.py index d9fac5c20..67149ae32 100644 --- a/benchmarks/bench.py +++ b/benchmarks/bench.py @@ -533,18 +533,18 @@ def main(path, text_output, fmt): output.append('* 36424 channels\n\n') tests = ( - partial(open_mdf3, memory='full'), - partial(open_mdf3, memory='low'), - partial(open_mdf3, memory='minimum'), - open_reader3, -# open_reader3_compression, - open_reader3_nodata, - partial(open_mdf4, memory='full'), - partial(open_mdf4, memory='low'), - partial(open_mdf4, memory='minimum'), - open_reader4, -# open_reader4_compression, - open_reader4_nodata, +# partial(open_mdf3, memory='full'), +# partial(open_mdf3, memory='low'), +# partial(open_mdf3, memory='minimum'), +# open_reader3, +## open_reader3_compression, +# open_reader3_nodata, +# partial(open_mdf4, memory='full'), +# partial(open_mdf4, memory='low'), +# partial(open_mdf4, memory='minimum'), +# open_reader4, +## open_reader4_compression, +# open_reader4_nodata, ) if tests: @@ -559,18 +559,18 @@ def main(path, text_output, fmt): output.extend(table_end(fmt)) tests = ( - partial(save_mdf3, memory='full'), - partial(save_mdf3, memory='low'), - partial(save_mdf3, memory='minimum'), - save_reader3, - save_reader3_nodata, -# save_reader3_compression, - partial(save_mdf4, memory='full'), - partial(save_mdf4, memory='low'), - partial(save_mdf4, memory='minimum'), - save_reader4, - save_reader4_nodata, -# save_reader4_compression, +# partial(save_mdf3, memory='full'), +# partial(save_mdf3, memory='low'), +# partial(save_mdf3, memory='minimum'), +# save_reader3, +# save_reader3_nodata, +## save_reader3_compression, +# partial(save_mdf4, memory='full'), +# partial(save_mdf4, memory='low'), +# partial(save_mdf4, memory='minimum'), +# save_reader4, +# save_reader4_nodata, +## save_reader4_compression, ) if tests: @@ -585,17 +585,17 @@ def main(path, text_output, fmt): output.extend(table_end(fmt)) tests = ( - partial(get_all_mdf3, memory='full'), - partial(get_all_mdf3, memory='low'), - partial(get_all_mdf3, memory='minimum'), - get_all_reader3, +# partial(get_all_mdf3, memory='full'), +# partial(get_all_mdf3, memory='low'), +# partial(get_all_mdf3, memory='minimum'), +# get_all_reader3, # get_all_reader3_nodata, # get_all_reader3_compression, partial(get_all_mdf4, memory='full'), - partial(get_all_mdf4, memory='low'), +# partial(get_all_mdf4, memory='low'), partial(get_all_mdf4, memory='minimum'), - get_all_reader4, -# get_all_reader4_nodata, +# get_all_reader4, + get_all_reader4_nodata, # get_all_reader4_compression, ) diff --git a/test/test_mdf.py b/test/test_mdf.py index 5b68ce483..6b412d0ad 100644 --- a/test/test_mdf.py +++ b/test/test_mdf.py @@ -9,6 +9,21 @@ import numpy as np +from numpy import ( + array, + float16, + float32, + float64, + int8, + int16, + int32, + int64, + uint8, + uint16, + uint32, + uint64, +) + from utils import MEMORY from asammdf import MDF, SUPPORTED_VERSIONS @@ -39,11 +54,1515 @@ def tearDownClass(cls): os.remove('tmp') def test_read(self): + + channels = { + +'$ActiveCalibrationPage': array([1, 0, 1, 1], dtype=uint8), +'$CalibrationLog': array([b'', b'Switch to reference page', b'Switch to working page', + b'Switch to working page'], + dtype='|S24'), +'ASAM.M.SCALAR.UBYTE.TAB_NOINTP_DEFAULT_VALUE': array([ 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 104. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 108. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 102. , + 110.66666412, 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. ], dtype=float32), +'ASAM_[0].M.MATRIX_DIM_16_1_1.UBYTE.IDENTICAL': array([ 88, 98, 108, 118, 128, 138, 148, 158, 168, 178, 188, 198, 208, + 218, 228, 238, 248, 2, 12, 22, 32, 42, 52, 62, 72, 82, + 92, 102, 112, 122, 132, 142, 152, 162, 172, 182, 192, 202, 212, + 222, 0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110, + 120, 130, 140, 150, 160, 170, 180, 190, 200, 210, 220, 230, 240, + 250, 4, 14, 24, 34, 44, 54, 64, 74, 84, 94, 104, 114, + 124, 134, 144, 154, 164, 174, 184, 194, 204, 214, 224, 234], dtype=uint8), +'ASAM.M.SCALAR.SWORD.IDENTICAL': array([900, 910, 920, 930, 940, 950, 960, 970, 980, 990, 0, 10, 20, + 30, 40, 50, 60, 70, 80, 90, 100, 110, 120, 130, 140, 150, + 160, 170, 180, 190, 200, 210, 220, 230, 240, 250, 260, 270, 280, + 290, 300, 310, 320, 330, 340, 350, 360, 370, 380, 390, 400, 410, + 420, 430, 440, 450, 460, 470, 480, 490, 500, 510, 520, 530, 540, + 550, 560, 570, 580, 590, 600, 610, 620, 630, 640, 650, 660, 670, + 680, 690, 700, 710, 720, 730, 740, 750, 760, 770, 780, 790], dtype=int16), +'ASAM.M.SCALAR.UBYTE.TAB_INTP_DEFAULT_VALUE': array([ 111., 111., 111., 111., 111., 111., 111., 111., 111., + 111., 111., 111., 111., 111., 111., 111., 111., 111., + 111., 111., 100., 110., 111., 111., 111., 111., 111., + 111., 111., 111., 111., 111., 111., 111., 111., 111., + 111., 111., 111., 111., 111., 111., 111., 111., 111., + 111., 104., 111., 111., 111., 111., 111., 111., 111., + 111., 111., 111., 111., 111., 111., 111., 111., 111., + 111., 111., 111., 111., 111., 111., 111., 111., 111., + 108., 111., 111., 111., 111., 111., 111., 111., 111., + 111., 111., 111., 111., 111., 111., 111., 111., 111.], dtype=float32), +'ASAM.M.SCALAR.UBYTE.FORM_X_PLUS_4': array([ 4., 14., 24., 34., 44., 54., 64., 74., 84., + 94., 104., 114., 124., 134., 144., 154., 164., 174., + 184., 194., 204., 214., 224., 234., 244., 254., 8., + 18., 28., 38., 48., 58., 68., 78., 88., 98., + 108., 118., 128., 138., 148., 158., 168., 178., 188., + 198., 208., 218., 228., 238., 248., 258., 12., 22., + 32., 42., 52., 62., 72., 82., 92., 102., 112., + 122., 132., 142., 152., 162., 172., 182., 192., 202., + 212., 222., 232., 242., 252., 6., 16., 26., 36., + 46., 56., 66., 76., 86., 96., 106., 116., 126.], dtype=float32), +'ASAM.M.SCALAR.SLONG.IDENTICAL': array([200, 210, 220, 230, 240, 250, 260, 270, 280, 290, 300, 310, 320, + 330, 340, 350, 360, 370, 380, 390, 400, 410, 420, 430, 440, 450, + 460, 470, 480, 490, 500, 510, 520, 530, 540, 550, 560, 570, 580, + 590, 600, 610, 620, 630, 640, 650, 660, 670, 680, 690, 700, 710, + 720, 730, 740, 750, 760, 770, 780, 790, 800, 810, 820, 830, 840, + 850, 860, 870, 880, 890, 900, 910, 920, 930, 940, 950, 960, 970, + 980, 990, 0, 10, 20, 30, 40, 50, 60, 70, 80, 90]), +'ASAM.M.SCALAR.UBYTE.IDENTICAL': array([188, 198, 208, 218, 228, 238, 248, 2, 12, 22, 32, 42, 52, + 62, 72, 82, 92, 102, 112, 122, 132, 142, 152, 162, 172, 182, + 192, 202, 212, 222, 0, 10, 20, 30, 40, 50, 60, 70, 80, + 90, 100, 110, 120, 130, 140, 150, 160, 170, 180, 190, 200, 210, + 220, 230, 240, 250, 4, 14, 24, 34, 44, 54, 64, 74, 84, + 94, 104, 114, 124, 134, 144, 154, 164, 174, 184, 194, 204, 214, + 224, 234, 244, 254, 8, 18, 28, 38, 48, 58, 68, 78], dtype=uint8), +'ASAM.M.SCALAR.UBYTE.TAB_INTP_NO_DEFAULT_VALUE': array([ 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 108. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 102. , 110.66666412, 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 100. , 110. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 104. , 111. , + 111. , 111. ], dtype=float32), +'ASAM.M.SCALAR.SBYTE.LINEAR_MUL_2': array([-136., -116., -96., -76., -56., -36., -16., 4., 24., + 44., 64., 84., 104., 124., 144., 164., 184., 204., + 224., 244., -248., -228., -208., -188., -168., -148., -128., + -108., -88., -68., 0., 20., 40., 60., 80., 100., + 120., 140., 160., 180., 200., 220., 240., -252., -232., + -212., -192., -172., -152., -132., -112., -92., -72., -52., + -32., -12., 8., 28., 48., 68., 88., 108., 128., + 148., 168., 188., 208., 228., 248., -244., -224., -204., + -184., -164., -144., -124., -104., -84., -64., -44., -24., + -4., 16., 36., 56., 76., 96., 116., 136., 156.], dtype=float32), +'ASAM_[0].M.ARRAY_SIZE_16.UBYTE.IDENTICAL': array([ 44, 54, 64, 74, 84, 94, 104, 114, 124, 134, 144, 154, 164, + 174, 184, 194, 204, 214, 224, 234, 244, 254, 8, 18, 28, 38, + 48, 58, 68, 78, 88, 98, 108, 118, 128, 138, 148, 158, 168, + 178, 188, 198, 208, 218, 228, 238, 248, 2, 12, 22, 32, 42, + 52, 62, 72, 82, 92, 102, 112, 122, 132, 142, 152, 162, 172, + 182, 192, 202, 212, 222, 0, 10, 20, 30, 40, 50, 60, 70, + 80, 90, 100, 110, 120, 130, 140, 150, 160, 170, 180, 190], dtype=uint8), +'ASAM_[0][0].M.MATRIX_DIM_8_2_1.UBYTE.IDENTICAL': array([244, 254, 8, 18, 28, 38, 48, 58, 68, 78, 88, 98, 108, + 118, 128, 138, 148, 158, 168, 178, 188, 198, 208, 218, 228, 238, + 248, 2, 12, 22, 32, 42, 52, 62, 72, 82, 92, 102, 112, + 122, 132, 142, 152, 162, 172, 182, 192, 202, 212, 222, 0, 10, + 20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120, 130, 140, + 150, 160, 170, 180, 190, 200, 210, 220, 230, 240, 250, 4, 14, + 24, 34, 44, 54, 64, 74, 84, 94, 104, 114, 124, 134], dtype=uint8), +'ASAM.M.SCALAR.UWORD.IDENTICAL.BITMASK_0FF0': array([61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 62, 62, 62, + 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, + 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, + 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, + 62, 62, 62, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, + 61, 61, 61, 61, 61, 61, 61, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, + 60, 60, 60, 60, 60, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 57, 57, 57, 57, 57, 57, 57, + 57, 57, 56, 56, 56, 56, 56, 56, 56, 56, 56, 55, 55, 55, 55, 55, 55, + 55, 55, 54, 54, 54, 54, 54, 54, 54, 54, 53, 53, 53, 53, 53, 53, 53, + 52, 52, 52, 52, 52, 52, 52, 51, 51, 51, 51, 51, 51, 51, 50, 50, 50, + 50, 50, 50, 49, 49, 49, 49, 49, 49, 48, 48, 48, 48, 48, 48, 47, 47, + 47, 47, 47, 47, 46, 46, 46, 46, 46, 46, 45, 45, 45, 45, 45, 45, 44, + 44, 44, 44, 44, 44, 43, 43, 43, 43, 43, 42, 42, 42, 42, 42, 42, 41, + 41, 41, 41, 41, 40, 40, 40, 40, 40, 39, 39, 39, 39, 39, 39, 38, 38, + 38, 38, 38, 37, 37, 37, 37, 37, 36, 36, 36, 36, 36, 35, 35, 35, 35, + 35, 34, 34, 34, 34, 34, 33, 33, 33, 33, 33, 33, 32, 32, 32, 32, 32, + 31, 31, 31, 31, 31, 30, 30, 30, 30, 30, 29, 29, 29, 29, 29, 28, 28, + 28, 28, 28, 27, 27, 27, 27, 27, 26, 26, 26, 26, 26, 25, 25, 25, 25, + 25, 25, 24, 24, 24, 24, 24, 23, 23, 23, 23, 23, 22, 22, 22, 22, 22, + 21, 21, 21, 21, 21, 21, 20, 20, 20, 20, 20, 19, 19, 19, 19, 19, 19, + 18, 18, 18, 18, 18, 17, 17, 17, 17, 17, 17, 16, 16, 16, 16, 16, 16, + 15, 15, 15, 15, 15, 15, 14, 14, 14, 14, 14, 14, 13, 13, 13, 13, 13, + 13, 12, 12, 12, 12, 12, 12, 11, 11, 11, 11, 11, 11, 11, 10, 10, 10, + 10, 10, 10, 10, 9, 9, 9, 9, 9, 9, 9, 8, 8, 8, 8, 8, 8, + 8, 7, 7, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, + 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, + 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, + 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, + 13, 13, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 16, 16, 16, + 16, 16, 16, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 19, 19, 19, + 19, 19, 19, 20, 20, 20, 20, 20, 21, 21, 21, 21, 21, 21, 22, 22, 22, + 22, 22, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 25, 25, 25, 25, 25, + 25, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 28, 28, 28, 28, 28, 29, + 29, 29, 29, 29, 30, 30, 30, 30, 30, 31, 31, 31, 31, 31, 32, 32, 32, + 32, 32, 33, 33, 33, 33, 33, 33, 34, 34, 34, 34, 34, 35, 35, 35, 35, + 35, 36, 36, 36, 36, 36, 37, 37, 37, 37, 37, 38, 38, 38, 38, 38, 39, + 39, 39, 39, 39, 39, 40, 40, 40, 40, 40, 41, 41, 41, 41, 41, 42, 42, + 42, 42, 42, 42, 43, 43, 43, 43, 43, 44, 44, 44, 44, 44, 44, 45, 45, + 45, 45, 45, 45, 46, 46, 46, 46, 46, 46, 47, 47, 47, 47, 47, 47, 48, + 48, 48, 48, 48, 48, 49, 49, 49, 49, 49, 49, 50], dtype=uint16), +'ASAM.M.SCALAR.UBYTE.VTAB_RANGE_DEFAULT_VALUE': array([ 13, 16, 19, 22, 25, 28, 31, 35, 38, 41, 44, 47, 50, + 53, 56, 60, 63, 66, 69, 72, 75, 78, 81, 84, 87, 90, + 94, 97, 100, 103, 106, 109, 112, 115, 118, 121, 124, 127, 130, + 133, 136, 139, 142, 145, 148, 151, 154, 157, 160, 163, 166, 169, + 172, 174, 177, 180, 183, 186, 189, 192, 195, 198, 200, 203, 206, + 209, 212, 214, 217, 220, 223, 226, 228, 231, 234, 237, 239, 242, + 245, 247, 250, 253, 255, 2, 5, 7, 10, 13, 15, 18, 20, + 23, 25, 28, 30, 33, 35, 38, 40, 43, 45, 48, 50, 53, + 55, 57, 60, 62, 65, 67, 69, 71, 74, 76, 78, 81, 83, + 85, 87, 89, 92, 94, 96, 98, 100, 102, 104, 107, 109, 111, + 113, 115, 117, 119, 121, 123, 125, 127, 128, 130, 132, 134, 136, + 138, 140, 141, 143, 145, 147, 149, 150, 152, 154, 155, 157, 159, + 160, 162, 163, 165, 167, 168, 170, 171, 173, 174, 176, 177, 178, + 180, 181, 183, 184, 185, 187, 188, 189, 190, 192, 193, 194, 195, + 196, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, + 210, 211, 212, 213, 213, 214, 215, 216, 217, 217, 218, 219, 219, + 220, 221, 221, 222, 223, 223, 224, 224, 225, 225, 226, 226, 227, + 227, 228, 228, 228, 229, 229, 229, 230, 230, 230, 230, 231, 231, + 231, 231, 231, 231, 231, 231, 231, 231, 232, 231, 231, 231, 231, + 231, 231, 231, 231, 231, 231, 230, 230, 230, 230, 229, 229, 229, + 228, 228, 228, 227, 227, 226, 226, 225, 225, 224, 224, 223, 223, + 222, 221, 221, 220, 219, 219, 218, 217, 217, 216, 215, 214, 213, + 213, 212, 211, 210, 209, 208, 207, 206, 205, 204, 203, 202, 201, + 200, 199, 198, 196, 195, 194, 193, 192, 190, 189, 188, 187, 185, + 184, 183, 181, 180, 178, 177, 176, 174, 173, 171, 170, 168, 167, + 165, 163, 162, 160, 159, 157, 155, 154, 152, 150, 149, 147, 145, + 143, 141, 140, 138, 136, 134, 132, 130, 128, 127, 125, 123, 121, + 119, 117, 115, 113, 111, 109, 107, 104, 102, 100, 98, 96, 94, + 92, 89, 87, 85, 83, 81, 78, 76, 74, 71, 69, 67, 65, + 62, 60, 57, 55, 53, 50, 48, 45, 43, 40, 38, 35, 33, + 30, 28, 25, 23, 20, 18, 15, 13, 10, 7, 5, 2, 255, + 253, 250, 247, 245, 242, 239, 237, 234, 231, 228, 226, 223, 220, + 217, 214, 212, 209, 206, 203, 200, 198, 195, 192, 189, 186, 183, + 180, 177, 174, 172, 169, 166, 163, 160, 157, 154, 151, 148, 145, + 142, 139, 136, 133, 130, 127, 124, 121, 118, 115, 112, 109, 106, + 103, 100, 97, 94, 90, 87, 84, 81, 78, 75, 72, 69, 66, + 63, 60, 56, 53, 50, 47, 44, 41, 38, 35, 31, 28, 25, + 22, 19, 16, 13, 9, 6, 3, 0, 253, 250, 247, 243, 240, + 237, 234, 231, 228, 225, 222, 218, 215, 212, 209, 206, 203, 200, + 196, 193, 190, 187, 184, 181, 178, 175, 171, 168, 165, 162, 159, + 156, 153, 150, 147, 144, 141, 137, 134, 131, 128, 125, 122, 119, + 116, 113, 110, 107, 104, 101, 98, 95, 92, 89, 86, 83, 80, + 77, 74, 71, 68, 65, 62, 59, 57, 54, 51, 48, 45, 42, + 39, 36, 33, 31, 28, 25, 22, 19, 17, 14, 11, 8, 5, + 3, 0, 253, 250, 248, 245, 242, 240, 237, 234, 232, 229, 226, + 224, 221, 218, 216, 213, 211, 208, 206, 203, 201, 198, 196, 193, + 191, 188, 186, 183, 181, 178, 176, 174, 171, 169, 166, 164, 162, + 160, 157, 155, 153, 150, 148, 146, 144, 142, 139, 137, 135, 133, + 131, 129, 127, 124, 122, 120, 118, 116, 114, 112, 110, 108, 106, + 104, 103, 101, 99, 97, 95, 93, 91, 90, 88, 86, 84, 82, + 81, 79, 77, 76, 74, 72, 71, 69, 68, 66, 64, 63, 61, + 60, 58, 57, 55, 54, 53, 51, 50, 48, 47, 46, 44, 43, + 42, 41, 39, 38, 37, 36, 35, 33, 32, 31, 30, 29, 28, + 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 18, 17, 16, + 15, 14, 14, 13, 12, 12, 11, 10, 10, 9, 8, 8, 7, + 7, 6, 6, 5, 5, 4, 4, 3, 3, 3, 2, 2, 2, + 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, + 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 5, 5, + 6, 6, 7, 7, 8, 8, 9, 10, 10, 11, 12, 12, 13, + 14, 14, 15, 16, 17, 18, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 35, 36, 37, 38, + 39, 41, 42, 43, 44, 46, 47, 48, 50, 51, 53, 54, 55, + 57, 58, 60, 61, 63, 64, 66, 68, 69, 71, 72, 74, 76, + 77, 79, 81, 82, 84, 86, 88, 90, 91, 93, 95, 97, 99, + 101, 103, 104, 106, 108, 110, 112, 114, 116, 118, 120, 122, 124, + 127, 129, 131, 133, 135, 137, 139, 142, 144, 146, 148, 150, 153, + 155, 157, 160, 162, 164, 166, 169, 171, 174, 176, 178, 181, 183, + 186, 188, 191, 193, 196, 198, 201, 203, 206, 208, 211, 213], dtype=uint8), +'ASAM.M.SCALAR.FLOAT32.IDENTICAL': array([ 8.13845703e+02, 8.16285095e+02, 8.18711975e+02, + 8.21126343e+02, 8.23527954e+02, 8.25916870e+02, + 8.28292908e+02, 8.30655945e+02, 8.33005920e+02, + 8.35342773e+02, 8.37666382e+02, 8.39976685e+02, + 8.42273560e+02, 8.44556885e+02, 8.46826660e+02, + 8.49082703e+02, 8.51325012e+02, 8.53553406e+02, + 8.55767822e+02, 8.57968262e+02, 8.60154541e+02, + 8.62326538e+02, 8.64484314e+02, 8.66627686e+02, + 8.68756531e+02, 8.70870911e+02, 8.72970581e+02, + 8.75055542e+02, 8.77125671e+02, 8.79180969e+02, + 8.81221252e+02, 8.83246521e+02, 8.85256592e+02, + 8.87251526e+02, 8.89231140e+02, 8.91195435e+02, + 8.93144226e+02, 8.95077515e+02, 8.96995178e+02, + 8.98897217e+02, 9.00783508e+02, 9.02653931e+02, + 9.04508484e+02, 9.06347107e+02, 9.08169617e+02, + 9.09976074e+02, 9.11766296e+02, 9.13540283e+02, + 9.15297974e+02, 9.17039246e+02, 9.18764038e+02, + 9.20472290e+02, 9.22163940e+02, 9.23838989e+02, + 9.25497253e+02, 9.27138733e+02, 9.28763306e+02, + 9.30371033e+02, 9.31961731e+02, 9.33535339e+02, + 9.35091858e+02, 9.36631226e+02, 9.38153320e+02, + 9.39658142e+02, 9.41145630e+02, 9.42615662e+02, + 9.44068237e+02, 9.45503235e+02, 9.46920715e+02, + 9.48320496e+02, 9.49702637e+02, 9.51066956e+02, + 9.52413513e+02, 9.53742188e+02, 9.55052979e+02, + 9.56345764e+02, 9.57620605e+02, 9.58877319e+02, + 9.60115906e+02, 9.61336365e+02, 9.62538574e+02, + 9.63722595e+02, 9.64888245e+02, 9.66035583e+02, + 9.67164490e+02, 9.68274963e+02, 9.69366943e+02, + 9.70440369e+02, 9.71495239e+02, 9.72531555e+02, + 9.73549133e+02, 9.74548096e+02, 9.75528259e+02, + 9.76489685e+02, 9.77432251e+02, 9.78356018e+02, + 9.79260864e+02, 9.80146851e+02, 9.81013855e+02, + 9.81861816e+02, 9.82690796e+02, 9.83500732e+02, + 9.84291565e+02, 9.85063293e+02, 9.85815857e+02, + 9.86549255e+02, 9.87263428e+02, 9.87958374e+02, + 9.88634033e+02, 9.89290466e+02, 9.89927551e+02, + 9.90545288e+02, 9.91143616e+02, 9.91722595e+02, + 9.92282166e+02, 9.92822327e+02, 9.93342957e+02, + 9.93844177e+02, 9.94325867e+02, 9.94788086e+02, + 9.95230713e+02, 9.95653809e+02, 9.96057373e+02, + 9.96441284e+02, 9.96805664e+02, 9.97150391e+02, + 9.97475525e+02, 9.97781006e+02, 9.98066833e+02, + 9.98332947e+02, 9.98579468e+02, 9.98806274e+02, + 9.99013367e+02, 9.99200745e+02, 9.99368469e+02, + 9.99516479e+02, 9.99644714e+02, 9.99753296e+02, + 9.99842102e+02, 9.99911194e+02, 9.99960510e+02, + 9.99990112e+02, 1.00000000e+03, 9.99990112e+02, + 9.99960510e+02, 9.99911194e+02, 9.99842102e+02, + 9.99753296e+02, 9.99644714e+02, 9.99516479e+02, + 9.99368469e+02, 9.99200745e+02, 9.99013367e+02, + 9.98806274e+02, 9.98579468e+02, 9.98332947e+02, + 9.98066833e+02, 9.97781006e+02, 9.97475525e+02, + 9.97150391e+02, 9.96805664e+02, 9.96441284e+02, + 9.96057373e+02, 9.95653809e+02, 9.95230713e+02, + 9.94788086e+02, 9.94325867e+02, 9.93844177e+02, + 9.93342957e+02, 9.92822327e+02, 9.92282166e+02, + 9.91722595e+02, 9.91143616e+02, 9.90545288e+02, + 9.89927551e+02, 9.89290466e+02, 9.88634033e+02, + 9.87958374e+02, 9.87263428e+02, 9.86549255e+02, + 9.85815857e+02, 9.85063293e+02, 9.84291565e+02, + 9.83500732e+02, 9.82690796e+02, 9.81861816e+02, + 9.81013855e+02, 9.80146851e+02, 9.79260864e+02, + 9.78356018e+02, 9.77432251e+02, 9.76489685e+02, + 9.75528259e+02, 9.74548096e+02, 9.73549133e+02, + 9.72531555e+02, 9.71495239e+02, 9.70440369e+02, + 9.69366943e+02, 9.68274963e+02, 9.67164490e+02, + 9.66035583e+02, 9.64888245e+02, 9.63722595e+02, + 9.62538574e+02, 9.61336365e+02, 9.60115906e+02, + 9.58877319e+02, 9.57620605e+02, 9.56345764e+02, + 9.55052979e+02, 9.53742188e+02, 9.52413513e+02, + 9.51066956e+02, 9.49702637e+02, 9.48320496e+02, + 9.46920715e+02, 9.45503235e+02, 9.44068237e+02, + 9.42615662e+02, 9.41145630e+02, 9.39658142e+02, + 9.38153320e+02, 9.36631226e+02, 9.35091858e+02, + 9.33535339e+02, 9.31961731e+02, 9.30371033e+02, + 9.28763306e+02, 9.27138733e+02, 9.25497253e+02, + 9.23838989e+02, 9.22163940e+02, 9.20472290e+02, + 9.18764038e+02, 9.17039246e+02, 9.15297974e+02, + 9.13540283e+02, 9.11766296e+02, 9.09976074e+02, + 9.08169617e+02, 9.06347107e+02, 9.04508484e+02, + 9.02653931e+02, 9.00783508e+02, 8.98897217e+02, + 8.96995178e+02, 8.95077515e+02, 8.93144226e+02, + 8.91195435e+02, 8.89231140e+02, 8.87251526e+02, + 8.85256592e+02, 8.83246521e+02, 8.81221252e+02, + 8.79180969e+02, 8.77125671e+02, 8.75055542e+02, + 8.72970581e+02, 8.70870911e+02, 8.68756531e+02, + 8.66627686e+02, 8.64484314e+02, 8.62326538e+02, + 8.60154541e+02, 8.57968262e+02, 8.55767822e+02, + 8.53553406e+02, 8.51325012e+02, 8.49082703e+02, + 8.46826660e+02, 8.44556885e+02, 8.42273560e+02, + 8.39976685e+02, 8.37666382e+02, 8.35342773e+02, + 8.33005920e+02, 8.30655945e+02, 8.28292908e+02, + 8.25916870e+02, 8.23527954e+02, 8.21126343e+02, + 8.18711975e+02, 8.16285095e+02, 8.13845703e+02, + 8.11393860e+02, 8.08929810e+02, 8.06453552e+02, + 8.03965149e+02, 8.01464783e+02, 7.98952515e+02, + 7.96428406e+02, 7.93892639e+02, 7.91345215e+02, + 7.88786377e+02, 7.86216064e+02, 7.83634460e+02, + 7.81041687e+02, 7.78437805e+02, 7.75822937e+02, + 7.73197144e+02, 7.70560608e+02, 7.67913391e+02, + 7.65255615e+02, 7.62587341e+02, 7.59908691e+02, + 7.57219788e+02, 7.54520691e+02, 7.51811584e+02, + 7.49092529e+02, 7.46363647e+02, 7.43625061e+02, + 7.40876831e+02, 7.38119080e+02, 7.35351990e+02, + 7.32575562e+02, 7.29789917e+02, 7.26995239e+02, + 7.24191589e+02, 7.21379089e+02, 7.18557861e+02, + 7.15728027e+02, 7.12889648e+02, 7.10042847e+02, + 7.07187805e+02, 7.04324524e+02, 7.01453247e+02, + 6.98573975e+02, 6.95686829e+02, 6.92791992e+02, + 6.89889526e+02, 6.86979614e+02, 6.84062256e+02, + 6.81137695e+02, 6.78205933e+02, 6.75267151e+02, + 6.72321472e+02, 6.69368958e+02, 6.66409790e+02, + 6.63444031e+02, 6.60471802e+02, 6.57493286e+02, + 6.54508484e+02, 6.51517639e+02, 6.48520813e+02, + 6.45518066e+02, 6.42509644e+02, 6.39495544e+02, + 6.36475952e+02, 6.33450989e+02, 6.30420776e+02, + 6.27385376e+02, 6.24344971e+02, 6.21299622e+02, + 6.18249512e+02, 6.15194702e+02, 6.12135376e+02, + 6.09071594e+02, 6.06003540e+02, 6.02931274e+02, + 5.99854980e+02, 5.96774719e+02, 5.93690674e+02, + 5.90602905e+02, 5.87511536e+02, 5.84416748e+02, + 5.81318604e+02, 5.78217224e+02, 5.75112793e+02, + 5.72005371e+02, 5.68895142e+02, 5.65782166e+02, + 5.62666626e+02, 5.59548584e+02, 5.56428223e+02, + 5.53305603e+02, 5.50180847e+02, 5.47054138e+02, + 5.43925598e+02, 5.40795288e+02, 5.37663391e+02, + 5.34530029e+02, 5.31395264e+02, 5.28259277e+02, + 5.25122131e+02, 5.21984070e+02, 5.18845093e+02, + 5.15705383e+02, 5.12565063e+02, 5.09424225e+02, + 5.06283020e+02, 5.03141571e+02, 5.00000000e+02, + 4.96858429e+02, 4.93716980e+02, 4.90575775e+02, + 4.87434967e+02, 4.84294617e+02, 4.81154907e+02, + 4.78015930e+02, 4.74877838e+02, 4.71740723e+02, + 4.68604736e+02, 4.65470001e+02, 4.62336609e+02, + 4.59204681e+02, 4.56074402e+02, 4.52945831e+02, + 4.49819153e+02, 4.46694427e+02, 4.43571808e+02, + 4.40451416e+02, 4.37333374e+02, 4.34217834e+02, + 4.31104858e+02, 4.27994598e+02, 4.24887207e+02, + 4.21782776e+02, 4.18681427e+02, 4.15583282e+02, + 4.12488464e+02, 4.09397125e+02, 4.06309357e+02, + 4.03225281e+02, 4.00145020e+02, 3.97068695e+02, + 3.93996460e+02, 3.90928375e+02, 3.87864624e+02, + 3.84805298e+02, 3.81750488e+02, 3.78700378e+02, + 3.75655060e+02, 3.72614624e+02, 3.69579254e+02, + 3.66549011e+02, 3.63524017e+02, 3.60504456e+02, + 3.57490356e+02, 3.54481903e+02, 3.51479218e+02, + 3.48482361e+02, 3.45491516e+02, 3.42506744e+02, + 3.39528198e+02, 3.36556000e+02, 3.33590240e+02, + 3.30631042e+02, 3.27678528e+02, 3.24732849e+02, + 3.21794067e+02, 3.18862305e+02, 3.15937714e+02, + 3.13020386e+02, 3.10110443e+02, 3.07208008e+02, + 3.04313171e+02, 3.01426056e+02, 2.98546783e+02, + 2.95675476e+02, 2.92812195e+02, 2.89957123e+02, + 2.87110352e+02, 2.84271973e+02, 2.81442108e+02, + 2.78620880e+02, 2.75808380e+02, 2.73004761e+02, + 2.70210083e+02, 2.67424469e+02, 2.64648041e+02, + 2.61880890e+02, 2.59123169e+02, 2.56374939e+02, + 2.53636322e+02, 2.50907440e+02, 2.48188400e+02, + 2.45479294e+02, 2.42780228e+02, 2.40091324e+02, + 2.37412689e+02, 2.34744415e+02, 2.32086609e+02, + 2.29439377e+02, 2.26802826e+02, 2.24177063e+02, + 2.21562195e+02, 2.18958313e+02, 2.16365524e+02, + 2.13783936e+02, 2.11213654e+02, 2.08654755e+02, + 2.06107376e+02, 2.03571594e+02, 2.01047516e+02, + 1.98535233e+02, 1.96034851e+02, 1.93546478e+02, + 1.91070190e+02, 1.88606110e+02, 1.86154312e+02, + 1.83714920e+02, 1.81288010e+02, 1.78873672e+02, + 1.76472015e+02, 1.74083130e+02, 1.71707123e+02, + 1.69344070e+02, 1.66994064e+02, 1.64657211e+02, + 1.62333603e+02, 1.60023315e+02, 1.57726440e+02, + 1.55443100e+02, 1.53173340e+02, 1.50917297e+02, + 1.48675018e+02, 1.46446609e+02, 1.44232162e+02, + 1.42031754e+02, 1.39845490e+02, 1.37673431e+02, + 1.35515686e+02, 1.33372330e+02, 1.31243439e+02, + 1.29129120e+02, 1.27029427e+02, 1.24944466e+02, + 1.22874313e+02, 1.20819046e+02, 1.18778748e+02, + 1.16753494e+02, 1.14743378e+02, 1.12748466e+02, + 1.10768852e+02, 1.08804596e+02, 1.06855782e+02, + 1.04922493e+02, 1.03004799e+02, 1.01102783e+02, + 9.92165070e+01, 9.73460541e+01, 9.54915009e+01, + 9.36529160e+01, 9.18303757e+01, 9.00239487e+01, + 8.82337036e+01, 8.64597092e+01, 8.47020493e+01, + 8.29607849e+01, 8.12359772e+01, 7.95277100e+01, + 7.78360367e+01, 7.61610336e+01, 7.45027618e+01, + 7.28612823e+01, 7.12366714e+01, 6.96289902e+01, + 6.80382919e+01, 6.64646530e+01, 6.49081192e+01, + 6.33687744e+01, 6.18466606e+01, 6.03418465e+01, + 5.88543854e+01, 5.73843460e+01, 5.59317741e+01, + 5.44967384e+01, 5.30792885e+01, 5.16794815e+01, + 5.02973747e+01, 4.89330215e+01, 4.75864754e+01, + 4.62577858e+01, 4.49470139e+01, 4.36542053e+01, + 4.23794136e+01, 4.11226883e+01, 3.98840752e+01, + 3.86636314e+01, 3.74613953e+01, 3.62774239e+01, + 3.51117554e+01, 3.39644432e+01, 3.28355293e+01, + 3.17250557e+01, 3.06330719e+01, 2.95596161e+01, + 2.85047321e+01, 2.74684620e+01, 2.64508476e+01, + 2.54519272e+01, 2.44717426e+01, 2.35103283e+01, + 2.25677280e+01, 2.16439743e+01, 2.07391052e+01, + 1.98531570e+01, 1.89861641e+01, 1.81381607e+01, + 1.73091812e+01, 1.64992561e+01, 1.57084198e+01, + 1.49367018e+01, 1.41841335e+01, 1.34507446e+01, + 1.27365637e+01, 1.20416193e+01, 1.13659382e+01, + 1.07095480e+01, 1.00724735e+01, 9.45474148e+00, + 8.85637474e+00, 8.27739716e+00, 7.71783257e+00, + 7.17770243e+00, 6.65702772e+00, 6.15582991e+00, + 5.67412758e+00, 5.21194077e+00, 4.76928711e+00, + 4.34618425e+00, 3.94264936e+00, 3.55869770e+00, + 3.19434476e+00, 2.84960485e+00, 2.52449155e+00, + 2.21901774e+00, 1.93319547e+00, 1.66703594e+00, + 1.42054987e+00, 1.19374681e+00, 9.86635804e-01, + 7.99224913e-01, 6.31521702e-01, 4.83532667e-01, + 3.55263680e-01, 2.46719822e-01, 1.57905355e-01, + 8.88238102e-02, 3.94778959e-02, 9.86957178e-03, + 0.00000000e+00, 9.86957271e-03, 3.94778997e-02, + 8.88238102e-02, 1.57905355e-01, 2.46719822e-01, + 3.55263680e-01, 4.83532667e-01, 6.31521702e-01, + 7.99224973e-01, 9.86635804e-01, 1.19374681e+00, + 1.42054987e+00, 1.66703594e+00, 1.93319547e+00, + 2.21901774e+00, 2.52449155e+00, 2.84960485e+00, + 3.19434476e+00, 3.55869770e+00, 3.94264936e+00, + 4.34618425e+00, 4.76928711e+00, 5.21194077e+00, + 5.67412758e+00, 6.15582991e+00, 6.65702772e+00, + 7.17770243e+00, 7.71783257e+00, 8.27739716e+00, + 8.85637474e+00, 9.45474148e+00, 1.00724735e+01, + 1.07095480e+01, 1.13659382e+01, 1.20416193e+01, + 1.27365637e+01, 1.34507446e+01, 1.41841335e+01, + 1.49367018e+01, 1.57084198e+01, 1.64992561e+01, + 1.73091812e+01, 1.81381607e+01, 1.89861641e+01, + 1.98531570e+01, 2.07391052e+01, 2.16439743e+01, + 2.25677280e+01, 2.35103302e+01, 2.44717426e+01, + 2.54519272e+01, 2.64508476e+01, 2.74684620e+01, + 2.85047321e+01, 2.95596161e+01, 3.06330719e+01, + 3.17250576e+01, 3.28355293e+01, 3.39644432e+01, + 3.51117554e+01, 3.62774239e+01, 3.74613953e+01, + 3.86636314e+01, 3.98840752e+01, 4.11226883e+01, + 4.23794136e+01, 4.36542053e+01, 4.49470139e+01, + 4.62577896e+01, 4.75864754e+01, 4.89330215e+01, + 5.02973747e+01, 5.16794815e+01, 5.30792885e+01, + 5.44967384e+01, 5.59317741e+01, 5.73843460e+01, + 5.88543854e+01, 6.03418465e+01, 6.18466606e+01, + 6.33687744e+01, 6.49081192e+01, 6.64646530e+01, + 6.80382919e+01, 6.96289902e+01, 7.12366714e+01, + 7.28612823e+01, 7.45027618e+01, 7.61610336e+01, + 7.78360367e+01, 7.95277100e+01, 8.12359772e+01, + 8.29607849e+01, 8.47020493e+01, 8.64597092e+01, + 8.82337036e+01, 9.00239487e+01, 9.18303757e+01, + 9.36529160e+01, 9.54915009e+01, 9.73460541e+01, + 9.92165070e+01, 1.01102783e+02, 1.03004799e+02, + 1.04922493e+02, 1.06855782e+02, 1.08804596e+02, + 1.10768852e+02, 1.12748466e+02, 1.14743378e+02, + 1.16753494e+02, 1.18778748e+02, 1.20819046e+02, + 1.22874313e+02, 1.24944466e+02, 1.27029427e+02, + 1.29129120e+02, 1.31243439e+02, 1.33372330e+02, + 1.35515686e+02, 1.37673431e+02, 1.39845490e+02, + 1.42031754e+02, 1.44232162e+02, 1.46446609e+02, + 1.48675018e+02, 1.50917297e+02, 1.53173340e+02, + 1.55443100e+02, 1.57726440e+02, 1.60023315e+02, + 1.62333603e+02, 1.64657211e+02, 1.66994064e+02, + 1.69344070e+02, 1.71707123e+02, 1.74083130e+02, + 1.76472015e+02, 1.78873672e+02, 1.81288010e+02, + 1.83714920e+02, 1.86154312e+02, 1.88606110e+02, + 1.91070190e+02, 1.93546478e+02, 1.96034851e+02, + 1.98535233e+02, 2.01047516e+02, 2.03571594e+02, + 2.06107376e+02, 2.08654755e+02, 2.11213654e+02, + 2.13783936e+02, 2.16365524e+02, 2.18958313e+02, + 2.21562195e+02, 2.24177063e+02, 2.26802826e+02, + 2.29439377e+02, 2.32086609e+02, 2.34744415e+02, + 2.37412689e+02, 2.40091324e+02, 2.42780228e+02, + 2.45479294e+02, 2.48188400e+02, 2.50907440e+02, + 2.53636322e+02, 2.56374939e+02, 2.59123169e+02, + 2.61880890e+02, 2.64648041e+02, 2.67424469e+02, + 2.70210083e+02, 2.73004761e+02, 2.75808380e+02, + 2.78620880e+02, 2.81442108e+02, 2.84271973e+02, + 2.87110352e+02, 2.89957123e+02, 2.92812195e+02, + 2.95675476e+02, 2.98546783e+02, 3.01426056e+02, + 3.04313171e+02, 3.07208008e+02, 3.10110443e+02, + 3.13020386e+02, 3.15937714e+02, 3.18862305e+02, + 3.21794067e+02, 3.24732849e+02, 3.27678528e+02, + 3.30631042e+02, 3.33590240e+02, 3.36556000e+02, + 3.39528198e+02, 3.42506744e+02, 3.45491516e+02, + 3.48482361e+02, 3.51479218e+02, 3.54481903e+02, + 3.57490356e+02, 3.60504456e+02, 3.63524017e+02, + 3.66549011e+02, 3.69579254e+02, 3.72614624e+02, + 3.75655060e+02, 3.78700378e+02, 3.81750488e+02, + 3.84805298e+02, 3.87864624e+02, 3.90928375e+02, + 3.93996460e+02, 3.97068695e+02, 4.00145020e+02, + 4.03225281e+02, 4.06309357e+02, 4.09397125e+02, + 4.12488464e+02, 4.15583282e+02, 4.18681427e+02, + 4.21782776e+02, 4.24887207e+02, 4.27994598e+02, + 4.31104858e+02, 4.34217834e+02, 4.37333374e+02, + 4.40451416e+02, 4.43571808e+02, 4.46694427e+02, + 4.49819153e+02, 4.52945831e+02, 4.56074402e+02, + 4.59204681e+02, 4.62336609e+02, 4.65470001e+02, + 4.68604736e+02, 4.71740723e+02, 4.74877838e+02, + 4.78015930e+02, 4.81154907e+02, 4.84294617e+02, + 4.87434967e+02, 4.90575775e+02, 4.93716980e+02, + 4.96858429e+02, 5.00000000e+02, 5.03141571e+02, + 5.06283020e+02, 5.09424225e+02], dtype=float32), +'ASAM.M.SCALAR.UWORD.IDENTICAL': array([ 32, 33, 35, 36, 37, 38, 39, 41, 42, 43, 44, + 46, 47, 48, 50, 51, 53, 54, 55, 57, 58, 60, + 61, 63, 64, 66, 68, 69, 71, 72, 74, 76, 77, + 79, 81, 82, 84, 86, 88, 90, 91, 93, 95, 97, + 99, 101, 103, 104, 106, 108, 110, 112, 114, 116, 118, + 120, 122, 124, 127, 129, 131, 133, 135, 137, 139, 142, + 144, 146, 148, 150, 153, 155, 157, 160, 162, 164, 166, + 169, 171, 174, 176, 178, 181, 183, 186, 188, 191, 193, + 196, 198, 201, 203, 206, 208, 211, 213, 216, 218, 221, + 224, 226, 229, 232, 234, 237, 240, 242, 245, 248, 250, + 253, 256, 259, 261, 264, 267, 270, 273, 275, 278, 281, + 284, 287, 289, 292, 295, 298, 301, 304, 307, 310, 313, + 315, 318, 321, 324, 327, 330, 333, 336, 339, 342, 345, + 348, 351, 354, 357, 360, 363, 366, 369, 372, 375, 378, + 381, 384, 387, 390, 393, 397, 400, 403, 406, 409, 412, + 415, 418, 421, 424, 427, 431, 434, 437, 440, 443, 446, + 449, 452, 456, 459, 462, 465, 468, 471, 474, 478, 481, + 484, 487, 490, 493, 496, 500, 503, 506, 509, 512, 515, + 518, 521, 525, 528, 531, 534, 537, 540, 543, 547, 550, + 553, 556, 559, 562, 565, 568, 572, 575, 578, 581, 584, + 587, 590, 593, 596, 599, 602, 606, 609, 612, 615, 618, + 621, 624, 627, 630, 633, 636, 639, 642, 645, 648, 651, + 654, 657, 660, 663, 666, 669, 672, 675, 678, 681, 684, + 686, 689, 692, 695, 698, 701, 704, 707, 710, 712, 715, + 718, 721, 724, 726, 729, 732, 735, 738, 740, 743, 746, + 749, 751, 754, 757, 759, 762, 765, 767, 770, 773, 775, + 778, 781, 783, 786, 788, 791, 793, 796, 798, 801, 803, + 806, 808, 811, 813, 816, 818, 821, 823, 825, 828, 830, + 833, 835, 837, 839, 842, 844, 846, 849, 851, 853, 855, + 857, 860, 862, 864, 866, 868, 870, 872, 875, 877, 879, + 881, 883, 885, 887, 889, 891, 893, 895, 896, 898, 900, + 902, 904, 906, 908, 909, 911, 913, 915, 917, 918, 920, + 922, 923, 925, 927, 928, 930, 931, 933, 935, 936, 938, + 939, 941, 942, 944, 945, 946, 948, 949, 951, 952, 953, + 955, 956, 957, 958, 960, 961, 962, 963, 964, 966, 967, + 968, 969, 970, 971, 972, 973, 974, 975, 976, 977, 978, + 979, 980, 981, 981, 982, 983, 984, 985, 985, 986, 987, + 987, 988, 989, 989, 990, 991, 991, 992, 992, 993, 993, + 994, 994, 995, 995, 996, 996, 996, 997, 997, 997, 998, + 998, 998, 998, 999, 999, 999, 999, 999, 999, 999, 999, + 999, 999, 1000, 999, 999, 999, 999, 999, 999, 999, 999, + 999, 999, 998, 998, 998, 998, 997, 997, 997, 996, 996, + 996, 995, 995, 994, 994, 993, 993, 992, 992, 991, 991, + 990, 989, 989, 988, 987, 987, 986, 985, 985, 984, 983, + 982, 981, 981, 980, 979, 978, 977, 976, 975, 974, 973, + 972, 971, 970, 969, 968, 967, 966, 964, 963, 962, 961, + 960, 958, 957, 956, 955, 953, 952, 951, 949, 948, 946, + 945, 944, 942, 941, 939, 938, 936, 935, 933, 931, 930, + 928, 927, 925, 923, 922, 920, 918, 917, 915, 913, 911, + 909, 908, 906, 904, 902, 900, 898, 896, 895, 893, 891, + 889, 887, 885, 883, 881, 879, 877, 875, 872, 870, 868, + 866, 864, 862, 860, 857, 855, 853, 851, 849, 846, 844, + 842, 839, 837, 835, 833, 830, 828, 825, 823, 821, 818, + 816, 813, 811, 808, 806, 803, 801, 798, 796, 793, 791, + 788, 786, 783, 781, 778, 775, 773, 770, 767, 765, 762, + 759, 757, 754, 751, 749, 746, 743, 740, 738, 735, 732, + 729, 726, 724, 721, 718, 715, 712, 710, 707, 704, 701, + 698, 695, 692, 689, 686, 684, 681, 678, 675, 672, 669, + 666, 663, 660, 657, 654, 651, 648, 645, 642, 639, 636, + 633, 630, 627, 624, 621, 618, 615, 612, 609, 606, 602, + 599, 596, 593, 590, 587, 584, 581, 578, 575, 572, 568, + 565, 562, 559, 556, 553, 550, 547, 543, 540, 537, 534, + 531, 528, 525, 521, 518, 515, 512, 509, 506, 503, 499, + 496, 493, 490, 487, 484, 481, 478, 474, 471, 468, 465, + 462, 459, 456, 452, 449, 446, 443, 440, 437, 434, 431, + 427, 424, 421, 418, 415, 412, 409, 406, 403, 400, 397, + 393, 390, 387, 384, 381, 378, 375, 372, 369, 366, 363, + 360, 357, 354, 351, 348, 345, 342, 339, 336, 333, 330, + 327, 324, 321, 318, 315, 313, 310, 307, 304, 301, 298, + 295, 292, 289, 287, 284, 281, 278, 275, 273, 270, 267, + 264, 261, 259, 256, 253, 250, 248, 245, 242, 240, 237, + 234, 232, 229, 226, 224, 221, 218, 216, 213, 211, 208, + 206, 203, 201, 198, 196, 193, 191, 188, 186, 183, 181, + 178, 176, 174, 171, 169, 166, 164, 162, 160, 157, 155, + 153, 150, 148, 146, 144, 142, 139, 137, 135, 133, 131, + 129, 127, 124, 122, 120, 118, 116, 114, 112, 110, 108, + 106, 104, 103, 101, 99, 97, 95, 93, 91, 90, 88, + 86, 84, 82, 81, 79, 77, 76, 74, 72, 71, 69, + 68, 66, 64, 63, 61, 60, 58, 57, 55, 54, 53, + 51, 50, 48, 47, 46, 44, 43, 42, 41, 39, 38, + 37, 36, 35, 33, 32, 31, 30, 29, 28, 27, 26, + 25, 24, 23, 22, 21], dtype=uint16), +'ASAM.M.SCALAR.UBYTE.TAB_VERB_NO_DEFAULT_VALUE': array([ 17, 16, 15, 14, 14, 13, 12, 12, 11, 10, 10, 9, 8, + 8, 7, 7, 6, 6, 5, 5, 4, 4, 3, 3, 3, 2, + 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, + 5, 5, 6, 6, 7, 7, 8, 8, 9, 10, 10, 11, 12, + 12, 13, 14, 14, 15, 16, 17, 18, 18, 19, 20, 21, 22, + 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 35, 36, + 37, 38, 39, 41, 42, 43, 44, 46, 47, 48, 50, 51, 53, + 54, 55, 57, 58, 60, 61, 63, 64, 66, 68, 69, 71, 72, + 74, 76, 77, 79, 81, 82, 84, 86, 88, 90, 91, 93, 95, + 97, 99, 101, 103, 104, 106, 108, 110, 112, 114, 116, 118, 120, + 122, 124, 127, 129, 131, 133, 135, 137, 139, 142, 144, 146, 148, + 150, 153, 155, 157, 160, 162, 164, 166, 169, 171, 174, 176, 178, + 181, 183, 186, 188, 191, 193, 196, 198, 201, 203, 206, 208, 211, + 213, 216, 218, 221, 224, 226, 229, 232, 234, 237, 240, 242, 245, + 248, 250, 253, 0, 3, 5, 8, 11, 14, 17, 19, 22, 25, + 28, 31, 33, 36, 39, 42, 45, 48, 51, 54, 57, 59, 62, + 65, 68, 71, 74, 77, 80, 83, 86, 89, 92, 95, 98, 101, + 104, 107, 110, 113, 116, 119, 122, 125, 128, 131, 134, 137, 141, + 144, 147, 150, 153, 156, 159, 162, 165, 168, 171, 175, 178, 181, + 184, 187, 190, 193, 196, 200, 203, 206, 209, 212, 215, 218, 222, + 225, 228, 231, 234, 237, 240, 244, 247, 250, 253, 0, 3, 6, + 9, 13, 16, 19, 22, 25, 28, 31, 35, 38, 41, 44, 47, + 50, 53, 56, 60, 63, 66, 69, 72, 75, 78, 81, 84, 87, + 90, 94, 97, 100, 103, 106, 109, 112, 115, 118, 121, 124, 127, + 130, 133, 136, 139, 142, 145, 148, 151, 154, 157, 160, 163, 166, + 169, 172, 174, 177, 180, 183, 186, 189, 192, 195, 198, 200, 203, + 206, 209, 212, 214, 217, 220, 223, 226, 228, 231, 234, 237, 239, + 242, 245, 247, 250, 253, 255, 2, 5, 7, 10, 13, 15, 18, + 20, 23, 25, 28, 30, 33, 35, 38, 40, 43, 45, 48, 50, + 53, 55, 57, 60, 62, 65, 67, 69, 71, 74, 76, 78, 81, + 83, 85, 87, 89, 92, 94, 96, 98, 100, 102, 104, 107, 109, + 111, 113, 115, 117, 119, 121, 123, 125, 127, 128, 130, 132, 134, + 136, 138, 140, 141, 143, 145, 147, 149, 150, 152, 154, 155, 157, + 159, 160, 162, 163, 165, 167, 168, 170, 171, 173, 174, 176, 177, + 178, 180, 181, 183, 184, 185, 187, 188, 189, 190, 192, 193, 194, + 195, 196, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, + 209, 210, 211, 212, 213, 213, 214, 215, 216, 217, 217, 218, 219, + 219, 220, 221, 221, 222, 223, 223, 224, 224, 225, 225, 226, 226, + 227, 227, 228, 228, 228, 229, 229, 229, 230, 230, 230, 230, 231, + 231, 231, 231, 231, 231, 231, 231, 231, 231, 232, 231, 231, 231, + 231, 231, 231, 231, 231, 231, 231, 230, 230, 230, 230, 229, 229, + 229, 228, 228, 228, 227, 227, 226, 226, 225, 225, 224, 224, 223, + 223, 222, 221, 221, 220, 219, 219, 218, 217, 217, 216, 215, 214, + 213, 213, 212, 211, 210, 209, 208, 207, 206, 205, 204, 203, 202, + 201, 200, 199, 198, 196, 195, 194, 193, 192, 190, 189, 188, 187, + 185, 184, 183, 181, 180, 178, 177, 176, 174, 173, 171, 170, 168, + 167, 165, 163, 162, 160, 159, 157, 155, 154, 152, 150, 149, 147, + 145, 143, 141, 140, 138, 136, 134, 132, 130, 128, 127, 125, 123, + 121, 119, 117, 115, 113, 111, 109, 107, 104, 102, 100, 98, 96, + 94, 92, 89, 87, 85, 83, 81, 78, 76, 74, 71, 69, 67, + 65, 62, 60, 57, 55, 53, 50, 48, 45, 43, 40, 38, 35, + 33, 30, 28, 25, 23, 20, 18, 15, 13, 10, 7, 5, 2, + 255, 253, 250, 247, 245, 242, 239, 237, 234, 231, 228, 226, 223, + 220, 217, 214, 212, 209, 206, 203, 200, 198, 195, 192, 189, 186, + 183, 180, 177, 174, 172, 169, 166, 163, 160, 157, 154, 151, 148, + 145, 142, 139, 136, 133, 130, 127, 124, 121, 118, 115, 112, 109, + 106, 103, 100, 97, 94, 90, 87, 84, 81, 78, 75, 72, 69, + 66, 63, 60, 56, 53, 50, 47, 44, 41, 38, 35, 31, 28, + 25, 22, 19, 16, 13, 9, 6, 3, 0, 253, 250, 247, 243, + 240, 237, 234, 231, 228, 225, 222, 218, 215, 212, 209, 206, 203, + 200, 196, 193, 190, 187, 184, 181, 178, 175, 171, 168, 165, 162, + 159, 156, 153, 150, 147, 144, 141, 137, 134, 131, 128, 125, 122, + 119, 116, 113, 110, 107, 104, 101, 98, 95, 92, 89, 86, 83, + 80, 77, 74, 71, 68, 65, 62, 59, 57, 54, 51, 48, 45, + 42, 39, 36, 33, 31, 28, 25, 22, 19, 17, 14, 11, 8, + 5, 3, 0, 253, 250, 248, 245, 242, 240, 237, 234, 232, 229, + 226, 224, 221, 218, 216, 213, 211, 208, 206, 203, 201, 198], dtype=uint8), +'ASAM.M.SCALAR.UBYTE.TAB_NOINTP_NO_DEFAULT_VALUE': array([ 105. , 102. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 109. , 106. , 103. , + 100. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 110.33333588, 108. , 105. , + 103. , 100. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 110.66666412, 110.66666412, + 110.33333588, 110. , 110. , 109. , + 108. , 108. , 107. , 107. , + 106. , 106. , 105. , 105. , + 104. , 104. , 103. , 103. , + 103. , 102. , 102. , 102. , + 101. , 101. , 101. , 101. , + 100. , 100. , 100. , 100. , + 100. , 100. , 100. , 100. , + 100. , 100. , 100. , 100. , + 100. , 100. , 100. , 100. , + 100. , 100. , 100. , 100. , + 100. , 101. , 101. , 101. , + 101. , 102. , 102. , 102. , + 103. , 103. , 103. , 104. , + 104. , 105. , 105. , 106. , + 106. , 107. , 107. , 108. , + 108. , 109. , 110. , 110. , + 110.33333588, 110.66666412, 110.66666412, 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 100. , + 103. , 105. , 108. , 110.33333588, + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 100. , 103. , 106. , 109. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 102. , + 105. , 107. , 110. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. ], dtype=float32), +'ASAM.M.SCALAR.UBYTE.TAB_VERB_DEFAULT_VALUE': array([218, 215, 212, 209, 206, 203, 200, 196, 193, 190, 187, 184, 181, + 178, 175, 171, 168, 165, 162, 159, 156, 153, 150, 147, 144, 141, + 137, 134, 131, 128, 125, 122, 119, 116, 113, 110, 107, 104, 101, + 98, 95, 92, 89, 86, 83, 80, 77, 74, 71, 68, 65, 62, + 59, 57, 54, 51, 48, 45, 42, 39, 36, 33, 31, 28, 25, + 22, 19, 17, 14, 11, 8, 5, 3, 0, 253, 250, 248, 245, + 242, 240, 237, 234, 232, 229, 226, 224, 221, 218, 216, 213, 211, + 208, 206, 203, 201, 198, 196, 193, 191, 188, 186, 183, 181, 178, + 176, 174, 171, 169, 166, 164, 162, 160, 157, 155, 153, 150, 148, + 146, 144, 142, 139, 137, 135, 133, 131, 129, 127, 124, 122, 120, + 118, 116, 114, 112, 110, 108, 106, 104, 103, 101, 99, 97, 95, + 93, 91, 90, 88, 86, 84, 82, 81, 79, 77, 76, 74, 72, + 71, 69, 68, 66, 64, 63, 61, 60, 58, 57, 55, 54, 53, + 51, 50, 48, 47, 46, 44, 43, 42, 41, 39, 38, 37, 36, + 35, 33, 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, + 21, 20, 19, 18, 18, 17, 16, 15, 14, 14, 13, 12, 12, + 11, 10, 10, 9, 8, 8, 7, 7, 6, 6, 5, 5, 4, + 4, 3, 3, 3, 2, 2, 2, 1, 1, 1, 1, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, + 3, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, + 9, 10, 10, 11, 12, 12, 13, 14, 14, 15, 16, 17, 18, + 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, + 31, 32, 33, 35, 36, 37, 38, 39, 41, 42, 43, 44, 46, + 47, 48, 50, 51, 53, 54, 55, 57, 58, 60, 61, 63, 64, + 66, 68, 69, 71, 72, 74, 76, 77, 79, 81, 82, 84, 86, + 88, 90, 91, 93, 95, 97, 99, 101, 103, 104, 106, 108, 110, + 112, 114, 116, 118, 120, 122, 124, 127, 129, 131, 133, 135, 137, + 139, 142, 144, 146, 148, 150, 153, 155, 157, 160, 162, 164, 166, + 169, 171, 174, 176, 178, 181, 183, 186, 188, 191, 193, 196, 198, + 201, 203, 206, 208, 211, 213, 216, 218, 221, 224, 226, 229, 232, + 234, 237, 240, 242, 245, 248, 250, 253, 0, 3, 5, 8, 11, + 14, 17, 19, 22, 25, 28, 31, 33, 36, 39, 42, 45, 48, + 51, 54, 57, 59, 62, 65, 68, 71, 74, 77, 80, 83, 86, + 89, 92, 95, 98, 101, 104, 107, 110, 113, 116, 119, 122, 125, + 128, 131, 134, 137, 141, 144, 147, 150, 153, 156, 159, 162, 165, + 168, 171, 175, 178, 181, 184, 187, 190, 193, 196, 200, 203, 206, + 209, 212, 215, 218, 222, 225, 228, 231, 234, 237, 240, 244, 247, + 250, 253, 0, 3, 6, 9, 13, 16, 19, 22, 25, 28, 31, + 35, 38, 41, 44, 47, 50, 53, 56, 60, 63, 66, 69, 72, + 75, 78, 81, 84, 87, 90, 94, 97, 100, 103, 106, 109, 112, + 115, 118, 121, 124, 127, 130, 133, 136, 139, 142, 145, 148, 151, + 154, 157, 160, 163, 166, 169, 172, 174, 177, 180, 183, 186, 189, + 192, 195, 198, 200, 203, 206, 209, 212, 214, 217, 220, 223, 226, + 228, 231, 234, 237, 239, 242, 245, 247, 250, 253, 255, 2, 5, + 7, 10, 13, 15, 18, 20, 23, 25, 28, 30, 33, 35, 38, + 40, 43, 45, 48, 50, 53, 55, 57, 60, 62, 65, 67, 69, + 71, 74, 76, 78, 81, 83, 85, 87, 89, 92, 94, 96, 98, + 100, 102, 104, 107, 109, 111, 113, 115, 117, 119, 121, 123, 125, + 127, 128, 130, 132, 134, 136, 138, 140, 141, 143, 145, 147, 149, + 150, 152, 154, 155, 157, 159, 160, 162, 163, 165, 167, 168, 170, + 171, 173, 174, 176, 177, 178, 180, 181, 183, 184, 185, 187, 188, + 189, 190, 192, 193, 194, 195, 196, 198, 199, 200, 201, 202, 203, + 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 213, 214, 215, + 216, 217, 217, 218, 219, 219, 220, 221, 221, 222, 223, 223, 224, + 224, 225, 225, 226, 226, 227, 227, 228, 228, 228, 229, 229, 229, + 230, 230, 230, 230, 231, 231, 231, 231, 231, 231, 231, 231, 231, + 231, 232, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 230, + 230, 230, 230, 229, 229, 229, 228, 228, 228, 227, 227, 226, 226, + 225, 225, 224, 224, 223, 223, 222, 221, 221, 220, 219, 219, 218, + 217, 217, 216, 215, 214, 213, 213, 212, 211, 210, 209, 208, 207, + 206, 205, 204, 203, 202, 201, 200, 199, 198, 196, 195, 194, 193, + 192, 190, 189, 188, 187, 185, 184, 183, 181, 180, 178, 177, 176, + 174, 173, 171, 170, 168, 167, 165, 163, 162, 160, 159, 157, 155, + 154, 152, 150, 149, 147, 145, 143, 141, 140, 138, 136, 134, 132, + 130, 128, 127, 125, 123, 121, 119, 117, 115, 113, 111, 109, 107, + 104, 102, 100, 98, 96, 94, 92, 89, 87, 85, 83, 81, 78, + 76, 74, 71, 69, 67, 65, 62, 60, 57, 55, 53, 50, 48, + 45, 43, 40, 38, 35, 33, 30, 28, 25, 23, 20, 18], dtype=uint8), +'ASAM.M.SCALAR.ULONG.IDENTICAL': array([ 186, 183, 181, 178, 176, 174, 171, 169, 166, 164, 162, + 160, 157, 155, 153, 150, 148, 146, 144, 142, 139, 137, + 135, 133, 131, 129, 127, 124, 122, 120, 118, 116, 114, + 112, 110, 108, 106, 104, 103, 101, 99, 97, 95, 93, + 91, 90, 88, 86, 84, 82, 81, 79, 77, 76, 74, + 72, 71, 69, 68, 66, 64, 63, 61, 60, 58, 57, + 55, 54, 53, 51, 50, 48, 47, 46, 44, 43, 42, + 41, 39, 38, 37, 36, 35, 33, 32, 31, 30, 29, + 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, + 18, 17, 16, 15, 14, 14, 13, 12, 12, 11, 10, + 10, 9, 8, 8, 7, 7, 6, 6, 5, 5, 4, + 4, 3, 3, 3, 2, 2, 2, 1, 1, 1, 1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, + 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, + 5, 5, 6, 6, 7, 7, 8, 8, 9, 10, 10, + 11, 12, 12, 13, 14, 14, 15, 16, 17, 18, 18, + 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 30, 31, 32, 33, 35, 36, 37, 38, 39, 41, 42, + 43, 44, 46, 47, 48, 50, 51, 53, 54, 55, 57, + 58, 60, 61, 63, 64, 66, 68, 69, 71, 72, 74, + 76, 77, 79, 81, 82, 84, 86, 88, 90, 91, 93, + 95, 97, 99, 101, 103, 104, 106, 108, 110, 112, 114, + 116, 118, 120, 122, 124, 127, 129, 131, 133, 135, 137, + 139, 142, 144, 146, 148, 150, 153, 155, 157, 160, 162, + 164, 166, 169, 171, 174, 176, 178, 181, 183, 186, 188, + 191, 193, 196, 198, 201, 203, 206, 208, 211, 213, 216, + 218, 221, 224, 226, 229, 232, 234, 237, 240, 242, 245, + 248, 250, 253, 256, 259, 261, 264, 267, 270, 273, 275, + 278, 281, 284, 287, 289, 292, 295, 298, 301, 304, 307, + 310, 313, 315, 318, 321, 324, 327, 330, 333, 336, 339, + 342, 345, 348, 351, 354, 357, 360, 363, 366, 369, 372, + 375, 378, 381, 384, 387, 390, 393, 397, 400, 403, 406, + 409, 412, 415, 418, 421, 424, 427, 431, 434, 437, 440, + 443, 446, 449, 452, 456, 459, 462, 465, 468, 471, 474, + 478, 481, 484, 487, 490, 493, 496, 500, 503, 506, 509, + 512, 515, 518, 521, 525, 528, 531, 534, 537, 540, 543, + 547, 550, 553, 556, 559, 562, 565, 568, 572, 575, 578, + 581, 584, 587, 590, 593, 596, 599, 602, 606, 609, 612, + 615, 618, 621, 624, 627, 630, 633, 636, 639, 642, 645, + 648, 651, 654, 657, 660, 663, 666, 669, 672, 675, 678, + 681, 684, 686, 689, 692, 695, 698, 701, 704, 707, 710, + 712, 715, 718, 721, 724, 726, 729, 732, 735, 738, 740, + 743, 746, 749, 751, 754, 757, 759, 762, 765, 767, 770, + 773, 775, 778, 781, 783, 786, 788, 791, 793, 796, 798, + 801, 803, 806, 808, 811, 813, 816, 818, 821, 823, 825, + 828, 830, 833, 835, 837, 839, 842, 844, 846, 849, 851, + 853, 855, 857, 860, 862, 864, 866, 868, 870, 872, 875, + 877, 879, 881, 883, 885, 887, 889, 891, 893, 895, 896, + 898, 900, 902, 904, 906, 908, 909, 911, 913, 915, 917, + 918, 920, 922, 923, 925, 927, 928, 930, 931, 933, 935, + 936, 938, 939, 941, 942, 944, 945, 946, 948, 949, 951, + 952, 953, 955, 956, 957, 958, 960, 961, 962, 963, 964, + 966, 967, 968, 969, 970, 971, 972, 973, 974, 975, 976, + 977, 978, 979, 980, 981, 981, 982, 983, 984, 985, 985, + 986, 987, 987, 988, 989, 989, 990, 991, 991, 992, 992, + 993, 993, 994, 994, 995, 995, 996, 996, 996, 997, 997, + 997, 998, 998, 998, 998, 999, 999, 999, 999, 999, 999, + 999, 999, 999, 999, 1000, 999, 999, 999, 999, 999, 999, + 999, 999, 999, 999, 998, 998, 998, 998, 997, 997, 997, + 996, 996, 996, 995, 995, 994, 994, 993, 993, 992, 992, + 991, 991, 990, 989, 989, 988, 987, 987, 986, 985, 985, + 984, 983, 982, 981, 981, 980, 979, 978, 977, 976, 975, + 974, 973, 972, 971, 970, 969, 968, 967, 966, 964, 963, + 962, 961, 960, 958, 957, 956, 955, 953, 952, 951, 949, + 948, 946, 945, 944, 942, 941, 939, 938, 936, 935, 933, + 931, 930, 928, 927, 925, 923, 922, 920, 918, 917, 915, + 913, 911, 909, 908, 906, 904, 902, 900, 898, 896, 895, + 893, 891, 889, 887, 885, 883, 881, 879, 877, 875, 872, + 870, 868, 866, 864, 862, 860, 857, 855, 853, 851, 849, + 846, 844, 842, 839, 837, 835, 833, 830, 828, 825, 823, + 821, 818, 816, 813, 811, 808, 806, 803, 801, 798, 796, + 793, 791, 788, 786, 783, 781, 778, 775, 773, 770, 767, + 765, 762, 759, 757, 754, 751, 749, 746, 743, 740, 738, + 735, 732, 729, 726, 724, 721, 718, 715, 712, 710, 707, + 704, 701, 698, 695, 692, 689, 686, 684, 681, 678, 675, + 672, 669, 666, 663, 660, 657, 654, 651, 648, 645, 642, + 639, 636, 633, 630, 627, 624, 621, 618, 615, 612, 609, + 606, 602, 599, 596, 593, 590, 587, 584, 581, 578, 575, + 572, 568, 565, 562, 559, 556, 553, 550, 547, 543, 540, + 537, 534, 531, 528, 525, 521, 518, 515, 512, 509, 506, + 503, 499, 496, 493, 490], dtype=uint32), +'ASAM.M.SCALAR.UBYTE.VTAB_RANGE_NO_DEFAULT_VALUE': array([199, 198, 196, 195, 194, 193, 192, 190, 189, 188, 187, 185, 184, + 183, 181, 180, 178, 177, 176, 174, 173, 171, 170, 168, 167, 165, + 163, 162, 160, 159, 157, 155, 154, 152, 150, 149, 147, 145, 143, + 141, 140, 138, 136, 134, 132, 130, 128, 127, 125, 123, 121, 119, + 117, 115, 113, 111, 109, 107, 104, 102, 100, 98, 96, 94, 92, + 89, 87, 85, 83, 81, 78, 76, 74, 71, 69, 67, 65, 62, + 60, 57, 55, 53, 50, 48, 45, 43, 40, 38, 35, 33, 30, + 28, 25, 23, 20, 18, 15, 13, 10, 7, 5, 2, 255, 253, + 250, 247, 245, 242, 239, 237, 234, 231, 228, 226, 223, 220, 217, + 214, 212, 209, 206, 203, 200, 198, 195, 192, 189, 186, 183, 180, + 177, 174, 172, 169, 166, 163, 160, 157, 154, 151, 148, 145, 142, + 139, 136, 133, 130, 127, 124, 121, 118, 115, 112, 109, 106, 103, + 100, 97, 94, 90, 87, 84, 81, 78, 75, 72, 69, 66, 63, + 60, 56, 53, 50, 47, 44, 41, 38, 35, 31, 28, 25, 22, + 19, 16, 13, 9, 6, 3, 0, 253, 250, 247, 243, 240, 237, + 234, 231, 228, 225, 222, 218, 215, 212, 209, 206, 203, 200, 196, + 193, 190, 187, 184, 181, 178, 175, 171, 168, 165, 162, 159, 156, + 153, 150, 147, 144, 141, 137, 134, 131, 128, 125, 122, 119, 116, + 113, 110, 107, 104, 101, 98, 95, 92, 89, 86, 83, 80, 77, + 74, 71, 68, 65, 62, 59, 57, 54, 51, 48, 45, 42, 39, + 36, 33, 31, 28, 25, 22, 19, 17, 14, 11, 8, 5, 3, + 0, 253, 250, 248, 245, 242, 240, 237, 234, 232, 229, 226, 224, + 221, 218, 216, 213, 211, 208, 206, 203, 201, 198, 196, 193, 191, + 188, 186, 183, 181, 178, 176, 174, 171, 169, 166, 164, 162, 160, + 157, 155, 153, 150, 148, 146, 144, 142, 139, 137, 135, 133, 131, + 129, 127, 124, 122, 120, 118, 116, 114, 112, 110, 108, 106, 104, + 103, 101, 99, 97, 95, 93, 91, 90, 88, 86, 84, 82, 81, + 79, 77, 76, 74, 72, 71, 69, 68, 66, 64, 63, 61, 60, + 58, 57, 55, 54, 53, 51, 50, 48, 47, 46, 44, 43, 42, + 41, 39, 38, 37, 36, 35, 33, 32, 31, 30, 29, 28, 27, + 26, 25, 24, 23, 22, 21, 20, 19, 18, 18, 17, 16, 15, + 14, 14, 13, 12, 12, 11, 10, 10, 9, 8, 8, 7, 7, + 6, 6, 5, 5, 4, 4, 3, 3, 3, 2, 2, 2, 1, + 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, + 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 5, 5, 6, + 6, 7, 7, 8, 8, 9, 10, 10, 11, 12, 12, 13, 14, + 14, 15, 16, 17, 18, 18, 19, 20, 21, 22, 23, 24, 25, + 26, 27, 28, 29, 30, 31, 32, 33, 35, 36, 37, 38, 39, + 41, 42, 43, 44, 46, 47, 48, 50, 51, 53, 54, 55, 57, + 58, 60, 61, 63, 64, 66, 68, 69, 71, 72, 74, 76, 77, + 79, 81, 82, 84, 86, 88, 90, 91, 93, 95, 97, 99, 101, + 103, 104, 106, 108, 110, 112, 114, 116, 118, 120, 122, 124, 127, + 129, 131, 133, 135, 137, 139, 142, 144, 146, 148, 150, 153, 155, + 157, 160, 162, 164, 166, 169, 171, 174, 176, 178, 181, 183, 186, + 188, 191, 193, 196, 198, 201, 203, 206, 208, 211, 213, 216, 218, + 221, 224, 226, 229, 232, 234, 237, 240, 242, 245, 248, 250, 253, + 0, 3, 5, 8, 11, 14, 17, 19, 22, 25, 28, 31, 33, + 36, 39, 42, 45, 48, 51, 54, 57, 59, 62, 65, 68, 71, + 74, 77, 80, 83, 86, 89, 92, 95, 98, 101, 104, 107, 110, + 113, 116, 119, 122, 125, 128, 131, 134, 137, 141, 144, 147, 150, + 153, 156, 159, 162, 165, 168, 171, 175, 178, 181, 184, 187, 190, + 193, 196, 200, 203, 206, 209, 212, 215, 218, 222, 225, 228, 231, + 234, 237, 240, 244, 247, 250, 253, 0, 3, 6, 9, 13, 16, + 19, 22, 25, 28, 31, 35, 38, 41, 44, 47, 50, 53, 56, + 60, 63, 66, 69, 72, 75, 78, 81, 84, 87, 90, 94, 97, + 100, 103, 106, 109, 112, 115, 118, 121, 124, 127, 130, 133, 136, + 139, 142, 145, 148, 151, 154, 157, 160, 163, 166, 169, 172, 174, + 177, 180, 183, 186, 189, 192, 195, 198, 200, 203, 206, 209, 212, + 214, 217, 220, 223, 226, 228, 231, 234, 237, 239, 242, 245, 247, + 250, 253, 255, 2, 5, 7, 10, 13, 15, 18, 20, 23, 25, + 28, 30, 33, 35, 38, 40, 43, 45, 48, 50, 53, 55, 57, + 60, 62, 65, 67, 69, 71, 74, 76, 78, 81, 83, 85, 87, + 89, 92, 94, 96, 98, 100, 102, 104, 107, 109, 111, 113, 115, + 117, 119, 121, 123, 125, 127, 128, 130, 132, 134, 136, 138, 140, + 141, 143, 145, 147, 149, 150, 152, 154, 155, 157, 159, 160, 162, + 163, 165, 167, 168, 170, 171, 173, 174, 176, 177, 178, 180, 181, + 183, 184, 185, 187, 188, 189, 190, 192, 193, 194, 195, 196, 198, + 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210], dtype=uint8), +'ASAM.M.SCALAR.FLOAT64.IDENTICAL': array([ 1.73091812e+01, 1.64992561e+01, 1.57084198e+01, + 1.49367018e+01, 1.41841335e+01, 1.34507446e+01, + 1.27365637e+01, 1.20416193e+01, 1.13659382e+01, + 1.07095480e+01, 1.00724735e+01, 9.45474148e+00, + 8.85637474e+00, 8.27739716e+00, 7.71783257e+00, + 7.17770243e+00, 6.65702772e+00, 6.15582991e+00, + 5.67412758e+00, 5.21194077e+00, 4.76928711e+00, + 4.34618425e+00, 3.94264936e+00, 3.55869770e+00, + 3.19434476e+00, 2.84960485e+00, 2.52449155e+00, + 2.21901774e+00, 1.93319547e+00, 1.66703594e+00, + 1.42054987e+00, 1.19374681e+00, 9.86635804e-01, + 7.99224973e-01, 6.31521702e-01, 4.83532667e-01, + 3.55263680e-01, 2.46719822e-01, 1.57905355e-01, + 8.88238102e-02, 3.94778997e-02, 9.86957178e-03, + 0.00000000e+00, 9.86957178e-03, 3.94778959e-02, + 8.88238102e-02, 1.57905355e-01, 2.46719822e-01, + 3.55263680e-01, 4.83532667e-01, 6.31521702e-01, + 7.99224973e-01, 9.86635804e-01, 1.19374681e+00, + 1.42054987e+00, 1.66703594e+00, 1.93319547e+00, + 2.21901774e+00, 2.52449155e+00, 2.84960485e+00, + 3.19434476e+00, 3.55869770e+00, 3.94264936e+00, + 4.34618425e+00, 4.76928711e+00, 5.21194077e+00, + 5.67412758e+00, 6.15582991e+00, 6.65702772e+00, + 7.17770243e+00, 7.71783257e+00, 8.27739716e+00, + 8.85637474e+00, 9.45474148e+00, 1.00724735e+01, + 1.07095480e+01, 1.13659382e+01, 1.20416193e+01, + 1.27365637e+01, 1.34507446e+01, 1.41841335e+01, + 1.49367018e+01, 1.57084198e+01, 1.64992561e+01, + 1.73091812e+01, 1.81381607e+01, 1.89861641e+01, + 1.98531570e+01, 2.07391052e+01, 2.16439743e+01, + 2.25677280e+01, 2.35103283e+01, 2.44717426e+01, + 2.54519272e+01, 2.64508476e+01, 2.74684620e+01, + 2.85047321e+01, 2.95596161e+01, 3.06330719e+01, + 3.17250557e+01, 3.28355293e+01, 3.39644432e+01, + 3.51117554e+01, 3.62774239e+01, 3.74613953e+01, + 3.86636314e+01, 3.98840752e+01, 4.11226883e+01, + 4.23794136e+01, 4.36542053e+01, 4.49470139e+01, + 4.62577896e+01, 4.75864754e+01, 4.89330215e+01, + 5.02973747e+01, 5.16794815e+01, 5.30792885e+01, + 5.44967384e+01, 5.59317741e+01, 5.73843460e+01, + 5.88543854e+01, 6.03418465e+01, 6.18466606e+01, + 6.33687744e+01, 6.49081192e+01, 6.64646530e+01, + 6.80382919e+01, 6.96289902e+01, 7.12366714e+01, + 7.28612823e+01, 7.45027618e+01, 7.61610336e+01, + 7.78360367e+01, 7.95277100e+01, 8.12359772e+01, + 8.29607849e+01, 8.47020493e+01, 8.64597092e+01, + 8.82337036e+01, 9.00239487e+01, 9.18303757e+01, + 9.36529160e+01, 9.54915009e+01, 9.73460541e+01, + 9.92165070e+01, 1.01102783e+02, 1.03004799e+02, + 1.04922493e+02, 1.06855782e+02, 1.08804596e+02, + 1.10768852e+02, 1.12748466e+02, 1.14743378e+02, + 1.16753494e+02, 1.18778748e+02, 1.20819046e+02, + 1.22874313e+02, 1.24944466e+02, 1.27029427e+02, + 1.29129120e+02, 1.31243439e+02, 1.33372330e+02, + 1.35515686e+02, 1.37673431e+02, 1.39845490e+02, + 1.42031754e+02, 1.44232162e+02, 1.46446609e+02, + 1.48675018e+02, 1.50917297e+02, 1.53173340e+02, + 1.55443100e+02, 1.57726440e+02, 1.60023315e+02, + 1.62333603e+02, 1.64657211e+02, 1.66994064e+02, + 1.69344070e+02, 1.71707123e+02, 1.74083130e+02, + 1.76472015e+02, 1.78873672e+02, 1.81288010e+02, + 1.83714920e+02, 1.86154312e+02, 1.88606110e+02, + 1.91070190e+02, 1.93546478e+02, 1.96034851e+02, + 1.98535233e+02, 2.01047516e+02, 2.03571594e+02, + 2.06107376e+02, 2.08654755e+02, 2.11213654e+02, + 2.13783936e+02, 2.16365524e+02, 2.18958313e+02, + 2.21562195e+02, 2.24177063e+02, 2.26802826e+02, + 2.29439377e+02, 2.32086609e+02, 2.34744415e+02, + 2.37412689e+02, 2.40091324e+02, 2.42780228e+02, + 2.45479294e+02, 2.48188400e+02, 2.50907440e+02, + 2.53636322e+02, 2.56374939e+02, 2.59123169e+02, + 2.61880890e+02, 2.64648041e+02, 2.67424469e+02, + 2.70210083e+02, 2.73004761e+02, 2.75808380e+02, + 2.78620880e+02, 2.81442108e+02, 2.84271973e+02, + 2.87110352e+02, 2.89957123e+02, 2.92812195e+02, + 2.95675476e+02, 2.98546783e+02, 3.01426056e+02, + 3.04313171e+02, 3.07208008e+02, 3.10110443e+02, + 3.13020386e+02, 3.15937714e+02, 3.18862305e+02, + 3.21794067e+02, 3.24732849e+02, 3.27678528e+02, + 3.30631042e+02, 3.33590240e+02, 3.36556000e+02, + 3.39528198e+02, 3.42506744e+02, 3.45491516e+02, + 3.48482361e+02, 3.51479218e+02, 3.54481903e+02, + 3.57490356e+02, 3.60504456e+02, 3.63524017e+02, + 3.66549011e+02, 3.69579254e+02, 3.72614624e+02, + 3.75655060e+02, 3.78700378e+02, 3.81750488e+02, + 3.84805298e+02, 3.87864624e+02, 3.90928375e+02, + 3.93996460e+02, 3.97068695e+02, 4.00145020e+02, + 4.03225281e+02, 4.06309357e+02, 4.09397125e+02, + 4.12488464e+02, 4.15583282e+02, 4.18681427e+02, + 4.21782776e+02, 4.24887207e+02, 4.27994598e+02, + 4.31104858e+02, 4.34217834e+02, 4.37333374e+02, + 4.40451416e+02, 4.43571808e+02, 4.46694427e+02, + 4.49819153e+02, 4.52945831e+02, 4.56074402e+02, + 4.59204681e+02, 4.62336609e+02, 4.65470001e+02, + 4.68604736e+02, 4.71740723e+02, 4.74877838e+02, + 4.78015930e+02, 4.81154907e+02, 4.84294617e+02, + 4.87434967e+02, 4.90575775e+02, 4.93716980e+02, + 4.96858429e+02, 5.00000000e+02, 5.03141571e+02, + 5.06283020e+02, 5.09424225e+02, 5.12565063e+02, + 5.15705383e+02, 5.18845093e+02, 5.21984070e+02, + 5.25122131e+02, 5.28259277e+02, 5.31395264e+02, + 5.34530029e+02, 5.37663391e+02, 5.40795288e+02, + 5.43925598e+02, 5.47054138e+02, 5.50180847e+02, + 5.53305603e+02, 5.56428223e+02, 5.59548584e+02, + 5.62666626e+02, 5.65782166e+02, 5.68895142e+02, + 5.72005371e+02, 5.75112793e+02, 5.78217224e+02, + 5.81318604e+02, 5.84416748e+02, 5.87511536e+02, + 5.90602905e+02, 5.93690674e+02, 5.96774719e+02, + 5.99854980e+02, 6.02931274e+02, 6.06003540e+02, + 6.09071594e+02, 6.12135376e+02, 6.15194702e+02, + 6.18249512e+02, 6.21299622e+02, 6.24344971e+02, + 6.27385376e+02, 6.30420776e+02, 6.33450989e+02, + 6.36475952e+02, 6.39495544e+02, 6.42509644e+02, + 6.45518066e+02, 6.48520813e+02, 6.51517639e+02, + 6.54508484e+02, 6.57493286e+02, 6.60471802e+02, + 6.63444031e+02, 6.66409790e+02, 6.69368958e+02, + 6.72321472e+02, 6.75267151e+02, 6.78205933e+02, + 6.81137695e+02, 6.84062256e+02, 6.86979614e+02, + 6.89889526e+02, 6.92791992e+02, 6.95686829e+02, + 6.98573975e+02, 7.01453247e+02, 7.04324524e+02, + 7.07187805e+02, 7.10042847e+02, 7.12889648e+02, + 7.15728027e+02, 7.18557861e+02, 7.21379089e+02, + 7.24191589e+02, 7.26995239e+02, 7.29789917e+02, + 7.32575562e+02, 7.35351990e+02, 7.38119080e+02, + 7.40876831e+02, 7.43625061e+02, 7.46363647e+02, + 7.49092529e+02, 7.51811584e+02, 7.54520691e+02, + 7.57219788e+02, 7.59908691e+02, 7.62587341e+02, + 7.65255615e+02, 7.67913391e+02, 7.70560608e+02, + 7.73197144e+02, 7.75822937e+02, 7.78437805e+02, + 7.81041687e+02, 7.83634460e+02, 7.86216064e+02, + 7.88786377e+02, 7.91345215e+02, 7.93892639e+02, + 7.96428406e+02, 7.98952515e+02, 8.01464783e+02, + 8.03965149e+02, 8.06453552e+02, 8.08929810e+02, + 8.11393860e+02, 8.13845703e+02, 8.16285095e+02, + 8.18711975e+02, 8.21126343e+02, 8.23527954e+02, + 8.25916870e+02, 8.28292908e+02, 8.30655945e+02, + 8.33005920e+02, 8.35342773e+02, 8.37666382e+02, + 8.39976685e+02, 8.42273560e+02, 8.44556885e+02, + 8.46826660e+02, 8.49082703e+02, 8.51325012e+02, + 8.53553406e+02, 8.55767822e+02, 8.57968262e+02, + 8.60154541e+02, 8.62326538e+02, 8.64484314e+02, + 8.66627686e+02, 8.68756531e+02, 8.70870911e+02, + 8.72970581e+02, 8.75055542e+02, 8.77125671e+02, + 8.79180969e+02, 8.81221252e+02, 8.83246521e+02, + 8.85256592e+02, 8.87251526e+02, 8.89231140e+02, + 8.91195435e+02, 8.93144226e+02, 8.95077515e+02, + 8.96995178e+02, 8.98897217e+02, 9.00783508e+02, + 9.02653931e+02, 9.04508484e+02, 9.06347107e+02, + 9.08169617e+02, 9.09976074e+02, 9.11766296e+02, + 9.13540283e+02, 9.15297974e+02, 9.17039246e+02, + 9.18764038e+02, 9.20472290e+02, 9.22163940e+02, + 9.23838989e+02, 9.25497253e+02, 9.27138733e+02, + 9.28763306e+02, 9.30371033e+02, 9.31961731e+02, + 9.33535339e+02, 9.35091858e+02, 9.36631226e+02, + 9.38153320e+02, 9.39658142e+02, 9.41145630e+02, + 9.42615662e+02, 9.44068237e+02, 9.45503235e+02, + 9.46920715e+02, 9.48320496e+02, 9.49702637e+02, + 9.51066956e+02, 9.52413513e+02, 9.53742188e+02, + 9.55052979e+02, 9.56345764e+02, 9.57620605e+02, + 9.58877319e+02, 9.60115906e+02, 9.61336365e+02, + 9.62538574e+02, 9.63722595e+02, 9.64888245e+02, + 9.66035583e+02, 9.67164490e+02, 9.68274963e+02, + 9.69366943e+02, 9.70440369e+02, 9.71495239e+02, + 9.72531555e+02, 9.73549133e+02, 9.74548096e+02, + 9.75528259e+02, 9.76489685e+02, 9.77432251e+02, + 9.78356018e+02, 9.79260864e+02, 9.80146851e+02, + 9.81013855e+02, 9.81861816e+02, 9.82690796e+02, + 9.83500732e+02, 9.84291565e+02, 9.85063293e+02, + 9.85815857e+02, 9.86549255e+02, 9.87263428e+02, + 9.87958374e+02, 9.88634033e+02, 9.89290466e+02, + 9.89927551e+02, 9.90545288e+02, 9.91143616e+02, + 9.91722595e+02, 9.92282166e+02, 9.92822327e+02, + 9.93342957e+02, 9.93844177e+02, 9.94325867e+02, + 9.94788086e+02, 9.95230713e+02, 9.95653809e+02, + 9.96057373e+02, 9.96441284e+02, 9.96805664e+02, + 9.97150391e+02, 9.97475525e+02, 9.97781006e+02, + 9.98066833e+02, 9.98332947e+02, 9.98579468e+02, + 9.98806274e+02, 9.99013367e+02, 9.99200745e+02, + 9.99368469e+02, 9.99516479e+02, 9.99644714e+02, + 9.99753296e+02, 9.99842102e+02, 9.99911194e+02, + 9.99960510e+02, 9.99990112e+02, 1.00000000e+03, + 9.99990112e+02, 9.99960510e+02, 9.99911194e+02, + 9.99842102e+02, 9.99753296e+02, 9.99644714e+02, + 9.99516479e+02, 9.99368469e+02, 9.99200745e+02, + 9.99013367e+02, 9.98806274e+02, 9.98579468e+02, + 9.98332947e+02, 9.98066833e+02, 9.97781006e+02, + 9.97475525e+02, 9.97150391e+02, 9.96805664e+02, + 9.96441284e+02, 9.96057373e+02, 9.95653809e+02, + 9.95230713e+02, 9.94788086e+02, 9.94325867e+02, + 9.93844177e+02, 9.93342957e+02, 9.92822327e+02, + 9.92282166e+02, 9.91722595e+02, 9.91143616e+02, + 9.90545288e+02, 9.89927551e+02, 9.89290466e+02, + 9.88634033e+02, 9.87958374e+02, 9.87263428e+02, + 9.86549255e+02, 9.85815857e+02, 9.85063293e+02, + 9.84291565e+02, 9.83500732e+02, 9.82690796e+02, + 9.81861816e+02, 9.81013855e+02, 9.80146851e+02, + 9.79260864e+02, 9.78356018e+02, 9.77432251e+02, + 9.76489685e+02, 9.75528259e+02, 9.74548096e+02, + 9.73549133e+02, 9.72531555e+02, 9.71495239e+02, + 9.70440369e+02, 9.69366943e+02, 9.68274963e+02, + 9.67164490e+02, 9.66035583e+02, 9.64888245e+02, + 9.63722595e+02, 9.62538574e+02, 9.61336365e+02, + 9.60115906e+02, 9.58877319e+02, 9.57620605e+02, + 9.56345764e+02, 9.55052979e+02, 9.53742188e+02, + 9.52413513e+02, 9.51066956e+02, 9.49702637e+02, + 9.48320496e+02, 9.46920715e+02, 9.45503235e+02, + 9.44068237e+02, 9.42615662e+02, 9.41145630e+02, + 9.39658142e+02, 9.38153320e+02, 9.36631226e+02, + 9.35091858e+02, 9.33535339e+02, 9.31961731e+02, + 9.30371033e+02, 9.28763306e+02, 9.27138733e+02, + 9.25497253e+02, 9.23838989e+02, 9.22163940e+02, + 9.20472290e+02, 9.18764038e+02, 9.17039246e+02, + 9.15297974e+02, 9.13540283e+02, 9.11766296e+02, + 9.09976074e+02, 9.08169617e+02, 9.06347107e+02, + 9.04508484e+02, 9.02653931e+02, 9.00783508e+02, + 8.98897217e+02, 8.96995178e+02, 8.95077515e+02, + 8.93144226e+02, 8.91195435e+02, 8.89231140e+02, + 8.87251526e+02, 8.85256592e+02, 8.83246521e+02, + 8.81221252e+02, 8.79180969e+02, 8.77125671e+02, + 8.75055542e+02, 8.72970581e+02, 8.70870911e+02, + 8.68756531e+02, 8.66627686e+02, 8.64484314e+02, + 8.62326538e+02, 8.60154541e+02, 8.57968262e+02, + 8.55767822e+02, 8.53553406e+02, 8.51325012e+02, + 8.49082703e+02, 8.46826660e+02, 8.44556885e+02, + 8.42273560e+02, 8.39976685e+02, 8.37666382e+02, + 8.35342773e+02, 8.33005920e+02, 8.30655945e+02, + 8.28292908e+02, 8.25916870e+02, 8.23527954e+02, + 8.21126343e+02, 8.18711975e+02, 8.16285095e+02, + 8.13845703e+02, 8.11393860e+02, 8.08929810e+02, + 8.06453552e+02, 8.03965149e+02, 8.01464783e+02, + 7.98952515e+02, 7.96428406e+02, 7.93892639e+02, + 7.91345215e+02, 7.88786377e+02, 7.86216064e+02, + 7.83634460e+02, 7.81041687e+02, 7.78437805e+02, + 7.75822937e+02, 7.73197144e+02, 7.70560608e+02, + 7.67913391e+02, 7.65255615e+02, 7.62587341e+02, + 7.59908691e+02, 7.57219788e+02, 7.54520691e+02, + 7.51811584e+02, 7.49092529e+02, 7.46363647e+02, + 7.43625061e+02, 7.40876831e+02, 7.38119080e+02, + 7.35351990e+02, 7.32575562e+02, 7.29789917e+02, + 7.26995239e+02, 7.24191589e+02, 7.21379089e+02, + 7.18557861e+02, 7.15728027e+02, 7.12889648e+02, + 7.10042847e+02, 7.07187805e+02, 7.04324524e+02, + 7.01453247e+02, 6.98573975e+02, 6.95686829e+02, + 6.92791992e+02, 6.89889526e+02, 6.86979614e+02, + 6.84062256e+02, 6.81137695e+02, 6.78205933e+02, + 6.75267151e+02, 6.72321472e+02, 6.69368958e+02, + 6.66409790e+02, 6.63444031e+02, 6.60471802e+02, + 6.57493286e+02, 6.54508484e+02, 6.51517639e+02, + 6.48520813e+02, 6.45518066e+02, 6.42509644e+02, + 6.39495544e+02, 6.36475952e+02, 6.33450989e+02, + 6.30420776e+02, 6.27385376e+02, 6.24344971e+02, + 6.21299622e+02, 6.18249512e+02, 6.15194702e+02, + 6.12135376e+02, 6.09071594e+02, 6.06003540e+02, + 6.02931274e+02, 5.99854980e+02, 5.96774719e+02, + 5.93690674e+02, 5.90602905e+02, 5.87511536e+02, + 5.84416748e+02, 5.81318604e+02, 5.78217224e+02, + 5.75112793e+02, 5.72005371e+02, 5.68895142e+02, + 5.65782166e+02, 5.62666626e+02, 5.59548584e+02, + 5.56428223e+02, 5.53305603e+02, 5.50180847e+02, + 5.47054138e+02, 5.43925598e+02, 5.40795288e+02, + 5.37663391e+02, 5.34530029e+02, 5.31395264e+02, + 5.28259277e+02, 5.25122131e+02, 5.21984070e+02, + 5.18845093e+02, 5.15705383e+02, 5.12565063e+02, + 5.09424225e+02, 5.06283020e+02, 5.03141571e+02, + 5.00000000e+02, 4.96858429e+02, 4.93716980e+02, + 4.90575775e+02, 4.87434967e+02, 4.84294617e+02, + 4.81154907e+02, 4.78015930e+02, 4.74877838e+02, + 4.71740723e+02, 4.68604736e+02, 4.65470001e+02, + 4.62336609e+02, 4.59204681e+02, 4.56074402e+02, + 4.52945831e+02, 4.49819153e+02, 4.46694427e+02, + 4.43571808e+02, 4.40451416e+02, 4.37333374e+02, + 4.34217834e+02, 4.31104858e+02, 4.27994598e+02, + 4.24887207e+02, 4.21782776e+02, 4.18681427e+02, + 4.15583282e+02, 4.12488464e+02, 4.09397125e+02, + 4.06309357e+02, 4.03225281e+02, 4.00145020e+02, + 3.97068695e+02, 3.93996460e+02, 3.90928375e+02, + 3.87864624e+02, 3.84805298e+02, 3.81750488e+02, + 3.78700378e+02, 3.75655060e+02, 3.72614624e+02, + 3.69579254e+02, 3.66549011e+02, 3.63524017e+02, + 3.60504456e+02, 3.57490356e+02, 3.54481903e+02, + 3.51479218e+02, 3.48482361e+02, 3.45491516e+02, + 3.42506744e+02, 3.39528198e+02, 3.36556000e+02, + 3.33590240e+02, 3.30631042e+02, 3.27678528e+02, + 3.24732849e+02, 3.21794067e+02, 3.18862305e+02, + 3.15937714e+02, 3.13020386e+02, 3.10110443e+02, + 3.07208008e+02, 3.04313171e+02, 3.01426056e+02, + 2.98546783e+02, 2.95675476e+02, 2.92812195e+02, + 2.89957123e+02, 2.87110352e+02, 2.84271973e+02, + 2.81442108e+02, 2.78620880e+02, 2.75808380e+02, + 2.73004761e+02, 2.70210083e+02, 2.67424469e+02, + 2.64648041e+02, 2.61880890e+02, 2.59123169e+02, + 2.56374939e+02, 2.53636322e+02, 2.50907440e+02, + 2.48188400e+02, 2.45479294e+02, 2.42780228e+02, + 2.40091324e+02, 2.37412689e+02, 2.34744415e+02, + 2.32086609e+02, 2.29439377e+02, 2.26802826e+02, + 2.24177063e+02, 2.21562195e+02, 2.18958313e+02, + 2.16365524e+02, 2.13783936e+02, 2.11213654e+02, + 2.08654755e+02, 2.06107376e+02, 2.03571594e+02, + 2.01047516e+02, 1.98535233e+02], dtype=float32), +'ASAM.M.SCALAR.UWORD.IDENTICAL.BITMASK_0008': array([0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, + 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, + 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1, + 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, + 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, + 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, + 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, + 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, + 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, + 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, + 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, + 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, + 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, + 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, + 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, + 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, + 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, + 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, + 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, + 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, + 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, + 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, + 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, + 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, + 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, + 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, + 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, + 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, + 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, + 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1], dtype=uint8), +'ASAM.M.VIRTUAL.SCALAR.SWORD.PHYSICAL': array([ -544, -464, -384, -304, -224, -144, -64, 16, 96, + 176, 256, 336, 416, 496, 576, 656, 736, 816, + 896, 976, -992, -912, -832, -752, -672, -592, -512, + -432, -352, -272, 0, 80, 160, 240, 320, 400, + 480, 560, 640, 720, 800, 880, 960, -1008, -928, + -848, -768, -688, -608, -528, -448, -368, -288, -208, + -128, -48, 32, 112, 192, 272, 352, 432, 512, + 592, 672, 752, 832, 912, 992, -976, -896, -816, + -736, -656, -576, -496, -416, -336, -256, -176, -96, + -16, 64, 144, 224, 304, 384, 464, 544, 624], dtype=int16), + } print("MDF read tests") + ret = True + for mdf in os.listdir('tmpdir'): for memory in MEMORY: - MDF(os.path.join('tmpdir', mdf), memory=memory).close() + with MDF(os.path.join('tmpdir', mdf), memory=memory) as input_file: + if input_file.version == '2.00': + continue + for name in set(input_file.channels_db) - {'time', 't'}: + signal = input_file.get(name) + original_samples = channels[name] + if signal.samples.dtype.kind == 'f': + signal = signal.astype(float32) + res = np.array_equal(signal.samples, original_samples) + if not res: + ret = False + + self.assertTrue(ret) def test_convert(self): print("MDF convert tests") From e584ea341b2da68e27c4b1cd0654c9b1e2dc8442 Mon Sep 17 00:00:00 2001 From: danielhrisca Date: Fri, 22 Dec 2017 10:53:23 +0200 Subject: [PATCH 032/117] mdfreader nodata merge tests --- benchmarks/bench.py | 75 +++++++++++++++++++++++++++++++-------------- 1 file changed, 52 insertions(+), 23 deletions(-) diff --git a/benchmarks/bench.py b/benchmarks/bench.py index 67149ae32..6ac1387b1 100644 --- a/benchmarks/bench.py +++ b/benchmarks/bench.py @@ -28,7 +28,7 @@ PYVERSION = sys.version_info[0] if PYVERSION > 2: - from time import perf_counter + from time import perf_counter else: from time import clock as perf_counter @@ -376,7 +376,7 @@ def get_all_reader3_compression(path, output, fmt): fmt) as timer: for s in x: x.getChannelData(s) - + with open('D:\\TMP\\f.txt', 'w') as f: f.write('OK') output.send([timer.output, timer.error]) @@ -443,6 +443,20 @@ def merge_reader_v3_compress(path, output, fmt): output.send([timer.output, timer.error]) +def merge_reader_v3_nodata(path, output, fmt): + os.chdir(path) + files = [r'test.mdf', ] * 2 + with Timer('Merge files', + 'mdfreader {} nodata v3'.format(mdfreader_version), + fmt) as timer: + x1 = MDFreader(files[0], noDataLoading=True) + x1.resample(0.01) + x2 = MDFreader(files[1], noDataLoading=True) + x2.resample(0.01) + x1.mergeMdf(x2) + output.send([timer.output, timer.error]) + + def merge_reader_v4(path, output, fmt): files = [r'test.mf4', ] * 2 os.chdir(path) @@ -470,6 +484,19 @@ def merge_reader_v4_compress(path, output, fmt): x1.mergeMdf(x2) output.send([timer.output, timer.error]) +def merge_reader_v4_nodata(path, output, fmt): + os.chdir(path) + files = [r'test.mf4', ] * 2 + with Timer('Merge files', + 'mdfreader {} nodata v4'.format(mdfreader_version), + fmt) as timer: + x1 = MDFreader(files[0], noDataLoading=True) + x1.resample(0.01) + x2 = MDFreader(files[1], noDataLoading=True) + x2.resample(0.01) + x1.mergeMdf(x2) + output.send([timer.output, timer.error]) + # # utility functions # @@ -537,13 +564,13 @@ def main(path, text_output, fmt): # partial(open_mdf3, memory='low'), # partial(open_mdf3, memory='minimum'), # open_reader3, -## open_reader3_compression, +# open_reader3_compression, # open_reader3_nodata, # partial(open_mdf4, memory='full'), # partial(open_mdf4, memory='low'), # partial(open_mdf4, memory='minimum'), # open_reader4, -## open_reader4_compression, +# open_reader4_compression, # open_reader4_nodata, ) @@ -564,13 +591,13 @@ def main(path, text_output, fmt): # partial(save_mdf3, memory='minimum'), # save_reader3, # save_reader3_nodata, -## save_reader3_compression, +# save_reader3_compression, # partial(save_mdf4, memory='full'), # partial(save_mdf4, memory='low'), # partial(save_mdf4, memory='minimum'), # save_reader4, # save_reader4_nodata, -## save_reader4_compression, +# save_reader4_compression, ) if tests: @@ -591,11 +618,11 @@ def main(path, text_output, fmt): # get_all_reader3, # get_all_reader3_nodata, # get_all_reader3_compression, - partial(get_all_mdf4, memory='full'), +# partial(get_all_mdf4, memory='full'), # partial(get_all_mdf4, memory='low'), - partial(get_all_mdf4, memory='minimum'), +# partial(get_all_mdf4, memory='minimum'), # get_all_reader4, - get_all_reader4_nodata, +# get_all_reader4_nodata, # get_all_reader4_compression, ) @@ -611,12 +638,12 @@ def main(path, text_output, fmt): output.extend(table_end(fmt)) tests = ( - partial(convert_v3_v4, memory='full'), - partial(convert_v3_v4, memory='low'), - partial(convert_v3_v4, memory='minimum'), - partial(convert_v4_v3, memory='full'), - partial(convert_v4_v3, memory='low'), - partial(convert_v4_v3, memory='minimum'), +# partial(convert_v3_v4, memory='full'), +# partial(convert_v3_v4, memory='low'), +# partial(convert_v3_v4, memory='minimum'), +# partial(convert_v4_v3, memory='full'), +# partial(convert_v4_v3, memory='low'), +# partial(convert_v4_v3, memory='minimum'), ) if tests: @@ -631,16 +658,18 @@ def main(path, text_output, fmt): output.extend(table_end(fmt)) tests = ( - partial(merge_v3, memory='full'), - partial(merge_v3, memory='low'), - partial(merge_v3, memory='minimum'), - merge_reader_v3, +# partial(merge_v3, memory='full'), +# partial(merge_v3, memory='low'), +# partial(merge_v3, memory='minimum'), +# merge_reader_v3, # merge_reader_v3_compress, - partial(merge_v4, memory='full'), - partial(merge_v4, memory='low'), - partial(merge_v4, memory='minimum'), +# merge_reader_v3_nodata, +# partial(merge_v4, memory='full'), +# partial(merge_v4, memory='low'), +# partial(merge_v4, memory='minimum'), merge_reader_v4, -# merge_reader_v4_compress, + merge_reader_v4_nodata, + merge_reader_v4_compress, ) if tests: From 1e76aff6a190e4b813723ee3926ef53d23f16cd7 Mon Sep 17 00:00:00 2001 From: danielhrisca Date: Fri, 22 Dec 2017 19:48:28 +0200 Subject: [PATCH 033/117] return raw channel values using get method --- asammdf/mdf2.py | 28 +++++++++++++++++++--------- asammdf/mdf3.py | 28 +++++++++++++++++++--------- asammdf/mdf4.py | 36 ++++++++++++++++++++++-------------- 3 files changed, 60 insertions(+), 32 deletions(-) diff --git a/asammdf/mdf2.py b/asammdf/mdf2.py index 5a2e42223..a75f2a104 100644 --- a/asammdf/mdf2.py +++ b/asammdf/mdf2.py @@ -2253,7 +2253,8 @@ def get(self, index=None, raster=None, samples_only=False, - data=None): + data=None, + raw=False): """Gets channel samples. Channel can be specified in two ways: @@ -2287,6 +2288,12 @@ def get(self, samples_only : bool if *True* return only the channel samples as numpy array; if *False* return a *Signal* object + data : bytes + prevent redundant data read by providing the raw data group samples + raw : bool + return channel samples without appling the conversion rule; default + `False` + Returns ------- @@ -2383,7 +2390,7 @@ def get(self, record_shape = tuple(shape) arrays = [ - self.get(group=dg_nr, index=ch_nr, samples_only=True) + self.get(group=dg_nr, index=ch_nr, samples_only=True, raw=raw) for ch_nr, dg_nr in dep.referenced_channels ] if cycles_nr: @@ -2463,7 +2470,10 @@ def get(self, if cycles_nr: - if conversion_type == v2c.CONVERSION_TYPE_NONE: + if raw: + pass + + elif conversion_type == v2c.CONVERSION_TYPE_NONE: if channel['data_type'] == v2c.DATA_TYPE_STRING: vals = [val.tobytes() for val in vals] @@ -2494,12 +2504,12 @@ def get(self, v2c.CONVERSION_TYPE_TABX): nr = conversion['ref_param_nr'] - raw = [conversion['raw_{}'.format(i)] for i in range(nr)] - raw = array(raw) + raw_vals = [conversion['raw_{}'.format(i)] for i in range(nr)] + raw_vals = array(raw_vals) phys = [conversion['phys_{}'.format(i)] for i in range(nr)] phys = array(phys) if conversion_type == v2c.CONVERSION_TYPE_TABI: - vals = interp(vals, raw, phys) + vals = interp(vals, raw_vals, phys) else: idx = searchsorted(raw, vals) idx = clip(idx, 0, len(raw) - 1) @@ -2507,14 +2517,14 @@ def get(self, elif conversion_type == v2c.CONVERSION_TYPE_VTAB: nr = conversion['ref_param_nr'] - raw = [ + raw_vals = [ conversion['param_val_{}'.format(i)] for i in range(nr) ] - raw = array(raw) + raw_vals = array(raw_vals) phys = [conversion['text_{}'.format(i)] for i in range(nr)] phys = array(phys) - info = {'raw': raw, 'phys': phys} + info = {'raw': raw_vals, 'phys': phys} elif conversion_type == v2c.CONVERSION_TYPE_VTABR: nr = conversion['ref_param_nr'] diff --git a/asammdf/mdf3.py b/asammdf/mdf3.py index 6b367bbe7..c0d398cb5 100644 --- a/asammdf/mdf3.py +++ b/asammdf/mdf3.py @@ -2223,7 +2223,8 @@ def get(self, index=None, raster=None, samples_only=False, - data=None): + data=None, + raw=False): """Gets channel samples. Channel can be specified in two ways: @@ -2256,6 +2257,12 @@ def get(self, samples_only : bool if *True* return only the channel samples as numpy array; if *False* return a *Signal* object + data : bytes + prevent redundant data read by providing the raw data group samples + raw : bool + return channel samples without appling the conversion rule; default + `False` + Returns ------- @@ -2352,7 +2359,7 @@ def get(self, record_shape = tuple(shape) arrays = [ - self.get(group=dg_nr, index=ch_nr, samples_only=True) + self.get(group=dg_nr, index=ch_nr, samples_only=True, raw=raw) for ch_nr, dg_nr in dep.referenced_channels ] if cycles_nr: @@ -2432,7 +2439,10 @@ def get(self, if cycles_nr: - if conversion_type == v3c.CONVERSION_TYPE_NONE: + if raw: + pass + + elif conversion_type == v3c.CONVERSION_TYPE_NONE: if channel['data_type'] == v3c.DATA_TYPE_STRING: vals = [val.tobytes() for val in vals] @@ -2463,12 +2473,12 @@ def get(self, v3c.CONVERSION_TYPE_TABX): nr = conversion['ref_param_nr'] - raw = [conversion['raw_{}'.format(i)] for i in range(nr)] - raw = array(raw) + raw_vals = [conversion['raw_{}'.format(i)] for i in range(nr)] + raw_vals = array(raw_vals) phys = [conversion['phys_{}'.format(i)] for i in range(nr)] phys = array(phys) if conversion_type == v3c.CONVERSION_TYPE_TABI: - vals = interp(vals, raw, phys) + vals = interp(vals, raw_vals, phys) else: idx = searchsorted(raw, vals) idx = clip(idx, 0, len(raw) - 1) @@ -2476,14 +2486,14 @@ def get(self, elif conversion_type == v3c.CONVERSION_TYPE_VTAB: nr = conversion['ref_param_nr'] - raw = [ + raw_vals = [ conversion['param_val_{}'.format(i)] for i in range(nr) ] - raw = array(raw) + raw_vals = array(raw_vals) phys = [conversion['text_{}'.format(i)] for i in range(nr)] phys = array(phys) - info = {'raw': raw, 'phys': phys} + info = {'raw': raw_vals, 'phys': phys} elif conversion_type == v3c.CONVERSION_TYPE_VTABR: nr = conversion['ref_param_nr'] diff --git a/asammdf/mdf4.py b/asammdf/mdf4.py index 2befdd1c1..1ed284063 100644 --- a/asammdf/mdf4.py +++ b/asammdf/mdf4.py @@ -2813,7 +2813,8 @@ def get(self, index=None, raster=None, samples_only=False, - data=None): + data=None, + raw=False): """Gets channel samples. Channel can be specified in two ways: @@ -2845,6 +2846,11 @@ def get(self, samples_only : bool if *True* return only the channel samples as numpy array; if *False* return a *Signal* object + data : bytes + prevent redundant data read by providing the raw data group samples + raw : bool + return channel samples without appling the conversion rule; default + `False` Returns ------- @@ -2951,7 +2957,7 @@ def get(self, else: names = [ch.name for ch in dependency_list] arrays = [ - self.get(name_, samples_only=True) + self.get(name_, samples_only=True, raw=raw) for name_ in names ] @@ -3165,7 +3171,9 @@ def get(self, else: conversion_type = conversion['conversion_type'] - if conversion_type == v4c.CONVERSION_TYPE_NON: + if raw: + pass + elif conversion_type == v4c.CONVERSION_TYPE_NON: # check if it is VLDS channel type with SDBLOCK data_type = channel['data_type'] channel_type = channel['channel_type'] @@ -3342,17 +3350,17 @@ def get(self, elif conversion_type in (v4c.CONVERSION_TYPE_TABI, v4c.CONVERSION_TYPE_TAB): nr = conversion['val_param_nr'] // 2 - raw = array( + raw_vals = array( [conversion['raw_{}'.format(i)] for i in range(nr)] ) phys = array( [conversion['phys_{}'.format(i)] for i in range(nr)] ) if conversion_type == v4c.CONVERSION_TYPE_TABI: - vals = interp(vals, raw, phys) + vals = interp(vals, raw_vals, phys) else: - idx = searchsorted(raw, vals) - idx = clip(idx, 0, len(raw) - 1) + idx = searchsorted(raw_vals, vals) + idx = clip(idx, 0, len(raw_vals) - 1) vals = phys[idx] elif conversion_type == v4c.CONVERSION_TYPE_RTAB: @@ -3399,7 +3407,7 @@ def get(self, elif conversion_type == v4c.CONVERSION_TYPE_TABX: nr = conversion['val_param_nr'] - raw = array( + raw_vals = array( [conversion['val_{}'.format(i)] for i in range(nr)] ) @@ -3434,7 +3442,7 @@ def get(self, else: default = b'' info = { - 'raw': raw, + 'raw': raw_vals, 'phys': phys, 'default': default, } @@ -3489,16 +3497,16 @@ def get(self, nr = conversion['val_param_nr'] - 1 if memory == 'minimum': - raw = [] + raw_vals = [] for i in range(nr): block = TextBlock( address=grp['texts']['conversion_tab'][ch_nr]['text_{}'.format(i)], stream=stream, ) - raw.append(block['text']) - raw = array(raw) + raw_vals.append(block['text']) + raw_vals = array(raw_vals) else: - raw = array( + raw_vals = array( [grp['texts']['conversion_tab'][ch_nr]['text_{}'.format(i)]['text'] for i in range(nr)] ) @@ -3507,7 +3515,7 @@ def get(self, ) default = conversion['val_default'] info = { - 'raw': raw, + 'raw': raw_vals, 'phys': phys, 'default': default, } From a84e41d0e3c6301761d327545fc96de7ec2e6080 Mon Sep 17 00:00:00 2001 From: danielhrisca Date: Fri, 22 Dec 2017 20:51:04 +0200 Subject: [PATCH 034/117] unified code to handle mdf versions 2 and 3 --- asammdf/__init__.py | 14 +- asammdf/mdf.py | 34 +- asammdf/mdf2.py | 3503 ----------------- asammdf/{mdf3.py => mdf_v2_v3.py} | 307 +- asammdf/{mdf4.py => mdf_v4.py} | 4 +- asammdf/utils.py | 4 +- asammdf/{v3blocks.py => v2_v3_blocks.py} | 420 +- .../{v3constants.py => v2_v3_constants.py} | 49 +- asammdf/v2blocks.py | 1574 -------- asammdf/v2constants.py | 345 -- asammdf/{v4blocks.py => v4_blocks.py} | 0 asammdf/{v4constants.py => v4_constants.py} | 0 benchmarks/bench.py | 30 +- test/{test_mdf2.py => test_mdf23.py} | 81 +- test/test_mdf3.py | 96 - 15 files changed, 568 insertions(+), 5893 deletions(-) delete mode 100644 asammdf/mdf2.py rename asammdf/{mdf3.py => mdf_v2_v3.py} (92%) rename asammdf/{mdf4.py => mdf_v4.py} (99%) rename asammdf/{v3blocks.py => v2_v3_blocks.py} (79%) rename asammdf/{v3constants.py => v2_v3_constants.py} (86%) delete mode 100644 asammdf/v2blocks.py delete mode 100644 asammdf/v2constants.py rename asammdf/{v4blocks.py => v4_blocks.py} (100%) rename asammdf/{v4constants.py => v4_constants.py} (100%) rename test/{test_mdf2.py => test_mdf23.py} (51%) delete mode 100644 test/test_mdf3.py diff --git a/asammdf/__init__.py b/asammdf/__init__.py index f7a3ddd2f..f5b1734ef 100644 --- a/asammdf/__init__.py +++ b/asammdf/__init__.py @@ -1,8 +1,7 @@ # -*- coding: utf-8 -*- """ asammdf is a parser and editor for ASAM MDF files """ -from .mdf2 import MDF2 -from .mdf3 import MDF3 -from .mdf4 import MDF4 +from .mdf_v2_v3 import MDF23 +from .mdf_v4 import MDF4 from .mdf import MDF, SUPPORTED_VERSIONS from .signal import Signal from .version import __version__ @@ -12,8 +11,7 @@ '__version__', 'configure', 'MDF', - 'MDF2', - 'MDF3', + 'MDF23', 'MDF4', 'Signal', 'SUPPORTED_VERSIONS', @@ -46,8 +44,7 @@ def configure( """ if integer_compacting is not None: - MDF2._compact_integers_on_append = bool(integer_compacting) - MDF3._compact_integers_on_append = bool(integer_compacting) + MDF23._compact_integers_on_append = bool(integer_compacting) MDF4._compact_integers_on_append = bool(integer_compacting) if split_threshold is not None: @@ -57,6 +54,5 @@ def configure( MDF4._split_data_blocks = bool(split_data_blocks) if overwrite is not None: - MDF2._overwrite = bool(overwrite) - MDF3._overwrite = bool(overwrite) + MDF23._overwrite = bool(overwrite) MDF4._overwrite = bool(overwrite) diff --git a/asammdf/mdf.py b/asammdf/mdf.py index 67db77a25..58cb3787f 100644 --- a/asammdf/mdf.py +++ b/asammdf/mdf.py @@ -11,14 +11,12 @@ import numpy as np from pandas import DataFrame -from .mdf2 import MDF2 -from .mdf3 import MDF3 -from .mdf4 import MDF4 +from .mdf_v2_v3 import MDF23 +from .mdf_v4 import MDF4 from .utils import MdfException -from .v2blocks import Channel as ChannelV2 -from .v3blocks import TextBlock as TextBlockV3 -from .v3blocks import Channel as ChannelV3 -from .v4blocks import TextBlock as TextBlockV4 +from .v2_v3_blocks import TextBlock as TextBlockV3 +from .v2_v3_blocks import Channel as ChannelV3 +from .v4_blocks import TextBlock as TextBlockV4 MDF2_VERSIONS = ('2.00', '2.14') @@ -63,11 +61,11 @@ def __init__(self, name=None, memory='full', version='4.10'): version = str(version) version = '{}.{}'.format(version[0], version[1:]) if version in MDF3_VERSIONS: - self._mdf = MDF3(name, memory) + self._mdf = MDF23(name, memory) elif version in MDF4_VERSIONS: self._mdf = MDF4(name, memory) elif version in MDF2_VERSIONS: - self._mdf = MDF2(name, memory) + self._mdf = MDF23(name, memory) else: message = ('"{}" is not a supported MDF file; ' '"{}" file version was found') @@ -76,7 +74,7 @@ def __init__(self, name=None, memory='full', version='4.10'): raise MdfException('File "{}" does not exist'.format(name)) else: if version in MDF3_VERSIONS: - self._mdf = MDF3( + self._mdf = MDF23( version=version, memory=memory, ) @@ -86,7 +84,7 @@ def __init__(self, name=None, memory='full', version='4.10'): memory=memory, ) elif version in MDF2_VERSIONS: - self._mdf = MDF2( + self._mdf = MDF23( version=version, memory=memory, ) @@ -654,16 +652,10 @@ def merge(files, outversion='4.10', memory='full'): ) name = block['text'] else: - if file.version in MDF2_VERSIONS: - channel = ChannelV2( - address=grp['channels'][j], - stream=stream, - ) - else: - channel = ChannelV3( - address=grp['channels'][j], - stream=stream, - ) + channel = ChannelV3( + address=grp['channels'][j], + stream=stream, + ) name = channel['short_name'] name = name.decode('latin-1').strip(' \r\n\t\0') else: diff --git a/asammdf/mdf2.py b/asammdf/mdf2.py deleted file mode 100644 index a75f2a104..000000000 --- a/asammdf/mdf2.py +++ /dev/null @@ -1,3503 +0,0 @@ -# -*- coding: utf-8 -*- -""" ASAM MDF version 3 file format module """ - -from __future__ import print_function, division -import sys - - -import os -import time -import warnings - -from collections import defaultdict -from functools import reduce, partial -from tempfile import TemporaryFile -from itertools import product -from copy import deepcopy - -from numpy import ( - interp, - linspace, - dtype, - array_equal, - column_stack, - array, - searchsorted, - log, - exp, - clip, - union1d, - float64, - flip, - unpackbits, - packbits, - roll, - zeros, - uint8, - arange, -) -from numpy.core.records import fromstring, fromarrays -from numpy.core.defchararray import encode -from numexpr import evaluate - -from .utils import ( - MdfException, - get_fmt, - pair, - fmt_to_datatype, - get_unique_name, - get_min_max, - fix_dtype_fields, -) -from .signal import Signal -from .version import __version__ -from . import v2constants as v2c -from .v2blocks import ( - Channel, - ChannelConversion, - ChannelDependency, - ChannelExtension, - ChannelGroup, - DataBlock, - DataGroup, - FileIdentificationBlock, - HeaderBlock, - TextBlock, - TriggerBlock, -) - - -get_fmt = partial(get_fmt, version=2) -fmt_to_datatype = partial(fmt_to_datatype, version=2) - -PYVERSION = sys.version_info[0] -if PYVERSION == 2: - from .utils import bytes - - -__all__ = ['MDF2', ] - - -class MDF2(object): - """If the *name* exist it will be loaded otherwise an empty file will be - created that can be later saved to disk - - Parameters - ---------- - name : string - mdf file name - memory : str - memory optimization option; default `full` - - * if *full* the data group binary data block will be memorised in RAM - * if *low* the channel data is read from disk on request, and the - metadata is memorised into RAM - * if *minimum* only minimal data is memorised into RAM - - version : string - mdf file version ('2.00' or '2.14'); default '2.14' - - Attributes - ---------- - name : string - mdf file name - groups : list - list of data groups - header : OrderedDict - mdf file header - file_history : TextBlock - file history text block; can be None - memory : bool - load measured data option - version : str - mdf version - channels_db : dict - used for fast channel access by name; for each name key the value is a - list of (group index, channel index) tuples - masters_db : dict - used for fast master channel access; for each group index key the value - is the master channel index - - """ - - _compact_integers_on_append = False - _overwrite = False - - def __init__(self, name=None, memory=2, version='2.14'): - self.groups = [] - self.header = None - self.identification = None - self.file_history = None - self.name = name - self.memory = memory - self.channels_db = {} - self.masters_db = {} - - self._master_channel_cache = {} - - # used for appending to MDF created with memory=False - self._tempfile = TemporaryFile() - self._tempfile.write(b'\0') - self._file = None - - if name: - self._file = open(self.name, 'rb') - self._read() - else: - self.identification = FileIdentificationBlock(version=version) - self.version = version - self.header = HeaderBlock(version=self.version) - - def _load_group_data(self, group): - """ get group's data block bytes""" - - if self.memory == 'full': - data = group['data_block']['data'] - else: - # could be an appended group - # for now appended groups keep the measured data in the memory. - # the plan is to use a temp file for appended groups, to keep the - # memory usage low. - if group['data_location'] == v2c.LOCATION_ORIGINAL_FILE: - # this is a group from the source file - # so fetch the measured data from it - stream = self._file - # go to the first data block of the current data group - dat_addr = group['data_group']['data_block_addr'] - - if group['sorted']: - read_size = group['size'] - data = DataBlock( - stream=stream, - address=dat_addr, size=read_size, - ) - data = data['data'] - - else: - read_size = group['size'] - record_id = group['channel_group']['record_id'] - cg_size = group['record_size'] - if group['data_group']['record_id_nr'] <= 2: - record_id_nr = group['data_group']['record_id_nr'] - else: - record_id_nr = 0 - cg_data = [] - - data = DataBlock( - stream=stream, - address=dat_addr, size=read_size, - ) - data = data['data'] - - i = 0 - size = len(data) - while i < size: - rec_id = data[i] - # skip record id - i += 1 - rec_size = cg_size[rec_id] - if rec_id == record_id: - rec_data = data[i: i+rec_size] - cg_data.append(rec_data) - # consider the second record ID if it exists - if record_id_nr == 2: - i += rec_size + 1 - else: - i += rec_size - data = b''.join(cg_data) - elif group['data_location'] == v2c.LOCATION_TEMPORARY_FILE: - read_size = group['size'] - dat_addr = group['data_group']['data_block_addr'] - if dat_addr: - self._tempfile.seek(dat_addr, v2c.SEEK_START) - data = self._tempfile.read(read_size) - else: - data = b'' - - return data - - def _prepare_record(self, group): - """ compute record dtype and parents dict for this group - - Parameters - ---------- - group : dict - MDF group dict - - Returns - ------- - parents, dtypes : dict, numpy.dtype - mapping of channels to records fields, records fiels dtype - - """ - - memory = self.memory - stream = self._file - grp = group - record_size = grp['channel_group']['samples_byte_nr'] << 3 - next_byte_aligned_position = 0 - types = [] - current_parent = "" - parent_start_offset = 0 - parents = {} - group_channels = set() - - if memory != 'minimum': - channels = grp['channels'] - else: - channels = [ - Channel(address=ch_addr, stream=stream) - for ch_addr in grp['channels'] - ] - - # the channels are first sorted ascending (see __lt__ method of Channel - # class): a channel with lower start offset is smaller, when two - # channels havethe same start offset the one with higer bit size is - # considered smaller. The reason is that when the numpy record is built - # and there are overlapping channels, the parent fields mustbe bigger - # (bit size) than the embedded channels. For each channel the parent - # dict will have a (parent name, bit offset) pair: the channel value is - # computed using the values from the parent field, and the bit offset, - # which is the channel's bit offset within the parent bytes. - # This means all parents will have themselves as parent, and bit offset - # of 0. Gaps in the records are also considered. Non standard integers - # size is adjusted to the first higher standard integer size (eq. uint - # of 28bits will be adjusted to 32bits) - - sortedchannels = sorted(enumerate(channels), key=lambda i: i[1]) - for original_index, new_ch in sortedchannels: - # skip channels with channel dependencies from the numpy record - if new_ch['ch_depend_addr']: - continue - - start_offset = new_ch['start_offset'] - bit_offset = start_offset % 8 - data_type = new_ch['data_type'] - bit_count = new_ch['bit_count'] - if memory == 'minimum': - channel_texts = grp['texts']['channels'][original_index] - if channel_texts and 'long_name_addr' in channel_texts: - address = grp['texts']['channels'][original_index]['long_name_addr'] - - block = TextBlock( - address=address, - stream=stream, - ) - name = block['text'].decode('latin-1').strip(' \r\n\t\0') - else: - name = new_ch['short_name'].decode('latin-1').strip(' \r\n\t\0') - name = name.split('\\')[0] - else: - name = new_ch.name - - # handle multiple occurance of same channel name - name = get_unique_name(group_channels, name) - group_channels.add(name) - - if start_offset >= next_byte_aligned_position: - parent_start_offset = (start_offset // 8) * 8 - - # check if there are byte gaps in the record - gap = (parent_start_offset - next_byte_aligned_position) // 8 - if gap: - types.append(('', 'a{}'.format(gap))) - - # adjust size to 1, 2, 4 or 8 bytes for nonstandard integers - size = bit_offset + bit_count - if data_type == v2c.DATA_TYPE_STRING: - next_byte_aligned_position = parent_start_offset + size - size = size // 8 - if next_byte_aligned_position <= record_size: - dtype_pair = (name, get_fmt(data_type, size)) - types.append(dtype_pair) - parents[original_index] = name, bit_offset - - elif data_type == v2c.DATA_TYPE_BYTEARRAY: - size = size // 8 - next_byte_aligned_position = parent_start_offset + size - if next_byte_aligned_position <= record_size: - dtype_pair = (name, 'u1', (size, 1)) - types.append(dtype_pair) - parents[original_index] = name, bit_offset - - else: - if size > 32: - next_byte_aligned_position = parent_start_offset + 64 - size = 8 - elif size > 16: - next_byte_aligned_position = parent_start_offset + 32 - size = 4 - elif size > 8: - next_byte_aligned_position = parent_start_offset + 16 - size = 2 - else: - next_byte_aligned_position = parent_start_offset + 8 - size = 1 - - if next_byte_aligned_position <= record_size: - dtype_pair = (name, get_fmt(data_type, size)) - types.append(dtype_pair) - parents[original_index] = name, bit_offset - - current_parent = name - else: - max_overlapping = next_byte_aligned_position - start_offset - if max_overlapping >= bit_count: - parents[original_index] = ( - current_parent, - start_offset - parent_start_offset, - ) - if next_byte_aligned_position > record_size: - break - - gap = (record_size - next_byte_aligned_position) >> 3 - if gap: - dtype_pair = ('', 'a{}'.format(gap)) - types.append(dtype_pair) - - if PYVERSION == 2: - types = fix_dtype_fields(types) - - return parents, dtype(types) - - def _get_not_byte_aligned_data(self, data, group, ch_nr): - - big_endian_types = ( - v2c.DATA_TYPE_UNSIGNED_MOTOROLA, - v2c.DATA_TYPE_FLOAT_MOTOROLA, - v2c.DATA_TYPE_DOUBLE_MOTOROLA, - v2c.DATA_TYPE_SIGNED_MOTOROLA, - ) - - record_size = group['channel_group']['samples_byte_nr'] - - if self.memory != 'minimum': - channel = group['channels'][ch_nr] - else: - channel = Channel( - address=group['channels'][ch_nr], - stream=self._file, - ) - - bit_offset = channel['start_offset'] % 8 - byte_offset = channel['start_offset'] // 8 - bit_count = channel['bit_count'] - - byte_count = bit_offset + bit_count - if byte_count % 8: - byte_count = (byte_count >> 3) + 1 - else: - byte_count >>= 3 - - types = [ - ('', 'a{}'.format(byte_offset)), - ('vals', '({},)u1'.format(byte_count)), - ('', 'a{}'.format(record_size - byte_count - byte_offset)), - ] - - vals = fromstring(data, dtype=dtype(types)) - - vals = vals['vals'] - - if channel['data_type'] not in big_endian_types: - vals = flip(vals, 1) - - vals = unpackbits(vals) - vals = roll(vals, bit_offset) - vals = vals.reshape((len(vals) // 8, 8)) - vals = packbits(vals) - vals = vals.reshape((len(vals) // byte_count, byte_count)) - - if bit_count < 64: - mask = 2 ** bit_count - 1 - masks = [] - while mask: - masks.append(mask & 0xFF) - mask >>= 8 - for i in range(byte_count - len(masks)): - masks.append(0) - - masks = masks[::-1] - for i, mask in enumerate(masks): - vals[:, i] &= mask - - if channel['data_type'] not in big_endian_types: - vals = flip(vals, 1) - - if bit_count <= 8: - size = 1 - elif bit_count <= 16: - size = 2 - elif bit_count <= 32: - size = 4 - elif bit_count <= 64: - size = 8 - else: - size = bit_count // 8 - - if size > byte_count: - extra_bytes = size - byte_count - extra = zeros((len(vals), extra_bytes), dtype=uint8) - - types = [ - ('vals', vals.dtype, vals.shape[1:]), - ('', extra.dtype, extra.shape[1:]), - ] - vals = fromarrays([vals, extra], dtype=dtype(types)) - vals = vals.tostring() - - fmt = get_fmt(channel['data_type'], size) - if size <= byte_count: - types = [ - ('vals', fmt), - ('', 'a{}'.format(byte_count - size)), - ] - else: - types = [('vals', fmt), ] - - vals = fromstring(vals, dtype=dtype(types)) - - return vals['vals'] - - def _validate_channel_selection(self, name=None, group=None, index=None): - """Gets channel comment. - - Channel can be specified in two ways: - - * using the first positional argument *name* - - * if there are multiple occurrences for this channel then the - *group* and *index* arguments can be used to select a specific - group. - * if there are multiple occurrences for this channel and either the - *group* or *index* arguments is None then a warning is issued - - * using the group number (keyword argument *group*) and the channel - number (keyword argument *index*). Use *info* method for group and - channel numbers - - - If the *raster* keyword argument is not *None* the output is - interpolated accordingly. - - Parameters - ---------- - name : string - name of channel - group : int - 0-based group index - index : int - 0-based channel index - - Returns - ------- - group_index, channel_index : (int, int) - selected channel's group and channel index - - """ - if name is None: - if group is None or index is None: - message = ('Invalid arguments for channel selection: ' - 'must give "name" or, "group" and "index"') - raise MdfException(message) - else: - gp_nr, ch_nr = group, index - if gp_nr > len(self.groups) - 1: - raise MdfException('Group index out of range') - if index > len(self.groups[gp_nr]['channels']) - 1: - raise MdfException('Channel index out of range') - else: - name = name.split('\\')[0] - if name not in self.channels_db: - raise MdfException('Channel "{}" not found'.format(name)) - else: - if group is None: - gp_nr, ch_nr = self.channels_db[name][0] - if len(self.channels_db[name]) > 1: - message = ('Multiple occurances for channel "{}". ' - 'Using first occurance from data group {}. ' - 'Provide both "group" and "index" arguments' - ' to select another data group') - message = message.format(name, gp_nr) - warnings.warn(message) - else: - group_valid = False - for gp_nr, ch_nr in self.channels_db[name]: - if gp_nr == group: - group_valid = True - if index is None: - break - elif index == ch_nr: - break - else: - if group_valid: - gp_nr, ch_nr = self.channels_db[name][group] - message = ('You have selected channel index "{}"' - 'of group "{}" for channel "{}", but ' - 'this channel index is invalid. Using ' - 'first occurance of "{}" in this group' - ' at index "{}"') - message = message.format( - index, - group, - name, - name, - ch_nr, - ) - else: - gp_nr, ch_nr = self.channels_db[name][0] - message = ('You have selected group "{}" for ' - 'channel "{}", but this channel was not' - ' found in this group, or this group ' - 'index does not exist. Using first ' - 'occurance of "{}" from group "{}"') - message = message.format(group, name, name, gp_nr) - warnings.warn(message) - return gp_nr, ch_nr - - def _read(self): - stream = self._file - memory = self.memory - - # performance optimization - read = stream.read - seek = stream.seek - - dg_cntr = 0 - seek(0, v2c.SEEK_START) - - self.identification = FileIdentificationBlock( - stream=stream, - ) - self.header = HeaderBlock(stream=stream) - - self.version = self.identification['version_str']\ - .decode('latin-1')\ - .strip(' \n\t\0') - - self.file_history = TextBlock( - address=self.header['comment_addr'], - stream=stream, - ) - - # this will hold mapping from channel address to Channel object - # needed for linking dependency blocks to referenced channels after - # the file is loaded - ch_map = {} - - # go to first date group - dg_addr = self.header['first_dg_addr'] - # read each data group sequentially - while dg_addr: - gp = DataGroup(address=dg_addr, stream=stream) - record_id_nr = gp['record_id_nr'] - cg_nr = gp['cg_nr'] - cg_addr = gp['first_cg_addr'] - data_addr = gp['data_block_addr'] - - # read trigger information if available - trigger_addr = gp['trigger_addr'] - if trigger_addr: - trigger = TriggerBlock(address=trigger_addr, - stream=stream) - if trigger['text_addr']: - trigger_text = TextBlock( - address=trigger['text_addr'], - stream=stream, - ) - else: - trigger_text = None - else: - trigger = None - trigger_text = None - - new_groups = [] - for i in range(cg_nr): - - new_groups.append({}) - grp = new_groups[-1] - grp['channels'] = [] - grp['channel_conversions'] = [] - grp['channel_extensions'] = [] - grp['data_block'] = None - grp['texts'] = { - 'channels': [], - 'conversion_tab': [], - 'channel_group': [], - } - grp['trigger'] = [trigger, trigger_text] - grp['channel_dependencies'] = [] - - if record_id_nr: - grp['sorted'] = False - else: - grp['sorted'] = True - - kargs = {'first_cg_addr': cg_addr, - 'data_block_addr': data_addr} - if self.version in ('3.20', '3.30'): - kargs['block_len'] = v2c.DG32_BLOCK_SIZE - else: - kargs['block_len'] = v2c.DG31_BLOCK_SIZE - - grp['data_group'] = DataGroup(**kargs) - - # read each channel group sequentially - grp['channel_group'] = ChannelGroup( - address=cg_addr, - stream=stream, - ) - - # read name and comment for current channel group - cg_texts = {} - grp['texts']['channel_group'].append(cg_texts) - - address = grp['channel_group']['comment_addr'] - if address: - if memory != 'minimum': - block = TextBlock( - address=address, - stream=stream, - ) - cg_texts['comment_addr'] = block - else: - cg_texts['comment_addr'] = address - - # go to first channel of the current channel group - ch_addr = grp['channel_group']['first_ch_addr'] - ch_cntr = 0 - grp_chs = grp['channels'] - grp_conv = grp['channel_conversions'] - grp_ch_texts = grp['texts']['channels'] - - while ch_addr: - # read channel block and create channel object - new_ch = Channel( - address=ch_addr, - stream=stream, - ) - - # check if it has channel dependencies - if new_ch['ch_depend_addr']: - dep = ChannelDependency( - address=new_ch['ch_depend_addr'], - stream=stream, - ) - grp['channel_dependencies'].append(dep) - else: - grp['channel_dependencies'].append(None) - - # update channel map - ch_map[ch_addr] = (ch_cntr, dg_cntr) - - # read conversion block - address = new_ch['conversion_addr'] - if address: - new_conv = ChannelConversion( - address=address, - stream=stream, - ) - if memory != 'minimum': - grp_conv.append(new_conv) - else: - grp_conv.append(address) - else: - new_conv = None - if memory != 'minimum': - grp_conv.append(None) - else: - grp_conv.append(0) - - vtab_texts = {} - if new_conv: - conv_type = new_conv['conversion_type'] - else: - conv_type = 0 - if conv_type == v2c.CONVERSION_TYPE_VTABR: - for idx in range(new_conv['ref_param_nr']): - address = new_conv['text_{}'.format(idx)] - if address: - if memory != 'minimum': - block = TextBlock( - address=address, - stream=stream, - ) - vtab_texts['text_{}'.format(idx)] = block - else: - vtab_texts['text_{}'.format(idx)] = address - - if vtab_texts: - grp['texts']['conversion_tab'].append(vtab_texts) - else: - grp['texts']['conversion_tab'].append(None) - - address = new_ch['source_depend_addr'] - if memory != 'minimum': - if address: - block = ChannelExtension( - address=address, - stream=stream, - ) - grp['channel_extensions'].append(block) - else: - grp['channel_extensions'].append(None) - else: - grp['channel_extensions'].append(address) - - # read text fields for channel - ch_texts = {} - for key in ( - 'long_name_addr', - 'comment_addr'): - address = new_ch.get(key, 0) - if address: - if memory != 'minimum': - ch_texts[key] = TextBlock( - address=address, - stream=stream, - ) - else: - ch_texts[key] = address - - if ch_texts: - grp_ch_texts.append(ch_texts) - else: - grp_ch_texts.append(None) - - # update channel object name and block_size attributes - if new_ch.get('long_name_addr', 0): - if memory != 'minimum': - name = ch_texts['long_name_addr']['text'] - else: - block = TextBlock( - address=ch_texts['long_name_addr'], - stream=stream, - ) - name = block['text'] - else: - name = new_ch['short_name'] - name = name.decode('latin-1').strip(' \n\t\0') - name = name.split('\\')[0] - new_ch.name = name - - if name in self.channels_db: - self.channels_db[name].append((dg_cntr, ch_cntr)) - else: - self.channels_db[name] = [] - self.channels_db[name].append((dg_cntr, ch_cntr)) - - if new_ch['channel_type'] == v2c.CHANNEL_TYPE_MASTER: - self.masters_db[dg_cntr] = ch_cntr - # go to next channel of the current channel group - - ch_cntr += 1 - if memory != 'minimum': - grp_chs.append(new_ch) - else: - grp_chs.append(ch_addr) - ch_addr = new_ch['next_ch_addr'] - - cg_addr = grp['channel_group']['next_cg_addr'] - dg_cntr += 1 - - # store channel groups record sizes dict and data block size in - # each new group data belong to the initial unsorted group, and - # add the key 'sorted' with the value False to use a flag; - # this is used later if memory=False - - cg_size = {} - total_size = 0 - - for grp in new_groups: - record_id = grp['channel_group']['record_id'] - cycles_nr = grp['channel_group']['cycles_nr'] - record_size = grp['channel_group']['samples_byte_nr'] - - cg_size[record_id] = record_size - - record_size += record_id_nr - total_size += record_size * cycles_nr - - grp['record_size'] = cg_size - grp['size'] = total_size - - if memory == 'full': - # read data block of the current data group - dat_addr = gp['data_block_addr'] - if dat_addr: - seek(dat_addr, v2c.SEEK_START) - data = read(total_size) - else: - data = b'' - if record_id_nr == 0: - grp = new_groups[0] - grp['data_location'] = v2c.LOCATION_MEMORY - grp['data_block'] = DataBlock(data=data) - - else: - # agregate data for each record ID in the cg_data dict - cg_data = defaultdict(list) - i = 0 - size = len(data) - while i < size: - rec_id = data[i] - # skip record id - i += 1 - rec_size = cg_size[rec_id] - rec_data = data[i: i+rec_size] - cg_data[rec_id].append(rec_data) - # possibly skip 2nd record id - if record_id_nr == 2: - i += rec_size + 1 - else: - i += rec_size - for grp in new_groups: - grp['data_location'] = v2c.LOCATION_MEMORY - data = cg_data[grp['channel_group']['record_id']] - data = b''.join(data) - grp['channel_group']['record_id'] = 1 - grp['data_block'] = DataBlock(data=data) - else: - for grp in new_groups: - grp['data_location'] = v2c.LOCATION_ORIGINAL_FILE - - self.groups.extend(new_groups) - - # go to next data group - dg_addr = gp['next_dg_addr'] - - # finally update the channel depency references - for grp in self.groups: - for dep in grp['channel_dependencies']: - if dep: - for i in range(dep['sd_nr']): - ref_channel_addr = dep['ch_{}'.format(i)] - channel = ch_map[ref_channel_addr] - dep.referenced_channels.append(channel) - - if self.memory == 'full': - self.close() - - def add_trigger(self, - group, - timestamp, - pre_time=0, - post_time=0, - comment=''): - """ add trigger to data group - - Parameters - ---------- - group : int - group index - timestamp : float - trigger time - pre_time : float - trigger pre time; default 0 - post_time : float - trigger post time; default 0 - comment : str - trigger comment - - """ - gp = self.groups[group] - trigger, trigger_text = gp['trigger'] - if trigger: - nr = trigger['trigger_event_nr'] - trigger['trigger_event_nr'] += 1 - trigger['block_len'] += 24 - trigger['trigger_{}_time'.format(nr)] = timestamp - trigger['trigger_{}_pretime'.format(nr)] = pre_time - trigger['trigger_{}_posttime'.format(nr)] = post_time - if trigger_text is None and comment: - trigger_text = TextBlock(text=comment) - gp['trigger'][1] = trigger_text - else: - trigger = TriggerBlock( - trigger_event_nr=1, - trigger_0_time=timestamp, - trigger_0_pretime=pre_time, - trigger_0_posttime=post_time, - ) - if comment: - trigger_text = TextBlock(text=comment) - else: - trigger_text = None - - gp['trigger'] = [trigger, trigger_text] - - def append(self, - signals, - acquisition_info='Python', - common_timebase=False): - """ - Appends a new data group. - - For channel dependencies type Signals, the *samples* attribute must be a - numpy.recarray - - Parameters - ---------- - signals : list - list on *Signal* objects - acquisition_info : str - acquisition information; default 'Python' - common_timebase : bool - flag to hint that the signals have the same timebase - - - Examples - -------- - >>> # case 1 conversion type None - >>> s1 = np.array([1, 2, 3, 4, 5]) - >>> s2 = np.array([-1, -2, -3, -4, -5]) - >>> s3 = np.array([0.1, 0.04, 0.09, 0.16, 0.25]) - >>> t = np.array([0.001, 0.002, 0.003, 0.004, 0.005]) - >>> names = ['Positive', 'Negative', 'Float'] - >>> units = ['+', '-', '.f'] - >>> info = {} - >>> s1 = Signal(samples=s1, timstamps=t, unit='+', name='Positive') - >>> s2 = Signal(samples=s2, timstamps=t, unit='-', name='Negative') - >>> s3 = Signal(samples=s3, timstamps=t, unit='flts', name='Floats') - >>> mdf = MDF2('new.mdf') - >>> mdf.append([s1, s2, s3], 'created by asammdf v1.1.0') - >>> # case 2: VTAB conversions from channels inside another file - >>> mdf1 = MDF2('in.mdf') - >>> ch1 = mdf1.get("Channel1_VTAB") - >>> ch2 = mdf1.get("Channel2_VTABR") - >>> sigs = [ch1, ch2] - >>> mdf2 = MDF2('out.mdf') - >>> mdf2.append(sigs, 'created by asammdf v1.1.0') - - """ - if not signals: - error = '"append" requires a non-empty list of Signal objects' - raise MdfException(error) - - # check if the signals have a common timebase - # if not interpolate the signals using the union of all timbases - t_ = signals[0].timestamps - if not common_timebase: - for s in signals[1:]: - if not array_equal(s.timestamps, t_): - different = True - break - else: - different = False - - if different: - times = [s.timestamps for s in signals] - t = reduce(union1d, times).flatten().astype(float64) - signals = [s.interp(t) for s in signals] - times = None - else: - t = t_ - else: - t = t_ - - memory = self.memory - file = self._tempfile - write = file.write - tell = file.tell - - # split regular from composed signals. Composed signals have recarray - # samples or multimendional ndarray. - # The regular signals will be first added to the group. - # The composed signals will be saved along side the fields, which will - # be saved as new signals. - simple_signals = [ - sig for sig in signals - if len(sig.samples.shape) <= 1 and - sig.samples.dtype.names is None - ] - composed_signals = [ - sig for sig in signals - if len(sig.samples.shape) > 1 or - sig.samples.dtype.names - ] - - # mdf version 4 structure channels and CANopen types will be saved to - # new channel groups - new_groups_signals = [ - sig for sig in composed_signals - if sig.samples.dtype.names and - sig.samples.dtype.names[0] != sig.name - ] - composed_signals = [ - sig for sig in composed_signals - if not sig.samples.dtype.names or - sig.samples.dtype.names[0] == sig.name - ] - - if simple_signals or composed_signals: - dg_cntr = len(self.groups) - - gp = {} - gp['channels'] = gp_channels = [] - gp['channel_conversions'] = gp_conv = [] - gp['channel_extensions'] = gp_source = [] - gp['channel_dependencies'] = gp_dep = [] - gp['texts'] = gp_texts = { - 'channels': [], - 'conversion_tab': [], - 'channel_group': [], - } - self.groups.append(gp) - - cycles_nr = len(t) - fields = [] - types = [] - parents = {} - ch_cntr = 0 - offset = 0 - field_names = set() - - # setup all blocks related to the time master channel - - # time channel texts - for _, item in gp_texts.items(): - item.append(None) - - gp_texts['channel_group'][-1] = {} - block = TextBlock(text=acquisition_info) - if memory != 'minimum': - gp_texts['channel_group'][-1]['comment_addr'] = block - else: - address = tell() - gp_texts['channel_group'][-1]['comment_addr'] = address - write(bytes(block)) - - # conversion for time channel - kargs = { - 'conversion_type': v2c.CONVERSION_TYPE_NONE, - 'unit': b's', - 'min_phy_value': t[0] if cycles_nr else 0, - 'max_phy_value': t[-1] if cycles_nr else 0, - } - block = ChannelConversion(**kargs) - if memory != 'minimum': - gp_conv.append(block) - else: - address = tell() - gp_conv.append(address) - write(bytes(block)) - - # source for time - kargs = { - 'module_nr': 0, - 'module_address': 0, - 'type': v2c.SOURCE_ECU, - 'description': b'Channel inserted by Python Script', - } - block = ChannelExtension(**kargs) - if memory != 'minimum': - gp_source.append(block) - else: - address = tell() - gp_source.append(address) - write(bytes(block)) - - # time channel - t_type, t_size = fmt_to_datatype(t.dtype) - kargs = { - 'short_name': b't', - 'channel_type': v2c.CHANNEL_TYPE_MASTER, - 'data_type': t_type, - 'start_offset': 0, - 'min_raw_value': t[0] if cycles_nr else 0, - 'max_raw_value': t[-1] if cycles_nr else 0, - 'bit_count': t_size, - } - if self.version == '2.00': - kargs['block_len'] = v2c.CN20_BLOCK_SIZE - else: - kargs['block_len'] = v2c.CN21_BLOCK_SIZE - channel = Channel(**kargs) - channel.name = name = 't' - if memory != 'minimum': - gp_channels.append(channel) - else: - address = tell() - gp_channels.append(address) - write(bytes(channel)) - - if name not in self.channels_db: - self.channels_db[name] = [] - self.channels_db[name].append((dg_cntr, ch_cntr)) - self.masters_db[dg_cntr] = 0 - # data group record parents - parents[ch_cntr] = name, 0 - - # time channel doesn't have channel dependencies - gp_dep.append(None) - - fields.append(t) - types.append((name, t.dtype)) - field_names.add(name) - - offset += t_size - ch_cntr += 1 - - if self._compact_integers_on_append: - compacted_signals = [ - {'signal': sig} - for sig in simple_signals - if sig.samples.dtype.kind in 'ui' - ] - - max_itemsize = 1 - dtype_ = dtype(uint8) - - for signal in compacted_signals: - itemsize = signal['signal'].samples.dtype.itemsize - - min_, max_ = get_min_max(signal['signal'].samples) - signal['min'], signal['max'] = min_, max_ - minimum_bitlength = (itemsize // 2) * 8 + 1 - bit_length = max( - int(max_).bit_length(), - int(min_).bit_length(), - ) - - signal['bit_count'] = max(minimum_bitlength, bit_length) - - if itemsize > max_itemsize: - dtype_ = dtype(' dtype_size: - break - else: - cluster.append(compacted_signals.pop(0)) - size += head_size - - bit_offset = 0 - field_name = get_unique_name(field_names, 'COMPACT') - types.append((field_name, dtype_)) - field_names.add(field_name) - - values = zeros(cycles_nr, dtype=dtype_) - - for signal_d in cluster: - - signal = signal_d['signal'] - bit_count = signal_d['bit_count'] - min_val = signal_d['min'] - max_val = signal_d['max'] - - name = signal.name - for _, item in gp['texts'].items(): - item.append(None) - - texts = {} - if len(name) >= 32 and self.version == '2.14': - block = TextBlock(text=name) - if memory != 'minimum': - texts['long_name_addr'] = block - else: - address = tell() - texts['long_name_addr'] = address - write(bytes(block)) - if texts: - gp_texts['channels'][-1] = texts - - texts = {} - info = signal.info - if info and 'raw' in info and not info['raw'].dtype.kind == 'S': - kargs = {} - kargs['conversion_type'] = v2c.CONVERSION_TYPE_VTAB - raw = info['raw'] - phys = info['phys'] - for i, (r_, p_) in enumerate(zip(raw, phys)): - kargs['text_{}'.format(i)] = p_[:31] + b'\0' - kargs['param_val_{}'.format(i)] = r_ - kargs['ref_param_nr'] = len(raw) - kargs['unit'] = signal.unit.encode('latin-1') - elif info and 'lower' in info: - kargs = {} - kargs['conversion_type'] = v2c.CONVERSION_TYPE_VTABR - lower = info['lower'] - upper = info['upper'] - texts = info['phys'] - kargs['unit'] = signal.unit.encode('latin-1') - kargs['ref_param_nr'] = len(upper) - - for i, vals in enumerate(zip(upper, lower, texts)): - u_, l_, t_ = vals - kargs['lower_{}'.format(i)] = l_ - kargs['upper_{}'.format(i)] = u_ - kargs['text_{}'.format(i)] = 0 - - key = 'text_{}'.format(i) - block = TextBlock(text=t_) - if memory != 'minimum': - texts[key] = block - else: - address = tell() - texts[key] = address - write(bytes(block)) - - else: - if min_val <= max_val: - min_phy_value = min_val - max_phy_value = max_val - else: - min_phy_value = 0 - max_phy_value = 0 - kargs = { - 'conversion_type': v2c.CONVERSION_TYPE_NONE, - 'unit': signal.unit.encode('latin-1'), - 'min_phy_value': min_phy_value, - 'max_phy_value': max_phy_value, - } - - if texts: - gp_texts['conversion_tab'][-1] = texts - - block = ChannelConversion(**kargs) - if memory != 'minimum': - gp_conv.append(block) - else: - address = tell() - gp_conv.append(address) - write(bytes(block)) - - # source for channel - kargs = { - 'module_nr': 0, - 'module_address': 0, - 'type': v2c.SOURCE_ECU, - 'description': b'Channel inserted by Python Script', - } - block = ChannelExtension(**kargs) - if memory != 'minimum': - gp_source.append(block) - else: - address = tell() - gp_source.append(address) - write(bytes(block)) - - # compute additional byte offset for large records size - current_offset = offset + bit_offset - if current_offset > v2c.MAX_UINT16: - additional_byte_offset = \ - (current_offset - v2c.MAX_UINT16) >> 3 - start_bit_offset = \ - current_offset - additional_byte_offset << 3 - else: - start_bit_offset = current_offset - additional_byte_offset = 0 - - if signal.samples.dtype.kind == 'u': - data_type = v2c.DATA_TYPE_UNSIGNED_INTEL - else: - data_type = v2c.DATA_TYPE_SIGNED_INTEL - - texts = {} - if len(name) >= 32 and self.version == '2.14': - short_name = (name[:31] + '\0').encode('latin-1') - if memory != 'minimum': - texts['long_name_addr'] = TextBlock(texts=name) - else: - address = tell() - texts['long_name_addr'] = address - block = TextBlock(texts=name) - gp_channels.append(address) - write(bytes(block)) - else: - short_name = name.encode('latin-1') - - if texts: - gp_texts['channels'][-1] = texts - - kargs = { - 'short_name': short_name, - 'channel_type': v2c.CHANNEL_TYPE_VALUE, - 'data_type': data_type, - 'min_raw_value': min_val if min_val <= max_val else 0, - 'max_raw_value': max_val if min_val <= max_val else 0, - 'start_offset': start_bit_offset, - 'bit_count': bit_count, - 'aditional_byte_offset': additional_byte_offset, - } - if self.version == '2.00': - kargs['block_len'] = v2c.CN20_BLOCK_SIZE - else: - kargs['block_len'] = v2c.CN21_BLOCK_SIZE - comment = signal.comment - if comment: - comment = comment.encode('latin-1') - if len(comment) >= 128: - comment = comment[:127] + b'\0' - kargs['description'] = comment - - channel = Channel(**kargs) - channel.name = name - if memory != 'minimum': - gp_channels.append(channel) - else: - address = tell() - gp_channels.append(address) - write(bytes(channel)) - - if name not in self.channels_db: - self.channels_db[name] = [] - self.channels_db[name].append((dg_cntr, ch_cntr)) - - # update the parents as well - parents[ch_cntr] = field_name, bit_offset - - # simple channels don't have channel dependencies - gp_dep.append(None) - - values += signal.samples.astype(dtype_) << bit_offset - bit_offset += bit_count - - ch_cntr += 1 - - offset += dtype_.itemsize * 8 - fields.append(values) - - # first add the signals in the simple signal list - for signal in simple_signals: - # channels texts - name = signal.name - for _, item in gp['texts'].items(): - item.append(None) - - texts = {} - if len(name) >= 32 and self.version == '2.14': - block = TextBlock(text=name) - if memory != 'minimum': - texts['long_name_addr'] = block - else: - address = tell() - texts['long_name_addr'] = address - write(bytes(block)) - if texts: - gp_texts['channels'][-1] = texts - - # conversions for channel - min_val, max_val = get_min_max(signal.samples) - - texts = {} - info = signal.info - if info and 'raw' in info and not info['raw'].dtype.kind == 'S': - kargs = {} - kargs['conversion_type'] = v2c.CONVERSION_TYPE_VTAB - raw = info['raw'] - phys = info['phys'] - for i, (r_, p_) in enumerate(zip(raw, phys)): - kargs['text_{}'.format(i)] = p_[:31] + b'\0' - kargs['param_val_{}'.format(i)] = r_ - kargs['ref_param_nr'] = len(raw) - kargs['unit'] = signal.unit.encode('latin-1') - elif info and 'lower' in info: - kargs = {} - kargs['conversion_type'] = v2c.CONVERSION_TYPE_VTABR - lower = info['lower'] - upper = info['upper'] - texts_ = info['phys'] - kargs['unit'] = signal.unit.encode('latin-1') - kargs['ref_param_nr'] = len(upper) - - for i, (u_, l_, t_) in enumerate(zip(upper, lower, texts_)): - kargs['lower_{}'.format(i)] = l_ - kargs['upper_{}'.format(i)] = u_ - kargs['text_{}'.format(i)] = 0 - - key = 'text_{}'.format(i) - block = TextBlock(text=t_) - if memory != 'minimum': - texts[key] = block - else: - address = tell() - texts[key] = address - write(bytes(block)) - - else: - if min_val <= max_val: - min_phy_value = min_val - max_phy_value = max_val - else: - min_phy_value = 0 - max_phy_value = 0 - kargs = { - 'conversion_type': v2c.CONVERSION_TYPE_NONE, - 'unit': signal.unit.encode('latin-1'), - 'min_phy_value': min_phy_value, - 'max_phy_value': max_phy_value, - } - - if texts: - gp_texts['conversion_tab'][-1] = texts - - block = ChannelConversion(**kargs) - if memory != 'minimum': - gp_conv.append(block) - else: - address = tell() - gp_conv.append(address) - write(bytes(block)) - - # source for channel - kargs = { - 'module_nr': 0, - 'module_address': 0, - 'type': v2c.SOURCE_ECU, - 'description': b'Channel inserted by Python Script', - } - block = ChannelExtension(**kargs) - if memory != 'minimum': - gp_source.append(block) - else: - address = tell() - gp_source.append(address) - write(bytes(block)) - - # compute additional byte offset for large records size - if offset > v2c.MAX_UINT16: - additional_byte_offset = (offset - v2c.MAX_UINT16) >> 3 - start_bit_offset = offset - additional_byte_offset << 3 - else: - start_bit_offset = offset - additional_byte_offset = 0 - s_type, s_size = fmt_to_datatype(signal.samples.dtype) - - if len(name) >= 32: - short_name = (name[:31] + '\0').encode('latin-1') - else: - short_name = name.encode('latin-1') - kargs = { - 'short_name': short_name, - 'channel_type': v2c.CHANNEL_TYPE_VALUE, - 'data_type': s_type, - 'min_raw_value': min_val if min_val <= max_val else 0, - 'max_raw_value': max_val if min_val <= max_val else 0, - 'start_offset': start_bit_offset, - 'bit_count': s_size, - 'aditional_byte_offset': additional_byte_offset, - } - if self.version == '2.00': - kargs['block_len'] = v2c.CN20_BLOCK_SIZE - else: - kargs['block_len'] = v2c.CN21_BLOCK_SIZE - comment = signal.comment - if comment: - if len(comment) >= 128: - comment = (comment[:127] + '\0').encode('latin-1') - else: - comment = comment.encode('latin-1') - kargs['description'] = comment - - channel = Channel(**kargs) - channel.name = name - if memory != 'minimum': - gp_channels.append(channel) - else: - address = tell() - gp_channels.append(address) - write(bytes(channel)) - offset += s_size - - if name not in self.channels_db: - self.channels_db[name] = [] - self.channels_db[name].append((dg_cntr, ch_cntr)) - - # update the parents as well - field_name = get_unique_name(field_names, name) - parents[ch_cntr] = field_name, 0 - - fields.append(signal.samples) - types.append((field_name, signal.samples.dtype)) - field_names.add(field_name) - - ch_cntr += 1 - - # simple channels don't have channel dependencies - gp_dep.append(None) - - # second, add the composed signals - for signal in composed_signals: - names = signal.samples.dtype.names - name = signal.name - - component_names = [] - component_samples = [] - if names: - samples = signal.samples[names[0]] - else: - samples = signal.samples - - shape = samples.shape[1:] - dims = [list(range(size)) for size in shape] - - for indexes in product(*dims): - subarray = samples - for idx in indexes: - subarray = subarray[:, idx] - component_samples.append(subarray) - - indexes = ''.join('[{}]'.format(idx) for idx in indexes) - component_name = '{}{}'.format(name, indexes) - component_names.append(component_name) - - # add channel dependency block for composed parent channel - sd_nr = len(component_samples) - kargs = {'sd_nr': sd_nr} - for i, dim in enumerate(shape[::-1]): - kargs['dim_{}'.format(i)] = dim - parent_dep = ChannelDependency(**kargs) - gp_dep.append(parent_dep) - - if names: - new_samples = [signal.samples[fld] for fld in names[1:]] - component_samples.extend(new_samples) - component_names.extend(names[1:]) - - # add composed parent signal texts - for _, item in gp['texts'].items(): - item.append(None) - - texts = {} - if len(name) >= 32 and self.version == '2.14': - block = TextBlock(text=name) - if memory != 'minimum': - texts['long_name_addr'] = block - else: - address = tell() - texts['long_name_addr'] = address - write(bytes(block)) - if texts: - gp_texts['channels'][-1] = texts - - # composed parent has no conversion - if memory != 'minimum': - gp_conv.append(None) - else: - gp_conv.append(0) - - # add parent and components sources - kargs = { - 'module_nr': 0, - 'module_address': 0, - 'type': v2c.SOURCE_ECU, - 'description': b'Channel inserted by Python Script', - } - block = ChannelExtension(**kargs) - if memory != 'minimum': - gp_source.append(block) - else: - address = tell() - gp_source.append(address) - write(bytes(block)) - - min_val, max_val = get_min_max(samples) - - s_type, s_size = fmt_to_datatype(samples.dtype) - # compute additional byte offset for large records size - if offset > v2c.MAX_UINT16: - additional_byte_offset = (offset - v2c.MAX_UINT16) >> 3 - start_bit_offset = offset - additional_byte_offset << 3 - else: - start_bit_offset = offset - additional_byte_offset = 0 - - if len(name) >= 32: - short_name = (name[:31] + '\0').encode('latin-1') - else: - short_name = name.encode('latin-1') - kargs = { - 'short_name': short_name, - 'channel_type': v2c.CHANNEL_TYPE_VALUE, - 'data_type': s_type, - 'min_raw_value': min_val if min_val <= max_val else 0, - 'max_raw_value': max_val if min_val <= max_val else 0, - 'start_offset': start_bit_offset, - 'bit_count': s_size, - 'aditional_byte_offset': additional_byte_offset, - } - if self.version == '2.00': - kargs['block_len'] = v2c.CN20_BLOCK_SIZE - else: - kargs['block_len'] = v2c.CN21_BLOCK_SIZE - comment = signal.comment - if comment: - if len(comment) >= 128: - comment = (comment[:127] + '\0').encode('latin-1') - else: - comment = comment.encode('latin-1') - kargs['description'] = comment - - channel = Channel(**kargs) - channel.name = name - channel.name = name - if memory != 'minimum': - gp_channels.append(channel) - else: - address = tell() - gp_channels.append(address) - write(bytes(channel)) - - if name not in self.channels_db: - self.channels_db[name] = [] - self.channels_db[name].append((dg_cntr, ch_cntr)) - - ch_cntr += 1 - - for i, (name, samples) in enumerate(zip(component_names, - component_samples)): - for _, item in gp['texts'].items(): - item.append(None) - - texts = {} - if len(name) >= 32 and self.version == '2.14': - block = TextBlock(text=name) - if memory != 'minimum': - texts['long_name_addr'] = block - else: - address = tell() - texts['long_name_addr'] = address - write(bytes(block)) - if texts: - gp_texts['channels'][-1] = texts - - min_val, max_val = get_min_max(samples) - s_type, s_size = fmt_to_datatype(samples.dtype) - shape = samples.shape[1:] - - kargs = { - 'module_nr': 0, - 'module_address': 0, - 'type': v2c.SOURCE_ECU, - 'description': b'Channel inserted by Python Script', - } - block = ChannelExtension(**kargs) - if memory != 'minimum': - gp_source.append(block) - else: - address = tell() - gp_source.append(address) - write(bytes(block)) - - if memory != 'minimum': - gp_conv.append(None) - else: - gp_conv.append(0) - - # compute additional byte offset for large records size - if offset > v2c.MAX_UINT16: - additional_byte_offset = (offset - v2c.MAX_UINT16) >> 3 - start_bit_offset = offset - additional_byte_offset << 3 - else: - start_bit_offset = offset - additional_byte_offset = 0 - - if len(name) >= 32: - short_name = (name[:31] + '\0').encode('latin-1') - else: - short_name = name.encode('latin-1') - kargs = { - 'short_name': short_name, - 'channel_type': v2c.CHANNEL_TYPE_VALUE, - 'data_type': s_type, - 'min_raw_value': min_val if min_val <= max_val else 0, - 'max_raw_value': max_val if min_val <= max_val else 0, - 'start_offset': start_bit_offset, - 'bit_count': s_size, - 'aditional_byte_offset': additional_byte_offset, - } - if self.version == '2.00': - kargs['block_len'] = v2c.CN20_BLOCK_SIZE - else: - kargs['block_len'] = v2c.CN21_BLOCK_SIZE - - channel = Channel(**kargs) - channel.name = name - if memory != 'minimum': - gp_channels.append(channel) - else: - address = tell() - gp_channels.append(address) - write(bytes(channel)) - size = s_size - for dim in shape: - size *= dim - offset += size - - if name not in self.channels_db: - self.channels_db[name] = [] - self.channels_db[name].append((dg_cntr, ch_cntr)) - - # update the parents as well - field_name = get_unique_name(field_names, name) - parents[ch_cntr] = field_name, 0 - - fields.append(samples) - types.append((field_name, samples.dtype, shape)) - field_names.add(field_name) - - gp_dep.append(None) - - if i < sd_nr: - dep_pair = ch_cntr, dg_cntr - parent_dep.referenced_channels.append(dep_pair) - else: - description = '{} - axis {}'.format(signal.name, name) - description = description.encode('latin-1') - channel['description'] = description - - ch_cntr += 1 - - # channel group - kargs = { - 'cycles_nr': cycles_nr, - 'samples_byte_nr': offset >> 3, - } - gp['channel_group'] = ChannelGroup(**kargs) - gp['channel_group']['ch_nr'] = ch_cntr - gp['size'] = cycles_nr * (offset >> 3) - - # data group - if self.version in ('3.20', '3.30'): - block_len = v2c.DG32_BLOCK_SIZE - else: - block_len = v2c.DG31_BLOCK_SIZE - gp['data_group'] = DataGroup(block_len=block_len) - - # data block - if PYVERSION == 2: - types = fix_dtype_fields(types) - types = dtype(types) - - gp['types'] = types - gp['parents'] = parents - gp['sorted'] = True - - samples = fromarrays(fields, dtype=types) - block = samples.tostring() - - if memory == 'full': - gp['data_location'] = v2c.LOCATION_MEMORY - kargs = {'data': block} - gp['data_block'] = DataBlock(**kargs) - else: - gp['data_location'] = v2c.LOCATION_TEMPORARY_FILE - if cycles_nr: - data_address = tell() - gp['data_group']['data_block_addr'] = data_address - self._tempfile.write(block) - else: - gp['data_group']['data_block_addr'] = 0 - - # data group trigger - gp['trigger'] = [None, None] - - for signal in new_groups_signals: - dg_cntr = len(self.groups) - gp = {} - gp['channels'] = gp_channels = [] - gp['channel_conversions'] = gp_conv = [] - gp['channel_extensions'] = gp_source = [] - gp['channel_dependencies'] = gp_dep = [] - gp['texts'] = gp_texts = { - 'channels': [], - 'conversion_tab': [], - 'channel_group': [], - } - self.groups.append(gp) - - cycles_nr = len(t) - fields = [] - types = [] - parents = {} - ch_cntr = 0 - offset = 0 - field_names = set() - - # setup all blocks related to the time master channel - - # time channel texts - for _, item in gp_texts.items(): - item.append(None) - - # conversion for time channel - kargs = { - 'conversion_type': v2c.CONVERSION_TYPE_NONE, - 'unit': b's', - 'min_phy_value': t[0] if cycles_nr else 0, - 'max_phy_value': t[-1] if cycles_nr else 0, - } - block = ChannelConversion(**kargs) - if memory == 'minimum': - address = tell() - write(bytes(block)) - gp_conv.append(address) - else: - gp_conv.append(ChannelConversion(**kargs)) - - # source for time - kargs = { - 'module_nr': 0, - 'module_address': 0, - 'type': v2c.SOURCE_ECU, - 'description': b'Channel inserted by Python Script', - } - block = ChannelExtension(**kargs) - if memory != 'minimum': - gp_source.append(block) - else: - address = tell() - gp_source.append(address) - write(bytes(block)) - - # time channel - t_type, t_size = fmt_to_datatype(t.dtype) - kargs = { - 'short_name': b't', - 'channel_type': v2c.CHANNEL_TYPE_MASTER, - 'data_type': t_type, - 'start_offset': 0, - 'min_raw_value': t[0] if cycles_nr else 0, - 'max_raw_value': t[-1] if cycles_nr else 0, - 'bit_count': t_size, - } - if self.version == '2.00': - kargs['block_len'] = v2c.CN20_BLOCK_SIZE - else: - kargs['block_len'] = v2c.CN21_BLOCK_SIZE - channel = Channel(**kargs) - channel.name = name = 't' - if memory != 'minimum': - gp_channels.append(channel) - else: - address = tell() - gp_channels.append(address) - write(bytes(channel)) - - if name not in self.channels_db: - self.channels_db[name] = [] - self.channels_db[name].append((dg_cntr, ch_cntr)) - self.masters_db[dg_cntr] = 0 - # data group record parents - parents[ch_cntr] = name, 0 - - # time channel doesn't have channel dependencies - gp_dep.append(None) - - fields.append(t) - types.append((name, t.dtype)) - field_names.add(name) - - offset += t_size - ch_cntr += 1 - - names = signal.samples.dtype.names - if names == ('ms', - 'days'): - block = TextBlock(text='From mdf v4 CANopen Time channel') - if memory == 'minimum': - address = tell() - write(bytes(block)) - gp_texts['channel_group'][-1] = {'comment_addr': address} - else: - gp_texts['channel_group'][-1] = {'comment_addr': block} - elif names == ('ms', - 'min', - 'hour', - 'day', - 'month', - 'year', - 'summer_time', - 'day_of_week'): - block = TextBlock(text='From mdf v4 CANopen Date channel') - if memory == 'minimum': - address = tell() - write(bytes(block)) - gp_texts['channel_group'][-1] = {'comment_addr': address} - else: - gp_texts['channel_group'][-1] = {'comment_addr': block} - else: - text = 'From mdf v4 structure channel composition' - block = TextBlock(text=text) - if memory == 'minimum': - address = tell() - write(bytes(block)) - gp_texts['channel_group'][-1] = {'comment_addr': address} - else: - gp_texts['channel_group'][-1] = {'comment_addr': block} - - for name in names: - - samples = signal.samples[name] - - # channels texts - for _, item in gp['texts'].items(): - item.append(None) - - texts = {} - if len(name) >= 32 and self.version == '2.14': - block = TextBlock(text=name) - texts['long_name_addr'] = block - if texts: - gp_texts['channels'][-1] = texts - - # conversions for channel - min_val, max_val = get_min_max(samples) - - kargs = { - 'conversion_type': v2c.CONVERSION_TYPE_NONE, - 'unit': signal.unit.encode('latin-1'), - 'min_phy_value': min_val if min_val <= max_val else 0, - 'max_phy_value': max_val if min_val <= max_val else 0, - } - block = ChannelConversion(**kargs) - if memory != 'minimum': - gp_conv.append(block) - else: - address = tell() - gp_conv.append(address) - write(bytes(block)) - - # source for channel - kargs = { - 'module_nr': 0, - 'module_address': 0, - 'type': v2c.SOURCE_ECU, - 'description': b'Channel inserted by Python Script', - } - block = ChannelExtension(**kargs) - if memory != 'minimum': - gp_source.append(block) - else: - address = tell() - gp_source.append(address) - write(bytes(block)) - - # compute additional byte offset for large records size - if offset > v2c.MAX_UINT16: - additional_byte_offset = (offset - v2c.MAX_UINT16) >> 3 - start_bit_offset = offset - additional_byte_offset << 3 - else: - start_bit_offset = offset - additional_byte_offset = 0 - s_type, s_size = fmt_to_datatype(samples.dtype) - if len(name) >= 32: - short_name = (name[:31] + '\0').encode('latin-1') - else: - short_name = name.encode('latin-1') - kargs = { - 'short_name': short_name, - 'channel_type': v2c.CHANNEL_TYPE_VALUE, - 'data_type': s_type, - 'min_raw_value': min_val if min_val <= max_val else 0, - 'max_raw_value': max_val if min_val <= max_val else 0, - 'start_offset': start_bit_offset, - 'bit_count': s_size, - 'aditional_byte_offset': additional_byte_offset, - } - if self.version == '2.00': - kargs['block_len'] = v2c.CN20_BLOCK_SIZE - else: - kargs['block_len'] = v2c.CN21_BLOCK_SIZE - - channel = Channel(**kargs) - channel.name = name - if memory != 'minimum': - gp_channels.append(channel) - else: - address = tell() - gp_channels.append(address) - write(bytes(channel)) - offset += s_size - - if name not in self.channels_db: - self.channels_db[name] = [] - self.channels_db[name].append((dg_cntr, ch_cntr)) - - # update the parents as well - field_name = get_unique_name(field_names, name) - parents[ch_cntr] = field_name, 0 - - fields.append(samples) - types.append((field_name, samples.dtype)) - field_names.add(field_name) - - ch_cntr += 1 - - # simple channels don't have channel dependencies - gp_dep.append(None) - - # channel group - kargs = { - 'cycles_nr': cycles_nr, - 'samples_byte_nr': offset >> 3, - } - gp['channel_group'] = ChannelGroup(**kargs) - gp['channel_group']['ch_nr'] = ch_cntr - gp['size'] = cycles_nr * (offset >> 3) - - # data group - if self.version in ('3.20', '3.30'): - block_len = v2c.DG32_BLOCK_SIZE - else: - block_len = v2c.DG31_BLOCK_SIZE - gp['data_group'] = DataGroup(block_len=block_len) - - # data block - if PYVERSION == 2: - types = fix_dtype_fields(types) - types = dtype(types) - - gp['types'] = types - gp['parents'] = parents - gp['sorted'] = True - - samples = fromarrays(fields, dtype=types) - try: - block = samples.tostring() - - if memory == 'full': - gp['data_location'] = v2c.LOCATION_MEMORY - kargs = {'data': block} - gp['data_block'] = DataBlock(**kargs) - else: - gp['data_location'] = v2c.LOCATION_TEMPORARY_FILE - if cycles_nr: - data_address = tell() - gp['data_group']['data_block_addr'] = data_address - self._tempfile.write(block) - else: - gp['data_group']['data_block_addr'] = 0 - except MemoryError: - if memory == 'full': - raise - else: - gp['data_location'] = v2c.LOCATION_TEMPORARY_FILE - - data_address = tell() - gp['data_group']['data_block_addr'] = data_address - for sample in samples: - self._tempfile.write(sample.tostring()) - - # data group trigger - gp['trigger'] = [None, None] - - def close(self): - """if the MDF was created with memory='minimum' and new - channels have been appended, then this must be called just before the - object is not used anymore to clean-up the temporary file - - """ - if self._tempfile is not None: - self._tempfile.close() - if self._file is not None: - self._file.close() - - def get_channel_unit(self, name=None, group=None, index=None): - """Gets channel unit. - - Channel can be specified in two ways: - - * using the first positional argument *name* - - * if there are multiple occurrences for this channel then the - *group* and *index* arguments can be used to select a specific - group. - * if there are multiple occurrences for this channel and either the - *group* or *index* arguments is None then a warning is issued - - * using the group number (keyword argument *group*) and the channel - number (keyword argument *index*). Use *info* method for group and - channel numbers - - - If the *raster* keyword argument is not *None* the output is - interpolated accordingly. - - Parameters - ---------- - name : string - name of channel - group : int - 0-based group index - index : int - 0-based channel index - - Returns - ------- - unit : str - found channel unit - - """ - gp_nr, ch_nr = self._validate_channel_selection( - name, - group, - index, - ) - - grp = self.groups[gp_nr] - if grp['data_location'] == v2c.LOCATION_ORIGINAL_FILE: - stream = self._file - else: - stream = self._tempfile - - if self.memory == 'minimum': - addr = grp['channel_conversions'][ch_nr] - if addr: - conversion = ChannelConversion( - address=addr, - stream=stream, - ) - else: - conversion = None - - else: - conversion = grp['channel_conversions'][ch_nr] - - if conversion: - unit = conversion['unit'].decode('latin-1').strip(' \n\t\0') - else: - unit = '' - - return unit - - def get_channel_comment(self, name=None, group=None, index=None): - """Gets channel comment. - - Channel can be specified in two ways: - - * using the first positional argument *name* - - * if there are multiple occurrences for this channel then the - *group* and *index* arguments can be used to select a specific - group. - * if there are multiple occurrences for this channel and either the - *group* or *index* arguments is None then a warning is issued - - * using the group number (keyword argument *group*) and the channel - number (keyword argument *index*). Use *info* method for group and - channel numbers - - - If the *raster* keyword argument is not *None* the output is - interpolated accordingly. - - Parameters - ---------- - name : string - name of channel - group : int - 0-based group index - index : int - 0-based channel index - - Returns - ------- - comment : str - found channel comment - - """ - gp_nr, ch_nr = self._validate_channel_selection( - name, - group, - index, - ) - - grp = self.groups[gp_nr] - if grp['data_location'] == v2c.LOCATION_ORIGINAL_FILE: - stream = self._file - else: - stream = self._tempfile - - if self.memory == 'minimum': - channel = Channel( - address=grp['channels'][ch_nr], - stream=stream, - ) - else: - channel = grp['channels'][ch_nr] - - comment = channel['description'].decode('latin-1') - comment = comment.strip(' \t\n\0') - - return comment - - def get(self, - name=None, - group=None, - index=None, - raster=None, - samples_only=False, - data=None, - raw=False): - """Gets channel samples. - - Channel can be specified in two ways: - - * using the first positional argument *name* - - * if there are multiple occurrences for this channel then the - *group* and *index* arguments can be used to select a specific - group. - * if there are multiple occurrences for this channel and either the - *group* or *index* arguments is None then a warning is issued - - * using the group number (keyword argument *group*) and the channel - number (keyword argument *index*). Use *info* method for group and - channel numbers - - - If the *raster* keyword argument is not *None* the output is - interpolated accordingly. - - Parameters - ---------- - name : string - name of channel - group : int - 0-based group index - index : int - 0-based channel index - raster : float - time raster in seconds - samples_only : bool - if *True* return only the channel samples as numpy array; if - *False* return a *Signal* object - data : bytes - prevent redundant data read by providing the raw data group samples - raw : bool - return channel samples without appling the conversion rule; default - `False` - - - Returns - ------- - res : (numpy.array | Signal) - returns *Signal* if *samples_only*=*False* (default option), - otherwise returns numpy.array. - The *Signal* samples are: - - * numpy recarray for channels that have CDBLOCK or BYTEARRAY - type channels - * numpy array for all the rest - - Raises - ------ - MdfError : - - * if the channel name is not found - * if the group index is out of range - * if the channel index is out of range - - """ - gp_nr, ch_nr = self._validate_channel_selection( - name, - group, - index, - ) - - memory = self.memory - grp = self.groups[gp_nr] - - if grp['data_location'] == v2c.LOCATION_ORIGINAL_FILE: - stream = self._file - else: - stream = self._tempfile - - channel = grp['channels'][ch_nr] - conversion = grp['channel_conversions'][ch_nr] - - if memory != 'minimum': - channel = grp['channels'][ch_nr] - conversion = grp['channel_conversions'][ch_nr] - name = channel.name - else: - channel = Channel( - address=grp['channels'][ch_nr], - stream=stream, - ) - addr = grp['channel_conversions'][ch_nr] - if addr: - conversion = ChannelConversion( - address=addr, - stream=stream, - ) - else: - conversion = None - if name is None: - if channel.get('long_name_addr', 0): - name = TextBlock( - address=channel['long_name_addr'], - stream=stream, - ) - name = name['text'] - else: - name = channel['short_name'] - name = name.decode('utf-8').strip(' \r\t\n\0') - name = name.split('\\')[0] - channel.name = name - - dep = grp['channel_dependencies'][ch_nr] - cycles_nr = grp['channel_group']['cycles_nr'] - - # get data group record - if data is None: - data = self._load_group_data(grp) - - info = None - - # check if this is a channel array - if dep: - if dep['dependency_type'] == v2c.DEPENDENCY_TYPE_VECTOR: - shape = [dep['sd_nr'], ] - elif dep['dependency_type'] >= v2c.DEPENDENCY_TYPE_NDIM: - shape = [] - i = 0 - while True: - try: - dim = dep['dim_{}'.format(i)] - shape.append(dim) - i += 1 - except KeyError: - break - shape = shape[::-1] - - record_shape = tuple(shape) - - arrays = [ - self.get(group=dg_nr, index=ch_nr, samples_only=True, raw=raw) - for ch_nr, dg_nr in dep.referenced_channels - ] - if cycles_nr: - shape.insert(0, cycles_nr) - - vals = column_stack(arrays).flatten().reshape(tuple(shape)) - - arrays = [vals, ] - types = [(channel.name, vals.dtype, record_shape), ] - - if PYVERSION == 2: - types = fix_dtype_fields(types) - - types = dtype(types) - vals = fromarrays(arrays, dtype=types) - - else: - # get channel values - try: - parents, dtypes = grp['parents'], grp['types'] - except KeyError: - grp['parents'], grp['types'] = self._prepare_record(grp) - parents, dtypes = grp['parents'], grp['types'] - - try: - parent, bit_offset = parents[ch_nr] - except KeyError: - parent, bit_offset = None, None - - if parent is not None: - if 'record' not in grp: - if dtypes.itemsize: - record = fromstring(data, dtype=dtypes) - else: - record = None - - if memory == 'full': - grp['record'] = record - else: - record = grp['record'] - - vals = record[parent] - bits = channel['bit_count'] - size = vals.dtype.itemsize - data_type = channel['data_type'] - - if vals.dtype.kind not in 'ui' and (bit_offset or not bits == size * 8): - vals = self._get_not_byte_aligned_data(data, grp, ch_nr) - else: - if bit_offset: - dtype_ = vals.dtype - if dtype_.kind == 'i': - vals = vals.astype(dtype('>= bit_offset - else: - vals = vals >> bit_offset - - if not bits == size * 8: - mask = (1 << bits) - 1 - if vals.flags.writeable: - vals &= mask - else: - vals = vals & mask - if data_type in v2c.SIGNED_INT: - size = vals.dtype.itemsize - mask = (1 << (size * 8)) - 1 - mask = (mask << bits) & mask - vals |= mask - vals = vals.astype('>> mdf = MDF2('test.mdf') - >>> mdf.info() - - """ - info = {} - for key in ('author', - 'organization', - 'project', - 'subject'): - value = self.header[key].decode('latin-1').strip(' \n\t\0') - info[key] = value - info['version'] = self.version - info['groups'] = len(self.groups) - for i, gp in enumerate(self.groups): - if gp['data_location'] == v2c.LOCATION_ORIGINAL_FILE: - stream = self._file - elif gp['data_location'] == v2c.LOCATION_TEMPORARY_FILE: - stream = self._tempfile - inf = {} - info['group {}'.format(i)] = inf - inf['cycles'] = gp['channel_group']['cycles_nr'] - inf['channels count'] = len(gp['channels']) - for j, channel in enumerate(gp['channels']): - if self.memory != 'minimum': - name = channel.name - else: - channel = Channel( - address=channel, - stream=stream, - ) - if channel.get('long_name_addr', 0): - name = TextBlock( - address=channel['long_name_addr'], - stream=stream, - ) - name = name['text'] - else: - name = channel['short_name'] - name = name.decode('utf-8').strip(' \r\t\n\0') - name = name.split('\\')[0] - - if channel['channel_type'] == v2c.CHANNEL_TYPE_MASTER: - ch_type = 'master' - else: - ch_type = 'value' - inf['channel {}'.format(j)] = 'name="{}" type={}'.format(name, ch_type) - - return info - - def save(self, dst='', overwrite=None, compression=0): - """Save MDF to *dst*. If *dst* is not provided the the destination file - name is the MDF name. If overwrite is *True* then the destination file - is overwritten, otherwise the file name is appended with '_', were - '' is the first counter that produces a new file name (that does - not already exist in the filesystem). - - Parameters - ---------- - dst : str - destination file name, Default '' - overwrite : bool - overwrite flag, default *False* - compression : int - does nothing for mdf version3; introduced here to share the same - API as mdf version 4 files - - """ - - if overwrite is None: - overwrite = self._overwrite - - if self.name is None and dst == '': - message = ('Must specify a destination file name ' - 'for MDF created from scratch') - raise MdfException(message) - - dst = dst if dst else self.name - if overwrite is False: - if os.path.isfile(dst): - cntr = 0 - while True: - name = os.path.splitext(dst)[0] + '_{}.mdf'.format(cntr) - if not os.path.isfile(name): - break - else: - cntr += 1 - message = ('Destination file "{}" already exists ' - 'and "overwrite" is False. Saving MDF file as "{}"') - message = message.format(dst, name) - warnings.warn(message) - dst = name - - if self.memory != 'minimum': - self._save_with_metadata(dst, overwrite, compression) - else: - self._save_without_metadata(dst, overwrite, compression) - - def _save_with_metadata(self, dst, overwrite, compression): - """Save MDF to *dst*. If *dst* is not provided the the destination file - name is the MDF name. If overwrite is *True* then the destination file - is overwritten, otherwise the file name is appended with '_', were - '' is the first counter that produces a new file name (that does - not already exist in the filesystem). - - Parameters - ---------- - dst : str - destination file name, Default '' - overwrite : bool - overwrite flag, default *False* - compression : int - does nothing for mdf version3; introduced here to share the same - API as mdf version 4 files - - """ - - if self.file_history is None: - self.file_history = TextBlock(text=''' -created -asammdf - -{} -'''.format(__version__)) - else: - text = '{}\n{}: updated by asammdf {}' - old_history = self.file_history['text'].decode('latin-1') - timestamp = time.asctime().encode('latin-1') - - text = text.format( - old_history, - timestamp, - __version__, - ) - self.file_history = TextBlock(text=text) - - if self.name is None and dst == '': - message = ('Must specify a destination file name ' - 'for MDF created from scratch') - raise MdfException(message) - - dst = dst if dst else self.name - if overwrite is False: - if os.path.isfile(dst): - cntr = 0 - while True: - name = os.path.splitext(dst)[0] + '_{}.mdf'.format(cntr) - if not os.path.isfile(name): - break - else: - cntr += 1 - message = ('Destination file "{}" already exists ' - 'and "overwrite" is False. Saving MDF file as "{}"') - message = message.format(dst, name) - warnings.warn(message) - dst = name - - # all MDF blocks are appended to the blocks list in the order in which - # they will be written to disk. While creating this list, all the - # relevant block links are updated so that once all blocks have been - # added to the list they can be written using the bytes protocol. - # DataGroup blocks are written first after the identification and - # header blocks. When memory='low' we need to restore the - # original data block addresses within the data group block. This is - # needed to allow further work with the object after the save method - # call (eq. new calls to get method). Since the data group blocks are - # written first, it is safe to restor the original links when the data - # blocks are written. For memory=False the blocks list will - # contain a tuple instead of a DataBlock instance; the tuple will have - # the reference to the data group object and the original link to the - # data block in the soource MDF file. - - if self.memory == 'low' and dst == self.name: - destination = dst + '.temp' - else: - destination = dst - - with open(destination, 'wb+') as dst_: - defined_texts = {} - - write = dst_.write - # list of all blocks - blocks = [] - - address = 0 - - blocks.append(self.identification) - address += v2c.ID_BLOCK_SIZE - - blocks.append(self.header) - address += self.header['block_len'] - - self.file_history.address = address - blocks.append(self.file_history) - address += self.file_history['block_len'] - - # DataGroup - # put them first in the block list so they will be written first to - # disk this way, in case of memory=False, we can safely - # restore he original data block address - for gp in self.groups: - dg = gp['data_group'] - blocks.append(dg) - dg.address = address - address += dg['block_len'] - - if self.groups: - for i, dg in enumerate(self.groups[:-1]): - addr = self.groups[i+1]['data_group'].address - dg['data_group']['next_dg_addr'] = addr - self.groups[-1]['data_group']['next_dg_addr'] = 0 - - for gp in self.groups: - gp_texts = gp['texts'] - - # Texts - for item_list in gp_texts.values(): - for my_dict in item_list: - if my_dict is None: - continue - for key, tx_block in my_dict.items(): - # text blocks can be shared - text = tx_block['text'] - if text in defined_texts: - tx_block.address = defined_texts[text] - else: - defined_texts[text] = address - tx_block.address = address - blocks.append(tx_block) - address += tx_block['block_len'] - - # ChannelConversions - cc = gp['channel_conversions'] - for i, conv in enumerate(cc): - if conv is None: - continue - - conv.address = address - if conv['conversion_type'] == v2c.CONVERSION_TYPE_VTABR: - pairs = gp_texts['conversion_tab'][i].items() - for key, item in pairs: - conv[key] = item.address - - blocks.append(conv) - address += conv['block_len'] - - # Channel Extension - cs = gp['channel_extensions'] - for source in cs: - if source: - source.address = address - blocks.append(source) - address += source['block_len'] - - # Channel Dependency - cd = gp['channel_dependencies'] - for dep in cd: - if dep: - dep.address = address - blocks.append(dep) - address += dep['block_len'] - - # Channels - ch_texts = gp_texts['channels'] - for i, channel in enumerate(gp['channels']): - channel.address = address - channel_texts = ch_texts[i] - - blocks.append(channel) - if self.version == '2.00': - address += v2c.CN20_BLOCK_SIZE - else: - address += v2c.CN21_BLOCK_SIZE - - if channel_texts: - for key in ('long_name_addr', - 'comment_addr'): - if key in channel_texts: - channel[key] = channel_texts[key].address - else: - channel[key] = 0 - - channel['conversion_addr'] = cc[i].address if cc[i] else 0 - if cs[i]: - channel['source_depend_addr'] = cs[i].address - else: - channel['source_depend_addr'] = 0 - if cd[i]: - channel['ch_depend_addr'] = cd[i].address - else: - channel['ch_depend_addr'] = 0 - - for channel, next_channel in pair(gp['channels']): - channel['next_ch_addr'] = next_channel.address - next_channel['next_ch_addr'] = 0 - - # ChannelGroup - cg = gp['channel_group'] - cg.address = address - blocks.append(cg) - address += cg['block_len'] - - cg['first_ch_addr'] = gp['channels'][0].address - cg['next_cg_addr'] = 0 - cg_texts = gp['texts']['channel_group'][0] - if 'comment_addr' in cg_texts: - addr = cg_texts['comment_addr'].address - cg['comment_addr'] = addr - - # TriggerBLock - trigger, trigger_text = gp['trigger'] - if trigger: - if trigger_text: - trigger_text.address = address - blocks.append(trigger_text) - address += trigger_text['block_len'] - trigger['comment_addr'] = trigger_text.address - else: - trigger['comment_addr'] = 0 - - trigger.address = address - blocks.append(trigger) - address += trigger['block_len'] - - # DataBlock - original_data_addr = gp['data_group']['data_block_addr'] - if gp['size']: - gp['data_group']['data_block_addr'] = address - else: - gp['data_group']['data_block_addr'] = 0 - address += gp['size'] - if self.memory == 'full': - blocks.append(gp['data_block']) - else: - # trying to call bytes([gp, address]) will result in an - # exceptionthat be used as a flag for non existing data - # block in caseof memory=False, the address is - # the actual addressof the data group's data within the - # original file - blocks.append([gp, original_data_addr]) - - # update referenced channels addresses in the channel dependecies - for gp in self.groups: - for dep in gp['channel_dependencies']: - if not dep: - continue - - for i, pair_ in enumerate(dep.referenced_channels): - ch_nr, dg_nr = pair_ - grp = self.groups[dg_nr] - ch = grp['channels'][ch_nr] - dep['ch_{}'.format(i)] = ch.address - dep['cg_{}'.format(i)] = grp['channel_group'].address - dep['dg_{}'.format(i)] = grp['data_group'].address - - # DataGroup - for gp in self.groups: - gp['data_group']['first_cg_addr'] = gp['channel_group'].address - if gp['trigger'][0]: - gp['data_group']['trigger_addr'] = gp['trigger'][0].address - else: - gp['data_group']['trigger_addr'] = 0 - - if self.groups: - address = self.groups[0]['data_group'].address - self.header['first_dg_addr'] = address - self.header['dg_nr'] = len(self.groups) - self.header['comment_addr'] = self.file_history.address - self.header['program_addr'] = 0 - - for block in blocks: - try: - write(bytes(block)) - except: - # this will only be executed for data blocks when - # memory=False - gp, address = block - # restore data block address from original file so that - # future calls to get will still work after the save - gp['data_group']['data_block_addr'] = address - data = self._load_group_data(gp) - write(data) - - if self.memory == 'low' and dst == self.name: - self.close() - os.remove(self.name) - os.rename(destination, self.name) - - self.groups = [] - self.header = None - self.identification = None - self.file_history = [] - self.channels_db = {} - self.masters_db = {} - self.attachments = [] - self.file_comment = None - - self._ch_map = {} - self._master_channel_cache = {} - - self._tempfile = TemporaryFile() - self._file = open(self.name, 'rb') - self._read() - - def _save_without_metadata(self, dst, overwrite, compression): - """Save MDF to *dst*. If *dst* is not provided the the destination file - name is the MDF name. If overwrite is *True* then the destination file - is overwritten, otherwise the file name is appended with '_', were - '' is the first counter that produces a new file name (that does - not already exist in the filesystem). - - Parameters - ---------- - dst : str - destination file name, Default '' - overwrite : bool - overwrite flag, default *False* - compression : int - does nothing for mdf version3; introduced here to share the same - API as mdf version 4 files - - """ - - if self.file_history is None: - self.file_history = TextBlock(text=''' -created -asammdf - -{} -'''.format(__version__)) - else: - text = '{}\n{}: updated by asammdf {}' - old_history = self.file_history['text'].decode('latin-1') - timestamp = time.asctime().encode('latin-1') - - text = text.format( - old_history, - timestamp, - __version__, - ) - self.file_history = TextBlock(text=text) - - # all MDF blocks are appended to the blocks list in the order in which - # they will be written to disk. While creating this list, all the - # relevant block links are updated so that once all blocks have been - # added to the list they can be written using the bytes protocol. - # DataGroup blocks are written first after the identification and - # header blocks. When memory=False we need to restore the - # original data block addresses within the data group block. This is - # needed to allow further work with the object after the save method - # call (eq. new calls to get method). Since the data group blocks are - # written first, it is safe to restor the original links when the data - # blocks are written. For memory=False the blocks list will - # contain a tuple instead of a DataBlock instance; the tuple will have - # the reference to the data group object and the original link to the - # data block in the soource MDF file. - - if dst == self.name: - destination = dst + '.temp' - else: - destination = dst - - with open(destination, 'wb+') as dst_: - defined_texts = {} - - write = dst_.write - tell = dst_.tell - seek = dst_.seek - # list of all blocks - blocks = [] - - address = 0 - - write(bytes(self.identification)) - - write(bytes(self.header)) - - address = tell() - self.file_history.address = address - write(bytes(self.file_history)) - - # DataGroup - # put them first in the block list so they will be written first to - # disk this way, in case of memory=False, we can safely - # restore he original data block address - - data_address = [] - - for gp in self.groups: - gp_texts = deepcopy(gp['texts']) - if gp['data_location'] == v2c.LOCATION_ORIGINAL_FILE: - stream = self._file - else: - stream = self._tempfile - - # Texts - for item_list in gp_texts.values(): - for my_dict in item_list: - if my_dict is None: - continue - for key, tx_block in my_dict.items(): - - # text blocks can be shared - block = TextBlock( - address=tx_block, - stream=stream, - ) - text = block['text'] - if text in defined_texts: - my_dict[key] = defined_texts[text] - else: - address = tell() - defined_texts[text] = address - my_dict[key] = address - write(bytes(block)) - - # ChannelConversions - cc = gp['temp_channel_conversions'] = [] - for i, conv in enumerate(gp['channel_conversions']): - if not conv: - gp['temp_channel_conversions'].append(0) - continue - - address = tell() - gp['temp_channel_conversions'].append(address) - conv = ChannelConversion( - address=conv, - stream=stream, - ) - if conv['conversion_type'] == v2c.CONVERSION_TYPE_VTABR: - pairs = gp_texts['conversion_tab'][i].items() - for key, item in pairs: - conv[key] = item - - write(bytes(conv)) - - # Channel Extension - cs = gp['temp_channel_extensions'] = [] - for source in gp['channel_extensions']: - if source: - address = tell() - gp['temp_channel_extensions'].append(address) - source = ChannelExtension( - address=source, - stream=stream, - ) - write(bytes(source)) - else: - gp['temp_channel_extensions'].append(0) - - # Channel Dependency - cd = gp['temp_channel_dependencies'] = [] - for dep in gp['channel_dependencies']: - if dep: - address = tell() - gp['temp_channel_dependencies'].append(address) - dep.address = address - write(bytes(dep)) - else: - gp['temp_channel_dependencies'].append(0) - - # Channels - blocks = [] - address = tell() - ch_texts = gp_texts['channels'] - gp['temp_channels'] = ch_addrs = [] - gp['channel_group']['first_ch_addr'] = address - for i, channel in enumerate(gp['channels']): - channel = Channel( - address=channel, - stream=stream, - ) - channel.address = address - channel_texts = ch_texts[i] - - ch_addrs.append(address) - - address += channel['block_len'] - blocks.append(channel) - - if channel_texts: - for key in ('long_name_addr', - 'comment_addr'): - if key in channel_texts: - channel[key] = channel_texts[key] - else: - channel[key] = 0 - else: - for key in ('long_name_addr', - 'comment_addr'): - channel[key] = 0 - if self.version == '2.00' and 'long_name_addr' in channel: - del channel['long_name_addr'] - - channel['conversion_addr'] = cc[i] - channel['source_depend_addr'] = cs[i] - channel['ch_depend_addr'] = cd[i] - - group_channels = gp['channels'] - if group_channels: - for j, channel in enumerate(blocks[:-1]): - channel['next_ch_addr'] = blocks[j+1].address - blocks[-1]['next_ch_addr'] = 0 - for block in blocks: - write(bytes(block)) - - blocks = None - - address = tell() - - # ChannelGroup - cg = gp['channel_group'] - cg.address = address - - cg['next_cg_addr'] = 0 - cg_texts = gp_texts['channel_group'][0] - if 'comment_addr' in cg_texts: - addr = cg_texts['comment_addr'] - cg['comment_addr'] = addr - write(bytes(cg)) - - address = tell() - - # TriggerBLock - trigger, trigger_text = gp['trigger'] - if trigger: - if trigger_text: - trigger_text.address = address - write(bytes(trigger_text)) - trigger['comment_addr'] = trigger_text.address - else: - trigger['comment_addr'] = 0 - - address = tell() - trigger.address = address - write(bytes(trigger)) - - address = tell() - - # DataBlock - data = self._load_group_data(gp) - - if data: - data_address.append(address) - write(bytes(data)) - else: - data_address.append(0) - - del gp['temp_channel_conversions'] - del gp['temp_channel_extensions'] - - orig_addr = [gp['data_group']['data_block_addr'] for gp in self.groups] - address = tell() - for i, gp in enumerate(self.groups): - dg = gp['data_group'] - dg['data_block_addr'] = data_address[i] - dg.address = address - address += dg['block_len'] - gp['data_group']['first_cg_addr'] = gp['channel_group'].address - if gp['trigger'][0]: - gp['data_group']['trigger_addr'] = gp['trigger'][0].address - else: - gp['data_group']['trigger_addr'] = 0 - - if self.groups: - for i, gp in enumerate(self.groups[:-1]): - addr = self.groups[i+1]['data_group'].address - gp['data_group']['next_dg_addr'] = addr - self.groups[-1]['data_group']['next_dg_addr'] = 0 - - for i, gp in enumerate(self.groups): - write(bytes(gp['data_group'])) - gp['data_block_addr'] = orig_addr[i] - - if self.groups: - address = self.groups[0]['data_group'].address - self.header['first_dg_addr'] = address - self.header['dg_nr'] = len(self.groups) - self.header['comment_addr'] = self.file_history.address - self.header['program_addr'] = 0 - - # update referenced channels addresses in the channel dependecies - for gp in self.groups: - for dep in gp['channel_dependencies']: - if not dep: - continue - - for i, pair_ in enumerate(dep.referenced_channels): - _, dg_nr = pair_ - grp = self.groups[dg_nr] - dep['ch_{}'.format(i)] = grp['temp_channels'][i] - dep['cg_{}'.format(i)] = grp['channel_group'].address - dep['dg_{}'.format(i)] = grp['data_group'].address - seek(dep.address, v2c.SEEK_START) - write(bytes(dep)) - - seek(v2c.ID_BLOCK_SIZE, v2c.SEEK_START) - write(bytes(self.header)) - - for gp in self.groups: - del gp['temp_channels'] - - if dst == self.name: - self.close() - os.remove(self.name) - os.rename(destination, self.name) - - self.groups = [] - self.header = None - self.identification = None - self.file_history = [] - self.channels_db = {} - self.masters_db = {} - self.attachments = [] - self.file_comment = None - - self._ch_map = {} - self._master_channel_cache = {} - - self._tempfile = TemporaryFile() - self._file = open(self.name, 'rb') - self._read() - - -if __name__ == '__main__': - pass diff --git a/asammdf/mdf3.py b/asammdf/mdf_v2_v3.py similarity index 92% rename from asammdf/mdf3.py rename to asammdf/mdf_v2_v3.py index c0d398cb5..60fadc0f4 100644 --- a/asammdf/mdf3.py +++ b/asammdf/mdf_v2_v3.py @@ -51,8 +51,8 @@ ) from .signal import Signal from .version import __version__ -from . import v3constants as v3c -from .v3blocks import ( +from . import v2_v3_constants as v23c +from .v2_v3_blocks import ( Channel, ChannelConversion, ChannelDependency, @@ -75,10 +75,10 @@ from .utils import bytes -__all__ = ['MDF3', ] +__all__ = ['MDF23', ] -class MDF3(object): +class MDF23(object): """If the *name* exist it will be loaded otherwise an empty file will be created that can be later saved to disk @@ -107,8 +107,8 @@ class MDF3(object): mdf file header file_history : TextBlock file history text block; can be None - memory : bool - load measured data option + memory : str + memory optimization option version : str mdf version channels_db : dict @@ -123,7 +123,7 @@ class MDF3(object): _compact_integers_on_append = False _overwrite = False - def __init__(self, name=None, memory=2, version='3.30'): + def __init__(self, name=None, memory='full', version='3.30'): self.groups = [] self.header = None self.identification = None @@ -158,7 +158,7 @@ def _load_group_data(self, group): # for now appended groups keep the measured data in the memory. # the plan is to use a temp file for appended groups, to keep the # memory usage low. - if group['data_location'] == v3c.LOCATION_ORIGINAL_FILE: + if group['data_location'] == v23c.LOCATION_ORIGINAL_FILE: # this is a group from the source file # so fetch the measured data from it stream = self._file @@ -193,23 +193,23 @@ def _load_group_data(self, group): size = len(data) while i < size: rec_id = data[i] - # skip redord id + # skip record id i += 1 rec_size = cg_size[rec_id] if rec_id == record_id: rec_data = data[i: i+rec_size] cg_data.append(rec_data) - # concider the second record ID if it exists + # consider the second record ID if it exists if record_id_nr == 2: i += rec_size + 1 else: i += rec_size data = b''.join(cg_data) - elif group['data_location'] == v3c.LOCATION_TEMPORARY_FILE: + elif group['data_location'] == v23c.LOCATION_TEMPORARY_FILE: read_size = group['size'] dat_addr = group['data_group']['data_block_addr'] if dat_addr: - self._tempfile.seek(dat_addr, v3c.SEEK_START) + self._tempfile.seek(dat_addr, v23c.SEEK_START) data = self._tempfile.read(read_size) else: data = b'' @@ -304,7 +304,7 @@ def _prepare_record(self, group): # adjust size to 1, 2, 4 or 8 bytes for nonstandard integers size = bit_offset + bit_count - if data_type == v3c.DATA_TYPE_STRING: + if data_type == v23c.DATA_TYPE_STRING: next_byte_aligned_position = parent_start_offset + size size = size // 8 if next_byte_aligned_position <= record_size: @@ -312,7 +312,7 @@ def _prepare_record(self, group): types.append(dtype_pair) parents[original_index] = name, bit_offset - elif data_type == v3c.DATA_TYPE_BYTEARRAY: + elif data_type == v23c.DATA_TYPE_BYTEARRAY: size = size // 8 next_byte_aligned_position = parent_start_offset + size if next_byte_aligned_position <= record_size: @@ -363,10 +363,10 @@ def _prepare_record(self, group): def _get_not_byte_aligned_data(self, data, group, ch_nr): big_endian_types = ( - v3c.DATA_TYPE_UNSIGNED_MOTOROLA, - v3c.DATA_TYPE_FLOAT_MOTOROLA, - v3c.DATA_TYPE_DOUBLE_MOTOROLA, - v3c.DATA_TYPE_SIGNED_MOTOROLA, + v23c.DATA_TYPE_UNSIGNED_MOTOROLA, + v23c.DATA_TYPE_FLOAT_MOTOROLA, + v23c.DATA_TYPE_DOUBLE_MOTOROLA, + v23c.DATA_TYPE_SIGNED_MOTOROLA, ) record_size = group['channel_group']['samples_byte_nr'] @@ -563,7 +563,7 @@ def _read(self): seek = stream.seek dg_cntr = 0 - seek(0, v3c.SEEK_START) + seek(0, v23c.SEEK_START) self.identification = FileIdentificationBlock( stream=stream, @@ -580,7 +580,7 @@ def _read(self): ) # this will hold mapping from channel address to Channel object - # needed for linking dependecy blocks to refernced channels after + # needed for linking dependency blocks to referenced channels after # the file is loaded ch_map = {} @@ -597,8 +597,10 @@ def _read(self): # read trigger information if available trigger_addr = gp['trigger_addr'] if trigger_addr: - trigger = TriggerBlock(address=trigger_addr, - stream=stream) + trigger = TriggerBlock( + address=trigger_addr, + stream=stream, + ) if trigger['text_addr']: trigger_text = TextBlock( address=trigger['text_addr'], @@ -634,10 +636,10 @@ def _read(self): kargs = {'first_cg_addr': cg_addr, 'data_block_addr': data_addr} - if self.version in ('3.20', '3.30'): - kargs['block_len'] = v3c.DG32_BLOCK_SIZE + if self.version >= '3.20': + kargs['block_len'] = v23c.DG_POST_320_BLOCK_SIZE else: - kargs['block_len'] = v3c.DG31_BLOCK_SIZE + kargs['block_len'] = v23c.DG_PRE_320_BLOCK_SIZE grp['data_group'] = DataGroup(**kargs) @@ -712,7 +714,7 @@ def _read(self): conv_type = new_conv['conversion_type'] else: conv_type = 0 - if conv_type == v3c.CONVERSION_TYPE_VTABR: + if conv_type == v23c.CONVERSION_TYPE_VTABR: for idx in range(new_conv['ref_param_nr']): address = new_conv['text_{}'.format(idx)] if address: @@ -749,7 +751,7 @@ def _read(self): 'long_name_addr', 'comment_addr', 'display_name_addr'): - address = new_ch[key] + address = new_ch.get(key, 0) if address: if memory != 'minimum': ch_texts[key] = TextBlock( @@ -765,7 +767,7 @@ def _read(self): grp_ch_texts.append(None) # update channel object name and block_size attributes - if new_ch['long_name_addr']: + if new_ch.get('long_name_addr', 0): if memory != 'minimum': name = ch_texts['long_name_addr']['text'] else: @@ -786,7 +788,7 @@ def _read(self): self.channels_db[name] = [] self.channels_db[name].append((dg_cntr, ch_cntr)) - if new_ch['channel_type'] == v3c.CHANNEL_TYPE_MASTER: + if new_ch['channel_type'] == v23c.CHANNEL_TYPE_MASTER: self.masters_db[dg_cntr] = ch_cntr # go to next channel of the current channel group @@ -825,13 +827,13 @@ def _read(self): # read data block of the current data group dat_addr = gp['data_block_addr'] if dat_addr: - seek(dat_addr, v3c.SEEK_START) + seek(dat_addr, v23c.SEEK_START) data = read(total_size) else: data = b'' if record_id_nr == 0: grp = new_groups[0] - grp['data_location'] = v3c.LOCATION_MEMORY + grp['data_location'] = v23c.LOCATION_MEMORY grp['data_block'] = DataBlock(data=data) else: @@ -852,14 +854,14 @@ def _read(self): else: i += rec_size for grp in new_groups: - grp['data_location'] = v3c.LOCATION_MEMORY + grp['data_location'] = v23c.LOCATION_MEMORY data = cg_data[grp['channel_group']['record_id']] data = b''.join(data) grp['channel_group']['record_id'] = 1 grp['data_block'] = DataBlock(data=data) else: for grp in new_groups: - grp['data_location'] = v3c.LOCATION_ORIGINAL_FILE + grp['data_location'] = v23c.LOCATION_ORIGINAL_FILE self.groups.extend(new_groups) @@ -1068,7 +1070,7 @@ def append(self, # conversion for time channel kargs = { - 'conversion_type': v3c.CONVERSION_TYPE_NONE, + 'conversion_type': v23c.CONVERSION_TYPE_NONE, 'unit': b's', 'min_phy_value': t[0] if cycles_nr else 0, 'max_phy_value': t[-1] if cycles_nr else 0, @@ -1085,7 +1087,7 @@ def append(self, kargs = { 'module_nr': 0, 'module_address': 0, - 'type': v3c.SOURCE_ECU, + 'type': v23c.SOURCE_ECU, 'description': b'Channel inserted by Python Script', } block = ChannelExtension(**kargs) @@ -1100,13 +1102,19 @@ def append(self, t_type, t_size = fmt_to_datatype(t.dtype) kargs = { 'short_name': b't', - 'channel_type': v3c.CHANNEL_TYPE_MASTER, + 'channel_type': v23c.CHANNEL_TYPE_MASTER, 'data_type': t_type, 'start_offset': 0, 'min_raw_value': t[0] if cycles_nr else 0, 'max_raw_value': t[-1] if cycles_nr else 0, 'bit_count': t_size, } + if self.version >= '3.00': + kargs['block_len'] = v23c.CN_DISPLAYNAME_BLOCK_SIZE + elif self.version >= '2.10': + kargs['block_len'] = v23c.CN_LONGNAME_BLOCK_SIZE + else: + kargs['block_len'] = v23c.CN_SHORT_BLOCK_SIZE channel = Channel(**kargs) channel.name = name = 't' if memory != 'minimum': @@ -1209,7 +1217,7 @@ def append(self, item.append(None) texts = {} - if len(name) >= 32: + if len(name) >= 32 and self.version >= '2.10': block = TextBlock(text=name) if memory != 'minimum': texts['long_name_addr'] = block @@ -1224,7 +1232,7 @@ def append(self, info = signal.info if info and 'raw' in info and not info['raw'].dtype.kind == 'S': kargs = {} - kargs['conversion_type'] = v3c.CONVERSION_TYPE_VTAB + kargs['conversion_type'] = v23c.CONVERSION_TYPE_VTAB raw = info['raw'] phys = info['phys'] for i, (r_, p_) in enumerate(zip(raw, phys)): @@ -1234,7 +1242,7 @@ def append(self, kargs['unit'] = signal.unit.encode('latin-1') elif info and 'lower' in info: kargs = {} - kargs['conversion_type'] = v3c.CONVERSION_TYPE_VTABR + kargs['conversion_type'] = v23c.CONVERSION_TYPE_VTABR lower = info['lower'] upper = info['upper'] texts = info['phys'] @@ -1264,7 +1272,7 @@ def append(self, min_phy_value = 0 max_phy_value = 0 kargs = { - 'conversion_type': v3c.CONVERSION_TYPE_NONE, + 'conversion_type': v23c.CONVERSION_TYPE_NONE, 'unit': signal.unit.encode('latin-1'), 'min_phy_value': min_phy_value, 'max_phy_value': max_phy_value, @@ -1285,7 +1293,7 @@ def append(self, kargs = { 'module_nr': 0, 'module_address': 0, - 'type': v3c.SOURCE_ECU, + 'type': v23c.SOURCE_ECU, 'description': b'Channel inserted by Python Script', } block = ChannelExtension(**kargs) @@ -1298,9 +1306,9 @@ def append(self, # compute additional byte offset for large records size current_offset = offset + bit_offset - if current_offset > v3c.MAX_UINT16: + if current_offset > v23c.MAX_UINT16: additional_byte_offset = \ - (current_offset - v3c.MAX_UINT16) >> 3 + (current_offset - v23c.MAX_UINT16) >> 3 start_bit_offset = \ current_offset - additional_byte_offset << 3 else: @@ -1308,12 +1316,12 @@ def append(self, additional_byte_offset = 0 if signal.samples.dtype.kind == 'u': - data_type = v3c.DATA_TYPE_UNSIGNED_INTEL + data_type = v23c.DATA_TYPE_UNSIGNED_INTEL else: - data_type = v3c.DATA_TYPE_SIGNED_INTEL + data_type = v23c.DATA_TYPE_SIGNED_INTEL texts = {} - if len(name) >= 32: + if len(name) >= 32 and self.version >= '2.10': short_name = (name[:31] + '\0').encode('latin-1') if memory != 'minimum': texts['long_name_addr'] = TextBlock(texts=name) @@ -1331,7 +1339,7 @@ def append(self, kargs = { 'short_name': short_name, - 'channel_type': v3c.CHANNEL_TYPE_VALUE, + 'channel_type': v23c.CHANNEL_TYPE_VALUE, 'data_type': data_type, 'min_raw_value': min_val if min_val <= max_val else 0, 'max_raw_value': max_val if min_val <= max_val else 0, @@ -1339,6 +1347,12 @@ def append(self, 'bit_count': bit_count, 'aditional_byte_offset': additional_byte_offset, } + if self.version >= '3.00': + kargs['block_len'] = v23c.CN_DISPLAYNAME_BLOCK_SIZE + elif self.version >= '2.10': + kargs['block_len'] = v23c.CN_LONGNAME_BLOCK_SIZE + else: + kargs['block_len'] = v23c.CN_SHORT_BLOCK_SIZE comment = signal.comment if comment: comment = comment.encode('latin-1') @@ -1381,7 +1395,7 @@ def append(self, item.append(None) texts = {} - if len(name) >= 32: + if len(name) >= 32 and self.version >= '2.10': block = TextBlock(text=name) if memory != 'minimum': texts['long_name_addr'] = block @@ -1399,7 +1413,7 @@ def append(self, info = signal.info if info and 'raw' in info and not info['raw'].dtype.kind == 'S': kargs = {} - kargs['conversion_type'] = v3c.CONVERSION_TYPE_VTAB + kargs['conversion_type'] = v23c.CONVERSION_TYPE_VTAB raw = info['raw'] phys = info['phys'] for i, (r_, p_) in enumerate(zip(raw, phys)): @@ -1409,7 +1423,7 @@ def append(self, kargs['unit'] = signal.unit.encode('latin-1') elif info and 'lower' in info: kargs = {} - kargs['conversion_type'] = v3c.CONVERSION_TYPE_VTABR + kargs['conversion_type'] = v23c.CONVERSION_TYPE_VTABR lower = info['lower'] upper = info['upper'] texts_ = info['phys'] @@ -1438,7 +1452,7 @@ def append(self, min_phy_value = 0 max_phy_value = 0 kargs = { - 'conversion_type': v3c.CONVERSION_TYPE_NONE, + 'conversion_type': v23c.CONVERSION_TYPE_NONE, 'unit': signal.unit.encode('latin-1'), 'min_phy_value': min_phy_value, 'max_phy_value': max_phy_value, @@ -1459,7 +1473,7 @@ def append(self, kargs = { 'module_nr': 0, 'module_address': 0, - 'type': v3c.SOURCE_ECU, + 'type': v23c.SOURCE_ECU, 'description': b'Channel inserted by Python Script', } block = ChannelExtension(**kargs) @@ -1471,8 +1485,8 @@ def append(self, write(bytes(block)) # compute additional byte offset for large records size - if offset > v3c.MAX_UINT16: - additional_byte_offset = (offset - v3c.MAX_UINT16) >> 3 + if offset > v23c.MAX_UINT16: + additional_byte_offset = (offset - v23c.MAX_UINT16) >> 3 start_bit_offset = offset - additional_byte_offset << 3 else: start_bit_offset = offset @@ -1485,7 +1499,7 @@ def append(self, short_name = name.encode('latin-1') kargs = { 'short_name': short_name, - 'channel_type': v3c.CHANNEL_TYPE_VALUE, + 'channel_type': v23c.CHANNEL_TYPE_VALUE, 'data_type': s_type, 'min_raw_value': min_val if min_val <= max_val else 0, 'max_raw_value': max_val if min_val <= max_val else 0, @@ -1493,6 +1507,12 @@ def append(self, 'bit_count': s_size, 'aditional_byte_offset': additional_byte_offset, } + if self.version >= '3.00': + kargs['block_len'] = v23c.CN_DISPLAYNAME_BLOCK_SIZE + elif self.version >= '2.10': + kargs['block_len'] = v23c.CN_LONGNAME_BLOCK_SIZE + else: + kargs['block_len'] = v23c.CN_SHORT_BLOCK_SIZE comment = signal.comment if comment: if len(comment) >= 128: @@ -1571,7 +1591,7 @@ def append(self, item.append(None) texts = {} - if len(name) >= 32: + if len(name) >= 32 and self.version >= '2.10': block = TextBlock(text=name) if memory != 'minimum': texts['long_name_addr'] = block @@ -1592,7 +1612,7 @@ def append(self, kargs = { 'module_nr': 0, 'module_address': 0, - 'type': v3c.SOURCE_ECU, + 'type': v23c.SOURCE_ECU, 'description': b'Channel inserted by Python Script', } block = ChannelExtension(**kargs) @@ -1607,8 +1627,8 @@ def append(self, s_type, s_size = fmt_to_datatype(samples.dtype) # compute additional byte offset for large records size - if offset > v3c.MAX_UINT16: - additional_byte_offset = (offset - v3c.MAX_UINT16) >> 3 + if offset > v23c.MAX_UINT16: + additional_byte_offset = (offset - v23c.MAX_UINT16) >> 3 start_bit_offset = offset - additional_byte_offset << 3 else: start_bit_offset = offset @@ -1620,7 +1640,7 @@ def append(self, short_name = name.encode('latin-1') kargs = { 'short_name': short_name, - 'channel_type': v3c.CHANNEL_TYPE_VALUE, + 'channel_type': v23c.CHANNEL_TYPE_VALUE, 'data_type': s_type, 'min_raw_value': min_val if min_val <= max_val else 0, 'max_raw_value': max_val if min_val <= max_val else 0, @@ -1628,6 +1648,12 @@ def append(self, 'bit_count': s_size, 'aditional_byte_offset': additional_byte_offset, } + if self.version >= '3.00': + kargs['block_len'] = v23c.CN_DISPLAYNAME_BLOCK_SIZE + elif self.version >= '2.10': + kargs['block_len'] = v23c.CN_LONGNAME_BLOCK_SIZE + else: + kargs['block_len'] = v23c.CN_SHORT_BLOCK_SIZE comment = signal.comment if comment: if len(comment) >= 128: @@ -1658,7 +1684,7 @@ def append(self, item.append(None) texts = {} - if len(name) >= 32: + if len(name) >= 32 and self.version >= '2.10': block = TextBlock(text=name) if memory != 'minimum': texts['long_name_addr'] = block @@ -1676,7 +1702,7 @@ def append(self, kargs = { 'module_nr': 0, 'module_address': 0, - 'type': v3c.SOURCE_ECU, + 'type': v23c.SOURCE_ECU, 'description': b'Channel inserted by Python Script', } block = ChannelExtension(**kargs) @@ -1693,8 +1719,8 @@ def append(self, gp_conv.append(0) # compute additional byte offset for large records size - if offset > v3c.MAX_UINT16: - additional_byte_offset = (offset - v3c.MAX_UINT16) >> 3 + if offset > v23c.MAX_UINT16: + additional_byte_offset = (offset - v23c.MAX_UINT16) >> 3 start_bit_offset = offset - additional_byte_offset << 3 else: start_bit_offset = offset @@ -1706,7 +1732,7 @@ def append(self, short_name = name.encode('latin-1') kargs = { 'short_name': short_name, - 'channel_type': v3c.CHANNEL_TYPE_VALUE, + 'channel_type': v23c.CHANNEL_TYPE_VALUE, 'data_type': s_type, 'min_raw_value': min_val if min_val <= max_val else 0, 'max_raw_value': max_val if min_val <= max_val else 0, @@ -1714,6 +1740,12 @@ def append(self, 'bit_count': s_size, 'aditional_byte_offset': additional_byte_offset, } + if self.version >= '3.00': + kargs['block_len'] = v23c.CN_DISPLAYNAME_BLOCK_SIZE + elif self.version >= '2.10': + kargs['block_len'] = v23c.CN_LONGNAME_BLOCK_SIZE + else: + kargs['block_len'] = v23c.CN_SHORT_BLOCK_SIZE channel = Channel(**kargs) channel.name = name @@ -1762,10 +1794,10 @@ def append(self, gp['size'] = cycles_nr * (offset >> 3) # data group - if self.version in ('3.20', '3.30'): - block_len = v3c.DG32_BLOCK_SIZE + if self.version >= '3.20': + block_len = v23c.DG_POST_320_BLOCK_SIZE else: - block_len = v3c.DG31_BLOCK_SIZE + block_len = v23c.DG_PRE_320_BLOCK_SIZE gp['data_group'] = DataGroup(block_len=block_len) # data block @@ -1781,11 +1813,11 @@ def append(self, block = samples.tostring() if memory == 'full': - gp['data_location'] = v3c.LOCATION_MEMORY + gp['data_location'] = v23c.LOCATION_MEMORY kargs = {'data': block} gp['data_block'] = DataBlock(**kargs) else: - gp['data_location'] = v3c.LOCATION_TEMPORARY_FILE + gp['data_location'] = v23c.LOCATION_TEMPORARY_FILE if cycles_nr: data_address = tell() gp['data_group']['data_block_addr'] = data_address @@ -1826,7 +1858,7 @@ def append(self, # conversion for time channel kargs = { - 'conversion_type': v3c.CONVERSION_TYPE_NONE, + 'conversion_type': v23c.CONVERSION_TYPE_NONE, 'unit': b's', 'min_phy_value': t[0] if cycles_nr else 0, 'max_phy_value': t[-1] if cycles_nr else 0, @@ -1843,7 +1875,7 @@ def append(self, kargs = { 'module_nr': 0, 'module_address': 0, - 'type': v3c.SOURCE_ECU, + 'type': v23c.SOURCE_ECU, 'description': b'Channel inserted by Python Script', } block = ChannelExtension(**kargs) @@ -1858,13 +1890,19 @@ def append(self, t_type, t_size = fmt_to_datatype(t.dtype) kargs = { 'short_name': b't', - 'channel_type': v3c.CHANNEL_TYPE_MASTER, + 'channel_type': v23c.CHANNEL_TYPE_MASTER, 'data_type': t_type, 'start_offset': 0, 'min_raw_value': t[0] if cycles_nr else 0, 'max_raw_value': t[-1] if cycles_nr else 0, 'bit_count': t_size, } + if self.version >= '3.00': + kargs['block_len'] = v23c.CN_DISPLAYNAME_BLOCK_SIZE + elif self.version >= '2.10': + kargs['block_len'] = v23c.CN_LONGNAME_BLOCK_SIZE + else: + kargs['block_len'] = v23c.CN_SHORT_BLOCK_SIZE channel = Channel(**kargs) channel.name = name = 't' if memory != 'minimum': @@ -1935,7 +1973,7 @@ def append(self, item.append(None) texts = {} - if len(name) >= 32: + if len(name) >= 32 and self.version >= '2.10': block = TextBlock(text=name) texts['long_name_addr'] = block if texts: @@ -1945,7 +1983,7 @@ def append(self, min_val, max_val = get_min_max(samples) kargs = { - 'conversion_type': v3c.CONVERSION_TYPE_NONE, + 'conversion_type': v23c.CONVERSION_TYPE_NONE, 'unit': signal.unit.encode('latin-1'), 'min_phy_value': min_val if min_val <= max_val else 0, 'max_phy_value': max_val if min_val <= max_val else 0, @@ -1962,7 +2000,7 @@ def append(self, kargs = { 'module_nr': 0, 'module_address': 0, - 'type': v3c.SOURCE_ECU, + 'type': v23c.SOURCE_ECU, 'description': b'Channel inserted by Python Script', } block = ChannelExtension(**kargs) @@ -1974,8 +2012,8 @@ def append(self, write(bytes(block)) # compute additional byte offset for large records size - if offset > v3c.MAX_UINT16: - additional_byte_offset = (offset - v3c.MAX_UINT16) >> 3 + if offset > v23c.MAX_UINT16: + additional_byte_offset = (offset - v23c.MAX_UINT16) >> 3 start_bit_offset = offset - additional_byte_offset << 3 else: start_bit_offset = offset @@ -1987,7 +2025,7 @@ def append(self, short_name = name.encode('latin-1') kargs = { 'short_name': short_name, - 'channel_type': v3c.CHANNEL_TYPE_VALUE, + 'channel_type': v23c.CHANNEL_TYPE_VALUE, 'data_type': s_type, 'min_raw_value': min_val if min_val <= max_val else 0, 'max_raw_value': max_val if min_val <= max_val else 0, @@ -1995,6 +2033,12 @@ def append(self, 'bit_count': s_size, 'aditional_byte_offset': additional_byte_offset, } + if self.version >= '3.00': + kargs['block_len'] = v23c.CN_DISPLAYNAME_BLOCK_SIZE + elif self.version >= '2.10': + kargs['block_len'] = v23c.CN_LONGNAME_BLOCK_SIZE + else: + kargs['block_len'] = v23c.CN_SHORT_BLOCK_SIZE channel = Channel(**kargs) channel.name = name @@ -2033,10 +2077,10 @@ def append(self, gp['size'] = cycles_nr * (offset >> 3) # data group - if self.version in ('3.20', '3.30'): - block_len = v3c.DG32_BLOCK_SIZE + if self.version >= '3.20': + block_len = v23c.DG_POST_320_BLOCK_SIZE else: - block_len = v3c.DG31_BLOCK_SIZE + block_len = v23c.DG_PRE_320_BLOCK_SIZE gp['data_group'] = DataGroup(block_len=block_len) # data block @@ -2053,11 +2097,11 @@ def append(self, block = samples.tostring() if memory == 'full': - gp['data_location'] = v3c.LOCATION_MEMORY + gp['data_location'] = v23c.LOCATION_MEMORY kargs = {'data': block} gp['data_block'] = DataBlock(**kargs) else: - gp['data_location'] = v3c.LOCATION_TEMPORARY_FILE + gp['data_location'] = v23c.LOCATION_TEMPORARY_FILE if cycles_nr: data_address = tell() gp['data_group']['data_block_addr'] = data_address @@ -2068,7 +2112,7 @@ def append(self, if memory == 'full': raise else: - gp['data_location'] = v3c.LOCATION_TEMPORARY_FILE + gp['data_location'] = v23c.LOCATION_TEMPORARY_FILE data_address = tell() gp['data_group']['data_block_addr'] = data_address @@ -2132,7 +2176,7 @@ def get_channel_unit(self, name=None, group=None, index=None): ) grp = self.groups[gp_nr] - if grp['data_location'] == v3c.LOCATION_ORIGINAL_FILE: + if grp['data_location'] == v23c.LOCATION_ORIGINAL_FILE: stream = self._file else: stream = self._tempfile @@ -2199,7 +2243,7 @@ def get_channel_comment(self, name=None, group=None, index=None): ) grp = self.groups[gp_nr] - if grp['data_location'] == v3c.LOCATION_ORIGINAL_FILE: + if grp['data_location'] == v23c.LOCATION_ORIGINAL_FILE: stream = self._file else: stream = self._tempfile @@ -2293,7 +2337,7 @@ def get(self, memory = self.memory grp = self.groups[gp_nr] - if grp['data_location'] == v3c.LOCATION_ORIGINAL_FILE: + if grp['data_location'] == v23c.LOCATION_ORIGINAL_FILE: stream = self._file else: stream = self._tempfile @@ -2319,7 +2363,7 @@ def get(self, else: conversion = None if name is None: - if channel['long_name_addr']: + if channel.get('long_name_addr', 0): name = TextBlock( address=channel['long_name_addr'], stream=stream, @@ -2342,9 +2386,9 @@ def get(self, # check if this is a channel array if dep: - if dep['dependency_type'] == v3c.DEPENDENCY_TYPE_VECTOR: + if dep['dependency_type'] == v23c.DEPENDENCY_TYPE_VECTOR: shape = [dep['sd_nr'], ] - elif dep['dependency_type'] >= v3c.DEPENDENCY_TYPE_NDIM: + elif dep['dependency_type'] >= v23c.DEPENDENCY_TYPE_NDIM: shape = [] i = 0 while True: @@ -2423,7 +2467,7 @@ def get(self, vals &= mask else: vals = vals & mask - if data_type in v3c.SIGNED_INT: + if data_type in v23c.SIGNED_INT: size = vals.dtype.itemsize mask = (1 << (size * 8)) - 1 mask = (mask << bits) & mask @@ -2433,7 +2477,7 @@ def get(self, vals = self._get_not_byte_aligned_data(data, grp, ch_nr) if conversion is None: - conversion_type = v3c.CONVERSION_TYPE_NONE + conversion_type = v23c.CONVERSION_TYPE_NONE else: conversion_type = conversion['conversion_type'] @@ -2442,9 +2486,9 @@ def get(self, if raw: pass - elif conversion_type == v3c.CONVERSION_TYPE_NONE: + elif conversion_type == v23c.CONVERSION_TYPE_NONE: - if channel['data_type'] == v3c.DATA_TYPE_STRING: + if channel['data_type'] == v23c.DATA_TYPE_STRING: vals = [val.tobytes() for val in vals] vals = [ x.decode('latin-1').strip(' \n\t\0') @@ -2453,7 +2497,7 @@ def get(self, vals = array(vals) vals = encode(vals, 'latin-1') - elif channel['data_type'] == v3c.DATA_TYPE_BYTEARRAY: + elif channel['data_type'] == v23c.DATA_TYPE_BYTEARRAY: arrays = [vals, ] types = [(channel.name, vals.dtype, vals.shape[1:]), ] if PYVERSION == 2: @@ -2461,7 +2505,7 @@ def get(self, types = dtype(types) vals = fromarrays(arrays, dtype=types) - elif conversion_type == v3c.CONVERSION_TYPE_LINEAR: + elif conversion_type == v23c.CONVERSION_TYPE_LINEAR: a = conversion['a'] b = conversion['b'] if (a, b) != (1, 0): @@ -2469,22 +2513,22 @@ def get(self, if b: vals += b - elif conversion_type in (v3c.CONVERSION_TYPE_TABI, - v3c.CONVERSION_TYPE_TABX): + elif conversion_type in (v23c.CONVERSION_TYPE_TABI, + v23c.CONVERSION_TYPE_TABX): nr = conversion['ref_param_nr'] raw_vals = [conversion['raw_{}'.format(i)] for i in range(nr)] raw_vals = array(raw_vals) phys = [conversion['phys_{}'.format(i)] for i in range(nr)] phys = array(phys) - if conversion_type == v3c.CONVERSION_TYPE_TABI: + if conversion_type == v23c.CONVERSION_TYPE_TABI: vals = interp(vals, raw_vals, phys) else: idx = searchsorted(raw, vals) idx = clip(idx, 0, len(raw) - 1) vals = phys[idx] - elif conversion_type == v3c.CONVERSION_TYPE_VTAB: + elif conversion_type == v23c.CONVERSION_TYPE_VTAB: nr = conversion['ref_param_nr'] raw_vals = [ conversion['param_val_{}'.format(i)] @@ -2495,7 +2539,7 @@ def get(self, phys = array(phys) info = {'raw': raw_vals, 'phys': phys} - elif conversion_type == v3c.CONVERSION_TYPE_VTABR: + elif conversion_type == v23c.CONVERSION_TYPE_VTABR: nr = conversion['ref_param_nr'] conv_texts = grp['texts']['conversion_tab'][ch_nr] @@ -2521,9 +2565,9 @@ def get(self, upper = array(upper) info = {'lower': lower, 'upper': upper, 'phys': texts} - elif conversion_type in (v3c.CONVERSION_TYPE_EXPO, - v3c.CONVERSION_TYPE_LOGH): - if conversion_type == v3c.CONVERSION_TYPE_EXPO: + elif conversion_type in (v23c.CONVERSION_TYPE_EXPO, + v23c.CONVERSION_TYPE_LOGH): + if conversion_type == v23c.CONVERSION_TYPE_EXPO: func = log else: func = exp @@ -2542,7 +2586,7 @@ def get(self, message = 'wrong conversion {}'.format(conversion_type) raise ValueError(message) - elif conversion_type == v3c.CONVERSION_TYPE_RAT: + elif conversion_type == v23c.CONVERSION_TYPE_RAT: P1 = conversion['P1'] P2 = conversion['P2'] P3 = conversion['P3'] @@ -2551,9 +2595,9 @@ def get(self, P6 = conversion['P6'] if (P1, P2, P3, P4, P5, P6) != (0, 1, 0, 0, 0, 1): X = vals - vals = evaluate(v3c.RAT_CONV_TEXT) + vals = evaluate(v23c.RAT_CONV_TEXT) - elif conversion_type == v3c.CONVERSION_TYPE_POLY: + elif conversion_type == v23c.CONVERSION_TYPE_POLY: P1 = conversion['P1'] P2 = conversion['P2'] P3 = conversion['P3'] @@ -2566,11 +2610,11 @@ def get(self, coefs = (P2, P3, P5, P6) if coefs == (0, 0, 0, 0): if P1 != P4: - vals = evaluate(v3c.POLY_CONV_SHORT_TEXT) + vals = evaluate(v23c.POLY_CONV_SHORT_TEXT) else: - vals = evaluate(v3c.POLY_CONV_LONG_TEXT) + vals = evaluate(v23c.POLY_CONV_LONG_TEXT) - elif conversion_type == v3c.CONVERSION_TYPE_FORMULA: + elif conversion_type == v23c.CONVERSION_TYPE_FORMULA: formula = conversion['formula'].decode('latin-1') formula = formula.strip(' \n\t\0') X1 = vals @@ -2623,7 +2667,7 @@ def get_master(self, index, data=None): return self._master_channel_cache[index] group = self.groups[index] - if group['data_location'] == v3c.LOCATION_ORIGINAL_FILE: + if group['data_location'] == v23c.LOCATION_ORIGINAL_FILE: stream = self._file else: stream = self._tempfile @@ -2691,10 +2735,10 @@ def get_master(self, index, data=None): # get timestamps if time_conv is None: - time_conv_type = v3c.CONVERSION_TYPE_NONE + time_conv_type = v23c.CONVERSION_TYPE_NONE else: time_conv_type = time_conv['conversion_type'] - if time_conv_type == v3c.CONVERSION_TYPE_LINEAR: + if time_conv_type == v23c.CONVERSION_TYPE_LINEAR: time_a = time_conv['a'] time_b = time_conv['b'] t = t * time_a @@ -2759,9 +2803,9 @@ def info(self): info['version'] = self.version info['groups'] = len(self.groups) for i, gp in enumerate(self.groups): - if gp['data_location'] == v3c.LOCATION_ORIGINAL_FILE: + if gp['data_location'] == v23c.LOCATION_ORIGINAL_FILE: stream = self._file - elif gp['data_location'] == v3c.LOCATION_TEMPORARY_FILE: + elif gp['data_location'] == v23c.LOCATION_TEMPORARY_FILE: stream = self._tempfile inf = {} info['group {}'.format(i)] = inf @@ -2775,7 +2819,7 @@ def info(self): address=channel, stream=stream, ) - if channel['long_name_addr']: + if channel.get('long_name_addr', 0): name = TextBlock( address=channel['long_name_addr'], stream=stream, @@ -2786,7 +2830,7 @@ def info(self): name = name.decode('utf-8').strip(' \r\t\n\0') name = name.split('\\')[0] - if channel['channel_type'] == v3c.CHANNEL_TYPE_MASTER: + if channel['channel_type'] == v23c.CHANNEL_TYPE_MASTER: ch_type = 'master' else: ch_type = 'value' @@ -2797,8 +2841,8 @@ def info(self): def save(self, dst='', overwrite=None, compression=0): """Save MDF to *dst*. If *dst* is not provided the the destination file name is the MDF name. If overwrite is *True* then the destination file - is overwritten, otherwise the file name is appened with '_', were - '' is the first conter that produces a new file name (that does + is overwritten, otherwise the file name is appended with '_', were + '' is the first counter that produces a new file name (that does not already exist in the filesystem). Parameters @@ -2931,7 +2975,7 @@ def _save_with_metadata(self, dst, overwrite, compression): address = 0 blocks.append(self.identification) - address += v3c.ID_BLOCK_SIZE + address += v23c.ID_BLOCK_SIZE blocks.append(self.header) address += self.header['block_len'] @@ -2982,7 +3026,7 @@ def _save_with_metadata(self, dst, overwrite, compression): continue conv.address = address - if conv['conversion_type'] == v3c.CONVERSION_TYPE_VTABR: + if conv['conversion_type'] == v23c.CONVERSION_TYPE_VTABR: pairs = gp_texts['conversion_tab'][i].items() for key, item in pairs: conv[key] = item.address @@ -3013,7 +3057,7 @@ def _save_with_metadata(self, dst, overwrite, compression): channel_texts = ch_texts[i] blocks.append(channel) - address += v3c.CN_BLOCK_SIZE + address += channel['block_len'] if channel_texts: for key in ('long_name_addr', @@ -3021,8 +3065,6 @@ def _save_with_metadata(self, dst, overwrite, compression): 'display_name_addr'): if key in channel_texts: channel[key] = channel_texts[key].address - else: - channel[key] = 0 channel['conversion_addr'] = cc[i].address if cc[i] else 0 if cs[i]: @@ -3232,7 +3274,7 @@ def _save_without_metadata(self, dst, overwrite, compression): for gp in self.groups: gp_texts = deepcopy(gp['texts']) - if gp['data_location'] == v3c.LOCATION_ORIGINAL_FILE: + if gp['data_location'] == v23c.LOCATION_ORIGINAL_FILE: stream = self._file else: stream = self._tempfile @@ -3271,7 +3313,7 @@ def _save_without_metadata(self, dst, overwrite, compression): address=conv, stream=stream, ) - if conv['conversion_type'] == v3c.CONVERSION_TYPE_VTABR: + if conv['conversion_type'] == v23c.CONVERSION_TYPE_VTABR: pairs = gp_texts['conversion_tab'][i].items() for key, item in pairs: conv[key] = item @@ -3328,13 +3370,6 @@ def _save_without_metadata(self, dst, overwrite, compression): 'display_name_addr'): if key in channel_texts: channel[key] = channel_texts[key] - else: - channel[key] = 0 - else: - for key in ('long_name_addr', - 'comment_addr', - 'display_name_addr'): - channel[key] = 0 channel['conversion_addr'] = cc[i] channel['source_depend_addr'] = cs[i] @@ -3435,10 +3470,10 @@ def _save_without_metadata(self, dst, overwrite, compression): dep['ch_{}'.format(i)] = grp['temp_channels'][i] dep['cg_{}'.format(i)] = grp['channel_group'].address dep['dg_{}'.format(i)] = grp['data_group'].address - seek(dep.address, v3c.SEEK_START) + seek(dep.address, v23c.SEEK_START) write(bytes(dep)) - seek(v3c.ID_BLOCK_SIZE, v3c.SEEK_START) + seek(v23c.ID_BLOCK_SIZE, v23c.SEEK_START) write(bytes(self.header)) for gp in self.groups: diff --git a/asammdf/mdf4.py b/asammdf/mdf_v4.py similarity index 99% rename from asammdf/mdf4.py rename to asammdf/mdf_v4.py index 1ed284063..9185df02f 100644 --- a/asammdf/mdf4.py +++ b/asammdf/mdf_v4.py @@ -43,7 +43,7 @@ from numpy.core.defchararray import encode from numexpr import evaluate -from .v4blocks import ( +from .v4_blocks import ( AttachmentBlock, Channel, ChannelArrayBlock, @@ -62,7 +62,7 @@ TextBlock, ) -from . import v4constants as v4c +from . import v4_constants as v4c from .utils import ( MdfException, get_fmt, diff --git a/asammdf/utils.py b/asammdf/utils.py index 7a5c72fd3..f4fe17bba 100644 --- a/asammdf/utils.py +++ b/asammdf/utils.py @@ -12,8 +12,8 @@ ) -from . import v3constants as v3c -from . import v4constants as v4c +from . import v2_v3_constants as v3c +from . import v4_constants as v4c __all__ = [ diff --git a/asammdf/v3blocks.py b/asammdf/v2_v3_blocks.py similarity index 79% rename from asammdf/v3blocks.py rename to asammdf/v2_v3_blocks.py index dae60a661..5fd0a159e 100644 --- a/asammdf/v3blocks.py +++ b/asammdf/v2_v3_blocks.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -""" classes that implement the blocks for MDF version 3 """ +""" classes that implement the blocks for MDF versions 2 and 3 """ from __future__ import print_function, division import sys @@ -8,13 +8,13 @@ from struct import unpack, pack, unpack_from from getpass import getuser -from . import v3constants as v3c +from . import v23constants as v23c PYVERSION = sys.version_info[0] PYVERSION_MAJOR = sys.version_info[0] * 10 + sys.version_info[1] -SEEK_START = v3c.SEEK_START -SEEK_END = v3c.SEEK_END +SEEK_START = v23c.SEEK_START +SEEK_END = v23c.SEEK_END __all__ = [ @@ -126,35 +126,85 @@ def __init__(self, **kargs): try: stream = kargs['stream'] self.address = address = kargs['address'] + stream.seek(address + 2, SEEK_START) + size = unpack('= v23c.CN_LONGNAME_BLOCK_SIZE: + self['long_name_addr'] = kargs.get('long_name_addr', 0) + if self['block_len'] >= v23c.CN_DISPLAYNAME_BLOCK_SIZE: + self['display_name_addr'] = kargs.get('display_name_addr', 0) + self['aditional_byte_offset'] = kargs.get( + 'aditional_byte_offset', + 0, + ) def __bytes__(self): + + block_len = self['block_len'] + if block_len == v23c.CN_DISPLAYNAME_BLOCK_SIZE: + fmt = v23c.FMT_CHANNEL_DISPLAYNAME + keys = v23c.KEYS_CHANNEL_DISPLAYNAME + elif block_len == v23c.CN_LONGNAME_BLOCK_SIZE: + fmt = v23c.FMT_CHANNEL_LONGNAME + keys = v23c.KEYS_CHANNEL_LONGNAME + else: + fmt = v23c.FMT_CHANNEL_SHORT + keys = v23c.KEYS_CHANNEL_SHORT + if PYVERSION_MAJOR >= 36: - result = pack(v3c.FMT_CHANNEL, *self.values()) + try: + result = pack(fmt, *self.values()) + except: + print(fmt, self) else: - result = pack( - v3c.FMT_CHANNEL, - *[self[key] for key in v3c.KEYS_CHANNEL] - ) + result = pack(fmt, *[self[key] for key in keys]) return result def __lt__(self, other): @@ -306,44 +370,44 @@ def __init__(self, **kargs): self['unit'], self['conversion_type'], self['ref_param_nr']) = unpack_from( - v3c.FMT_CONVERSION_COMMON_SHORT, + v23c.FMT_CONVERSION_COMMON_SHORT, block, ) conv_type = self['conversion_type'] - if conv_type == v3c.CONVERSION_TYPE_LINEAR: + if conv_type == v23c.CONVERSION_TYPE_LINEAR: (self['b'], self['a']) = unpack_from( '<2d', block, - v3c.CC_COMMON_SHORT_SIZE, + v23c.CC_COMMON_SHORT_SIZE, ) - if not size == v3c.CC_LIN_BLOCK_SIZE: - self['CANapeHiddenExtra'] = block[v3c.CC_LIN_BLOCK_SIZE - 4:] + if not size == v23c.CC_LIN_BLOCK_SIZE: + self['CANapeHiddenExtra'] = block[v23c.CC_LIN_BLOCK_SIZE - 4:] - elif conv_type == v3c.CONVERSION_TYPE_NONE: + elif conv_type == v23c.CONVERSION_TYPE_NONE: pass - elif conv_type == v3c.CONVERSION_TYPE_FORMULA: - self['formula'] = block[v3c.CC_COMMON_SHORT_SIZE:] + elif conv_type == v23c.CONVERSION_TYPE_FORMULA: + self['formula'] = block[v23c.CC_COMMON_SHORT_SIZE:] elif conv_type in ( - v3c.CONVERSION_TYPE_TABI, - v3c.CONVERSION_TYPE_TABX): + v23c.CONVERSION_TYPE_TABI, + v23c.CONVERSION_TYPE_TABX): nr = self['ref_param_nr'] values = unpack_from( '<{}d'.format(2*nr), block, - v3c.CC_COMMON_SHORT_SIZE, + v23c.CC_COMMON_SHORT_SIZE, ) for i in range(nr): (self['raw_{}'.format(i)], self['phys_{}'.format(i)]) = values[i*2], values[2*i+1] elif conv_type in ( - v3c.CONVERSION_TYPE_POLY, - v3c.CONVERSION_TYPE_RAT): + v23c.CONVERSION_TYPE_POLY, + v23c.CONVERSION_TYPE_RAT): (self['P1'], self['P2'], self['P3'], @@ -352,12 +416,12 @@ def __init__(self, **kargs): self['P6']) = unpack_from( '<6d', block, - v3c.CC_COMMON_SHORT_SIZE, + v23c.CC_COMMON_SHORT_SIZE, ) elif conv_type in ( - v3c.CONVERSION_TYPE_EXPO, - v3c.CONVERSION_TYPE_LOGH): + v23c.CONVERSION_TYPE_EXPO, + v23c.CONVERSION_TYPE_LOGH): (self['P1'], self['P2'], self['P3'], @@ -367,29 +431,29 @@ def __init__(self, **kargs): self['P7']) = unpack_from( '<7d', block, - v3c.CC_COMMON_SHORT_SIZE, + v23c.CC_COMMON_SHORT_SIZE, ) - elif conv_type == v3c.CONVERSION_TYPE_VTAB: + elif conv_type == v23c.CONVERSION_TYPE_VTAB: nr = self['ref_param_nr'] values = unpack_from( '<' + 'd32s' * nr, block, - v3c.CC_COMMON_SHORT_SIZE, + v23c.CC_COMMON_SHORT_SIZE, ) for i in range(nr): (self['param_val_{}'.format(i)], self['text_{}'.format(i)]) = values[i*2], values[2*i+1] - elif conv_type == v3c.CONVERSION_TYPE_VTABR: + elif conv_type == v23c.CONVERSION_TYPE_VTABR: nr = self['ref_param_nr'] values = unpack_from( '<' + '2dI' * nr, block, - v3c.CC_COMMON_SHORT_SIZE, + v23c.CC_COMMON_SHORT_SIZE, ) for i in range(nr): (self['lower_{}'.format(i)], @@ -399,40 +463,40 @@ def __init__(self, **kargs): self.address = 0 self['id'] = 'CC'.encode('latin-1') - if kargs['conversion_type'] == v3c.CONVERSION_TYPE_NONE: + if kargs['conversion_type'] == v23c.CONVERSION_TYPE_NONE: self['block_len'] = kargs.get( 'block_len', - v3c.CC_COMMON_BLOCK_SIZE, + v23c.CC_COMMON_BLOCK_SIZE, ) self['range_flag'] = kargs.get('range_flag', 1) self['min_phy_value'] = kargs.get('min_phy_value', 0) self['max_phy_value'] = kargs.get('max_phy_value', 0) self['unit'] = kargs.get('unit', ('\0'*20).encode('latin-1')) - self['conversion_type'] = v3c.CONVERSION_TYPE_NONE + self['conversion_type'] = v23c.CONVERSION_TYPE_NONE self['ref_param_nr'] = kargs.get('ref_param_nr', 0) - elif kargs['conversion_type'] == v3c.CONVERSION_TYPE_LINEAR: + elif kargs['conversion_type'] == v23c.CONVERSION_TYPE_LINEAR: self['block_len'] = kargs.get( 'block_len', - v3c.CC_LIN_BLOCK_SIZE, + v23c.CC_LIN_BLOCK_SIZE, ) self['range_flag'] = kargs.get('range_flag', 1) self['min_phy_value'] = kargs.get('min_phy_value', 0) self['max_phy_value'] = kargs.get('max_phy_value', 0) self['unit'] = kargs.get('unit', ('\0'*20).encode('latin-1')) - self['conversion_type'] = v3c.CONVERSION_TYPE_LINEAR + self['conversion_type'] = v23c.CONVERSION_TYPE_LINEAR self['ref_param_nr'] = kargs.get('ref_param_nr', 2) self['b'] = kargs.get('b', 0) self['a'] = kargs.get('a', 1) - if not self['block_len'] == v3c.CC_LIN_BLOCK_SIZE: + if not self['block_len'] == v23c.CC_LIN_BLOCK_SIZE: self['CANapeHiddenExtra'] = kargs['CANapeHiddenExtra'] elif kargs['conversion_type'] in ( - v3c.CONVERSION_TYPE_POLY, - v3c.CONVERSION_TYPE_RAT): + v23c.CONVERSION_TYPE_POLY, + v23c.CONVERSION_TYPE_RAT): self['block_len'] = kargs.get( 'block_len', - v3c.CC_POLY_BLOCK_SIZE, + v23c.CC_POLY_BLOCK_SIZE, ) self['range_flag'] = kargs.get('range_flag', 1) self['min_phy_value'] = kargs.get('min_phy_value', 0) @@ -440,7 +504,7 @@ def __init__(self, **kargs): self['unit'] = kargs.get('unit', ('\0'*20).encode('latin-1')) self['conversion_type'] = kargs.get( 'conversion_type', - v3c.CONVERSION_TYPE_POLY, + v23c.CONVERSION_TYPE_POLY, ) self['ref_param_nr'] = kargs.get('ref_param_nr', 2) self['P1'] = kargs.get('P1', 0) @@ -451,11 +515,11 @@ def __init__(self, **kargs): self['P6'] = kargs.get('P6', 0) elif kargs['conversion_type'] in ( - v3c.CONVERSION_TYPE_EXPO, - v3c.CONVERSION_TYPE_LOGH): + v23c.CONVERSION_TYPE_EXPO, + v23c.CONVERSION_TYPE_LOGH): self['block_len'] = kargs.get( 'block_len', - v3c.CC_EXPO_BLOCK_SIZE, + v23c.CC_EXPO_BLOCK_SIZE, ) self['range_flag'] = kargs.get('range_flag', 1) self['min_phy_value'] = kargs.get('min_phy_value', 0) @@ -463,7 +527,7 @@ def __init__(self, **kargs): self['unit'] = kargs.get('unit', ('\0'*20).encode('latin-1')) self['conversion_type'] = kargs.get( 'conversion_type', - v3c.CONVERSION_TYPE_EXPO, + v23c.CONVERSION_TYPE_EXPO, ) self['ref_param_nr'] = kargs.get('ref_param_nr', 2) self['P1'] = kargs.get('P1', 0) @@ -474,10 +538,10 @@ def __init__(self, **kargs): self['P6'] = kargs.get('P6', 0) self['P7'] = kargs.get('P7', 0) - elif kargs['conversion_type'] == v3c.CONVERSION_TYPE_FORMULA: + elif kargs['conversion_type'] == v23c.CONVERSION_TYPE_FORMULA: self['block_len'] = kargs.get( 'block_len', - v3c.CC_POLY_BLOCK_SIZE, + v23c.CC_POLY_BLOCK_SIZE, ) self['range_flag'] = kargs.get('range_flag', 1) self['min_phy_value'] = kargs.get('min_phy_value', 0) @@ -485,14 +549,14 @@ def __init__(self, **kargs): self['unit'] = kargs.get('unit', ('\0'*20).encode('latin-1')) self['conversion_type'] = kargs.get( 'conversion_type', - v3c.CONVERSION_TYPE_FORMULA, + v23c.CONVERSION_TYPE_FORMULA, ) self['ref_param_nr'] = kargs.get('ref_param_nr', 2) self['formula'] = kargs.get('formula', b'X1'+b'\0'*254) elif kargs['conversion_type'] in ( - v3c.CONVERSION_TYPE_TABI, - v3c.CONVERSION_TYPE_TABX): + v23c.CONVERSION_TYPE_TABI, + v23c.CONVERSION_TYPE_TABX): nr = kargs['ref_param_nr'] self['block_len'] = kargs['block_len'] self['range_flag'] = kargs.get('range_flag', 1) @@ -501,41 +565,41 @@ def __init__(self, **kargs): self['unit'] = kargs.get('unit', ('\0'*20).encode('latin-1')) self['conversion_type'] = kargs.get( 'conversion_type', - v3c.CONVERSION_TYPE_TABI, + v23c.CONVERSION_TYPE_TABI, ) self['ref_param_nr'] = kargs.get('ref_param_nr', 2) for i in range(nr): self['raw_{}'.format(i)] = kargs['raw_{}'.format(i)] self['phys_{}'.format(i)] = kargs['phys_{}'.format(i)] - elif kargs['conversion_type'] == v3c.CONVERSION_TYPE_VTAB: + elif kargs['conversion_type'] == v23c.CONVERSION_TYPE_VTAB: nr = kargs['ref_param_nr'] self['block_len'] = kargs.get( 'block_len', - v3c.CC_COMMON_BLOCK_SIZE + 40*nr, + v23c.CC_COMMON_BLOCK_SIZE + 40*nr, ) self['range_flag'] = kargs.get('range_flag', 0) self['min_phy_value'] = kargs.get('min_phy_value', 0) self['max_phy_value'] = kargs.get('max_phy_value', 0) self['unit'] = kargs.get('unit', ('\0'*20).encode('latin-1')) - self['conversion_type'] = v3c.CONVERSION_TYPE_VTAB + self['conversion_type'] = v23c.CONVERSION_TYPE_VTAB self['ref_param_nr'] = nr for i in range(nr): self['param_val_{}'.format(i)] = kargs['param_val_{}'.format(i)] self['text_{}'.format(i)] = kargs['text_{}'.format(i)] - elif kargs['conversion_type'] == v3c.CONVERSION_TYPE_VTABR: + elif kargs['conversion_type'] == v23c.CONVERSION_TYPE_VTABR: nr = kargs.get('ref_param_nr', 0) self['block_len'] = kargs.get( 'block_len', - v3c.CC_COMMON_BLOCK_SIZE + 20*nr, + v23c.CC_COMMON_BLOCK_SIZE + 20*nr, ) self['range_flag'] = kargs.get('range_flag', 0) self['min_phy_value'] = kargs.get('min_phy_value', 0) self['max_phy_value'] = kargs.get('max_phy_value', 0) self['unit'] = kargs.get('unit', ('\0'*20).encode('latin-1')) - self['conversion_type'] = v3c.CONVERSION_TYPE_VTABR + self['conversion_type'] = v23c.CONVERSION_TYPE_VTABR self['ref_param_nr'] = kargs.get('ref_param_nr', 0) for i in range(self['ref_param_nr']): @@ -551,58 +615,58 @@ def __bytes__(self): conv = self['conversion_type'] # compute the fmt - if conv == v3c.CONVERSION_TYPE_NONE: - fmt = v3c.FMT_CONVERSION_COMMON - elif conv == v3c.CONVERSION_TYPE_FORMULA: - fmt = v3c.FMT_CONVERSION_FORMULA - elif conv == v3c.CONVERSION_TYPE_LINEAR: - fmt = v3c.FMT_CONVERSION_LINEAR - if not self['block_len'] == v3c.CC_LIN_BLOCK_SIZE: - fmt += '{}s'.format(self['block_len'] - v3c.CC_LIN_BLOCK_SIZE) - elif conv in (v3c.CONVERSION_TYPE_POLY, v3c.CONVERSION_TYPE_RAT): - fmt = v3c.FMT_CONVERSION_POLY_RAT - elif conv in (v3c.CONVERSION_TYPE_EXPO, v3c.CONVERSION_TYPE_LOGH): - fmt = v3c.FMT_CONVERSION_EXPO_LOGH - elif conv in (v3c.CONVERSION_TYPE_TABI, v3c.CONVERSION_TYPE_TABX): + if conv == v23c.CONVERSION_TYPE_NONE: + fmt = v23c.FMT_CONVERSION_COMMON + elif conv == v23c.CONVERSION_TYPE_FORMULA: + fmt = v23c.FMT_CONVERSION_FORMULA + elif conv == v23c.CONVERSION_TYPE_LINEAR: + fmt = v23c.FMT_CONVERSION_LINEAR + if not self['block_len'] == v23c.CC_LIN_BLOCK_SIZE: + fmt += '{}s'.format(self['block_len'] - v23c.CC_LIN_BLOCK_SIZE) + elif conv in (v23c.CONVERSION_TYPE_POLY, v23c.CONVERSION_TYPE_RAT): + fmt = v23c.FMT_CONVERSION_POLY_RAT + elif conv in (v23c.CONVERSION_TYPE_EXPO, v23c.CONVERSION_TYPE_LOGH): + fmt = v23c.FMT_CONVERSION_EXPO_LOGH + elif conv in (v23c.CONVERSION_TYPE_TABI, v23c.CONVERSION_TYPE_TABX): nr = self['ref_param_nr'] - fmt = v3c.FMT_CONVERSION_COMMON + '{}d'.format(nr * 2) - elif conv == v3c.CONVERSION_TYPE_VTABR: + fmt = v23c.FMT_CONVERSION_COMMON + '{}d'.format(nr * 2) + elif conv == v23c.CONVERSION_TYPE_VTABR: nr = self['ref_param_nr'] - fmt = v3c.FMT_CONVERSION_COMMON + '2dI' * nr - elif conv == v3c.CONVERSION_TYPE_VTAB: + fmt = v23c.FMT_CONVERSION_COMMON + '2dI' * nr + elif conv == v23c.CONVERSION_TYPE_VTAB: nr = self['ref_param_nr'] - fmt = v3c.FMT_CONVERSION_COMMON + 'd32s' * nr + fmt = v23c.FMT_CONVERSION_COMMON + 'd32s' * nr # compute the keys only for Python < 3.6 if PYVERSION_MAJOR < 36: - if conv == v3c.CONVERSION_TYPE_NONE: - keys = v3c.KEYS_CONVESION_NONE - elif conv == v3c.CONVERSION_TYPE_FORMULA: - keys = v3c.KEYS_CONVESION_FORMULA - elif conv == v3c.CONVERSION_TYPE_LINEAR: - keys = v3c.KEYS_CONVESION_LINEAR - if not self['block_len'] == v3c.CC_LIN_BLOCK_SIZE: + if conv == v23c.CONVERSION_TYPE_NONE: + keys = v23c.KEYS_CONVESION_NONE + elif conv == v23c.CONVERSION_TYPE_FORMULA: + keys = v23c.KEYS_CONVESION_FORMULA + elif conv == v23c.CONVERSION_TYPE_LINEAR: + keys = v23c.KEYS_CONVESION_LINEAR + if not self['block_len'] == v23c.CC_LIN_BLOCK_SIZE: keys += ('CANapeHiddenExtra',) - elif conv in (v3c.CONVERSION_TYPE_POLY, v3c.CONVERSION_TYPE_RAT): - keys = v3c.KEYS_CONVESION_POLY_RAT - elif conv in (v3c.CONVERSION_TYPE_EXPO, v3c.CONVERSION_TYPE_LOGH): - keys = v3c.KEYS_CONVESION_EXPO_LOGH - elif conv in (v3c.CONVERSION_TYPE_TABI, v3c.CONVERSION_TYPE_TABX): + elif conv in (v23c.CONVERSION_TYPE_POLY, v23c.CONVERSION_TYPE_RAT): + keys = v23c.KEYS_CONVESION_POLY_RAT + elif conv in (v23c.CONVERSION_TYPE_EXPO, v23c.CONVERSION_TYPE_LOGH): + keys = v23c.KEYS_CONVESION_EXPO_LOGH + elif conv in (v23c.CONVERSION_TYPE_TABI, v23c.CONVERSION_TYPE_TABX): nr = self['ref_param_nr'] - keys = list(v3c.KEYS_CONVESION_NONE) + keys = list(v23c.KEYS_CONVESION_NONE) for i in range(nr): keys.append('raw_{}'.format(i)) keys.append('phys_{}'.format(i)) - elif conv == v3c.CONVERSION_TYPE_VTABR: + elif conv == v23c.CONVERSION_TYPE_VTABR: nr = self['ref_param_nr'] - keys = list(v3c.KEYS_CONVESION_NONE) + keys = list(v23c.KEYS_CONVESION_NONE) for i in range(nr): keys.append('lower_{}'.format(i)) keys.append('upper_{}'.format(i)) keys.append('text_{}'.format(i)) - elif conv == v3c.CONVERSION_TYPE_VTAB: + elif conv == v23c.CONVERSION_TYPE_VTAB: nr = self['ref_param_nr'] - keys = list(v3c.KEYS_CONVESION_NONE) + keys = list(v23c.KEYS_CONVESION_NONE) for i in range(nr): keys.append('param_val_{}'.format(i)) keys.append('text_{}'.format(i)) @@ -787,28 +851,28 @@ def __init__(self, **kargs): stream.seek(address, SEEK_START) (self['id'], self['block_len'], - self['type']) = unpack(v3c.FMT_SOURCE_COMMON, stream.read(6)) + self['type']) = unpack(v23c.FMT_SOURCE_COMMON, stream.read(6)) block = stream.read(self['block_len'] - 6) - if self['type'] == v3c.SOURCE_ECU: + if self['type'] == v23c.SOURCE_ECU: (self['module_nr'], self['module_address'], self['description'], self['ECU_identification'], - self['reserved0']) = unpack(v3c.FMT_SOURCE_EXTRA_ECU, block) - elif self['type'] == v3c.SOURCE_VECTOR: + self['reserved0']) = unpack(v23c.FMT_SOURCE_EXTRA_ECU, block) + elif self['type'] == v23c.SOURCE_VECTOR: (self['CAN_id'], self['CAN_ch_index'], self['message_name'], self['sender_name'], - self['reserved0']) = unpack(v3c.FMT_SOURCE_EXTRA_VECTOR, block) + self['reserved0']) = unpack(v23c.FMT_SOURCE_EXTRA_VECTOR, block) except KeyError: self.address = 0 self['id'] = kargs.get('id', 'CE'.encode('latin-1')) - self['block_len'] = kargs.get('block_len', v3c.CE_BLOCK_SIZE) + self['block_len'] = kargs.get('block_len', v23c.CE_BLOCK_SIZE) self['type'] = kargs.get('type', 2) - if self['type'] == v3c.SOURCE_ECU: + if self['type'] == v23c.SOURCE_ECU: self['module_nr'] = kargs.get('module_nr', 0) self['module_address'] = kargs.get('module_address', 0) self['description'] = kargs.get('description', b'\0') @@ -817,7 +881,7 @@ def __init__(self, **kargs): b'\0', ) self['reserved0'] = kargs.get('reserved0', b'\0') - elif self['type'] == v3c.SOURCE_VECTOR: + elif self['type'] == v23c.SOURCE_VECTOR: self['CAN_id'] = kargs.get('CAN_id', 0) self['CAN_ch_index'] = kargs.get('CAN_ch_index', 0) self['message_name'] = kargs.get('message_name', b'\0') @@ -826,12 +890,12 @@ def __init__(self, **kargs): def __bytes__(self): typ = self['type'] - if typ == v3c.SOURCE_ECU: - fmt = v3c.FMT_SOURCE_ECU - keys = v3c.KEYS_SOURCE_ECU + if typ == v23c.SOURCE_ECU: + fmt = v23c.FMT_SOURCE_ECU + keys = v23c.KEYS_SOURCE_ECU else: - fmt = v3c.FMT_SOURCE_VECTOR - keys = v3c.KEYS_SOURCE_VECTOR + fmt = v23c.FMT_SOURCE_VECTOR + keys = v23c.KEYS_SOURCE_VECTOR if PYVERSION_MAJOR >= 36: result = pack(fmt, *self.values()) @@ -900,7 +964,7 @@ def __init__(self, **kargs): stream = kargs['stream'] self.address = address = kargs['address'] stream.seek(address, SEEK_START) - block = stream.read(v3c.CG_BLOCK_SIZE) + block = stream.read(v23c.CG_PRE_330_BLOCK_SIZE) (self['id'], self['block_len'], @@ -910,13 +974,16 @@ def __init__(self, **kargs): self['record_id'], self['ch_nr'], self['samples_byte_nr'], - self['cycles_nr']) = unpack(v3c.FMT_CHANNEL_GROUP, block) - if self['block_len'] == v3c.CG33_BLOCK_SIZE: + self['cycles_nr']) = unpack(v23c.FMT_CHANNEL_GROUP, block) + if self['block_len'] == v23c.CG_POST_330_BLOCK_SIZE: self['sample_reduction_addr'] = unpack('= 36: @@ -1030,7 +1097,7 @@ def __init__(self, **kargs): stream = kargs['stream'] self.address = address = kargs['address'] stream.seek(address, SEEK_START) - block = stream.read(v3c.DG31_BLOCK_SIZE) + block = stream.read(v23c.DG_PRE_320_BLOCK_SIZE) (self['id'], self['block_len'], @@ -1039,31 +1106,34 @@ def __init__(self, **kargs): self['trigger_addr'], self['data_block_addr'], self['cg_nr'], - self['record_id_nr']) = unpack(v3c.FMT_DATA_GROUP, block) + self['record_id_nr']) = unpack(v23c.FMT_DATA_GROUP_PRE_320, block) - if self['block_len'] == v3c.DG32_BLOCK_SIZE: + if self['block_len'] == v23c.DG_POST_320_BLOCK_SIZE: self['reserved0'] = stream.read(4) except KeyError: self.address = 0 self['id'] = kargs.get('id', 'DG'.encode('latin-1')) - self['block_len'] = kargs.get('block_len', v3c. DG32_BLOCK_SIZE) + self['block_len'] = kargs.get( + 'block_len', + v23c.DG_PRE_320_BLOCK_SIZE, + ) self['next_dg_addr'] = kargs.get('next_dg_addr', 0) self['first_cg_addr'] = kargs.get('first_cg_addr', 0) self['trigger_addr'] = kargs.get('comment_addr', 0) self['data_block_addr'] = kargs.get('data_block_addr', 0) self['cg_nr'] = kargs.get('cg_nr', 1) self['record_id_nr'] = kargs.get('record_id_nr', 0) - if self['block_len'] == v3c.DG32_BLOCK_SIZE: + if self['block_len'] == v23c.DG_POST_320_BLOCK_SIZE: self['reserved0'] = b'\0\0\0\0' def __bytes__(self): - if self['block_len'] == v3c.DG32_BLOCK_SIZE: - fmt = v3c.FMT_DATA_GROUP_32 - keys = v3c.KEYS_DATA_GROUP_32 + if self['block_len'] == v23c.DG_POST_320_BLOCK_SIZE: + fmt = v23c.FMT_DATA_GROUP_POST_320 + keys = v23c.KEYS_DATA_GROUP_POST_320 else: - fmt = v3c.FMT_DATA_GROUP - keys = v3c.KEYS_DATA_GROUP + fmt = v23c.FMT_DATA_GROUP_PRE_320 + keys = v23c.KEYS_DATA_GROUP_PRE_320 if PYVERSION_MAJOR >= 36: result = pack(fmt, *self.values()) else: @@ -1128,15 +1198,15 @@ def __init__(self, **kargs): self['reserved1'], self['unfinalized_standard_flags'], self['unfinalized_custom_flags']) = unpack( - v3c.ID_FMT, - stream.read(v3c.ID_BLOCK_SIZE), + v23c.ID_FMT, + stream.read(v23c.ID_BLOCK_SIZE), ) except KeyError: version = kargs['version'] self['file_identification'] = 'MDF '.encode('latin-1') self['version_str'] = version.encode('latin-1') + b'\0' * 4 self['program_identification'] = 'Python '.encode('latin-1') - self['byte_order'] = v3c.BYTE_ORDER_INTEL + self['byte_order'] = v23c.BYTE_ORDER_INTEL self['float_format'] = 0 self['mdf_version'] = int(version.replace('.', '')) self['code_page'] = 0 @@ -1147,9 +1217,9 @@ def __init__(self, **kargs): def __bytes__(self): if PYVERSION_MAJOR >= 36: - result = pack(v3c.ID_FMT, *self.values()) + result = pack(v23c.ID_FMT, *self.values()) else: - result = pack(v3c.ID_FMT, *[self[key] for key in v3c.ID_KEYS]) + result = pack(v23c.ID_FMT, *[self[key] for key in v23c.ID_KEYS]) return result @@ -1217,23 +1287,23 @@ def __init__(self, **kargs): self['organization'], self['project'], self['subject']) = unpack( - v3c.HEADER_COMMON_FMT, - stream.read(v3c.HEADER_COMMON_SIZE), + v23c.HEADER_COMMON_FMT, + stream.read(v23c.HEADER_COMMON_SIZE), ) - if self['block_len'] > v3c.HEADER_COMMON_SIZE: + if self['block_len'] > v23c.HEADER_COMMON_SIZE: (self['abs_time'], self['tz_offset'], self['time_quality'], self['timer_identification']) = unpack( - v3c.HEADER_POST_320_EXTRA_FMT, - stream.read(v3c.HEADER_POST_320_EXTRA_SIZE), + v23c.HEADER_POST_320_EXTRA_FMT, + stream.read(v23c.HEADER_POST_320_EXTRA_SIZE), ) except KeyError: version = kargs.get('version', '3.20') self['id'] = 'HD'.encode('latin-1') - self['block_len'] = 208 if version in ('3.20', '3.30') else 164 + self['block_len'] = 208 if version >= '3.20' else 164 self['first_dg_addr'] = 0 self['comment_addr'] = 0 self['program_addr'] = 0 @@ -1247,18 +1317,18 @@ def __init__(self, **kargs): self['project'] = '{:\0<32}'.format('').encode('latin-1') self['subject'] = '{:\0<32}'.format('').encode('latin-1') - if self['block_len'] > v3c.HEADER_COMMON_SIZE: + if self['block_len'] > v23c.HEADER_COMMON_SIZE: self['abs_time'] = int(t1) self['tz_offset'] = 2 self['time_quality'] = 0 self['timer_identification'] = '{:\0<32}'.format('Local PC Reference Time').encode('latin-1') def __bytes__(self): - fmt = v3c.HEADER_COMMON_FMT - keys = v3c.HEADER_COMMON_KEYS - if self['block_len'] > v3c.HEADER_COMMON_SIZE: - fmt += v3c.HEADER_POST_320_EXTRA_FMT - keys += v3c.HEADER_POST_320_EXTRA_KEYS + fmt = v23c.HEADER_COMMON_FMT + keys = v23c.HEADER_COMMON_KEYS + if self['block_len'] > v23c.HEADER_COMMON_SIZE: + fmt += v23c.HEADER_POST_320_EXTRA_FMT + keys += v23c.HEADER_POST_320_EXTRA_KEYS if PYVERSION_MAJOR >= 36: result = pack(fmt, *self.values()) else: @@ -1312,11 +1382,11 @@ def __init__(self, **kargs): pass def __bytes__(self): - fmt = v3c.FMT_PROGRAM_BLOCK.format(self['block_len']) + fmt = v23c.FMT_PROGRAM_BLOCK.format(self['block_len']) if PYVERSION_MAJOR >= 36: result = pack(fmt, *self.values()) else: - result = pack(fmt, *[self[key] for key in v3c.KEYS_PROGRAM_BLOCK]) + result = pack(fmt, *[self[key] for key in v23c.KEYS_PROGRAM_BLOCK]) return result @@ -1365,8 +1435,8 @@ def __init__(self, **kargs): self['data_block_addr'], self['cycles_nr'], self['time_interval']) = unpack( - v3c.FMT_SAMPLE_REDUCTION_BLOCK, - stream.read(v3c.SR_BLOCK_SIZE), + v23c.FMT_SAMPLE_REDUCTION_BLOCK, + stream.read(v23c.SR_BLOCK_SIZE), ) except KeyError: @@ -1374,8 +1444,8 @@ def __init__(self, **kargs): def __bytes__(self): result = pack( - v3c.FMT_SAMPLE_REDUCTION_BLOCK, - *[self[key] for key in v3c.KEYS_SAMPLE_REDUCTION_BLOCK] + v23c.FMT_SAMPLE_REDUCTION_BLOCK, + *[self[key] for key in v23c.KEYS_SAMPLE_REDUCTION_BLOCK] ) return result @@ -1458,7 +1528,7 @@ def __bytes__(self): else: result = pack( '<2sH{}s'.format(self['block_len']-4), - *[self[key] for key in v3c.KEYS_TEXT_BLOCK] + *[self[key] for key in v23c.KEYS_TEXT_BLOCK] ) return result diff --git a/asammdf/v3constants.py b/asammdf/v2_v3_constants.py similarity index 86% rename from asammdf/v3constants.py rename to asammdf/v2_v3_constants.py index 61625b4b1..5679cfce2 100644 --- a/asammdf/v3constants.py +++ b/asammdf/v2_v3_constants.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -""" MDF v3 constants """ +""" MDF v2 and v3 constants """ # byte order BYTE_ORDER_INTEL = 0 @@ -87,12 +87,14 @@ HEADER_POST_320_EXTRA_SIZE = 44 CE_BLOCK_SIZE = 128 FH_BLOCK_SIZE = 56 -DG31_BLOCK_SIZE = 24 -DG32_BLOCK_SIZE = 28 +DG_PRE_320_BLOCK_SIZE = 24 +DG_POST_320_BLOCK_SIZE = 28 HD_BLOCK_SIZE = 104 -CN_BLOCK_SIZE = 228 -CG_BLOCK_SIZE = 26 -CG33_BLOCK_SIZE = 30 +CN_DISPLAYNAME_BLOCK_SIZE = 228 +CN_SHORT_BLOCK_SIZE = 218 +CN_LONGNAME_BLOCK_SIZE = 222 +CG_PRE_330_BLOCK_SIZE = 26 +CG_POST_330_BLOCK_SIZE = 30 DT_BLOCK_SIZE = 24 CC_COMMON_BLOCK_SIZE = 46 CC_COMMON_SHORT_SIZE = 42 @@ -154,8 +156,8 @@ 'timer_identification', ) -FMT_CHANNEL = '<2sH5IH32s128s4H3d2IH' -KEYS_CHANNEL = ( +FMT_CHANNEL_DISPLAYNAME = '<2sH5IH32s128s4H3d2IH' +KEYS_CHANNEL_DISPLAYNAME = ( 'id', 'block_len', 'next_ch_addr', @@ -178,6 +180,29 @@ 'aditional_byte_offset', ) +FMT_CHANNEL_SHORT = '<2sH5IH32s128s4H3d' +FMT_CHANNEL_LONGNAME = FMT_CHANNEL_SHORT + 'I' +KEYS_CHANNEL_SHORT = ( + 'id', + 'block_len', + 'next_ch_addr', + 'conversion_addr', + 'source_depend_addr', + 'ch_depend_addr', + 'comment_addr', + 'channel_type', + 'short_name', + 'description', + 'start_offset', + 'bit_count', + 'data_type', + 'range_flag', + 'min_raw_value', + 'max_raw_value', + 'sampling_rate', +) +KEYS_CHANNEL_LONGNAME = KEYS_CHANNEL_SHORT + ('long_name_addr', ) + FMT_CHANNEL_GROUP = '<2sH3I3HI' KEYS_CHANNEL_GROUP = ( 'id', @@ -191,8 +216,8 @@ 'cycles_nr', ) -FMT_DATA_GROUP_32 = '<2sH4I2H4s' -KEYS_DATA_GROUP_32 = ( +FMT_DATA_GROUP_POST_320 = '<2sH4I2H4s' +KEYS_DATA_GROUP_POST_320 = ( 'id', 'block_len', 'next_dg_addr', @@ -204,8 +229,8 @@ 'reserved0', ) -FMT_DATA_GROUP = '<2sH4I2H' -KEYS_DATA_GROUP = ( +FMT_DATA_GROUP_PRE_320 = '<2sH4I2H' +KEYS_DATA_GROUP_PRE_320 = ( 'id', 'block_len', 'next_dg_addr', diff --git a/asammdf/v2blocks.py b/asammdf/v2blocks.py deleted file mode 100644 index 3310edfb0..000000000 --- a/asammdf/v2blocks.py +++ /dev/null @@ -1,1574 +0,0 @@ -# -*- coding: utf-8 -*- -""" -classes that implement the blocks for MDF version 3 -""" - -from __future__ import print_function, division -import sys -import time - -from struct import unpack, pack, unpack_from -from getpass import getuser - -from . import v2constants as v2c - - -PYVERSION = sys.version_info[0] -PYVERSION_MAJOR = sys.version_info[0] * 10 + sys.version_info[1] -SEEK_START = v2c.SEEK_START -SEEK_END = v2c.SEEK_END - - -__all__ = [ - 'Channel', - 'ChannelConversion', - 'ChannelDependency', - 'ChannelExtension', - 'ChannelGroup', - 'DataBlock', - 'DataGroup', - 'FileIdentificationBlock', - 'HeaderBlock', - 'ProgramBlock', - 'SampleReduction', - 'TextBlock', - 'TriggerBlock', -] - - -class Channel(dict): - ''' CNBLOCK class derived from *dict* - - The Channel object can be created in two modes: - - * using the *stream* and *address* keyword parameters - when reading - from file - * using any of the following presented keys - when creating a new Channel - - The keys have the following meaning: - - * id - Block type identifier, always "CN" - * block_len - Block size of this block in bytes (entire CNBLOCK) - * next_ch_addr - Pointer to next channel block (CNBLOCK) of this channel - group (NIL allowed) - * conversion_addr - Pointer to the conversion formula (CCBLOCK) of this - signal (NIL allowed) - * source_depend_addr - Pointer to the source-depending extensions (CEBLOCK) - of this signal (NIL allowed) - * ch_depend_addr - Pointer to the dependency block (CDBLOCK) of this signal - (NIL allowed) - * comment_addr - Pointer to the channel comment (TXBLOCK) of this signal - (NIL allowed) - * channel_type - Channel type - - * 0 = data channel - * 1 = time channel for all signals of this group (in each channel group, - exactly one channel must be defined as time channel). - The time stamps recording in a time channel are always relative - to the start time of the measurement defined in HDBLOCK. - - * short_name - Short signal name, i.e. the first 31 characters of the - ASAM-MCD name of the signal (end of text should be indicated by 0) - * description - Signal description (end of text should be indicated by 0) - * start_offset - Start offset in bits to determine the first bit of the - signal in the data record. The start offset N is divided into two parts: - a "Byte offset" (= N div 8) and a "Bit offset" (= N mod 8). - The channel block can define an "additional Byte offset" (see below) - which must be added to the Byte offset. - * bit_count - Number of bits used to encode the value of this signal in a - data record - * data_type - Signal data type - * range_flag - Value range valid flag - * min_raw_value - Minimum signal value that occurred for this signal - (raw value) - * max_raw_value - Maximum signal value that occurred for this signal - (raw value) - * sampling_rate - Sampling rate for a virtual time channel. Unit [s] - * long_name_addr - Pointer to TXBLOCK that contains the ASAM-MCD long signal - name - * display_name_addr - Pointer to TXBLOCK that contains the signal's display - name (NIL allowed) - * aditional_byte_offset - Additional Byte offset of the signal in the data - record (default value: 0). - - Parameters - ---------- - stream : file handle - mdf file handle - address : int - block address inside mdf file - - Attributes - ---------- - name : str - full channel name - address : int - block address inside mdf file - dependencies : list - lsit of channel dependencies - - Examples - -------- - >>> with open('test.mdf', 'rb') as mdf: - ... ch1 = Channel(stream=mdf, address=0xBA52) - >>> ch2 = Channel() - >>> ch1.name - 'VehicleSpeed' - >>> ch1['id'] - b'CN' - - ''' - __slots__ = ['name', 'address'] - - def __init__(self, **kargs): - super(Channel, self).__init__() - - self.name = '' - - try: - stream = kargs['stream'] - self.address = address = kargs['address'] - stream.seek(address + 2, SEEK_START) - size = unpack('= 36: - result = pack(fmt, *self.values()) - else: - result = pack(fmt, *[self[key] for key in keys]) - return result - - def __lt__(self, other): - self_start = self['start_offset'] - other_start = other['start_offset'] - if self_start < other_start: - result = 1 - elif self_start == other_start: - if self['bit_count'] >= other['bit_count']: - result = 1 - else: - result = 0 - else: - result = 0 - return result - - -class ChannelConversion(dict): - ''' CCBLOCK class derived from *dict* - - The ChannelConversion object can be created in two modes: - - * using the *stream* and *address* keyword parameters - when reading - from file - * using any of the following presented keys - when creating a new - ChannelConversion - - The first keys are common for all conversion types, and are followed by - conversion specific keys. The keys have the following meaning: - - * common keys - - * id - Block type identifier, always "CC" - * block_len - Block size of this block in bytes (entire CCBLOCK) - * range_flag - Physical value range valid flag: - * min_phy_value - Minimum physical signal value that occurred for this - signal - * max_phy_value - Maximum physical signal value that occurred for this - signal - * unit - Physical unit (string should be terminated with 0) - * conversion_type - Conversion type (formula identifier) - * ref_param_nr - Size information about additional conversion data - - * specific keys - - * linear conversion - - * b - offset - * a - factor - * CANapeHiddenExtra - sometimes CANape appends extra information; - not compliant with MDF specs - - * ASAM formula conversion - - * formula - ecuation as string - - * polynomial or rational conversion - - * P1 .. P6 - factors - - * exponential or logarithmic conversion - - * P1 .. P7 - factors - - * tabular with or without interpolation (grouped by *n*) - - * raw_{n} - n-th raw integer value (X axis) - * phys_{n} - n-th physical value (Y axis) - - * text table conversion - - * param_val_{n} - n-th integers value (X axis) - * text_{n} - n-th text value (Y axis) - - * text range table conversion - - * lower_{n} - n-th lower raw value - * upper_{n} - n-th upper raw value - * text_{n} - n-th text value - - Parameters - ---------- - stream : file handle - mdf file handle - address : int - block address inside mdf file - - Attributes - ---------- - address : int - block address inside mdf file - - Examples - -------- - >>> with open('test.mdf', 'rb') as mdf: - ... cc1 = ChannelConversion(stream=mdf, address=0xBA52) - >>> cc2 = ChannelConversion(conversion_type=0) - >>> cc1['b'], cc1['a'] - 0, 100.0 - - ''' - __slots__ = ['address',] - def __init__(self, **kargs): - super(ChannelConversion, self).__init__() - - try: - stream = kargs['stream'] - self.address = address = kargs['address'] - stream.seek(address, SEEK_START) - block = stream.read(4) - (self['id'], - self['block_len']) = unpack('<2sH', block) - size = self['block_len'] - block = stream.read(size - 4) - - (self['range_flag'], - self['min_phy_value'], - self['max_phy_value'], - self['unit'], - self['conversion_type'], - self['ref_param_nr']) = unpack_from( - v2c.FMT_CONVERSION_COMMON_SHORT, - block, - ) - - conv_type = self['conversion_type'] - - if conv_type == v2c.CONVERSION_TYPE_LINEAR: - (self['b'], - self['a']) = unpack_from( - '<2d', - block, - v2c.CC_COMMON_SHORT_SIZE, - ) - if not size == v2c.CC_LIN_BLOCK_SIZE: - self['CANapeHiddenExtra'] = block[v2c.CC_LIN_BLOCK_SIZE - 4:] - - elif conv_type == v2c.CONVERSION_TYPE_NONE: - pass - - elif conv_type == v2c.CONVERSION_TYPE_FORMULA: - self['formula'] = block[v2c.CC_COMMON_SHORT_SIZE:] - - elif conv_type in ( - v2c.CONVERSION_TYPE_TABI, - v2c.CONVERSION_TYPE_TABX): - nr = self['ref_param_nr'] - values = unpack_from( - '<{}d'.format(2*nr), - block, - v2c.CC_COMMON_SHORT_SIZE, - ) - for i in range(nr): - (self['raw_{}'.format(i)], - self['phys_{}'.format(i)]) = values[i*2], values[2*i+1] - - elif conv_type in ( - v2c.CONVERSION_TYPE_POLY, - v2c.CONVERSION_TYPE_RAT): - (self['P1'], - self['P2'], - self['P3'], - self['P4'], - self['P5'], - self['P6']) = unpack_from( - '<6d', - block, - v2c.CC_COMMON_SHORT_SIZE, - ) - - elif conv_type in ( - v2c.CONVERSION_TYPE_EXPO, - v2c.CONVERSION_TYPE_LOGH): - (self['P1'], - self['P2'], - self['P3'], - self['P4'], - self['P5'], - self['P6'], - self['P7']) = unpack_from( - '<7d', - block, - v2c.CC_COMMON_SHORT_SIZE, - ) - - elif conv_type == v2c.CONVERSION_TYPE_VTAB: - nr = self['ref_param_nr'] - - values = unpack_from( - '<' + 'd32s' * nr, - block, - v2c.CC_COMMON_SHORT_SIZE, - ) - - for i in range(nr): - (self['param_val_{}'.format(i)], - self['text_{}'.format(i)]) = values[i*2], values[2*i+1] - - elif conv_type == v2c.CONVERSION_TYPE_VTABR: - nr = self['ref_param_nr'] - - values = unpack_from( - '<' + '2dI' * nr, - block, - v2c.CC_COMMON_SHORT_SIZE, - ) - for i in range(nr): - (self['lower_{}'.format(i)], - self['upper_{}'.format(i)], - self['text_{}'.format(i)]) = values[i*3], values[3*i+1], values[3*i+2] - except KeyError: - self.address = 0 - self['id'] = 'CC'.encode('latin-1') - - if kargs['conversion_type'] == v2c.CONVERSION_TYPE_NONE: - self['block_len'] = kargs.get( - 'block_len', - v2c.CC_COMMON_BLOCK_SIZE, - ) - self['range_flag'] = kargs.get('range_flag', 1) - self['min_phy_value'] = kargs.get('min_phy_value', 0) - self['max_phy_value'] = kargs.get('max_phy_value', 0) - self['unit'] = kargs.get('unit', ('\0'*20).encode('latin-1')) - self['conversion_type'] = v2c.CONVERSION_TYPE_NONE - self['ref_param_nr'] = kargs.get('ref_param_nr', 0) - - elif kargs['conversion_type'] == v2c.CONVERSION_TYPE_LINEAR: - self['block_len'] = kargs.get( - 'block_len', - v2c.CC_LIN_BLOCK_SIZE, - ) - self['range_flag'] = kargs.get('range_flag', 1) - self['min_phy_value'] = kargs.get('min_phy_value', 0) - self['max_phy_value'] = kargs.get('max_phy_value', 0) - self['unit'] = kargs.get('unit', ('\0'*20).encode('latin-1')) - self['conversion_type'] = v2c.CONVERSION_TYPE_LINEAR - self['ref_param_nr'] = kargs.get('ref_param_nr', 2) - self['b'] = kargs.get('b', 0) - self['a'] = kargs.get('a', 1) - if not self['block_len'] == v2c.CC_LIN_BLOCK_SIZE: - self['CANapeHiddenExtra'] = kargs['CANapeHiddenExtra'] - - elif kargs['conversion_type'] in ( - v2c.CONVERSION_TYPE_POLY, - v2c.CONVERSION_TYPE_RAT): - self['block_len'] = kargs.get( - 'block_len', - v2c.CC_POLY_BLOCK_SIZE, - ) - self['range_flag'] = kargs.get('range_flag', 1) - self['min_phy_value'] = kargs.get('min_phy_value', 0) - self['max_phy_value'] = kargs.get('max_phy_value', 0) - self['unit'] = kargs.get('unit', ('\0'*20).encode('latin-1')) - self['conversion_type'] = kargs.get( - 'conversion_type', - v2c.CONVERSION_TYPE_POLY, - ) - self['ref_param_nr'] = kargs.get('ref_param_nr', 2) - self['P1'] = kargs.get('P1', 0) - self['P2'] = kargs.get('P2', 0) - self['P3'] = kargs.get('P3', 0) - self['P4'] = kargs.get('P4', 0) - self['P5'] = kargs.get('P5', 0) - self['P6'] = kargs.get('P6', 0) - - elif kargs['conversion_type'] in ( - v2c.CONVERSION_TYPE_EXPO, - v2c.CONVERSION_TYPE_LOGH): - self['block_len'] = kargs.get( - 'block_len', - v2c.CC_EXPO_BLOCK_SIZE, - ) - self['range_flag'] = kargs.get('range_flag', 1) - self['min_phy_value'] = kargs.get('min_phy_value', 0) - self['max_phy_value'] = kargs.get('max_phy_value', 0) - self['unit'] = kargs.get('unit', ('\0'*20).encode('latin-1')) - self['conversion_type'] = kargs.get( - 'conversion_type', - v2c.CONVERSION_TYPE_EXPO, - ) - self['ref_param_nr'] = kargs.get('ref_param_nr', 2) - self['P1'] = kargs.get('P1', 0) - self['P2'] = kargs.get('P2', 0) - self['P3'] = kargs.get('P3', 0) - self['P4'] = kargs.get('P4', 0) - self['P5'] = kargs.get('P5', 0) - self['P6'] = kargs.get('P6', 0) - self['P7'] = kargs.get('P7', 0) - - elif kargs['conversion_type'] == v2c.CONVERSION_TYPE_FORMULA: - self['block_len'] = kargs.get( - 'block_len', - v2c.CC_POLY_BLOCK_SIZE, - ) - self['range_flag'] = kargs.get('range_flag', 1) - self['min_phy_value'] = kargs.get('min_phy_value', 0) - self['max_phy_value'] = kargs.get('max_phy_value', 0) - self['unit'] = kargs.get('unit', ('\0'*20).encode('latin-1')) - self['conversion_type'] = kargs.get( - 'conversion_type', - v2c.CONVERSION_TYPE_FORMULA, - ) - self['ref_param_nr'] = kargs.get('ref_param_nr', 2) - self['formula'] = kargs.get('formula', b'X1'+b'\0'*254) - - elif kargs['conversion_type'] in ( - v2c.CONVERSION_TYPE_TABI, - v2c.CONVERSION_TYPE_TABX): - nr = kargs['ref_param_nr'] - self['block_len'] = kargs['block_len'] - self['range_flag'] = kargs.get('range_flag', 1) - self['min_phy_value'] = kargs.get('min_phy_value', 0) - self['max_phy_value'] = kargs.get('max_phy_value', 0) - self['unit'] = kargs.get('unit', ('\0'*20).encode('latin-1')) - self['conversion_type'] = kargs.get( - 'conversion_type', - v2c.CONVERSION_TYPE_TABI, - ) - self['ref_param_nr'] = kargs.get('ref_param_nr', 2) - for i in range(nr): - self['raw_{}'.format(i)] = kargs['raw_{}'.format(i)] - self['phys_{}'.format(i)] = kargs['phys_{}'.format(i)] - - elif kargs['conversion_type'] == v2c.CONVERSION_TYPE_VTAB: - nr = kargs['ref_param_nr'] - self['block_len'] = kargs.get( - 'block_len', - v2c.CC_COMMON_BLOCK_SIZE + 40*nr, - ) - self['range_flag'] = kargs.get('range_flag', 0) - self['min_phy_value'] = kargs.get('min_phy_value', 0) - self['max_phy_value'] = kargs.get('max_phy_value', 0) - self['unit'] = kargs.get('unit', ('\0'*20).encode('latin-1')) - self['conversion_type'] = v2c.CONVERSION_TYPE_VTAB - self['ref_param_nr'] = nr - - for i in range(nr): - self['param_val_{}'.format(i)] = kargs['param_val_{}'.format(i)] - self['text_{}'.format(i)] = kargs['text_{}'.format(i)] - - elif kargs['conversion_type'] == v2c.CONVERSION_TYPE_VTABR: - nr = kargs.get('ref_param_nr', 0) - self['block_len'] = kargs.get( - 'block_len', - v2c.CC_COMMON_BLOCK_SIZE + 20*nr, - ) - self['range_flag'] = kargs.get('range_flag', 0) - self['min_phy_value'] = kargs.get('min_phy_value', 0) - self['max_phy_value'] = kargs.get('max_phy_value', 0) - self['unit'] = kargs.get('unit', ('\0'*20).encode('latin-1')) - self['conversion_type'] = v2c.CONVERSION_TYPE_VTABR - self['ref_param_nr'] = kargs.get('ref_param_nr', 0) - - for i in range(self['ref_param_nr']): - self['lower_{}'.format(i)] = kargs['lower_{}'.format(i)] - self['upper_{}'.format(i)] = kargs['upper_{}'.format(i)] - self['text_{}'.format(i)] = kargs['text_{}'.format(i)] - else: - message = 'Conversion type "{}" not implemented' - message = message.format(kargs['conversion_type']) - raise Exception(message) - - def __bytes__(self): - conv = self['conversion_type'] - - # compute the fmt - if conv == v2c.CONVERSION_TYPE_NONE: - fmt = v2c.FMT_CONVERSION_COMMON - elif conv == v2c.CONVERSION_TYPE_FORMULA: - fmt = v2c.FMT_CONVERSION_FORMULA - elif conv == v2c.CONVERSION_TYPE_LINEAR: - fmt = v2c.FMT_CONVERSION_LINEAR - if not self['block_len'] == v2c.CC_LIN_BLOCK_SIZE: - fmt += '{}s'.format(self['block_len'] - v2c.CC_LIN_BLOCK_SIZE) - elif conv in (v2c.CONVERSION_TYPE_POLY, v2c.CONVERSION_TYPE_RAT): - fmt = v2c.FMT_CONVERSION_POLY_RAT - elif conv in (v2c.CONVERSION_TYPE_EXPO, v2c.CONVERSION_TYPE_LOGH): - fmt = v2c.FMT_CONVERSION_EXPO_LOGH - elif conv in (v2c.CONVERSION_TYPE_TABI, v2c.CONVERSION_TYPE_TABX): - nr = self['ref_param_nr'] - fmt = v2c.FMT_CONVERSION_COMMON + '{}d'.format(nr * 2) - elif conv == v2c.CONVERSION_TYPE_VTABR: - nr = self['ref_param_nr'] - fmt = v2c.FMT_CONVERSION_COMMON + '2dI' * nr - elif conv == v2c.CONVERSION_TYPE_VTAB: - nr = self['ref_param_nr'] - fmt = v2c.FMT_CONVERSION_COMMON + 'd32s' * nr - - # compute the keys only for Python < 3.6 - if PYVERSION_MAJOR < 36: - if conv == v2c.CONVERSION_TYPE_NONE: - keys = v2c.KEYS_CONVESION_NONE - elif conv == v2c.CONVERSION_TYPE_FORMULA: - keys = v2c.KEYS_CONVESION_FORMULA - elif conv == v2c.CONVERSION_TYPE_LINEAR: - keys = v2c.KEYS_CONVESION_LINEAR - if not self['block_len'] == v2c.CC_LIN_BLOCK_SIZE: - keys += ('CANapeHiddenExtra',) - elif conv in (v2c.CONVERSION_TYPE_POLY, v2c.CONVERSION_TYPE_RAT): - keys = v2c.KEYS_CONVESION_POLY_RAT - elif conv in (v2c.CONVERSION_TYPE_EXPO, v2c.CONVERSION_TYPE_LOGH): - keys = v2c.KEYS_CONVESION_EXPO_LOGH - elif conv in (v2c.CONVERSION_TYPE_TABI, v2c.CONVERSION_TYPE_TABX): - nr = self['ref_param_nr'] - keys = list(v2c.KEYS_CONVESION_NONE) - for i in range(nr): - keys.append('raw_{}'.format(i)) - keys.append('phys_{}'.format(i)) - elif conv == v2c.CONVERSION_TYPE_VTABR: - nr = self['ref_param_nr'] - keys = list(v2c.KEYS_CONVESION_NONE) - for i in range(nr): - keys.append('lower_{}'.format(i)) - keys.append('upper_{}'.format(i)) - keys.append('text_{}'.format(i)) - elif conv == v2c.CONVERSION_TYPE_VTAB: - nr = self['ref_param_nr'] - keys = list(v2c.KEYS_CONVESION_NONE) - for i in range(nr): - keys.append('param_val_{}'.format(i)) - keys.append('text_{}'.format(i)) - - if PYVERSION_MAJOR >= 36: - result = pack(fmt, *self.values()) - else: - result = pack(fmt, *[self[key] for key in keys]) - return result - - -class ChannelDependency(dict): - ''' CDBLOCK class derived from *dict* - - Currently the ChannelDependency object can only be created using the - *stream* and *address* keyword parameters when reading from file - - The keys have the following meaning: - - * id - Block type identifier, always "CD" - * block_len - Block size of this block in bytes (entire CDBLOCK) - * dependency_type - Dependency type - * sd_nr - Total number of signals dependencies (m) - * for each dependency there is a group of three keys: - - * dg_{n} - Pointer to the data group block (DGBLOCK) of signal - dependency *n* - * cg_{n} - Pointer to the channel group block (DGBLOCK) of signal - dependency *n* - * ch_{n} - Pointer to the channel block (DGBLOCK) of signal dependency - *n* - - * there can also be optional keys which decribe dimensions for the - N-dimensional dependencies: - - * dim_{n} - Optional: size of dimension *n* for N-dimensional dependency - - Parameters - ---------- - stream : file handle - mdf file handle - address : int - block address inside mdf file - - Attributes - ---------- - address : int - block address inside mdf file - - ''' - __slots__ = ['address', 'referenced_channels'] - def __init__(self, **kargs): - super(ChannelDependency, self).__init__() - - self.referenced_channels = [] - - try: - stream = kargs['stream'] - self.address = address = kargs['address'] - stream.seek(address, SEEK_START) - - (self['id'], - self['block_len'], - self['dependency_type'], - self['sd_nr']) = unpack('<2s3H', stream.read(8)) - - links_size = 3 * 4 * self['sd_nr'] - links = unpack( - '<{}I'.format(3 * self['sd_nr']), - stream.read(links_size), - ) - - for i in range(self['sd_nr']): - self['dg_{}'.format(i)] = links[3*i] - self['cg_{}'.format(i)] = links[3*i+1] - self['ch_{}'.format(i)] = links[3*i+2] - - optional_dims_nr = (self['block_len'] - 8 - links_size) // 2 - if optional_dims_nr: - dims = unpack( - '<{}H'.format(optional_dims_nr), - stream.read(optional_dims_nr * 2), - ) - for i, dim in enumerate(dims): - self['dim_{}'.format(i)] = dim - - except KeyError: - sd_nr = kargs['sd_nr'] - self['id'] = b'CD' - self['block_len'] = 8 + 3 * 4 * sd_nr - self['dependency_type'] = 1 - self['sd_nr'] = sd_nr - for i in range(sd_nr): - self['dg_{}'.format(i)] = 0 - self['cg_{}'.format(i)] = 0 - self['ch_{}'.format(i)] = 0 - i = 0 - while True: - try: - self['dim_{}'.format(i)] = kargs['dim_{}'.format(i)] - i += 1 - except KeyError: - break - if i: - self['dependency_type'] = 256 + i - self['block_len'] += 2 * i - - def __bytes__(self): - fmt = '<2s3H{}I'.format(self['sd_nr'] * 3) - keys = ('id', 'block_len', 'dependency_type', 'sd_nr') - for i in range(self['sd_nr']): - keys += ('dg_{}'.format(i), 'cg_{}'.format(i), 'ch_{}'.format(i)) - links_size = 3 * 4 * self['sd_nr'] - option_dims_nr = (self['block_len'] - 8 - links_size) // 2 - if option_dims_nr: - fmt += '{}H'.format(option_dims_nr) - keys += tuple('dim_{}'.format(i) for i in range(option_dims_nr)) - if PYVERSION_MAJOR >= 36: - result = pack(fmt, *self.values()) - else: - result = pack(fmt, *[self[key] for key in keys]) - return result - - -class ChannelExtension(dict): - ''' CEBLOCK class derived from *dict* - - The ChannelExtension object can be created in two modes: - - * using the *stream* and *address* keyword parameters - when reading from - file - * using any of the following presented keys - when creating a new - ChannelExtension - - The first keys are common for all conversion types, and are followed by - conversion specific keys. The keys have the following meaning: - - * common keys - - * id - Block type identifier, always "CE" - * block_len - Block size of this block in bytes (entire CEBLOCK) - * type - Extension type identifier - - * specific keys - - * for DIM block - - * module_nr - Number of module - * module_address - Address - * description - Description - * ECU_identification - Identification of ECU - * reserved0' - reserved - - * for Vector CAN block - - * CAN_id - Identifier of CAN message - * CAN_ch_index - Index of CAN channel - * message_name - Name of message (string should be terminated by 0) - * sender_name - Name of sender (string should be terminated by 0) - * reserved0 - reserved - - Parameters - ---------- - stream : file handle - mdf file handle - address : int - block address inside mdf file - - Attributes - ---------- - address : int - block address inside mdf file - - ''' - __slots__ = ['address',] - def __init__(self, **kargs): - super(ChannelExtension, self).__init__() - - try: - stream = kargs['stream'] - self.address = address = kargs['address'] - stream.seek(address, SEEK_START) - (self['id'], - self['block_len'], - self['type']) = unpack(v2c.FMT_SOURCE_COMMON, stream.read(6)) - block = stream.read(self['block_len'] - 6) - - if self['type'] == v2c.SOURCE_ECU: - (self['module_nr'], - self['module_address'], - self['description'], - self['ECU_identification'], - self['reserved0']) = unpack(v2c.FMT_SOURCE_EXTRA_ECU, block) - elif self['type'] == v2c.SOURCE_VECTOR: - (self['CAN_id'], - self['CAN_ch_index'], - self['message_name'], - self['sender_name'], - self['reserved0']) = unpack(v2c.FMT_SOURCE_EXTRA_VECTOR, block) - except KeyError: - - self.address = 0 - self['id'] = kargs.get('id', 'CE'.encode('latin-1')) - self['block_len'] = kargs.get('block_len', v2c.CE_BLOCK_SIZE) - self['type'] = kargs.get('type', 2) - if self['type'] == v2c.SOURCE_ECU: - self['module_nr'] = kargs.get('module_nr', 0) - self['module_address'] = kargs.get('module_address', 0) - self['description'] = kargs.get('description', b'\0') - self['ECU_identification'] = kargs.get( - 'ECU_identification', - b'\0', - ) - self['reserved0'] = kargs.get('reserved0', b'\0') - elif self['type'] == v2c.SOURCE_VECTOR: - self['CAN_id'] = kargs.get('CAN_id', 0) - self['CAN_ch_index'] = kargs.get('CAN_ch_index', 0) - self['message_name'] = kargs.get('message_name', b'\0') - self['sender_name'] = kargs.get('sender_name', b'\0') - self['reserved0'] = kargs.get('reserved0', b'\0') - - def __bytes__(self): - typ = self['type'] - if typ == v2c.SOURCE_ECU: - fmt = v2c.FMT_SOURCE_ECU - keys = v2c.KEYS_SOURCE_ECU - else: - fmt = v2c.FMT_SOURCE_VECTOR - keys = v2c.KEYS_SOURCE_VECTOR - - if PYVERSION_MAJOR >= 36: - result = pack(fmt, *self.values()) - else: - result = pack(fmt, *[self[key] for key in keys]) - return result - - -class ChannelGroup(dict): - ''' CGBLOCK class derived from *dict* - - The ChannelGroup object can be created in two modes: - - * using the *stream* and *address* keyword parameters - when reading from - file - * using any of the following presented keys - when creating a new - ChannelGroup - - The keys have the following meaning: - - * id - Block type identifier, always "CG" - * block_len - Block size of this block in bytes (entire CGBLOCK) - * next_cg_addr - Pointer to next channel group block (CGBLOCK) (NIL allowed) - * first_ch_addr - Pointer to first channel block (CNBLOCK) (NIL allowed) - * comment_addr - Pointer to channel group comment text (TXBLOCK) - (NIL allowed) - * record_id - Record ID, i.e. value of the identifier for a record if the - DGBLOCK defines a number of record IDs > 0 - * ch_nr - Number of channels (redundant information) - * samples_byte_nr - Size of data record in Bytes (without record ID), i.e. - size of plain data for a each recorded sample of this channel group - * cycles_nr - Number of records of this type in the data block i.e. number - of samples for this channel group - * sample_reduction_addr - only since version 3.3. Pointer to first sample - reduction block (SRBLOCK) (NIL allowed) Default value: NIL. - - Parameters - ---------- - stream : file handle - mdf file handle - address : int - block address inside mdf file - - Attributes - ---------- - address : int - block address inside mdf file - - Examples - -------- - >>> with open('test.mdf', 'rb') as mdf: - ... cg1 = ChannelGroup(stream=mdf, address=0xBA52) - >>> cg2 = ChannelGroup(sample_bytes_nr=32) - >>> hex(cg1.address) - 0xBA52 - >>> cg1['id'] - b'CG' - - ''' - __slots__ = ['address',] - def __init__(self, **kargs): - super(ChannelGroup, self).__init__() - - try: - - stream = kargs['stream'] - self.address = address = kargs['address'] - stream.seek(address, SEEK_START) - block = stream.read(v2c.CG_BLOCK_SIZE) - - (self['id'], - self['block_len'], - self['next_cg_addr'], - self['first_ch_addr'], - self['comment_addr'], - self['record_id'], - self['ch_nr'], - self['samples_byte_nr'], - self['cycles_nr']) = unpack(v2c.FMT_CHANNEL_GROUP, block) - if self['block_len'] == v2c.CG33_BLOCK_SIZE: - self['sample_reduction_addr'] = unpack('= 36: - result = pack(fmt, *self.values()) - else: - result = pack(fmt, *[self[key] for key in keys]) - return result - -class DataBlock(dict): - """Data Block class derived from *dict* - - The DataBlock object can be created in two modes: - - * using the *stream*, *address* and *size* keyword parameters - when reading - from file - * using any of the following presented keys - when creating a new - ChannelGroup - - The keys have the following meaning: - - * data - bytes block - - Attributes - ---------- - address : int - block address - - Parameters - ---------- - address : int - block address inside the measurement file - stream : file.io.handle - binary file stream - - """ - __slots__ = ['address',] - def __init__(self, **kargs): - super(DataBlock, self).__init__() - - try: - stream = kargs['stream'] - size = kargs['size'] - self.address = address = kargs['address'] - stream.seek(address, SEEK_START) - - self['data'] = stream.read(size) - - except KeyError: - self.address = 0 - self['data'] = kargs.get('data', b'') - - def __bytes__(self): - return self['data'] - - -class DataGroup(dict): - ''' DGBLOCK class derived from *dict* - - The DataGroup object can be created in two modes: - - * using the *stream* and *address* keyword parameters - when reading from - file - * using any of the following presented keys - when creating a new DataGroup - - The keys have the following meaning: - - * id - Block type identifier, always "DG" - * block_len - Block size of this block in bytes (entire DGBLOCK) - * next_dg_addr - Pointer to next data group block (DGBLOCK) (NIL allowed) - * first_cg_addr - Pointer to first channel group block (CGBLOCK) - (NIL allowed) - * trigger_addr - Pointer to trigger block (TRBLOCK) (NIL allowed) - * data_block_addr - Pointer to the data block - * cg_nr - Number of channel groups (redundant information) - * record_id_nr - Number of record IDs in the data block - * reserved0 - since version 3.2; Reserved - - Parameters - ---------- - stream : file handle - mdf file handle - address : int - block address inside mdf file - - Attributes - ---------- - address : int - block address inside mdf file - - ''' - __slots__ = ['address',] - def __init__(self, **kargs): - super(DataGroup, self).__init__() - - try: - stream = kargs['stream'] - self.address = address = kargs['address'] - stream.seek(address, SEEK_START) - block = stream.read(v2c.DG31_BLOCK_SIZE) - - (self['id'], - self['block_len'], - self['next_dg_addr'], - self['first_cg_addr'], - self['trigger_addr'], - self['data_block_addr'], - self['cg_nr'], - self['record_id_nr']) = unpack(v2c.FMT_DATA_GROUP, block) - - if self['block_len'] == v2c.DG32_BLOCK_SIZE: - self['reserved0'] = stream.read(4) - - except KeyError: - self.address = 0 - self['id'] = kargs.get('id', 'DG'.encode('latin-1')) - self['block_len'] = kargs.get('block_len', v2c. DG32_BLOCK_SIZE) - self['next_dg_addr'] = kargs.get('next_dg_addr', 0) - self['first_cg_addr'] = kargs.get('first_cg_addr', 0) - self['trigger_addr'] = kargs.get('comment_addr', 0) - self['data_block_addr'] = kargs.get('data_block_addr', 0) - self['cg_nr'] = kargs.get('cg_nr', 1) - self['record_id_nr'] = kargs.get('record_id_nr', 0) - if self['block_len'] == v2c.DG32_BLOCK_SIZE: - self['reserved0'] = b'\0\0\0\0' - - def __bytes__(self): - if self['block_len'] == v2c.DG32_BLOCK_SIZE: - fmt = v2c.FMT_DATA_GROUP_32 - keys = v2c.KEYS_DATA_GROUP_32 - else: - fmt = v2c.FMT_DATA_GROUP - keys = v2c.KEYS_DATA_GROUP - if PYVERSION_MAJOR >= 36: - result = pack(fmt, *self.values()) - else: - result = pack(fmt, *[self[key] for key in keys]) - return result - - -class FileIdentificationBlock(dict): - ''' IDBLOCK class derived from *dict* - - The TriggerBlock object can be created in two modes: - - * using the *stream* and *address* keyword parameters - when reading from - file - * using the classmethod *from_text* - - The keys have the following meaning: - - * file_identification - file identifier - * version_str - format identifier - * program_identification - program identifier - * byte_order - default byte order - * float_format - default floating-point format - * mdf_version - version number of MDF format - * code_page - code page number - * reserved0 - reserved - * reserved1 - reserved - * unfinalized_standard_flags - Standard Flags for unfinalized MDF - * unfinalized_custom_flags - Custom Flags for unfinalized MDF - - Parameters - ---------- - stream : file handle - mdf file handle - version : int - mdf version in case of new file - - Attributes - ---------- - address : int - block address inside mdf file; should be 0 always - - ''' - __slots__ = ['address',] - def __init__(self, **kargs): - super(FileIdentificationBlock, self).__init__() - - self.address = 0 - try: - - stream = kargs['stream'] - stream.seek(0, SEEK_START) - - (self['file_identification'], - self['version_str'], - self['program_identification'], - self['byte_order'], - self['float_format'], - self['mdf_version'], - self['code_page'], - self['reserved0'], - self['reserved1'], - self['unfinalized_standard_flags'], - self['unfinalized_custom_flags']) = unpack( - v2c.ID_FMT, - stream.read(v2c.ID_BLOCK_SIZE), - ) - except KeyError: - version = kargs['version'] - self['file_identification'] = 'MDF '.encode('latin-1') - self['version_str'] = version.encode('latin-1') + b'\0' * 4 - self['program_identification'] = 'Python '.encode('latin-1') - self['byte_order'] = v2c.BYTE_ORDER_INTEL - self['float_format'] = 0 - self['mdf_version'] = int(version.replace('.', '')) - self['code_page'] = 0 - self['reserved0'] = b'\0' * 2 - self['reserved1'] = b'\0' * 26 - self['unfinalized_standard_flags'] = 0 - self['unfinalized_custom_flags'] = 0 - - def __bytes__(self): - if PYVERSION_MAJOR >= 36: - result = pack(v2c.ID_FMT, *self.values()) - else: - result = pack( - v2c.ID_FMT, - *[self[key] for key in v2c.ID_KEYS] - ) - return result - - -class HeaderBlock(dict): - ''' HDBLOCK class derived from *dict* - - The TriggerBlock object can be created in two modes: - - * using the *stream* - when reading from file - * using the classmethod *from_text* - - The keys have the following meaning: - - * id - Block type identifier, always "HD" - * block_len - Block size of this block in bytes (entire HDBLOCK) - * first_dg_addr - Pointer to the first data group block (DGBLOCK) - * comment_addr - Pointer to the measurement file comment text (TXBLOCK) (NIL - allowed) - * program_addr - Pointer to program block (PRBLOCK) (NIL allowed) - * dg_nr - Number of data groups (redundant information) - * date - Date at which the recording was started in "DD:MM:YYYY" format - * time - Time at which the recording was started in "HH:MM:SS" format - * author - author name - * organization - organization - * project - project name - * subject - subject - - Since version 3.2 the following extra keys were added: - - * abs_time - Time stamp at which recording was started in nanoseconds. - * tz_offset - UTC time offset in hours (= GMT time zone) - * time_quality - Time quality class - * timer_identification - Timer identification (time source), - - Parameters - ---------- - stream : file handle - mdf file handle - - Attributes - ---------- - address : int - block address inside mdf file; should be 64 always - - ''' - __slots__ = ['address',] - def __init__(self, **kargs): - super(HeaderBlock, self).__init__() - - self.address = 64 - try: - - stream = kargs['stream'] - stream.seek(64, SEEK_START) - - (self['id'], - self['block_len'], - self['first_dg_addr'], - self['comment_addr'], - self['program_addr'], - self['dg_nr'], - self['date'], - self['time'], - self['author'], - self['organization'], - self['project'], - self['subject']) = unpack( - v2c.HEADER_COMMON_FMT, - stream.read(v2c.HEADER_COMMON_SIZE), - ) - - if self['block_len'] > v2c.HEADER_COMMON_SIZE: - (self['abs_time'], - self['tz_offset'], - self['time_quality'], - self['timer_identification']) = unpack( - v2c.HEADER_POST_320_EXTRA_FMT, - stream.read(v2c.HEADER_POST_320_EXTRA_SIZE), - ) - - except KeyError: - self['id'] = 'HD'.encode('latin-1') - self['block_len'] = 164 - self['first_dg_addr'] = 0 - self['comment_addr'] = 0 - self['program_addr'] = 0 - self['dg_nr'] = 0 - t1 = time.time() * 10**9 - t2 = time.gmtime() - self['date'] = '{:\0<10}'.format(time.strftime('%d:%m:%Y', t2)).encode('latin-1') - self['time'] = '{:\0<8}'.format(time.strftime('%X', t2)).encode('latin-1') - self['author'] = '{:\0<32}'.format(getuser()).encode('latin-1') - self['organization'] = '{:\0<32}'.format('').encode('latin-1') - self['project'] = '{:\0<32}'.format('').encode('latin-1') - self['subject'] = '{:\0<32}'.format('').encode('latin-1') - - if self['block_len'] > v2c.HEADER_COMMON_SIZE: - self['abs_time'] = int(t1) - self['tz_offset'] = 2 - self['time_quality'] = 0 - self['timer_identification'] = '{:\0<32}'.format('Local PC Reference Time').encode('latin-1') - - def __bytes__(self): - fmt = v2c.HEADER_COMMON_FMT - keys = v2c.HEADER_COMMON_KEYS - if self['block_len'] > v2c.HEADER_COMMON_SIZE: - fmt += v2c.HEADER_POST_320_EXTRA_FMT - keys += v2c.HEADER_POST_320_EXTRA_KEYS - if PYVERSION_MAJOR >= 36: - result = pack(fmt, *self.values()) - else: - result = pack(fmt, *[self[key] for key in keys]) - return result - - -class ProgramBlock(dict): - ''' PRBLOCK class derived from *dict* - - The ProgramBlock object can be created in two modes: - - * using the *stream* and *address* keyword parameters - when reading from - file - * using any of the following presented keys - when creating a new - ProgramBlock - - The keys have the following meaning: - - * id - Block type identifier, always "PR" - * block_len - Block size of this block in bytes (entire PRBLOCK) - * data - Program-specific data - - Parameters - ---------- - stream : file handle - mdf file handle - address : int - block address inside mdf file - - Attributes - ---------- - address : int - block address inside mdf file - - ''' - __slots__ = ['address',] - def __init__(self, **kargs): - super(ProgramBlock, self).__init__() - - try: - stream = kargs['stream'] - self.address = address = kargs['address'] - stream.seek(address, SEEK_START) - - (self['id'], - self['block_len']) = unpack('<2sH', stream.read(4)) - self['data'] = stream.read(self['block_len'] - 4) - - except KeyError: - pass - - def __bytes__(self): - fmt = v2c.FMT_PROGRAM_BLOCK.format(self['block_len']) - if PYVERSION_MAJOR >= 36: - result = pack(fmt, *self.values()) - else: - result = pack(fmt, *[self[key] for key in v2c.KEYS_PROGRAM_BLOCK]) - return result - - -class SampleReduction(dict): - ''' SRBLOCK class derived from *dict* - - Currently the SampleReduction object can only be created by using the - *stream* and *address* keyword parameters - when reading from file - - The keys have the following meaning: - - * id - Block type identifier, always "SR" - * block_len - Block size of this block in bytes (entire SRBLOCK) - * next_sr_addr - Pointer to next sample reduction block (SRBLOCK) (NIL - allowed) - * data_block_addr - Pointer to the data block for this sample reduction - * cycles_nr - Number of reduced samples in the data block. - * time_interval - Length of time interval [s] used to calculate the reduced - samples. - - Parameters - ---------- - stream : file handle - mdf file handle - address : int - block address inside mdf file - - Attributes - ---------- - address : int - block address inside mdf file - - ''' - __slots__ = ['address',] - def __init__(self, **kargs): - super(SampleReduction, self).__init__() - - try: - stream = kargs['stream'] - self.address = address = kargs['address'] - stream.seek(address, SEEK_START) - - (self['id'], - self['block_len'], - self['next_sr_addr'], - self['data_block_addr'], - self['cycles_nr'], - self['time_interval']) = unpack( - v2c.FMT_SAMPLE_REDUCTION_BLOCK, - stream.read(v2c.SR_BLOCK_SIZE), - ) - - except KeyError: - pass - - def __bytes__(self): - result = pack( - v2c.FMT_SAMPLE_REDUCTION_BLOCK, - *[self[key] for key in v2c.KEYS_SAMPLE_REDUCTION_BLOCK] - ) - return result - - -class TextBlock(dict): - ''' TXBLOCK class derived from *dict* - - The ProgramBlock object can be created in two modes: - - * using the *stream* and *address* keyword parameters - when reading from - file - * using the classmethod *from_text* - - The keys have the following meaning: - - * id - Block type identifier, always "TX" - * block_len - Block size of this block in bytes (entire TXBLOCK) - * text - Text (new line indicated by CR and LF; end of text indicated by 0) - - Parameters - ---------- - stream : file handle - mdf file handle - address : int - block address inside mdf file - text : bytes - bytes for creating a new TextBlock - - Attributes - ---------- - address : int - block address inside mdf file - text_str : str - text data as unicode string - - Examples - -------- - >>> tx1 = TextBlock.from_text('VehicleSpeed') - >>> tx1.text_str - 'VehicleSpeed' - >>> tx1['text'] - b'VehicleSpeed' - - ''' - __slots__ = ['address',] - def __init__(self, **kargs): - super(TextBlock, self).__init__() - try: - stream = kargs['stream'] - self.address = address = kargs['address'] - - stream.seek(address, SEEK_START) - (self['id'], - self['block_len']) = unpack('<2sH', stream.read(4)) - size = self['block_len'] - 4 - self['text'] = stream.read(size) - - except KeyError: - self.address = 0 - text = kargs['text'] - - if PYVERSION == 3: - try: - text = text.encode('utf-8') - except AttributeError: - pass - else: - try: - text = text.encode('utf-8') - except (AttributeError, UnicodeDecodeError): - pass - - self['id'] = b'TX' - self['block_len'] = len(text) + 4 + 1 - self['text'] = text + b'\0' - - def __bytes__(self): - if PYVERSION_MAJOR >= 36: - result = pack( - '<2sH{}s'.format(self['block_len']-4), - *self.values() - ) - else: - result = pack( - '<2sH{}s'.format(self['block_len']-4), - *[self[key] for key in v2c.KEYS_TEXT_BLOCK] - ) - return result - - -class TriggerBlock(dict): - ''' TRBLOCK class derived from *dict* - - The TriggerBlock object can be created in two modes: - - * using the *stream* and *address* keyword parameters - when reading from - file - * using the classmethod *from_text* - - The keys have the following meaning: - - * id - Block type identifier, always "TX" - * block_len - Block size of this block in bytes (entire TRBLOCK) - * text_addr - Pointer to trigger comment text (TXBLOCK) (NIL allowed) - * trigger_events_nr - Number of trigger events n (0 allowed) - * trigger_{n}_time - Trigger time [s] of trigger event *n* - * trigger_{n}_pretime - Pre trigger time [s] of trigger event *n* - * trigger_{n}_posttime - Post trigger time [s] of trigger event *n* - - Parameters - ---------- - stream : file handle - mdf file handle - address : int - block address inside mdf file - - Attributes - ---------- - address : int - block address inside mdf file - - ''' - __slots__ = ['address',] - def __init__(self, **kargs): - super(TriggerBlock, self).__init__() - - try: - self.address = address = kargs['address'] - stream = kargs['stream'] - - stream.seek(address + 2, SEEK_START) - size = unpack('= 36: - result = pack(fmt, *self.values()) - else: - result = pack(fmt, *[self[key] for key in keys]) - return result diff --git a/asammdf/v2constants.py b/asammdf/v2constants.py deleted file mode 100644 index cd9f2fef0..000000000 --- a/asammdf/v2constants.py +++ /dev/null @@ -1,345 +0,0 @@ -# -*- coding: utf-8 -*- -""" MDF v2 constants """ - -# byte order -BYTE_ORDER_INTEL = 0 -BYTE_ORDER_MOTOROLA = 1 - -# data types -DATA_TYPE_UNSIGNED = 0 -DATA_TYPE_SIGNED = 1 -DATA_TYPE_FLOAT = 2 -DATA_TYPE_DOUBLE = 3 -DATA_TYPE_STRING = 7 -DATA_TYPE_BYTEARRAY = 8 -DATA_TYPE_UNSIGNED_INTEL = 13 -DATA_TYPE_UNSIGNED_MOTOROLA = 9 -DATA_TYPE_SIGNED_INTEL = 14 -DATA_TYPE_SIGNED_MOTOROLA = 10 -DATA_TYPE_FLOAT_INTEL = 15 -DATA_TYPE_FLOAT_MOTOROLA = 11 -DATA_TYPE_DOUBLE_INTEL = 16 -DATA_TYPE_DOUBLE_MOTOROLA = 12 - -SIGNED_INT = { - DATA_TYPE_SIGNED, - DATA_TYPE_SIGNED_INTEL, - DATA_TYPE_SIGNED_MOTOROLA, -} -STANDARD_INT_SIZES = {8, 16, 32, 64} - -INT_TYPES = { - DATA_TYPE_UNSIGNED, - DATA_TYPE_SIGNED, - DATA_TYPE_UNSIGNED_INTEL, - DATA_TYPE_UNSIGNED_MOTOROLA, - DATA_TYPE_SIGNED_INTEL, - DATA_TYPE_SIGNED_MOTOROLA, -} - -# channel types -CHANNEL_TYPE_VALUE = 0 -CHANNEL_TYPE_MASTER = 1 - -# channel conversion types -CONVERSION_TYPE_NONE = 65535 -CONVERSION_TYPE_LINEAR = 0 -CONVERSION_TYPE_TABI = 1 -CONVERSION_TYPE_TABX = 2 -CONVERSION_TYPE_POLY = 6 -CONVERSION_TYPE_EXPO = 7 -CONVERSION_TYPE_LOGH = 8 -CONVERSION_TYPE_RAT = 9 -CONVERSION_TYPE_FORMULA = 10 -CONVERSION_TYPE_VTAB = 11 -CONVERSION_TYPE_VTABR = 12 - -RAT_CONV_TEXT = '(P1 * X**2 + P2 * X + P3) / (P4 * X**2 + P5 * X + P6)' -POLY_CONV_SHORT_TEXT = 'P4 * X / P1' -POLY_CONV_LONG_TEXT = '(P2 - (P4 * (X - P5 -P6))) / (P3* (X - P5 - P6) - P1)' - -DEPENDENCY_TYPE_NONE = 0 -DEPENDENCY_TYPE_VECTOR = 1 -DEPENDENCY_TYPE_NDIM = 256 - -# flags -FLAG_PRECISION = 1 -FLAG_PHY_RANGE_OK = 2 -FLAG_VAL_RANGE_OK = 8 - -# channel source types -SOURCE_ECU = 2 -SOURCE_VECTOR = 19 - -# bus types -BUS_TYPE_NONE = 0 -BUS_TYPE_CAN = 2 -BUS_TYPE_FLEXRAY = 5 - -# file IO seek types -SEEK_START = 0 -SEEK_REL = 1 -SEEK_END = 2 - -# blocks size -ID_BLOCK_SIZE = 64 -HEADER_COMMON_SIZE = 164 -HEADER_POST_320_EXTRA_SIZE = 44 -CE_BLOCK_SIZE = 128 -FH_BLOCK_SIZE = 56 -DG31_BLOCK_SIZE = 24 -DG32_BLOCK_SIZE = 28 -HD_BLOCK_SIZE = 104 -CN20_BLOCK_SIZE = 218 -CN21_BLOCK_SIZE = 222 -CG_BLOCK_SIZE = 26 -CG33_BLOCK_SIZE = 30 -DT_BLOCK_SIZE = 24 -CC_COMMON_BLOCK_SIZE = 46 -CC_COMMON_SHORT_SIZE = 42 -CC_ALG_BLOCK_SIZE = 88 -CC_LIN_BLOCK_SIZE = 62 -CC_POLY_BLOCK_SIZE = 94 -CC_EXPO_BLOCK_SIZE = 102 -CC_FORMULA_BLOCK_SIZE = 304 -SR_BLOCK_SIZE = 156 - -# max int values -MAX_UINT8 = 2 << 8 - 1 -MAX_UINT16 = 2 << 16 - 1 -MAX_UNIT32 = 2 << 32 - 1 -MAX_UINT64 = 2 << 64 - 1 - -# data location -LOCATION_ORIGINAL_FILE = 0 -LOCATION_TEMPORARY_FILE = 1 -LOCATION_MEMORY = 2 - -# blocks struct fmts and keys -ID_FMT = '<8s8s8s4H2s26s2H' -ID_KEYS = ( - 'file_identification', - 'version_str', - 'program_identification', - 'byte_order', - 'float_format', - 'mdf_version', - 'code_page', - 'reserved0', - 'reserved1', - 'unfinalized_standard_flags', - 'unfinalized_custom_flags', -) - -HEADER_COMMON_FMT = '<2sH3IH10s8s32s32s32s32s' -HEADER_COMMON_KEYS = ( - 'id', - 'block_len', - 'first_dg_addr', - 'comment_addr', - 'program_addr', - 'dg_nr', - 'date', - 'time', - 'author', - 'organization', - 'project', - 'subject', -) - -HEADER_POST_320_EXTRA_FMT = 'Q2H32s' -HEADER_POST_320_EXTRA_KEYS = ( - 'abs_time', - 'tz_offset', - 'time_quality', - 'timer_identification', -) - -FMT_CHANNEL_20 = '<2sH5IH32s128s4H3d' -FMT_CHANNEL_21 = FMT_CHANNEL_20 + 'I' -KEYS_CHANNEL_20 = ( - 'id', - 'block_len', - 'next_ch_addr', - 'conversion_addr', - 'source_depend_addr', - 'ch_depend_addr', - 'comment_addr', - 'channel_type', - 'short_name', - 'description', - 'start_offset', - 'bit_count', - 'data_type', - 'range_flag', - 'min_raw_value', - 'max_raw_value', - 'sampling_rate', -) -KEYS_CHANNEL_21 = KEYS_CHANNEL_20 + ('long_name_addr', ) - -FMT_CHANNEL_GROUP = '<2sH3I3HI' -KEYS_CHANNEL_GROUP = ( - 'id', - 'block_len', - 'next_cg_addr', - 'first_ch_addr', - 'comment_addr', - 'record_id', - 'ch_nr', - 'samples_byte_nr', - 'cycles_nr', -) - -FMT_DATA_GROUP_32 = '<2sH4I2H4s' -KEYS_DATA_GROUP_32 = ( - 'id', - 'block_len', - 'next_dg_addr', - 'first_cg_addr', - 'trigger_addr', - 'data_block_addr', - 'cg_nr', - 'record_id_nr', - 'reserved0', -) - -FMT_DATA_GROUP = '<2sH4I2H' -KEYS_DATA_GROUP = ( - 'id', - 'block_len', - 'next_dg_addr', - 'first_cg_addr', - 'trigger_addr', - 'data_block_addr', - 'cg_nr', - 'record_id_nr', -) - -FMT_SOURCE_COMMON = '<2s2H' -FMT_SOURCE_ECU = '<2s3HI80s32s4s' -FMT_SOURCE_EXTRA_ECU = ' Date: Sat, 23 Dec 2017 00:01:51 +0200 Subject: [PATCH 035/117] update major version number --- asammdf/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/asammdf/version.py b/asammdf/version.py index 52be6e575..b29834508 100644 --- a/asammdf/version.py +++ b/asammdf/version.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- """ asammdf version module """ -__version__ = '2.8.2dev' +__version__ = '3.0.0dev' From 05e494b1a05da403a37f39e0961180ca8934a7ca Mon Sep 17 00:00:00 2001 From: danielhrisca Date: Sat, 23 Dec 2017 00:12:36 +0200 Subject: [PATCH 036/117] update documentation and fix import errors --- asammdf/v2_v3_blocks.py | 2 +- asammdf/v4_blocks.py | 2 +- benchmarks/bench.py | 36 ++++----- documentation/mdf.rst | 13 ++-- documentation/{mdf2.rst => mdf23.rst} | 14 ++-- documentation/mdf3.rst | 76 ------------------- documentation/mdf4.rst | 2 +- .../{v2blocks.rst => v2v3blocks.rst} | 24 +++--- documentation/v3blocks.rst | 71 ----------------- documentation/v4blocks.rst | 26 +++---- 10 files changed, 59 insertions(+), 207 deletions(-) rename documentation/{mdf2.rst => mdf23.rst} (95%) delete mode 100644 documentation/mdf3.rst rename documentation/{v2blocks.rst => v2v3blocks.rst} (62%) delete mode 100644 documentation/v3blocks.rst diff --git a/asammdf/v2_v3_blocks.py b/asammdf/v2_v3_blocks.py index 5fd0a159e..e9bd8a534 100644 --- a/asammdf/v2_v3_blocks.py +++ b/asammdf/v2_v3_blocks.py @@ -8,7 +8,7 @@ from struct import unpack, pack, unpack_from from getpass import getuser -from . import v23constants as v23c +from . import v2_v3_constants as v23c PYVERSION = sys.version_info[0] diff --git a/asammdf/v4_blocks.py b/asammdf/v4_blocks.py index 4653a146a..4c7f94e0b 100644 --- a/asammdf/v4_blocks.py +++ b/asammdf/v4_blocks.py @@ -15,7 +15,7 @@ import numpy as np -from . import v4constants as v4c +from . import v4_constants as v4c PYVERSION = sys.version_info[0] PYVERSION_MAJOR = sys.version_info[0] * 10 + sys.version_info[1] diff --git a/benchmarks/bench.py b/benchmarks/bench.py index b1ad8df19..1b0105e55 100644 --- a/benchmarks/bench.py +++ b/benchmarks/bench.py @@ -612,15 +612,15 @@ def main(path, text_output, fmt): output.extend(table_end(fmt)) tests = ( -# partial(get_all_mdf3, memory='full'), -# partial(get_all_mdf3, memory='low'), -# partial(get_all_mdf3, memory='minimum'), + partial(get_all_mdf3, memory='full'), + partial(get_all_mdf3, memory='low'), + partial(get_all_mdf3, memory='minimum'), # get_all_reader3, # get_all_reader3_nodata, # get_all_reader3_compression, -# partial(get_all_mdf4, memory='full'), -# partial(get_all_mdf4, memory='low'), -# partial(get_all_mdf4, memory='minimum'), + partial(get_all_mdf4, memory='full'), + partial(get_all_mdf4, memory='low'), + partial(get_all_mdf4, memory='minimum'), # get_all_reader4, # get_all_reader4_nodata, # get_all_reader4_compression, @@ -638,12 +638,12 @@ def main(path, text_output, fmt): output.extend(table_end(fmt)) tests = ( -# partial(convert_v3_v4, memory='full'), -# partial(convert_v3_v4, memory='low'), -# partial(convert_v3_v4, memory='minimum'), -# partial(convert_v4_v3, memory='full'), -# partial(convert_v4_v3, memory='low'), -# partial(convert_v4_v3, memory='minimum'), + partial(convert_v3_v4, memory='full'), + partial(convert_v3_v4, memory='low'), + partial(convert_v3_v4, memory='minimum'), + partial(convert_v4_v3, memory='full'), + partial(convert_v4_v3, memory='low'), + partial(convert_v4_v3, memory='minimum'), ) if tests: @@ -658,15 +658,15 @@ def main(path, text_output, fmt): output.extend(table_end(fmt)) tests = ( -# partial(merge_v3, memory='full'), -# partial(merge_v3, memory='low'), -# partial(merge_v3, memory='minimum'), + partial(merge_v3, memory='full'), + partial(merge_v3, memory='low'), + partial(merge_v3, memory='minimum'), # merge_reader_v3, # merge_reader_v3_compress, # merge_reader_v3_nodata, -# partial(merge_v4, memory='full'), -# partial(merge_v4, memory='low'), -# partial(merge_v4, memory='minimum'), + partial(merge_v4, memory='full'), + partial(merge_v4, memory='low'), + partial(merge_v4, memory='minimum'), # merge_reader_v4, # merge_reader_v4_nodata, # merge_reader_v4_compress, diff --git a/documentation/mdf.rst b/documentation/mdf.rst index 75f952ac1..a3fef2a9a 100644 --- a/documentation/mdf.rst +++ b/documentation/mdf.rst @@ -21,9 +21,9 @@ MDF === -This class acts as a proxy for the MDF3 and MDF4 classes. -All attribute access is delegated to the underlying *_mdf* attribute (MDF3 or MDF4 object). -See MDF3 and MDF4 for available extra methods. +This class acts as a proxy for the MDF23 and MDF4 classes. +All attribute access is delegated to the underlying *_mdf* attribute (MDF23 or MDF4 object). +See MDF23 and MDF4 for available extra methods. An empty MDF file is created if the *name* argument is not provided. If the *name* argument is provided then the file must exist in the filesystem, otherwise an exception is raised. @@ -40,14 +40,13 @@ Best practice is to use the MDF as a context manager. This way all resources are :members: -MDF2, MDF3 and MDF4 classes ---------------------------- +MDF23 and MDF4 classes +---------------------- .. toctree:: :maxdepth: 1 - mdf2 - mdf3 + mdf23 mdf4 Notes about *memory* argument diff --git a/documentation/mdf2.rst b/documentation/mdf23.rst similarity index 95% rename from documentation/mdf2.rst rename to documentation/mdf23.rst index 2e9393308..a3c3a1075 100644 --- a/documentation/mdf2.rst +++ b/documentation/mdf23.rst @@ -16,10 +16,10 @@ .. role:: orange .. role:: brown -.. _mdf2: +.. _mdf23: -MDF2 -==== +MDF23 +===== asammdf tries to emulate the mdf structure using Python builtin data types. @@ -63,14 +63,14 @@ The *master_db* attibute is a dictionary that holds the *channel index* of the API --- -.. autoclass:: asammdf.mdf2.MDF2 +.. autoclass:: asammdf.mdf_v2_v3.MDF23 :members: :noindex: -MDF version 2 blocks --------------------- +MDF version 2 & 3 blocks +------------------------ .. toctree:: :maxdepth: 2 - v2blocks + v2v3blocks diff --git a/documentation/mdf3.rst b/documentation/mdf3.rst deleted file mode 100644 index 07ca52ab2..000000000 --- a/documentation/mdf3.rst +++ /dev/null @@ -1,76 +0,0 @@ -.. raw:: html - - - - - - - - - -.. role:: red -.. role:: blue -.. role:: green -.. role:: cyan -.. role:: magenta -.. role:: orange -.. role:: brown - -.. _mdf3: - -MDF3 -==== - -asammdf tries to emulate the mdf structure using Python builtin data types. - -The *header* attibute is an OrderedDict that holds the file metadata. - -The *groups* attribute is a dictionary list with the following keys: - -* data_group : DataGroup object -* channel_group : ChannelGroup object -* channels : list of Channel objects with the same order as found in the mdf file -* channel_conversions : list of ChannelConversion objects in 1-to-1 relation with the channel list -* channel_sources : list of SourceInformation objects in 1-to-1 relation with the channels list -* chanel_dependencies : list of ChannelDependency objects in a 1-to-1 relation with the channel list -* data_block : DataBlock object -* texts : dictionay containing TextBlock objects used throughout the mdf - - * channels : list of dictionaries that contain TextBlock objects ralated to each channel - - * long_name_addr : channel long name - * comment_addr : channel comment - * display_name_addr : channel display name - - * channel group : list of dictionaries that contain TextBlock objects ralated to each channel group - - * comment_addr : channel group comment - - * conversion_tab : list of dictionaries that contain TextBlock objects ralated to VATB and VTABR channel conversions - - * text_{n} : n-th text of the VTABR conversion - -* sorted : bool flag to indicate if the source file was sorted; it is used when `memory` is `low` or `minimum` -* size : data block size; used for lazy laoding of measured data -* record_size : dict of record ID -> record size pairs - -The *file_history* attribute is a TextBlock object. - -The *channel_db* attibute is a dictionary that holds the *(data group index, channel index)* pair for all signals. This is used to speed up the *get_signal_by_name* method. - -The *master_db* attibute is a dictionary that holds the *channel index* of the master channel for all data groups. This is used to speed up the *get_signal_by_name* method. - -API ---- - -.. autoclass:: asammdf.mdf3.MDF3 - :members: - :noindex: - -MDF version 3 blocks --------------------- - -.. toctree:: - :maxdepth: 2 - - v3blocks diff --git a/documentation/mdf4.rst b/documentation/mdf4.rst index 6c9f6ea56..4e2a8c59c 100644 --- a/documentation/mdf4.rst +++ b/documentation/mdf4.rst @@ -72,7 +72,7 @@ The *master_db* attibute is a dictionary that holds the *channel index* of the API --- -.. autoclass:: asammdf.mdf4.MDF4 +.. autoclass:: asammdf.mdf_v4.MDF4 :members: :noindex: diff --git a/documentation/v2blocks.rst b/documentation/v2v3blocks.rst similarity index 62% rename from documentation/v2blocks.rst rename to documentation/v2v3blocks.rst index 0fd80dab0..0186a37ed 100644 --- a/documentation/v2blocks.rst +++ b/documentation/v2v3blocks.rst @@ -22,50 +22,50 @@ The following classes implement different MDF version3 blocks. Channel Class ------------- -.. autoclass:: asammdf.mdf2.Channel +.. autoclass:: asammdf.v2_v3_blocks.Channel ChannelConversion Class ----------------------- -.. autoclass:: asammdf.mdf2.ChannelConversion +.. autoclass:: asammdf.v2_v3_blocks.ChannelConversion ChannelDependency Class ----------------------- -.. autoclass:: asammdf.mdf2.ChannelDependency +.. autoclass:: asammdf.v2_v3_blocks.ChannelDependency ChannelExtension Class ---------------------- -.. autoclass:: asammdf.mdf2.ChannelExtension +.. autoclass:: asammdf.v2_v3_blocks.ChannelExtension ChannelGroup Class ------------------ -.. autoclass:: asammdf.mdf2.ChannelGroup +.. autoclass:: asammdf.v2_v3_blocks.ChannelGroup DataGroup Class --------------- -.. autoclass:: asammdf.mdf2.DataGroup +.. autoclass:: asammdf.v2_v3_blocks.DataGroup FileIdentificationBlock Class ----------------------------- -.. autoclass:: asammdf.mdf2.FileIdentificationBlock +.. autoclass:: asammdf.v2_v3_blocks.FileIdentificationBlock HeaderBlock Class ----------------- -.. autoclass:: asammdf.mdf2.HeaderBlock +.. autoclass:: asammdf.v2_v3_blocks.HeaderBlock ProgramBlock Class ------------------ -.. autoclass:: asammdf.v2blocks.ProgramBlock +.. autoclass:: asammdf.v2_v3_blocks.ProgramBlock SampleReduction Class --------------------- -.. autoclass:: asammdf.v2blocks.SampleReduction +.. autoclass:: asammdf.v2_v3_blocks.SampleReduction :members: TextBlock Class --------------- -.. autoclass:: asammdf.mdf2.TextBlock +.. autoclass:: asammdf.v2_v3_blocks.TextBlock TriggerBlock Class ------------------ -.. autoclass:: asammdf.mdf2.TriggerBlock +.. autoclass:: asammdf.v2_v3_blocks.TriggerBlock diff --git a/documentation/v3blocks.rst b/documentation/v3blocks.rst deleted file mode 100644 index 167ac3270..000000000 --- a/documentation/v3blocks.rst +++ /dev/null @@ -1,71 +0,0 @@ -.. raw:: html - - - - - - - - - -.. role:: red -.. role:: blue -.. role:: green -.. role:: cyan -.. role:: magenta -.. role:: orange -.. role:: brown - -.. _v3blocks: - -The following classes implement different MDF version3 blocks. - -Channel Class -------------- -.. autoclass:: asammdf.mdf3.Channel - - -ChannelConversion Class ------------------------ -.. autoclass:: asammdf.mdf3.ChannelConversion - -ChannelDependency Class ------------------------ -.. autoclass:: asammdf.mdf3.ChannelDependency - -ChannelExtension Class ----------------------- -.. autoclass:: asammdf.mdf3.ChannelExtension - -ChannelGroup Class ------------------- -.. autoclass:: asammdf.mdf3.ChannelGroup - -DataGroup Class ---------------- -.. autoclass:: asammdf.mdf3.DataGroup - -FileIdentificationBlock Class ------------------------------ -.. autoclass:: asammdf.mdf3.FileIdentificationBlock - -HeaderBlock Class ------------------ -.. autoclass:: asammdf.mdf3.HeaderBlock - -ProgramBlock Class ------------------- -.. autoclass:: asammdf.v3blocks.ProgramBlock - -SampleReduction Class ---------------------- -.. autoclass:: asammdf.v3blocks.SampleReduction - :members: - -TextBlock Class ---------------- -.. autoclass:: asammdf.mdf3.TextBlock - -TriggerBlock Class ------------------- -.. autoclass:: asammdf.mdf3.TriggerBlock diff --git a/documentation/v4blocks.rst b/documentation/v4blocks.rst index 2ba9d3861..e5bc48299 100644 --- a/documentation/v4blocks.rst +++ b/documentation/v4blocks.rst @@ -18,64 +18,64 @@ .. _v4blocks: -The following classes implement different MDF version3 blocks. +The following classes implement different MDF version4 blocks. AttachmentBlock Class --------------------- -.. autoclass:: asammdf.mdf4.AttachmentBlock +.. autoclass:: asammdf.v4_blocks.AttachmentBlock :members: Channel Class ------------- -.. autoclass:: asammdf.mdf4.Channel +.. autoclass:: asammdf.v4_blocks.Channel :members: ChannelConversion Class ----------------------- -.. autoclass:: asammdf.mdf4.ChannelConversion +.. autoclass:: asammdf.v4_blocks.ChannelConversion :members: ChannelGroup Class ------------------ -.. autoclass:: asammdf.mdf4.ChannelGroup +.. autoclass:: asammdf.v4_blocks.ChannelGroup :members: DataGroup Class --------------- -.. autoclass:: asammdf.mdf4.DataGroup +.. autoclass:: asammdf.v4_blocks.DataGroup :members: DataList Class -------------- -.. autoclass:: asammdf.mdf4.DataList +.. autoclass:: asammdf.v4_blocks.DataList :members: DataBlock Class --------------- -.. autoclass:: asammdf.mdf4.DataBlock +.. autoclass:: asammdf.v4_blocks.DataBlock :members: FileIdentificationBlock Class ----------------------------- -.. autoclass:: asammdf.mdf4.FileIdentificationBlock +.. autoclass:: asammdf.v4_blocks.FileIdentificationBlock :members: HeaderBlock Class ----------------- -.. autoclass:: asammdf.mdf4.HeaderBlock +.. autoclass:: asammdf.v4_blocks.HeaderBlock :members: SourceInformation Class ----------------------- -.. autoclass:: asammdf.mdf4.SourceInformation +.. autoclass:: asammdf.v4_blocks.SourceInformation :members: FileHistory Class ----------------- -.. autoclass:: asammdf.mdf4.FileHistory +.. autoclass:: asammdf.v4_blocks.FileHistory :members: TextBlock Class --------------- -.. autoclass:: asammdf.mdf4.TextBlock +.. autoclass:: asammdf.v4_blocks.TextBlock :members: From 9b6ce9960421cdd1a75cc2967e21bde767a6697a Mon Sep 17 00:00:00 2001 From: danielhrisca Date: Sat, 23 Dec 2017 00:45:31 +0200 Subject: [PATCH 037/117] code cleanup --- asammdf/__init__.py | 1 - asammdf/mdf.py | 11 +-- asammdf/mdf_v2_v3.py | 77 +++++---------- asammdf/mdf_v4.py | 187 ++++++++++++++----------------------- asammdf/utils.py | 2 - asammdf/v2_v3_blocks.py | 98 ++++++++++--------- asammdf/v2_v3_constants.py | 2 +- asammdf/v4_blocks.py | 97 +++++++++---------- asammdf/v4_constants.py | 2 - 9 files changed, 201 insertions(+), 276 deletions(-) diff --git a/asammdf/__init__.py b/asammdf/__init__.py index f5b1734ef..bc42cd087 100644 --- a/asammdf/__init__.py +++ b/asammdf/__init__.py @@ -6,7 +6,6 @@ from .signal import Signal from .version import __version__ - __all__ = [ '__version__', 'configure', diff --git a/asammdf/mdf.py b/asammdf/mdf.py index 58cb3787f..dba312ee4 100644 --- a/asammdf/mdf.py +++ b/asammdf/mdf.py @@ -18,13 +18,11 @@ from .v2_v3_blocks import Channel as ChannelV3 from .v4_blocks import TextBlock as TextBlockV4 - MDF2_VERSIONS = ('2.00', '2.14') MDF3_VERSIONS = ('3.00', '3.10', '3.20', '3.30') MDF4_VERSIONS = ('4.00', '4.10', '4.11') SUPPORTED_VERSIONS = MDF2_VERSIONS + MDF3_VERSIONS + MDF4_VERSIONS - __all__ = ['MDF', 'SUPPORTED_VERSIONS'] @@ -49,6 +47,7 @@ class MDF(object): '4.00', '4.10', '4.11'); default '4.10' """ + def __init__(self, name=None, memory='full', version='4.10'): if name: if os.path.isfile(name): @@ -363,7 +362,7 @@ def export(self, fmt, filename=None): excel_name = os.path.splitext(name)[0] nr = len(self.groups) for i, grp in enumerate(self.groups): - print('Exporting group {} of {}'.format(i+1, nr)) + print('Exporting group {} of {}'.format(i + 1, nr)) data = self._load_group_data(grp) @@ -376,7 +375,6 @@ def export(self, fmt, filename=None): if self.version in MDF2_VERSIONS + MDF3_VERSIONS: for j, item in enumerate(header_items): - ws.write(j, 0, item.title(), bold) ws.write(j, 1, self.header[item].decode('latin-1')) @@ -393,7 +391,7 @@ def export(self, fmt, filename=None): master_index = self.masters_db[i] for j in range(grp['channel_group']['cycles_nr']): - ws.write(j+3, 0, str(j)) + ws.write(j + 3, 0, str(j)) for j, _ in enumerate(grp['channels']): sig = self.get(group=i, index=j, data=data) @@ -414,7 +412,7 @@ def export(self, fmt, filename=None): csv_name = os.path.splitext(name)[0] nr = len(self.groups) for i, grp in enumerate(self.groups): - print('Exporting group {} of {}'.format(i+1, nr)) + print('Exporting group {} of {}'.format(i + 1, nr)) data = self._load_group_data(grp) group_name = 'DataGroup_{}'.format(i + 1) @@ -840,5 +838,6 @@ def select(self, channels, dataframe=False): return signals + if __name__ == '__main__': pass diff --git a/asammdf/mdf_v2_v3.py b/asammdf/mdf_v2_v3.py index 60fadc0f4..dc9f1e1c4 100644 --- a/asammdf/mdf_v2_v3.py +++ b/asammdf/mdf_v2_v3.py @@ -1,57 +1,27 @@ # -*- coding: utf-8 -*- """ ASAM MDF version 3 file format module """ -from __future__ import print_function, division -import sys - +from __future__ import division, print_function import os +import sys import time import warnings - from collections import defaultdict -from functools import reduce, partial -from tempfile import TemporaryFile -from itertools import product from copy import deepcopy +from functools import partial, reduce +from itertools import product +from tempfile import TemporaryFile -from numpy import ( - interp, - linspace, - dtype, - array_equal, - column_stack, - array, - searchsorted, - log, - exp, - clip, - union1d, - float64, - flip, - unpackbits, - packbits, - roll, - zeros, - uint8, - arange, -) -from numpy.core.records import fromstring, fromarrays -from numpy.core.defchararray import encode from numexpr import evaluate +from numpy import (arange, array, array_equal, clip, column_stack, dtype, exp, flip, float64, interp, linspace, log, + packbits, roll, searchsorted, uint8, union1d, unpackbits, zeros) +from numpy.core.defchararray import encode +from numpy.core.records import fromarrays, fromstring -from .utils import ( - MdfException, - get_fmt, - pair, - fmt_to_datatype, - get_unique_name, - get_min_max, - fix_dtype_fields, -) -from .signal import Signal -from .version import __version__ from . import v2_v3_constants as v23c +from .signal import Signal +from .utils import (MdfException, fix_dtype_fields, fmt_to_datatype, get_fmt, get_min_max, get_unique_name, pair) from .v2_v3_blocks import ( Channel, ChannelConversion, @@ -65,7 +35,7 @@ TextBlock, TriggerBlock, ) - +from .version import __version__ get_fmt = partial(get_fmt, version=3) fmt_to_datatype = partial(fmt_to_datatype, version=3) @@ -74,7 +44,6 @@ if PYVERSION == 2: from .utils import bytes - __all__ = ['MDF23', ] @@ -197,7 +166,7 @@ def _load_group_data(self, group): i += 1 rec_size = cg_size[rec_id] if rec_id == record_id: - rec_data = data[i: i+rec_size] + rec_data = data[i: i + rec_size] cg_data.append(rec_data) # consider the second record ID if it exists if record_id_nr == 2: @@ -570,8 +539,8 @@ def _read(self): ) self.header = HeaderBlock(stream=stream) - self.version = self.identification['version_str']\ - .decode('latin-1')\ + self.version = self.identification['version_str'] \ + .decode('latin-1') \ .strip(' \n\t\0') self.file_history = TextBlock( @@ -846,7 +815,7 @@ def _read(self): # skip record id i += 1 rec_size = cg_size[rec_id] - rec_data = data[i: i+rec_size] + rec_data = data[i: i + rec_size] cg_data[rec_id].append(rec_data) # possibly skip 2nd record id if record_id_nr == 2: @@ -1009,12 +978,12 @@ def append(self, simple_signals = [ sig for sig in signals if len(sig.samples.shape) <= 1 and - sig.samples.dtype.names is None + sig.samples.dtype.names is None ] composed_signals = [ sig for sig in signals if len(sig.samples.shape) > 1 or - sig.samples.dtype.names + sig.samples.dtype.names ] # mdf version 4 structure channels and CANopen types will be saved to @@ -1022,12 +991,12 @@ def append(self, new_groups_signals = [ sig for sig in composed_signals if sig.samples.dtype.names and - sig.samples.dtype.names[0] != sig.name + sig.samples.dtype.names[0] != sig.name ] composed_signals = [ sig for sig in composed_signals if not sig.samples.dtype.names or - sig.samples.dtype.names[0] == sig.name + sig.samples.dtype.names[0] == sig.name ] if simple_signals or composed_signals: @@ -2996,7 +2965,7 @@ def _save_with_metadata(self, dst, overwrite, compression): if self.groups: for i, dg in enumerate(self.groups[:-1]): - addr = self.groups[i+1]['data_group'].address + addr = self.groups[i + 1]['data_group'].address dg['data_group']['next_dg_addr'] = addr self.groups[-1]['data_group']['next_dg_addr'] = 0 @@ -3378,7 +3347,7 @@ def _save_without_metadata(self, dst, overwrite, compression): group_channels = gp['channels'] if group_channels: for j, channel in enumerate(blocks[:-1]): - channel['next_ch_addr'] = blocks[j+1].address + channel['next_ch_addr'] = blocks[j + 1].address blocks[-1]['next_ch_addr'] = 0 for block in blocks: write(bytes(block)) @@ -3443,7 +3412,7 @@ def _save_without_metadata(self, dst, overwrite, compression): if self.groups: for i, gp in enumerate(self.groups[:-1]): - addr = self.groups[i+1]['data_group'].address + addr = self.groups[i + 1]['data_group'].address gp['data_group']['next_dg_addr'] = addr self.groups[-1]['data_group']['next_dg_addr'] = 0 diff --git a/asammdf/mdf_v4.py b/asammdf/mdf_v4.py index 9185df02f..4e952938c 100644 --- a/asammdf/mdf_v4.py +++ b/asammdf/mdf_v4.py @@ -3,79 +3,35 @@ ASAM MDF version 4 file format module """ -from __future__ import print_function, division +from __future__ import division, print_function + +import os import sys import time import warnings -import os - -from tempfile import TemporaryFile -from struct import unpack, unpack_from -from functools import reduce, partial +import xml.etree.ElementTree as XML from collections import defaultdict +from copy import deepcopy +from functools import partial, reduce from hashlib import md5 -import xml.etree.ElementTree as XML from math import ceil -from copy import deepcopy +from struct import unpack, unpack_from +from tempfile import TemporaryFile -from numpy import ( - interp, - linspace, - dtype, - array_equal, - zeros, - uint8, - array, - searchsorted, - clip, - union1d, - float64, - frombuffer, - argwhere, - arange, - flip, - unpackbits, - packbits, - roll, - transpose, -) -from numpy.core.records import fromstring, fromarrays -from numpy.core.defchararray import encode from numexpr import evaluate - -from .v4_blocks import ( - AttachmentBlock, - Channel, - ChannelArrayBlock, - ChannelGroup, - ChannelConversion, - DataBlock, - DataZippedBlock, - DataGroup, - DataList, - FileHistory, - FileIdentificationBlock, - HeaderBlock, - HeaderList, - SignalDataBlock, - SourceInformation, - TextBlock, -) +from numpy import (arange, argwhere, array, array_equal, clip, dtype, flip, float64, frombuffer, interp, linspace, + packbits, roll, searchsorted, transpose, uint8, union1d, unpackbits, zeros) +from numpy.core.defchararray import encode +from numpy.core.records import fromarrays, fromstring from . import v4_constants as v4c -from .utils import ( - MdfException, - get_fmt, - fmt_to_datatype, - get_unique_name, - get_min_max, - fix_dtype_fields, -) - from .signal import Signal +from .utils import (MdfException, fix_dtype_fields, fmt_to_datatype, get_fmt, get_min_max, get_unique_name) +from .v4_blocks import (AttachmentBlock, Channel, ChannelArrayBlock, ChannelConversion, ChannelGroup, DataBlock, + DataGroup, DataList, DataZippedBlock, FileHistory, FileIdentificationBlock, HeaderBlock, + HeaderList, SignalDataBlock, SourceInformation, TextBlock) from .version import __version__ - get_fmt = partial(get_fmt, version=4) fmt_to_datatype = partial(fmt_to_datatype, version=4) @@ -370,10 +326,10 @@ def _read(self): i += 1 rec_size = cg_size[rec_id] if rec_size: - rec_data = data[i: i+rec_size] + rec_data = data[i: i + rec_size] cg_data[rec_id].append(rec_data) else: - rec_size = unpack(' 1 and len(shape) == 1: - shape += (ca_block['byte_offset_base'] // size, ) + shape += (ca_block['byte_offset_base'] // size,) dim = 1 for d in shape: dim *= d @@ -1307,7 +1263,7 @@ def append(self, signals, source_info='Python', common_timebase=False): composed_signals = [ sig for sig in signals if len(sig.samples.shape) > 1 or - sig.samples.dtype.names + sig.samples.dtype.names ] dg_cntr = len(self.groups) @@ -1340,7 +1296,7 @@ def append(self, signals, source_info='Python', common_timebase=False): # time channel texts for key in ('channels', 'sources', 'channel_group', 'conversions'): gp['texts'][key].append({}) - for key in ('conversion_tab', ): + for key in ('conversion_tab',): gp['texts'][key].append(None) memory = self.memory @@ -2256,7 +2212,6 @@ def append(self, signals, source_info='Python', common_timebase=False): for i in range(dims_nr): kargs['dim_size_{}'.format(i)] = shape[i] - parent_dep = ChannelArrayBlock(**kargs) gp_dep.append([parent_dep, ]) @@ -2594,8 +2549,8 @@ def extract_attachment(self, index): if flags & v4c.FLAG_AT_EMBEDDED: data = attachment.extract() - file_path = texts['file_name_addr']['text']\ - .decode('utf-8')\ + file_path = texts['file_name_addr']['text'] \ + .decode('utf-8') \ .strip(' \n\t\0') out_path = os.path.dirname(file_path) if out_path: @@ -2609,16 +2564,16 @@ def extract_attachment(self, index): else: # for external attachments read the file and return the content if flags & v4c.FLAG_AT_MD5_VALID: - file_path = texts['file_name_addr']['text']\ - .decode('utf-8')\ + file_path = texts['file_name_addr']['text'] \ + .decode('utf-8') \ .strip(' \n\t\0') data = open(file_path, 'rb').read() md5_worker = md5() md5_worker.update(data) md5_sum = md5_worker.digest() if attachment['md5_sum'] == md5_sum: - if texts['mime_addr']['text']\ - .decode('utf-8')\ + if texts['mime_addr']['text'] \ + .decode('utf-8') \ .startswith('text'): with open(file_path, 'r') as f: data = f.read() @@ -2634,8 +2589,8 @@ def extract_attachment(self, index): ) warnings.warn(message) else: - if texts['mime_addr']['text']\ - .decode('utf-8')\ + if texts['mime_addr']['text'] \ + .decode('utf-8') \ .startswith('text'): mode = 'r' else: @@ -2998,7 +2953,6 @@ def get(self, dep = dependency_list[0] if dep['flags'] & v4c.FLAG_CA_INVERSE_LAYOUT: - shape = vals.shape shape = (shape[0],) + shape[1:][::-1] vals = vals.reshape(shape) @@ -3012,7 +2966,7 @@ def get(self, dims_nr = ca_block['dims'] if ca_block['ca_type'] == v4c.CA_TYPE_SCALE_AXIS: - shape = (ca_block['dim_size_0'], ) + shape = (ca_block['dim_size_0'],) arrays.append(vals) dtype_pair = channel.name, vals.dtype, shape types.append(dtype_pair) @@ -3025,7 +2979,7 @@ def get(self, if ca_block['flags'] & v4c.FLAG_CA_FIXED_AXIS: for i in range(dims_nr): - shape = (ca_block['dim_size_{}'.format(i)], ) + shape = (ca_block['dim_size_{}'.format(i)],) axis = [] for j in range(shape[0]): key = 'axis_{}_value_{}'.format(i, j) @@ -3049,7 +3003,7 @@ def get(self, axisname = axisname.split('\\')[0] else: axisname = self.groups[dg_nr]['channels'][ch_nr].name - shape = (ca_block['dim_size_{}'.format(i)], ) + shape = (ca_block['dim_size_{}'.format(i)],) axis_values = self.get( group=dg_nr, index=ch_nr, @@ -3074,7 +3028,7 @@ def get(self, if ca_block['flags'] & v4c.FLAG_CA_FIXED_AXIS: for i in range(dims_nr): - shape = (ca_block['dim_size_{}'.format(i)], ) + shape = (ca_block['dim_size_{}'.format(i)],) axis = [] for j in range(shape[0]): key = 'axis_{}_value_{}'.format(i, j) @@ -3094,7 +3048,7 @@ def get(self, axisname = axisname.split('\\')[0] else: axisname = self.groups[dg_nr]['channels'][ch_nr].name - shape = (ca_block['dim_size_{}'.format(i)], ) + shape = (ca_block['dim_size_{}'.format(i)],) axis_values = self.get( group=dg_nr, index=ch_nr, @@ -3290,7 +3244,7 @@ def get(self, offset = int(offset) str_size = unpack_from('= 36: - try: - result = pack(fmt, *self.values()) - except: - print(fmt, self) + result = pack(fmt, *self.values()) else: result = pack(fmt, *[self[key] for key in keys]) return result @@ -350,7 +345,8 @@ class ChannelConversion(dict): 0, 100.0 ''' - __slots__ = ['address',] + __slots__ = ['address', ] + def __init__(self, **kargs): super(ChannelConversion, self).__init__() @@ -397,13 +393,13 @@ def __init__(self, **kargs): v23c.CONVERSION_TYPE_TABX): nr = self['ref_param_nr'] values = unpack_from( - '<{}d'.format(2*nr), + '<{}d'.format(2 * nr), block, v23c.CC_COMMON_SHORT_SIZE, ) for i in range(nr): (self['raw_{}'.format(i)], - self['phys_{}'.format(i)]) = values[i*2], values[2*i+1] + self['phys_{}'.format(i)]) = values[i * 2], values[2 * i + 1] elif conv_type in ( v23c.CONVERSION_TYPE_POLY, @@ -445,7 +441,7 @@ def __init__(self, **kargs): for i in range(nr): (self['param_val_{}'.format(i)], - self['text_{}'.format(i)]) = values[i*2], values[2*i+1] + self['text_{}'.format(i)]) = values[i * 2], values[2 * i + 1] elif conv_type == v23c.CONVERSION_TYPE_VTABR: nr = self['ref_param_nr'] @@ -458,7 +454,7 @@ def __init__(self, **kargs): for i in range(nr): (self['lower_{}'.format(i)], self['upper_{}'.format(i)], - self['text_{}'.format(i)]) = values[i*3], values[3*i+1], values[3*i+2] + self['text_{}'.format(i)]) = values[i * 3], values[3 * i + 1], values[3 * i + 2] except KeyError: self.address = 0 self['id'] = 'CC'.encode('latin-1') @@ -471,7 +467,7 @@ def __init__(self, **kargs): self['range_flag'] = kargs.get('range_flag', 1) self['min_phy_value'] = kargs.get('min_phy_value', 0) self['max_phy_value'] = kargs.get('max_phy_value', 0) - self['unit'] = kargs.get('unit', ('\0'*20).encode('latin-1')) + self['unit'] = kargs.get('unit', ('\0' * 20).encode('latin-1')) self['conversion_type'] = v23c.CONVERSION_TYPE_NONE self['ref_param_nr'] = kargs.get('ref_param_nr', 0) @@ -483,7 +479,7 @@ def __init__(self, **kargs): self['range_flag'] = kargs.get('range_flag', 1) self['min_phy_value'] = kargs.get('min_phy_value', 0) self['max_phy_value'] = kargs.get('max_phy_value', 0) - self['unit'] = kargs.get('unit', ('\0'*20).encode('latin-1')) + self['unit'] = kargs.get('unit', ('\0' * 20).encode('latin-1')) self['conversion_type'] = v23c.CONVERSION_TYPE_LINEAR self['ref_param_nr'] = kargs.get('ref_param_nr', 2) self['b'] = kargs.get('b', 0) @@ -501,7 +497,7 @@ def __init__(self, **kargs): self['range_flag'] = kargs.get('range_flag', 1) self['min_phy_value'] = kargs.get('min_phy_value', 0) self['max_phy_value'] = kargs.get('max_phy_value', 0) - self['unit'] = kargs.get('unit', ('\0'*20).encode('latin-1')) + self['unit'] = kargs.get('unit', ('\0' * 20).encode('latin-1')) self['conversion_type'] = kargs.get( 'conversion_type', v23c.CONVERSION_TYPE_POLY, @@ -524,7 +520,7 @@ def __init__(self, **kargs): self['range_flag'] = kargs.get('range_flag', 1) self['min_phy_value'] = kargs.get('min_phy_value', 0) self['max_phy_value'] = kargs.get('max_phy_value', 0) - self['unit'] = kargs.get('unit', ('\0'*20).encode('latin-1')) + self['unit'] = kargs.get('unit', ('\0' * 20).encode('latin-1')) self['conversion_type'] = kargs.get( 'conversion_type', v23c.CONVERSION_TYPE_EXPO, @@ -546,13 +542,13 @@ def __init__(self, **kargs): self['range_flag'] = kargs.get('range_flag', 1) self['min_phy_value'] = kargs.get('min_phy_value', 0) self['max_phy_value'] = kargs.get('max_phy_value', 0) - self['unit'] = kargs.get('unit', ('\0'*20).encode('latin-1')) + self['unit'] = kargs.get('unit', ('\0' * 20).encode('latin-1')) self['conversion_type'] = kargs.get( 'conversion_type', v23c.CONVERSION_TYPE_FORMULA, ) self['ref_param_nr'] = kargs.get('ref_param_nr', 2) - self['formula'] = kargs.get('formula', b'X1'+b'\0'*254) + self['formula'] = kargs.get('formula', b'X1' + b'\0' * 254) elif kargs['conversion_type'] in ( v23c.CONVERSION_TYPE_TABI, @@ -562,7 +558,7 @@ def __init__(self, **kargs): self['range_flag'] = kargs.get('range_flag', 1) self['min_phy_value'] = kargs.get('min_phy_value', 0) self['max_phy_value'] = kargs.get('max_phy_value', 0) - self['unit'] = kargs.get('unit', ('\0'*20).encode('latin-1')) + self['unit'] = kargs.get('unit', ('\0' * 20).encode('latin-1')) self['conversion_type'] = kargs.get( 'conversion_type', v23c.CONVERSION_TYPE_TABI, @@ -576,12 +572,12 @@ def __init__(self, **kargs): nr = kargs['ref_param_nr'] self['block_len'] = kargs.get( 'block_len', - v23c.CC_COMMON_BLOCK_SIZE + 40*nr, + v23c.CC_COMMON_BLOCK_SIZE + 40 * nr, ) self['range_flag'] = kargs.get('range_flag', 0) self['min_phy_value'] = kargs.get('min_phy_value', 0) self['max_phy_value'] = kargs.get('max_phy_value', 0) - self['unit'] = kargs.get('unit', ('\0'*20).encode('latin-1')) + self['unit'] = kargs.get('unit', ('\0' * 20).encode('latin-1')) self['conversion_type'] = v23c.CONVERSION_TYPE_VTAB self['ref_param_nr'] = nr @@ -593,12 +589,12 @@ def __init__(self, **kargs): nr = kargs.get('ref_param_nr', 0) self['block_len'] = kargs.get( 'block_len', - v23c.CC_COMMON_BLOCK_SIZE + 20*nr, + v23c.CC_COMMON_BLOCK_SIZE + 20 * nr, ) self['range_flag'] = kargs.get('range_flag', 0) self['min_phy_value'] = kargs.get('min_phy_value', 0) self['max_phy_value'] = kargs.get('max_phy_value', 0) - self['unit'] = kargs.get('unit', ('\0'*20).encode('latin-1')) + self['unit'] = kargs.get('unit', ('\0' * 20).encode('latin-1')) self['conversion_type'] = v23c.CONVERSION_TYPE_VTABR self['ref_param_nr'] = kargs.get('ref_param_nr', 0) @@ -718,6 +714,7 @@ class ChannelDependency(dict): ''' __slots__ = ['address', 'referenced_channels'] + def __init__(self, **kargs): super(ChannelDependency, self).__init__() @@ -740,9 +737,9 @@ def __init__(self, **kargs): ) for i in range(self['sd_nr']): - self['dg_{}'.format(i)] = links[3*i] - self['cg_{}'.format(i)] = links[3*i+1] - self['ch_{}'.format(i)] = links[3*i+2] + self['dg_{}'.format(i)] = links[3 * i] + self['cg_{}'.format(i)] = links[3 * i + 1] + self['ch_{}'.format(i)] = links[3 * i + 2] optional_dims_nr = (self['block_len'] - 8 - links_size) // 2 if optional_dims_nr: @@ -841,7 +838,8 @@ class ChannelExtension(dict): block address inside mdf file ''' - __slots__ = ['address',] + __slots__ = ['address', ] + def __init__(self, **kargs): super(ChannelExtension, self).__init__() @@ -955,7 +953,8 @@ class ChannelGroup(dict): b'CG' ''' - __slots__ = ['address',] + __slots__ = ['address', ] + def __init__(self, **kargs): super(ChannelGroup, self).__init__() @@ -1006,6 +1005,7 @@ def __bytes__(self): result = pack(fmt, *[self[key] for key in keys]) return result + class DataBlock(dict): """Data Block class derived from *dict* @@ -1033,7 +1033,8 @@ class DataBlock(dict): binary file stream """ - __slots__ = ['address',] + __slots__ = ['address', ] + def __init__(self, **kargs): super(DataBlock, self).__init__() @@ -1089,7 +1090,8 @@ class DataGroup(dict): block address inside mdf file ''' - __slots__ = ['address',] + __slots__ = ['address', ] + def __init__(self, **kargs): super(DataGroup, self).__init__() @@ -1177,7 +1179,8 @@ class FileIdentificationBlock(dict): block address inside mdf file; should be 0 always ''' - __slots__ = ['address',] + __slots__ = ['address', ] + def __init__(self, **kargs): super(FileIdentificationBlock, self).__init__() @@ -1265,7 +1268,8 @@ class HeaderBlock(dict): block address inside mdf file; should be 64 always ''' - __slots__ = ['address',] + __slots__ = ['address', ] + def __init__(self, **kargs): super(HeaderBlock, self).__init__() @@ -1308,7 +1312,7 @@ def __init__(self, **kargs): self['comment_addr'] = 0 self['program_addr'] = 0 self['dg_nr'] = 0 - t1 = time.time() * 10**9 + t1 = time.time() * 10 ** 9 t2 = time.gmtime() self['date'] = '{:\0<10}'.format(time.strftime('%d:%m:%Y', t2)).encode('latin-1') self['time'] = '{:\0<8}'.format(time.strftime('%X', t2)).encode('latin-1') @@ -1365,7 +1369,8 @@ class ProgramBlock(dict): block address inside mdf file ''' - __slots__ = ['address',] + __slots__ = ['address', ] + def __init__(self, **kargs): super(ProgramBlock, self).__init__() @@ -1420,7 +1425,8 @@ class SampleReduction(dict): block address inside mdf file ''' - __slots__ = ['address',] + __slots__ = ['address', ] + def __init__(self, **kargs): super(SampleReduction, self).__init__() @@ -1490,7 +1496,8 @@ class TextBlock(dict): b'VehicleSpeed' ''' - __slots__ = ['address',] + __slots__ = ['address', ] + def __init__(self, **kargs): super(TextBlock, self).__init__() try: @@ -1524,10 +1531,10 @@ def __init__(self, **kargs): def __bytes__(self): if PYVERSION_MAJOR >= 36: - result = pack('<2sH{}s'.format(self['block_len']-4), *self.values()) + result = pack('<2sH{}s'.format(self['block_len'] - 4), *self.values()) else: result = pack( - '<2sH{}s'.format(self['block_len']-4), + '<2sH{}s'.format(self['block_len'] - 4), *[self[key] for key in v23c.KEYS_TEXT_BLOCK] ) return result @@ -1565,7 +1572,8 @@ class TriggerBlock(dict): block address inside mdf file ''' - __slots__ = ['address',] + __slots__ = ['address', ] + def __init__(self, **kargs): super(TriggerBlock, self).__init__() @@ -1585,11 +1593,11 @@ def __init__(self, **kargs): nr = self['trigger_events_nr'] if nr: - values = unpack('<{}d'.format(3*nr), block[10:]) + values = unpack('<{}d'.format(3 * nr), block[10:]) for i in range(nr): (self['trigger_{}_time'.format(i)], self['trigger_{}_pretime'.format(i)], - self['trigger_{}_posttime'.format(i)]) = values[i*3], values[3*i+1], values[3*i+2] + self['trigger_{}_posttime'.format(i)]) = values[i * 3], values[3 * i + 1], values[3 * i + 2] except KeyError: self['id'] = b'TR' diff --git a/asammdf/v2_v3_constants.py b/asammdf/v2_v3_constants.py index 5679cfce2..7675ed11f 100644 --- a/asammdf/v2_v3_constants.py +++ b/asammdf/v2_v3_constants.py @@ -201,7 +201,7 @@ 'max_raw_value', 'sampling_rate', ) -KEYS_CHANNEL_LONGNAME = KEYS_CHANNEL_SHORT + ('long_name_addr', ) +KEYS_CHANNEL_LONGNAME = KEYS_CHANNEL_SHORT + ('long_name_addr',) FMT_CHANNEL_GROUP = '<2sH3I3HI' KEYS_CHANNEL_GROUP = ( diff --git a/asammdf/v4_blocks.py b/asammdf/v4_blocks.py index 4c7f94e0b..3c4d33ad4 100644 --- a/asammdf/v4_blocks.py +++ b/asammdf/v4_blocks.py @@ -2,15 +2,13 @@ """ classes that implement the blocks for MDF version 4 """ -from __future__ import print_function, division -import sys - +from __future__ import division, print_function +import sys import time import warnings - from hashlib import md5 -from struct import unpack, pack, unpack_from +from struct import pack, unpack, unpack_from from zlib import compress, decompress import numpy as np @@ -22,7 +20,6 @@ SEEK_START = v4c.SEEK_START SEEK_END = v4c.SEEK_END - __all__ = [ 'AttachmentBlock', 'Channel', @@ -179,7 +176,6 @@ def __init__(self, **kargs): links_nr = self['links_nr'] - links = unpack_from('<{}Q'.format(links_nr), block) params = unpack_from(v4c.FMT_CHANNEL_PARAMS, block, links_nr * 8) @@ -193,7 +189,7 @@ def __init__(self, **kargs): self['comment_addr']) = links[:8] for i in range(params[10]): - self['attachment_{}_addr'.format(i)] = links[8+i] + self['attachment_{}_addr'.format(i)] = links[8 + i] if params[6] & v4c.FLAG_CN_DEFAULT_X: (self['default_X_dg_addr'], @@ -355,7 +351,7 @@ def __init__(self, **kargs): self['links_nr']) = unpack('<4sI2Q', stream.read(24)) nr = self['links_nr'] - links = unpack('<{}Q'.format(nr), stream.read(8*nr)) + links = unpack('<{}Q'.format(nr), stream.read(8 * nr)) self['composition_addr'] = links[0] values = unpack('<2BHIiI', stream.read(16)) @@ -367,7 +363,7 @@ def __init__(self, **kargs): # lookup table with fixed axis elif nr == dims_nr + 1: for i in range(dims_nr): - self['axis_conversion_{}'.format(i)] = links[i+1] + self['axis_conversion_{}'.format(i)] = links[i + 1] # lookup table with CN template elif nr == 4 * dims_nr + 1: @@ -375,9 +371,9 @@ def __init__(self, **kargs): self['axis_conversion_{}'.format(i)] = links[i + 1] links = links[dims_nr + 1:] for i in range(dims_nr): - self['scale_axis_{}_dg_addr'.format(i)] = links[3*i] - self['scale_axis_{}_cg_addr'.format(i)] = links[3*i + 1] - self['scale_axis_{}_ch_addr'.format(i)] = links[3*i + 2] + self['scale_axis_{}_dg_addr'.format(i)] = links[3 * i] + self['scale_axis_{}_cg_addr'.format(i)] = links[3 * i + 1] + self['scale_axis_{}_ch_addr'.format(i)] = links[3 * i + 2] (self['ca_type'], self['storage'], @@ -386,7 +382,7 @@ def __init__(self, **kargs): self['byte_offset_base'], self['invalidation_bit_base']) = values - dim_sizes = unpack('<{}Q'.format(dims_nr), stream.read(8*dims_nr)) + dim_sizes = unpack('<{}Q'.format(dims_nr), stream.read(8 * dims_nr)) for i, size in enumerate(dim_sizes): self['dim_size_{}'.format(i)] = size @@ -481,7 +477,6 @@ def __init__(self, **kargs): for i in range(dims_nr): self['dim_size_{}'.format(i)] = kargs['dim_size_{}'.format(i)] - def __bytes__(self): flags = self['flags'] ca_type = self['ca_type'] @@ -535,11 +530,11 @@ def __bytes__(self): ) keys += ( 'ca_type', - 'storage', - 'dims', - 'flags', - 'byte_offset_base', - 'invalidation_bit_base', + 'storage', + 'dims', + 'flags', + 'byte_offset_base', + 'invalidation_bit_base', ) keys += tuple('dim_size_{}'.format(i) for i in range(dims_nr)) keys += tuple( @@ -769,7 +764,7 @@ def __init__(self, **kargs): values = unpack('<{}d'.format(nr), block[56:]) for i in range(nr // 2): (self['raw_{}'.format(i)], - self['phys_{}'.format(i)]) = values[i*2], values[2*i+1] + self['phys_{}'.format(i)]) = values[i * 2], values[2 * i + 1] elif conv == v4c.CONVERSION_TYPE_RTAB: (self['name_addr'], @@ -791,7 +786,7 @@ def __init__(self, **kargs): for i in range((nr - 1) // 3): (self['lower_{}'.format(i)], self['upper_{}'.format(i)], - self['phys_{}'.format(i)]) = values[i*3], values[3*i+1], values[3*i+2] + self['phys_{}'.format(i)]) = values[i * 3], values[3 * i + 1], values[3 * i + 2] self['default'] = unpack('= 36: @@ -1214,7 +1209,8 @@ class DataBlock(dict): file handle """ - __slots__ = ['address',] + __slots__ = ['address', ] + def __init__(self, **kargs): super(DataBlock, self).__init__() @@ -1249,7 +1245,6 @@ def __bytes__(self): return result - class DataZippedBlock(dict): """DZBLOCK class @@ -1262,6 +1257,7 @@ class DataZippedBlock(dict): """ __slots__ = ['address', 'prevent_data_setitem', 'return_unzipped'] + def __init__(self, **kargs): super(DataZippedBlock, self).__init__() @@ -1323,9 +1319,9 @@ def __setitem__(self, item, value): cols = self['param'] lines = self['original_size'] // cols - nd = np.fromstring(data[:lines*cols], dtype=np.uint8) + nd = np.fromstring(data[:lines * cols], dtype=np.uint8) nd = nd.reshape((lines, cols)) - data = nd.transpose().tostring() + data[lines*cols:] + data = nd.transpose().tostring() + data[lines * cols:] data = compress(data) @@ -1344,9 +1340,9 @@ def __getitem__(self, item): cols = self['param'] lines = self['original_size'] // cols - nd = np.fromstring(data[:lines*cols], dtype=np.uint8) + nd = np.fromstring(data[:lines * cols], dtype=np.uint8) nd = nd.reshape((cols, lines)) - data = nd.transpose().tostring() + data[lines*cols:] + data = nd.transpose().tostring() + data[lines * cols:] else: data = super(DataZippedBlock, self).__getitem__(item) value = data @@ -1367,7 +1363,8 @@ def __bytes__(self): class DataGroup(dict): """DGBLOCK class""" - __slots__ = ['address',] + __slots__ = ['address', ] + def __init__(self, **kargs): super(DataGroup, self).__init__() @@ -1402,7 +1399,7 @@ def __init__(self, **kargs): self['data_block_addr'] = kargs.get('data_block_addr', 0) self['comment_addr'] = kargs.get('comment_addr', 0) self['record_id_len'] = kargs.get('record_id_len', 0) - self['reserved1'] = kargs.get('reserved1', b'\00'*7) + self['reserved1'] = kargs.get('reserved1', b'\00' * 7) def __bytes__(self): if PYVERSION_MAJOR >= 36: @@ -1417,7 +1414,8 @@ def __bytes__(self): class DataList(dict): """DLBLOCK class""" - __slots__ = ['address',] + __slots__ = ['address', ] + def __init__(self, **kargs): super(DataList, self).__init__() @@ -1438,7 +1436,7 @@ def __init__(self, **kargs): links = unpack( '<{}Q'.format(self['links_nr'] - 1), - stream.read( (self['links_nr'] - 1) * 8 ), + stream.read((self['links_nr'] - 1) * 8), ) for i, addr in enumerate(links): @@ -1456,7 +1454,7 @@ def __init__(self, **kargs): self['data_block_nr']) = unpack('<3sI', stream.read(7)) offsets = unpack( '<{}Q'.format(self['links_nr'] - 1), - stream.read((self['links_nr'] - 1)*8), + stream.read((self['links_nr'] - 1) * 8), ) for i, offset in enumerate(offsets): self['offset_{}'.format(i)] = offset @@ -1485,7 +1483,6 @@ def __init__(self, **kargs): for i, offset in enumerate(self['links_nr'] - 1): self['offset_{}'.format(i)] = kargs['offset_{}'.format(i)] - def __bytes__(self): fmt = v4c.FMT_DATA_LIST.format(self['links_nr']) if PYVERSION_MAJOR < 36: @@ -1515,7 +1512,8 @@ def __bytes__(self): class FileIdentificationBlock(dict): """IDBLOCK class""" - __slots__ = ['address',] + __slots__ = ['address', ] + def __init__(self, **kargs): super(FileIdentificationBlock, self).__init__() @@ -1570,7 +1568,8 @@ def __bytes__(self): class FileHistory(dict): """FHBLOCK class""" - __slots__ = ['address',] + __slots__ = ['address', ] + def __init__(self, **kargs): super(FileHistory, self).__init__() @@ -1601,11 +1600,11 @@ def __init__(self, **kargs): self['links_nr'] = kargs.get('links_nr', 2) self['next_fh_addr'] = kargs.get('next_fh_addr', 0) self['comment_addr'] = kargs.get('comment_addr', 0) - self['abs_time'] = kargs.get('abs_time', int(time.time()) * 10**9) + self['abs_time'] = kargs.get('abs_time', int(time.time()) * 10 ** 9) self['tz_offset'] = kargs.get('tz_offset', 120) self['daylight_save_time'] = kargs.get('daylight_save_time', 60) self['time_flags'] = kargs.get('time_flags', 2) - self['reserved1'] = kargs.get('reserved1', b'\x00'*3) + self['reserved1'] = kargs.get('reserved1', b'\x00' * 3) def __bytes__(self): if PYVERSION_MAJOR >= 36: @@ -1620,7 +1619,8 @@ def __bytes__(self): class HeaderBlock(dict): """HDBLOCK class""" - __slots__ = ['address',] + __slots__ = ['address', ] + def __init__(self, **kargs): super(HeaderBlock, self).__init__() @@ -1667,7 +1667,7 @@ def __init__(self, **kargs): ) self['first_event_addr'] = kargs.get('first_event_addr', 0) self['comment_addr'] = kargs.get('comment_addr', 0) - self['abs_time'] = kargs.get('abs_time', int(time.time()) * 10**9) + self['abs_time'] = kargs.get('abs_time', int(time.time()) * 10 ** 9) self['tz_offset'] = kargs.get('tz_offset', 120) self['daylight_save_time'] = kargs.get('daylight_save_time', 60) self['time_flags'] = kargs.get('time_flags', 2) @@ -1791,7 +1791,8 @@ def __bytes__(self): class SignalDataBlock(dict): """SDBLOCK class""" - __slots__ = ['address',] + __slots__ = ['address', ] + def __init__(self, **kargs): super(SignalDataBlock, self).__init__() diff --git a/asammdf/v4_constants.py b/asammdf/v4_constants.py index 78c6b953f..7831598b9 100644 --- a/asammdf/v4_constants.py +++ b/asammdf/v4_constants.py @@ -68,7 +68,6 @@ CA_TYPE_LOOKUP = 2 CA_STORAGE_TYPE_CN_TEMPLATE = 0 - SOURCE_ECU = 1 SOURCE_BUS = 2 SOURCE_IO = 3 @@ -254,7 +253,6 @@ FMT_CONVERSION_RAT_INIT = '<4Q2B3H8d' - FMT_HEADER_BLOCK = '<4sI9Q2H4B2Q' FMT_IDENTIFICATION_BLOCK = '<8s8s8s5H26s2H' From 93fc976d379aefc617540259ef0b640694aee167 Mon Sep 17 00:00:00 2001 From: danielhrisca Date: Sat, 23 Dec 2017 14:10:57 +0200 Subject: [PATCH 038/117] documentation fixes asserts to validate proper block ID read from files --- asammdf/mdf.py | 17 ++++++----------- asammdf/mdf_v2_v3.py | 3 ++- asammdf/v2_v3_blocks.py | 36 ++++++++++++++++++++++++++++++------ documentation/index.rst | 2 +- 4 files changed, 39 insertions(+), 19 deletions(-) diff --git a/asammdf/mdf.py b/asammdf/mdf.py index dba312ee4..9abb3ea12 100644 --- a/asammdf/mdf.py +++ b/asammdf/mdf.py @@ -18,7 +18,7 @@ from .v2_v3_blocks import Channel as ChannelV3 from .v4_blocks import TextBlock as TextBlockV4 -MDF2_VERSIONS = ('2.00', '2.14') +MDF2_VERSIONS = ('2.00', '2.10', '2.14') MDF3_VERSIONS = ('3.00', '3.10', '3.20', '3.30') MDF4_VERSIONS = ('4.00', '4.10', '4.11') SUPPORTED_VERSIONS = MDF2_VERSIONS + MDF3_VERSIONS + MDF4_VERSIONS @@ -43,8 +43,8 @@ class MDF(object): * if *minimum* only minimal data is loaded into RAM version : string - mdf file version from ('2.00', '2.14', '3.00', '3.10', '3.20', '3.30', - '4.00', '4.10', '4.11'); default '4.10' + mdf file version from ('2.00', '2.10', '2.14', '3.00', '3.10', '3.20', + '3.30', '4.00', '4.10', '4.11'); default '4.10' """ @@ -72,7 +72,7 @@ def __init__(self, name=None, memory='full', version='4.10'): else: raise MdfException('File "{}" does not exist'.format(name)) else: - if version in MDF3_VERSIONS: + if version in MDF2_VERSIONS + MDF3_VERSIONS: self._mdf = MDF23( version=version, memory=memory, @@ -82,11 +82,6 @@ def __init__(self, name=None, memory='full', version='4.10'): version=version, memory=memory, ) - elif version in MDF2_VERSIONS: - self._mdf = MDF23( - version=version, - memory=memory, - ) # link underlying _file attributes and methods to the new MDF object for attr in set(dir(self._mdf)) - set(dir(self)): @@ -138,8 +133,8 @@ def convert(self, to, memory='full'): Parameters ---------- to : str - new mdf version from ('2.00', '2.14', '3.00', '3.10', '3.20', - '3.30', '4.00', '4.10', '4.11') + new mdf file version from ('2.00', '2.10', '2.14', '3.00', '3.10', + '3.20', '3.30', '4.00', '4.10', '4.11'); default '4.10' memory : str memory option; default `full` diff --git a/asammdf/mdf_v2_v3.py b/asammdf/mdf_v2_v3.py index dc9f1e1c4..7d88fe137 100644 --- a/asammdf/mdf_v2_v3.py +++ b/asammdf/mdf_v2_v3.py @@ -64,7 +64,8 @@ class MDF23(object): * if *minimum* only minimal data is memorised into RAM version : string - mdf file version ('3.00', '3.10', '3.20' or '3.30'); default '3.30' + mdf file version ('2.00', '2.10', '2.14', '3.00', '3.10', '3.20' or + '3.30'); default '3.30' Attributes ---------- diff --git a/asammdf/v2_v3_blocks.py b/asammdf/v2_v3_blocks.py index e6ae94b60..c72fc7931 100644 --- a/asammdf/v2_v3_blocks.py +++ b/asammdf/v2_v3_blocks.py @@ -195,6 +195,8 @@ def __init__(self, **kargs): self['max_raw_value'], self['sampling_rate']) = unpack(v23c.FMT_CHANNEL_SHORT, block) + assert self['id'] == b'CN' + except KeyError: self.address = 0 @@ -455,6 +457,9 @@ def __init__(self, **kargs): (self['lower_{}'.format(i)], self['upper_{}'.format(i)], self['text_{}'.format(i)]) = values[i * 3], values[3 * i + 1], values[3 * i + 2] + + assert self['id'] == b'CC' + except KeyError: self.address = 0 self['id'] = 'CC'.encode('latin-1') @@ -750,6 +755,8 @@ def __init__(self, **kargs): for i, dim in enumerate(dims): self['dim_{}'.format(i)] = dim + assert self['id'] == b'CD' + except KeyError: sd_nr = kargs['sd_nr'] self['id'] = b'CD' @@ -864,10 +871,12 @@ def __init__(self, **kargs): self['message_name'], self['sender_name'], self['reserved0']) = unpack(v23c.FMT_SOURCE_EXTRA_VECTOR, block) + assert self['id'] == b'CE' + except KeyError: self.address = 0 - self['id'] = kargs.get('id', 'CE'.encode('latin-1')) + self['id'] = b'CE' self['block_len'] = kargs.get('block_len', v23c.CE_BLOCK_SIZE) self['type'] = kargs.get('type', 2) if self['type'] == v23c.SOURCE_ECU: @@ -976,9 +985,10 @@ def __init__(self, **kargs): self['cycles_nr']) = unpack(v23c.FMT_CHANNEL_GROUP, block) if self['block_len'] == v23c.CG_POST_330_BLOCK_SIZE: self['sample_reduction_addr'] = unpack('= '3.20' else 164 self['first_dg_addr'] = 0 self['comment_addr'] = 0 @@ -1383,8 +1397,12 @@ def __init__(self, **kargs): self['block_len']) = unpack('<2sH', stream.read(4)) self['data'] = stream.read(self['block_len'] - 4) + assert self['id'] == b'PR' + except KeyError: - pass + self['id'] = b'PR' + self['block_len'] = len(kargs['data']) + 6 + self['data'] = kargs['data'] def __bytes__(self): fmt = v23c.FMT_PROGRAM_BLOCK.format(self['block_len']) @@ -1445,6 +1463,8 @@ def __init__(self, **kargs): stream.read(v23c.SR_BLOCK_SIZE), ) + assert self['id'] == b'SR' + except KeyError: pass @@ -1510,6 +1530,8 @@ def __init__(self, **kargs): size = self['block_len'] - 4 self['text'] = stream.read(size) + assert self['id'] == b'TX' + except KeyError: self.address = 0 text = kargs['text'] @@ -1551,7 +1573,7 @@ class TriggerBlock(dict): The keys have the following meaning: - * id - Block type identifier, always "TX" + * id - Block type identifier, always "TR" * block_len - Block size of this block in bytes (entire TRBLOCK) * text_addr - Pointer to trigger comment text (TXBLOCK) (NIL allowed) * trigger_events_nr - Number of trigger events n (0 allowed) @@ -1599,6 +1621,8 @@ def __init__(self, **kargs): self['trigger_{}_pretime'.format(i)], self['trigger_{}_posttime'.format(i)]) = values[i * 3], values[3 * i + 1], values[3 * i + 2] + assert self['id'] == b'TR' + except KeyError: self['id'] = b'TR' self['block_len'] = 10 + kargs['trigger_events_nr'] * 8 * 3 diff --git a/documentation/index.rst b/documentation/index.rst index 6baa206ad..8132feea0 100644 --- a/documentation/index.rst +++ b/documentation/index.rst @@ -25,7 +25,7 @@ Features * create new mdf files from scratch * append new channels -* read unsorted MDF v3 and v4 files +* read unsorted MDF v2, v3 and v4 files * filter a subset of channels from original mdf file * cut measurement to specified time interval * convert to different mdf version From c7a47cfa48cef73ce581cf3e3c58f52056feb60c Mon Sep 17 00:00:00 2001 From: danielhrisca Date: Sat, 23 Dec 2017 14:28:35 +0200 Subject: [PATCH 039/117] asserts to validate proper block ID read from mdf version 4 files --- asammdf/v4_blocks.py | 40 +++++++++++++++++++++++++++++++++++----- 1 file changed, 35 insertions(+), 5 deletions(-) diff --git a/asammdf/v4_blocks.py b/asammdf/v4_blocks.py index 3c4d33ad4..1ec8dc62e 100644 --- a/asammdf/v4_blocks.py +++ b/asammdf/v4_blocks.py @@ -75,6 +75,8 @@ def __init__(self, **kargs): self['embedded_data'] = stream.read(self['embedded_size']) + assert self['id'] == b'##AT' + except KeyError: data = kargs['data'] @@ -223,6 +225,8 @@ def __init__(self, **kargs): links_nr * 8, ) + assert self['id'] == b'##CN' + else: self.address = 0 @@ -392,6 +396,8 @@ def __init__(self, **kargs): value = unpack(' Date: Sat, 23 Dec 2017 14:55:08 +0200 Subject: [PATCH 040/117] use MdfException instead of asserts --- asammdf/v2_v3_blocks.py | 45 ++++++++++++++++++++++-------- asammdf/v4_blocks.py | 61 +++++++++++++++++++++++++++++++---------- 2 files changed, 80 insertions(+), 26 deletions(-) diff --git a/asammdf/v2_v3_blocks.py b/asammdf/v2_v3_blocks.py index c72fc7931..a8a6a84fe 100644 --- a/asammdf/v2_v3_blocks.py +++ b/asammdf/v2_v3_blocks.py @@ -8,6 +8,7 @@ from getpass import getuser from struct import pack, unpack, unpack_from +from .utils import MdfException from . import v2_v3_constants as v23c PYVERSION = sys.version_info[0] @@ -195,7 +196,9 @@ def __init__(self, **kargs): self['max_raw_value'], self['sampling_rate']) = unpack(v23c.FMT_CHANNEL_SHORT, block) - assert self['id'] == b'CN' + if self['id'] != b'CN': + message = 'Expected "CN" block but found "{}"' + raise MdfException(message.format(self['id'])) except KeyError: @@ -458,7 +461,9 @@ def __init__(self, **kargs): self['upper_{}'.format(i)], self['text_{}'.format(i)]) = values[i * 3], values[3 * i + 1], values[3 * i + 2] - assert self['id'] == b'CC' + if self['id'] != b'CC': + message = 'Expected "CC" block but found "{}"' + raise MdfException(message.format(self['id'])) except KeyError: self.address = 0 @@ -755,7 +760,9 @@ def __init__(self, **kargs): for i, dim in enumerate(dims): self['dim_{}'.format(i)] = dim - assert self['id'] == b'CD' + if self['id'] != b'CD': + message = 'Expected "CD" block but found "{}"' + raise MdfException(message.format(self['id'])) except KeyError: sd_nr = kargs['sd_nr'] @@ -871,7 +878,9 @@ def __init__(self, **kargs): self['message_name'], self['sender_name'], self['reserved0']) = unpack(v23c.FMT_SOURCE_EXTRA_VECTOR, block) - assert self['id'] == b'CE' + if self['id'] != b'CE': + message = 'Expected "CE" block but found "{}"' + raise MdfException(message.format(self['id'])) except KeyError: @@ -985,7 +994,9 @@ def __init__(self, **kargs): self['cycles_nr']) = unpack(v23c.FMT_CHANNEL_GROUP, block) if self['block_len'] == v23c.CG_POST_330_BLOCK_SIZE: self['sample_reduction_addr'] = unpack(' Date: Sat, 23 Dec 2017 15:13:33 +0200 Subject: [PATCH 041/117] rearranged imports --- asammdf/__init__.py | 1 + asammdf/mdf_v2_v3.py | 33 ++++++++++++++++++++++--- asammdf/mdf_v4.py | 53 ++++++++++++++++++++++++++++++++++++----- asammdf/v2_v3_blocks.py | 2 +- asammdf/v4_blocks.py | 2 +- 5 files changed, 80 insertions(+), 11 deletions(-) diff --git a/asammdf/__init__.py b/asammdf/__init__.py index bc42cd087..7004e80ac 100644 --- a/asammdf/__init__.py +++ b/asammdf/__init__.py @@ -1,5 +1,6 @@ # -*- coding: utf-8 -*- """ asammdf is a parser and editor for ASAM MDF files """ + from .mdf_v2_v3 import MDF23 from .mdf_v4 import MDF4 from .mdf import MDF, SUPPORTED_VERSIONS diff --git a/asammdf/mdf_v2_v3.py b/asammdf/mdf_v2_v3.py index 7d88fe137..aa5094f65 100644 --- a/asammdf/mdf_v2_v3.py +++ b/asammdf/mdf_v2_v3.py @@ -14,14 +14,41 @@ from tempfile import TemporaryFile from numexpr import evaluate -from numpy import (arange, array, array_equal, clip, column_stack, dtype, exp, flip, float64, interp, linspace, log, - packbits, roll, searchsorted, uint8, union1d, unpackbits, zeros) +from numpy import ( + arange, + array, + array_equal, + clip, + column_stack, + dtype, + exp, + flip, + float64, + interp, + linspace, + log, + packbits, + roll, + searchsorted, + uint8, + union1d, + unpackbits, + zeros, +) from numpy.core.defchararray import encode from numpy.core.records import fromarrays, fromstring from . import v2_v3_constants as v23c from .signal import Signal -from .utils import (MdfException, fix_dtype_fields, fmt_to_datatype, get_fmt, get_min_max, get_unique_name, pair) +from .utils import ( + MdfException, + fix_dtype_fields, + fmt_to_datatype, + get_fmt, + get_min_max, + get_unique_name, + pair, +) from .v2_v3_blocks import ( Channel, ChannelConversion, diff --git a/asammdf/mdf_v4.py b/asammdf/mdf_v4.py index 4e952938c..8c68dcdf7 100644 --- a/asammdf/mdf_v4.py +++ b/asammdf/mdf_v4.py @@ -19,17 +19,58 @@ from tempfile import TemporaryFile from numexpr import evaluate -from numpy import (arange, argwhere, array, array_equal, clip, dtype, flip, float64, frombuffer, interp, linspace, - packbits, roll, searchsorted, transpose, uint8, union1d, unpackbits, zeros) +from numpy import ( + arange, + argwhere, + array, + array_equal, + clip, + dtype, + flip, + float64, + frombuffer, + interp, + linspace, + packbits, + roll, + searchsorted, + transpose, + uint8, + union1d, + unpackbits, + zeros, +) from numpy.core.defchararray import encode from numpy.core.records import fromarrays, fromstring from . import v4_constants as v4c from .signal import Signal -from .utils import (MdfException, fix_dtype_fields, fmt_to_datatype, get_fmt, get_min_max, get_unique_name) -from .v4_blocks import (AttachmentBlock, Channel, ChannelArrayBlock, ChannelConversion, ChannelGroup, DataBlock, - DataGroup, DataList, DataZippedBlock, FileHistory, FileIdentificationBlock, HeaderBlock, - HeaderList, SignalDataBlock, SourceInformation, TextBlock) +from .utils import ( + MdfException, + fix_dtype_fields, + fmt_to_datatype, + get_fmt, + get_min_max, + get_unique_name, +) +from .v4_blocks import ( + AttachmentBlock, + Channel, + ChannelArrayBlock, + ChannelConversion, + ChannelGroup, + DataBlock, + DataGroup, + DataList, + DataZippedBlock, + FileHistory, + FileIdentificationBlock, + HeaderBlock, + HeaderList, + SignalDataBlock, + SourceInformation, + TextBlock, +) from .version import __version__ get_fmt = partial(get_fmt, version=4) diff --git a/asammdf/v2_v3_blocks.py b/asammdf/v2_v3_blocks.py index a8a6a84fe..abc8a94ed 100644 --- a/asammdf/v2_v3_blocks.py +++ b/asammdf/v2_v3_blocks.py @@ -8,8 +8,8 @@ from getpass import getuser from struct import pack, unpack, unpack_from -from .utils import MdfException from . import v2_v3_constants as v23c +from .utils import MdfException PYVERSION = sys.version_info[0] PYVERSION_MAJOR = sys.version_info[0] * 10 + sys.version_info[1] diff --git a/asammdf/v4_blocks.py b/asammdf/v4_blocks.py index 3000a2a26..90b645e4e 100644 --- a/asammdf/v4_blocks.py +++ b/asammdf/v4_blocks.py @@ -13,8 +13,8 @@ import numpy as np -from .utils import MdfException from . import v4_constants as v4c +from .utils import MdfException PYVERSION = sys.version_info[0] PYVERSION_MAJOR = sys.version_info[0] * 10 + sys.version_info[1] From 746c4bb4a5bec9e993ff45127c72d7b870054586 Mon Sep 17 00:00:00 2001 From: danielhrisca Date: Sat, 23 Dec 2017 19:54:08 +0200 Subject: [PATCH 042/117] fix error in saving mdf version 4 RTABX channels --- asammdf/mdf_v4.py | 11 +++++++---- test/test_mdf.py | 39 +++++++++++++++++++++++++++++++++++++-- 2 files changed, 44 insertions(+), 6 deletions(-) diff --git a/asammdf/mdf_v4.py b/asammdf/mdf_v4.py index 8c68dcdf7..8bdc4cf0f 100644 --- a/asammdf/mdf_v4.py +++ b/asammdf/mdf_v4.py @@ -1786,6 +1786,7 @@ def append(self, signals, source_info='Python', common_timebase=False): write(bytes(block)) kargs['default_addr'] = 0 kargs['links_nr'] = len(raw) + 5 + block = ChannelConversion(**kargs) if memory != 'minimum': gp_conv.append(block) @@ -1793,6 +1794,8 @@ def append(self, signals, source_info='Python', common_timebase=False): address = tell() gp_conv.append(address) write(bytes(block)) + + elif info and 'lower' in info: kargs = {} kargs['conversion_type'] = v4c.CONVERSION_TYPE_RTABX @@ -4566,6 +4569,7 @@ def _save_without_metadata(self, dst, overwrite, compression): gp['temp_channel_conversions'] = [] for j, conv in enumerate(gp['channel_conversions']): if conv: + address = tell() gp['temp_channel_conversions'].append(address) conv = ChannelConversion( @@ -4582,10 +4586,9 @@ def _save_without_metadata(self, dst, overwrite, compression): conv[key] = text_block conv['inv_conv_addr'] = 0 - if conv['conversion_type'] in tab_conversion: - for key in temp_texts['conversion_tab'][j]: - conv[key] = temp_texts['conversion_tab'][j][key] - + if conv['conversion_type'] in tab_conversion: + for key in temp_texts['conversion_tab'][j]: + conv[key] = temp_texts['conversion_tab'][j][key] write(bytes(conv)) else: gp['temp_channel_conversions'].append(0) diff --git a/test/test_mdf.py b/test/test_mdf.py index 6b412d0ad..61a44dae7 100644 --- a/test/test_mdf.py +++ b/test/test_mdf.py @@ -50,8 +50,9 @@ def setUpClass(cls): def tearDownClass(cls): shutil.rmtree('tmpdir', True) os.remove('test.zip') - if os.path.isfile('tmp'): - os.remove('tmp') + for filename in ('tmp', 'tmp1', 'tmp2')[:1]: + if os.path.isfile(filename): + os.remove(filename) def test_read(self): @@ -1621,6 +1622,40 @@ def test_merge(self): self.assertTrue(equal) + def test_cut(self): + print("MDF cut tests") + + for mdfname in os.listdir('tmpdir'): + for memory in MEMORY[:1]: + input_file = os.path.join('tmpdir', mdfname) + + print(input_file) + + MDF(input_file, memory=memory).cut(stop=2).save('tmp1', overwrite=True) + MDF(input_file, memory=memory).cut(start=2).save('tmp2', overwrite=True) + + MDF.merge(['tmp1', 'tmp2'], MDF(input_file, memory='minimum').version).save('tmp', overwrite=True) + + equal = True + + with MDF(input_file, memory=memory) as mdf, \ + MDF('tmp', memory=memory) as mdf2: + + for i, group in enumerate(mdf.groups): + for j, channel in enumerate(group['channels'][1:], 1): + original = mdf.get(group=i, index=j) + converted = mdf2.get(group=i, index=j) + if not np.array_equal( + original.samples, + converted.samples): + equal = False + if not np.array_equal( + original.timestamps, + converted.timestamps): + equal = False + + self.assertTrue(equal) + if __name__ == '__main__': unittest.main() From ddda7ac7d82c0d37eb3456084cc57d966f3d2cd4 Mon Sep 17 00:00:00 2001 From: danielhrisca Date: Sun, 24 Dec 2017 22:58:52 +0200 Subject: [PATCH 043/117] fix get error for generated MDF files (result of merge, filter, cut) --- asammdf/mdf.py | 3 +- asammdf/mdf_v4.py | 28 ++++--- test/test_mdf.py | 185 +++++++++++++++++++++++++++++++++++++--------- 3 files changed, 168 insertions(+), 48 deletions(-) diff --git a/asammdf/mdf.py b/asammdf/mdf.py index 9abb3ea12..bd72e1643 100644 --- a/asammdf/mdf.py +++ b/asammdf/mdf.py @@ -504,7 +504,8 @@ def filter(self, channels, memory=None): gps[group] = set() gps[group].add(index) if self.version in MDF2_VERSIONS + MDF3_VERSIONS: - dep = group['channel_dependencies'][index] + grp = self.groups[group] + dep = grp['channel_dependencies'][index] if dep: for ch_nr, gp_nr in dep.referenced_channels: if gp_nr == group: diff --git a/asammdf/mdf_v4.py b/asammdf/mdf_v4.py index 8bdc4cf0f..2220974d0 100644 --- a/asammdf/mdf_v4.py +++ b/asammdf/mdf_v4.py @@ -3041,8 +3041,10 @@ def get(self, ch_nr, dg_nr = ca_block.referenced_channels[i] if memory == 'minimum': axisname = self.groups[dg_nr]['texts']['channels'][ch_nr]['name_addr'] - block = TextBlock(address=axisname, - stream=self._file) + block = TextBlock( + address=axisname, + stream=stream, + ) axisname = block['text'].decode('utf-8').strip(' \t\n\r\0') axisname = axisname.split('\\')[0] else: @@ -3051,7 +3053,8 @@ def get(self, axis_values = self.get( group=dg_nr, index=ch_nr, - samples_only=True) + samples_only=True, + ) axis_values = axis_values[axisname] arrays.append(axis_values) dtype_pair = ( @@ -3086,8 +3089,10 @@ def get(self, ch_nr, dg_nr = ca_block.referenced_channels[i] if memory == 'minimum': axisname = self.groups[dg_nr]['texts']['channels'][ch_nr]['name_addr'] - block = TextBlock(address=axisname, - stream=self._file) + block = TextBlock( + address=axisname, + stream=stream, + ) axisname = block['text'].decode('utf-8').strip(' \t\n\r\0') axisname = axisname.split('\\')[0] else: @@ -3096,7 +3101,8 @@ def get(self, axis_values = self.get( group=dg_nr, index=ch_nr, - samples_only=True) + samples_only=True, + ) axis_values = axis_values[axisname] arrays.append(axis_values) dtype_pair = axisname, axis_values.dtype, shape @@ -3339,7 +3345,7 @@ def get(self, else: block = TextBlock( address=grp['texts']['conversions'][ch_nr]['formula_addr'], - stream=self._file, + stream=stream, ) formula = block['text'].decode('utf-8').strip(' \n\t\0') X = vals @@ -3424,7 +3430,7 @@ def get(self, if address: block = TextBlock( address=address, - stream=self._file, + stream=stream, ) phys.append(block['text']) else: @@ -3434,7 +3440,7 @@ def get(self, if grp['texts']['conversion_tab'][ch_nr].get('default_addr', 0): block = TextBlock( address=grp['texts']['conversion_tab'][ch_nr]['default_addr'], - stream=self._file, + stream=stream, ) default = block['text'] else: @@ -3463,7 +3469,7 @@ def get(self, if address: block = TextBlock( address=address, - stream=self._file, + stream=stream, ) phys.append(block['text']) else: @@ -3472,7 +3478,7 @@ def get(self, if grp['texts']['conversion_tab'][ch_nr].get('default_addr', 0): block = TextBlock( address=grp['texts']['conversion_tab'][ch_nr]['default_addr'], - stream=self._file, + stream=stream, ) default = block['text'] else: diff --git a/test/test_mdf.py b/test/test_mdf.py index 61a44dae7..88572b51f 100644 --- a/test/test_mdf.py +++ b/test/test_mdf.py @@ -1,6 +1,7 @@ #!/usr/bin/env python from __future__ import print_function import os +import random import sys import unittest import shutil @@ -29,34 +30,7 @@ CHANNEL_LEN = 100000 - -class TestMDF(unittest.TestCase): - - def test_measurement(self): - self.assertTrue(MDF) - - @classmethod - def setUpClass(cls): - PYVERSION = sys.version_info[0] - - url = 'https://github.com/danielhrisca/asammdf/files/1565237/test.files.zip' - if PYVERSION == 3: - urllib.request.urlretrieve(url, 'test.zip') - else: - urllib.urlretrieve(url, 'test.zip') - ZipFile(r'test.zip').extractall('tmpdir') - - @classmethod - def tearDownClass(cls): - shutil.rmtree('tmpdir', True) - os.remove('test.zip') - for filename in ('tmp', 'tmp1', 'tmp2')[:1]: - if os.path.isfile(filename): - os.remove(filename) - - def test_read(self): - - channels = { +CHANNELS = { '$ActiveCalibrationPage': array([1, 0, 1, 1], dtype=uint8), '$CalibrationLog': array([b'', b'Switch to reference page', b'Switch to working page', @@ -1545,6 +1519,34 @@ def test_read(self): -736, -656, -576, -496, -416, -336, -256, -176, -96, -16, 64, 144, 224, 304, 384, 464, 544, 624], dtype=int16), } + + +class TestMDF(unittest.TestCase): + + def test_measurement(self): + self.assertTrue(MDF) + + @classmethod + def setUpClass(cls): + PYVERSION = sys.version_info[0] + + url = 'https://github.com/danielhrisca/asammdf/files/1565237/test.files.zip' + if PYVERSION == 3: + urllib.request.urlretrieve(url, 'test.zip') + else: + urllib.urlretrieve(url, 'test.zip') + ZipFile(r'test.zip').extractall('tmpdir') + + @classmethod + def tearDownClass(cls): + shutil.rmtree('tmpdir', True) + os.remove('test.zip') + for filename in ('tmp', 'tmp1', 'tmp2')[:1]: + if os.path.isfile(filename): + os.remove(filename) + + def test_read(self): + print("MDF read tests") ret = True @@ -1556,7 +1558,7 @@ def test_read(self): continue for name in set(input_file.channels_db) - {'time', 't'}: signal = input_file.get(name) - original_samples = channels[name] + original_samples = CHANNELS[name] if signal.samples.dtype.kind == 'f': signal = signal.astype(float32) res = np.array_equal(signal.samples, original_samples) @@ -1622,19 +1624,21 @@ def test_merge(self): self.assertTrue(equal) - def test_cut(self): - print("MDF cut tests") + def test_cut_absolute(self): + print("MDF cut absolute tests") for mdfname in os.listdir('tmpdir'): - for memory in MEMORY[:1]: + for memory in MEMORY: input_file = os.path.join('tmpdir', mdfname) - print(input_file) - MDF(input_file, memory=memory).cut(stop=2).save('tmp1', overwrite=True) - MDF(input_file, memory=memory).cut(start=2).save('tmp2', overwrite=True) + MDF(input_file, memory=memory).cut(start=2, stop=6).save('tmp2', overwrite=True) + MDF(input_file, memory=memory).cut(start=6).save('tmp3', overwrite=True) - MDF.merge(['tmp1', 'tmp2'], MDF(input_file, memory='minimum').version).save('tmp', overwrite=True) + MDF.merge( + ['tmp1', 'tmp2', 'tmp3'], + MDF(input_file, memory='minimum').version, + ).save('tmp', overwrite=True) equal = True @@ -1656,6 +1660,115 @@ def test_cut(self): self.assertTrue(equal) + def test_cut_relative(self): + print("MDF cut relative tests") + + for mdfname in os.listdir('tmpdir'): + for memory in MEMORY: + input_file = os.path.join('tmpdir', mdfname) + + MDF(input_file, memory=memory).cut(stop=3, whence=1).save('tmp1', overwrite=True) + MDF(input_file, memory=memory).cut(start=3, stop=5, whence=1).save('tmp2', overwrite=True) + MDF(input_file, memory=memory).cut(start=5, whence=1).save('tmp3', overwrite=True) + + MDF.merge( + ['tmp1', 'tmp2', 'tmp3'], + MDF(input_file, memory='minimum').version, + ).save('tmp', overwrite=True) + + equal = True + + with MDF(input_file, memory=memory) as mdf, \ + MDF('tmp', memory=memory) as mdf2: + + for i, group in enumerate(mdf.groups): + for j, channel in enumerate(group['channels'][1:], 1): + original = mdf.get(group=i, index=j) + converted = mdf2.get(group=i, index=j) + if not np.array_equal( + original.samples, + converted.samples): + equal = False + if not np.array_equal( + original.timestamps, + converted.timestamps): + equal = False + + self.assertTrue(equal) + + def test_filter(self): + print("MDF filter tests") + + for mdfname in os.listdir('tmpdir'): + for memory in MEMORY: + input_file = os.path.join('tmpdir', mdfname) + + if MDF(input_file, memory=memory).version == '2.00': + continue + + channels_nr = np.random.randint(1, len(CHANNELS) + 1) + + channel_list = random.sample(list(CHANNELS), channels_nr) + + filtered_mdf = MDF(input_file, memory=memory).filter(channel_list, memory=memory) + + self.assertTrue((set(filtered_mdf.channels_db) - {'t', 'time'}) == set(channel_list)) + + equal = True + + with MDF(input_file, memory=memory) as mdf: + + for name in channel_list: + original = mdf.get(name) + filtered = filtered_mdf.get(name) + if not np.array_equal( + original.samples, + filtered.samples): + equal = False + if not np.array_equal( + original.timestamps, + filtered.timestamps): + equal = False + + self.assertTrue(equal) + + def test_select(self): + print("MDF select tests") + + for mdfname in os.listdir('tmpdir'): + for memory in MEMORY: + input_file = os.path.join('tmpdir', mdfname) + + if MDF(input_file, memory=memory).version == '2.00': + continue + + channels_nr = np.random.randint(1, len(CHANNELS) + 1) + + channel_list = random.sample(list(CHANNELS), channels_nr) + + selected_signals = MDF(input_file, memory=memory).select(channel_list) + + self.assertTrue(len(selected_signals) == len(channel_list)) + + self.assertTrue(all(ch.name == name for ch, name in zip(selected_signals, channel_list))) + + equal = True + + with MDF(input_file, memory=memory) as mdf: + + for selected in selected_signals: + original = mdf.get(selected.name) + if not np.array_equal( + original.samples, + selected.samples): + equal = False + if not np.array_equal( + original.timestamps, + selected.timestamps): + equal = False + + self.assertTrue(equal) + if __name__ == '__main__': unittest.main() From ee9d583b48e3be68dc3e321c50f2023b80fc82a5 Mon Sep 17 00:00:00 2001 From: danielhrisca Date: Sun, 24 Dec 2017 23:10:13 +0200 Subject: [PATCH 044/117] update codacy coverage badge --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 23607c5a1..97b33ccb0 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@ [![Build Status](https://travis-ci.org/danielhrisca/asammdf.svg?branch=development)](https://travis-ci.org/danielhrisca/asammdf) [![PyPI version](https://badge.fury.io/py/asammdf.svg)](https://badge.fury.io/py/asammdf) -[![Documentation Status](http://readthedocs.org/projects/asammdf/badge/?version=master)](http://asammdf.readthedocs.io/en/development/?badge=stable) +[![Documentation Status](http://readthedocs.org/projects/asammdf/badge/?version=development)](http://asammdf.readthedocs.io/en/development/?badge=stable) [![Codacy Badge](https://api.codacy.com/project/badge/Grade/a3da21da90ca43a5b72fc24b56880c99)](https://www.codacy.com/app/danielhrisca/asammdf?utm_source=github.com&utm_medium=referral&utm_content=danielhrisca/asammdf&utm_campaign=badger) -[![Codacy Badge](https://api.codacy.com/project/badge/Coverage/0f91740b9c504ad397e3f9405788021e)](https://www.codacy.com/app/yahym/asammdf?utm_source=github.com&utm_medium=referral&utm_content=yahym/asammdf&utm_campaign=Badge_Coverage) +[![Codacy Badge](https://api.codacy.com/project/badge/Coverage/a3da21da90ca43a5b72fc24b56880c99)](https://www.codacy.com/app/danielhrisca/asammdf?utm_source=github.com&utm_medium=referral&utm_content=danielhrisca/asammdf&utm_campaign=Badge_Coverage) *asammdf* is a fast parser/editor for ASAM (Associtation for Standardisation of Automation and Measuring Systems) MDF (Measurement Data Format) files. From c2b96d0af089a1781cfab9f51cca4f81d2cb4c96 Mon Sep 17 00:00:00 2001 From: danielhrisca Date: Sun, 24 Dec 2017 23:13:02 +0200 Subject: [PATCH 045/117] update codacy coverage badge - take 2 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 97b33ccb0..52499d90e 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ [![PyPI version](https://badge.fury.io/py/asammdf.svg)](https://badge.fury.io/py/asammdf) [![Documentation Status](http://readthedocs.org/projects/asammdf/badge/?version=development)](http://asammdf.readthedocs.io/en/development/?badge=stable) [![Codacy Badge](https://api.codacy.com/project/badge/Grade/a3da21da90ca43a5b72fc24b56880c99)](https://www.codacy.com/app/danielhrisca/asammdf?utm_source=github.com&utm_medium=referral&utm_content=danielhrisca/asammdf&utm_campaign=badger) -[![Codacy Badge](https://api.codacy.com/project/badge/Coverage/a3da21da90ca43a5b72fc24b56880c99)](https://www.codacy.com/app/danielhrisca/asammdf?utm_source=github.com&utm_medium=referral&utm_content=danielhrisca/asammdf&utm_campaign=Badge_Coverage) +[![Codacy Badge](https://api.codacy.com/project/badge/Coverage/a3da21da90ca43a5b72fc24b56880c99)](https://www.codacy.com/app/danielhrisca/asammdf?utm_source=github.com&;utm_medium=referral&;utm_content=danielhrisca/asammdf&;utm_campaign=Badge_Coverage) *asammdf* is a fast parser/editor for ASAM (Associtation for Standardisation of Automation and Measuring Systems) MDF (Measurement Data Format) files. From f4a6cbd5ab71204238af33a5ff71bdd28cdf8a90 Mon Sep 17 00:00:00 2001 From: danielhrisca Date: Wed, 27 Dec 2017 19:43:43 +0200 Subject: [PATCH 046/117] fix saving of channel composition channels --- asammdf/mdf_v4.py | 70 ++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 60 insertions(+), 10 deletions(-) diff --git a/asammdf/mdf_v4.py b/asammdf/mdf_v4.py index 2220974d0..f012792c0 100644 --- a/asammdf/mdf_v4.py +++ b/asammdf/mdf_v4.py @@ -1355,10 +1355,10 @@ def append(self, signals, source_info='Python', common_timebase=False): block = TextBlock(text='s', meta=False) if memory != 'minimum': - gp_texts['conversions'][-1]['unit_addr'] = block + gp_texts['channels'][-1]['unit_addr'] = block else: address = tell() - gp_texts['conversions'][-1]['unit_addr'] = address + gp_texts['channels'][-1]['unit_addr'] = address write(bytes(block)) si_text = TextBlock(text=source_info, meta=False) @@ -1795,7 +1795,6 @@ def append(self, signals, source_info='Python', common_timebase=False): gp_conv.append(address) write(bytes(block)) - elif info and 'lower' in info: kargs = {} kargs['conversion_type'] = v4c.CONVERSION_TYPE_RTABX @@ -2082,7 +2081,6 @@ def append(self, signals, source_info='Python', common_timebase=False): else: gp_conv.append(0) - # source for time if memory != 'minimum': gp_source.append(SourceInformation()) else: @@ -2168,12 +2166,9 @@ def append(self, signals, source_info='Python', common_timebase=False): # source for time if memory != 'minimum': - gp_source.append(SourceInformation()) + gp_source.append(None) else: - address = tell() - block = SourceInformation() - write(bytes(block)) - gp_source.append(address) + gp_source.append(0) # add channel block min_val, max_val = get_min_max(signal.samples) @@ -4225,6 +4220,22 @@ def _save_with_metadata(self, dst, overwrite, compression): channel['next_ch_addr'] = group_channels[j + 1].address group_channels[-1]['next_ch_addr'] = 0 + # channel dependecies + j = 0 + while j < len(gp['channels']): + dep_list = gp['channel_dependencies'][j] + if dep_list and all( + isinstance(dep, Channel) for dep in dep_list): + gp['channels'][j]['component_addr'] = dep_list[0].address + gp['channels'][j]['next_ch_addr'] = dep_list[-1]['next_ch_addr'] + dep_list[-1]['next_ch_addr'] = 0 + j += len(dep_list) + + for dep in dep_list: + dep['source_addr'] = 0 + else: + j += 1 + # channel group gp['channel_group'].address = address gp['channel_group']['first_ch_addr'] = gp['channels'][0].address @@ -4623,22 +4634,34 @@ def _save_without_metadata(self, dst, overwrite, compression): gp['temp_channel_sources'].append(0) # channel dependecies + temp_deps = [] for j, dep_list in enumerate(gp['channel_dependencies']): if dep_list: if all(isinstance(dep, ChannelArrayBlock) for dep in dep_list): + temp_deps.append([]) + for dep in dep_list: address = tell() dep.address = address + temp_deps[-1].append(address) write(bytes(dep)) for k, dep in enumerate(dep_list[:-1]): dep['composition_addr'] = dep_list[k + 1].address dep_list[-1]['composition_addr'] = 0 + else: + temp_deps.append([]) + for _ in dep_list: + temp_deps[-1].append(0) + else: + temp_deps.append(0) + + # channels blocks = [] chans = [] - address = tell() + address = blocks_start_addr = tell() gp['temp_channels'] = ch_addrs = [] gp['channel_group']['first_ch_addr'] = address for j, channel in enumerate(gp['channels']): @@ -4689,6 +4712,33 @@ def _save_without_metadata(self, dst, overwrite, compression): for j, channel in enumerate(chans[:-1]): channel['next_ch_addr'] = chans[j + 1].address chans[-1]['next_ch_addr'] = 0 + + # channel dependecies + j = 0 + while j < len(gp['channels']): + dep_list = gp['channel_dependencies'][j] + if dep_list and all( + isinstance(dep, int) for dep in dep_list): + + dep = chans[j+1] + + channel = chans[j] + channel['component_addr'] = dep.address + + dep = chans[j+len(dep_list)] + channel['next_ch_addr'] = dep['next_ch_addr'] + dep['next_ch_addr'] = 0 + + for k, dep_addr in enumerate(dep_list): + dep = chans[j+1+k] + dep['source_addr'] = 0 + + j += len(dep_list) + else: + j += 1 + + seek(blocks_start_addr, v4c.SEEK_START) + for block in blocks: write(bytes(block)) From 20d39871c991b864ab096bd449340ed1d8abfdc8 Mon Sep 17 00:00:00 2001 From: danielhrisca Date: Wed, 27 Dec 2017 20:36:17 +0200 Subject: [PATCH 047/117] fixes related to channel composition --- asammdf/mdf.py | 2 +- asammdf/mdf_v4.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/asammdf/mdf.py b/asammdf/mdf.py index bd72e1643..ef94ecae3 100644 --- a/asammdf/mdf.py +++ b/asammdf/mdf.py @@ -116,7 +116,7 @@ def _excluded_channels(self, index): for dependencies in group['channel_dependencies']: if dependencies is None: continue - if all(dep['id'] == b'##CN' for dep in dependencies): + if all(dep['id'] == b'##CN' if not isinstance(dep, int) else True for dep in dependencies): for ch in dependencies: excluded_channels.add(channels.index(ch)) else: diff --git a/asammdf/mdf_v4.py b/asammdf/mdf_v4.py index f012792c0..b54a19498 100644 --- a/asammdf/mdf_v4.py +++ b/asammdf/mdf_v4.py @@ -399,7 +399,7 @@ def _read(self): continue for dep in dep_list: - if isinstance(dep, Channel): + if isinstance(dep, (Channel, int)): break else: conditions = ( @@ -2931,7 +2931,7 @@ def get(self, arrays = [] name = channel.name - if all(isinstance(dep, Channel) for dep in dependency_list): + if all(isinstance(dep, (Channel, int)) for dep in dependency_list): # structure channel composition if memory == 'minimum': names = [] From 93b188717ecba85243a2dae25d5fcc4c96c9c841 Mon Sep 17 00:00:00 2001 From: Daniel Hrisca Date: Wed, 27 Dec 2017 20:39:28 +0200 Subject: [PATCH 048/117] Update README.md third attempt to fix codacy coverage badge --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 52499d90e..e299b06cf 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ [![PyPI version](https://badge.fury.io/py/asammdf.svg)](https://badge.fury.io/py/asammdf) [![Documentation Status](http://readthedocs.org/projects/asammdf/badge/?version=development)](http://asammdf.readthedocs.io/en/development/?badge=stable) [![Codacy Badge](https://api.codacy.com/project/badge/Grade/a3da21da90ca43a5b72fc24b56880c99)](https://www.codacy.com/app/danielhrisca/asammdf?utm_source=github.com&utm_medium=referral&utm_content=danielhrisca/asammdf&utm_campaign=badger) -[![Codacy Badge](https://api.codacy.com/project/badge/Coverage/a3da21da90ca43a5b72fc24b56880c99)](https://www.codacy.com/app/danielhrisca/asammdf?utm_source=github.com&;utm_medium=referral&;utm_content=danielhrisca/asammdf&;utm_campaign=Badge_Coverage) +[![Codacy Badge](https://api.codacy.com/project/badge/Coverage/a3da21da90ca43a5b72fc24b56880c99)](https://www.codacy.com/app/danielhrisca/asammdf?utm_source=github.com&utm_medium=referral&utm_content=danielhrisca/asammdf&utm_campaign=Badge_Coverage) *asammdf* is a fast parser/editor for ASAM (Associtation for Standardisation of Automation and Measuring Systems) MDF (Measurement Data Format) files. From dc97a64b91b5fedcb0ca92cf6bf81cd6fba51b22 Mon Sep 17 00:00:00 2001 From: danielhrisca Date: Wed, 27 Dec 2017 20:50:26 +0200 Subject: [PATCH 049/117] coverage badge for dev branch --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e299b06cf..33edb7514 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ [![PyPI version](https://badge.fury.io/py/asammdf.svg)](https://badge.fury.io/py/asammdf) [![Documentation Status](http://readthedocs.org/projects/asammdf/badge/?version=development)](http://asammdf.readthedocs.io/en/development/?badge=stable) [![Codacy Badge](https://api.codacy.com/project/badge/Grade/a3da21da90ca43a5b72fc24b56880c99)](https://www.codacy.com/app/danielhrisca/asammdf?utm_source=github.com&utm_medium=referral&utm_content=danielhrisca/asammdf&utm_campaign=badger) -[![Codacy Badge](https://api.codacy.com/project/badge/Coverage/a3da21da90ca43a5b72fc24b56880c99)](https://www.codacy.com/app/danielhrisca/asammdf?utm_source=github.com&utm_medium=referral&utm_content=danielhrisca/asammdf&utm_campaign=Badge_Coverage) +[![Codacy Badge](https://api.codacy.com/project/badge/Coverage/a3da21da90ca43a5b72fc24b56880c99?branch=development)](https://www.codacy.com/app/danielhrisca/asammdf?utm_source=github.com&utm_medium=referral&utm_content=danielhrisca/asammdf&utm_campaign=Badge_Coverage) *asammdf* is a fast parser/editor for ASAM (Associtation for Standardisation of Automation and Measuring Systems) MDF (Measurement Data Format) files. From 3ab5bc68889c13e8b0b621a5427dc8448119f9db Mon Sep 17 00:00:00 2001 From: danielhrisca Date: Wed, 27 Dec 2017 20:52:07 +0200 Subject: [PATCH 050/117] set codacy grade badge to development branch --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 33edb7514..e84ada457 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ [![Build Status](https://travis-ci.org/danielhrisca/asammdf.svg?branch=development)](https://travis-ci.org/danielhrisca/asammdf) [![PyPI version](https://badge.fury.io/py/asammdf.svg)](https://badge.fury.io/py/asammdf) [![Documentation Status](http://readthedocs.org/projects/asammdf/badge/?version=development)](http://asammdf.readthedocs.io/en/development/?badge=stable) -[![Codacy Badge](https://api.codacy.com/project/badge/Grade/a3da21da90ca43a5b72fc24b56880c99)](https://www.codacy.com/app/danielhrisca/asammdf?utm_source=github.com&utm_medium=referral&utm_content=danielhrisca/asammdf&utm_campaign=badger) +[![Codacy Badge](https://api.codacy.com/project/badge/Grade/a3da21da90ca43a5b72fc24b56880c99?branch=development)](https://www.codacy.com/app/danielhrisca/asammdf?utm_source=github.com&utm_medium=referral&utm_content=danielhrisca/asammdf&utm_campaign=badger) [![Codacy Badge](https://api.codacy.com/project/badge/Coverage/a3da21da90ca43a5b72fc24b56880c99?branch=development)](https://www.codacy.com/app/danielhrisca/asammdf?utm_source=github.com&utm_medium=referral&utm_content=danielhrisca/asammdf&utm_campaign=Badge_Coverage) From c9cc4b4a09e4e16595ab30ea9d2e8686ec4eee47 Mon Sep 17 00:00:00 2001 From: danielhrisca Date: Thu, 28 Dec 2017 11:52:18 +0200 Subject: [PATCH 051/117] allow passing MDF instances to the merge method, alongside string file names --- README.md | 4 ++-- asammdf/mdf.py | 8 ++++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index e84ada457..e299b06cf 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@ [![Build Status](https://travis-ci.org/danielhrisca/asammdf.svg?branch=development)](https://travis-ci.org/danielhrisca/asammdf) [![PyPI version](https://badge.fury.io/py/asammdf.svg)](https://badge.fury.io/py/asammdf) [![Documentation Status](http://readthedocs.org/projects/asammdf/badge/?version=development)](http://asammdf.readthedocs.io/en/development/?badge=stable) -[![Codacy Badge](https://api.codacy.com/project/badge/Grade/a3da21da90ca43a5b72fc24b56880c99?branch=development)](https://www.codacy.com/app/danielhrisca/asammdf?utm_source=github.com&utm_medium=referral&utm_content=danielhrisca/asammdf&utm_campaign=badger) -[![Codacy Badge](https://api.codacy.com/project/badge/Coverage/a3da21da90ca43a5b72fc24b56880c99?branch=development)](https://www.codacy.com/app/danielhrisca/asammdf?utm_source=github.com&utm_medium=referral&utm_content=danielhrisca/asammdf&utm_campaign=Badge_Coverage) +[![Codacy Badge](https://api.codacy.com/project/badge/Grade/a3da21da90ca43a5b72fc24b56880c99)](https://www.codacy.com/app/danielhrisca/asammdf?utm_source=github.com&utm_medium=referral&utm_content=danielhrisca/asammdf&utm_campaign=badger) +[![Codacy Badge](https://api.codacy.com/project/badge/Coverage/a3da21da90ca43a5b72fc24b56880c99)](https://www.codacy.com/app/danielhrisca/asammdf?utm_source=github.com&utm_medium=referral&utm_content=danielhrisca/asammdf&utm_campaign=Badge_Coverage) *asammdf* is a fast parser/editor for ASAM (Associtation for Standardisation of Automation and Measuring Systems) MDF (Measurement Data Format) files. diff --git a/asammdf/mdf.py b/asammdf/mdf.py index ef94ecae3..6f91646ca 100644 --- a/asammdf/mdf.py +++ b/asammdf/mdf.py @@ -576,7 +576,7 @@ def merge(files, outversion='4.10', memory='full'): Parameters ---------- files : list | tuple - list of MDF file names + list of MDF file names or MDF instances outversion : str merged file version memory : str @@ -595,7 +595,11 @@ def merge(files, outversion='4.10', memory='full'): if not files: raise MdfException('No files given for merge') - files = [MDF(file, memory) for file in files] + files = [ + MDF(file, memory) + for file in files + if not isinstance(file, MDF) + ] if not len(set(len(file.groups) for file in files)) == 1: message = ("Can't merge files: " From 30cd050860a17913b57fb57fe14c439b57230e75 Mon Sep 17 00:00:00 2001 From: danielhrisca Date: Thu, 28 Dec 2017 11:54:54 +0200 Subject: [PATCH 052/117] allow passing MDF instances to the merge method, alongside string file names - fixed list comprehension --- asammdf/mdf.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/asammdf/mdf.py b/asammdf/mdf.py index 6f91646ca..23d4f1ddf 100644 --- a/asammdf/mdf.py +++ b/asammdf/mdf.py @@ -596,9 +596,8 @@ def merge(files, outversion='4.10', memory='full'): raise MdfException('No files given for merge') files = [ - MDF(file, memory) + file if isinstance(file, MDF) else MDF(file, memory) for file in files - if not isinstance(file, MDF) ] if not len(set(len(file.groups) for file in files)) == 1: From 5599d242e83aa19ea2ca2ba521936e852b5f2003 Mon Sep 17 00:00:00 2001 From: danielhrisca Date: Thu, 28 Dec 2017 12:02:44 +0200 Subject: [PATCH 053/117] unzip demo test file to dedicated temporary folder in preparation for adding channel array and channel composition test --- README.md | 4 ++-- test/test_mdf.py | 32 ++++++++++++++++---------------- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index e299b06cf..e84ada457 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@ [![Build Status](https://travis-ci.org/danielhrisca/asammdf.svg?branch=development)](https://travis-ci.org/danielhrisca/asammdf) [![PyPI version](https://badge.fury.io/py/asammdf.svg)](https://badge.fury.io/py/asammdf) [![Documentation Status](http://readthedocs.org/projects/asammdf/badge/?version=development)](http://asammdf.readthedocs.io/en/development/?badge=stable) -[![Codacy Badge](https://api.codacy.com/project/badge/Grade/a3da21da90ca43a5b72fc24b56880c99)](https://www.codacy.com/app/danielhrisca/asammdf?utm_source=github.com&utm_medium=referral&utm_content=danielhrisca/asammdf&utm_campaign=badger) -[![Codacy Badge](https://api.codacy.com/project/badge/Coverage/a3da21da90ca43a5b72fc24b56880c99)](https://www.codacy.com/app/danielhrisca/asammdf?utm_source=github.com&utm_medium=referral&utm_content=danielhrisca/asammdf&utm_campaign=Badge_Coverage) +[![Codacy Badge](https://api.codacy.com/project/badge/Grade/a3da21da90ca43a5b72fc24b56880c99?branch=development)](https://www.codacy.com/app/danielhrisca/asammdf?utm_source=github.com&utm_medium=referral&utm_content=danielhrisca/asammdf&utm_campaign=badger) +[![Codacy Badge](https://api.codacy.com/project/badge/Coverage/a3da21da90ca43a5b72fc24b56880c99?branch=development)](https://www.codacy.com/app/danielhrisca/asammdf?utm_source=github.com&utm_medium=referral&utm_content=danielhrisca/asammdf&utm_campaign=Badge_Coverage) *asammdf* is a fast parser/editor for ASAM (Associtation for Standardisation of Automation and Measuring Systems) MDF (Measurement Data Format) files. diff --git a/test/test_mdf.py b/test/test_mdf.py index 88572b51f..d3a4eb312 100644 --- a/test/test_mdf.py +++ b/test/test_mdf.py @@ -1535,11 +1535,11 @@ def setUpClass(cls): urllib.request.urlretrieve(url, 'test.zip') else: urllib.urlretrieve(url, 'test.zip') - ZipFile(r'test.zip').extractall('tmpdir') + ZipFile(r'test.zip').extractall('tmpdir_demo') @classmethod def tearDownClass(cls): - shutil.rmtree('tmpdir', True) + shutil.rmtree('tmpdir_demo', True) os.remove('test.zip') for filename in ('tmp', 'tmp1', 'tmp2')[:1]: if os.path.isfile(filename): @@ -1551,9 +1551,9 @@ def test_read(self): ret = True - for mdf in os.listdir('tmpdir'): + for mdf in os.listdir('tmpdir_demo'): for memory in MEMORY: - with MDF(os.path.join('tmpdir', mdf), memory=memory) as input_file: + with MDF(os.path.join('tmpdir_demo', mdf), memory=memory) as input_file: if input_file.version == '2.00': continue for name in set(input_file.channels_db) - {'time', 't'}: @@ -1571,9 +1571,9 @@ def test_convert(self): print("MDF convert tests") for out in SUPPORTED_VERSIONS[1:]: - for mdfname in os.listdir('tmpdir'): + for mdfname in os.listdir('tmpdir_demo'): for memory in MEMORY: - input_file = os.path.join('tmpdir', mdfname) + input_file = os.path.join('tmpdir_demo', mdfname) with MDF(input_file, memory=memory) as mdf: mdf.convert(out, memory=memory).save('tmp', overwrite=True) @@ -1601,9 +1601,9 @@ def test_merge(self): print("MDF merge tests") for out in SUPPORTED_VERSIONS: - for mdfname in os.listdir('tmpdir'): + for mdfname in os.listdir('tmpdir_demo'): for memory in MEMORY: - input_file = os.path.join('tmpdir', mdfname) + input_file = os.path.join('tmpdir_demo', mdfname) files = [input_file, ] * 4 MDF.merge(files, out, memory).save('tmp', overwrite=True) @@ -1627,9 +1627,9 @@ def test_merge(self): def test_cut_absolute(self): print("MDF cut absolute tests") - for mdfname in os.listdir('tmpdir'): + for mdfname in os.listdir('tmpdir_demo'): for memory in MEMORY: - input_file = os.path.join('tmpdir', mdfname) + input_file = os.path.join('tmpdir_demo', mdfname) MDF(input_file, memory=memory).cut(stop=2).save('tmp1', overwrite=True) MDF(input_file, memory=memory).cut(start=2, stop=6).save('tmp2', overwrite=True) @@ -1663,9 +1663,9 @@ def test_cut_absolute(self): def test_cut_relative(self): print("MDF cut relative tests") - for mdfname in os.listdir('tmpdir'): + for mdfname in os.listdir('tmpdir_demo'): for memory in MEMORY: - input_file = os.path.join('tmpdir', mdfname) + input_file = os.path.join('tmpdir_demo', mdfname) MDF(input_file, memory=memory).cut(stop=3, whence=1).save('tmp1', overwrite=True) MDF(input_file, memory=memory).cut(start=3, stop=5, whence=1).save('tmp2', overwrite=True) @@ -1699,9 +1699,9 @@ def test_cut_relative(self): def test_filter(self): print("MDF filter tests") - for mdfname in os.listdir('tmpdir'): + for mdfname in os.listdir('tmpdir_demo'): for memory in MEMORY: - input_file = os.path.join('tmpdir', mdfname) + input_file = os.path.join('tmpdir_demo', mdfname) if MDF(input_file, memory=memory).version == '2.00': continue @@ -1735,9 +1735,9 @@ def test_filter(self): def test_select(self): print("MDF select tests") - for mdfname in os.listdir('tmpdir'): + for mdfname in os.listdir('tmpdir_demo'): for memory in MEMORY: - input_file = os.path.join('tmpdir', mdfname) + input_file = os.path.join('tmpdir_demo', mdfname) if MDF(input_file, memory=memory).version == '2.00': continue From 37428ff1228c2b2628272ec7997a5b3ed5540808 Mon Sep 17 00:00:00 2001 From: danielhrisca Date: Thu, 28 Dec 2017 13:03:49 +0200 Subject: [PATCH 054/117] improve README.md --- README.md | 37 ++++++++++++++++--------------------- 1 file changed, 16 insertions(+), 21 deletions(-) diff --git a/README.md b/README.md index e84ada457..ef4ac2d17 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,3 @@ -[![Build Status](https://travis-ci.org/danielhrisca/asammdf.svg?branch=development)](https://travis-ci.org/danielhrisca/asammdf) -[![PyPI version](https://badge.fury.io/py/asammdf.svg)](https://badge.fury.io/py/asammdf) -[![Documentation Status](http://readthedocs.org/projects/asammdf/badge/?version=development)](http://asammdf.readthedocs.io/en/development/?badge=stable) -[![Codacy Badge](https://api.codacy.com/project/badge/Grade/a3da21da90ca43a5b72fc24b56880c99?branch=development)](https://www.codacy.com/app/danielhrisca/asammdf?utm_source=github.com&utm_medium=referral&utm_content=danielhrisca/asammdf&utm_campaign=badger) -[![Codacy Badge](https://api.codacy.com/project/badge/Coverage/a3da21da90ca43a5b72fc24b56880c99?branch=development)](https://www.codacy.com/app/danielhrisca/asammdf?utm_source=github.com&utm_medium=referral&utm_content=danielhrisca/asammdf&utm_campaign=Badge_Coverage) *asammdf* is a fast parser/editor for ASAM (Associtation for Standardisation of Automation and Measuring Systems) MDF (Measurement Data Format) files. @@ -11,17 +6,23 @@ *asammdf* works on Python 2.7, and Python >= 3.4 (Travis CI tests done with Python 2.7 and Python >= 3.5) +# Status +! | master | development +--|--|-- +Travis CI | [![Build Status](https://travis-ci.org/danielhrisca/asammdf.svg?branch=master)](https://travis-ci.org/danielhrisca/asammdf) | [![Build Status](https://travis-ci.org/danielhrisca/asammdf.svg?branch=development)](https://travis-ci.org/danielhrisca/asammdf) +Coverage | [![Codacy Badge](https://api.codacy.com/project/badge/Coverage/a3da21da90ca43a5b72fc24b56880c99?branch=master)](https://www.codacy.com/app/danielhrisca/asammdf?utm_source=github.com&utm_medium=referral&utm_content=danielhrisca/asammdf&utm_campaign=Badge_Coverage) | [![Codacy Badge](https://api.codacy.com/project/badge/Coverage/a3da21da90ca43a5b72fc24b56880c99?branch=development)](https://www.codacy.com/app/danielhrisca/asammdf?utm_source=github.com&utm_medium=referral&utm_content=danielhrisca/asammdf&utm_campaign=Badge_Coverage) +ReadTheDocs | [![Documentation Status](http://readthedocs.org/projects/asammdf/badge/?version=master)](http://asammdf.readthedocs.io/en/master/?badge=stable) | [![Documentation Status](http://readthedocs.org/projects/asammdf/badge/?version=development)](http://asammdf.readthedocs.io/en/development/?badge=stable) +PyPI | [![PyPI version](https://badge.fury.io/py/asammdf.svg)](https://badge.fury.io/py/asammdf) | -Project goals -============= + +# Project goals The main goals for this library are: * to be faster than the other Python based mdf libraries * to have clean and easy to understand code base * to have minimal 3-rd party dependencies -Features -======== +# Features * create new mdf files from scratch * append new channels @@ -54,8 +55,7 @@ Features * usually a measurement will have channels from different sources at different rates * the *Signal* class facilitates operations with such channels -Major features not implemented (yet) -==================================== +# Major features not implemented (yet) * for version 3 * functionality related to sample reduction block (but the class is defined) @@ -71,8 +71,7 @@ Major features not implemented (yet) * channels with default X axis * channels with reference to attachment -Usage -===== +# Usage ```python from asammdf import MDF @@ -98,12 +97,10 @@ Usage Check the *examples* folder for extended usage demo, or the documentation http://asammdf.readthedocs.io/en/development/examples.html -Documentation -============= +# Documentation http://asammdf.readthedocs.io/en/development -Installation -============ +# Installation *asammdf* is available on * github: https://github.com/danielhrisca/asammdf/ @@ -113,8 +110,7 @@ Installation pip install asammdf ``` -Dependencies -============ +# Dependencies asammdf uses the following libraries * numpy : the heart that makes all tick @@ -129,8 +125,7 @@ optional dependencies needed for exports * xlsxwriter : for Excel export * scipy : for Matlab .mat export -Benchmarks -========== +# Benchmarks http://asammdf.readthedocs.io/en/development/benchmarks.html From a93f1f74c102df4b7093511c2dc6d7a9f480f840 Mon Sep 17 00:00:00 2001 From: danielhrisca Date: Thu, 28 Dec 2017 13:06:54 +0200 Subject: [PATCH 055/117] add missing Codacy badges --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index ef4ac2d17..914ddc357 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,7 @@ ! | master | development --|--|-- Travis CI | [![Build Status](https://travis-ci.org/danielhrisca/asammdf.svg?branch=master)](https://travis-ci.org/danielhrisca/asammdf) | [![Build Status](https://travis-ci.org/danielhrisca/asammdf.svg?branch=development)](https://travis-ci.org/danielhrisca/asammdf) +Codacy | [![Codacy Badge](https://api.codacy.com/project/badge/Grade/a3da21da90ca43a5b72fc24b56880c99?branch=master)](https://www.codacy.com/app/danielhrisca/asammdf?utm_source=github.com&utm_medium=referral&utm_content=danielhrisca/asammdf&utm_campaign=badger) | [![Codacy Badge](https://api.codacy.com/project/badge/Grade/a3da21da90ca43a5b72fc24b56880c99?branch=development)](https://www.codacy.com/app/danielhrisca/asammdf?utm_source=github.com&utm_medium=referral&utm_content=danielhrisca/asammdf&utm_campaign=badger) Coverage | [![Codacy Badge](https://api.codacy.com/project/badge/Coverage/a3da21da90ca43a5b72fc24b56880c99?branch=master)](https://www.codacy.com/app/danielhrisca/asammdf?utm_source=github.com&utm_medium=referral&utm_content=danielhrisca/asammdf&utm_campaign=Badge_Coverage) | [![Codacy Badge](https://api.codacy.com/project/badge/Coverage/a3da21da90ca43a5b72fc24b56880c99?branch=development)](https://www.codacy.com/app/danielhrisca/asammdf?utm_source=github.com&utm_medium=referral&utm_content=danielhrisca/asammdf&utm_campaign=Badge_Coverage) ReadTheDocs | [![Documentation Status](http://readthedocs.org/projects/asammdf/badge/?version=master)](http://asammdf.readthedocs.io/en/master/?badge=stable) | [![Documentation Status](http://readthedocs.org/projects/asammdf/badge/?version=development)](http://asammdf.readthedocs.io/en/development/?badge=stable) PyPI | [![PyPI version](https://badge.fury.io/py/asammdf.svg)](https://badge.fury.io/py/asammdf) | From 3c7a1a9daf4ef59b4e21e6718c2affde628e6533 Mon Sep 17 00:00:00 2001 From: danielhrisca Date: Thu, 28 Dec 2017 15:49:02 +0200 Subject: [PATCH 056/117] added tests for mdf version 4 arrays --- asammdf/mdf.py | 8 +- test/test_mdf.py | 1637 ++++------------------------------------------ test/utils.py | 1583 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 1729 insertions(+), 1499 deletions(-) diff --git a/asammdf/mdf.py b/asammdf/mdf.py index 23d4f1ddf..c6a14dc6b 100644 --- a/asammdf/mdf.py +++ b/asammdf/mdf.py @@ -116,7 +116,9 @@ def _excluded_channels(self, index): for dependencies in group['channel_dependencies']: if dependencies is None: continue - if all(dep['id'] == b'##CN' if not isinstance(dep, int) else True for dep in dependencies): + if all(dep['id'] == b'##CN' + if not isinstance(dep, int) else True + for dep in dependencies): for ch in dependencies: excluded_channels.add(channels.index(ch)) else: @@ -515,7 +517,9 @@ def filter(self, channels, memory=None): dependencies = grp['channel_dependencies'][index] if dependencies is None: continue - if all(dep['id'] == b'##CN' for dep in dependencies): + if all(dep['id'] == b'##CN' + if not isinstance(dep, int) else True + for dep in dependencies): channels = grp['channels'] for ch in dependencies: excluded_channels[group].append(channels.index(ch)) diff --git a/test/test_mdf.py b/test/test_mdf.py index d3a4eb312..d603afd7a 100644 --- a/test/test_mdf.py +++ b/test/test_mdf.py @@ -25,1501 +25,15 @@ uint64, ) -from utils import MEMORY +from utils import ( + CHANNELS_DEMO, + CHANNELS_ARRAY, + MEMORY, +) from asammdf import MDF, SUPPORTED_VERSIONS CHANNEL_LEN = 100000 -CHANNELS = { - -'$ActiveCalibrationPage': array([1, 0, 1, 1], dtype=uint8), -'$CalibrationLog': array([b'', b'Switch to reference page', b'Switch to working page', - b'Switch to working page'], - dtype='|S24'), -'ASAM.M.SCALAR.UBYTE.TAB_NOINTP_DEFAULT_VALUE': array([ 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 104. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 108. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 102. , - 110.66666412, 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. ], dtype=float32), -'ASAM_[0].M.MATRIX_DIM_16_1_1.UBYTE.IDENTICAL': array([ 88, 98, 108, 118, 128, 138, 148, 158, 168, 178, 188, 198, 208, - 218, 228, 238, 248, 2, 12, 22, 32, 42, 52, 62, 72, 82, - 92, 102, 112, 122, 132, 142, 152, 162, 172, 182, 192, 202, 212, - 222, 0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110, - 120, 130, 140, 150, 160, 170, 180, 190, 200, 210, 220, 230, 240, - 250, 4, 14, 24, 34, 44, 54, 64, 74, 84, 94, 104, 114, - 124, 134, 144, 154, 164, 174, 184, 194, 204, 214, 224, 234], dtype=uint8), -'ASAM.M.SCALAR.SWORD.IDENTICAL': array([900, 910, 920, 930, 940, 950, 960, 970, 980, 990, 0, 10, 20, - 30, 40, 50, 60, 70, 80, 90, 100, 110, 120, 130, 140, 150, - 160, 170, 180, 190, 200, 210, 220, 230, 240, 250, 260, 270, 280, - 290, 300, 310, 320, 330, 340, 350, 360, 370, 380, 390, 400, 410, - 420, 430, 440, 450, 460, 470, 480, 490, 500, 510, 520, 530, 540, - 550, 560, 570, 580, 590, 600, 610, 620, 630, 640, 650, 660, 670, - 680, 690, 700, 710, 720, 730, 740, 750, 760, 770, 780, 790], dtype=int16), -'ASAM.M.SCALAR.UBYTE.TAB_INTP_DEFAULT_VALUE': array([ 111., 111., 111., 111., 111., 111., 111., 111., 111., - 111., 111., 111., 111., 111., 111., 111., 111., 111., - 111., 111., 100., 110., 111., 111., 111., 111., 111., - 111., 111., 111., 111., 111., 111., 111., 111., 111., - 111., 111., 111., 111., 111., 111., 111., 111., 111., - 111., 104., 111., 111., 111., 111., 111., 111., 111., - 111., 111., 111., 111., 111., 111., 111., 111., 111., - 111., 111., 111., 111., 111., 111., 111., 111., 111., - 108., 111., 111., 111., 111., 111., 111., 111., 111., - 111., 111., 111., 111., 111., 111., 111., 111., 111.], dtype=float32), -'ASAM.M.SCALAR.UBYTE.FORM_X_PLUS_4': array([ 4., 14., 24., 34., 44., 54., 64., 74., 84., - 94., 104., 114., 124., 134., 144., 154., 164., 174., - 184., 194., 204., 214., 224., 234., 244., 254., 8., - 18., 28., 38., 48., 58., 68., 78., 88., 98., - 108., 118., 128., 138., 148., 158., 168., 178., 188., - 198., 208., 218., 228., 238., 248., 258., 12., 22., - 32., 42., 52., 62., 72., 82., 92., 102., 112., - 122., 132., 142., 152., 162., 172., 182., 192., 202., - 212., 222., 232., 242., 252., 6., 16., 26., 36., - 46., 56., 66., 76., 86., 96., 106., 116., 126.], dtype=float32), -'ASAM.M.SCALAR.SLONG.IDENTICAL': array([200, 210, 220, 230, 240, 250, 260, 270, 280, 290, 300, 310, 320, - 330, 340, 350, 360, 370, 380, 390, 400, 410, 420, 430, 440, 450, - 460, 470, 480, 490, 500, 510, 520, 530, 540, 550, 560, 570, 580, - 590, 600, 610, 620, 630, 640, 650, 660, 670, 680, 690, 700, 710, - 720, 730, 740, 750, 760, 770, 780, 790, 800, 810, 820, 830, 840, - 850, 860, 870, 880, 890, 900, 910, 920, 930, 940, 950, 960, 970, - 980, 990, 0, 10, 20, 30, 40, 50, 60, 70, 80, 90]), -'ASAM.M.SCALAR.UBYTE.IDENTICAL': array([188, 198, 208, 218, 228, 238, 248, 2, 12, 22, 32, 42, 52, - 62, 72, 82, 92, 102, 112, 122, 132, 142, 152, 162, 172, 182, - 192, 202, 212, 222, 0, 10, 20, 30, 40, 50, 60, 70, 80, - 90, 100, 110, 120, 130, 140, 150, 160, 170, 180, 190, 200, 210, - 220, 230, 240, 250, 4, 14, 24, 34, 44, 54, 64, 74, 84, - 94, 104, 114, 124, 134, 144, 154, 164, 174, 184, 194, 204, 214, - 224, 234, 244, 254, 8, 18, 28, 38, 48, 58, 68, 78], dtype=uint8), -'ASAM.M.SCALAR.UBYTE.TAB_INTP_NO_DEFAULT_VALUE': array([ 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 108. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 102. , 110.66666412, 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 100. , 110. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 104. , 111. , - 111. , 111. ], dtype=float32), -'ASAM.M.SCALAR.SBYTE.LINEAR_MUL_2': array([-136., -116., -96., -76., -56., -36., -16., 4., 24., - 44., 64., 84., 104., 124., 144., 164., 184., 204., - 224., 244., -248., -228., -208., -188., -168., -148., -128., - -108., -88., -68., 0., 20., 40., 60., 80., 100., - 120., 140., 160., 180., 200., 220., 240., -252., -232., - -212., -192., -172., -152., -132., -112., -92., -72., -52., - -32., -12., 8., 28., 48., 68., 88., 108., 128., - 148., 168., 188., 208., 228., 248., -244., -224., -204., - -184., -164., -144., -124., -104., -84., -64., -44., -24., - -4., 16., 36., 56., 76., 96., 116., 136., 156.], dtype=float32), -'ASAM_[0].M.ARRAY_SIZE_16.UBYTE.IDENTICAL': array([ 44, 54, 64, 74, 84, 94, 104, 114, 124, 134, 144, 154, 164, - 174, 184, 194, 204, 214, 224, 234, 244, 254, 8, 18, 28, 38, - 48, 58, 68, 78, 88, 98, 108, 118, 128, 138, 148, 158, 168, - 178, 188, 198, 208, 218, 228, 238, 248, 2, 12, 22, 32, 42, - 52, 62, 72, 82, 92, 102, 112, 122, 132, 142, 152, 162, 172, - 182, 192, 202, 212, 222, 0, 10, 20, 30, 40, 50, 60, 70, - 80, 90, 100, 110, 120, 130, 140, 150, 160, 170, 180, 190], dtype=uint8), -'ASAM_[0][0].M.MATRIX_DIM_8_2_1.UBYTE.IDENTICAL': array([244, 254, 8, 18, 28, 38, 48, 58, 68, 78, 88, 98, 108, - 118, 128, 138, 148, 158, 168, 178, 188, 198, 208, 218, 228, 238, - 248, 2, 12, 22, 32, 42, 52, 62, 72, 82, 92, 102, 112, - 122, 132, 142, 152, 162, 172, 182, 192, 202, 212, 222, 0, 10, - 20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120, 130, 140, - 150, 160, 170, 180, 190, 200, 210, 220, 230, 240, 250, 4, 14, - 24, 34, 44, 54, 64, 74, 84, 94, 104, 114, 124, 134], dtype=uint8), -'ASAM.M.SCALAR.UWORD.IDENTICAL.BITMASK_0FF0': array([61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 62, 62, 62, - 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, - 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, - 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, - 62, 62, 62, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, - 61, 61, 61, 61, 61, 61, 61, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, - 60, 60, 60, 60, 60, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, - 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 57, 57, 57, 57, 57, 57, 57, - 57, 57, 56, 56, 56, 56, 56, 56, 56, 56, 56, 55, 55, 55, 55, 55, 55, - 55, 55, 54, 54, 54, 54, 54, 54, 54, 54, 53, 53, 53, 53, 53, 53, 53, - 52, 52, 52, 52, 52, 52, 52, 51, 51, 51, 51, 51, 51, 51, 50, 50, 50, - 50, 50, 50, 49, 49, 49, 49, 49, 49, 48, 48, 48, 48, 48, 48, 47, 47, - 47, 47, 47, 47, 46, 46, 46, 46, 46, 46, 45, 45, 45, 45, 45, 45, 44, - 44, 44, 44, 44, 44, 43, 43, 43, 43, 43, 42, 42, 42, 42, 42, 42, 41, - 41, 41, 41, 41, 40, 40, 40, 40, 40, 39, 39, 39, 39, 39, 39, 38, 38, - 38, 38, 38, 37, 37, 37, 37, 37, 36, 36, 36, 36, 36, 35, 35, 35, 35, - 35, 34, 34, 34, 34, 34, 33, 33, 33, 33, 33, 33, 32, 32, 32, 32, 32, - 31, 31, 31, 31, 31, 30, 30, 30, 30, 30, 29, 29, 29, 29, 29, 28, 28, - 28, 28, 28, 27, 27, 27, 27, 27, 26, 26, 26, 26, 26, 25, 25, 25, 25, - 25, 25, 24, 24, 24, 24, 24, 23, 23, 23, 23, 23, 22, 22, 22, 22, 22, - 21, 21, 21, 21, 21, 21, 20, 20, 20, 20, 20, 19, 19, 19, 19, 19, 19, - 18, 18, 18, 18, 18, 17, 17, 17, 17, 17, 17, 16, 16, 16, 16, 16, 16, - 15, 15, 15, 15, 15, 15, 14, 14, 14, 14, 14, 14, 13, 13, 13, 13, 13, - 13, 12, 12, 12, 12, 12, 12, 11, 11, 11, 11, 11, 11, 11, 10, 10, 10, - 10, 10, 10, 10, 9, 9, 9, 9, 9, 9, 9, 8, 8, 8, 8, 8, 8, - 8, 7, 7, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, - 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, - 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, - 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, - 13, 13, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 16, 16, 16, - 16, 16, 16, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 19, 19, 19, - 19, 19, 19, 20, 20, 20, 20, 20, 21, 21, 21, 21, 21, 21, 22, 22, 22, - 22, 22, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 25, 25, 25, 25, 25, - 25, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 28, 28, 28, 28, 28, 29, - 29, 29, 29, 29, 30, 30, 30, 30, 30, 31, 31, 31, 31, 31, 32, 32, 32, - 32, 32, 33, 33, 33, 33, 33, 33, 34, 34, 34, 34, 34, 35, 35, 35, 35, - 35, 36, 36, 36, 36, 36, 37, 37, 37, 37, 37, 38, 38, 38, 38, 38, 39, - 39, 39, 39, 39, 39, 40, 40, 40, 40, 40, 41, 41, 41, 41, 41, 42, 42, - 42, 42, 42, 42, 43, 43, 43, 43, 43, 44, 44, 44, 44, 44, 44, 45, 45, - 45, 45, 45, 45, 46, 46, 46, 46, 46, 46, 47, 47, 47, 47, 47, 47, 48, - 48, 48, 48, 48, 48, 49, 49, 49, 49, 49, 49, 50], dtype=uint16), -'ASAM.M.SCALAR.UBYTE.VTAB_RANGE_DEFAULT_VALUE': array([ 13, 16, 19, 22, 25, 28, 31, 35, 38, 41, 44, 47, 50, - 53, 56, 60, 63, 66, 69, 72, 75, 78, 81, 84, 87, 90, - 94, 97, 100, 103, 106, 109, 112, 115, 118, 121, 124, 127, 130, - 133, 136, 139, 142, 145, 148, 151, 154, 157, 160, 163, 166, 169, - 172, 174, 177, 180, 183, 186, 189, 192, 195, 198, 200, 203, 206, - 209, 212, 214, 217, 220, 223, 226, 228, 231, 234, 237, 239, 242, - 245, 247, 250, 253, 255, 2, 5, 7, 10, 13, 15, 18, 20, - 23, 25, 28, 30, 33, 35, 38, 40, 43, 45, 48, 50, 53, - 55, 57, 60, 62, 65, 67, 69, 71, 74, 76, 78, 81, 83, - 85, 87, 89, 92, 94, 96, 98, 100, 102, 104, 107, 109, 111, - 113, 115, 117, 119, 121, 123, 125, 127, 128, 130, 132, 134, 136, - 138, 140, 141, 143, 145, 147, 149, 150, 152, 154, 155, 157, 159, - 160, 162, 163, 165, 167, 168, 170, 171, 173, 174, 176, 177, 178, - 180, 181, 183, 184, 185, 187, 188, 189, 190, 192, 193, 194, 195, - 196, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, - 210, 211, 212, 213, 213, 214, 215, 216, 217, 217, 218, 219, 219, - 220, 221, 221, 222, 223, 223, 224, 224, 225, 225, 226, 226, 227, - 227, 228, 228, 228, 229, 229, 229, 230, 230, 230, 230, 231, 231, - 231, 231, 231, 231, 231, 231, 231, 231, 232, 231, 231, 231, 231, - 231, 231, 231, 231, 231, 231, 230, 230, 230, 230, 229, 229, 229, - 228, 228, 228, 227, 227, 226, 226, 225, 225, 224, 224, 223, 223, - 222, 221, 221, 220, 219, 219, 218, 217, 217, 216, 215, 214, 213, - 213, 212, 211, 210, 209, 208, 207, 206, 205, 204, 203, 202, 201, - 200, 199, 198, 196, 195, 194, 193, 192, 190, 189, 188, 187, 185, - 184, 183, 181, 180, 178, 177, 176, 174, 173, 171, 170, 168, 167, - 165, 163, 162, 160, 159, 157, 155, 154, 152, 150, 149, 147, 145, - 143, 141, 140, 138, 136, 134, 132, 130, 128, 127, 125, 123, 121, - 119, 117, 115, 113, 111, 109, 107, 104, 102, 100, 98, 96, 94, - 92, 89, 87, 85, 83, 81, 78, 76, 74, 71, 69, 67, 65, - 62, 60, 57, 55, 53, 50, 48, 45, 43, 40, 38, 35, 33, - 30, 28, 25, 23, 20, 18, 15, 13, 10, 7, 5, 2, 255, - 253, 250, 247, 245, 242, 239, 237, 234, 231, 228, 226, 223, 220, - 217, 214, 212, 209, 206, 203, 200, 198, 195, 192, 189, 186, 183, - 180, 177, 174, 172, 169, 166, 163, 160, 157, 154, 151, 148, 145, - 142, 139, 136, 133, 130, 127, 124, 121, 118, 115, 112, 109, 106, - 103, 100, 97, 94, 90, 87, 84, 81, 78, 75, 72, 69, 66, - 63, 60, 56, 53, 50, 47, 44, 41, 38, 35, 31, 28, 25, - 22, 19, 16, 13, 9, 6, 3, 0, 253, 250, 247, 243, 240, - 237, 234, 231, 228, 225, 222, 218, 215, 212, 209, 206, 203, 200, - 196, 193, 190, 187, 184, 181, 178, 175, 171, 168, 165, 162, 159, - 156, 153, 150, 147, 144, 141, 137, 134, 131, 128, 125, 122, 119, - 116, 113, 110, 107, 104, 101, 98, 95, 92, 89, 86, 83, 80, - 77, 74, 71, 68, 65, 62, 59, 57, 54, 51, 48, 45, 42, - 39, 36, 33, 31, 28, 25, 22, 19, 17, 14, 11, 8, 5, - 3, 0, 253, 250, 248, 245, 242, 240, 237, 234, 232, 229, 226, - 224, 221, 218, 216, 213, 211, 208, 206, 203, 201, 198, 196, 193, - 191, 188, 186, 183, 181, 178, 176, 174, 171, 169, 166, 164, 162, - 160, 157, 155, 153, 150, 148, 146, 144, 142, 139, 137, 135, 133, - 131, 129, 127, 124, 122, 120, 118, 116, 114, 112, 110, 108, 106, - 104, 103, 101, 99, 97, 95, 93, 91, 90, 88, 86, 84, 82, - 81, 79, 77, 76, 74, 72, 71, 69, 68, 66, 64, 63, 61, - 60, 58, 57, 55, 54, 53, 51, 50, 48, 47, 46, 44, 43, - 42, 41, 39, 38, 37, 36, 35, 33, 32, 31, 30, 29, 28, - 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 18, 17, 16, - 15, 14, 14, 13, 12, 12, 11, 10, 10, 9, 8, 8, 7, - 7, 6, 6, 5, 5, 4, 4, 3, 3, 3, 2, 2, 2, - 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, - 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 5, 5, - 6, 6, 7, 7, 8, 8, 9, 10, 10, 11, 12, 12, 13, - 14, 14, 15, 16, 17, 18, 18, 19, 20, 21, 22, 23, 24, - 25, 26, 27, 28, 29, 30, 31, 32, 33, 35, 36, 37, 38, - 39, 41, 42, 43, 44, 46, 47, 48, 50, 51, 53, 54, 55, - 57, 58, 60, 61, 63, 64, 66, 68, 69, 71, 72, 74, 76, - 77, 79, 81, 82, 84, 86, 88, 90, 91, 93, 95, 97, 99, - 101, 103, 104, 106, 108, 110, 112, 114, 116, 118, 120, 122, 124, - 127, 129, 131, 133, 135, 137, 139, 142, 144, 146, 148, 150, 153, - 155, 157, 160, 162, 164, 166, 169, 171, 174, 176, 178, 181, 183, - 186, 188, 191, 193, 196, 198, 201, 203, 206, 208, 211, 213], dtype=uint8), -'ASAM.M.SCALAR.FLOAT32.IDENTICAL': array([ 8.13845703e+02, 8.16285095e+02, 8.18711975e+02, - 8.21126343e+02, 8.23527954e+02, 8.25916870e+02, - 8.28292908e+02, 8.30655945e+02, 8.33005920e+02, - 8.35342773e+02, 8.37666382e+02, 8.39976685e+02, - 8.42273560e+02, 8.44556885e+02, 8.46826660e+02, - 8.49082703e+02, 8.51325012e+02, 8.53553406e+02, - 8.55767822e+02, 8.57968262e+02, 8.60154541e+02, - 8.62326538e+02, 8.64484314e+02, 8.66627686e+02, - 8.68756531e+02, 8.70870911e+02, 8.72970581e+02, - 8.75055542e+02, 8.77125671e+02, 8.79180969e+02, - 8.81221252e+02, 8.83246521e+02, 8.85256592e+02, - 8.87251526e+02, 8.89231140e+02, 8.91195435e+02, - 8.93144226e+02, 8.95077515e+02, 8.96995178e+02, - 8.98897217e+02, 9.00783508e+02, 9.02653931e+02, - 9.04508484e+02, 9.06347107e+02, 9.08169617e+02, - 9.09976074e+02, 9.11766296e+02, 9.13540283e+02, - 9.15297974e+02, 9.17039246e+02, 9.18764038e+02, - 9.20472290e+02, 9.22163940e+02, 9.23838989e+02, - 9.25497253e+02, 9.27138733e+02, 9.28763306e+02, - 9.30371033e+02, 9.31961731e+02, 9.33535339e+02, - 9.35091858e+02, 9.36631226e+02, 9.38153320e+02, - 9.39658142e+02, 9.41145630e+02, 9.42615662e+02, - 9.44068237e+02, 9.45503235e+02, 9.46920715e+02, - 9.48320496e+02, 9.49702637e+02, 9.51066956e+02, - 9.52413513e+02, 9.53742188e+02, 9.55052979e+02, - 9.56345764e+02, 9.57620605e+02, 9.58877319e+02, - 9.60115906e+02, 9.61336365e+02, 9.62538574e+02, - 9.63722595e+02, 9.64888245e+02, 9.66035583e+02, - 9.67164490e+02, 9.68274963e+02, 9.69366943e+02, - 9.70440369e+02, 9.71495239e+02, 9.72531555e+02, - 9.73549133e+02, 9.74548096e+02, 9.75528259e+02, - 9.76489685e+02, 9.77432251e+02, 9.78356018e+02, - 9.79260864e+02, 9.80146851e+02, 9.81013855e+02, - 9.81861816e+02, 9.82690796e+02, 9.83500732e+02, - 9.84291565e+02, 9.85063293e+02, 9.85815857e+02, - 9.86549255e+02, 9.87263428e+02, 9.87958374e+02, - 9.88634033e+02, 9.89290466e+02, 9.89927551e+02, - 9.90545288e+02, 9.91143616e+02, 9.91722595e+02, - 9.92282166e+02, 9.92822327e+02, 9.93342957e+02, - 9.93844177e+02, 9.94325867e+02, 9.94788086e+02, - 9.95230713e+02, 9.95653809e+02, 9.96057373e+02, - 9.96441284e+02, 9.96805664e+02, 9.97150391e+02, - 9.97475525e+02, 9.97781006e+02, 9.98066833e+02, - 9.98332947e+02, 9.98579468e+02, 9.98806274e+02, - 9.99013367e+02, 9.99200745e+02, 9.99368469e+02, - 9.99516479e+02, 9.99644714e+02, 9.99753296e+02, - 9.99842102e+02, 9.99911194e+02, 9.99960510e+02, - 9.99990112e+02, 1.00000000e+03, 9.99990112e+02, - 9.99960510e+02, 9.99911194e+02, 9.99842102e+02, - 9.99753296e+02, 9.99644714e+02, 9.99516479e+02, - 9.99368469e+02, 9.99200745e+02, 9.99013367e+02, - 9.98806274e+02, 9.98579468e+02, 9.98332947e+02, - 9.98066833e+02, 9.97781006e+02, 9.97475525e+02, - 9.97150391e+02, 9.96805664e+02, 9.96441284e+02, - 9.96057373e+02, 9.95653809e+02, 9.95230713e+02, - 9.94788086e+02, 9.94325867e+02, 9.93844177e+02, - 9.93342957e+02, 9.92822327e+02, 9.92282166e+02, - 9.91722595e+02, 9.91143616e+02, 9.90545288e+02, - 9.89927551e+02, 9.89290466e+02, 9.88634033e+02, - 9.87958374e+02, 9.87263428e+02, 9.86549255e+02, - 9.85815857e+02, 9.85063293e+02, 9.84291565e+02, - 9.83500732e+02, 9.82690796e+02, 9.81861816e+02, - 9.81013855e+02, 9.80146851e+02, 9.79260864e+02, - 9.78356018e+02, 9.77432251e+02, 9.76489685e+02, - 9.75528259e+02, 9.74548096e+02, 9.73549133e+02, - 9.72531555e+02, 9.71495239e+02, 9.70440369e+02, - 9.69366943e+02, 9.68274963e+02, 9.67164490e+02, - 9.66035583e+02, 9.64888245e+02, 9.63722595e+02, - 9.62538574e+02, 9.61336365e+02, 9.60115906e+02, - 9.58877319e+02, 9.57620605e+02, 9.56345764e+02, - 9.55052979e+02, 9.53742188e+02, 9.52413513e+02, - 9.51066956e+02, 9.49702637e+02, 9.48320496e+02, - 9.46920715e+02, 9.45503235e+02, 9.44068237e+02, - 9.42615662e+02, 9.41145630e+02, 9.39658142e+02, - 9.38153320e+02, 9.36631226e+02, 9.35091858e+02, - 9.33535339e+02, 9.31961731e+02, 9.30371033e+02, - 9.28763306e+02, 9.27138733e+02, 9.25497253e+02, - 9.23838989e+02, 9.22163940e+02, 9.20472290e+02, - 9.18764038e+02, 9.17039246e+02, 9.15297974e+02, - 9.13540283e+02, 9.11766296e+02, 9.09976074e+02, - 9.08169617e+02, 9.06347107e+02, 9.04508484e+02, - 9.02653931e+02, 9.00783508e+02, 8.98897217e+02, - 8.96995178e+02, 8.95077515e+02, 8.93144226e+02, - 8.91195435e+02, 8.89231140e+02, 8.87251526e+02, - 8.85256592e+02, 8.83246521e+02, 8.81221252e+02, - 8.79180969e+02, 8.77125671e+02, 8.75055542e+02, - 8.72970581e+02, 8.70870911e+02, 8.68756531e+02, - 8.66627686e+02, 8.64484314e+02, 8.62326538e+02, - 8.60154541e+02, 8.57968262e+02, 8.55767822e+02, - 8.53553406e+02, 8.51325012e+02, 8.49082703e+02, - 8.46826660e+02, 8.44556885e+02, 8.42273560e+02, - 8.39976685e+02, 8.37666382e+02, 8.35342773e+02, - 8.33005920e+02, 8.30655945e+02, 8.28292908e+02, - 8.25916870e+02, 8.23527954e+02, 8.21126343e+02, - 8.18711975e+02, 8.16285095e+02, 8.13845703e+02, - 8.11393860e+02, 8.08929810e+02, 8.06453552e+02, - 8.03965149e+02, 8.01464783e+02, 7.98952515e+02, - 7.96428406e+02, 7.93892639e+02, 7.91345215e+02, - 7.88786377e+02, 7.86216064e+02, 7.83634460e+02, - 7.81041687e+02, 7.78437805e+02, 7.75822937e+02, - 7.73197144e+02, 7.70560608e+02, 7.67913391e+02, - 7.65255615e+02, 7.62587341e+02, 7.59908691e+02, - 7.57219788e+02, 7.54520691e+02, 7.51811584e+02, - 7.49092529e+02, 7.46363647e+02, 7.43625061e+02, - 7.40876831e+02, 7.38119080e+02, 7.35351990e+02, - 7.32575562e+02, 7.29789917e+02, 7.26995239e+02, - 7.24191589e+02, 7.21379089e+02, 7.18557861e+02, - 7.15728027e+02, 7.12889648e+02, 7.10042847e+02, - 7.07187805e+02, 7.04324524e+02, 7.01453247e+02, - 6.98573975e+02, 6.95686829e+02, 6.92791992e+02, - 6.89889526e+02, 6.86979614e+02, 6.84062256e+02, - 6.81137695e+02, 6.78205933e+02, 6.75267151e+02, - 6.72321472e+02, 6.69368958e+02, 6.66409790e+02, - 6.63444031e+02, 6.60471802e+02, 6.57493286e+02, - 6.54508484e+02, 6.51517639e+02, 6.48520813e+02, - 6.45518066e+02, 6.42509644e+02, 6.39495544e+02, - 6.36475952e+02, 6.33450989e+02, 6.30420776e+02, - 6.27385376e+02, 6.24344971e+02, 6.21299622e+02, - 6.18249512e+02, 6.15194702e+02, 6.12135376e+02, - 6.09071594e+02, 6.06003540e+02, 6.02931274e+02, - 5.99854980e+02, 5.96774719e+02, 5.93690674e+02, - 5.90602905e+02, 5.87511536e+02, 5.84416748e+02, - 5.81318604e+02, 5.78217224e+02, 5.75112793e+02, - 5.72005371e+02, 5.68895142e+02, 5.65782166e+02, - 5.62666626e+02, 5.59548584e+02, 5.56428223e+02, - 5.53305603e+02, 5.50180847e+02, 5.47054138e+02, - 5.43925598e+02, 5.40795288e+02, 5.37663391e+02, - 5.34530029e+02, 5.31395264e+02, 5.28259277e+02, - 5.25122131e+02, 5.21984070e+02, 5.18845093e+02, - 5.15705383e+02, 5.12565063e+02, 5.09424225e+02, - 5.06283020e+02, 5.03141571e+02, 5.00000000e+02, - 4.96858429e+02, 4.93716980e+02, 4.90575775e+02, - 4.87434967e+02, 4.84294617e+02, 4.81154907e+02, - 4.78015930e+02, 4.74877838e+02, 4.71740723e+02, - 4.68604736e+02, 4.65470001e+02, 4.62336609e+02, - 4.59204681e+02, 4.56074402e+02, 4.52945831e+02, - 4.49819153e+02, 4.46694427e+02, 4.43571808e+02, - 4.40451416e+02, 4.37333374e+02, 4.34217834e+02, - 4.31104858e+02, 4.27994598e+02, 4.24887207e+02, - 4.21782776e+02, 4.18681427e+02, 4.15583282e+02, - 4.12488464e+02, 4.09397125e+02, 4.06309357e+02, - 4.03225281e+02, 4.00145020e+02, 3.97068695e+02, - 3.93996460e+02, 3.90928375e+02, 3.87864624e+02, - 3.84805298e+02, 3.81750488e+02, 3.78700378e+02, - 3.75655060e+02, 3.72614624e+02, 3.69579254e+02, - 3.66549011e+02, 3.63524017e+02, 3.60504456e+02, - 3.57490356e+02, 3.54481903e+02, 3.51479218e+02, - 3.48482361e+02, 3.45491516e+02, 3.42506744e+02, - 3.39528198e+02, 3.36556000e+02, 3.33590240e+02, - 3.30631042e+02, 3.27678528e+02, 3.24732849e+02, - 3.21794067e+02, 3.18862305e+02, 3.15937714e+02, - 3.13020386e+02, 3.10110443e+02, 3.07208008e+02, - 3.04313171e+02, 3.01426056e+02, 2.98546783e+02, - 2.95675476e+02, 2.92812195e+02, 2.89957123e+02, - 2.87110352e+02, 2.84271973e+02, 2.81442108e+02, - 2.78620880e+02, 2.75808380e+02, 2.73004761e+02, - 2.70210083e+02, 2.67424469e+02, 2.64648041e+02, - 2.61880890e+02, 2.59123169e+02, 2.56374939e+02, - 2.53636322e+02, 2.50907440e+02, 2.48188400e+02, - 2.45479294e+02, 2.42780228e+02, 2.40091324e+02, - 2.37412689e+02, 2.34744415e+02, 2.32086609e+02, - 2.29439377e+02, 2.26802826e+02, 2.24177063e+02, - 2.21562195e+02, 2.18958313e+02, 2.16365524e+02, - 2.13783936e+02, 2.11213654e+02, 2.08654755e+02, - 2.06107376e+02, 2.03571594e+02, 2.01047516e+02, - 1.98535233e+02, 1.96034851e+02, 1.93546478e+02, - 1.91070190e+02, 1.88606110e+02, 1.86154312e+02, - 1.83714920e+02, 1.81288010e+02, 1.78873672e+02, - 1.76472015e+02, 1.74083130e+02, 1.71707123e+02, - 1.69344070e+02, 1.66994064e+02, 1.64657211e+02, - 1.62333603e+02, 1.60023315e+02, 1.57726440e+02, - 1.55443100e+02, 1.53173340e+02, 1.50917297e+02, - 1.48675018e+02, 1.46446609e+02, 1.44232162e+02, - 1.42031754e+02, 1.39845490e+02, 1.37673431e+02, - 1.35515686e+02, 1.33372330e+02, 1.31243439e+02, - 1.29129120e+02, 1.27029427e+02, 1.24944466e+02, - 1.22874313e+02, 1.20819046e+02, 1.18778748e+02, - 1.16753494e+02, 1.14743378e+02, 1.12748466e+02, - 1.10768852e+02, 1.08804596e+02, 1.06855782e+02, - 1.04922493e+02, 1.03004799e+02, 1.01102783e+02, - 9.92165070e+01, 9.73460541e+01, 9.54915009e+01, - 9.36529160e+01, 9.18303757e+01, 9.00239487e+01, - 8.82337036e+01, 8.64597092e+01, 8.47020493e+01, - 8.29607849e+01, 8.12359772e+01, 7.95277100e+01, - 7.78360367e+01, 7.61610336e+01, 7.45027618e+01, - 7.28612823e+01, 7.12366714e+01, 6.96289902e+01, - 6.80382919e+01, 6.64646530e+01, 6.49081192e+01, - 6.33687744e+01, 6.18466606e+01, 6.03418465e+01, - 5.88543854e+01, 5.73843460e+01, 5.59317741e+01, - 5.44967384e+01, 5.30792885e+01, 5.16794815e+01, - 5.02973747e+01, 4.89330215e+01, 4.75864754e+01, - 4.62577858e+01, 4.49470139e+01, 4.36542053e+01, - 4.23794136e+01, 4.11226883e+01, 3.98840752e+01, - 3.86636314e+01, 3.74613953e+01, 3.62774239e+01, - 3.51117554e+01, 3.39644432e+01, 3.28355293e+01, - 3.17250557e+01, 3.06330719e+01, 2.95596161e+01, - 2.85047321e+01, 2.74684620e+01, 2.64508476e+01, - 2.54519272e+01, 2.44717426e+01, 2.35103283e+01, - 2.25677280e+01, 2.16439743e+01, 2.07391052e+01, - 1.98531570e+01, 1.89861641e+01, 1.81381607e+01, - 1.73091812e+01, 1.64992561e+01, 1.57084198e+01, - 1.49367018e+01, 1.41841335e+01, 1.34507446e+01, - 1.27365637e+01, 1.20416193e+01, 1.13659382e+01, - 1.07095480e+01, 1.00724735e+01, 9.45474148e+00, - 8.85637474e+00, 8.27739716e+00, 7.71783257e+00, - 7.17770243e+00, 6.65702772e+00, 6.15582991e+00, - 5.67412758e+00, 5.21194077e+00, 4.76928711e+00, - 4.34618425e+00, 3.94264936e+00, 3.55869770e+00, - 3.19434476e+00, 2.84960485e+00, 2.52449155e+00, - 2.21901774e+00, 1.93319547e+00, 1.66703594e+00, - 1.42054987e+00, 1.19374681e+00, 9.86635804e-01, - 7.99224913e-01, 6.31521702e-01, 4.83532667e-01, - 3.55263680e-01, 2.46719822e-01, 1.57905355e-01, - 8.88238102e-02, 3.94778959e-02, 9.86957178e-03, - 0.00000000e+00, 9.86957271e-03, 3.94778997e-02, - 8.88238102e-02, 1.57905355e-01, 2.46719822e-01, - 3.55263680e-01, 4.83532667e-01, 6.31521702e-01, - 7.99224973e-01, 9.86635804e-01, 1.19374681e+00, - 1.42054987e+00, 1.66703594e+00, 1.93319547e+00, - 2.21901774e+00, 2.52449155e+00, 2.84960485e+00, - 3.19434476e+00, 3.55869770e+00, 3.94264936e+00, - 4.34618425e+00, 4.76928711e+00, 5.21194077e+00, - 5.67412758e+00, 6.15582991e+00, 6.65702772e+00, - 7.17770243e+00, 7.71783257e+00, 8.27739716e+00, - 8.85637474e+00, 9.45474148e+00, 1.00724735e+01, - 1.07095480e+01, 1.13659382e+01, 1.20416193e+01, - 1.27365637e+01, 1.34507446e+01, 1.41841335e+01, - 1.49367018e+01, 1.57084198e+01, 1.64992561e+01, - 1.73091812e+01, 1.81381607e+01, 1.89861641e+01, - 1.98531570e+01, 2.07391052e+01, 2.16439743e+01, - 2.25677280e+01, 2.35103302e+01, 2.44717426e+01, - 2.54519272e+01, 2.64508476e+01, 2.74684620e+01, - 2.85047321e+01, 2.95596161e+01, 3.06330719e+01, - 3.17250576e+01, 3.28355293e+01, 3.39644432e+01, - 3.51117554e+01, 3.62774239e+01, 3.74613953e+01, - 3.86636314e+01, 3.98840752e+01, 4.11226883e+01, - 4.23794136e+01, 4.36542053e+01, 4.49470139e+01, - 4.62577896e+01, 4.75864754e+01, 4.89330215e+01, - 5.02973747e+01, 5.16794815e+01, 5.30792885e+01, - 5.44967384e+01, 5.59317741e+01, 5.73843460e+01, - 5.88543854e+01, 6.03418465e+01, 6.18466606e+01, - 6.33687744e+01, 6.49081192e+01, 6.64646530e+01, - 6.80382919e+01, 6.96289902e+01, 7.12366714e+01, - 7.28612823e+01, 7.45027618e+01, 7.61610336e+01, - 7.78360367e+01, 7.95277100e+01, 8.12359772e+01, - 8.29607849e+01, 8.47020493e+01, 8.64597092e+01, - 8.82337036e+01, 9.00239487e+01, 9.18303757e+01, - 9.36529160e+01, 9.54915009e+01, 9.73460541e+01, - 9.92165070e+01, 1.01102783e+02, 1.03004799e+02, - 1.04922493e+02, 1.06855782e+02, 1.08804596e+02, - 1.10768852e+02, 1.12748466e+02, 1.14743378e+02, - 1.16753494e+02, 1.18778748e+02, 1.20819046e+02, - 1.22874313e+02, 1.24944466e+02, 1.27029427e+02, - 1.29129120e+02, 1.31243439e+02, 1.33372330e+02, - 1.35515686e+02, 1.37673431e+02, 1.39845490e+02, - 1.42031754e+02, 1.44232162e+02, 1.46446609e+02, - 1.48675018e+02, 1.50917297e+02, 1.53173340e+02, - 1.55443100e+02, 1.57726440e+02, 1.60023315e+02, - 1.62333603e+02, 1.64657211e+02, 1.66994064e+02, - 1.69344070e+02, 1.71707123e+02, 1.74083130e+02, - 1.76472015e+02, 1.78873672e+02, 1.81288010e+02, - 1.83714920e+02, 1.86154312e+02, 1.88606110e+02, - 1.91070190e+02, 1.93546478e+02, 1.96034851e+02, - 1.98535233e+02, 2.01047516e+02, 2.03571594e+02, - 2.06107376e+02, 2.08654755e+02, 2.11213654e+02, - 2.13783936e+02, 2.16365524e+02, 2.18958313e+02, - 2.21562195e+02, 2.24177063e+02, 2.26802826e+02, - 2.29439377e+02, 2.32086609e+02, 2.34744415e+02, - 2.37412689e+02, 2.40091324e+02, 2.42780228e+02, - 2.45479294e+02, 2.48188400e+02, 2.50907440e+02, - 2.53636322e+02, 2.56374939e+02, 2.59123169e+02, - 2.61880890e+02, 2.64648041e+02, 2.67424469e+02, - 2.70210083e+02, 2.73004761e+02, 2.75808380e+02, - 2.78620880e+02, 2.81442108e+02, 2.84271973e+02, - 2.87110352e+02, 2.89957123e+02, 2.92812195e+02, - 2.95675476e+02, 2.98546783e+02, 3.01426056e+02, - 3.04313171e+02, 3.07208008e+02, 3.10110443e+02, - 3.13020386e+02, 3.15937714e+02, 3.18862305e+02, - 3.21794067e+02, 3.24732849e+02, 3.27678528e+02, - 3.30631042e+02, 3.33590240e+02, 3.36556000e+02, - 3.39528198e+02, 3.42506744e+02, 3.45491516e+02, - 3.48482361e+02, 3.51479218e+02, 3.54481903e+02, - 3.57490356e+02, 3.60504456e+02, 3.63524017e+02, - 3.66549011e+02, 3.69579254e+02, 3.72614624e+02, - 3.75655060e+02, 3.78700378e+02, 3.81750488e+02, - 3.84805298e+02, 3.87864624e+02, 3.90928375e+02, - 3.93996460e+02, 3.97068695e+02, 4.00145020e+02, - 4.03225281e+02, 4.06309357e+02, 4.09397125e+02, - 4.12488464e+02, 4.15583282e+02, 4.18681427e+02, - 4.21782776e+02, 4.24887207e+02, 4.27994598e+02, - 4.31104858e+02, 4.34217834e+02, 4.37333374e+02, - 4.40451416e+02, 4.43571808e+02, 4.46694427e+02, - 4.49819153e+02, 4.52945831e+02, 4.56074402e+02, - 4.59204681e+02, 4.62336609e+02, 4.65470001e+02, - 4.68604736e+02, 4.71740723e+02, 4.74877838e+02, - 4.78015930e+02, 4.81154907e+02, 4.84294617e+02, - 4.87434967e+02, 4.90575775e+02, 4.93716980e+02, - 4.96858429e+02, 5.00000000e+02, 5.03141571e+02, - 5.06283020e+02, 5.09424225e+02], dtype=float32), -'ASAM.M.SCALAR.UWORD.IDENTICAL': array([ 32, 33, 35, 36, 37, 38, 39, 41, 42, 43, 44, - 46, 47, 48, 50, 51, 53, 54, 55, 57, 58, 60, - 61, 63, 64, 66, 68, 69, 71, 72, 74, 76, 77, - 79, 81, 82, 84, 86, 88, 90, 91, 93, 95, 97, - 99, 101, 103, 104, 106, 108, 110, 112, 114, 116, 118, - 120, 122, 124, 127, 129, 131, 133, 135, 137, 139, 142, - 144, 146, 148, 150, 153, 155, 157, 160, 162, 164, 166, - 169, 171, 174, 176, 178, 181, 183, 186, 188, 191, 193, - 196, 198, 201, 203, 206, 208, 211, 213, 216, 218, 221, - 224, 226, 229, 232, 234, 237, 240, 242, 245, 248, 250, - 253, 256, 259, 261, 264, 267, 270, 273, 275, 278, 281, - 284, 287, 289, 292, 295, 298, 301, 304, 307, 310, 313, - 315, 318, 321, 324, 327, 330, 333, 336, 339, 342, 345, - 348, 351, 354, 357, 360, 363, 366, 369, 372, 375, 378, - 381, 384, 387, 390, 393, 397, 400, 403, 406, 409, 412, - 415, 418, 421, 424, 427, 431, 434, 437, 440, 443, 446, - 449, 452, 456, 459, 462, 465, 468, 471, 474, 478, 481, - 484, 487, 490, 493, 496, 500, 503, 506, 509, 512, 515, - 518, 521, 525, 528, 531, 534, 537, 540, 543, 547, 550, - 553, 556, 559, 562, 565, 568, 572, 575, 578, 581, 584, - 587, 590, 593, 596, 599, 602, 606, 609, 612, 615, 618, - 621, 624, 627, 630, 633, 636, 639, 642, 645, 648, 651, - 654, 657, 660, 663, 666, 669, 672, 675, 678, 681, 684, - 686, 689, 692, 695, 698, 701, 704, 707, 710, 712, 715, - 718, 721, 724, 726, 729, 732, 735, 738, 740, 743, 746, - 749, 751, 754, 757, 759, 762, 765, 767, 770, 773, 775, - 778, 781, 783, 786, 788, 791, 793, 796, 798, 801, 803, - 806, 808, 811, 813, 816, 818, 821, 823, 825, 828, 830, - 833, 835, 837, 839, 842, 844, 846, 849, 851, 853, 855, - 857, 860, 862, 864, 866, 868, 870, 872, 875, 877, 879, - 881, 883, 885, 887, 889, 891, 893, 895, 896, 898, 900, - 902, 904, 906, 908, 909, 911, 913, 915, 917, 918, 920, - 922, 923, 925, 927, 928, 930, 931, 933, 935, 936, 938, - 939, 941, 942, 944, 945, 946, 948, 949, 951, 952, 953, - 955, 956, 957, 958, 960, 961, 962, 963, 964, 966, 967, - 968, 969, 970, 971, 972, 973, 974, 975, 976, 977, 978, - 979, 980, 981, 981, 982, 983, 984, 985, 985, 986, 987, - 987, 988, 989, 989, 990, 991, 991, 992, 992, 993, 993, - 994, 994, 995, 995, 996, 996, 996, 997, 997, 997, 998, - 998, 998, 998, 999, 999, 999, 999, 999, 999, 999, 999, - 999, 999, 1000, 999, 999, 999, 999, 999, 999, 999, 999, - 999, 999, 998, 998, 998, 998, 997, 997, 997, 996, 996, - 996, 995, 995, 994, 994, 993, 993, 992, 992, 991, 991, - 990, 989, 989, 988, 987, 987, 986, 985, 985, 984, 983, - 982, 981, 981, 980, 979, 978, 977, 976, 975, 974, 973, - 972, 971, 970, 969, 968, 967, 966, 964, 963, 962, 961, - 960, 958, 957, 956, 955, 953, 952, 951, 949, 948, 946, - 945, 944, 942, 941, 939, 938, 936, 935, 933, 931, 930, - 928, 927, 925, 923, 922, 920, 918, 917, 915, 913, 911, - 909, 908, 906, 904, 902, 900, 898, 896, 895, 893, 891, - 889, 887, 885, 883, 881, 879, 877, 875, 872, 870, 868, - 866, 864, 862, 860, 857, 855, 853, 851, 849, 846, 844, - 842, 839, 837, 835, 833, 830, 828, 825, 823, 821, 818, - 816, 813, 811, 808, 806, 803, 801, 798, 796, 793, 791, - 788, 786, 783, 781, 778, 775, 773, 770, 767, 765, 762, - 759, 757, 754, 751, 749, 746, 743, 740, 738, 735, 732, - 729, 726, 724, 721, 718, 715, 712, 710, 707, 704, 701, - 698, 695, 692, 689, 686, 684, 681, 678, 675, 672, 669, - 666, 663, 660, 657, 654, 651, 648, 645, 642, 639, 636, - 633, 630, 627, 624, 621, 618, 615, 612, 609, 606, 602, - 599, 596, 593, 590, 587, 584, 581, 578, 575, 572, 568, - 565, 562, 559, 556, 553, 550, 547, 543, 540, 537, 534, - 531, 528, 525, 521, 518, 515, 512, 509, 506, 503, 499, - 496, 493, 490, 487, 484, 481, 478, 474, 471, 468, 465, - 462, 459, 456, 452, 449, 446, 443, 440, 437, 434, 431, - 427, 424, 421, 418, 415, 412, 409, 406, 403, 400, 397, - 393, 390, 387, 384, 381, 378, 375, 372, 369, 366, 363, - 360, 357, 354, 351, 348, 345, 342, 339, 336, 333, 330, - 327, 324, 321, 318, 315, 313, 310, 307, 304, 301, 298, - 295, 292, 289, 287, 284, 281, 278, 275, 273, 270, 267, - 264, 261, 259, 256, 253, 250, 248, 245, 242, 240, 237, - 234, 232, 229, 226, 224, 221, 218, 216, 213, 211, 208, - 206, 203, 201, 198, 196, 193, 191, 188, 186, 183, 181, - 178, 176, 174, 171, 169, 166, 164, 162, 160, 157, 155, - 153, 150, 148, 146, 144, 142, 139, 137, 135, 133, 131, - 129, 127, 124, 122, 120, 118, 116, 114, 112, 110, 108, - 106, 104, 103, 101, 99, 97, 95, 93, 91, 90, 88, - 86, 84, 82, 81, 79, 77, 76, 74, 72, 71, 69, - 68, 66, 64, 63, 61, 60, 58, 57, 55, 54, 53, - 51, 50, 48, 47, 46, 44, 43, 42, 41, 39, 38, - 37, 36, 35, 33, 32, 31, 30, 29, 28, 27, 26, - 25, 24, 23, 22, 21], dtype=uint16), -'ASAM.M.SCALAR.UBYTE.TAB_VERB_NO_DEFAULT_VALUE': array([ 17, 16, 15, 14, 14, 13, 12, 12, 11, 10, 10, 9, 8, - 8, 7, 7, 6, 6, 5, 5, 4, 4, 3, 3, 3, 2, - 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 1, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, - 5, 5, 6, 6, 7, 7, 8, 8, 9, 10, 10, 11, 12, - 12, 13, 14, 14, 15, 16, 17, 18, 18, 19, 20, 21, 22, - 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 35, 36, - 37, 38, 39, 41, 42, 43, 44, 46, 47, 48, 50, 51, 53, - 54, 55, 57, 58, 60, 61, 63, 64, 66, 68, 69, 71, 72, - 74, 76, 77, 79, 81, 82, 84, 86, 88, 90, 91, 93, 95, - 97, 99, 101, 103, 104, 106, 108, 110, 112, 114, 116, 118, 120, - 122, 124, 127, 129, 131, 133, 135, 137, 139, 142, 144, 146, 148, - 150, 153, 155, 157, 160, 162, 164, 166, 169, 171, 174, 176, 178, - 181, 183, 186, 188, 191, 193, 196, 198, 201, 203, 206, 208, 211, - 213, 216, 218, 221, 224, 226, 229, 232, 234, 237, 240, 242, 245, - 248, 250, 253, 0, 3, 5, 8, 11, 14, 17, 19, 22, 25, - 28, 31, 33, 36, 39, 42, 45, 48, 51, 54, 57, 59, 62, - 65, 68, 71, 74, 77, 80, 83, 86, 89, 92, 95, 98, 101, - 104, 107, 110, 113, 116, 119, 122, 125, 128, 131, 134, 137, 141, - 144, 147, 150, 153, 156, 159, 162, 165, 168, 171, 175, 178, 181, - 184, 187, 190, 193, 196, 200, 203, 206, 209, 212, 215, 218, 222, - 225, 228, 231, 234, 237, 240, 244, 247, 250, 253, 0, 3, 6, - 9, 13, 16, 19, 22, 25, 28, 31, 35, 38, 41, 44, 47, - 50, 53, 56, 60, 63, 66, 69, 72, 75, 78, 81, 84, 87, - 90, 94, 97, 100, 103, 106, 109, 112, 115, 118, 121, 124, 127, - 130, 133, 136, 139, 142, 145, 148, 151, 154, 157, 160, 163, 166, - 169, 172, 174, 177, 180, 183, 186, 189, 192, 195, 198, 200, 203, - 206, 209, 212, 214, 217, 220, 223, 226, 228, 231, 234, 237, 239, - 242, 245, 247, 250, 253, 255, 2, 5, 7, 10, 13, 15, 18, - 20, 23, 25, 28, 30, 33, 35, 38, 40, 43, 45, 48, 50, - 53, 55, 57, 60, 62, 65, 67, 69, 71, 74, 76, 78, 81, - 83, 85, 87, 89, 92, 94, 96, 98, 100, 102, 104, 107, 109, - 111, 113, 115, 117, 119, 121, 123, 125, 127, 128, 130, 132, 134, - 136, 138, 140, 141, 143, 145, 147, 149, 150, 152, 154, 155, 157, - 159, 160, 162, 163, 165, 167, 168, 170, 171, 173, 174, 176, 177, - 178, 180, 181, 183, 184, 185, 187, 188, 189, 190, 192, 193, 194, - 195, 196, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, - 209, 210, 211, 212, 213, 213, 214, 215, 216, 217, 217, 218, 219, - 219, 220, 221, 221, 222, 223, 223, 224, 224, 225, 225, 226, 226, - 227, 227, 228, 228, 228, 229, 229, 229, 230, 230, 230, 230, 231, - 231, 231, 231, 231, 231, 231, 231, 231, 231, 232, 231, 231, 231, - 231, 231, 231, 231, 231, 231, 231, 230, 230, 230, 230, 229, 229, - 229, 228, 228, 228, 227, 227, 226, 226, 225, 225, 224, 224, 223, - 223, 222, 221, 221, 220, 219, 219, 218, 217, 217, 216, 215, 214, - 213, 213, 212, 211, 210, 209, 208, 207, 206, 205, 204, 203, 202, - 201, 200, 199, 198, 196, 195, 194, 193, 192, 190, 189, 188, 187, - 185, 184, 183, 181, 180, 178, 177, 176, 174, 173, 171, 170, 168, - 167, 165, 163, 162, 160, 159, 157, 155, 154, 152, 150, 149, 147, - 145, 143, 141, 140, 138, 136, 134, 132, 130, 128, 127, 125, 123, - 121, 119, 117, 115, 113, 111, 109, 107, 104, 102, 100, 98, 96, - 94, 92, 89, 87, 85, 83, 81, 78, 76, 74, 71, 69, 67, - 65, 62, 60, 57, 55, 53, 50, 48, 45, 43, 40, 38, 35, - 33, 30, 28, 25, 23, 20, 18, 15, 13, 10, 7, 5, 2, - 255, 253, 250, 247, 245, 242, 239, 237, 234, 231, 228, 226, 223, - 220, 217, 214, 212, 209, 206, 203, 200, 198, 195, 192, 189, 186, - 183, 180, 177, 174, 172, 169, 166, 163, 160, 157, 154, 151, 148, - 145, 142, 139, 136, 133, 130, 127, 124, 121, 118, 115, 112, 109, - 106, 103, 100, 97, 94, 90, 87, 84, 81, 78, 75, 72, 69, - 66, 63, 60, 56, 53, 50, 47, 44, 41, 38, 35, 31, 28, - 25, 22, 19, 16, 13, 9, 6, 3, 0, 253, 250, 247, 243, - 240, 237, 234, 231, 228, 225, 222, 218, 215, 212, 209, 206, 203, - 200, 196, 193, 190, 187, 184, 181, 178, 175, 171, 168, 165, 162, - 159, 156, 153, 150, 147, 144, 141, 137, 134, 131, 128, 125, 122, - 119, 116, 113, 110, 107, 104, 101, 98, 95, 92, 89, 86, 83, - 80, 77, 74, 71, 68, 65, 62, 59, 57, 54, 51, 48, 45, - 42, 39, 36, 33, 31, 28, 25, 22, 19, 17, 14, 11, 8, - 5, 3, 0, 253, 250, 248, 245, 242, 240, 237, 234, 232, 229, - 226, 224, 221, 218, 216, 213, 211, 208, 206, 203, 201, 198], dtype=uint8), -'ASAM.M.SCALAR.UBYTE.TAB_NOINTP_NO_DEFAULT_VALUE': array([ 105. , 102. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 109. , 106. , 103. , - 100. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 110.33333588, 108. , 105. , - 103. , 100. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 110.66666412, 110.66666412, - 110.33333588, 110. , 110. , 109. , - 108. , 108. , 107. , 107. , - 106. , 106. , 105. , 105. , - 104. , 104. , 103. , 103. , - 103. , 102. , 102. , 102. , - 101. , 101. , 101. , 101. , - 100. , 100. , 100. , 100. , - 100. , 100. , 100. , 100. , - 100. , 100. , 100. , 100. , - 100. , 100. , 100. , 100. , - 100. , 100. , 100. , 100. , - 100. , 101. , 101. , 101. , - 101. , 102. , 102. , 102. , - 103. , 103. , 103. , 104. , - 104. , 105. , 105. , 106. , - 106. , 107. , 107. , 108. , - 108. , 109. , 110. , 110. , - 110.33333588, 110.66666412, 110.66666412, 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 100. , - 103. , 105. , 108. , 110.33333588, - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 100. , 103. , 106. , 109. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 102. , - 105. , 107. , 110. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. , - 111. , 111. , 111. , 111. ], dtype=float32), -'ASAM.M.SCALAR.UBYTE.TAB_VERB_DEFAULT_VALUE': array([218, 215, 212, 209, 206, 203, 200, 196, 193, 190, 187, 184, 181, - 178, 175, 171, 168, 165, 162, 159, 156, 153, 150, 147, 144, 141, - 137, 134, 131, 128, 125, 122, 119, 116, 113, 110, 107, 104, 101, - 98, 95, 92, 89, 86, 83, 80, 77, 74, 71, 68, 65, 62, - 59, 57, 54, 51, 48, 45, 42, 39, 36, 33, 31, 28, 25, - 22, 19, 17, 14, 11, 8, 5, 3, 0, 253, 250, 248, 245, - 242, 240, 237, 234, 232, 229, 226, 224, 221, 218, 216, 213, 211, - 208, 206, 203, 201, 198, 196, 193, 191, 188, 186, 183, 181, 178, - 176, 174, 171, 169, 166, 164, 162, 160, 157, 155, 153, 150, 148, - 146, 144, 142, 139, 137, 135, 133, 131, 129, 127, 124, 122, 120, - 118, 116, 114, 112, 110, 108, 106, 104, 103, 101, 99, 97, 95, - 93, 91, 90, 88, 86, 84, 82, 81, 79, 77, 76, 74, 72, - 71, 69, 68, 66, 64, 63, 61, 60, 58, 57, 55, 54, 53, - 51, 50, 48, 47, 46, 44, 43, 42, 41, 39, 38, 37, 36, - 35, 33, 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, - 21, 20, 19, 18, 18, 17, 16, 15, 14, 14, 13, 12, 12, - 11, 10, 10, 9, 8, 8, 7, 7, 6, 6, 5, 5, 4, - 4, 3, 3, 3, 2, 2, 2, 1, 1, 1, 1, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, - 3, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, - 9, 10, 10, 11, 12, 12, 13, 14, 14, 15, 16, 17, 18, - 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, - 31, 32, 33, 35, 36, 37, 38, 39, 41, 42, 43, 44, 46, - 47, 48, 50, 51, 53, 54, 55, 57, 58, 60, 61, 63, 64, - 66, 68, 69, 71, 72, 74, 76, 77, 79, 81, 82, 84, 86, - 88, 90, 91, 93, 95, 97, 99, 101, 103, 104, 106, 108, 110, - 112, 114, 116, 118, 120, 122, 124, 127, 129, 131, 133, 135, 137, - 139, 142, 144, 146, 148, 150, 153, 155, 157, 160, 162, 164, 166, - 169, 171, 174, 176, 178, 181, 183, 186, 188, 191, 193, 196, 198, - 201, 203, 206, 208, 211, 213, 216, 218, 221, 224, 226, 229, 232, - 234, 237, 240, 242, 245, 248, 250, 253, 0, 3, 5, 8, 11, - 14, 17, 19, 22, 25, 28, 31, 33, 36, 39, 42, 45, 48, - 51, 54, 57, 59, 62, 65, 68, 71, 74, 77, 80, 83, 86, - 89, 92, 95, 98, 101, 104, 107, 110, 113, 116, 119, 122, 125, - 128, 131, 134, 137, 141, 144, 147, 150, 153, 156, 159, 162, 165, - 168, 171, 175, 178, 181, 184, 187, 190, 193, 196, 200, 203, 206, - 209, 212, 215, 218, 222, 225, 228, 231, 234, 237, 240, 244, 247, - 250, 253, 0, 3, 6, 9, 13, 16, 19, 22, 25, 28, 31, - 35, 38, 41, 44, 47, 50, 53, 56, 60, 63, 66, 69, 72, - 75, 78, 81, 84, 87, 90, 94, 97, 100, 103, 106, 109, 112, - 115, 118, 121, 124, 127, 130, 133, 136, 139, 142, 145, 148, 151, - 154, 157, 160, 163, 166, 169, 172, 174, 177, 180, 183, 186, 189, - 192, 195, 198, 200, 203, 206, 209, 212, 214, 217, 220, 223, 226, - 228, 231, 234, 237, 239, 242, 245, 247, 250, 253, 255, 2, 5, - 7, 10, 13, 15, 18, 20, 23, 25, 28, 30, 33, 35, 38, - 40, 43, 45, 48, 50, 53, 55, 57, 60, 62, 65, 67, 69, - 71, 74, 76, 78, 81, 83, 85, 87, 89, 92, 94, 96, 98, - 100, 102, 104, 107, 109, 111, 113, 115, 117, 119, 121, 123, 125, - 127, 128, 130, 132, 134, 136, 138, 140, 141, 143, 145, 147, 149, - 150, 152, 154, 155, 157, 159, 160, 162, 163, 165, 167, 168, 170, - 171, 173, 174, 176, 177, 178, 180, 181, 183, 184, 185, 187, 188, - 189, 190, 192, 193, 194, 195, 196, 198, 199, 200, 201, 202, 203, - 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 213, 214, 215, - 216, 217, 217, 218, 219, 219, 220, 221, 221, 222, 223, 223, 224, - 224, 225, 225, 226, 226, 227, 227, 228, 228, 228, 229, 229, 229, - 230, 230, 230, 230, 231, 231, 231, 231, 231, 231, 231, 231, 231, - 231, 232, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 230, - 230, 230, 230, 229, 229, 229, 228, 228, 228, 227, 227, 226, 226, - 225, 225, 224, 224, 223, 223, 222, 221, 221, 220, 219, 219, 218, - 217, 217, 216, 215, 214, 213, 213, 212, 211, 210, 209, 208, 207, - 206, 205, 204, 203, 202, 201, 200, 199, 198, 196, 195, 194, 193, - 192, 190, 189, 188, 187, 185, 184, 183, 181, 180, 178, 177, 176, - 174, 173, 171, 170, 168, 167, 165, 163, 162, 160, 159, 157, 155, - 154, 152, 150, 149, 147, 145, 143, 141, 140, 138, 136, 134, 132, - 130, 128, 127, 125, 123, 121, 119, 117, 115, 113, 111, 109, 107, - 104, 102, 100, 98, 96, 94, 92, 89, 87, 85, 83, 81, 78, - 76, 74, 71, 69, 67, 65, 62, 60, 57, 55, 53, 50, 48, - 45, 43, 40, 38, 35, 33, 30, 28, 25, 23, 20, 18], dtype=uint8), -'ASAM.M.SCALAR.ULONG.IDENTICAL': array([ 186, 183, 181, 178, 176, 174, 171, 169, 166, 164, 162, - 160, 157, 155, 153, 150, 148, 146, 144, 142, 139, 137, - 135, 133, 131, 129, 127, 124, 122, 120, 118, 116, 114, - 112, 110, 108, 106, 104, 103, 101, 99, 97, 95, 93, - 91, 90, 88, 86, 84, 82, 81, 79, 77, 76, 74, - 72, 71, 69, 68, 66, 64, 63, 61, 60, 58, 57, - 55, 54, 53, 51, 50, 48, 47, 46, 44, 43, 42, - 41, 39, 38, 37, 36, 35, 33, 32, 31, 30, 29, - 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, - 18, 17, 16, 15, 14, 14, 13, 12, 12, 11, 10, - 10, 9, 8, 8, 7, 7, 6, 6, 5, 5, 4, - 4, 3, 3, 3, 2, 2, 2, 1, 1, 1, 1, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, - 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, - 5, 5, 6, 6, 7, 7, 8, 8, 9, 10, 10, - 11, 12, 12, 13, 14, 14, 15, 16, 17, 18, 18, - 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, - 30, 31, 32, 33, 35, 36, 37, 38, 39, 41, 42, - 43, 44, 46, 47, 48, 50, 51, 53, 54, 55, 57, - 58, 60, 61, 63, 64, 66, 68, 69, 71, 72, 74, - 76, 77, 79, 81, 82, 84, 86, 88, 90, 91, 93, - 95, 97, 99, 101, 103, 104, 106, 108, 110, 112, 114, - 116, 118, 120, 122, 124, 127, 129, 131, 133, 135, 137, - 139, 142, 144, 146, 148, 150, 153, 155, 157, 160, 162, - 164, 166, 169, 171, 174, 176, 178, 181, 183, 186, 188, - 191, 193, 196, 198, 201, 203, 206, 208, 211, 213, 216, - 218, 221, 224, 226, 229, 232, 234, 237, 240, 242, 245, - 248, 250, 253, 256, 259, 261, 264, 267, 270, 273, 275, - 278, 281, 284, 287, 289, 292, 295, 298, 301, 304, 307, - 310, 313, 315, 318, 321, 324, 327, 330, 333, 336, 339, - 342, 345, 348, 351, 354, 357, 360, 363, 366, 369, 372, - 375, 378, 381, 384, 387, 390, 393, 397, 400, 403, 406, - 409, 412, 415, 418, 421, 424, 427, 431, 434, 437, 440, - 443, 446, 449, 452, 456, 459, 462, 465, 468, 471, 474, - 478, 481, 484, 487, 490, 493, 496, 500, 503, 506, 509, - 512, 515, 518, 521, 525, 528, 531, 534, 537, 540, 543, - 547, 550, 553, 556, 559, 562, 565, 568, 572, 575, 578, - 581, 584, 587, 590, 593, 596, 599, 602, 606, 609, 612, - 615, 618, 621, 624, 627, 630, 633, 636, 639, 642, 645, - 648, 651, 654, 657, 660, 663, 666, 669, 672, 675, 678, - 681, 684, 686, 689, 692, 695, 698, 701, 704, 707, 710, - 712, 715, 718, 721, 724, 726, 729, 732, 735, 738, 740, - 743, 746, 749, 751, 754, 757, 759, 762, 765, 767, 770, - 773, 775, 778, 781, 783, 786, 788, 791, 793, 796, 798, - 801, 803, 806, 808, 811, 813, 816, 818, 821, 823, 825, - 828, 830, 833, 835, 837, 839, 842, 844, 846, 849, 851, - 853, 855, 857, 860, 862, 864, 866, 868, 870, 872, 875, - 877, 879, 881, 883, 885, 887, 889, 891, 893, 895, 896, - 898, 900, 902, 904, 906, 908, 909, 911, 913, 915, 917, - 918, 920, 922, 923, 925, 927, 928, 930, 931, 933, 935, - 936, 938, 939, 941, 942, 944, 945, 946, 948, 949, 951, - 952, 953, 955, 956, 957, 958, 960, 961, 962, 963, 964, - 966, 967, 968, 969, 970, 971, 972, 973, 974, 975, 976, - 977, 978, 979, 980, 981, 981, 982, 983, 984, 985, 985, - 986, 987, 987, 988, 989, 989, 990, 991, 991, 992, 992, - 993, 993, 994, 994, 995, 995, 996, 996, 996, 997, 997, - 997, 998, 998, 998, 998, 999, 999, 999, 999, 999, 999, - 999, 999, 999, 999, 1000, 999, 999, 999, 999, 999, 999, - 999, 999, 999, 999, 998, 998, 998, 998, 997, 997, 997, - 996, 996, 996, 995, 995, 994, 994, 993, 993, 992, 992, - 991, 991, 990, 989, 989, 988, 987, 987, 986, 985, 985, - 984, 983, 982, 981, 981, 980, 979, 978, 977, 976, 975, - 974, 973, 972, 971, 970, 969, 968, 967, 966, 964, 963, - 962, 961, 960, 958, 957, 956, 955, 953, 952, 951, 949, - 948, 946, 945, 944, 942, 941, 939, 938, 936, 935, 933, - 931, 930, 928, 927, 925, 923, 922, 920, 918, 917, 915, - 913, 911, 909, 908, 906, 904, 902, 900, 898, 896, 895, - 893, 891, 889, 887, 885, 883, 881, 879, 877, 875, 872, - 870, 868, 866, 864, 862, 860, 857, 855, 853, 851, 849, - 846, 844, 842, 839, 837, 835, 833, 830, 828, 825, 823, - 821, 818, 816, 813, 811, 808, 806, 803, 801, 798, 796, - 793, 791, 788, 786, 783, 781, 778, 775, 773, 770, 767, - 765, 762, 759, 757, 754, 751, 749, 746, 743, 740, 738, - 735, 732, 729, 726, 724, 721, 718, 715, 712, 710, 707, - 704, 701, 698, 695, 692, 689, 686, 684, 681, 678, 675, - 672, 669, 666, 663, 660, 657, 654, 651, 648, 645, 642, - 639, 636, 633, 630, 627, 624, 621, 618, 615, 612, 609, - 606, 602, 599, 596, 593, 590, 587, 584, 581, 578, 575, - 572, 568, 565, 562, 559, 556, 553, 550, 547, 543, 540, - 537, 534, 531, 528, 525, 521, 518, 515, 512, 509, 506, - 503, 499, 496, 493, 490], dtype=uint32), -'ASAM.M.SCALAR.UBYTE.VTAB_RANGE_NO_DEFAULT_VALUE': array([199, 198, 196, 195, 194, 193, 192, 190, 189, 188, 187, 185, 184, - 183, 181, 180, 178, 177, 176, 174, 173, 171, 170, 168, 167, 165, - 163, 162, 160, 159, 157, 155, 154, 152, 150, 149, 147, 145, 143, - 141, 140, 138, 136, 134, 132, 130, 128, 127, 125, 123, 121, 119, - 117, 115, 113, 111, 109, 107, 104, 102, 100, 98, 96, 94, 92, - 89, 87, 85, 83, 81, 78, 76, 74, 71, 69, 67, 65, 62, - 60, 57, 55, 53, 50, 48, 45, 43, 40, 38, 35, 33, 30, - 28, 25, 23, 20, 18, 15, 13, 10, 7, 5, 2, 255, 253, - 250, 247, 245, 242, 239, 237, 234, 231, 228, 226, 223, 220, 217, - 214, 212, 209, 206, 203, 200, 198, 195, 192, 189, 186, 183, 180, - 177, 174, 172, 169, 166, 163, 160, 157, 154, 151, 148, 145, 142, - 139, 136, 133, 130, 127, 124, 121, 118, 115, 112, 109, 106, 103, - 100, 97, 94, 90, 87, 84, 81, 78, 75, 72, 69, 66, 63, - 60, 56, 53, 50, 47, 44, 41, 38, 35, 31, 28, 25, 22, - 19, 16, 13, 9, 6, 3, 0, 253, 250, 247, 243, 240, 237, - 234, 231, 228, 225, 222, 218, 215, 212, 209, 206, 203, 200, 196, - 193, 190, 187, 184, 181, 178, 175, 171, 168, 165, 162, 159, 156, - 153, 150, 147, 144, 141, 137, 134, 131, 128, 125, 122, 119, 116, - 113, 110, 107, 104, 101, 98, 95, 92, 89, 86, 83, 80, 77, - 74, 71, 68, 65, 62, 59, 57, 54, 51, 48, 45, 42, 39, - 36, 33, 31, 28, 25, 22, 19, 17, 14, 11, 8, 5, 3, - 0, 253, 250, 248, 245, 242, 240, 237, 234, 232, 229, 226, 224, - 221, 218, 216, 213, 211, 208, 206, 203, 201, 198, 196, 193, 191, - 188, 186, 183, 181, 178, 176, 174, 171, 169, 166, 164, 162, 160, - 157, 155, 153, 150, 148, 146, 144, 142, 139, 137, 135, 133, 131, - 129, 127, 124, 122, 120, 118, 116, 114, 112, 110, 108, 106, 104, - 103, 101, 99, 97, 95, 93, 91, 90, 88, 86, 84, 82, 81, - 79, 77, 76, 74, 72, 71, 69, 68, 66, 64, 63, 61, 60, - 58, 57, 55, 54, 53, 51, 50, 48, 47, 46, 44, 43, 42, - 41, 39, 38, 37, 36, 35, 33, 32, 31, 30, 29, 28, 27, - 26, 25, 24, 23, 22, 21, 20, 19, 18, 18, 17, 16, 15, - 14, 14, 13, 12, 12, 11, 10, 10, 9, 8, 8, 7, 7, - 6, 6, 5, 5, 4, 4, 3, 3, 3, 2, 2, 2, 1, - 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, - 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 5, 5, 6, - 6, 7, 7, 8, 8, 9, 10, 10, 11, 12, 12, 13, 14, - 14, 15, 16, 17, 18, 18, 19, 20, 21, 22, 23, 24, 25, - 26, 27, 28, 29, 30, 31, 32, 33, 35, 36, 37, 38, 39, - 41, 42, 43, 44, 46, 47, 48, 50, 51, 53, 54, 55, 57, - 58, 60, 61, 63, 64, 66, 68, 69, 71, 72, 74, 76, 77, - 79, 81, 82, 84, 86, 88, 90, 91, 93, 95, 97, 99, 101, - 103, 104, 106, 108, 110, 112, 114, 116, 118, 120, 122, 124, 127, - 129, 131, 133, 135, 137, 139, 142, 144, 146, 148, 150, 153, 155, - 157, 160, 162, 164, 166, 169, 171, 174, 176, 178, 181, 183, 186, - 188, 191, 193, 196, 198, 201, 203, 206, 208, 211, 213, 216, 218, - 221, 224, 226, 229, 232, 234, 237, 240, 242, 245, 248, 250, 253, - 0, 3, 5, 8, 11, 14, 17, 19, 22, 25, 28, 31, 33, - 36, 39, 42, 45, 48, 51, 54, 57, 59, 62, 65, 68, 71, - 74, 77, 80, 83, 86, 89, 92, 95, 98, 101, 104, 107, 110, - 113, 116, 119, 122, 125, 128, 131, 134, 137, 141, 144, 147, 150, - 153, 156, 159, 162, 165, 168, 171, 175, 178, 181, 184, 187, 190, - 193, 196, 200, 203, 206, 209, 212, 215, 218, 222, 225, 228, 231, - 234, 237, 240, 244, 247, 250, 253, 0, 3, 6, 9, 13, 16, - 19, 22, 25, 28, 31, 35, 38, 41, 44, 47, 50, 53, 56, - 60, 63, 66, 69, 72, 75, 78, 81, 84, 87, 90, 94, 97, - 100, 103, 106, 109, 112, 115, 118, 121, 124, 127, 130, 133, 136, - 139, 142, 145, 148, 151, 154, 157, 160, 163, 166, 169, 172, 174, - 177, 180, 183, 186, 189, 192, 195, 198, 200, 203, 206, 209, 212, - 214, 217, 220, 223, 226, 228, 231, 234, 237, 239, 242, 245, 247, - 250, 253, 255, 2, 5, 7, 10, 13, 15, 18, 20, 23, 25, - 28, 30, 33, 35, 38, 40, 43, 45, 48, 50, 53, 55, 57, - 60, 62, 65, 67, 69, 71, 74, 76, 78, 81, 83, 85, 87, - 89, 92, 94, 96, 98, 100, 102, 104, 107, 109, 111, 113, 115, - 117, 119, 121, 123, 125, 127, 128, 130, 132, 134, 136, 138, 140, - 141, 143, 145, 147, 149, 150, 152, 154, 155, 157, 159, 160, 162, - 163, 165, 167, 168, 170, 171, 173, 174, 176, 177, 178, 180, 181, - 183, 184, 185, 187, 188, 189, 190, 192, 193, 194, 195, 196, 198, - 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210], dtype=uint8), -'ASAM.M.SCALAR.FLOAT64.IDENTICAL': array([ 1.73091812e+01, 1.64992561e+01, 1.57084198e+01, - 1.49367018e+01, 1.41841335e+01, 1.34507446e+01, - 1.27365637e+01, 1.20416193e+01, 1.13659382e+01, - 1.07095480e+01, 1.00724735e+01, 9.45474148e+00, - 8.85637474e+00, 8.27739716e+00, 7.71783257e+00, - 7.17770243e+00, 6.65702772e+00, 6.15582991e+00, - 5.67412758e+00, 5.21194077e+00, 4.76928711e+00, - 4.34618425e+00, 3.94264936e+00, 3.55869770e+00, - 3.19434476e+00, 2.84960485e+00, 2.52449155e+00, - 2.21901774e+00, 1.93319547e+00, 1.66703594e+00, - 1.42054987e+00, 1.19374681e+00, 9.86635804e-01, - 7.99224973e-01, 6.31521702e-01, 4.83532667e-01, - 3.55263680e-01, 2.46719822e-01, 1.57905355e-01, - 8.88238102e-02, 3.94778997e-02, 9.86957178e-03, - 0.00000000e+00, 9.86957178e-03, 3.94778959e-02, - 8.88238102e-02, 1.57905355e-01, 2.46719822e-01, - 3.55263680e-01, 4.83532667e-01, 6.31521702e-01, - 7.99224973e-01, 9.86635804e-01, 1.19374681e+00, - 1.42054987e+00, 1.66703594e+00, 1.93319547e+00, - 2.21901774e+00, 2.52449155e+00, 2.84960485e+00, - 3.19434476e+00, 3.55869770e+00, 3.94264936e+00, - 4.34618425e+00, 4.76928711e+00, 5.21194077e+00, - 5.67412758e+00, 6.15582991e+00, 6.65702772e+00, - 7.17770243e+00, 7.71783257e+00, 8.27739716e+00, - 8.85637474e+00, 9.45474148e+00, 1.00724735e+01, - 1.07095480e+01, 1.13659382e+01, 1.20416193e+01, - 1.27365637e+01, 1.34507446e+01, 1.41841335e+01, - 1.49367018e+01, 1.57084198e+01, 1.64992561e+01, - 1.73091812e+01, 1.81381607e+01, 1.89861641e+01, - 1.98531570e+01, 2.07391052e+01, 2.16439743e+01, - 2.25677280e+01, 2.35103283e+01, 2.44717426e+01, - 2.54519272e+01, 2.64508476e+01, 2.74684620e+01, - 2.85047321e+01, 2.95596161e+01, 3.06330719e+01, - 3.17250557e+01, 3.28355293e+01, 3.39644432e+01, - 3.51117554e+01, 3.62774239e+01, 3.74613953e+01, - 3.86636314e+01, 3.98840752e+01, 4.11226883e+01, - 4.23794136e+01, 4.36542053e+01, 4.49470139e+01, - 4.62577896e+01, 4.75864754e+01, 4.89330215e+01, - 5.02973747e+01, 5.16794815e+01, 5.30792885e+01, - 5.44967384e+01, 5.59317741e+01, 5.73843460e+01, - 5.88543854e+01, 6.03418465e+01, 6.18466606e+01, - 6.33687744e+01, 6.49081192e+01, 6.64646530e+01, - 6.80382919e+01, 6.96289902e+01, 7.12366714e+01, - 7.28612823e+01, 7.45027618e+01, 7.61610336e+01, - 7.78360367e+01, 7.95277100e+01, 8.12359772e+01, - 8.29607849e+01, 8.47020493e+01, 8.64597092e+01, - 8.82337036e+01, 9.00239487e+01, 9.18303757e+01, - 9.36529160e+01, 9.54915009e+01, 9.73460541e+01, - 9.92165070e+01, 1.01102783e+02, 1.03004799e+02, - 1.04922493e+02, 1.06855782e+02, 1.08804596e+02, - 1.10768852e+02, 1.12748466e+02, 1.14743378e+02, - 1.16753494e+02, 1.18778748e+02, 1.20819046e+02, - 1.22874313e+02, 1.24944466e+02, 1.27029427e+02, - 1.29129120e+02, 1.31243439e+02, 1.33372330e+02, - 1.35515686e+02, 1.37673431e+02, 1.39845490e+02, - 1.42031754e+02, 1.44232162e+02, 1.46446609e+02, - 1.48675018e+02, 1.50917297e+02, 1.53173340e+02, - 1.55443100e+02, 1.57726440e+02, 1.60023315e+02, - 1.62333603e+02, 1.64657211e+02, 1.66994064e+02, - 1.69344070e+02, 1.71707123e+02, 1.74083130e+02, - 1.76472015e+02, 1.78873672e+02, 1.81288010e+02, - 1.83714920e+02, 1.86154312e+02, 1.88606110e+02, - 1.91070190e+02, 1.93546478e+02, 1.96034851e+02, - 1.98535233e+02, 2.01047516e+02, 2.03571594e+02, - 2.06107376e+02, 2.08654755e+02, 2.11213654e+02, - 2.13783936e+02, 2.16365524e+02, 2.18958313e+02, - 2.21562195e+02, 2.24177063e+02, 2.26802826e+02, - 2.29439377e+02, 2.32086609e+02, 2.34744415e+02, - 2.37412689e+02, 2.40091324e+02, 2.42780228e+02, - 2.45479294e+02, 2.48188400e+02, 2.50907440e+02, - 2.53636322e+02, 2.56374939e+02, 2.59123169e+02, - 2.61880890e+02, 2.64648041e+02, 2.67424469e+02, - 2.70210083e+02, 2.73004761e+02, 2.75808380e+02, - 2.78620880e+02, 2.81442108e+02, 2.84271973e+02, - 2.87110352e+02, 2.89957123e+02, 2.92812195e+02, - 2.95675476e+02, 2.98546783e+02, 3.01426056e+02, - 3.04313171e+02, 3.07208008e+02, 3.10110443e+02, - 3.13020386e+02, 3.15937714e+02, 3.18862305e+02, - 3.21794067e+02, 3.24732849e+02, 3.27678528e+02, - 3.30631042e+02, 3.33590240e+02, 3.36556000e+02, - 3.39528198e+02, 3.42506744e+02, 3.45491516e+02, - 3.48482361e+02, 3.51479218e+02, 3.54481903e+02, - 3.57490356e+02, 3.60504456e+02, 3.63524017e+02, - 3.66549011e+02, 3.69579254e+02, 3.72614624e+02, - 3.75655060e+02, 3.78700378e+02, 3.81750488e+02, - 3.84805298e+02, 3.87864624e+02, 3.90928375e+02, - 3.93996460e+02, 3.97068695e+02, 4.00145020e+02, - 4.03225281e+02, 4.06309357e+02, 4.09397125e+02, - 4.12488464e+02, 4.15583282e+02, 4.18681427e+02, - 4.21782776e+02, 4.24887207e+02, 4.27994598e+02, - 4.31104858e+02, 4.34217834e+02, 4.37333374e+02, - 4.40451416e+02, 4.43571808e+02, 4.46694427e+02, - 4.49819153e+02, 4.52945831e+02, 4.56074402e+02, - 4.59204681e+02, 4.62336609e+02, 4.65470001e+02, - 4.68604736e+02, 4.71740723e+02, 4.74877838e+02, - 4.78015930e+02, 4.81154907e+02, 4.84294617e+02, - 4.87434967e+02, 4.90575775e+02, 4.93716980e+02, - 4.96858429e+02, 5.00000000e+02, 5.03141571e+02, - 5.06283020e+02, 5.09424225e+02, 5.12565063e+02, - 5.15705383e+02, 5.18845093e+02, 5.21984070e+02, - 5.25122131e+02, 5.28259277e+02, 5.31395264e+02, - 5.34530029e+02, 5.37663391e+02, 5.40795288e+02, - 5.43925598e+02, 5.47054138e+02, 5.50180847e+02, - 5.53305603e+02, 5.56428223e+02, 5.59548584e+02, - 5.62666626e+02, 5.65782166e+02, 5.68895142e+02, - 5.72005371e+02, 5.75112793e+02, 5.78217224e+02, - 5.81318604e+02, 5.84416748e+02, 5.87511536e+02, - 5.90602905e+02, 5.93690674e+02, 5.96774719e+02, - 5.99854980e+02, 6.02931274e+02, 6.06003540e+02, - 6.09071594e+02, 6.12135376e+02, 6.15194702e+02, - 6.18249512e+02, 6.21299622e+02, 6.24344971e+02, - 6.27385376e+02, 6.30420776e+02, 6.33450989e+02, - 6.36475952e+02, 6.39495544e+02, 6.42509644e+02, - 6.45518066e+02, 6.48520813e+02, 6.51517639e+02, - 6.54508484e+02, 6.57493286e+02, 6.60471802e+02, - 6.63444031e+02, 6.66409790e+02, 6.69368958e+02, - 6.72321472e+02, 6.75267151e+02, 6.78205933e+02, - 6.81137695e+02, 6.84062256e+02, 6.86979614e+02, - 6.89889526e+02, 6.92791992e+02, 6.95686829e+02, - 6.98573975e+02, 7.01453247e+02, 7.04324524e+02, - 7.07187805e+02, 7.10042847e+02, 7.12889648e+02, - 7.15728027e+02, 7.18557861e+02, 7.21379089e+02, - 7.24191589e+02, 7.26995239e+02, 7.29789917e+02, - 7.32575562e+02, 7.35351990e+02, 7.38119080e+02, - 7.40876831e+02, 7.43625061e+02, 7.46363647e+02, - 7.49092529e+02, 7.51811584e+02, 7.54520691e+02, - 7.57219788e+02, 7.59908691e+02, 7.62587341e+02, - 7.65255615e+02, 7.67913391e+02, 7.70560608e+02, - 7.73197144e+02, 7.75822937e+02, 7.78437805e+02, - 7.81041687e+02, 7.83634460e+02, 7.86216064e+02, - 7.88786377e+02, 7.91345215e+02, 7.93892639e+02, - 7.96428406e+02, 7.98952515e+02, 8.01464783e+02, - 8.03965149e+02, 8.06453552e+02, 8.08929810e+02, - 8.11393860e+02, 8.13845703e+02, 8.16285095e+02, - 8.18711975e+02, 8.21126343e+02, 8.23527954e+02, - 8.25916870e+02, 8.28292908e+02, 8.30655945e+02, - 8.33005920e+02, 8.35342773e+02, 8.37666382e+02, - 8.39976685e+02, 8.42273560e+02, 8.44556885e+02, - 8.46826660e+02, 8.49082703e+02, 8.51325012e+02, - 8.53553406e+02, 8.55767822e+02, 8.57968262e+02, - 8.60154541e+02, 8.62326538e+02, 8.64484314e+02, - 8.66627686e+02, 8.68756531e+02, 8.70870911e+02, - 8.72970581e+02, 8.75055542e+02, 8.77125671e+02, - 8.79180969e+02, 8.81221252e+02, 8.83246521e+02, - 8.85256592e+02, 8.87251526e+02, 8.89231140e+02, - 8.91195435e+02, 8.93144226e+02, 8.95077515e+02, - 8.96995178e+02, 8.98897217e+02, 9.00783508e+02, - 9.02653931e+02, 9.04508484e+02, 9.06347107e+02, - 9.08169617e+02, 9.09976074e+02, 9.11766296e+02, - 9.13540283e+02, 9.15297974e+02, 9.17039246e+02, - 9.18764038e+02, 9.20472290e+02, 9.22163940e+02, - 9.23838989e+02, 9.25497253e+02, 9.27138733e+02, - 9.28763306e+02, 9.30371033e+02, 9.31961731e+02, - 9.33535339e+02, 9.35091858e+02, 9.36631226e+02, - 9.38153320e+02, 9.39658142e+02, 9.41145630e+02, - 9.42615662e+02, 9.44068237e+02, 9.45503235e+02, - 9.46920715e+02, 9.48320496e+02, 9.49702637e+02, - 9.51066956e+02, 9.52413513e+02, 9.53742188e+02, - 9.55052979e+02, 9.56345764e+02, 9.57620605e+02, - 9.58877319e+02, 9.60115906e+02, 9.61336365e+02, - 9.62538574e+02, 9.63722595e+02, 9.64888245e+02, - 9.66035583e+02, 9.67164490e+02, 9.68274963e+02, - 9.69366943e+02, 9.70440369e+02, 9.71495239e+02, - 9.72531555e+02, 9.73549133e+02, 9.74548096e+02, - 9.75528259e+02, 9.76489685e+02, 9.77432251e+02, - 9.78356018e+02, 9.79260864e+02, 9.80146851e+02, - 9.81013855e+02, 9.81861816e+02, 9.82690796e+02, - 9.83500732e+02, 9.84291565e+02, 9.85063293e+02, - 9.85815857e+02, 9.86549255e+02, 9.87263428e+02, - 9.87958374e+02, 9.88634033e+02, 9.89290466e+02, - 9.89927551e+02, 9.90545288e+02, 9.91143616e+02, - 9.91722595e+02, 9.92282166e+02, 9.92822327e+02, - 9.93342957e+02, 9.93844177e+02, 9.94325867e+02, - 9.94788086e+02, 9.95230713e+02, 9.95653809e+02, - 9.96057373e+02, 9.96441284e+02, 9.96805664e+02, - 9.97150391e+02, 9.97475525e+02, 9.97781006e+02, - 9.98066833e+02, 9.98332947e+02, 9.98579468e+02, - 9.98806274e+02, 9.99013367e+02, 9.99200745e+02, - 9.99368469e+02, 9.99516479e+02, 9.99644714e+02, - 9.99753296e+02, 9.99842102e+02, 9.99911194e+02, - 9.99960510e+02, 9.99990112e+02, 1.00000000e+03, - 9.99990112e+02, 9.99960510e+02, 9.99911194e+02, - 9.99842102e+02, 9.99753296e+02, 9.99644714e+02, - 9.99516479e+02, 9.99368469e+02, 9.99200745e+02, - 9.99013367e+02, 9.98806274e+02, 9.98579468e+02, - 9.98332947e+02, 9.98066833e+02, 9.97781006e+02, - 9.97475525e+02, 9.97150391e+02, 9.96805664e+02, - 9.96441284e+02, 9.96057373e+02, 9.95653809e+02, - 9.95230713e+02, 9.94788086e+02, 9.94325867e+02, - 9.93844177e+02, 9.93342957e+02, 9.92822327e+02, - 9.92282166e+02, 9.91722595e+02, 9.91143616e+02, - 9.90545288e+02, 9.89927551e+02, 9.89290466e+02, - 9.88634033e+02, 9.87958374e+02, 9.87263428e+02, - 9.86549255e+02, 9.85815857e+02, 9.85063293e+02, - 9.84291565e+02, 9.83500732e+02, 9.82690796e+02, - 9.81861816e+02, 9.81013855e+02, 9.80146851e+02, - 9.79260864e+02, 9.78356018e+02, 9.77432251e+02, - 9.76489685e+02, 9.75528259e+02, 9.74548096e+02, - 9.73549133e+02, 9.72531555e+02, 9.71495239e+02, - 9.70440369e+02, 9.69366943e+02, 9.68274963e+02, - 9.67164490e+02, 9.66035583e+02, 9.64888245e+02, - 9.63722595e+02, 9.62538574e+02, 9.61336365e+02, - 9.60115906e+02, 9.58877319e+02, 9.57620605e+02, - 9.56345764e+02, 9.55052979e+02, 9.53742188e+02, - 9.52413513e+02, 9.51066956e+02, 9.49702637e+02, - 9.48320496e+02, 9.46920715e+02, 9.45503235e+02, - 9.44068237e+02, 9.42615662e+02, 9.41145630e+02, - 9.39658142e+02, 9.38153320e+02, 9.36631226e+02, - 9.35091858e+02, 9.33535339e+02, 9.31961731e+02, - 9.30371033e+02, 9.28763306e+02, 9.27138733e+02, - 9.25497253e+02, 9.23838989e+02, 9.22163940e+02, - 9.20472290e+02, 9.18764038e+02, 9.17039246e+02, - 9.15297974e+02, 9.13540283e+02, 9.11766296e+02, - 9.09976074e+02, 9.08169617e+02, 9.06347107e+02, - 9.04508484e+02, 9.02653931e+02, 9.00783508e+02, - 8.98897217e+02, 8.96995178e+02, 8.95077515e+02, - 8.93144226e+02, 8.91195435e+02, 8.89231140e+02, - 8.87251526e+02, 8.85256592e+02, 8.83246521e+02, - 8.81221252e+02, 8.79180969e+02, 8.77125671e+02, - 8.75055542e+02, 8.72970581e+02, 8.70870911e+02, - 8.68756531e+02, 8.66627686e+02, 8.64484314e+02, - 8.62326538e+02, 8.60154541e+02, 8.57968262e+02, - 8.55767822e+02, 8.53553406e+02, 8.51325012e+02, - 8.49082703e+02, 8.46826660e+02, 8.44556885e+02, - 8.42273560e+02, 8.39976685e+02, 8.37666382e+02, - 8.35342773e+02, 8.33005920e+02, 8.30655945e+02, - 8.28292908e+02, 8.25916870e+02, 8.23527954e+02, - 8.21126343e+02, 8.18711975e+02, 8.16285095e+02, - 8.13845703e+02, 8.11393860e+02, 8.08929810e+02, - 8.06453552e+02, 8.03965149e+02, 8.01464783e+02, - 7.98952515e+02, 7.96428406e+02, 7.93892639e+02, - 7.91345215e+02, 7.88786377e+02, 7.86216064e+02, - 7.83634460e+02, 7.81041687e+02, 7.78437805e+02, - 7.75822937e+02, 7.73197144e+02, 7.70560608e+02, - 7.67913391e+02, 7.65255615e+02, 7.62587341e+02, - 7.59908691e+02, 7.57219788e+02, 7.54520691e+02, - 7.51811584e+02, 7.49092529e+02, 7.46363647e+02, - 7.43625061e+02, 7.40876831e+02, 7.38119080e+02, - 7.35351990e+02, 7.32575562e+02, 7.29789917e+02, - 7.26995239e+02, 7.24191589e+02, 7.21379089e+02, - 7.18557861e+02, 7.15728027e+02, 7.12889648e+02, - 7.10042847e+02, 7.07187805e+02, 7.04324524e+02, - 7.01453247e+02, 6.98573975e+02, 6.95686829e+02, - 6.92791992e+02, 6.89889526e+02, 6.86979614e+02, - 6.84062256e+02, 6.81137695e+02, 6.78205933e+02, - 6.75267151e+02, 6.72321472e+02, 6.69368958e+02, - 6.66409790e+02, 6.63444031e+02, 6.60471802e+02, - 6.57493286e+02, 6.54508484e+02, 6.51517639e+02, - 6.48520813e+02, 6.45518066e+02, 6.42509644e+02, - 6.39495544e+02, 6.36475952e+02, 6.33450989e+02, - 6.30420776e+02, 6.27385376e+02, 6.24344971e+02, - 6.21299622e+02, 6.18249512e+02, 6.15194702e+02, - 6.12135376e+02, 6.09071594e+02, 6.06003540e+02, - 6.02931274e+02, 5.99854980e+02, 5.96774719e+02, - 5.93690674e+02, 5.90602905e+02, 5.87511536e+02, - 5.84416748e+02, 5.81318604e+02, 5.78217224e+02, - 5.75112793e+02, 5.72005371e+02, 5.68895142e+02, - 5.65782166e+02, 5.62666626e+02, 5.59548584e+02, - 5.56428223e+02, 5.53305603e+02, 5.50180847e+02, - 5.47054138e+02, 5.43925598e+02, 5.40795288e+02, - 5.37663391e+02, 5.34530029e+02, 5.31395264e+02, - 5.28259277e+02, 5.25122131e+02, 5.21984070e+02, - 5.18845093e+02, 5.15705383e+02, 5.12565063e+02, - 5.09424225e+02, 5.06283020e+02, 5.03141571e+02, - 5.00000000e+02, 4.96858429e+02, 4.93716980e+02, - 4.90575775e+02, 4.87434967e+02, 4.84294617e+02, - 4.81154907e+02, 4.78015930e+02, 4.74877838e+02, - 4.71740723e+02, 4.68604736e+02, 4.65470001e+02, - 4.62336609e+02, 4.59204681e+02, 4.56074402e+02, - 4.52945831e+02, 4.49819153e+02, 4.46694427e+02, - 4.43571808e+02, 4.40451416e+02, 4.37333374e+02, - 4.34217834e+02, 4.31104858e+02, 4.27994598e+02, - 4.24887207e+02, 4.21782776e+02, 4.18681427e+02, - 4.15583282e+02, 4.12488464e+02, 4.09397125e+02, - 4.06309357e+02, 4.03225281e+02, 4.00145020e+02, - 3.97068695e+02, 3.93996460e+02, 3.90928375e+02, - 3.87864624e+02, 3.84805298e+02, 3.81750488e+02, - 3.78700378e+02, 3.75655060e+02, 3.72614624e+02, - 3.69579254e+02, 3.66549011e+02, 3.63524017e+02, - 3.60504456e+02, 3.57490356e+02, 3.54481903e+02, - 3.51479218e+02, 3.48482361e+02, 3.45491516e+02, - 3.42506744e+02, 3.39528198e+02, 3.36556000e+02, - 3.33590240e+02, 3.30631042e+02, 3.27678528e+02, - 3.24732849e+02, 3.21794067e+02, 3.18862305e+02, - 3.15937714e+02, 3.13020386e+02, 3.10110443e+02, - 3.07208008e+02, 3.04313171e+02, 3.01426056e+02, - 2.98546783e+02, 2.95675476e+02, 2.92812195e+02, - 2.89957123e+02, 2.87110352e+02, 2.84271973e+02, - 2.81442108e+02, 2.78620880e+02, 2.75808380e+02, - 2.73004761e+02, 2.70210083e+02, 2.67424469e+02, - 2.64648041e+02, 2.61880890e+02, 2.59123169e+02, - 2.56374939e+02, 2.53636322e+02, 2.50907440e+02, - 2.48188400e+02, 2.45479294e+02, 2.42780228e+02, - 2.40091324e+02, 2.37412689e+02, 2.34744415e+02, - 2.32086609e+02, 2.29439377e+02, 2.26802826e+02, - 2.24177063e+02, 2.21562195e+02, 2.18958313e+02, - 2.16365524e+02, 2.13783936e+02, 2.11213654e+02, - 2.08654755e+02, 2.06107376e+02, 2.03571594e+02, - 2.01047516e+02, 1.98535233e+02], dtype=float32), -'ASAM.M.SCALAR.UWORD.IDENTICAL.BITMASK_0008': array([0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, - 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, - 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1, - 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, - 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, - 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, - 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, - 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, - 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, - 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, - 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, - 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, - 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, - 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, - 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, - 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, - 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, - 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, - 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, - 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, - 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, - 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, - 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, - 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, - 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, - 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, - 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, - 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, - 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, - 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1], dtype=uint8), -'ASAM.M.VIRTUAL.SCALAR.SWORD.PHYSICAL': array([ -544, -464, -384, -304, -224, -144, -64, 16, 96, - 176, 256, 336, 416, 496, 576, 656, 736, 816, - 896, 976, -992, -912, -832, -752, -672, -592, -512, - -432, -352, -272, 0, 80, 160, 240, 320, 400, - 480, 560, 640, 720, 800, 880, 960, -1008, -928, - -848, -768, -688, -608, -528, -448, -368, -288, -208, - -128, -48, 32, 112, 192, 272, 352, 432, 512, - 592, 672, 752, 832, 912, 992, -976, -896, -816, - -736, -656, -576, -496, -416, -336, -256, -176, -96, - -16, 64, 144, 224, 304, 384, 464, 544, 624], dtype=int16), - } - class TestMDF(unittest.TestCase): @@ -1537,9 +51,17 @@ def setUpClass(cls): urllib.urlretrieve(url, 'test.zip') ZipFile(r'test.zip').extractall('tmpdir_demo') + url = 'https://github.com/danielhrisca/asammdf/files/1591223/test.arrays.zip' + if PYVERSION == 3: + urllib.request.urlretrieve(url, 'test.zip') + else: + urllib.urlretrieve(url, 'test.zip') + ZipFile(r'test.zip').extractall('tmpdir_array') + @classmethod def tearDownClass(cls): shutil.rmtree('tmpdir_demo', True) + shutil.rmtree('tmpdir_array', True) os.remove('test.zip') for filename in ('tmp', 'tmp1', 'tmp2')[:1]: if os.path.isfile(filename): @@ -1558,7 +80,7 @@ def test_read(self): continue for name in set(input_file.channels_db) - {'time', 't'}: signal = input_file.get(name) - original_samples = CHANNELS[name] + original_samples = CHANNELS_DEMO[name] if signal.samples.dtype.kind == 'f': signal = signal.astype(float32) res = np.array_equal(signal.samples, original_samples) @@ -1567,6 +89,24 @@ def test_read(self): self.assertTrue(ret) + def test_read_array(self): + + print("MDF read array tests") + + ret = True + + for mdf in os.listdir('tmpdir_array'): + for memory in MEMORY: + with MDF(os.path.join('tmpdir_array', mdf), memory=memory) as input_file: + for name in set(input_file.channels_db) - {'time', 't'}: + signal = input_file.get(name) + original_samples = CHANNELS_ARRAY[name] + res = np.array_equal(signal.samples, original_samples) + if not res: + ret = False + + self.assertTrue(ret) + def test_convert(self): print("MDF convert tests") @@ -1624,6 +164,33 @@ def test_merge(self): self.assertTrue(equal) + def test_merge_array(self): + print("MDF merge array tests") + + for out in (version for version in SUPPORTED_VERSIONS if version >= '4.00'): + for mdfname in os.listdir('tmpdir_array'): + for memory in MEMORY: + input_file = os.path.join('tmpdir_array', mdfname) + files = [input_file, ] * 4 + + MDF.merge(files, out, memory).save('tmp', overwrite=True) + + equal = True + + with MDF(input_file, memory=memory) as mdf, \ + MDF('tmp', memory=memory) as mdf2: + + for i, group in enumerate(mdf.groups): + for j, channel in enumerate(group['channels'][1:], 1): + original = mdf.get(group=i, index=j) + converted = mdf2.get(group=i, index=j) + if not np.array_equal( + np.tile(original.samples, 4), + converted.samples): + equal = False + + self.assertTrue(equal) + def test_cut_absolute(self): print("MDF cut absolute tests") @@ -1660,6 +227,45 @@ def test_cut_absolute(self): self.assertTrue(equal) + @unittest.skip + def test_cut_absolute_array(self): + print("MDF cut absolute array tests") + + for mdfname in os.listdir('tmpdir_array'): + for memory in MEMORY: + input_file = os.path.join('tmpdir_array', mdfname) + + MDF(input_file, memory=memory).cut(stop=2).save('tmp1', overwrite=True) + MDF(input_file, memory=memory).cut(start=2, stop=6).save('tmp2', overwrite=True) + MDF(input_file, memory=memory).cut(start=6).save('tmp3', overwrite=True) + + MDF.merge( + ['tmp1', 'tmp2', 'tmp3'], + MDF(input_file, memory='minimum').version, + ).save('tmp', overwrite=True) + + equal = True + + with MDF(input_file, memory=memory) as mdf, \ + MDF('tmp', memory=memory) as mdf2: + + for i, group in enumerate(mdf.groups): + for j, channel in enumerate(group['channels'][1:], 1): + original = mdf.get(group=i, index=j) + converted = mdf2.get(group=i, index=j) + if not np.array_equal( + original.samples, + converted.samples): + print(original.name, original.samples, converted.samples) + equal = False + if not np.array_equal( + original.timestamps, + converted.timestamps): + print(original.name, original.timestamps, converted.timestamps) + equal = False + + self.assertTrue(equal) + def test_cut_relative(self): print("MDF cut relative tests") @@ -1706,9 +312,9 @@ def test_filter(self): if MDF(input_file, memory=memory).version == '2.00': continue - channels_nr = np.random.randint(1, len(CHANNELS) + 1) + channels_nr = np.random.randint(1, len(CHANNELS_DEMO) + 1) - channel_list = random.sample(list(CHANNELS), channels_nr) + channel_list = random.sample(list(CHANNELS_DEMO), channels_nr) filtered_mdf = MDF(input_file, memory=memory).filter(channel_list, memory=memory) @@ -1732,6 +338,43 @@ def test_filter(self): self.assertTrue(equal) + @unittest.skip + def test_filter_array(self): + print("MDF filter array tests") + + for mdfname in os.listdir('tmpdir_array'): + for memory in MEMORY: + input_file = os.path.join('tmpdir_array', mdfname) + + channels_nr = np.random.randint(1, len(CHANNELS_ARRAY) + 1) + + channel_list = random.sample(list(CHANNELS_ARRAY), channels_nr) + + filtered_mdf = MDF(input_file, memory=memory).filter(channel_list, memory=memory) + from pprint import pprint + pprint(set(filtered_mdf.channels_db) - {'t', 'time'}) + pprint(set(channel_list)) + pprint((set(filtered_mdf.channels_db) - {'t', 'time'}) - set(channel_list)) + self.assertTrue((set(filtered_mdf.channels_db) - {'t', 'time'}) == set(channel_list)) + + equal = True + + with MDF(input_file, memory=memory) as mdf: + + for name in channel_list: + original = mdf.get(name) + filtered = filtered_mdf.get(name) + if not np.array_equal( + original.samples, + filtered.samples): + equal = False + if not np.array_equal( + original.timestamps, + filtered.timestamps): + equal = False + + self.assertTrue(equal) + def test_select(self): print("MDF select tests") @@ -1739,12 +382,12 @@ def test_select(self): for memory in MEMORY: input_file = os.path.join('tmpdir_demo', mdfname) - if MDF(input_file, memory=memory).version == '2.00': + if MDF(input_file).version == '2.00': continue - channels_nr = np.random.randint(1, len(CHANNELS) + 1) + channels_nr = np.random.randint(1, len(CHANNELS_DEMO) + 1) - channel_list = random.sample(list(CHANNELS), channels_nr) + channel_list = random.sample(list(CHANNELS_DEMO), channels_nr) selected_signals = MDF(input_file, memory=memory).select(channel_list) diff --git a/test/utils.py b/test/utils.py index 687247d1f..5da36badd 100644 --- a/test/utils.py +++ b/test/utils.py @@ -1,10 +1,1593 @@ # -*- coding: utf-8 -*- import os +import numpy as np MEMORY = ('minimum', 'low', 'full') +CHANNELS_DEMO = { + +'$ActiveCalibrationPage': np.array([1, 0, 1, 1], dtype=np.uint8), +'$CalibrationLog': np.array([b'', b'Switch to reference page', b'Switch to working page', + b'Switch to working page'], + dtype='|S24'), +'ASAM.M.SCALAR.UBYTE.TAB_NOINTP_DEFAULT_VALUE': np.array([ 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 104. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 108. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 102. , + 110.66666412, 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. ], dtype=np.float32), +'ASAM_[0].M.MATRIX_DIM_16_1_1.UBYTE.IDENTICAL': np.array([ 88, 98, 108, 118, 128, 138, 148, 158, 168, 178, 188, 198, 208, + 218, 228, 238, 248, 2, 12, 22, 32, 42, 52, 62, 72, 82, + 92, 102, 112, 122, 132, 142, 152, 162, 172, 182, 192, 202, 212, + 222, 0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110, + 120, 130, 140, 150, 160, 170, 180, 190, 200, 210, 220, 230, 240, + 250, 4, 14, 24, 34, 44, 54, 64, 74, 84, 94, 104, 114, + 124, 134, 144, 154, 164, 174, 184, 194, 204, 214, 224, 234], dtype=np.uint8), +'ASAM.M.SCALAR.SWORD.IDENTICAL': np.array([900, 910, 920, 930, 940, 950, 960, 970, 980, 990, 0, 10, 20, + 30, 40, 50, 60, 70, 80, 90, 100, 110, 120, 130, 140, 150, + 160, 170, 180, 190, 200, 210, 220, 230, 240, 250, 260, 270, 280, + 290, 300, 310, 320, 330, 340, 350, 360, 370, 380, 390, 400, 410, + 420, 430, 440, 450, 460, 470, 480, 490, 500, 510, 520, 530, 540, + 550, 560, 570, 580, 590, 600, 610, 620, 630, 640, 650, 660, 670, + 680, 690, 700, 710, 720, 730, 740, 750, 760, 770, 780, 790], dtype=np.int16), +'ASAM.M.SCALAR.UBYTE.TAB_INTP_DEFAULT_VALUE': np.array([ 111., 111., 111., 111., 111., 111., 111., 111., 111., + 111., 111., 111., 111., 111., 111., 111., 111., 111., + 111., 111., 100., 110., 111., 111., 111., 111., 111., + 111., 111., 111., 111., 111., 111., 111., 111., 111., + 111., 111., 111., 111., 111., 111., 111., 111., 111., + 111., 104., 111., 111., 111., 111., 111., 111., 111., + 111., 111., 111., 111., 111., 111., 111., 111., 111., + 111., 111., 111., 111., 111., 111., 111., 111., 111., + 108., 111., 111., 111., 111., 111., 111., 111., 111., + 111., 111., 111., 111., 111., 111., 111., 111., 111.], dtype=np.float32), +'ASAM.M.SCALAR.UBYTE.FORM_X_PLUS_4': np.array([ 4., 14., 24., 34., 44., 54., 64., 74., 84., + 94., 104., 114., 124., 134., 144., 154., 164., 174., + 184., 194., 204., 214., 224., 234., 244., 254., 8., + 18., 28., 38., 48., 58., 68., 78., 88., 98., + 108., 118., 128., 138., 148., 158., 168., 178., 188., + 198., 208., 218., 228., 238., 248., 258., 12., 22., + 32., 42., 52., 62., 72., 82., 92., 102., 112., + 122., 132., 142., 152., 162., 172., 182., 192., 202., + 212., 222., 232., 242., 252., 6., 16., 26., 36., + 46., 56., 66., 76., 86., 96., 106., 116., 126.], dtype=np.float32), +'ASAM.M.SCALAR.SLONG.IDENTICAL': np.array([200, 210, 220, 230, 240, 250, 260, 270, 280, 290, 300, 310, 320, + 330, 340, 350, 360, 370, 380, 390, 400, 410, 420, 430, 440, 450, + 460, 470, 480, 490, 500, 510, 520, 530, 540, 550, 560, 570, 580, + 590, 600, 610, 620, 630, 640, 650, 660, 670, 680, 690, 700, 710, + 720, 730, 740, 750, 760, 770, 780, 790, 800, 810, 820, 830, 840, + 850, 860, 870, 880, 890, 900, 910, 920, 930, 940, 950, 960, 970, + 980, 990, 0, 10, 20, 30, 40, 50, 60, 70, 80, 90]), +'ASAM.M.SCALAR.UBYTE.IDENTICAL': np.array([188, 198, 208, 218, 228, 238, 248, 2, 12, 22, 32, 42, 52, + 62, 72, 82, 92, 102, 112, 122, 132, 142, 152, 162, 172, 182, + 192, 202, 212, 222, 0, 10, 20, 30, 40, 50, 60, 70, 80, + 90, 100, 110, 120, 130, 140, 150, 160, 170, 180, 190, 200, 210, + 220, 230, 240, 250, 4, 14, 24, 34, 44, 54, 64, 74, 84, + 94, 104, 114, 124, 134, 144, 154, 164, 174, 184, 194, 204, 214, + 224, 234, 244, 254, 8, 18, 28, 38, 48, 58, 68, 78], dtype=np.uint8), +'ASAM.M.SCALAR.UBYTE.TAB_INTP_NO_DEFAULT_VALUE': np.array([ 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 108. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 102. , 110.66666412, 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 100. , 110. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 104. , 111. , + 111. , 111. ], dtype=np.float32), +'ASAM.M.SCALAR.SBYTE.LINEAR_MUL_2': np.array([-136., -116., -96., -76., -56., -36., -16., 4., 24., + 44., 64., 84., 104., 124., 144., 164., 184., 204., + 224., 244., -248., -228., -208., -188., -168., -148., -128., + -108., -88., -68., 0., 20., 40., 60., 80., 100., + 120., 140., 160., 180., 200., 220., 240., -252., -232., + -212., -192., -172., -152., -132., -112., -92., -72., -52., + -32., -12., 8., 28., 48., 68., 88., 108., 128., + 148., 168., 188., 208., 228., 248., -244., -224., -204., + -184., -164., -144., -124., -104., -84., -64., -44., -24., + -4., 16., 36., 56., 76., 96., 116., 136., 156.], dtype=np.float32), +'ASAM_[0].M.ARRAY_SIZE_16.UBYTE.IDENTICAL': np.array([ 44, 54, 64, 74, 84, 94, 104, 114, 124, 134, 144, 154, 164, + 174, 184, 194, 204, 214, 224, 234, 244, 254, 8, 18, 28, 38, + 48, 58, 68, 78, 88, 98, 108, 118, 128, 138, 148, 158, 168, + 178, 188, 198, 208, 218, 228, 238, 248, 2, 12, 22, 32, 42, + 52, 62, 72, 82, 92, 102, 112, 122, 132, 142, 152, 162, 172, + 182, 192, 202, 212, 222, 0, 10, 20, 30, 40, 50, 60, 70, + 80, 90, 100, 110, 120, 130, 140, 150, 160, 170, 180, 190], dtype=np.uint8), +'ASAM_[0][0].M.MATRIX_DIM_8_2_1.UBYTE.IDENTICAL': np.array([244, 254, 8, 18, 28, 38, 48, 58, 68, 78, 88, 98, 108, + 118, 128, 138, 148, 158, 168, 178, 188, 198, 208, 218, 228, 238, + 248, 2, 12, 22, 32, 42, 52, 62, 72, 82, 92, 102, 112, + 122, 132, 142, 152, 162, 172, 182, 192, 202, 212, 222, 0, 10, + 20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120, 130, 140, + 150, 160, 170, 180, 190, 200, 210, 220, 230, 240, 250, 4, 14, + 24, 34, 44, 54, 64, 74, 84, 94, 104, 114, 124, 134], dtype=np.uint8), +'ASAM.M.SCALAR.UWORD.IDENTICAL.BITMASK_0FF0': np.array([61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 62, 62, 62, + 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, + 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, + 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, + 62, 62, 62, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, + 61, 61, 61, 61, 61, 61, 61, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, + 60, 60, 60, 60, 60, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 57, 57, 57, 57, 57, 57, 57, + 57, 57, 56, 56, 56, 56, 56, 56, 56, 56, 56, 55, 55, 55, 55, 55, 55, + 55, 55, 54, 54, 54, 54, 54, 54, 54, 54, 53, 53, 53, 53, 53, 53, 53, + 52, 52, 52, 52, 52, 52, 52, 51, 51, 51, 51, 51, 51, 51, 50, 50, 50, + 50, 50, 50, 49, 49, 49, 49, 49, 49, 48, 48, 48, 48, 48, 48, 47, 47, + 47, 47, 47, 47, 46, 46, 46, 46, 46, 46, 45, 45, 45, 45, 45, 45, 44, + 44, 44, 44, 44, 44, 43, 43, 43, 43, 43, 42, 42, 42, 42, 42, 42, 41, + 41, 41, 41, 41, 40, 40, 40, 40, 40, 39, 39, 39, 39, 39, 39, 38, 38, + 38, 38, 38, 37, 37, 37, 37, 37, 36, 36, 36, 36, 36, 35, 35, 35, 35, + 35, 34, 34, 34, 34, 34, 33, 33, 33, 33, 33, 33, 32, 32, 32, 32, 32, + 31, 31, 31, 31, 31, 30, 30, 30, 30, 30, 29, 29, 29, 29, 29, 28, 28, + 28, 28, 28, 27, 27, 27, 27, 27, 26, 26, 26, 26, 26, 25, 25, 25, 25, + 25, 25, 24, 24, 24, 24, 24, 23, 23, 23, 23, 23, 22, 22, 22, 22, 22, + 21, 21, 21, 21, 21, 21, 20, 20, 20, 20, 20, 19, 19, 19, 19, 19, 19, + 18, 18, 18, 18, 18, 17, 17, 17, 17, 17, 17, 16, 16, 16, 16, 16, 16, + 15, 15, 15, 15, 15, 15, 14, 14, 14, 14, 14, 14, 13, 13, 13, 13, 13, + 13, 12, 12, 12, 12, 12, 12, 11, 11, 11, 11, 11, 11, 11, 10, 10, 10, + 10, 10, 10, 10, 9, 9, 9, 9, 9, 9, 9, 8, 8, 8, 8, 8, 8, + 8, 7, 7, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, + 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, + 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, + 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, + 13, 13, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 16, 16, 16, + 16, 16, 16, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 19, 19, 19, + 19, 19, 19, 20, 20, 20, 20, 20, 21, 21, 21, 21, 21, 21, 22, 22, 22, + 22, 22, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 25, 25, 25, 25, 25, + 25, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 28, 28, 28, 28, 28, 29, + 29, 29, 29, 29, 30, 30, 30, 30, 30, 31, 31, 31, 31, 31, 32, 32, 32, + 32, 32, 33, 33, 33, 33, 33, 33, 34, 34, 34, 34, 34, 35, 35, 35, 35, + 35, 36, 36, 36, 36, 36, 37, 37, 37, 37, 37, 38, 38, 38, 38, 38, 39, + 39, 39, 39, 39, 39, 40, 40, 40, 40, 40, 41, 41, 41, 41, 41, 42, 42, + 42, 42, 42, 42, 43, 43, 43, 43, 43, 44, 44, 44, 44, 44, 44, 45, 45, + 45, 45, 45, 45, 46, 46, 46, 46, 46, 46, 47, 47, 47, 47, 47, 47, 48, + 48, 48, 48, 48, 48, 49, 49, 49, 49, 49, 49, 50], dtype=np.uint16), +'ASAM.M.SCALAR.UBYTE.VTAB_RANGE_DEFAULT_VALUE': np.array([ 13, 16, 19, 22, 25, 28, 31, 35, 38, 41, 44, 47, 50, + 53, 56, 60, 63, 66, 69, 72, 75, 78, 81, 84, 87, 90, + 94, 97, 100, 103, 106, 109, 112, 115, 118, 121, 124, 127, 130, + 133, 136, 139, 142, 145, 148, 151, 154, 157, 160, 163, 166, 169, + 172, 174, 177, 180, 183, 186, 189, 192, 195, 198, 200, 203, 206, + 209, 212, 214, 217, 220, 223, 226, 228, 231, 234, 237, 239, 242, + 245, 247, 250, 253, 255, 2, 5, 7, 10, 13, 15, 18, 20, + 23, 25, 28, 30, 33, 35, 38, 40, 43, 45, 48, 50, 53, + 55, 57, 60, 62, 65, 67, 69, 71, 74, 76, 78, 81, 83, + 85, 87, 89, 92, 94, 96, 98, 100, 102, 104, 107, 109, 111, + 113, 115, 117, 119, 121, 123, 125, 127, 128, 130, 132, 134, 136, + 138, 140, 141, 143, 145, 147, 149, 150, 152, 154, 155, 157, 159, + 160, 162, 163, 165, 167, 168, 170, 171, 173, 174, 176, 177, 178, + 180, 181, 183, 184, 185, 187, 188, 189, 190, 192, 193, 194, 195, + 196, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, + 210, 211, 212, 213, 213, 214, 215, 216, 217, 217, 218, 219, 219, + 220, 221, 221, 222, 223, 223, 224, 224, 225, 225, 226, 226, 227, + 227, 228, 228, 228, 229, 229, 229, 230, 230, 230, 230, 231, 231, + 231, 231, 231, 231, 231, 231, 231, 231, 232, 231, 231, 231, 231, + 231, 231, 231, 231, 231, 231, 230, 230, 230, 230, 229, 229, 229, + 228, 228, 228, 227, 227, 226, 226, 225, 225, 224, 224, 223, 223, + 222, 221, 221, 220, 219, 219, 218, 217, 217, 216, 215, 214, 213, + 213, 212, 211, 210, 209, 208, 207, 206, 205, 204, 203, 202, 201, + 200, 199, 198, 196, 195, 194, 193, 192, 190, 189, 188, 187, 185, + 184, 183, 181, 180, 178, 177, 176, 174, 173, 171, 170, 168, 167, + 165, 163, 162, 160, 159, 157, 155, 154, 152, 150, 149, 147, 145, + 143, 141, 140, 138, 136, 134, 132, 130, 128, 127, 125, 123, 121, + 119, 117, 115, 113, 111, 109, 107, 104, 102, 100, 98, 96, 94, + 92, 89, 87, 85, 83, 81, 78, 76, 74, 71, 69, 67, 65, + 62, 60, 57, 55, 53, 50, 48, 45, 43, 40, 38, 35, 33, + 30, 28, 25, 23, 20, 18, 15, 13, 10, 7, 5, 2, 255, + 253, 250, 247, 245, 242, 239, 237, 234, 231, 228, 226, 223, 220, + 217, 214, 212, 209, 206, 203, 200, 198, 195, 192, 189, 186, 183, + 180, 177, 174, 172, 169, 166, 163, 160, 157, 154, 151, 148, 145, + 142, 139, 136, 133, 130, 127, 124, 121, 118, 115, 112, 109, 106, + 103, 100, 97, 94, 90, 87, 84, 81, 78, 75, 72, 69, 66, + 63, 60, 56, 53, 50, 47, 44, 41, 38, 35, 31, 28, 25, + 22, 19, 16, 13, 9, 6, 3, 0, 253, 250, 247, 243, 240, + 237, 234, 231, 228, 225, 222, 218, 215, 212, 209, 206, 203, 200, + 196, 193, 190, 187, 184, 181, 178, 175, 171, 168, 165, 162, 159, + 156, 153, 150, 147, 144, 141, 137, 134, 131, 128, 125, 122, 119, + 116, 113, 110, 107, 104, 101, 98, 95, 92, 89, 86, 83, 80, + 77, 74, 71, 68, 65, 62, 59, 57, 54, 51, 48, 45, 42, + 39, 36, 33, 31, 28, 25, 22, 19, 17, 14, 11, 8, 5, + 3, 0, 253, 250, 248, 245, 242, 240, 237, 234, 232, 229, 226, + 224, 221, 218, 216, 213, 211, 208, 206, 203, 201, 198, 196, 193, + 191, 188, 186, 183, 181, 178, 176, 174, 171, 169, 166, 164, 162, + 160, 157, 155, 153, 150, 148, 146, 144, 142, 139, 137, 135, 133, + 131, 129, 127, 124, 122, 120, 118, 116, 114, 112, 110, 108, 106, + 104, 103, 101, 99, 97, 95, 93, 91, 90, 88, 86, 84, 82, + 81, 79, 77, 76, 74, 72, 71, 69, 68, 66, 64, 63, 61, + 60, 58, 57, 55, 54, 53, 51, 50, 48, 47, 46, 44, 43, + 42, 41, 39, 38, 37, 36, 35, 33, 32, 31, 30, 29, 28, + 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 18, 17, 16, + 15, 14, 14, 13, 12, 12, 11, 10, 10, 9, 8, 8, 7, + 7, 6, 6, 5, 5, 4, 4, 3, 3, 3, 2, 2, 2, + 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, + 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 5, 5, + 6, 6, 7, 7, 8, 8, 9, 10, 10, 11, 12, 12, 13, + 14, 14, 15, 16, 17, 18, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 35, 36, 37, 38, + 39, 41, 42, 43, 44, 46, 47, 48, 50, 51, 53, 54, 55, + 57, 58, 60, 61, 63, 64, 66, 68, 69, 71, 72, 74, 76, + 77, 79, 81, 82, 84, 86, 88, 90, 91, 93, 95, 97, 99, + 101, 103, 104, 106, 108, 110, 112, 114, 116, 118, 120, 122, 124, + 127, 129, 131, 133, 135, 137, 139, 142, 144, 146, 148, 150, 153, + 155, 157, 160, 162, 164, 166, 169, 171, 174, 176, 178, 181, 183, + 186, 188, 191, 193, 196, 198, 201, 203, 206, 208, 211, 213], dtype=np.uint8), +'ASAM.M.SCALAR.FLOAT32.IDENTICAL': np.array([ 8.13845703e+02, 8.16285095e+02, 8.18711975e+02, + 8.21126343e+02, 8.23527954e+02, 8.25916870e+02, + 8.28292908e+02, 8.30655945e+02, 8.33005920e+02, + 8.35342773e+02, 8.37666382e+02, 8.39976685e+02, + 8.42273560e+02, 8.44556885e+02, 8.46826660e+02, + 8.49082703e+02, 8.51325012e+02, 8.53553406e+02, + 8.55767822e+02, 8.57968262e+02, 8.60154541e+02, + 8.62326538e+02, 8.64484314e+02, 8.66627686e+02, + 8.68756531e+02, 8.70870911e+02, 8.72970581e+02, + 8.75055542e+02, 8.77125671e+02, 8.79180969e+02, + 8.81221252e+02, 8.83246521e+02, 8.85256592e+02, + 8.87251526e+02, 8.89231140e+02, 8.91195435e+02, + 8.93144226e+02, 8.95077515e+02, 8.96995178e+02, + 8.98897217e+02, 9.00783508e+02, 9.02653931e+02, + 9.04508484e+02, 9.06347107e+02, 9.08169617e+02, + 9.09976074e+02, 9.11766296e+02, 9.13540283e+02, + 9.15297974e+02, 9.17039246e+02, 9.18764038e+02, + 9.20472290e+02, 9.22163940e+02, 9.23838989e+02, + 9.25497253e+02, 9.27138733e+02, 9.28763306e+02, + 9.30371033e+02, 9.31961731e+02, 9.33535339e+02, + 9.35091858e+02, 9.36631226e+02, 9.38153320e+02, + 9.39658142e+02, 9.41145630e+02, 9.42615662e+02, + 9.44068237e+02, 9.45503235e+02, 9.46920715e+02, + 9.48320496e+02, 9.49702637e+02, 9.51066956e+02, + 9.52413513e+02, 9.53742188e+02, 9.55052979e+02, + 9.56345764e+02, 9.57620605e+02, 9.58877319e+02, + 9.60115906e+02, 9.61336365e+02, 9.62538574e+02, + 9.63722595e+02, 9.64888245e+02, 9.66035583e+02, + 9.67164490e+02, 9.68274963e+02, 9.69366943e+02, + 9.70440369e+02, 9.71495239e+02, 9.72531555e+02, + 9.73549133e+02, 9.74548096e+02, 9.75528259e+02, + 9.76489685e+02, 9.77432251e+02, 9.78356018e+02, + 9.79260864e+02, 9.80146851e+02, 9.81013855e+02, + 9.81861816e+02, 9.82690796e+02, 9.83500732e+02, + 9.84291565e+02, 9.85063293e+02, 9.85815857e+02, + 9.86549255e+02, 9.87263428e+02, 9.87958374e+02, + 9.88634033e+02, 9.89290466e+02, 9.89927551e+02, + 9.90545288e+02, 9.91143616e+02, 9.91722595e+02, + 9.92282166e+02, 9.92822327e+02, 9.93342957e+02, + 9.93844177e+02, 9.94325867e+02, 9.94788086e+02, + 9.95230713e+02, 9.95653809e+02, 9.96057373e+02, + 9.96441284e+02, 9.96805664e+02, 9.97150391e+02, + 9.97475525e+02, 9.97781006e+02, 9.98066833e+02, + 9.98332947e+02, 9.98579468e+02, 9.98806274e+02, + 9.99013367e+02, 9.99200745e+02, 9.99368469e+02, + 9.99516479e+02, 9.99644714e+02, 9.99753296e+02, + 9.99842102e+02, 9.99911194e+02, 9.99960510e+02, + 9.99990112e+02, 1.00000000e+03, 9.99990112e+02, + 9.99960510e+02, 9.99911194e+02, 9.99842102e+02, + 9.99753296e+02, 9.99644714e+02, 9.99516479e+02, + 9.99368469e+02, 9.99200745e+02, 9.99013367e+02, + 9.98806274e+02, 9.98579468e+02, 9.98332947e+02, + 9.98066833e+02, 9.97781006e+02, 9.97475525e+02, + 9.97150391e+02, 9.96805664e+02, 9.96441284e+02, + 9.96057373e+02, 9.95653809e+02, 9.95230713e+02, + 9.94788086e+02, 9.94325867e+02, 9.93844177e+02, + 9.93342957e+02, 9.92822327e+02, 9.92282166e+02, + 9.91722595e+02, 9.91143616e+02, 9.90545288e+02, + 9.89927551e+02, 9.89290466e+02, 9.88634033e+02, + 9.87958374e+02, 9.87263428e+02, 9.86549255e+02, + 9.85815857e+02, 9.85063293e+02, 9.84291565e+02, + 9.83500732e+02, 9.82690796e+02, 9.81861816e+02, + 9.81013855e+02, 9.80146851e+02, 9.79260864e+02, + 9.78356018e+02, 9.77432251e+02, 9.76489685e+02, + 9.75528259e+02, 9.74548096e+02, 9.73549133e+02, + 9.72531555e+02, 9.71495239e+02, 9.70440369e+02, + 9.69366943e+02, 9.68274963e+02, 9.67164490e+02, + 9.66035583e+02, 9.64888245e+02, 9.63722595e+02, + 9.62538574e+02, 9.61336365e+02, 9.60115906e+02, + 9.58877319e+02, 9.57620605e+02, 9.56345764e+02, + 9.55052979e+02, 9.53742188e+02, 9.52413513e+02, + 9.51066956e+02, 9.49702637e+02, 9.48320496e+02, + 9.46920715e+02, 9.45503235e+02, 9.44068237e+02, + 9.42615662e+02, 9.41145630e+02, 9.39658142e+02, + 9.38153320e+02, 9.36631226e+02, 9.35091858e+02, + 9.33535339e+02, 9.31961731e+02, 9.30371033e+02, + 9.28763306e+02, 9.27138733e+02, 9.25497253e+02, + 9.23838989e+02, 9.22163940e+02, 9.20472290e+02, + 9.18764038e+02, 9.17039246e+02, 9.15297974e+02, + 9.13540283e+02, 9.11766296e+02, 9.09976074e+02, + 9.08169617e+02, 9.06347107e+02, 9.04508484e+02, + 9.02653931e+02, 9.00783508e+02, 8.98897217e+02, + 8.96995178e+02, 8.95077515e+02, 8.93144226e+02, + 8.91195435e+02, 8.89231140e+02, 8.87251526e+02, + 8.85256592e+02, 8.83246521e+02, 8.81221252e+02, + 8.79180969e+02, 8.77125671e+02, 8.75055542e+02, + 8.72970581e+02, 8.70870911e+02, 8.68756531e+02, + 8.66627686e+02, 8.64484314e+02, 8.62326538e+02, + 8.60154541e+02, 8.57968262e+02, 8.55767822e+02, + 8.53553406e+02, 8.51325012e+02, 8.49082703e+02, + 8.46826660e+02, 8.44556885e+02, 8.42273560e+02, + 8.39976685e+02, 8.37666382e+02, 8.35342773e+02, + 8.33005920e+02, 8.30655945e+02, 8.28292908e+02, + 8.25916870e+02, 8.23527954e+02, 8.21126343e+02, + 8.18711975e+02, 8.16285095e+02, 8.13845703e+02, + 8.11393860e+02, 8.08929810e+02, 8.06453552e+02, + 8.03965149e+02, 8.01464783e+02, 7.98952515e+02, + 7.96428406e+02, 7.93892639e+02, 7.91345215e+02, + 7.88786377e+02, 7.86216064e+02, 7.83634460e+02, + 7.81041687e+02, 7.78437805e+02, 7.75822937e+02, + 7.73197144e+02, 7.70560608e+02, 7.67913391e+02, + 7.65255615e+02, 7.62587341e+02, 7.59908691e+02, + 7.57219788e+02, 7.54520691e+02, 7.51811584e+02, + 7.49092529e+02, 7.46363647e+02, 7.43625061e+02, + 7.40876831e+02, 7.38119080e+02, 7.35351990e+02, + 7.32575562e+02, 7.29789917e+02, 7.26995239e+02, + 7.24191589e+02, 7.21379089e+02, 7.18557861e+02, + 7.15728027e+02, 7.12889648e+02, 7.10042847e+02, + 7.07187805e+02, 7.04324524e+02, 7.01453247e+02, + 6.98573975e+02, 6.95686829e+02, 6.92791992e+02, + 6.89889526e+02, 6.86979614e+02, 6.84062256e+02, + 6.81137695e+02, 6.78205933e+02, 6.75267151e+02, + 6.72321472e+02, 6.69368958e+02, 6.66409790e+02, + 6.63444031e+02, 6.60471802e+02, 6.57493286e+02, + 6.54508484e+02, 6.51517639e+02, 6.48520813e+02, + 6.45518066e+02, 6.42509644e+02, 6.39495544e+02, + 6.36475952e+02, 6.33450989e+02, 6.30420776e+02, + 6.27385376e+02, 6.24344971e+02, 6.21299622e+02, + 6.18249512e+02, 6.15194702e+02, 6.12135376e+02, + 6.09071594e+02, 6.06003540e+02, 6.02931274e+02, + 5.99854980e+02, 5.96774719e+02, 5.93690674e+02, + 5.90602905e+02, 5.87511536e+02, 5.84416748e+02, + 5.81318604e+02, 5.78217224e+02, 5.75112793e+02, + 5.72005371e+02, 5.68895142e+02, 5.65782166e+02, + 5.62666626e+02, 5.59548584e+02, 5.56428223e+02, + 5.53305603e+02, 5.50180847e+02, 5.47054138e+02, + 5.43925598e+02, 5.40795288e+02, 5.37663391e+02, + 5.34530029e+02, 5.31395264e+02, 5.28259277e+02, + 5.25122131e+02, 5.21984070e+02, 5.18845093e+02, + 5.15705383e+02, 5.12565063e+02, 5.09424225e+02, + 5.06283020e+02, 5.03141571e+02, 5.00000000e+02, + 4.96858429e+02, 4.93716980e+02, 4.90575775e+02, + 4.87434967e+02, 4.84294617e+02, 4.81154907e+02, + 4.78015930e+02, 4.74877838e+02, 4.71740723e+02, + 4.68604736e+02, 4.65470001e+02, 4.62336609e+02, + 4.59204681e+02, 4.56074402e+02, 4.52945831e+02, + 4.49819153e+02, 4.46694427e+02, 4.43571808e+02, + 4.40451416e+02, 4.37333374e+02, 4.34217834e+02, + 4.31104858e+02, 4.27994598e+02, 4.24887207e+02, + 4.21782776e+02, 4.18681427e+02, 4.15583282e+02, + 4.12488464e+02, 4.09397125e+02, 4.06309357e+02, + 4.03225281e+02, 4.00145020e+02, 3.97068695e+02, + 3.93996460e+02, 3.90928375e+02, 3.87864624e+02, + 3.84805298e+02, 3.81750488e+02, 3.78700378e+02, + 3.75655060e+02, 3.72614624e+02, 3.69579254e+02, + 3.66549011e+02, 3.63524017e+02, 3.60504456e+02, + 3.57490356e+02, 3.54481903e+02, 3.51479218e+02, + 3.48482361e+02, 3.45491516e+02, 3.42506744e+02, + 3.39528198e+02, 3.36556000e+02, 3.33590240e+02, + 3.30631042e+02, 3.27678528e+02, 3.24732849e+02, + 3.21794067e+02, 3.18862305e+02, 3.15937714e+02, + 3.13020386e+02, 3.10110443e+02, 3.07208008e+02, + 3.04313171e+02, 3.01426056e+02, 2.98546783e+02, + 2.95675476e+02, 2.92812195e+02, 2.89957123e+02, + 2.87110352e+02, 2.84271973e+02, 2.81442108e+02, + 2.78620880e+02, 2.75808380e+02, 2.73004761e+02, + 2.70210083e+02, 2.67424469e+02, 2.64648041e+02, + 2.61880890e+02, 2.59123169e+02, 2.56374939e+02, + 2.53636322e+02, 2.50907440e+02, 2.48188400e+02, + 2.45479294e+02, 2.42780228e+02, 2.40091324e+02, + 2.37412689e+02, 2.34744415e+02, 2.32086609e+02, + 2.29439377e+02, 2.26802826e+02, 2.24177063e+02, + 2.21562195e+02, 2.18958313e+02, 2.16365524e+02, + 2.13783936e+02, 2.11213654e+02, 2.08654755e+02, + 2.06107376e+02, 2.03571594e+02, 2.01047516e+02, + 1.98535233e+02, 1.96034851e+02, 1.93546478e+02, + 1.91070190e+02, 1.88606110e+02, 1.86154312e+02, + 1.83714920e+02, 1.81288010e+02, 1.78873672e+02, + 1.76472015e+02, 1.74083130e+02, 1.71707123e+02, + 1.69344070e+02, 1.66994064e+02, 1.64657211e+02, + 1.62333603e+02, 1.60023315e+02, 1.57726440e+02, + 1.55443100e+02, 1.53173340e+02, 1.50917297e+02, + 1.48675018e+02, 1.46446609e+02, 1.44232162e+02, + 1.42031754e+02, 1.39845490e+02, 1.37673431e+02, + 1.35515686e+02, 1.33372330e+02, 1.31243439e+02, + 1.29129120e+02, 1.27029427e+02, 1.24944466e+02, + 1.22874313e+02, 1.20819046e+02, 1.18778748e+02, + 1.16753494e+02, 1.14743378e+02, 1.12748466e+02, + 1.10768852e+02, 1.08804596e+02, 1.06855782e+02, + 1.04922493e+02, 1.03004799e+02, 1.01102783e+02, + 9.92165070e+01, 9.73460541e+01, 9.54915009e+01, + 9.36529160e+01, 9.18303757e+01, 9.00239487e+01, + 8.82337036e+01, 8.64597092e+01, 8.47020493e+01, + 8.29607849e+01, 8.12359772e+01, 7.95277100e+01, + 7.78360367e+01, 7.61610336e+01, 7.45027618e+01, + 7.28612823e+01, 7.12366714e+01, 6.96289902e+01, + 6.80382919e+01, 6.64646530e+01, 6.49081192e+01, + 6.33687744e+01, 6.18466606e+01, 6.03418465e+01, + 5.88543854e+01, 5.73843460e+01, 5.59317741e+01, + 5.44967384e+01, 5.30792885e+01, 5.16794815e+01, + 5.02973747e+01, 4.89330215e+01, 4.75864754e+01, + 4.62577858e+01, 4.49470139e+01, 4.36542053e+01, + 4.23794136e+01, 4.11226883e+01, 3.98840752e+01, + 3.86636314e+01, 3.74613953e+01, 3.62774239e+01, + 3.51117554e+01, 3.39644432e+01, 3.28355293e+01, + 3.17250557e+01, 3.06330719e+01, 2.95596161e+01, + 2.85047321e+01, 2.74684620e+01, 2.64508476e+01, + 2.54519272e+01, 2.44717426e+01, 2.35103283e+01, + 2.25677280e+01, 2.16439743e+01, 2.07391052e+01, + 1.98531570e+01, 1.89861641e+01, 1.81381607e+01, + 1.73091812e+01, 1.64992561e+01, 1.57084198e+01, + 1.49367018e+01, 1.41841335e+01, 1.34507446e+01, + 1.27365637e+01, 1.20416193e+01, 1.13659382e+01, + 1.07095480e+01, 1.00724735e+01, 9.45474148e+00, + 8.85637474e+00, 8.27739716e+00, 7.71783257e+00, + 7.17770243e+00, 6.65702772e+00, 6.15582991e+00, + 5.67412758e+00, 5.21194077e+00, 4.76928711e+00, + 4.34618425e+00, 3.94264936e+00, 3.55869770e+00, + 3.19434476e+00, 2.84960485e+00, 2.52449155e+00, + 2.21901774e+00, 1.93319547e+00, 1.66703594e+00, + 1.42054987e+00, 1.19374681e+00, 9.86635804e-01, + 7.99224913e-01, 6.31521702e-01, 4.83532667e-01, + 3.55263680e-01, 2.46719822e-01, 1.57905355e-01, + 8.88238102e-02, 3.94778959e-02, 9.86957178e-03, + 0.00000000e+00, 9.86957271e-03, 3.94778997e-02, + 8.88238102e-02, 1.57905355e-01, 2.46719822e-01, + 3.55263680e-01, 4.83532667e-01, 6.31521702e-01, + 7.99224973e-01, 9.86635804e-01, 1.19374681e+00, + 1.42054987e+00, 1.66703594e+00, 1.93319547e+00, + 2.21901774e+00, 2.52449155e+00, 2.84960485e+00, + 3.19434476e+00, 3.55869770e+00, 3.94264936e+00, + 4.34618425e+00, 4.76928711e+00, 5.21194077e+00, + 5.67412758e+00, 6.15582991e+00, 6.65702772e+00, + 7.17770243e+00, 7.71783257e+00, 8.27739716e+00, + 8.85637474e+00, 9.45474148e+00, 1.00724735e+01, + 1.07095480e+01, 1.13659382e+01, 1.20416193e+01, + 1.27365637e+01, 1.34507446e+01, 1.41841335e+01, + 1.49367018e+01, 1.57084198e+01, 1.64992561e+01, + 1.73091812e+01, 1.81381607e+01, 1.89861641e+01, + 1.98531570e+01, 2.07391052e+01, 2.16439743e+01, + 2.25677280e+01, 2.35103302e+01, 2.44717426e+01, + 2.54519272e+01, 2.64508476e+01, 2.74684620e+01, + 2.85047321e+01, 2.95596161e+01, 3.06330719e+01, + 3.17250576e+01, 3.28355293e+01, 3.39644432e+01, + 3.51117554e+01, 3.62774239e+01, 3.74613953e+01, + 3.86636314e+01, 3.98840752e+01, 4.11226883e+01, + 4.23794136e+01, 4.36542053e+01, 4.49470139e+01, + 4.62577896e+01, 4.75864754e+01, 4.89330215e+01, + 5.02973747e+01, 5.16794815e+01, 5.30792885e+01, + 5.44967384e+01, 5.59317741e+01, 5.73843460e+01, + 5.88543854e+01, 6.03418465e+01, 6.18466606e+01, + 6.33687744e+01, 6.49081192e+01, 6.64646530e+01, + 6.80382919e+01, 6.96289902e+01, 7.12366714e+01, + 7.28612823e+01, 7.45027618e+01, 7.61610336e+01, + 7.78360367e+01, 7.95277100e+01, 8.12359772e+01, + 8.29607849e+01, 8.47020493e+01, 8.64597092e+01, + 8.82337036e+01, 9.00239487e+01, 9.18303757e+01, + 9.36529160e+01, 9.54915009e+01, 9.73460541e+01, + 9.92165070e+01, 1.01102783e+02, 1.03004799e+02, + 1.04922493e+02, 1.06855782e+02, 1.08804596e+02, + 1.10768852e+02, 1.12748466e+02, 1.14743378e+02, + 1.16753494e+02, 1.18778748e+02, 1.20819046e+02, + 1.22874313e+02, 1.24944466e+02, 1.27029427e+02, + 1.29129120e+02, 1.31243439e+02, 1.33372330e+02, + 1.35515686e+02, 1.37673431e+02, 1.39845490e+02, + 1.42031754e+02, 1.44232162e+02, 1.46446609e+02, + 1.48675018e+02, 1.50917297e+02, 1.53173340e+02, + 1.55443100e+02, 1.57726440e+02, 1.60023315e+02, + 1.62333603e+02, 1.64657211e+02, 1.66994064e+02, + 1.69344070e+02, 1.71707123e+02, 1.74083130e+02, + 1.76472015e+02, 1.78873672e+02, 1.81288010e+02, + 1.83714920e+02, 1.86154312e+02, 1.88606110e+02, + 1.91070190e+02, 1.93546478e+02, 1.96034851e+02, + 1.98535233e+02, 2.01047516e+02, 2.03571594e+02, + 2.06107376e+02, 2.08654755e+02, 2.11213654e+02, + 2.13783936e+02, 2.16365524e+02, 2.18958313e+02, + 2.21562195e+02, 2.24177063e+02, 2.26802826e+02, + 2.29439377e+02, 2.32086609e+02, 2.34744415e+02, + 2.37412689e+02, 2.40091324e+02, 2.42780228e+02, + 2.45479294e+02, 2.48188400e+02, 2.50907440e+02, + 2.53636322e+02, 2.56374939e+02, 2.59123169e+02, + 2.61880890e+02, 2.64648041e+02, 2.67424469e+02, + 2.70210083e+02, 2.73004761e+02, 2.75808380e+02, + 2.78620880e+02, 2.81442108e+02, 2.84271973e+02, + 2.87110352e+02, 2.89957123e+02, 2.92812195e+02, + 2.95675476e+02, 2.98546783e+02, 3.01426056e+02, + 3.04313171e+02, 3.07208008e+02, 3.10110443e+02, + 3.13020386e+02, 3.15937714e+02, 3.18862305e+02, + 3.21794067e+02, 3.24732849e+02, 3.27678528e+02, + 3.30631042e+02, 3.33590240e+02, 3.36556000e+02, + 3.39528198e+02, 3.42506744e+02, 3.45491516e+02, + 3.48482361e+02, 3.51479218e+02, 3.54481903e+02, + 3.57490356e+02, 3.60504456e+02, 3.63524017e+02, + 3.66549011e+02, 3.69579254e+02, 3.72614624e+02, + 3.75655060e+02, 3.78700378e+02, 3.81750488e+02, + 3.84805298e+02, 3.87864624e+02, 3.90928375e+02, + 3.93996460e+02, 3.97068695e+02, 4.00145020e+02, + 4.03225281e+02, 4.06309357e+02, 4.09397125e+02, + 4.12488464e+02, 4.15583282e+02, 4.18681427e+02, + 4.21782776e+02, 4.24887207e+02, 4.27994598e+02, + 4.31104858e+02, 4.34217834e+02, 4.37333374e+02, + 4.40451416e+02, 4.43571808e+02, 4.46694427e+02, + 4.49819153e+02, 4.52945831e+02, 4.56074402e+02, + 4.59204681e+02, 4.62336609e+02, 4.65470001e+02, + 4.68604736e+02, 4.71740723e+02, 4.74877838e+02, + 4.78015930e+02, 4.81154907e+02, 4.84294617e+02, + 4.87434967e+02, 4.90575775e+02, 4.93716980e+02, + 4.96858429e+02, 5.00000000e+02, 5.03141571e+02, + 5.06283020e+02, 5.09424225e+02], dtype=np.float32), +'ASAM.M.SCALAR.UWORD.IDENTICAL': np.array([ 32, 33, 35, 36, 37, 38, 39, 41, 42, 43, 44, + 46, 47, 48, 50, 51, 53, 54, 55, 57, 58, 60, + 61, 63, 64, 66, 68, 69, 71, 72, 74, 76, 77, + 79, 81, 82, 84, 86, 88, 90, 91, 93, 95, 97, + 99, 101, 103, 104, 106, 108, 110, 112, 114, 116, 118, + 120, 122, 124, 127, 129, 131, 133, 135, 137, 139, 142, + 144, 146, 148, 150, 153, 155, 157, 160, 162, 164, 166, + 169, 171, 174, 176, 178, 181, 183, 186, 188, 191, 193, + 196, 198, 201, 203, 206, 208, 211, 213, 216, 218, 221, + 224, 226, 229, 232, 234, 237, 240, 242, 245, 248, 250, + 253, 256, 259, 261, 264, 267, 270, 273, 275, 278, 281, + 284, 287, 289, 292, 295, 298, 301, 304, 307, 310, 313, + 315, 318, 321, 324, 327, 330, 333, 336, 339, 342, 345, + 348, 351, 354, 357, 360, 363, 366, 369, 372, 375, 378, + 381, 384, 387, 390, 393, 397, 400, 403, 406, 409, 412, + 415, 418, 421, 424, 427, 431, 434, 437, 440, 443, 446, + 449, 452, 456, 459, 462, 465, 468, 471, 474, 478, 481, + 484, 487, 490, 493, 496, 500, 503, 506, 509, 512, 515, + 518, 521, 525, 528, 531, 534, 537, 540, 543, 547, 550, + 553, 556, 559, 562, 565, 568, 572, 575, 578, 581, 584, + 587, 590, 593, 596, 599, 602, 606, 609, 612, 615, 618, + 621, 624, 627, 630, 633, 636, 639, 642, 645, 648, 651, + 654, 657, 660, 663, 666, 669, 672, 675, 678, 681, 684, + 686, 689, 692, 695, 698, 701, 704, 707, 710, 712, 715, + 718, 721, 724, 726, 729, 732, 735, 738, 740, 743, 746, + 749, 751, 754, 757, 759, 762, 765, 767, 770, 773, 775, + 778, 781, 783, 786, 788, 791, 793, 796, 798, 801, 803, + 806, 808, 811, 813, 816, 818, 821, 823, 825, 828, 830, + 833, 835, 837, 839, 842, 844, 846, 849, 851, 853, 855, + 857, 860, 862, 864, 866, 868, 870, 872, 875, 877, 879, + 881, 883, 885, 887, 889, 891, 893, 895, 896, 898, 900, + 902, 904, 906, 908, 909, 911, 913, 915, 917, 918, 920, + 922, 923, 925, 927, 928, 930, 931, 933, 935, 936, 938, + 939, 941, 942, 944, 945, 946, 948, 949, 951, 952, 953, + 955, 956, 957, 958, 960, 961, 962, 963, 964, 966, 967, + 968, 969, 970, 971, 972, 973, 974, 975, 976, 977, 978, + 979, 980, 981, 981, 982, 983, 984, 985, 985, 986, 987, + 987, 988, 989, 989, 990, 991, 991, 992, 992, 993, 993, + 994, 994, 995, 995, 996, 996, 996, 997, 997, 997, 998, + 998, 998, 998, 999, 999, 999, 999, 999, 999, 999, 999, + 999, 999, 1000, 999, 999, 999, 999, 999, 999, 999, 999, + 999, 999, 998, 998, 998, 998, 997, 997, 997, 996, 996, + 996, 995, 995, 994, 994, 993, 993, 992, 992, 991, 991, + 990, 989, 989, 988, 987, 987, 986, 985, 985, 984, 983, + 982, 981, 981, 980, 979, 978, 977, 976, 975, 974, 973, + 972, 971, 970, 969, 968, 967, 966, 964, 963, 962, 961, + 960, 958, 957, 956, 955, 953, 952, 951, 949, 948, 946, + 945, 944, 942, 941, 939, 938, 936, 935, 933, 931, 930, + 928, 927, 925, 923, 922, 920, 918, 917, 915, 913, 911, + 909, 908, 906, 904, 902, 900, 898, 896, 895, 893, 891, + 889, 887, 885, 883, 881, 879, 877, 875, 872, 870, 868, + 866, 864, 862, 860, 857, 855, 853, 851, 849, 846, 844, + 842, 839, 837, 835, 833, 830, 828, 825, 823, 821, 818, + 816, 813, 811, 808, 806, 803, 801, 798, 796, 793, 791, + 788, 786, 783, 781, 778, 775, 773, 770, 767, 765, 762, + 759, 757, 754, 751, 749, 746, 743, 740, 738, 735, 732, + 729, 726, 724, 721, 718, 715, 712, 710, 707, 704, 701, + 698, 695, 692, 689, 686, 684, 681, 678, 675, 672, 669, + 666, 663, 660, 657, 654, 651, 648, 645, 642, 639, 636, + 633, 630, 627, 624, 621, 618, 615, 612, 609, 606, 602, + 599, 596, 593, 590, 587, 584, 581, 578, 575, 572, 568, + 565, 562, 559, 556, 553, 550, 547, 543, 540, 537, 534, + 531, 528, 525, 521, 518, 515, 512, 509, 506, 503, 499, + 496, 493, 490, 487, 484, 481, 478, 474, 471, 468, 465, + 462, 459, 456, 452, 449, 446, 443, 440, 437, 434, 431, + 427, 424, 421, 418, 415, 412, 409, 406, 403, 400, 397, + 393, 390, 387, 384, 381, 378, 375, 372, 369, 366, 363, + 360, 357, 354, 351, 348, 345, 342, 339, 336, 333, 330, + 327, 324, 321, 318, 315, 313, 310, 307, 304, 301, 298, + 295, 292, 289, 287, 284, 281, 278, 275, 273, 270, 267, + 264, 261, 259, 256, 253, 250, 248, 245, 242, 240, 237, + 234, 232, 229, 226, 224, 221, 218, 216, 213, 211, 208, + 206, 203, 201, 198, 196, 193, 191, 188, 186, 183, 181, + 178, 176, 174, 171, 169, 166, 164, 162, 160, 157, 155, + 153, 150, 148, 146, 144, 142, 139, 137, 135, 133, 131, + 129, 127, 124, 122, 120, 118, 116, 114, 112, 110, 108, + 106, 104, 103, 101, 99, 97, 95, 93, 91, 90, 88, + 86, 84, 82, 81, 79, 77, 76, 74, 72, 71, 69, + 68, 66, 64, 63, 61, 60, 58, 57, 55, 54, 53, + 51, 50, 48, 47, 46, 44, 43, 42, 41, 39, 38, + 37, 36, 35, 33, 32, 31, 30, 29, 28, 27, 26, + 25, 24, 23, 22, 21], dtype=np.uint16), +'ASAM.M.SCALAR.UBYTE.TAB_VERB_NO_DEFAULT_VALUE': np.array([ 17, 16, 15, 14, 14, 13, 12, 12, 11, 10, 10, 9, 8, + 8, 7, 7, 6, 6, 5, 5, 4, 4, 3, 3, 3, 2, + 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, + 5, 5, 6, 6, 7, 7, 8, 8, 9, 10, 10, 11, 12, + 12, 13, 14, 14, 15, 16, 17, 18, 18, 19, 20, 21, 22, + 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 35, 36, + 37, 38, 39, 41, 42, 43, 44, 46, 47, 48, 50, 51, 53, + 54, 55, 57, 58, 60, 61, 63, 64, 66, 68, 69, 71, 72, + 74, 76, 77, 79, 81, 82, 84, 86, 88, 90, 91, 93, 95, + 97, 99, 101, 103, 104, 106, 108, 110, 112, 114, 116, 118, 120, + 122, 124, 127, 129, 131, 133, 135, 137, 139, 142, 144, 146, 148, + 150, 153, 155, 157, 160, 162, 164, 166, 169, 171, 174, 176, 178, + 181, 183, 186, 188, 191, 193, 196, 198, 201, 203, 206, 208, 211, + 213, 216, 218, 221, 224, 226, 229, 232, 234, 237, 240, 242, 245, + 248, 250, 253, 0, 3, 5, 8, 11, 14, 17, 19, 22, 25, + 28, 31, 33, 36, 39, 42, 45, 48, 51, 54, 57, 59, 62, + 65, 68, 71, 74, 77, 80, 83, 86, 89, 92, 95, 98, 101, + 104, 107, 110, 113, 116, 119, 122, 125, 128, 131, 134, 137, 141, + 144, 147, 150, 153, 156, 159, 162, 165, 168, 171, 175, 178, 181, + 184, 187, 190, 193, 196, 200, 203, 206, 209, 212, 215, 218, 222, + 225, 228, 231, 234, 237, 240, 244, 247, 250, 253, 0, 3, 6, + 9, 13, 16, 19, 22, 25, 28, 31, 35, 38, 41, 44, 47, + 50, 53, 56, 60, 63, 66, 69, 72, 75, 78, 81, 84, 87, + 90, 94, 97, 100, 103, 106, 109, 112, 115, 118, 121, 124, 127, + 130, 133, 136, 139, 142, 145, 148, 151, 154, 157, 160, 163, 166, + 169, 172, 174, 177, 180, 183, 186, 189, 192, 195, 198, 200, 203, + 206, 209, 212, 214, 217, 220, 223, 226, 228, 231, 234, 237, 239, + 242, 245, 247, 250, 253, 255, 2, 5, 7, 10, 13, 15, 18, + 20, 23, 25, 28, 30, 33, 35, 38, 40, 43, 45, 48, 50, + 53, 55, 57, 60, 62, 65, 67, 69, 71, 74, 76, 78, 81, + 83, 85, 87, 89, 92, 94, 96, 98, 100, 102, 104, 107, 109, + 111, 113, 115, 117, 119, 121, 123, 125, 127, 128, 130, 132, 134, + 136, 138, 140, 141, 143, 145, 147, 149, 150, 152, 154, 155, 157, + 159, 160, 162, 163, 165, 167, 168, 170, 171, 173, 174, 176, 177, + 178, 180, 181, 183, 184, 185, 187, 188, 189, 190, 192, 193, 194, + 195, 196, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, + 209, 210, 211, 212, 213, 213, 214, 215, 216, 217, 217, 218, 219, + 219, 220, 221, 221, 222, 223, 223, 224, 224, 225, 225, 226, 226, + 227, 227, 228, 228, 228, 229, 229, 229, 230, 230, 230, 230, 231, + 231, 231, 231, 231, 231, 231, 231, 231, 231, 232, 231, 231, 231, + 231, 231, 231, 231, 231, 231, 231, 230, 230, 230, 230, 229, 229, + 229, 228, 228, 228, 227, 227, 226, 226, 225, 225, 224, 224, 223, + 223, 222, 221, 221, 220, 219, 219, 218, 217, 217, 216, 215, 214, + 213, 213, 212, 211, 210, 209, 208, 207, 206, 205, 204, 203, 202, + 201, 200, 199, 198, 196, 195, 194, 193, 192, 190, 189, 188, 187, + 185, 184, 183, 181, 180, 178, 177, 176, 174, 173, 171, 170, 168, + 167, 165, 163, 162, 160, 159, 157, 155, 154, 152, 150, 149, 147, + 145, 143, 141, 140, 138, 136, 134, 132, 130, 128, 127, 125, 123, + 121, 119, 117, 115, 113, 111, 109, 107, 104, 102, 100, 98, 96, + 94, 92, 89, 87, 85, 83, 81, 78, 76, 74, 71, 69, 67, + 65, 62, 60, 57, 55, 53, 50, 48, 45, 43, 40, 38, 35, + 33, 30, 28, 25, 23, 20, 18, 15, 13, 10, 7, 5, 2, + 255, 253, 250, 247, 245, 242, 239, 237, 234, 231, 228, 226, 223, + 220, 217, 214, 212, 209, 206, 203, 200, 198, 195, 192, 189, 186, + 183, 180, 177, 174, 172, 169, 166, 163, 160, 157, 154, 151, 148, + 145, 142, 139, 136, 133, 130, 127, 124, 121, 118, 115, 112, 109, + 106, 103, 100, 97, 94, 90, 87, 84, 81, 78, 75, 72, 69, + 66, 63, 60, 56, 53, 50, 47, 44, 41, 38, 35, 31, 28, + 25, 22, 19, 16, 13, 9, 6, 3, 0, 253, 250, 247, 243, + 240, 237, 234, 231, 228, 225, 222, 218, 215, 212, 209, 206, 203, + 200, 196, 193, 190, 187, 184, 181, 178, 175, 171, 168, 165, 162, + 159, 156, 153, 150, 147, 144, 141, 137, 134, 131, 128, 125, 122, + 119, 116, 113, 110, 107, 104, 101, 98, 95, 92, 89, 86, 83, + 80, 77, 74, 71, 68, 65, 62, 59, 57, 54, 51, 48, 45, + 42, 39, 36, 33, 31, 28, 25, 22, 19, 17, 14, 11, 8, + 5, 3, 0, 253, 250, 248, 245, 242, 240, 237, 234, 232, 229, + 226, 224, 221, 218, 216, 213, 211, 208, 206, 203, 201, 198], dtype=np.uint8), +'ASAM.M.SCALAR.UBYTE.TAB_NOINTP_NO_DEFAULT_VALUE': np.array([ 105. , 102. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 109. , 106. , 103. , + 100. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 110.33333588, 108. , 105. , + 103. , 100. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 110.66666412, 110.66666412, + 110.33333588, 110. , 110. , 109. , + 108. , 108. , 107. , 107. , + 106. , 106. , 105. , 105. , + 104. , 104. , 103. , 103. , + 103. , 102. , 102. , 102. , + 101. , 101. , 101. , 101. , + 100. , 100. , 100. , 100. , + 100. , 100. , 100. , 100. , + 100. , 100. , 100. , 100. , + 100. , 100. , 100. , 100. , + 100. , 100. , 100. , 100. , + 100. , 101. , 101. , 101. , + 101. , 102. , 102. , 102. , + 103. , 103. , 103. , 104. , + 104. , 105. , 105. , 106. , + 106. , 107. , 107. , 108. , + 108. , 109. , 110. , 110. , + 110.33333588, 110.66666412, 110.66666412, 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 100. , + 103. , 105. , 108. , 110.33333588, + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 100. , 103. , 106. , 109. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 102. , + 105. , 107. , 110. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. , + 111. , 111. , 111. , 111. ], dtype=np.float32), +'ASAM.M.SCALAR.UBYTE.TAB_VERB_DEFAULT_VALUE': np.array([218, 215, 212, 209, 206, 203, 200, 196, 193, 190, 187, 184, 181, + 178, 175, 171, 168, 165, 162, 159, 156, 153, 150, 147, 144, 141, + 137, 134, 131, 128, 125, 122, 119, 116, 113, 110, 107, 104, 101, + 98, 95, 92, 89, 86, 83, 80, 77, 74, 71, 68, 65, 62, + 59, 57, 54, 51, 48, 45, 42, 39, 36, 33, 31, 28, 25, + 22, 19, 17, 14, 11, 8, 5, 3, 0, 253, 250, 248, 245, + 242, 240, 237, 234, 232, 229, 226, 224, 221, 218, 216, 213, 211, + 208, 206, 203, 201, 198, 196, 193, 191, 188, 186, 183, 181, 178, + 176, 174, 171, 169, 166, 164, 162, 160, 157, 155, 153, 150, 148, + 146, 144, 142, 139, 137, 135, 133, 131, 129, 127, 124, 122, 120, + 118, 116, 114, 112, 110, 108, 106, 104, 103, 101, 99, 97, 95, + 93, 91, 90, 88, 86, 84, 82, 81, 79, 77, 76, 74, 72, + 71, 69, 68, 66, 64, 63, 61, 60, 58, 57, 55, 54, 53, + 51, 50, 48, 47, 46, 44, 43, 42, 41, 39, 38, 37, 36, + 35, 33, 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, + 21, 20, 19, 18, 18, 17, 16, 15, 14, 14, 13, 12, 12, + 11, 10, 10, 9, 8, 8, 7, 7, 6, 6, 5, 5, 4, + 4, 3, 3, 3, 2, 2, 2, 1, 1, 1, 1, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, + 3, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, + 9, 10, 10, 11, 12, 12, 13, 14, 14, 15, 16, 17, 18, + 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, + 31, 32, 33, 35, 36, 37, 38, 39, 41, 42, 43, 44, 46, + 47, 48, 50, 51, 53, 54, 55, 57, 58, 60, 61, 63, 64, + 66, 68, 69, 71, 72, 74, 76, 77, 79, 81, 82, 84, 86, + 88, 90, 91, 93, 95, 97, 99, 101, 103, 104, 106, 108, 110, + 112, 114, 116, 118, 120, 122, 124, 127, 129, 131, 133, 135, 137, + 139, 142, 144, 146, 148, 150, 153, 155, 157, 160, 162, 164, 166, + 169, 171, 174, 176, 178, 181, 183, 186, 188, 191, 193, 196, 198, + 201, 203, 206, 208, 211, 213, 216, 218, 221, 224, 226, 229, 232, + 234, 237, 240, 242, 245, 248, 250, 253, 0, 3, 5, 8, 11, + 14, 17, 19, 22, 25, 28, 31, 33, 36, 39, 42, 45, 48, + 51, 54, 57, 59, 62, 65, 68, 71, 74, 77, 80, 83, 86, + 89, 92, 95, 98, 101, 104, 107, 110, 113, 116, 119, 122, 125, + 128, 131, 134, 137, 141, 144, 147, 150, 153, 156, 159, 162, 165, + 168, 171, 175, 178, 181, 184, 187, 190, 193, 196, 200, 203, 206, + 209, 212, 215, 218, 222, 225, 228, 231, 234, 237, 240, 244, 247, + 250, 253, 0, 3, 6, 9, 13, 16, 19, 22, 25, 28, 31, + 35, 38, 41, 44, 47, 50, 53, 56, 60, 63, 66, 69, 72, + 75, 78, 81, 84, 87, 90, 94, 97, 100, 103, 106, 109, 112, + 115, 118, 121, 124, 127, 130, 133, 136, 139, 142, 145, 148, 151, + 154, 157, 160, 163, 166, 169, 172, 174, 177, 180, 183, 186, 189, + 192, 195, 198, 200, 203, 206, 209, 212, 214, 217, 220, 223, 226, + 228, 231, 234, 237, 239, 242, 245, 247, 250, 253, 255, 2, 5, + 7, 10, 13, 15, 18, 20, 23, 25, 28, 30, 33, 35, 38, + 40, 43, 45, 48, 50, 53, 55, 57, 60, 62, 65, 67, 69, + 71, 74, 76, 78, 81, 83, 85, 87, 89, 92, 94, 96, 98, + 100, 102, 104, 107, 109, 111, 113, 115, 117, 119, 121, 123, 125, + 127, 128, 130, 132, 134, 136, 138, 140, 141, 143, 145, 147, 149, + 150, 152, 154, 155, 157, 159, 160, 162, 163, 165, 167, 168, 170, + 171, 173, 174, 176, 177, 178, 180, 181, 183, 184, 185, 187, 188, + 189, 190, 192, 193, 194, 195, 196, 198, 199, 200, 201, 202, 203, + 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 213, 214, 215, + 216, 217, 217, 218, 219, 219, 220, 221, 221, 222, 223, 223, 224, + 224, 225, 225, 226, 226, 227, 227, 228, 228, 228, 229, 229, 229, + 230, 230, 230, 230, 231, 231, 231, 231, 231, 231, 231, 231, 231, + 231, 232, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 230, + 230, 230, 230, 229, 229, 229, 228, 228, 228, 227, 227, 226, 226, + 225, 225, 224, 224, 223, 223, 222, 221, 221, 220, 219, 219, 218, + 217, 217, 216, 215, 214, 213, 213, 212, 211, 210, 209, 208, 207, + 206, 205, 204, 203, 202, 201, 200, 199, 198, 196, 195, 194, 193, + 192, 190, 189, 188, 187, 185, 184, 183, 181, 180, 178, 177, 176, + 174, 173, 171, 170, 168, 167, 165, 163, 162, 160, 159, 157, 155, + 154, 152, 150, 149, 147, 145, 143, 141, 140, 138, 136, 134, 132, + 130, 128, 127, 125, 123, 121, 119, 117, 115, 113, 111, 109, 107, + 104, 102, 100, 98, 96, 94, 92, 89, 87, 85, 83, 81, 78, + 76, 74, 71, 69, 67, 65, 62, 60, 57, 55, 53, 50, 48, + 45, 43, 40, 38, 35, 33, 30, 28, 25, 23, 20, 18], dtype=np.uint8), +'ASAM.M.SCALAR.ULONG.IDENTICAL': np.array([ 186, 183, 181, 178, 176, 174, 171, 169, 166, 164, 162, + 160, 157, 155, 153, 150, 148, 146, 144, 142, 139, 137, + 135, 133, 131, 129, 127, 124, 122, 120, 118, 116, 114, + 112, 110, 108, 106, 104, 103, 101, 99, 97, 95, 93, + 91, 90, 88, 86, 84, 82, 81, 79, 77, 76, 74, + 72, 71, 69, 68, 66, 64, 63, 61, 60, 58, 57, + 55, 54, 53, 51, 50, 48, 47, 46, 44, 43, 42, + 41, 39, 38, 37, 36, 35, 33, 32, 31, 30, 29, + 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, + 18, 17, 16, 15, 14, 14, 13, 12, 12, 11, 10, + 10, 9, 8, 8, 7, 7, 6, 6, 5, 5, 4, + 4, 3, 3, 3, 2, 2, 2, 1, 1, 1, 1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, + 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, + 5, 5, 6, 6, 7, 7, 8, 8, 9, 10, 10, + 11, 12, 12, 13, 14, 14, 15, 16, 17, 18, 18, + 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 30, 31, 32, 33, 35, 36, 37, 38, 39, 41, 42, + 43, 44, 46, 47, 48, 50, 51, 53, 54, 55, 57, + 58, 60, 61, 63, 64, 66, 68, 69, 71, 72, 74, + 76, 77, 79, 81, 82, 84, 86, 88, 90, 91, 93, + 95, 97, 99, 101, 103, 104, 106, 108, 110, 112, 114, + 116, 118, 120, 122, 124, 127, 129, 131, 133, 135, 137, + 139, 142, 144, 146, 148, 150, 153, 155, 157, 160, 162, + 164, 166, 169, 171, 174, 176, 178, 181, 183, 186, 188, + 191, 193, 196, 198, 201, 203, 206, 208, 211, 213, 216, + 218, 221, 224, 226, 229, 232, 234, 237, 240, 242, 245, + 248, 250, 253, 256, 259, 261, 264, 267, 270, 273, 275, + 278, 281, 284, 287, 289, 292, 295, 298, 301, 304, 307, + 310, 313, 315, 318, 321, 324, 327, 330, 333, 336, 339, + 342, 345, 348, 351, 354, 357, 360, 363, 366, 369, 372, + 375, 378, 381, 384, 387, 390, 393, 397, 400, 403, 406, + 409, 412, 415, 418, 421, 424, 427, 431, 434, 437, 440, + 443, 446, 449, 452, 456, 459, 462, 465, 468, 471, 474, + 478, 481, 484, 487, 490, 493, 496, 500, 503, 506, 509, + 512, 515, 518, 521, 525, 528, 531, 534, 537, 540, 543, + 547, 550, 553, 556, 559, 562, 565, 568, 572, 575, 578, + 581, 584, 587, 590, 593, 596, 599, 602, 606, 609, 612, + 615, 618, 621, 624, 627, 630, 633, 636, 639, 642, 645, + 648, 651, 654, 657, 660, 663, 666, 669, 672, 675, 678, + 681, 684, 686, 689, 692, 695, 698, 701, 704, 707, 710, + 712, 715, 718, 721, 724, 726, 729, 732, 735, 738, 740, + 743, 746, 749, 751, 754, 757, 759, 762, 765, 767, 770, + 773, 775, 778, 781, 783, 786, 788, 791, 793, 796, 798, + 801, 803, 806, 808, 811, 813, 816, 818, 821, 823, 825, + 828, 830, 833, 835, 837, 839, 842, 844, 846, 849, 851, + 853, 855, 857, 860, 862, 864, 866, 868, 870, 872, 875, + 877, 879, 881, 883, 885, 887, 889, 891, 893, 895, 896, + 898, 900, 902, 904, 906, 908, 909, 911, 913, 915, 917, + 918, 920, 922, 923, 925, 927, 928, 930, 931, 933, 935, + 936, 938, 939, 941, 942, 944, 945, 946, 948, 949, 951, + 952, 953, 955, 956, 957, 958, 960, 961, 962, 963, 964, + 966, 967, 968, 969, 970, 971, 972, 973, 974, 975, 976, + 977, 978, 979, 980, 981, 981, 982, 983, 984, 985, 985, + 986, 987, 987, 988, 989, 989, 990, 991, 991, 992, 992, + 993, 993, 994, 994, 995, 995, 996, 996, 996, 997, 997, + 997, 998, 998, 998, 998, 999, 999, 999, 999, 999, 999, + 999, 999, 999, 999, 1000, 999, 999, 999, 999, 999, 999, + 999, 999, 999, 999, 998, 998, 998, 998, 997, 997, 997, + 996, 996, 996, 995, 995, 994, 994, 993, 993, 992, 992, + 991, 991, 990, 989, 989, 988, 987, 987, 986, 985, 985, + 984, 983, 982, 981, 981, 980, 979, 978, 977, 976, 975, + 974, 973, 972, 971, 970, 969, 968, 967, 966, 964, 963, + 962, 961, 960, 958, 957, 956, 955, 953, 952, 951, 949, + 948, 946, 945, 944, 942, 941, 939, 938, 936, 935, 933, + 931, 930, 928, 927, 925, 923, 922, 920, 918, 917, 915, + 913, 911, 909, 908, 906, 904, 902, 900, 898, 896, 895, + 893, 891, 889, 887, 885, 883, 881, 879, 877, 875, 872, + 870, 868, 866, 864, 862, 860, 857, 855, 853, 851, 849, + 846, 844, 842, 839, 837, 835, 833, 830, 828, 825, 823, + 821, 818, 816, 813, 811, 808, 806, 803, 801, 798, 796, + 793, 791, 788, 786, 783, 781, 778, 775, 773, 770, 767, + 765, 762, 759, 757, 754, 751, 749, 746, 743, 740, 738, + 735, 732, 729, 726, 724, 721, 718, 715, 712, 710, 707, + 704, 701, 698, 695, 692, 689, 686, 684, 681, 678, 675, + 672, 669, 666, 663, 660, 657, 654, 651, 648, 645, 642, + 639, 636, 633, 630, 627, 624, 621, 618, 615, 612, 609, + 606, 602, 599, 596, 593, 590, 587, 584, 581, 578, 575, + 572, 568, 565, 562, 559, 556, 553, 550, 547, 543, 540, + 537, 534, 531, 528, 525, 521, 518, 515, 512, 509, 506, + 503, 499, 496, 493, 490], dtype=np.uint32), +'ASAM.M.SCALAR.UBYTE.VTAB_RANGE_NO_DEFAULT_VALUE': np.array([199, 198, 196, 195, 194, 193, 192, 190, 189, 188, 187, 185, 184, + 183, 181, 180, 178, 177, 176, 174, 173, 171, 170, 168, 167, 165, + 163, 162, 160, 159, 157, 155, 154, 152, 150, 149, 147, 145, 143, + 141, 140, 138, 136, 134, 132, 130, 128, 127, 125, 123, 121, 119, + 117, 115, 113, 111, 109, 107, 104, 102, 100, 98, 96, 94, 92, + 89, 87, 85, 83, 81, 78, 76, 74, 71, 69, 67, 65, 62, + 60, 57, 55, 53, 50, 48, 45, 43, 40, 38, 35, 33, 30, + 28, 25, 23, 20, 18, 15, 13, 10, 7, 5, 2, 255, 253, + 250, 247, 245, 242, 239, 237, 234, 231, 228, 226, 223, 220, 217, + 214, 212, 209, 206, 203, 200, 198, 195, 192, 189, 186, 183, 180, + 177, 174, 172, 169, 166, 163, 160, 157, 154, 151, 148, 145, 142, + 139, 136, 133, 130, 127, 124, 121, 118, 115, 112, 109, 106, 103, + 100, 97, 94, 90, 87, 84, 81, 78, 75, 72, 69, 66, 63, + 60, 56, 53, 50, 47, 44, 41, 38, 35, 31, 28, 25, 22, + 19, 16, 13, 9, 6, 3, 0, 253, 250, 247, 243, 240, 237, + 234, 231, 228, 225, 222, 218, 215, 212, 209, 206, 203, 200, 196, + 193, 190, 187, 184, 181, 178, 175, 171, 168, 165, 162, 159, 156, + 153, 150, 147, 144, 141, 137, 134, 131, 128, 125, 122, 119, 116, + 113, 110, 107, 104, 101, 98, 95, 92, 89, 86, 83, 80, 77, + 74, 71, 68, 65, 62, 59, 57, 54, 51, 48, 45, 42, 39, + 36, 33, 31, 28, 25, 22, 19, 17, 14, 11, 8, 5, 3, + 0, 253, 250, 248, 245, 242, 240, 237, 234, 232, 229, 226, 224, + 221, 218, 216, 213, 211, 208, 206, 203, 201, 198, 196, 193, 191, + 188, 186, 183, 181, 178, 176, 174, 171, 169, 166, 164, 162, 160, + 157, 155, 153, 150, 148, 146, 144, 142, 139, 137, 135, 133, 131, + 129, 127, 124, 122, 120, 118, 116, 114, 112, 110, 108, 106, 104, + 103, 101, 99, 97, 95, 93, 91, 90, 88, 86, 84, 82, 81, + 79, 77, 76, 74, 72, 71, 69, 68, 66, 64, 63, 61, 60, + 58, 57, 55, 54, 53, 51, 50, 48, 47, 46, 44, 43, 42, + 41, 39, 38, 37, 36, 35, 33, 32, 31, 30, 29, 28, 27, + 26, 25, 24, 23, 22, 21, 20, 19, 18, 18, 17, 16, 15, + 14, 14, 13, 12, 12, 11, 10, 10, 9, 8, 8, 7, 7, + 6, 6, 5, 5, 4, 4, 3, 3, 3, 2, 2, 2, 1, + 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, + 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 5, 5, 6, + 6, 7, 7, 8, 8, 9, 10, 10, 11, 12, 12, 13, 14, + 14, 15, 16, 17, 18, 18, 19, 20, 21, 22, 23, 24, 25, + 26, 27, 28, 29, 30, 31, 32, 33, 35, 36, 37, 38, 39, + 41, 42, 43, 44, 46, 47, 48, 50, 51, 53, 54, 55, 57, + 58, 60, 61, 63, 64, 66, 68, 69, 71, 72, 74, 76, 77, + 79, 81, 82, 84, 86, 88, 90, 91, 93, 95, 97, 99, 101, + 103, 104, 106, 108, 110, 112, 114, 116, 118, 120, 122, 124, 127, + 129, 131, 133, 135, 137, 139, 142, 144, 146, 148, 150, 153, 155, + 157, 160, 162, 164, 166, 169, 171, 174, 176, 178, 181, 183, 186, + 188, 191, 193, 196, 198, 201, 203, 206, 208, 211, 213, 216, 218, + 221, 224, 226, 229, 232, 234, 237, 240, 242, 245, 248, 250, 253, + 0, 3, 5, 8, 11, 14, 17, 19, 22, 25, 28, 31, 33, + 36, 39, 42, 45, 48, 51, 54, 57, 59, 62, 65, 68, 71, + 74, 77, 80, 83, 86, 89, 92, 95, 98, 101, 104, 107, 110, + 113, 116, 119, 122, 125, 128, 131, 134, 137, 141, 144, 147, 150, + 153, 156, 159, 162, 165, 168, 171, 175, 178, 181, 184, 187, 190, + 193, 196, 200, 203, 206, 209, 212, 215, 218, 222, 225, 228, 231, + 234, 237, 240, 244, 247, 250, 253, 0, 3, 6, 9, 13, 16, + 19, 22, 25, 28, 31, 35, 38, 41, 44, 47, 50, 53, 56, + 60, 63, 66, 69, 72, 75, 78, 81, 84, 87, 90, 94, 97, + 100, 103, 106, 109, 112, 115, 118, 121, 124, 127, 130, 133, 136, + 139, 142, 145, 148, 151, 154, 157, 160, 163, 166, 169, 172, 174, + 177, 180, 183, 186, 189, 192, 195, 198, 200, 203, 206, 209, 212, + 214, 217, 220, 223, 226, 228, 231, 234, 237, 239, 242, 245, 247, + 250, 253, 255, 2, 5, 7, 10, 13, 15, 18, 20, 23, 25, + 28, 30, 33, 35, 38, 40, 43, 45, 48, 50, 53, 55, 57, + 60, 62, 65, 67, 69, 71, 74, 76, 78, 81, 83, 85, 87, + 89, 92, 94, 96, 98, 100, 102, 104, 107, 109, 111, 113, 115, + 117, 119, 121, 123, 125, 127, 128, 130, 132, 134, 136, 138, 140, + 141, 143, 145, 147, 149, 150, 152, 154, 155, 157, 159, 160, 162, + 163, 165, 167, 168, 170, 171, 173, 174, 176, 177, 178, 180, 181, + 183, 184, 185, 187, 188, 189, 190, 192, 193, 194, 195, 196, 198, + 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210], dtype=np.uint8), +'ASAM.M.SCALAR.FLOAT64.IDENTICAL': np.array([ 1.73091812e+01, 1.64992561e+01, 1.57084198e+01, + 1.49367018e+01, 1.41841335e+01, 1.34507446e+01, + 1.27365637e+01, 1.20416193e+01, 1.13659382e+01, + 1.07095480e+01, 1.00724735e+01, 9.45474148e+00, + 8.85637474e+00, 8.27739716e+00, 7.71783257e+00, + 7.17770243e+00, 6.65702772e+00, 6.15582991e+00, + 5.67412758e+00, 5.21194077e+00, 4.76928711e+00, + 4.34618425e+00, 3.94264936e+00, 3.55869770e+00, + 3.19434476e+00, 2.84960485e+00, 2.52449155e+00, + 2.21901774e+00, 1.93319547e+00, 1.66703594e+00, + 1.42054987e+00, 1.19374681e+00, 9.86635804e-01, + 7.99224973e-01, 6.31521702e-01, 4.83532667e-01, + 3.55263680e-01, 2.46719822e-01, 1.57905355e-01, + 8.88238102e-02, 3.94778997e-02, 9.86957178e-03, + 0.00000000e+00, 9.86957178e-03, 3.94778959e-02, + 8.88238102e-02, 1.57905355e-01, 2.46719822e-01, + 3.55263680e-01, 4.83532667e-01, 6.31521702e-01, + 7.99224973e-01, 9.86635804e-01, 1.19374681e+00, + 1.42054987e+00, 1.66703594e+00, 1.93319547e+00, + 2.21901774e+00, 2.52449155e+00, 2.84960485e+00, + 3.19434476e+00, 3.55869770e+00, 3.94264936e+00, + 4.34618425e+00, 4.76928711e+00, 5.21194077e+00, + 5.67412758e+00, 6.15582991e+00, 6.65702772e+00, + 7.17770243e+00, 7.71783257e+00, 8.27739716e+00, + 8.85637474e+00, 9.45474148e+00, 1.00724735e+01, + 1.07095480e+01, 1.13659382e+01, 1.20416193e+01, + 1.27365637e+01, 1.34507446e+01, 1.41841335e+01, + 1.49367018e+01, 1.57084198e+01, 1.64992561e+01, + 1.73091812e+01, 1.81381607e+01, 1.89861641e+01, + 1.98531570e+01, 2.07391052e+01, 2.16439743e+01, + 2.25677280e+01, 2.35103283e+01, 2.44717426e+01, + 2.54519272e+01, 2.64508476e+01, 2.74684620e+01, + 2.85047321e+01, 2.95596161e+01, 3.06330719e+01, + 3.17250557e+01, 3.28355293e+01, 3.39644432e+01, + 3.51117554e+01, 3.62774239e+01, 3.74613953e+01, + 3.86636314e+01, 3.98840752e+01, 4.11226883e+01, + 4.23794136e+01, 4.36542053e+01, 4.49470139e+01, + 4.62577896e+01, 4.75864754e+01, 4.89330215e+01, + 5.02973747e+01, 5.16794815e+01, 5.30792885e+01, + 5.44967384e+01, 5.59317741e+01, 5.73843460e+01, + 5.88543854e+01, 6.03418465e+01, 6.18466606e+01, + 6.33687744e+01, 6.49081192e+01, 6.64646530e+01, + 6.80382919e+01, 6.96289902e+01, 7.12366714e+01, + 7.28612823e+01, 7.45027618e+01, 7.61610336e+01, + 7.78360367e+01, 7.95277100e+01, 8.12359772e+01, + 8.29607849e+01, 8.47020493e+01, 8.64597092e+01, + 8.82337036e+01, 9.00239487e+01, 9.18303757e+01, + 9.36529160e+01, 9.54915009e+01, 9.73460541e+01, + 9.92165070e+01, 1.01102783e+02, 1.03004799e+02, + 1.04922493e+02, 1.06855782e+02, 1.08804596e+02, + 1.10768852e+02, 1.12748466e+02, 1.14743378e+02, + 1.16753494e+02, 1.18778748e+02, 1.20819046e+02, + 1.22874313e+02, 1.24944466e+02, 1.27029427e+02, + 1.29129120e+02, 1.31243439e+02, 1.33372330e+02, + 1.35515686e+02, 1.37673431e+02, 1.39845490e+02, + 1.42031754e+02, 1.44232162e+02, 1.46446609e+02, + 1.48675018e+02, 1.50917297e+02, 1.53173340e+02, + 1.55443100e+02, 1.57726440e+02, 1.60023315e+02, + 1.62333603e+02, 1.64657211e+02, 1.66994064e+02, + 1.69344070e+02, 1.71707123e+02, 1.74083130e+02, + 1.76472015e+02, 1.78873672e+02, 1.81288010e+02, + 1.83714920e+02, 1.86154312e+02, 1.88606110e+02, + 1.91070190e+02, 1.93546478e+02, 1.96034851e+02, + 1.98535233e+02, 2.01047516e+02, 2.03571594e+02, + 2.06107376e+02, 2.08654755e+02, 2.11213654e+02, + 2.13783936e+02, 2.16365524e+02, 2.18958313e+02, + 2.21562195e+02, 2.24177063e+02, 2.26802826e+02, + 2.29439377e+02, 2.32086609e+02, 2.34744415e+02, + 2.37412689e+02, 2.40091324e+02, 2.42780228e+02, + 2.45479294e+02, 2.48188400e+02, 2.50907440e+02, + 2.53636322e+02, 2.56374939e+02, 2.59123169e+02, + 2.61880890e+02, 2.64648041e+02, 2.67424469e+02, + 2.70210083e+02, 2.73004761e+02, 2.75808380e+02, + 2.78620880e+02, 2.81442108e+02, 2.84271973e+02, + 2.87110352e+02, 2.89957123e+02, 2.92812195e+02, + 2.95675476e+02, 2.98546783e+02, 3.01426056e+02, + 3.04313171e+02, 3.07208008e+02, 3.10110443e+02, + 3.13020386e+02, 3.15937714e+02, 3.18862305e+02, + 3.21794067e+02, 3.24732849e+02, 3.27678528e+02, + 3.30631042e+02, 3.33590240e+02, 3.36556000e+02, + 3.39528198e+02, 3.42506744e+02, 3.45491516e+02, + 3.48482361e+02, 3.51479218e+02, 3.54481903e+02, + 3.57490356e+02, 3.60504456e+02, 3.63524017e+02, + 3.66549011e+02, 3.69579254e+02, 3.72614624e+02, + 3.75655060e+02, 3.78700378e+02, 3.81750488e+02, + 3.84805298e+02, 3.87864624e+02, 3.90928375e+02, + 3.93996460e+02, 3.97068695e+02, 4.00145020e+02, + 4.03225281e+02, 4.06309357e+02, 4.09397125e+02, + 4.12488464e+02, 4.15583282e+02, 4.18681427e+02, + 4.21782776e+02, 4.24887207e+02, 4.27994598e+02, + 4.31104858e+02, 4.34217834e+02, 4.37333374e+02, + 4.40451416e+02, 4.43571808e+02, 4.46694427e+02, + 4.49819153e+02, 4.52945831e+02, 4.56074402e+02, + 4.59204681e+02, 4.62336609e+02, 4.65470001e+02, + 4.68604736e+02, 4.71740723e+02, 4.74877838e+02, + 4.78015930e+02, 4.81154907e+02, 4.84294617e+02, + 4.87434967e+02, 4.90575775e+02, 4.93716980e+02, + 4.96858429e+02, 5.00000000e+02, 5.03141571e+02, + 5.06283020e+02, 5.09424225e+02, 5.12565063e+02, + 5.15705383e+02, 5.18845093e+02, 5.21984070e+02, + 5.25122131e+02, 5.28259277e+02, 5.31395264e+02, + 5.34530029e+02, 5.37663391e+02, 5.40795288e+02, + 5.43925598e+02, 5.47054138e+02, 5.50180847e+02, + 5.53305603e+02, 5.56428223e+02, 5.59548584e+02, + 5.62666626e+02, 5.65782166e+02, 5.68895142e+02, + 5.72005371e+02, 5.75112793e+02, 5.78217224e+02, + 5.81318604e+02, 5.84416748e+02, 5.87511536e+02, + 5.90602905e+02, 5.93690674e+02, 5.96774719e+02, + 5.99854980e+02, 6.02931274e+02, 6.06003540e+02, + 6.09071594e+02, 6.12135376e+02, 6.15194702e+02, + 6.18249512e+02, 6.21299622e+02, 6.24344971e+02, + 6.27385376e+02, 6.30420776e+02, 6.33450989e+02, + 6.36475952e+02, 6.39495544e+02, 6.42509644e+02, + 6.45518066e+02, 6.48520813e+02, 6.51517639e+02, + 6.54508484e+02, 6.57493286e+02, 6.60471802e+02, + 6.63444031e+02, 6.66409790e+02, 6.69368958e+02, + 6.72321472e+02, 6.75267151e+02, 6.78205933e+02, + 6.81137695e+02, 6.84062256e+02, 6.86979614e+02, + 6.89889526e+02, 6.92791992e+02, 6.95686829e+02, + 6.98573975e+02, 7.01453247e+02, 7.04324524e+02, + 7.07187805e+02, 7.10042847e+02, 7.12889648e+02, + 7.15728027e+02, 7.18557861e+02, 7.21379089e+02, + 7.24191589e+02, 7.26995239e+02, 7.29789917e+02, + 7.32575562e+02, 7.35351990e+02, 7.38119080e+02, + 7.40876831e+02, 7.43625061e+02, 7.46363647e+02, + 7.49092529e+02, 7.51811584e+02, 7.54520691e+02, + 7.57219788e+02, 7.59908691e+02, 7.62587341e+02, + 7.65255615e+02, 7.67913391e+02, 7.70560608e+02, + 7.73197144e+02, 7.75822937e+02, 7.78437805e+02, + 7.81041687e+02, 7.83634460e+02, 7.86216064e+02, + 7.88786377e+02, 7.91345215e+02, 7.93892639e+02, + 7.96428406e+02, 7.98952515e+02, 8.01464783e+02, + 8.03965149e+02, 8.06453552e+02, 8.08929810e+02, + 8.11393860e+02, 8.13845703e+02, 8.16285095e+02, + 8.18711975e+02, 8.21126343e+02, 8.23527954e+02, + 8.25916870e+02, 8.28292908e+02, 8.30655945e+02, + 8.33005920e+02, 8.35342773e+02, 8.37666382e+02, + 8.39976685e+02, 8.42273560e+02, 8.44556885e+02, + 8.46826660e+02, 8.49082703e+02, 8.51325012e+02, + 8.53553406e+02, 8.55767822e+02, 8.57968262e+02, + 8.60154541e+02, 8.62326538e+02, 8.64484314e+02, + 8.66627686e+02, 8.68756531e+02, 8.70870911e+02, + 8.72970581e+02, 8.75055542e+02, 8.77125671e+02, + 8.79180969e+02, 8.81221252e+02, 8.83246521e+02, + 8.85256592e+02, 8.87251526e+02, 8.89231140e+02, + 8.91195435e+02, 8.93144226e+02, 8.95077515e+02, + 8.96995178e+02, 8.98897217e+02, 9.00783508e+02, + 9.02653931e+02, 9.04508484e+02, 9.06347107e+02, + 9.08169617e+02, 9.09976074e+02, 9.11766296e+02, + 9.13540283e+02, 9.15297974e+02, 9.17039246e+02, + 9.18764038e+02, 9.20472290e+02, 9.22163940e+02, + 9.23838989e+02, 9.25497253e+02, 9.27138733e+02, + 9.28763306e+02, 9.30371033e+02, 9.31961731e+02, + 9.33535339e+02, 9.35091858e+02, 9.36631226e+02, + 9.38153320e+02, 9.39658142e+02, 9.41145630e+02, + 9.42615662e+02, 9.44068237e+02, 9.45503235e+02, + 9.46920715e+02, 9.48320496e+02, 9.49702637e+02, + 9.51066956e+02, 9.52413513e+02, 9.53742188e+02, + 9.55052979e+02, 9.56345764e+02, 9.57620605e+02, + 9.58877319e+02, 9.60115906e+02, 9.61336365e+02, + 9.62538574e+02, 9.63722595e+02, 9.64888245e+02, + 9.66035583e+02, 9.67164490e+02, 9.68274963e+02, + 9.69366943e+02, 9.70440369e+02, 9.71495239e+02, + 9.72531555e+02, 9.73549133e+02, 9.74548096e+02, + 9.75528259e+02, 9.76489685e+02, 9.77432251e+02, + 9.78356018e+02, 9.79260864e+02, 9.80146851e+02, + 9.81013855e+02, 9.81861816e+02, 9.82690796e+02, + 9.83500732e+02, 9.84291565e+02, 9.85063293e+02, + 9.85815857e+02, 9.86549255e+02, 9.87263428e+02, + 9.87958374e+02, 9.88634033e+02, 9.89290466e+02, + 9.89927551e+02, 9.90545288e+02, 9.91143616e+02, + 9.91722595e+02, 9.92282166e+02, 9.92822327e+02, + 9.93342957e+02, 9.93844177e+02, 9.94325867e+02, + 9.94788086e+02, 9.95230713e+02, 9.95653809e+02, + 9.96057373e+02, 9.96441284e+02, 9.96805664e+02, + 9.97150391e+02, 9.97475525e+02, 9.97781006e+02, + 9.98066833e+02, 9.98332947e+02, 9.98579468e+02, + 9.98806274e+02, 9.99013367e+02, 9.99200745e+02, + 9.99368469e+02, 9.99516479e+02, 9.99644714e+02, + 9.99753296e+02, 9.99842102e+02, 9.99911194e+02, + 9.99960510e+02, 9.99990112e+02, 1.00000000e+03, + 9.99990112e+02, 9.99960510e+02, 9.99911194e+02, + 9.99842102e+02, 9.99753296e+02, 9.99644714e+02, + 9.99516479e+02, 9.99368469e+02, 9.99200745e+02, + 9.99013367e+02, 9.98806274e+02, 9.98579468e+02, + 9.98332947e+02, 9.98066833e+02, 9.97781006e+02, + 9.97475525e+02, 9.97150391e+02, 9.96805664e+02, + 9.96441284e+02, 9.96057373e+02, 9.95653809e+02, + 9.95230713e+02, 9.94788086e+02, 9.94325867e+02, + 9.93844177e+02, 9.93342957e+02, 9.92822327e+02, + 9.92282166e+02, 9.91722595e+02, 9.91143616e+02, + 9.90545288e+02, 9.89927551e+02, 9.89290466e+02, + 9.88634033e+02, 9.87958374e+02, 9.87263428e+02, + 9.86549255e+02, 9.85815857e+02, 9.85063293e+02, + 9.84291565e+02, 9.83500732e+02, 9.82690796e+02, + 9.81861816e+02, 9.81013855e+02, 9.80146851e+02, + 9.79260864e+02, 9.78356018e+02, 9.77432251e+02, + 9.76489685e+02, 9.75528259e+02, 9.74548096e+02, + 9.73549133e+02, 9.72531555e+02, 9.71495239e+02, + 9.70440369e+02, 9.69366943e+02, 9.68274963e+02, + 9.67164490e+02, 9.66035583e+02, 9.64888245e+02, + 9.63722595e+02, 9.62538574e+02, 9.61336365e+02, + 9.60115906e+02, 9.58877319e+02, 9.57620605e+02, + 9.56345764e+02, 9.55052979e+02, 9.53742188e+02, + 9.52413513e+02, 9.51066956e+02, 9.49702637e+02, + 9.48320496e+02, 9.46920715e+02, 9.45503235e+02, + 9.44068237e+02, 9.42615662e+02, 9.41145630e+02, + 9.39658142e+02, 9.38153320e+02, 9.36631226e+02, + 9.35091858e+02, 9.33535339e+02, 9.31961731e+02, + 9.30371033e+02, 9.28763306e+02, 9.27138733e+02, + 9.25497253e+02, 9.23838989e+02, 9.22163940e+02, + 9.20472290e+02, 9.18764038e+02, 9.17039246e+02, + 9.15297974e+02, 9.13540283e+02, 9.11766296e+02, + 9.09976074e+02, 9.08169617e+02, 9.06347107e+02, + 9.04508484e+02, 9.02653931e+02, 9.00783508e+02, + 8.98897217e+02, 8.96995178e+02, 8.95077515e+02, + 8.93144226e+02, 8.91195435e+02, 8.89231140e+02, + 8.87251526e+02, 8.85256592e+02, 8.83246521e+02, + 8.81221252e+02, 8.79180969e+02, 8.77125671e+02, + 8.75055542e+02, 8.72970581e+02, 8.70870911e+02, + 8.68756531e+02, 8.66627686e+02, 8.64484314e+02, + 8.62326538e+02, 8.60154541e+02, 8.57968262e+02, + 8.55767822e+02, 8.53553406e+02, 8.51325012e+02, + 8.49082703e+02, 8.46826660e+02, 8.44556885e+02, + 8.42273560e+02, 8.39976685e+02, 8.37666382e+02, + 8.35342773e+02, 8.33005920e+02, 8.30655945e+02, + 8.28292908e+02, 8.25916870e+02, 8.23527954e+02, + 8.21126343e+02, 8.18711975e+02, 8.16285095e+02, + 8.13845703e+02, 8.11393860e+02, 8.08929810e+02, + 8.06453552e+02, 8.03965149e+02, 8.01464783e+02, + 7.98952515e+02, 7.96428406e+02, 7.93892639e+02, + 7.91345215e+02, 7.88786377e+02, 7.86216064e+02, + 7.83634460e+02, 7.81041687e+02, 7.78437805e+02, + 7.75822937e+02, 7.73197144e+02, 7.70560608e+02, + 7.67913391e+02, 7.65255615e+02, 7.62587341e+02, + 7.59908691e+02, 7.57219788e+02, 7.54520691e+02, + 7.51811584e+02, 7.49092529e+02, 7.46363647e+02, + 7.43625061e+02, 7.40876831e+02, 7.38119080e+02, + 7.35351990e+02, 7.32575562e+02, 7.29789917e+02, + 7.26995239e+02, 7.24191589e+02, 7.21379089e+02, + 7.18557861e+02, 7.15728027e+02, 7.12889648e+02, + 7.10042847e+02, 7.07187805e+02, 7.04324524e+02, + 7.01453247e+02, 6.98573975e+02, 6.95686829e+02, + 6.92791992e+02, 6.89889526e+02, 6.86979614e+02, + 6.84062256e+02, 6.81137695e+02, 6.78205933e+02, + 6.75267151e+02, 6.72321472e+02, 6.69368958e+02, + 6.66409790e+02, 6.63444031e+02, 6.60471802e+02, + 6.57493286e+02, 6.54508484e+02, 6.51517639e+02, + 6.48520813e+02, 6.45518066e+02, 6.42509644e+02, + 6.39495544e+02, 6.36475952e+02, 6.33450989e+02, + 6.30420776e+02, 6.27385376e+02, 6.24344971e+02, + 6.21299622e+02, 6.18249512e+02, 6.15194702e+02, + 6.12135376e+02, 6.09071594e+02, 6.06003540e+02, + 6.02931274e+02, 5.99854980e+02, 5.96774719e+02, + 5.93690674e+02, 5.90602905e+02, 5.87511536e+02, + 5.84416748e+02, 5.81318604e+02, 5.78217224e+02, + 5.75112793e+02, 5.72005371e+02, 5.68895142e+02, + 5.65782166e+02, 5.62666626e+02, 5.59548584e+02, + 5.56428223e+02, 5.53305603e+02, 5.50180847e+02, + 5.47054138e+02, 5.43925598e+02, 5.40795288e+02, + 5.37663391e+02, 5.34530029e+02, 5.31395264e+02, + 5.28259277e+02, 5.25122131e+02, 5.21984070e+02, + 5.18845093e+02, 5.15705383e+02, 5.12565063e+02, + 5.09424225e+02, 5.06283020e+02, 5.03141571e+02, + 5.00000000e+02, 4.96858429e+02, 4.93716980e+02, + 4.90575775e+02, 4.87434967e+02, 4.84294617e+02, + 4.81154907e+02, 4.78015930e+02, 4.74877838e+02, + 4.71740723e+02, 4.68604736e+02, 4.65470001e+02, + 4.62336609e+02, 4.59204681e+02, 4.56074402e+02, + 4.52945831e+02, 4.49819153e+02, 4.46694427e+02, + 4.43571808e+02, 4.40451416e+02, 4.37333374e+02, + 4.34217834e+02, 4.31104858e+02, 4.27994598e+02, + 4.24887207e+02, 4.21782776e+02, 4.18681427e+02, + 4.15583282e+02, 4.12488464e+02, 4.09397125e+02, + 4.06309357e+02, 4.03225281e+02, 4.00145020e+02, + 3.97068695e+02, 3.93996460e+02, 3.90928375e+02, + 3.87864624e+02, 3.84805298e+02, 3.81750488e+02, + 3.78700378e+02, 3.75655060e+02, 3.72614624e+02, + 3.69579254e+02, 3.66549011e+02, 3.63524017e+02, + 3.60504456e+02, 3.57490356e+02, 3.54481903e+02, + 3.51479218e+02, 3.48482361e+02, 3.45491516e+02, + 3.42506744e+02, 3.39528198e+02, 3.36556000e+02, + 3.33590240e+02, 3.30631042e+02, 3.27678528e+02, + 3.24732849e+02, 3.21794067e+02, 3.18862305e+02, + 3.15937714e+02, 3.13020386e+02, 3.10110443e+02, + 3.07208008e+02, 3.04313171e+02, 3.01426056e+02, + 2.98546783e+02, 2.95675476e+02, 2.92812195e+02, + 2.89957123e+02, 2.87110352e+02, 2.84271973e+02, + 2.81442108e+02, 2.78620880e+02, 2.75808380e+02, + 2.73004761e+02, 2.70210083e+02, 2.67424469e+02, + 2.64648041e+02, 2.61880890e+02, 2.59123169e+02, + 2.56374939e+02, 2.53636322e+02, 2.50907440e+02, + 2.48188400e+02, 2.45479294e+02, 2.42780228e+02, + 2.40091324e+02, 2.37412689e+02, 2.34744415e+02, + 2.32086609e+02, 2.29439377e+02, 2.26802826e+02, + 2.24177063e+02, 2.21562195e+02, 2.18958313e+02, + 2.16365524e+02, 2.13783936e+02, 2.11213654e+02, + 2.08654755e+02, 2.06107376e+02, 2.03571594e+02, + 2.01047516e+02, 1.98535233e+02], dtype=np.float32), +'ASAM.M.SCALAR.UWORD.IDENTICAL.BITMASK_0008': np.array([0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, + 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, + 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1, + 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, + 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, + 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, + 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, + 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, + 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, + 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, + 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, + 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, + 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, + 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, + 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, + 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, + 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, + 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, + 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, + 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, + 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, + 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, + 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, + 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, + 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, + 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, + 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, + 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, + 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, + 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1], dtype=np.uint8), +'ASAM.M.VIRTUAL.SCALAR.SWORD.PHYSICAL': np.array([ -544, -464, -384, -304, -224, -144, -64, 16, 96, + 176, 256, 336, 416, 496, 576, 656, 736, 816, + 896, 976, -992, -912, -832, -752, -672, -592, -512, + -432, -352, -272, 0, 80, 160, 240, 320, 400, + 480, 560, 640, 720, 800, 880, 960, -1008, -928, + -848, -768, -688, -608, -528, -448, -368, -288, -208, + -128, -48, 32, 112, 192, 272, 352, 432, 512, + 592, 672, 752, 832, 912, 992, -976, -896, -816, + -736, -656, -576, -496, -416, -336, -256, -176, -96, + -16, 64, 144, 224, 304, 384, 464, 544, 624], dtype=np.int16), + } + +CHANNELS_ARRAY = { + 'Int32': np.array(range(-20, 20), dtype=np.int32), + 'Float64': np.array(range(-20, 20), dtype=np.float64) * 0.25, + 'Uint8': np.array(range(0, 80, 2), dtype=np.uint8), + 'Uint64': np.ones(40, dtype=np.uint64) * 2**40, + 'XAxis': np.array([0, 1, 2] * 40, np.uint8).reshape(40,3,), + 'YAxis': np.array([0, 1, 2, 3] * 40, np.uint8).reshape(40,4), + 'Saw': np.arange(0, 1200, 10, dtype=np.uint16) % 0xFF, + 'Ones': np.ones(120, dtype=np.int8), + 'Cos': np.cos(2*np.pi*np.arange(0, 360, 3)/360, dtype=np.float64), + 'Sin': np.sin(2*np.pi*np.arange(0, 360, 3)/360, dtype=np.float64), + 'Zeros': np.zeros(120, dtype=np.int32), +} + +l = [] +for i in range(40): + l.append([i,] * 12) +arrays = [ + np.array(l, np.int16).reshape(40,3,4), + CHANNELS_ARRAY['XAxis'], + CHANNELS_ARRAY['YAxis'], +] +types = [ + ('Int16Array', np.int16, (3,4)), + ('XAxis', np.uint8, (3,)), + ('YAxis', np.uint8, (4,)), +] +CHANNELS_ARRAY['Int16Array'] = np.core.records.fromarrays( + arrays, + dtype=np.dtype(types), +) + +arrays = [CHANNELS_ARRAY['XAxis'], ] +types = [('XAxis', np.uint8, (3,)),] +CHANNELS_ARRAY['XAxis'] = np.core.records.fromarrays( + arrays, + dtype=np.dtype(types), +) + +arrays = [CHANNELS_ARRAY['YAxis'], ] +types = [('YAxis', np.uint8, (4,)),] +CHANNELS_ARRAY['YAxis'] = np.core.records.fromarrays( + arrays, + dtype=np.dtype(types), +) + +l = [] +for i in range(-60, 60): + l.append([0.1*i,] * 9) +arrays = [np.array(l, np.float32).reshape(120,3,3),] +types = [('Matrix', np.float32, (3,3)),] +CHANNELS_ARRAY['Matrix'] = np.core.records.fromarrays( + arrays, + dtype=np.dtype(types), +) + +arrays = [ + CHANNELS_ARRAY['Saw'], + CHANNELS_ARRAY['Ones'], + CHANNELS_ARRAY['Cos'], + CHANNELS_ARRAY['Sin'], + CHANNELS_ARRAY['Zeros'], +] +types = [ + ('Saw', np.uint16), + ('Ones', np.int8), + ('Cos', np.float64), + ('Sin', np.float64), + ('Zeros', np.int32), +] +CHANNELS_ARRAY['Maths'] = np.core.records.fromarrays( + arrays, + dtype=np.dtype(types), +) + +arrays = [ + CHANNELS_ARRAY['Int32'], + CHANNELS_ARRAY['Float64'], + CHANNELS_ARRAY['Uint8'], + CHANNELS_ARRAY['Uint64'], +] +types = [ + ('Int32', np.int32), + ('Float64', np.float64), + ('Uint8', np.uint8), + ('Uint64', np.uint64), +] +CHANNELS_ARRAY['Composed'] = np.core.records.fromarrays( + arrays, + dtype=np.dtype(types), +) + def get_test_data(filename=""): """ Utility functions needed by all test scripts. From 13398fd4b111bb499c320d1c8579b73efe9f77aa Mon Sep 17 00:00:00 2001 From: danielhrisca Date: Thu, 28 Dec 2017 18:06:31 +0200 Subject: [PATCH 057/117] debug test_read_array on travis --- test/test_mdf.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/test/test_mdf.py b/test/test_mdf.py index d603afd7a..f3b26c9f4 100644 --- a/test/test_mdf.py +++ b/test/test_mdf.py @@ -6,8 +6,10 @@ import unittest import shutil import urllib +from pprint import pprint from zipfile import ZipFile + import numpy as np from numpy import ( @@ -103,6 +105,9 @@ def test_read_array(self): original_samples = CHANNELS_ARRAY[name] res = np.array_equal(signal.samples, original_samples) if not res: + pprint(name) + pprint(signal.samples) + pprint(original_samples) ret = False self.assertTrue(ret) From 19b32e5c148d2ca43c2cc9cdedc0a78ac9f4e63f Mon Sep 17 00:00:00 2001 From: danielhrisca Date: Thu, 28 Dec 2017 23:20:38 +0200 Subject: [PATCH 058/117] fix issue with array test on 32 bit python (cos and sin functions difference between 32 and 64 bit Python) --- test/test_mdf.py | 17 ++++++++--------- test/utils.py | 4 ++-- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/test/test_mdf.py b/test/test_mdf.py index f3b26c9f4..7037ccfa6 100644 --- a/test/test_mdf.py +++ b/test/test_mdf.py @@ -53,7 +53,7 @@ def setUpClass(cls): urllib.urlretrieve(url, 'test.zip') ZipFile(r'test.zip').extractall('tmpdir_demo') - url = 'https://github.com/danielhrisca/asammdf/files/1591223/test.arrays.zip' + url = 'https://github.com/danielhrisca/asammdf/files/1592123/test.arrays.zip' if PYVERSION == 3: urllib.request.urlretrieve(url, 'test.zip') else: @@ -105,10 +105,12 @@ def test_read_array(self): original_samples = CHANNELS_ARRAY[name] res = np.array_equal(signal.samples, original_samples) if not res: - pprint(name) - pprint(signal.samples) - pprint(original_samples) - ret = False + if name == 'Cos': + for i, pair in enumerate(zip(signal.samples, original_samples)): + print(i, pair, pair[0] == pair[1]) + for i, pair in enumerate(zip(signal.samples.astype(np.float32), original_samples.astype(np.float32))): + print(i, pair, pair[0] == pair[1]) + ret = False self.assertTrue(ret) @@ -356,10 +358,7 @@ def test_filter_array(self): channel_list = random.sample(list(CHANNELS_ARRAY), channels_nr) filtered_mdf = MDF(input_file, memory=memory).filter(channel_list, memory=memory) - from pprint import pprint - pprint(set(filtered_mdf.channels_db) - {'t', 'time'}) - pprint(set(channel_list)) - pprint((set(filtered_mdf.channels_db) - {'t', 'time'}) - set(channel_list)) + self.assertTrue((set(filtered_mdf.channels_db) - {'t', 'time'}) == set(channel_list)) equal = True diff --git a/test/utils.py b/test/utils.py index 5da36badd..223ef3e0e 100644 --- a/test/utils.py +++ b/test/utils.py @@ -1505,8 +1505,8 @@ 'YAxis': np.array([0, 1, 2, 3] * 40, np.uint8).reshape(40,4), 'Saw': np.arange(0, 1200, 10, dtype=np.uint16) % 0xFF, 'Ones': np.ones(120, dtype=np.int8), - 'Cos': np.cos(2*np.pi*np.arange(0, 360, 3)/360, dtype=np.float64), - 'Sin': np.sin(2*np.pi*np.arange(0, 360, 3)/360, dtype=np.float64), + 'Cos': np.cos(np.arange(0, 360, 3, dtype=np.float32)/360*2*np.pi, dtype=np.float32).astype(np.float64), + 'Sin': np.sin(np.arange(0, 360, 3, dtype=np.float32)/360*2*np.pi, dtype=np.float32).astype(np.float64), 'Zeros': np.zeros(120, dtype=np.int32), } From a9f80ccd1ca9d765be2c1b0ddeb6aea3e2c4bab9 Mon Sep 17 00:00:00 2001 From: danielhrisca Date: Thu, 28 Dec 2017 23:30:12 +0200 Subject: [PATCH 059/117] don't use @unittest.skip decorator since it fails the travis CI build on python 2.7 --- test/test_mdf.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/test/test_mdf.py b/test/test_mdf.py index 7037ccfa6..1f7fa6ad4 100644 --- a/test/test_mdf.py +++ b/test/test_mdf.py @@ -234,8 +234,8 @@ def test_cut_absolute(self): self.assertTrue(equal) - @unittest.skip - def test_cut_absolute_array(self): + + def _test_cut_absolute_array(self): print("MDF cut absolute array tests") for mdfname in os.listdir('tmpdir_array'): @@ -345,8 +345,7 @@ def test_filter(self): self.assertTrue(equal) - @unittest.skip - def test_filter_array(self): + def _test_filter_array(self): print("MDF filter array tests") for mdfname in os.listdir('tmpdir_array'): From 993a7f0b897c19713ba5234990fa01f79dca5b55 Mon Sep 17 00:00:00 2001 From: danielhrisca Date: Thu, 28 Dec 2017 23:41:29 +0200 Subject: [PATCH 060/117] enable all cut tests for arrays --- test/test_mdf.py | 44 ++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 40 insertions(+), 4 deletions(-) diff --git a/test/test_mdf.py b/test/test_mdf.py index 1f7fa6ad4..7cfc25ca0 100644 --- a/test/test_mdf.py +++ b/test/test_mdf.py @@ -235,16 +235,16 @@ def test_cut_absolute(self): self.assertTrue(equal) - def _test_cut_absolute_array(self): + def test_cut_absolute_array(self): print("MDF cut absolute array tests") for mdfname in os.listdir('tmpdir_array'): for memory in MEMORY: input_file = os.path.join('tmpdir_array', mdfname) - MDF(input_file, memory=memory).cut(stop=2).save('tmp1', overwrite=True) - MDF(input_file, memory=memory).cut(start=2, stop=6).save('tmp2', overwrite=True) - MDF(input_file, memory=memory).cut(start=6).save('tmp3', overwrite=True) + MDF(input_file, memory=memory).cut(stop=2.1).save('tmp1', overwrite=True) + MDF(input_file, memory=memory).cut(start=2.1, stop=6.1).save('tmp2', overwrite=True) + MDF(input_file, memory=memory).cut(start=6.1).save('tmp3', overwrite=True) MDF.merge( ['tmp1', 'tmp2', 'tmp3'], @@ -309,6 +309,42 @@ def test_cut_relative(self): self.assertTrue(equal) + def test_cut_relative_array(self): + print("MDF cut relative array tests") + + for mdfname in os.listdir('tmpdir_array'): + for memory in MEMORY: + input_file = os.path.join('tmpdir_array', mdfname) + + MDF(input_file, memory=memory).cut(stop=3.1, whence=1).save('tmp1', overwrite=True) + MDF(input_file, memory=memory).cut(start=3.1, stop=5.1, whence=1).save('tmp2', overwrite=True) + MDF(input_file, memory=memory).cut(start=5.1, whence=1).save('tmp3', overwrite=True) + + MDF.merge( + ['tmp1', 'tmp2', 'tmp3'], + MDF(input_file, memory='minimum').version, + ).save('tmp', overwrite=True) + + equal = True + + with MDF(input_file, memory=memory) as mdf, \ + MDF('tmp', memory=memory) as mdf2: + + for i, group in enumerate(mdf.groups): + for j, channel in enumerate(group['channels'][1:], 1): + original = mdf.get(group=i, index=j) + converted = mdf2.get(group=i, index=j) + if not np.array_equal( + original.samples, + converted.samples): + equal = False + if not np.array_equal( + original.timestamps, + converted.timestamps): + equal = False + + self.assertTrue(equal) + def test_filter(self): print("MDF filter tests") From 4e60c380063d560b74e03a93931676682fa591a4 Mon Sep 17 00:00:00 2001 From: danielhrisca Date: Fri, 29 Dec 2017 00:53:54 +0200 Subject: [PATCH 061/117] fix error when filtering contains a channel composition and memory=='minimum' --- asammdf/mdf_v4.py | 10 ++++++++++ asammdf/v4_blocks.py | 2 +- test/test_mdf.py | 27 +++++++++++++++++++++++---- 3 files changed, 34 insertions(+), 5 deletions(-) diff --git a/asammdf/mdf_v4.py b/asammdf/mdf_v4.py index b54a19498..27c98b858 100644 --- a/asammdf/mdf_v4.py +++ b/asammdf/mdf_v4.py @@ -1402,6 +1402,7 @@ def append(self, signals, source_info='Python', common_timebase=False): 'lower_limit': t[0] if cycles_nr else 0, 'upper_limit': t[-1] if cycles_nr else 0, 'flags': v4c.FLAG_PHY_RANGE_OK | v4c.FLAG_VAL_RANGE_OK, + 'name_addr': gp_texts['channels'][-1]['name_addr'], } ch = Channel(**kargs) ch.name = name = 't' @@ -1665,6 +1666,7 @@ def append(self, signals, source_info='Python', common_timebase=False): 'max_raw_value': max_val if min_val <= max_val else 0, 'lower_limit': min_val if min_val <= max_val else 0, 'upper_limit': max_val if min_val <= max_val else 0, + 'name_addr': gp_texts['channels'][-1]['name_addr'], } if min_val > max_val: kargs['flags'] = 0 @@ -1872,6 +1874,7 @@ def append(self, signals, source_info='Python', common_timebase=False): 'max_raw_value': max_val if min_val <= max_val else 0, 'lower_limit': min_val if min_val <= max_val else 0, 'upper_limit': max_val if min_val <= max_val else 0, + 'name_addr': gp_texts['channels'][-1]['name_addr'], } if min_val > max_val: kargs['flags'] = 0 @@ -2013,6 +2016,7 @@ def append(self, signals, source_info='Python', common_timebase=False): 'lower_limit': 0, 'upper_limit': 0, 'flags': 0, + 'name_addr': gp_texts['channels'][-1]['name_addr'], } ch = Channel(**kargs) ch.name = name @@ -2101,6 +2105,7 @@ def append(self, signals, source_info='Python', common_timebase=False): 'lower_limit': 0, 'upper_limit': 0, 'flags': 0, + 'name_addr': gp_texts['channels'][-1]['name_addr'], } ch = Channel(**kargs) ch.name = name @@ -2183,6 +2188,7 @@ def append(self, signals, source_info='Python', common_timebase=False): 'lower_limit': min_val if min_val <= max_val else 0, 'upper_limit': max_val if min_val <= max_val else 0, 'flags': v4c.FLAG_PHY_RANGE_OK | v4c.FLAG_VAL_RANGE_OK, + 'name_addr': gp_texts['channels'][-1]['name_addr'], } ch = Channel(**kargs) @@ -2335,6 +2341,7 @@ def append(self, signals, source_info='Python', common_timebase=False): 'lower_limit': 0, 'upper_limit': 0, 'flags': 0, + 'name_addr': gp_texts['channels'][-1]['name_addr'], } ch = Channel(**kargs) ch.name = name @@ -2430,6 +2437,7 @@ def append(self, signals, source_info='Python', common_timebase=False): 'lower_limit': min_val if min_val <= max_val else 0, 'upper_limit': max_val if min_val <= max_val else 0, 'flags': v4c.FLAG_PHY_RANGE_OK | v4c.FLAG_VAL_RANGE_OK, + 'name_addr': gp_texts['channels'][-1]['name_addr'], } channel = Channel(**kargs) @@ -2941,10 +2949,12 @@ def get(self, address=address, stream=stream, ) + block = TextBlock( address=channel['name_addr'], stream=stream, ) + name_ = block['text'].decode('utf-8') name_ = name_.split('\\')[0].strip(' \n\r\t\0') names.append(name_) diff --git a/asammdf/v4_blocks.py b/asammdf/v4_blocks.py index 90b645e4e..588164734 100644 --- a/asammdf/v4_blocks.py +++ b/asammdf/v4_blocks.py @@ -241,7 +241,7 @@ def __init__(self, **kargs): self['links_nr'] = 8 self['next_ch_addr'] = 0 self['component_addr'] = 0 - self['name_addr'] = 0 + self['name_addr'] = kargs.get('name_addr', 0) self['source_addr'] = 0 self['conversion_addr'] = 0 self['data_block_addr'] = 0 diff --git a/test/test_mdf.py b/test/test_mdf.py index 7cfc25ca0..80956cbbc 100644 --- a/test/test_mdf.py +++ b/test/test_mdf.py @@ -63,7 +63,7 @@ def setUpClass(cls): @classmethod def tearDownClass(cls): shutil.rmtree('tmpdir_demo', True) - shutil.rmtree('tmpdir_array', True) +# shutil.rmtree('tmpdir_array', True) os.remove('test.zip') for filename in ('tmp', 'tmp1', 'tmp2')[:1]: if os.path.isfile(filename): @@ -381,11 +381,11 @@ def test_filter(self): self.assertTrue(equal) - def _test_filter_array(self): + def test_filter_array(self): print("MDF filter array tests") for mdfname in os.listdir('tmpdir_array'): - for memory in MEMORY: + for memory in MEMORY[:1]: input_file = os.path.join('tmpdir_array', mdfname) channels_nr = np.random.randint(1, len(CHANNELS_ARRAY) + 1) @@ -394,7 +394,26 @@ def _test_filter_array(self): filtered_mdf = MDF(input_file, memory=memory).filter(channel_list, memory=memory) - self.assertTrue((set(filtered_mdf.channels_db) - {'t', 'time'}) == set(channel_list)) + filtered_mdf.save('fiteed.mf4', overwrite=True) + + target = set(channel_list) + if 'Int16Array' in target: + target = target - {'XAxis', 'YAxis'} + if 'Maths' in target: + target = target - {'Saw', 'Ones', 'Cos', 'Sin', 'Zeros'} + if 'Composed' in target: + target = target - {'Int32', 'Float64', 'Uint8', 'Uint64'} + + actual = set(filtered_mdf.channels_db) - {'t', 'time'} + + if 'Int16Array' in actual: + actual = actual - {'XAxis', 'YAxis'} + if 'Maths' in actual: + actual = actual - {'Saw', 'Ones', 'Cos', 'Sin', 'Zeros'} + if 'Composed' in actual: + actual = actual - {'Int32', 'Float64', 'Uint8', 'Uint64'} + + self.assertTrue(actual == target) equal = True From 8059640bc5e762d4bcceeabafa2d8c0156a22456 Mon Sep 17 00:00:00 2001 From: danielhrisca Date: Fri, 29 Dec 2017 14:46:06 +0200 Subject: [PATCH 062/117] added array select tests --- asammdf/mdf_v2_v3.py | 43 ++++++++++++++++++++++++++++++++----- test/test_mdf.py | 51 ++++++++++++++++++++++++++++++++++---------- 2 files changed, 78 insertions(+), 16 deletions(-) diff --git a/asammdf/mdf_v2_v3.py b/asammdf/mdf_v2_v3.py index aa5094f65..854a89bf0 100644 --- a/asammdf/mdf_v2_v3.py +++ b/asammdf/mdf_v2_v3.py @@ -1242,11 +1242,11 @@ def append(self, kargs['conversion_type'] = v23c.CONVERSION_TYPE_VTABR lower = info['lower'] upper = info['upper'] - texts = info['phys'] + texts_ = info['phys'] kargs['unit'] = signal.unit.encode('latin-1') kargs['ref_param_nr'] = len(upper) - for i, vals in enumerate(zip(upper, lower, texts)): + for i, vals in enumerate(zip(upper, lower, texts_)): u_, l_, t_ = vals kargs['lower_{}'.format(i)] = l_ kargs['upper_{}'.format(i)] = u_ @@ -1321,12 +1321,11 @@ def append(self, if len(name) >= 32 and self.version >= '2.10': short_name = (name[:31] + '\0').encode('latin-1') if memory != 'minimum': - texts['long_name_addr'] = TextBlock(texts=name) + texts['long_name_addr'] = TextBlock(text=name) else: address = tell() texts['long_name_addr'] = address - block = TextBlock(texts=name) - gp_channels.append(address) + block = TextBlock(text=name) write(bytes(block)) else: short_name = name.encode('latin-1') @@ -1334,6 +1333,12 @@ def append(self, if texts: gp_texts['channels'][-1] = texts + channel_texts = gp_texts['channels'][-1] + if channel_texts: + long_name_addr = channel_texts.get('long_name_addr', 0) + else: + long_name_addr = 0 + kargs = { 'short_name': short_name, 'channel_type': v23c.CHANNEL_TYPE_VALUE, @@ -1343,6 +1348,7 @@ def append(self, 'start_offset': start_bit_offset, 'bit_count': bit_count, 'aditional_byte_offset': additional_byte_offset, + 'long_name_addr': long_name_addr, } if self.version >= '3.00': kargs['block_len'] = v23c.CN_DISPLAYNAME_BLOCK_SIZE @@ -1494,6 +1500,13 @@ def append(self, short_name = (name[:31] + '\0').encode('latin-1') else: short_name = name.encode('latin-1') + + channel_texts = gp_texts['channels'][-1] + if channel_texts: + long_name_addr = channel_texts.get('long_name_addr', 0) + else: + long_name_addr = 0 + kargs = { 'short_name': short_name, 'channel_type': v23c.CHANNEL_TYPE_VALUE, @@ -1503,6 +1516,7 @@ def append(self, 'start_offset': start_bit_offset, 'bit_count': s_size, 'aditional_byte_offset': additional_byte_offset, + 'long_name_addr': long_name_addr, } if self.version >= '3.00': kargs['block_len'] = v23c.CN_DISPLAYNAME_BLOCK_SIZE @@ -1635,6 +1649,12 @@ def append(self, short_name = (name[:31] + '\0').encode('latin-1') else: short_name = name.encode('latin-1') + channel_texts = gp_texts['channels'][-1] + if channel_texts: + long_name_addr = channel_texts.get('long_name_addr', 0) + else: + long_name_addr = 0 + kargs = { 'short_name': short_name, 'channel_type': v23c.CHANNEL_TYPE_VALUE, @@ -1644,6 +1664,7 @@ def append(self, 'start_offset': start_bit_offset, 'bit_count': s_size, 'aditional_byte_offset': additional_byte_offset, + 'long_name_addr': long_name_addr, } if self.version >= '3.00': kargs['block_len'] = v23c.CN_DISPLAYNAME_BLOCK_SIZE @@ -1727,6 +1748,11 @@ def append(self, short_name = (name[:31] + '\0').encode('latin-1') else: short_name = name.encode('latin-1') + channel_texts = gp_texts['channels'][-1] + if channel_texts: + long_name_addr = channel_texts.get('long_name_addr', 0) + else: + long_name_addr = 0 kargs = { 'short_name': short_name, 'channel_type': v23c.CHANNEL_TYPE_VALUE, @@ -1736,6 +1762,7 @@ def append(self, 'start_offset': start_bit_offset, 'bit_count': s_size, 'aditional_byte_offset': additional_byte_offset, + 'long_name_addr': long_name_addr, } if self.version >= '3.00': kargs['block_len'] = v23c.CN_DISPLAYNAME_BLOCK_SIZE @@ -2020,6 +2047,11 @@ def append(self, short_name = (name[:31] + '\0').encode('latin-1') else: short_name = name.encode('latin-1') + channel_texts = gp_texts['channels'][-1] + if channel_texts: + long_name_addr = channel_texts.get('long_name_addr', 0) + else: + long_name_addr = 0 kargs = { 'short_name': short_name, 'channel_type': v23c.CHANNEL_TYPE_VALUE, @@ -2029,6 +2061,7 @@ def append(self, 'start_offset': start_bit_offset, 'bit_count': s_size, 'aditional_byte_offset': additional_byte_offset, + 'long_name_addr': long_name_addr, } if self.version >= '3.00': kargs['block_len'] = v23c.CN_DISPLAYNAME_BLOCK_SIZE diff --git a/test/test_mdf.py b/test/test_mdf.py index 80956cbbc..6683dc4cc 100644 --- a/test/test_mdf.py +++ b/test/test_mdf.py @@ -32,7 +32,7 @@ CHANNELS_ARRAY, MEMORY, ) -from asammdf import MDF, SUPPORTED_VERSIONS +from asammdf import MDF, SUPPORTED_VERSIONS, configure CHANNEL_LEN = 100000 @@ -63,9 +63,9 @@ def setUpClass(cls): @classmethod def tearDownClass(cls): shutil.rmtree('tmpdir_demo', True) -# shutil.rmtree('tmpdir_array', True) + shutil.rmtree('tmpdir_array', True) os.remove('test.zip') - for filename in ('tmp', 'tmp1', 'tmp2')[:1]: + for filename in ('tmp', 'tmp1', 'tmp2'): if os.path.isfile(filename): os.remove(filename) @@ -105,12 +105,7 @@ def test_read_array(self): original_samples = CHANNELS_ARRAY[name] res = np.array_equal(signal.samples, original_samples) if not res: - if name == 'Cos': - for i, pair in enumerate(zip(signal.samples, original_samples)): - print(i, pair, pair[0] == pair[1]) - for i, pair in enumerate(zip(signal.samples.astype(np.float32), original_samples.astype(np.float32))): - print(i, pair, pair[0] == pair[1]) - ret = False + ret = False self.assertTrue(ret) @@ -121,6 +116,8 @@ def test_convert(self): for mdfname in os.listdir('tmpdir_demo'): for memory in MEMORY: input_file = os.path.join('tmpdir_demo', mdfname) + if MDF(input_file).version == '2.00': + continue with MDF(input_file, memory=memory) as mdf: mdf.convert(out, memory=memory).save('tmp', overwrite=True) @@ -263,12 +260,10 @@ def test_cut_absolute_array(self): if not np.array_equal( original.samples, converted.samples): - print(original.name, original.samples, converted.samples) equal = False if not np.array_equal( original.timestamps, converted.timestamps): - print(original.name, original.timestamps, converted.timestamps) equal = False self.assertTrue(equal) @@ -470,6 +465,40 @@ def test_select(self): self.assertTrue(equal) + def test_select_array(self): + print("MDF select array tests") + + for mdfname in os.listdir('tmpdir_array'): + for memory in MEMORY: + input_file = os.path.join('tmpdir_array', mdfname) + + channels_nr = np.random.randint(1, len(CHANNELS_ARRAY) + 1) + + channel_list = random.sample(list(CHANNELS_ARRAY), channels_nr) + + selected_signals = MDF(input_file, memory=memory).select(channel_list) + + self.assertTrue(len(selected_signals) == len(channel_list)) + + self.assertTrue(all(ch.name == name for ch, name in zip(selected_signals, channel_list))) + + equal = True + + with MDF(input_file, memory=memory) as mdf: + + for selected in selected_signals: + original = mdf.get(selected.name) + if not np.array_equal( + original.samples, + selected.samples): + equal = False + if not np.array_equal( + original.timestamps, + selected.timestamps): + equal = False + + self.assertTrue(equal) + if __name__ == '__main__': unittest.main() From c3b4a3d5d6936b0280237219c7968766b8351095 Mon Sep 17 00:00:00 2001 From: danielhrisca Date: Fri, 29 Dec 2017 15:07:43 +0200 Subject: [PATCH 063/117] fix rounding error in test data --- test/test_mdf.py | 2 ++ test/utils.py | 2 ++ 2 files changed, 4 insertions(+) diff --git a/test/test_mdf.py b/test/test_mdf.py index 6683dc4cc..9d617f2c0 100644 --- a/test/test_mdf.py +++ b/test/test_mdf.py @@ -100,6 +100,8 @@ def test_read_array(self): for mdf in os.listdir('tmpdir_array'): for memory in MEMORY: with MDF(os.path.join('tmpdir_array', mdf), memory=memory) as input_file: + if input_file.version == '2.00': + continue for name in set(input_file.channels_db) - {'time', 't'}: signal = input_file.get(name) original_samples = CHANNELS_ARRAY[name] diff --git a/test/utils.py b/test/utils.py index 223ef3e0e..c00fe68d1 100644 --- a/test/utils.py +++ b/test/utils.py @@ -1510,6 +1510,8 @@ 'Zeros': np.zeros(120, dtype=np.int32), } +CHANNELS_ARRAY['Sin'][70] = -0.5 + l = [] for i in range(40): l.append([i,] * 12) From 8f8ddcc6699c72bcbd94ba8fb474096f52d44789 Mon Sep 17 00:00:00 2001 From: danielhrisca Date: Fri, 29 Dec 2017 19:25:28 +0200 Subject: [PATCH 064/117] added unsorted file for CI tests --- test/test_mdf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_mdf.py b/test/test_mdf.py index 9d617f2c0..7f2277018 100644 --- a/test/test_mdf.py +++ b/test/test_mdf.py @@ -46,7 +46,7 @@ def test_measurement(self): def setUpClass(cls): PYVERSION = sys.version_info[0] - url = 'https://github.com/danielhrisca/asammdf/files/1565237/test.files.zip' + url = 'https://github.com/danielhrisca/asammdf/files/1593570/test.demo.zip' if PYVERSION == 3: urllib.request.urlretrieve(url, 'test.zip') else: From 2d359133b7c1b37e930946e4e51e64fc1e97d1b1 Mon Sep 17 00:00:00 2001 From: danielhrisca Date: Fri, 29 Dec 2017 19:38:32 +0200 Subject: [PATCH 065/117] python 2 unsorted fix --- asammdf/mdf_v4.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/asammdf/mdf_v4.py b/asammdf/mdf_v4.py index 27c98b858..c8d523bfa 100644 --- a/asammdf/mdf_v4.py +++ b/asammdf/mdf_v4.py @@ -293,11 +293,14 @@ def _read(self): samples_size = channel_group['samples_byte_nr'] inval_size = channel_group['invalidation_bytes_nr'] record_id = channel_group['record_id'] - + if PYVERSION == 2: + record_id = chr(record_id) cg_size[record_id] = samples_size + inval_size else: # VLDS flags record_id = channel_group['record_id'] + if PYVERSION == 2: + record_id = chr(record_id) cg_size[record_id] = 0 if record_id_nr: From af4a2e40c317e6631045ed616575b1530a6f9af8 Mon Sep 17 00:00:00 2001 From: danielhrisca Date: Fri, 29 Dec 2017 20:32:41 +0200 Subject: [PATCH 066/117] further fixes for python2 unsorted file handling --- asammdf/mdf_v2_v3.py | 4 ++++ asammdf/mdf_v4.py | 4 ++++ test/test_mdf.py | 1 + 3 files changed, 9 insertions(+) diff --git a/asammdf/mdf_v2_v3.py b/asammdf/mdf_v2_v3.py index 854a89bf0..3f2eaebe5 100644 --- a/asammdf/mdf_v2_v3.py +++ b/asammdf/mdf_v2_v3.py @@ -173,6 +173,8 @@ def _load_group_data(self, group): else: read_size = group['size'] record_id = group['channel_group']['record_id'] + if PYVERSION == 2: + record_id = chr(record_id) cg_size = group['record_size'] if group['data_group']['record_id_nr'] <= 2: record_id_nr = group['data_group']['record_id_nr'] @@ -809,6 +811,8 @@ def _read(self): for grp in new_groups: record_id = grp['channel_group']['record_id'] + if PYVERSION == 2: + record_id = chr(record_id) cycles_nr = grp['channel_group']['cycles_nr'] record_size = grp['channel_group']['samples_byte_nr'] diff --git a/asammdf/mdf_v4.py b/asammdf/mdf_v4.py index c8d523bfa..78eda3b9e 100644 --- a/asammdf/mdf_v4.py +++ b/asammdf/mdf_v4.py @@ -385,6 +385,8 @@ def _read(self): for grp in new_groups: grp['data_location'] = v4c.LOCATION_MEMORY record_id = grp['channel_group']['record_id'] + if PYVERSION == 2: + record_id = chr(record_id) data = b''.join(cg_data[record_id]) grp['channel_group']['record_id'] = 1 grp['data_block'] = DataBlock(data=data) @@ -761,6 +763,8 @@ def _load_group_data(self, group): cg_data = [] cg_size = group['record_size'] record_id = channel_group['record_id'] + if PYVERSION == 2: + record_id = chr(record_id) if data_group['record_id_len'] <= 2: record_id_nr = data_group['record_id_len'] else: diff --git a/test/test_mdf.py b/test/test_mdf.py index 7f2277018..3aa3cb161 100644 --- a/test/test_mdf.py +++ b/test/test_mdf.py @@ -120,6 +120,7 @@ def test_convert(self): input_file = os.path.join('tmpdir_demo', mdfname) if MDF(input_file).version == '2.00': continue + print(input_file, memory) with MDF(input_file, memory=memory) as mdf: mdf.convert(out, memory=memory).save('tmp', overwrite=True) From f189301c56be1e9e22d66be69129af21f4106c1a Mon Sep 17 00:00:00 2001 From: danielhrisca Date: Sat, 30 Dec 2017 08:54:38 +0200 Subject: [PATCH 067/117] use regex istead of xml parser for mdf version4 channel commments --- asammdf/mdf_v4.py | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/asammdf/mdf_v4.py b/asammdf/mdf_v4.py index 78eda3b9e..49a818d34 100644 --- a/asammdf/mdf_v4.py +++ b/asammdf/mdf_v4.py @@ -6,10 +6,10 @@ from __future__ import division, print_function import os +import re import sys import time import warnings -import xml.etree.ElementTree as XML from collections import defaultdict from copy import deepcopy from functools import partial, reduce @@ -81,6 +81,8 @@ v4c.CHANNEL_TYPE_VIRTUAL_MASTER, ) +TX = re.compile('(?P(.|\n)+?)') + PYVERSION = sys.version_info[0] if PYVERSION == 2: from .utils import bytes @@ -2805,9 +2807,10 @@ def get_channel_comment(self, name=None, group=None, index=None): if comment['id'] == b'##MD': comment = comment['text'].decode('utf-8').strip(' \n\t\0') - try: - comment = XML.fromstring(comment).find('TX').text - except: + match = TX.search(comment) + if match: + comment = match.group('text') + else: comment = '' else: comment = comment['text'].decode('utf-8') @@ -3656,9 +3659,10 @@ def get(self, if comment['id'] == b'##MD': comment = comment['text'].decode('utf-8').strip(' \n\t\0') - try: - comment = XML.fromstring(comment).find('TX').text - except: + match = TX.search(comment) + if match: + comment = match.group('text') + else: comment = '' else: comment = comment['text'].decode('utf-8') From 162f94220c89e593b29ad5531a32bd91b911bcf9 Mon Sep 17 00:00:00 2001 From: danielhrisca Date: Sat, 30 Dec 2017 10:04:04 +0200 Subject: [PATCH 068/117] remove duplicate code in mdf version 3 append --- asammdf/mdf_v2_v3.py | 56 +++++++++++--------------------------------- 1 file changed, 14 insertions(+), 42 deletions(-) diff --git a/asammdf/mdf_v2_v3.py b/asammdf/mdf_v2_v3.py index 3f2eaebe5..4d6b02da7 100644 --- a/asammdf/mdf_v2_v3.py +++ b/asammdf/mdf_v2_v3.py @@ -997,6 +997,13 @@ def append(self, else: t = t_ + if self.version >= '3.00': + channel_size = v23c.CN_DISPLAYNAME_BLOCK_SIZE + elif self.version >= '2.10': + channel_size = v23c.CN_LONGNAME_BLOCK_SIZE + else: + channel_size = v23c.CN_SHORT_BLOCK_SIZE + memory = self.memory file = self._tempfile write = file.write @@ -1109,13 +1116,8 @@ def append(self, 'min_raw_value': t[0] if cycles_nr else 0, 'max_raw_value': t[-1] if cycles_nr else 0, 'bit_count': t_size, + 'block_len': channel_size, } - if self.version >= '3.00': - kargs['block_len'] = v23c.CN_DISPLAYNAME_BLOCK_SIZE - elif self.version >= '2.10': - kargs['block_len'] = v23c.CN_LONGNAME_BLOCK_SIZE - else: - kargs['block_len'] = v23c.CN_SHORT_BLOCK_SIZE channel = Channel(**kargs) channel.name = name = 't' if memory != 'minimum': @@ -1353,13 +1355,8 @@ def append(self, 'bit_count': bit_count, 'aditional_byte_offset': additional_byte_offset, 'long_name_addr': long_name_addr, + 'block_len': channel_size, } - if self.version >= '3.00': - kargs['block_len'] = v23c.CN_DISPLAYNAME_BLOCK_SIZE - elif self.version >= '2.10': - kargs['block_len'] = v23c.CN_LONGNAME_BLOCK_SIZE - else: - kargs['block_len'] = v23c.CN_SHORT_BLOCK_SIZE comment = signal.comment if comment: comment = comment.encode('latin-1') @@ -1521,13 +1518,8 @@ def append(self, 'bit_count': s_size, 'aditional_byte_offset': additional_byte_offset, 'long_name_addr': long_name_addr, + 'block_len': channel_size, } - if self.version >= '3.00': - kargs['block_len'] = v23c.CN_DISPLAYNAME_BLOCK_SIZE - elif self.version >= '2.10': - kargs['block_len'] = v23c.CN_LONGNAME_BLOCK_SIZE - else: - kargs['block_len'] = v23c.CN_SHORT_BLOCK_SIZE comment = signal.comment if comment: if len(comment) >= 128: @@ -1669,13 +1661,8 @@ def append(self, 'bit_count': s_size, 'aditional_byte_offset': additional_byte_offset, 'long_name_addr': long_name_addr, + 'block_len': channel_size, } - if self.version >= '3.00': - kargs['block_len'] = v23c.CN_DISPLAYNAME_BLOCK_SIZE - elif self.version >= '2.10': - kargs['block_len'] = v23c.CN_LONGNAME_BLOCK_SIZE - else: - kargs['block_len'] = v23c.CN_SHORT_BLOCK_SIZE comment = signal.comment if comment: if len(comment) >= 128: @@ -1767,13 +1754,8 @@ def append(self, 'bit_count': s_size, 'aditional_byte_offset': additional_byte_offset, 'long_name_addr': long_name_addr, + 'block_len': channel_size, } - if self.version >= '3.00': - kargs['block_len'] = v23c.CN_DISPLAYNAME_BLOCK_SIZE - elif self.version >= '2.10': - kargs['block_len'] = v23c.CN_LONGNAME_BLOCK_SIZE - else: - kargs['block_len'] = v23c.CN_SHORT_BLOCK_SIZE channel = Channel(**kargs) channel.name = name @@ -1924,13 +1906,8 @@ def append(self, 'min_raw_value': t[0] if cycles_nr else 0, 'max_raw_value': t[-1] if cycles_nr else 0, 'bit_count': t_size, + 'block_len': channel_size, } - if self.version >= '3.00': - kargs['block_len'] = v23c.CN_DISPLAYNAME_BLOCK_SIZE - elif self.version >= '2.10': - kargs['block_len'] = v23c.CN_LONGNAME_BLOCK_SIZE - else: - kargs['block_len'] = v23c.CN_SHORT_BLOCK_SIZE channel = Channel(**kargs) channel.name = name = 't' if memory != 'minimum': @@ -2066,13 +2043,8 @@ def append(self, 'bit_count': s_size, 'aditional_byte_offset': additional_byte_offset, 'long_name_addr': long_name_addr, + 'block_len': channel_size, } - if self.version >= '3.00': - kargs['block_len'] = v23c.CN_DISPLAYNAME_BLOCK_SIZE - elif self.version >= '2.10': - kargs['block_len'] = v23c.CN_LONGNAME_BLOCK_SIZE - else: - kargs['block_len'] = v23c.CN_SHORT_BLOCK_SIZE channel = Channel(**kargs) channel.name = name From b05cd5fbab05fd568d43c8a814a6bcda0dc4611c Mon Sep 17 00:00:00 2001 From: danielhrisca Date: Sat, 30 Dec 2017 11:42:10 +0200 Subject: [PATCH 069/117] added unsorted mdf version 3 test file --- test/test_mdf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_mdf.py b/test/test_mdf.py index 3aa3cb161..20ca9dbbb 100644 --- a/test/test_mdf.py +++ b/test/test_mdf.py @@ -46,7 +46,7 @@ def test_measurement(self): def setUpClass(cls): PYVERSION = sys.version_info[0] - url = 'https://github.com/danielhrisca/asammdf/files/1593570/test.demo.zip' + url = 'https://github.com/danielhrisca/asammdf/files/1594267/test.demo.zip' if PYVERSION == 3: urllib.request.urlretrieve(url, 'test.zip') else: From e43d3e4bf92b02d56c0c4a3bde939d7070a1e4cb Mon Sep 17 00:00:00 2001 From: danielhrisca Date: Sat, 30 Dec 2017 13:14:16 +0200 Subject: [PATCH 070/117] fix error in mdf version 3 handling of unsorted measurements fix python 2 32bit compatibility (long and int) --- asammdf/mdf_v2_v3.py | 5 ++++- asammdf/mdf_v4.py | 10 ++++++---- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/asammdf/mdf_v2_v3.py b/asammdf/mdf_v2_v3.py index 4d6b02da7..25fcb8cb1 100644 --- a/asammdf/mdf_v2_v3.py +++ b/asammdf/mdf_v2_v3.py @@ -856,7 +856,10 @@ def _read(self): i += rec_size for grp in new_groups: grp['data_location'] = v23c.LOCATION_MEMORY - data = cg_data[grp['channel_group']['record_id']] + record_id = grp['channel_group']['record_id'] + if PYVERSION == 2: + record_id = chr(record_id) + data = cg_data[record_id] data = b''.join(data) grp['channel_group']['record_id'] = 1 grp['data_block'] = DataBlock(data=data) diff --git a/asammdf/mdf_v4.py b/asammdf/mdf_v4.py index 49a818d34..df35c2130 100644 --- a/asammdf/mdf_v4.py +++ b/asammdf/mdf_v4.py @@ -86,6 +86,8 @@ PYVERSION = sys.version_info[0] if PYVERSION == 2: from .utils import bytes +else: + from past.builtins import long __all__ = ['MDF4', ] @@ -406,7 +408,7 @@ def _read(self): continue for dep in dep_list: - if isinstance(dep, (Channel, int)): + if isinstance(dep, (Channel, int, long)): break else: conditions = ( @@ -2949,7 +2951,7 @@ def get(self, arrays = [] name = channel.name - if all(isinstance(dep, (Channel, int)) for dep in dependency_list): + if all(isinstance(dep, (Channel, int, long)) for dep in dependency_list): # structure channel composition if memory == 'minimum': names = [] @@ -4723,7 +4725,7 @@ def _save_without_metadata(self, dst, overwrite, compression): if gp['channel_dependencies'][j]: block = gp['channel_dependencies'][j][0] - if isinstance(block, int): + if isinstance(block, (int, long)): channel['component_addr'] = block else: channel['component_addr'] = block.address @@ -4739,7 +4741,7 @@ def _save_without_metadata(self, dst, overwrite, compression): while j < len(gp['channels']): dep_list = gp['channel_dependencies'][j] if dep_list and all( - isinstance(dep, int) for dep in dep_list): + isinstance(dep, (int, long)) for dep in dep_list): dep = chans[j+1] From acde773e013be7ef62262957a892c3a348dd6d32 Mon Sep 17 00:00:00 2001 From: danielhrisca Date: Sat, 30 Dec 2017 22:17:17 +0200 Subject: [PATCH 071/117] fix compacting of integers on save --- asammdf/mdf_v2_v3.py | 21 +- asammdf/mdf_v4.py | 26 ++- test/test_mdf.py | 534 +++++++++++++++++++++++++++++++------------ test/test_mdf23.py | 17 +- 4 files changed, 434 insertions(+), 164 deletions(-) diff --git a/asammdf/mdf_v2_v3.py b/asammdf/mdf_v2_v3.py index 25fcb8cb1..9884cb10a 100644 --- a/asammdf/mdf_v2_v3.py +++ b/asammdf/mdf_v2_v3.py @@ -27,6 +27,7 @@ interp, linspace, log, + ones, packbits, roll, searchsorted, @@ -1167,6 +1168,7 @@ def append(self, int(max_).bit_length(), int(min_).bit_length(), ) + bit_length += 1 signal['bit_count'] = max(minimum_bitlength, bit_length) @@ -2476,12 +2478,25 @@ def get(self, vals &= mask else: vals = vals & mask + if data_type in v23c.SIGNED_INT: + size = vals.dtype.itemsize - mask = (1 << (size * 8)) - 1 - mask = (mask << bits) & mask - vals |= mask + + masks = ones( + cycles_nr, + dtype=dtype('> (bits - 1)).astype(dtype('> (bits - 1)).astype(dtype('= '4.00'): for mdfname in os.listdir('tmpdir_array'): for memory in MEMORY: @@ -198,9 +246,36 @@ def test_merge_array(self): self.assertTrue(equal) + configure(True, True) + + for out in (version for version in SUPPORTED_VERSIONS if version >= '4.00'): + for mdfname in os.listdir('tmpdir_array'): + for memory in MEMORY: + input_file = os.path.join('tmpdir_array', mdfname) + files = [input_file, ] * 4 + + MDF.merge(files, out, memory).save('tmp', overwrite=True) + + equal = True + + with MDF(input_file, memory=memory) as mdf, \ + MDF('tmp', memory=memory) as mdf2: + + for name in set(mdf.channels_db) - {'t', 'time'}: + original = mdf.get(name) + converted = mdf2.get(name) + if not np.array_equal( + np.tile(original.samples, 4), + converted.samples): + equal = False + + self.assertTrue(equal) + def test_cut_absolute(self): print("MDF cut absolute tests") + configure(False, False) + for mdfname in os.listdir('tmpdir_demo'): for memory in MEMORY: input_file = os.path.join('tmpdir_demo', mdfname) @@ -234,10 +309,49 @@ def test_cut_absolute(self): self.assertTrue(equal) + configure(True, True) + + for mdfname in os.listdir('tmpdir_demo'): + for memory in MEMORY: + input_file = os.path.join('tmpdir_demo', mdfname) + if '2.00' in input_file: + continue + + MDF(input_file, memory=memory).cut(stop=2).save('tmp1', overwrite=True) + MDF(input_file, memory=memory).cut(start=2, stop=6).save('tmp2', overwrite=True) + MDF(input_file, memory=memory).cut(start=6).save('tmp3', overwrite=True) + + MDF.merge( + ['tmp1', 'tmp2', 'tmp3'], + MDF(input_file, memory='minimum').version, + ).save('tmp', overwrite=True) + + equal = True + + with MDF(input_file, memory=memory) as mdf, \ + MDF('tmp', memory=memory) as mdf2: + + for name in set(mdf.channels_db) - {'time', 't'}: + original = mdf.get(name) + converted = mdf2.get(name) + if not np.array_equal( + original.samples, + converted.samples): + print(original, converted, '='*80, sep='\n') + equal = False + if not np.array_equal( + original.timestamps, + converted.timestamps): + equal = False + + self.assertTrue(equal) + def test_cut_absolute_array(self): print("MDF cut absolute array tests") + configure(False, False) + for mdfname in os.listdir('tmpdir_array'): for memory in MEMORY: input_file = os.path.join('tmpdir_array', mdfname) @@ -271,12 +385,50 @@ def test_cut_absolute_array(self): self.assertTrue(equal) + configure(True, True) + + for mdfname in os.listdir('tmpdir_array'): + for memory in MEMORY: + input_file = os.path.join('tmpdir_array', mdfname) + + MDF(input_file, memory=memory).cut(stop=2.1).save('tmp1', overwrite=True) + MDF(input_file, memory=memory).cut(start=2.1, stop=6.1).save('tmp2', overwrite=True) + MDF(input_file, memory=memory).cut(start=6.1).save('tmp3', overwrite=True) + + MDF.merge( + ['tmp1', 'tmp2', 'tmp3'], + MDF(input_file, memory='minimum').version, + ).save('tmp', overwrite=True) + + equal = True + + with MDF(input_file, memory=memory) as mdf, \ + MDF('tmp', memory=memory) as mdf2: + + for name in set(mdf.channels_db) - {'time', 't'}: + original = mdf.get(name) + converted = mdf2.get(name) + if not np.array_equal( + original.samples, + converted.samples): + equal = False + if not np.array_equal( + original.timestamps, + converted.timestamps): + equal = False + + self.assertTrue(equal) + def test_cut_relative(self): print("MDF cut relative tests") + configure(False, False) + for mdfname in os.listdir('tmpdir_demo'): for memory in MEMORY: input_file = os.path.join('tmpdir_demo', mdfname) + if '2.00' in input_file: + continue MDF(input_file, memory=memory).cut(stop=3, whence=1).save('tmp1', overwrite=True) MDF(input_file, memory=memory).cut(start=3, stop=5, whence=1).save('tmp2', overwrite=True) @@ -307,9 +459,45 @@ def test_cut_relative(self): self.assertTrue(equal) + configure(True, True) + + for mdfname in os.listdir('tmpdir_demo'): + for memory in MEMORY: + input_file = os.path.join('tmpdir_demo', mdfname) + + MDF(input_file, memory=memory).cut(stop=3, whence=1).save('tmp1', overwrite=True) + MDF(input_file, memory=memory).cut(start=3, stop=5, whence=1).save('tmp2', overwrite=True) + MDF(input_file, memory=memory).cut(start=5, whence=1).save('tmp3', overwrite=True) + + MDF.merge( + ['tmp1', 'tmp2', 'tmp3'], + MDF(input_file, memory='minimum').version, + ).save('tmp', overwrite=True) + + equal = True + + with MDF(input_file, memory=memory) as mdf, \ + MDF('tmp', memory=memory) as mdf2: + + for name in set(mdf.channels_db) - {'time', 't'}: + original = mdf.get(name) + converted = mdf2.get(name) + if not np.array_equal( + original.samples, + converted.samples): + equal = False + if not np.array_equal( + original.timestamps, + converted.timestamps): + equal = False + + self.assertTrue(equal) + def test_cut_relative_array(self): print("MDF cut relative array tests") + configure(False, False) + for mdfname in os.listdir('tmpdir_array'): for memory in MEMORY: input_file = os.path.join('tmpdir_array', mdfname) @@ -343,164 +531,210 @@ def test_cut_relative_array(self): self.assertTrue(equal) - def test_filter(self): - print("MDF filter tests") + configure(True, True) - for mdfname in os.listdir('tmpdir_demo'): + for mdfname in os.listdir('tmpdir_array'): for memory in MEMORY: - input_file = os.path.join('tmpdir_demo', mdfname) - - if MDF(input_file, memory=memory).version == '2.00': - continue - - channels_nr = np.random.randint(1, len(CHANNELS_DEMO) + 1) - - channel_list = random.sample(list(CHANNELS_DEMO), channels_nr) + input_file = os.path.join('tmpdir_array', mdfname) - filtered_mdf = MDF(input_file, memory=memory).filter(channel_list, memory=memory) + MDF(input_file, memory=memory).cut(stop=3.1, whence=1).save('tmp1', overwrite=True) + MDF(input_file, memory=memory).cut(start=3.1, stop=5.1, whence=1).save('tmp2', overwrite=True) + MDF(input_file, memory=memory).cut(start=5.1, whence=1).save('tmp3', overwrite=True) - self.assertTrue((set(filtered_mdf.channels_db) - {'t', 'time'}) == set(channel_list)) + MDF.merge( + ['tmp1', 'tmp2', 'tmp3'], + MDF(input_file, memory='minimum').version, + ).save('tmp', overwrite=True) equal = True - with MDF(input_file, memory=memory) as mdf: + with MDF(input_file, memory=memory) as mdf, \ + MDF('tmp', memory=memory) as mdf2: - for name in channel_list: + for name in set(mdf.channels_db) - {'time', 't'}: original = mdf.get(name) - filtered = filtered_mdf.get(name) + converted = mdf2.get(name) if not np.array_equal( original.samples, - filtered.samples): + converted.samples): equal = False if not np.array_equal( original.timestamps, - filtered.timestamps): + converted.timestamps): equal = False self.assertTrue(equal) + def test_filter(self): + print("MDF filter tests") + + for enable in (True, False): + configure(enable, enable) + + for mdfname in os.listdir('tmpdir_demo'): + for memory in MEMORY: + input_file = os.path.join('tmpdir_demo', mdfname) + + if MDF(input_file, memory=memory).version == '2.00': + continue + + channels_nr = np.random.randint(1, len(CHANNELS_DEMO) + 1) + + channel_list = random.sample(list(CHANNELS_DEMO), channels_nr) + + filtered_mdf = MDF(input_file, memory=memory).filter(channel_list, memory=memory) + + self.assertTrue((set(filtered_mdf.channels_db) - {'t', 'time'}) == set(channel_list)) + + equal = True + + with MDF(input_file, memory=memory) as mdf: + + for name in channel_list: + original = mdf.get(name) + filtered = filtered_mdf.get(name) + if not np.array_equal( + original.samples, + filtered.samples): + equal = False + if not np.array_equal( + original.timestamps, + filtered.timestamps): + equal = False + + self.assertTrue(equal) + def test_filter_array(self): print("MDF filter array tests") - for mdfname in os.listdir('tmpdir_array'): - for memory in MEMORY[:1]: - input_file = os.path.join('tmpdir_array', mdfname) + for enable in (True, False): + configure(enable, enable) - channels_nr = np.random.randint(1, len(CHANNELS_ARRAY) + 1) + for mdfname in os.listdir('tmpdir_array'): + for memory in MEMORY[:1]: + input_file = os.path.join('tmpdir_array', mdfname) - channel_list = random.sample(list(CHANNELS_ARRAY), channels_nr) + channels_nr = np.random.randint(1, len(CHANNELS_ARRAY) + 1) - filtered_mdf = MDF(input_file, memory=memory).filter(channel_list, memory=memory) + channel_list = random.sample(list(CHANNELS_ARRAY), channels_nr) - filtered_mdf.save('fiteed.mf4', overwrite=True) + filtered_mdf = MDF(input_file, memory=memory).filter(channel_list, memory=memory) - target = set(channel_list) - if 'Int16Array' in target: - target = target - {'XAxis', 'YAxis'} - if 'Maths' in target: - target = target - {'Saw', 'Ones', 'Cos', 'Sin', 'Zeros'} - if 'Composed' in target: - target = target - {'Int32', 'Float64', 'Uint8', 'Uint64'} + filtered_mdf.save('fiteed.mf4', overwrite=True) - actual = set(filtered_mdf.channels_db) - {'t', 'time'} + target = set(channel_list) + if 'Int16Array' in target: + target = target - {'XAxis', 'YAxis'} + if 'Maths' in target: + target = target - {'Saw', 'Ones', 'Cos', 'Sin', 'Zeros'} + if 'Composed' in target: + target = target - {'Int32', 'Float64', 'Uint8', 'Uint64'} - if 'Int16Array' in actual: - actual = actual - {'XAxis', 'YAxis'} - if 'Maths' in actual: - actual = actual - {'Saw', 'Ones', 'Cos', 'Sin', 'Zeros'} - if 'Composed' in actual: - actual = actual - {'Int32', 'Float64', 'Uint8', 'Uint64'} + actual = set(filtered_mdf.channels_db) - {'t', 'time'} - self.assertTrue(actual == target) + if 'Int16Array' in actual: + actual = actual - {'XAxis', 'YAxis'} + if 'Maths' in actual: + actual = actual - {'Saw', 'Ones', 'Cos', 'Sin', 'Zeros'} + if 'Composed' in actual: + actual = actual - {'Int32', 'Float64', 'Uint8', 'Uint64'} - equal = True + self.assertTrue(actual == target) - with MDF(input_file, memory=memory) as mdf: + equal = True - for name in channel_list: - original = mdf.get(name) - filtered = filtered_mdf.get(name) - if not np.array_equal( - original.samples, - filtered.samples): - equal = False - if not np.array_equal( - original.timestamps, - filtered.timestamps): - equal = False + with MDF(input_file, memory=memory) as mdf: - self.assertTrue(equal) + for name in channel_list: + original = mdf.get(name) + filtered = filtered_mdf.get(name) + if not np.array_equal( + original.samples, + filtered.samples): + equal = False + if not np.array_equal( + original.timestamps, + filtered.timestamps): + equal = False + + self.assertTrue(equal) def test_select(self): print("MDF select tests") - for mdfname in os.listdir('tmpdir_demo'): - for memory in MEMORY: - input_file = os.path.join('tmpdir_demo', mdfname) + for enable in (True, False): + configure(enable, enable) - if MDF(input_file).version == '2.00': - continue + for mdfname in os.listdir('tmpdir_demo'): + for memory in MEMORY: + input_file = os.path.join('tmpdir_demo', mdfname) - channels_nr = np.random.randint(1, len(CHANNELS_DEMO) + 1) + if MDF(input_file).version == '2.00': + continue - channel_list = random.sample(list(CHANNELS_DEMO), channels_nr) + channels_nr = np.random.randint(1, len(CHANNELS_DEMO) + 1) - selected_signals = MDF(input_file, memory=memory).select(channel_list) + channel_list = random.sample(list(CHANNELS_DEMO), channels_nr) - self.assertTrue(len(selected_signals) == len(channel_list)) + selected_signals = MDF(input_file, memory=memory).select(channel_list) - self.assertTrue(all(ch.name == name for ch, name in zip(selected_signals, channel_list))) + self.assertTrue(len(selected_signals) == len(channel_list)) - equal = True + self.assertTrue(all(ch.name == name for ch, name in zip(selected_signals, channel_list))) - with MDF(input_file, memory=memory) as mdf: + equal = True - for selected in selected_signals: - original = mdf.get(selected.name) - if not np.array_equal( - original.samples, - selected.samples): - equal = False - if not np.array_equal( - original.timestamps, - selected.timestamps): - equal = False + with MDF(input_file, memory=memory) as mdf: - self.assertTrue(equal) + for selected in selected_signals: + original = mdf.get(selected.name) + if not np.array_equal( + original.samples, + selected.samples): + equal = False + if not np.array_equal( + original.timestamps, + selected.timestamps): + equal = False + + self.assertTrue(equal) def test_select_array(self): print("MDF select array tests") - for mdfname in os.listdir('tmpdir_array'): - for memory in MEMORY: - input_file = os.path.join('tmpdir_array', mdfname) + for enable in (True, False): + configure(enable, enable) - channels_nr = np.random.randint(1, len(CHANNELS_ARRAY) + 1) + for mdfname in os.listdir('tmpdir_array'): + for memory in MEMORY: + input_file = os.path.join('tmpdir_array', mdfname) - channel_list = random.sample(list(CHANNELS_ARRAY), channels_nr) + channels_nr = np.random.randint(1, len(CHANNELS_ARRAY) + 1) - selected_signals = MDF(input_file, memory=memory).select(channel_list) + channel_list = random.sample(list(CHANNELS_ARRAY), channels_nr) - self.assertTrue(len(selected_signals) == len(channel_list)) + selected_signals = MDF(input_file, memory=memory).select(channel_list) - self.assertTrue(all(ch.name == name for ch, name in zip(selected_signals, channel_list))) + self.assertTrue(len(selected_signals) == len(channel_list)) - equal = True + self.assertTrue(all(ch.name == name for ch, name in zip(selected_signals, channel_list))) - with MDF(input_file, memory=memory) as mdf: + equal = True - for selected in selected_signals: - original = mdf.get(selected.name) - if not np.array_equal( - original.samples, - selected.samples): - equal = False - if not np.array_equal( - original.timestamps, - selected.timestamps): - equal = False + with MDF(input_file, memory=memory) as mdf: - self.assertTrue(equal) + for selected in selected_signals: + original = mdf.get(selected.name) + if not np.array_equal( + original.samples, + selected.samples): + equal = False + if not np.array_equal( + original.timestamps, + selected.timestamps): + equal = False + + self.assertTrue(equal) if __name__ == '__main__': diff --git a/test/test_mdf23.py b/test/test_mdf23.py index 1430e3d3b..bafc056e6 100644 --- a/test/test_mdf23.py +++ b/test/test_mdf23.py @@ -6,9 +6,14 @@ import numpy as np from utils import MEMORY -from asammdf import MDF, MDF23, Signal +from asammdf import MDF, MDF23, Signal, configure -CHANNEL_LEN = 100000 +CHANNEL_LEN = 10000 + +configure(integer_compacting=True, + split_data_blocks=True, + split_threshold=260, + overwrite=True) class TestMDF23(unittest.TestCase): @@ -24,7 +29,7 @@ def test_read_mdf2_00(self): print('Read 2.00 using seed =', seed) sig_int = Signal( - np.random.randint(-2**31, 2**31, CHANNEL_LEN), + np.random.randint(-2**15, -1, CHANNEL_LEN), np.arange(CHANNEL_LEN), name='Integer Channel', unit='unit1', @@ -62,7 +67,7 @@ def test_read_mdf2_14(self): print('Read 2.14 using seed =', seed) sig_int = Signal( - np.random.randint(-2**31, 2**31, CHANNEL_LEN), + np.random.randint(-2**29, 2**29, CHANNEL_LEN), np.arange(CHANNEL_LEN), name='Integer Channel', unit='unit1', @@ -99,7 +104,7 @@ def test_read_mdf3_00(self): print('Read 3.00 using seed =', seed) sig_int = Signal( - np.random.randint(-2**31, 2**31, CHANNEL_LEN), + np.random.randint(-2**16, 2**16, CHANNEL_LEN, np.int32), np.arange(CHANNEL_LEN), name='Integer Channel', unit='unit1', @@ -137,7 +142,7 @@ def test_read_mdf3_10(self): print('Read 3.10 using seed =', seed) sig_int = Signal( - np.random.randint(-2**31, 2**31, CHANNEL_LEN), + np.random.randint(-2**9, 2**7, CHANNEL_LEN), np.arange(CHANNEL_LEN), name='Integer Channel', unit='unit1', From 029c05dced46797ddfb7b16b308340bc85577a97 Mon Sep 17 00:00:00 2001 From: danielhrisca Date: Sat, 30 Dec 2017 22:31:38 +0200 Subject: [PATCH 072/117] remove unused function from utils.py --- asammdf/mdf_v4.py | 2 +- asammdf/utils.py | 122 ++-------------------------------------------- test/test_mdf.py | 30 +++--------- 3 files changed, 11 insertions(+), 143 deletions(-) diff --git a/asammdf/mdf_v4.py b/asammdf/mdf_v4.py index 2b002b535..af37be76b 100644 --- a/asammdf/mdf_v4.py +++ b/asammdf/mdf_v4.py @@ -4768,7 +4768,7 @@ def _save_without_metadata(self, dst, overwrite, compression): channel['next_ch_addr'] = dep['next_ch_addr'] dep['next_ch_addr'] = 0 - for k, dep_addr in enumerate(dep_list): + for k, _ in enumerate(dep_list): dep = chans[j+1+k] dep['source_addr'] = 0 diff --git a/asammdf/utils.py b/asammdf/utils.py index 9f245f22a..a1b79e4dd 100644 --- a/asammdf/utils.py +++ b/asammdf/utils.py @@ -4,7 +4,6 @@ ''' import itertools -import re from numpy import ( amin, @@ -17,6 +16,9 @@ __all__ = [ 'MdfException', 'get_fmt', + 'get_min_max', + 'get_unique_name', + 'fix_dtype_fields', 'fmt_to_datatype', 'pair', 'bytes', @@ -39,53 +41,6 @@ def bytes(obj): raise -def dtype_mapping(invalue, outversion=3): - """ map data types between mdf versions 3 and 4 - - Parameters - ---------- - invalue : int - original data type - outversion : int - mdf version of output data type - - Returns - ------- - res : int - mapped data type - - """ - - v3tov4 = {v3c.DATA_TYPE_UNSIGNED: v4c.DATA_TYPE_UNSIGNED_INTEL, - v3c.DATA_TYPE_SIGNED: v4c.DATA_TYPE_SIGNED_INTEL, - v3c.DATA_TYPE_FLOAT: v4c.DATA_TYPE_REAL_INTEL, - v3c.DATA_TYPE_DOUBLE: v4c.DATA_TYPE_REAL_INTEL, - v3c.DATA_TYPE_STRING: v4c.DATA_TYPE_STRING_LATIN_1, - v3c.DATA_TYPE_UNSIGNED_INTEL: v4c.DATA_TYPE_UNSIGNED_INTEL, - v3c.DATA_TYPE_UNSIGNED_INTEL: v4c.DATA_TYPE_UNSIGNED_INTEL, - v3c.DATA_TYPE_SIGNED_INTEL: v4c.DATA_TYPE_SIGNED_INTEL, - v3c.DATA_TYPE_SIGNED_INTEL: v4c.DATA_TYPE_SIGNED_INTEL, - v3c.DATA_TYPE_FLOAT_INTEL: v4c.DATA_TYPE_REAL_INTEL, - v3c.DATA_TYPE_FLOAT_INTEL: v4c.DATA_TYPE_REAL_INTEL, - v3c.DATA_TYPE_DOUBLE_INTEL: v4c.DATA_TYPE_REAL_INTEL, - v3c.DATA_TYPE_DOUBLE_INTEL: v4c.DATA_TYPE_REAL_INTEL} - - v4tov3 = {v4c.DATA_TYPE_UNSIGNED_INTEL: v3c.DATA_TYPE_UNSIGNED_INTEL, - v4c.DATA_TYPE_UNSIGNED_MOTOROLA: v3c.DATA_TYPE_UNSIGNED_MOTOROLA, - v4c.DATA_TYPE_SIGNED_INTEL: v3c.DATA_TYPE_SIGNED_INTEL, - v4c.DATA_TYPE_STRING_LATIN_1: v3c.DATA_TYPE_STRING, - v4c.DATA_TYPE_BYTEARRAY: v3c.DATA_TYPE_STRING, - v4c.DATA_TYPE_REAL_INTEL: v3c.DATA_TYPE_DOUBLE_INTEL, - v4c.DATA_TYPE_REAL_MOTOROLA: v3c.DATA_TYPE_DOUBLE_MOTOROLA, - v4c.DATA_TYPE_SIGNED_MOTOROLA: v3c.DATA_TYPE_SIGNED_MOTOROLA} - - if outversion == 3: - res = v4tov3[invalue] - else: - res = v3tov4[invalue] - return res - - def get_fmt(data_type, size, version=3): """convert mdf channel data type to numpy dtype format string @@ -280,74 +235,3 @@ def get_min_max(samples): else: min_val, max_val = 0, 0 return min_val, max_val - - -def load_dbc(dbc): - """ Loads all messages description from DBC - - Parameters - ---------- - dbc : str - DBC file path - - Returns - ------- - messages : dict - the keys are the message ID's from the dbc - - """ - - pattern = r'(?P^BO_ (.+\n)+)' - - with open(dbc, 'r') as dbc_file: - string = dbc_file.read() - - messages = {} - - for match_ in re.finditer(pattern, string, flags=re.M): - msg = match_.group('msg') - - pattern = r'BO_ (?P\d+) (?P[^ :]+): (?P\d).+' - match = re.search(pattern, msg) - can_id = int(match.group('can_id')) - name = match.group('name') - dlc = int(match.group('dlc')) - - pattern = (r'SG_ (?P[^ ]+) : ' - r'(?P\d{1,2})\|(?P\d{1,2})' - r'@(?P\d)(?P[+-])' - r' \((?P[^,]+),(?P[^)]+)\)' - r' \[(?P[^|]+)\|(?P[^]]+)\]' - r' "(?P[^"]*)"') - - messages[can_id] = { - 'name': name, - 'dlc': dlc, - 'signals': {}, - 'can_id': can_id - } - - signals = messages[can_id]['signals'] - - for match in re.finditer(pattern, msg): - signal_name = match.group('name') - start_bit = int(match.group('start_bit')) - size = int(match.group('size')) - byte_order = match.group('byte_order') - signed = match.group('signed') == '-' - factor = float(match.group('factor')) - offset = float(match.group('offset')) - min_value = float(match.group('min_value')) - max_value = float(match.group('max_value')) - unit = match.group('unit') - signals[signal_name] = {'start_bit': start_bit, - 'size': size, - 'byte_order': byte_order, - 'signed': signed, - 'factor': factor, - 'offset': offset, - 'min_value': min_value, - 'max_value': max_value, - 'unit': unit} - - return messages diff --git a/test/test_mdf.py b/test/test_mdf.py index 3b7564a5d..3f2f9dae4 100644 --- a/test/test_mdf.py +++ b/test/test_mdf.py @@ -6,27 +6,11 @@ import unittest import shutil import urllib -from pprint import pprint from zipfile import ZipFile import numpy as np -from numpy import ( - array, - float16, - float32, - float64, - int8, - int16, - int32, - int64, - uint8, - uint16, - uint32, - uint64, -) - from utils import ( CHANNELS_DEMO, CHANNELS_ARRAY, @@ -93,7 +77,7 @@ def test_read(self): signal = input_file.get(name) original_samples = CHANNELS_DEMO[name] if signal.samples.dtype.kind == 'f': - signal = signal.astype(float32) + signal = signal.astype(np.float32) res = np.array_equal(signal.samples, original_samples) if not res: ret = False @@ -179,7 +163,7 @@ def test_merge(self): MDF('tmp', memory=memory) as mdf2: for i, group in enumerate(mdf.groups): - for j, channel in enumerate(group['channels'][1:], 1): + for j, _ in enumerate(group['channels'][1:], 1): original = mdf.get(group=i, index=j) converted = mdf2.get(group=i, index=j) if not np.array_equal( @@ -236,7 +220,7 @@ def test_merge_array(self): MDF('tmp', memory=memory) as mdf2: for i, group in enumerate(mdf.groups): - for j, channel in enumerate(group['channels'][1:], 1): + for j, _ in enumerate(group['channels'][1:], 1): original = mdf.get(group=i, index=j) converted = mdf2.get(group=i, index=j) if not np.array_equal( @@ -295,7 +279,7 @@ def test_cut_absolute(self): MDF('tmp', memory=memory) as mdf2: for i, group in enumerate(mdf.groups): - for j, channel in enumerate(group['channels'][1:], 1): + for j, _ in enumerate(group['channels'][1:], 1): original = mdf.get(group=i, index=j) converted = mdf2.get(group=i, index=j) if not np.array_equal( @@ -371,7 +355,7 @@ def test_cut_absolute_array(self): MDF('tmp', memory=memory) as mdf2: for i, group in enumerate(mdf.groups): - for j, channel in enumerate(group['channels'][1:], 1): + for j, _ in enumerate(group['channels'][1:], 1): original = mdf.get(group=i, index=j) converted = mdf2.get(group=i, index=j) if not np.array_equal( @@ -445,7 +429,7 @@ def test_cut_relative(self): MDF('tmp', memory=memory) as mdf2: for i, group in enumerate(mdf.groups): - for j, channel in enumerate(group['channels'][1:], 1): + for j, _ in enumerate(group['channels'][1:], 1): original = mdf.get(group=i, index=j) converted = mdf2.get(group=i, index=j) if not np.array_equal( @@ -517,7 +501,7 @@ def test_cut_relative_array(self): MDF('tmp', memory=memory) as mdf2: for i, group in enumerate(mdf.groups): - for j, channel in enumerate(group['channels'][1:], 1): + for j, _ in enumerate(group['channels'][1:], 1): original = mdf.get(group=i, index=j) converted = mdf2.get(group=i, index=j) if not np.array_equal( From 6fa55f2b79ab77a603dedd9a7d0b2a20957ce8a7 Mon Sep 17 00:00:00 2001 From: danielhrisca Date: Sat, 30 Dec 2017 23:52:51 +0200 Subject: [PATCH 073/117] add get_channel_unit tests add get_channel_comment test for mdf version 4 --- test/test_mdf.py | 41 +++++++++++++++++++++++++++++++++++ test/utils.py | 56 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 97 insertions(+) diff --git a/test/test_mdf.py b/test/test_mdf.py index 3f2f9dae4..19c4c7f2e 100644 --- a/test/test_mdf.py +++ b/test/test_mdf.py @@ -14,7 +14,9 @@ from utils import ( CHANNELS_DEMO, CHANNELS_ARRAY, + COMMENTS, MEMORY, + UNITS, ) from asammdf import MDF, SUPPORTED_VERSIONS, configure @@ -84,6 +86,45 @@ def test_read(self): self.assertTrue(ret) + def test_get_channel_comment_v4(self): + print("MDF get channel comment tests") + + ret = True + + for mdf in os.listdir('tmpdir_demo'): + for memory in MEMORY: + with MDF(os.path.join('tmpdir_demo', mdf), memory=memory) as input_file: + if input_file.version < '4.00': + continue + print(mdf, memory) + for channel_name, original_comment in COMMENTS.items(): + comment = input_file.get_channel_comment(channel_name) + if comment != original_comment: + print(channel_name, original_comment, comment) + ret = False + + self.assertTrue(ret) + + def test_get_channel_units(self): + print("MDF get channel units tests") + + ret = True + + for mdf in os.listdir('tmpdir_demo'): + for memory in MEMORY: + with MDF(os.path.join('tmpdir_demo', mdf), memory=memory) as input_file: + if input_file.version == '2.00': + continue + print(mdf, memory) + for channel_name, original_unit in UNITS.items(): + comment = input_file.get_channel_unit(channel_name) + if comment != original_unit: + print(channel_name, original_unit, comment) + ret = False + + self.assertTrue(ret) + + def test_read_array(self): print("MDF read array tests") diff --git a/test/utils.py b/test/utils.py index c00fe68d1..6f87b29d5 100644 --- a/test/utils.py +++ b/test/utils.py @@ -1590,6 +1590,62 @@ dtype=np.dtype(types), ) +COMMENTS = { + "ASAM.M.VIRTUAL.SCALAR.SWORD.PHYSICAL": "Virtual measurement with 2 * ASAM.M.SCALAR.SBYTE.LINEAR_MUL_2 as input (based on the phys value of ASAM.M.SCALAR.SBYTE.LINEAR_MUL_2", + "ASAM_[0][0].M.MATRIX_DIM_8_2_1.UBYTE.IDENTICAL": "Scalar measurement", + "ASAM_[0].M.MATRIX_DIM_16_1_1.UBYTE.IDENTICAL": "Scalar measurement", + "ASAM_[0].M.ARRAY_SIZE_16.UBYTE.IDENTICAL": "Scalar measurement", + "ASAM.M.SCALAR.UBYTE.TAB_NOINTP_DEFAULT_VALUE": "Scalar measurement with verbal conversion and default value", + "ASAM.M.SCALAR.UBYTE.TAB_INTP_NO_DEFAULT_VALUE": "Scalar measurement with verbal conversion and default value", + "ASAM.M.SCALAR.UBYTE.TAB_INTP_DEFAULT_VALUE": "Scalar measurement with verbal conversion and default value", + "ASAM.M.SCALAR.UBYTE.IDENTICAL": "Scalar measurement", + "ASAM.M.SCALAR.UBYTE.FORM_X_PLUS_4": "Scalar measurement", + "ASAM.M.SCALAR.SWORD.IDENTICAL": "Scalar measurement", + "ASAM.M.SCALAR.SLONG.IDENTICAL": "Scalar measurement", + "ASAM.M.SCALAR.SBYTE.LINEAR_MUL_2": "Scalar measurement", + "ASAM.M.SCALAR.UWORD.IDENTICAL.BITMASK_0FF0": "Scalar measurement with Bitmask for a bit-area", + "ASAM.M.SCALAR.UWORD.IDENTICAL.BITMASK_0008": "Scalar measurement with Bitmask for a single bit", + "ASAM.M.SCALAR.UWORD.IDENTICAL": "Scalar measurement", + "ASAM.M.SCALAR.ULONG.IDENTICAL": "Scalar measurement", + "ASAM.M.SCALAR.UBYTE.VTAB_RANGE_NO_DEFAULT_VALUE": "Scalar measurement with verbal conversion and default value", + "ASAM.M.SCALAR.UBYTE.VTAB_RANGE_DEFAULT_VALUE": "Scalar measurement with verbal conversion and default value", + "ASAM.M.SCALAR.UBYTE.TAB_VERB_NO_DEFAULT_VALUE": "Scalar measurement with verbal conversion", + "ASAM.M.SCALAR.UBYTE.TAB_VERB_DEFAULT_VALUE": "Scalar measurement with verbal conversion and default value", + "ASAM.M.SCALAR.UBYTE.TAB_NOINTP_NO_DEFAULT_VALUE": "Scalar measurement with verbal conversion and default value", + "ASAM.M.SCALAR.FLOAT64.IDENTICAL": "Scalar measurement", + "ASAM.M.SCALAR.FLOAT32.IDENTICAL": "Scalar measurement", + "$CalibrationLog": "", + "$ActiveCalibrationPage": "", +} + +UNITS = { + "ASAM.M.VIRTUAL.SCALAR.SWORD.PHYSICAL": "", + "ASAM_[0][0].M.MATRIX_DIM_8_2_1.UBYTE.IDENTICAL": "hours", + "ASAM_[0].M.MATRIX_DIM_16_1_1.UBYTE.IDENTICAL": "hours", + "ASAM_[0].M.ARRAY_SIZE_16.UBYTE.IDENTICAL": "hours", + "ASAM.M.SCALAR.UBYTE.TAB_NOINTP_DEFAULT_VALUE": "U/ min", + "ASAM.M.SCALAR.UBYTE.TAB_INTP_NO_DEFAULT_VALUE": "U/ min", + "ASAM.M.SCALAR.UBYTE.TAB_INTP_DEFAULT_VALUE": "U/ min", + "ASAM.M.SCALAR.UBYTE.IDENTICAL": "hours", + "ASAM.M.SCALAR.UBYTE.FORM_X_PLUS_4": "rpm", + "ASAM.M.SCALAR.SWORD.IDENTICAL": "hours", + "ASAM.M.SCALAR.SLONG.IDENTICAL": "hours", + "ASAM.M.SCALAR.SBYTE.LINEAR_MUL_2": "m/s", + "ASAM.M.SCALAR.UWORD.IDENTICAL.BITMASK_0FF0": "hours", + "ASAM.M.SCALAR.UWORD.IDENTICAL.BITMASK_0008": "hours", + "ASAM.M.SCALAR.UWORD.IDENTICAL": "hours", + "ASAM.M.SCALAR.ULONG.IDENTICAL": "hours", + "ASAM.M.SCALAR.UBYTE.VTAB_RANGE_NO_DEFAULT_VALUE": "", + "ASAM.M.SCALAR.UBYTE.VTAB_RANGE_DEFAULT_VALUE": "", + "ASAM.M.SCALAR.UBYTE.TAB_VERB_NO_DEFAULT_VALUE": "", + "ASAM.M.SCALAR.UBYTE.TAB_VERB_DEFAULT_VALUE": "", + "ASAM.M.SCALAR.UBYTE.TAB_NOINTP_NO_DEFAULT_VALUE": "U/ min", + "ASAM.M.SCALAR.FLOAT64.IDENTICAL": "hours", + "ASAM.M.SCALAR.FLOAT32.IDENTICAL": "hours", + "$CalibrationLog": "", + "$ActiveCalibrationPage": "", +} + def get_test_data(filename=""): """ Utility functions needed by all test scripts. From 474989e4669283464238230e18e2dbc822f3a502 Mon Sep 17 00:00:00 2001 From: danielhrisca Date: Sun, 31 Dec 2017 11:01:13 +0200 Subject: [PATCH 074/117] fix save methods --- asammdf/mdf_v2_v3.py | 87 ++++++++++++++++++++++++++++++------------- asammdf/mdf_v4.py | 50 ++++++++++++++++++++++--- test/test_mdf.py | 88 +++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 193 insertions(+), 32 deletions(-) diff --git a/asammdf/mdf_v2_v3.py b/asammdf/mdf_v2_v3.py index 9884cb10a..b0c1bd3b8 100644 --- a/asammdf/mdf_v2_v3.py +++ b/asammdf/mdf_v2_v3.py @@ -640,6 +640,7 @@ def _read(self): kargs['block_len'] = v23c.DG_POST_320_BLOCK_SIZE else: kargs['block_len'] = v23c.DG_PRE_320_BLOCK_SIZE + kargs['record_id_nr'] = record_id_nr grp['data_group'] = DataGroup(**kargs) @@ -2879,36 +2880,35 @@ def save(self, dst='', overwrite=None, compression=0): does nothing for mdf version3; introduced here to share the same API as mdf version 4 files + Returns + ------- + output_file : str + output file name + """ if overwrite is None: overwrite = self._overwrite + output_file = '' if self.name is None and dst == '': message = ('Must specify a destination file name ' 'for MDF created from scratch') raise MdfException(message) - dst = dst if dst else self.name - if overwrite is False: - if os.path.isfile(dst): - cntr = 0 - while True: - name = os.path.splitext(dst)[0] + '_{}.mdf'.format(cntr) - if not os.path.isfile(name): - break - else: - cntr += 1 - message = ('Destination file "{}" already exists ' - 'and "overwrite" is False. Saving MDF file as "{}"') - message = message.format(dst, name) - warnings.warn(message) - dst = name - - if self.memory != 'minimum': - self._save_with_metadata(dst, overwrite, compression) + if self.memory == 'minimum': + output_file = self._save_without_metadata( + dst, + overwrite, + compression, + ) else: - self._save_without_metadata(dst, overwrite, compression) + output_file = self._save_with_metadata( + dst, + overwrite, + compression, + ) + return output_file def _save_with_metadata(self, dst, overwrite, compression): """Save MDF to *dst*. If *dst* is not provided the the destination file @@ -2954,6 +2954,7 @@ def _save_with_metadata(self, dst, overwrite, compression): raise MdfException(message) dst = dst if dst else self.name + dst = os.path.splitext(dst)[0] + '.mdf' if overwrite is False: if os.path.isfile(dst): cntr = 0 @@ -3012,8 +3013,11 @@ def _save_with_metadata(self, dst, overwrite, compression): # put them first in the block list so they will be written first to # disk this way, in case of memory=False, we can safely # restore he original data block address + gp_rec_ids = [] for gp in self.groups: dg = gp['data_group'] + gp_rec_ids.append(dg['record_id_nr']) + dg['record_id_nr'] = 0 blocks.append(dg) dg.address = address address += dg['block_len'] @@ -3024,7 +3028,7 @@ def _save_with_metadata(self, dst, overwrite, compression): dg['data_group']['next_dg_addr'] = addr self.groups[-1]['data_group']['next_dg_addr'] = 0 - for gp in self.groups: + for idx, gp in enumerate(self.groups): gp_texts = gp['texts'] # Texts @@ -3124,9 +3128,9 @@ def _save_with_metadata(self, dst, overwrite, compression): trigger_text.address = address blocks.append(trigger_text) address += trigger_text['block_len'] - trigger['comment_addr'] = trigger_text.address + trigger['text_addr'] = trigger_text.address else: - trigger['comment_addr'] = 0 + trigger['text_addr'] = 0 trigger.address = address blocks.append(trigger) @@ -3138,7 +3142,7 @@ def _save_with_metadata(self, dst, overwrite, compression): gp['data_group']['data_block_addr'] = address else: gp['data_group']['data_block_addr'] = 0 - address += gp['size'] + address += gp['size'] - gp_rec_ids[idx] * gp['channel_group']['cycles_nr'] if self.memory == 'full': blocks.append(gp['data_block']) else: @@ -3191,6 +3195,9 @@ def _save_with_metadata(self, dst, overwrite, compression): data = self._load_group_data(gp) write(data) + for gp, rec_id in zip(self.groups, gp_rec_ids): + gp['data_group']['record_id_nr'] = rec_id + if self.memory == 'low' and dst == self.name: self.close() os.remove(self.name) @@ -3211,6 +3218,7 @@ def _save_with_metadata(self, dst, overwrite, compression): self._tempfile = TemporaryFile() self._file = open(self.name, 'rb') self._read() + return dst def _save_without_metadata(self, dst, overwrite, compression): """Save MDF to *dst*. If *dst* is not provided the the destination file @@ -3265,6 +3273,28 @@ def _save_without_metadata(self, dst, overwrite, compression): # the reference to the data group object and the original link to the # data block in the soource MDF file. + if self.name is None and dst == '': + message = ('Must specify a destination file name ' + 'for MDF created from scratch') + raise MdfException(message) + + dst = dst if dst else self.name + dst = os.path.splitext(dst)[0] + '.mdf' + if overwrite is False: + if os.path.isfile(dst): + cntr = 0 + while True: + name = os.path.splitext(dst)[0] + '_{}.mdf'.format(cntr) + if not os.path.isfile(name): + break + else: + cntr += 1 + message = ('Destination file "{}" already exists ' + 'and "overwrite" is False. Saving MDF file as "{}"') + message = message.format(dst, name) + warnings.warn(message) + dst = name + if dst == self.name: destination = dst + '.temp' else: @@ -3430,9 +3460,9 @@ def _save_without_metadata(self, dst, overwrite, compression): if trigger_text: trigger_text.address = address write(bytes(trigger_text)) - trigger['comment_addr'] = trigger_text.address + trigger['text_addr'] = trigger_text.address else: - trigger['comment_addr'] = 0 + trigger['text_addr'] = 0 address = tell() trigger.address = address @@ -3454,8 +3484,11 @@ def _save_without_metadata(self, dst, overwrite, compression): orig_addr = [gp['data_group']['data_block_addr'] for gp in self.groups] address = tell() + gp_rec_ids = [] for i, gp in enumerate(self.groups): dg = gp['data_group'] + gp_rec_ids.append(dg['record_id_nr']) + dg['record_id_nr'] = 0 dg['data_block_addr'] = data_address[i] dg.address = address address += dg['block_len'] @@ -3475,6 +3508,9 @@ def _save_without_metadata(self, dst, overwrite, compression): write(bytes(gp['data_group'])) gp['data_block_addr'] = orig_addr[i] + for gp, rec_id in zip(self.groups, gp_rec_ids): + gp['data_group']['record_id_nr'] = rec_id + if self.groups: address = self.groups[0]['data_group'].address self.header['first_dg_addr'] = address @@ -3523,6 +3559,7 @@ def _save_without_metadata(self, dst, overwrite, compression): self._tempfile = TemporaryFile() self._file = open(self.name, 'rb') self._read() + return dst if __name__ == '__main__': diff --git a/asammdf/mdf_v4.py b/asammdf/mdf_v4.py index af37be76b..1ff6286c9 100644 --- a/asammdf/mdf_v4.py +++ b/asammdf/mdf_v4.py @@ -3872,9 +3872,15 @@ def save(self, dst='', overwrite=None, compression=0): * 2 - transposition + deflate (slowest, but produces the smallest files) + Returns + ------- + output_file : str + output file name + """ if overwrite is None: overwrite = self._overwrite + output_file = '' if self.name is None and dst == '': message = ('Must specify a destination file name ' @@ -3882,9 +3888,18 @@ def save(self, dst='', overwrite=None, compression=0): raise MdfException(message) else: if self.memory == 'minimum': - self._save_without_metadata(dst, overwrite, compression) + output_file = self._save_without_metadata( + dst, + overwrite, + compression, + ) else: - self._save_with_metadata(dst, overwrite, compression) + output_file = self._save_with_metadata( + dst, + overwrite, + compression, + ) + return output_file def _save_with_metadata(self, dst, overwrite, compression): """Save MDF to *dst*. If *dst* is not provided the the destination file @@ -3914,6 +3929,7 @@ def _save_with_metadata(self, dst, overwrite, compression): raise MdfException(message) dst = dst if dst else self.name + dst = os.path.splitext(dst)[0] + '.mf4' if overwrite is False: if os.path.isfile(dst): cntr = 0 @@ -3982,8 +3998,11 @@ def _save_with_metadata(self, dst, overwrite, compression): samples_size = gp['channel_group']['samples_byte_nr'] split_size = MDF4._split_threshold // samples_size split_size *= samples_size - chunks = len(data) / split_size - chunks = int(ceil(chunks)) + if split_size == 0: + chunks = 1 + else: + chunks = len(data) / split_size + chunks = int(ceil(chunks)) else: chunks = 1 @@ -4119,7 +4138,10 @@ def _save_with_metadata(self, dst, overwrite, compression): self.file_history[-1][0]['next_fh_addr'] = 0 # data groups + gp_rec_ids = [] for gp in self.groups: + gp_rec_ids.append(gp['data_group']['record_id_len']) + gp['data_group']['record_id_len'] = 0 gp['data_group'].address = address address += gp['data_group']['block_len'] blocks.append(gp['data_group']) @@ -4306,6 +4328,9 @@ def _save_with_metadata(self, dst, overwrite, compression): for block in blocks: write(bytes(block)) + for gp, rec_id in zip(self.groups, gp_rec_ids): + gp['data_group']['record_id_len'] = rec_id + if self.groups: addr_ = self.groups[0]['data_group'].address self.header['first_dg_addr'] = addr_ @@ -4349,6 +4374,8 @@ def _save_with_metadata(self, dst, overwrite, compression): self._file = open(self.name, 'rb') self._read() + return dst + def _save_without_metadata(self, dst, overwrite, compression): """Save MDF to *dst*. If *dst* is not provided the the destination file name is the MDF name. If overwrite is *True* then the destination file @@ -4377,6 +4404,7 @@ def _save_without_metadata(self, dst, overwrite, compression): raise MdfException(message) dst = dst if dst else self.name + dst = os.path.splitext(dst)[0] + '.mf4' if overwrite is False: if os.path.isfile(dst): cntr = 0 @@ -4445,8 +4473,11 @@ def _save_without_metadata(self, dst, overwrite, compression): samples_size = gp['channel_group']['samples_byte_nr'] split_size = MDF4._split_threshold // samples_size split_size *= samples_size - chunks = len(data) / split_size - chunks = int(ceil(chunks)) + if split_size == 0: + chunks = 1 + else: + chunks = len(data) / split_size + chunks = int(ceil(chunks)) else: chunks = 1 @@ -4808,9 +4839,12 @@ def _save_without_metadata(self, dst, overwrite, compression): blocks = [] address = tell() + gp_rec_ids = [] # data groups for gp in self.groups: gp['data_group'].address = address + gp_rec_ids.append(gp['data_group']['record_id_len']) + gp['data_group']['record_id_len'] = 0 address += gp['data_group']['block_len'] blocks.append(gp['data_group']) @@ -4824,6 +4858,9 @@ def _save_without_metadata(self, dst, overwrite, compression): for block in blocks: write(bytes(block)) + for gp, rec_id in zip(self.groups, gp_rec_ids): + gp['data_group']['record_id_len'] = rec_id + if self.groups: addr_ = self.groups[0]['data_group'].address self.header['first_dg_addr'] = addr_ @@ -4884,3 +4921,4 @@ def _save_without_metadata(self, dst, overwrite, compression): self._tempfile = TemporaryFile() self._file = open(self.name, 'rb') self._read() + return dst diff --git a/test/test_mdf.py b/test/test_mdf.py index 19c4c7f2e..11c95d7ff 100644 --- a/test/test_mdf.py +++ b/test/test_mdf.py @@ -6,6 +6,7 @@ import unittest import shutil import urllib +from itertools import product from zipfile import ZipFile @@ -58,7 +59,7 @@ def tearDownClass(cls): shutil.rmtree('tmpdir_demo', True) shutil.rmtree('tmpdir_array', True) os.remove('test.zip') - for filename in ('tmp', 'tmp1', 'tmp2'): + for filename in ('tmpx', 'tmp1', 'tmp2'): if os.path.isfile(filename): os.remove(filename) @@ -684,6 +685,91 @@ def test_filter_array(self): self.assertTrue(equal) + def test_save(self): + print("MDF save tests") + + compressions = [0, 1, 2] + split_sizes = [260, 10**5] + split_enables = [True, False] + overwrite_enables = [True, False] + for compression, memory, size, split_enable, overwrite in product(compressions, MEMORY, split_sizes, split_enables, overwrite_enables): + configure( + integer_compacting=False, + split_data_blocks=split_enable, + split_threshold=size, + overwrite=overwrite, + ) + + for mdfname in os.listdir('tmpdir_demo'): + input_file = os.path.join('tmpdir_demo', mdfname) + if MDF(input_file).version == '2.00': + continue + print(input_file, compression, memory, size, split_enable, overwrite) + with MDF(input_file, memory=memory) as mdf: + out_file = mdf.save('tmp', compression=compression) + print(out_file) + + equal = True + + with MDF(input_file, memory=memory) as mdf, \ + MDF(out_file, memory=memory) as mdf2: + + for name in set(mdf.channels_db) - {'t', 'time'}: + original = mdf.get(name) + converted = mdf2.get(name) + if not np.array_equal( + original.samples, + converted.samples): + print(name, original, converted) + equal = False + if not np.array_equal( + original.timestamps, + converted.timestamps): + equal = False + + self.assertTrue(equal) + + def test_save_array(self): + print("MDF save array tests") + + compressions = [0, 1, 2] + split_sizes = [260, 10**5] + split_enables = [True, False] + overwrite_enables = [True, False] + for compression, memory, size, split_enable, overwrite in product(compressions, MEMORY, split_sizes, split_enables, overwrite_enables): + configure( + integer_compacting=False, + split_data_blocks=split_enable, + split_threshold=size, + overwrite=overwrite, + ) + + for mdfname in os.listdir('tmpdir_array'): + input_file = os.path.join('tmpdir_array', mdfname) + print(input_file, compression, memory, size, split_enable, overwrite) + with MDF(input_file, memory=memory) as mdf: + out_file = mdf.save('tmp', compression=compression) + + equal = True + + with MDF(input_file, memory=memory) as mdf, \ + MDF(out_file, memory=memory) as mdf2: + + for name in set(mdf.channels_db) - {'t', 'time'}: + original = mdf.get(name) + converted = mdf2.get(name) + if not np.array_equal( + original.samples, + converted.samples): + print(name, original, converted) + equal = False + if not np.array_equal( + original.timestamps, + converted.timestamps): + equal = False + + self.assertTrue(equal) + def test_select(self): print("MDF select tests") From 8b33eb791af250fcd4b6da649c18d5cecf606c61 Mon Sep 17 00:00:00 2001 From: danielhrisca Date: Sun, 31 Dec 2017 11:07:32 +0200 Subject: [PATCH 075/117] cleanup folder after tests --- test/test_mdf.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/test_mdf.py b/test/test_mdf.py index 11c95d7ff..4814743bd 100644 --- a/test/test_mdf.py +++ b/test/test_mdf.py @@ -59,8 +59,8 @@ def tearDownClass(cls): shutil.rmtree('tmpdir_demo', True) shutil.rmtree('tmpdir_array', True) os.remove('test.zip') - for filename in ('tmpx', 'tmp1', 'tmp2'): - if os.path.isfile(filename): + for filename in os.listdir(): + if os.path.isfile(filename) and filename.startswith('tmp'): os.remove(filename) def test_read(self): From 4fc1e868a95f9c4766990ed12dfa327a5c6b0a84 Mon Sep 17 00:00:00 2001 From: danielhrisca Date: Sun, 31 Dec 2017 11:21:17 +0200 Subject: [PATCH 076/117] fix tests to use the new returned saved file name --- test/test_mdf.py | 116 ++++++++++++++++++++++----------------------- test/test_mdf23.py | 24 ++++------ test/test_mdf4.py | 14 ++---- 3 files changed, 71 insertions(+), 83 deletions(-) diff --git a/test/test_mdf.py b/test/test_mdf.py index 4814743bd..4635e7d92 100644 --- a/test/test_mdf.py +++ b/test/test_mdf.py @@ -163,13 +163,13 @@ def test_convert(self): continue print(input_file, memory, out) with MDF(input_file, memory=memory) as mdf: - mdf.convert(out, memory=memory).save('tmp', + outfile = mdf.convert(out, memory=memory).save('tmp', overwrite=True) equal = True with MDF(input_file, memory=memory) as mdf, \ - MDF('tmp', memory=memory) as mdf2: + MDF(outfile, memory=memory) as mdf2: for name in set(mdf.channels_db) - {'t', 'time'}: original = mdf.get(name) @@ -197,12 +197,12 @@ def test_merge(self): input_file = os.path.join('tmpdir_demo', mdfname) files = [input_file, ] * 4 - MDF.merge(files, out, memory).save('tmp', overwrite=True) + outfile = MDF.merge(files, out, memory).save('tmp', overwrite=True) equal = True with MDF(input_file, memory=memory) as mdf, \ - MDF('tmp', memory=memory) as mdf2: + MDF(outfile, memory=memory) as mdf2: for i, group in enumerate(mdf.groups): for j, _ in enumerate(group['channels'][1:], 1): @@ -225,12 +225,12 @@ def test_merge(self): continue files = [input_file, ] * 4 - MDF.merge(files, out, memory).save('tmp', overwrite=True) + outfile = MDF.merge(files, out, memory).save('tmp', overwrite=True) equal = True with MDF(input_file, memory=memory) as mdf, \ - MDF('tmp', memory=memory) as mdf2: + MDF(outfile, memory=memory) as mdf2: for name in set(mdf.channels_db) - {'t', 'time'}: original = mdf.get(name) @@ -254,12 +254,12 @@ def test_merge_array(self): input_file = os.path.join('tmpdir_array', mdfname) files = [input_file, ] * 4 - MDF.merge(files, out, memory).save('tmp', overwrite=True) + outfile = MDF.merge(files, out, memory).save('tmp', overwrite=True) equal = True with MDF(input_file, memory=memory) as mdf, \ - MDF('tmp', memory=memory) as mdf2: + MDF(outfile, memory=memory) as mdf2: for i, group in enumerate(mdf.groups): for j, _ in enumerate(group['channels'][1:], 1): @@ -280,12 +280,12 @@ def test_merge_array(self): input_file = os.path.join('tmpdir_array', mdfname) files = [input_file, ] * 4 - MDF.merge(files, out, memory).save('tmp', overwrite=True) + outfile = MDF.merge(files, out, memory).save('tmp', overwrite=True) equal = True with MDF(input_file, memory=memory) as mdf, \ - MDF('tmp', memory=memory) as mdf2: + MDF(outfile, memory=memory) as mdf2: for name in set(mdf.channels_db) - {'t', 'time'}: original = mdf.get(name) @@ -306,19 +306,19 @@ def test_cut_absolute(self): for memory in MEMORY: input_file = os.path.join('tmpdir_demo', mdfname) - MDF(input_file, memory=memory).cut(stop=2).save('tmp1', overwrite=True) - MDF(input_file, memory=memory).cut(start=2, stop=6).save('tmp2', overwrite=True) - MDF(input_file, memory=memory).cut(start=6).save('tmp3', overwrite=True) + outfile1 = MDF(input_file, memory=memory).cut(stop=2).save('tmp1', overwrite=True) + outfile2 = MDF(input_file, memory=memory).cut(start=2, stop=6).save('tmp2', overwrite=True) + outfile3 = MDF(input_file, memory=memory).cut(start=6).save('tmp3', overwrite=True) - MDF.merge( - ['tmp1', 'tmp2', 'tmp3'], + outfile = MDF.merge( + [outfile1, outfile2, outfile3], MDF(input_file, memory='minimum').version, ).save('tmp', overwrite=True) equal = True with MDF(input_file, memory=memory) as mdf, \ - MDF('tmp', memory=memory) as mdf2: + MDF(outfile, memory=memory) as mdf2: for i, group in enumerate(mdf.groups): for j, _ in enumerate(group['channels'][1:], 1): @@ -343,19 +343,19 @@ def test_cut_absolute(self): if '2.00' in input_file: continue - MDF(input_file, memory=memory).cut(stop=2).save('tmp1', overwrite=True) - MDF(input_file, memory=memory).cut(start=2, stop=6).save('tmp2', overwrite=True) - MDF(input_file, memory=memory).cut(start=6).save('tmp3', overwrite=True) + outfile1 = MDF(input_file, memory=memory).cut(stop=2).save('tmp1', overwrite=True) + outfile2 = MDF(input_file, memory=memory).cut(start=2, stop=6).save('tmp2', overwrite=True) + outfile3 = MDF(input_file, memory=memory).cut(start=6).save('tmp3', overwrite=True) - MDF.merge( - ['tmp1', 'tmp2', 'tmp3'], + outfile = MDF.merge( + [outfile1, outfile2, outfile3], MDF(input_file, memory='minimum').version, ).save('tmp', overwrite=True) equal = True with MDF(input_file, memory=memory) as mdf, \ - MDF('tmp', memory=memory) as mdf2: + MDF(outfile, memory=memory) as mdf2: for name in set(mdf.channels_db) - {'time', 't'}: original = mdf.get(name) @@ -382,19 +382,19 @@ def test_cut_absolute_array(self): for memory in MEMORY: input_file = os.path.join('tmpdir_array', mdfname) - MDF(input_file, memory=memory).cut(stop=2.1).save('tmp1', overwrite=True) - MDF(input_file, memory=memory).cut(start=2.1, stop=6.1).save('tmp2', overwrite=True) - MDF(input_file, memory=memory).cut(start=6.1).save('tmp3', overwrite=True) + outfile1 = MDF(input_file, memory=memory).cut(stop=2.1).save('tmp1', overwrite=True) + outfile2 = MDF(input_file, memory=memory).cut(start=2.1, stop=6.1).save('tmp2', overwrite=True) + outfile3 = MDF(input_file, memory=memory).cut(start=6.1).save('tmp3', overwrite=True) - MDF.merge( - ['tmp1', 'tmp2', 'tmp3'], + outfile = MDF.merge( + [outfile1, outfile2, outfile3], MDF(input_file, memory='minimum').version, ).save('tmp', overwrite=True) equal = True with MDF(input_file, memory=memory) as mdf, \ - MDF('tmp', memory=memory) as mdf2: + MDF(outfile, memory=memory) as mdf2: for i, group in enumerate(mdf.groups): for j, _ in enumerate(group['channels'][1:], 1): @@ -417,19 +417,19 @@ def test_cut_absolute_array(self): for memory in MEMORY: input_file = os.path.join('tmpdir_array', mdfname) - MDF(input_file, memory=memory).cut(stop=2.1).save('tmp1', overwrite=True) - MDF(input_file, memory=memory).cut(start=2.1, stop=6.1).save('tmp2', overwrite=True) - MDF(input_file, memory=memory).cut(start=6.1).save('tmp3', overwrite=True) + outfile1 = MDF(input_file, memory=memory).cut(stop=2.1).save('tmp1', overwrite=True) + outfile2 = MDF(input_file, memory=memory).cut(start=2.1, stop=6.1).save('tmp2', overwrite=True) + outfile3 = MDF(input_file, memory=memory).cut(start=6.1).save('tmp3', overwrite=True) - MDF.merge( - ['tmp1', 'tmp2', 'tmp3'], + outfile = MDF.merge( + [outfile1, outfile2, outfile3], MDF(input_file, memory='minimum').version, ).save('tmp', overwrite=True) equal = True with MDF(input_file, memory=memory) as mdf, \ - MDF('tmp', memory=memory) as mdf2: + MDF(outfile, memory=memory) as mdf2: for name in set(mdf.channels_db) - {'time', 't'}: original = mdf.get(name) @@ -456,19 +456,19 @@ def test_cut_relative(self): if '2.00' in input_file: continue - MDF(input_file, memory=memory).cut(stop=3, whence=1).save('tmp1', overwrite=True) - MDF(input_file, memory=memory).cut(start=3, stop=5, whence=1).save('tmp2', overwrite=True) - MDF(input_file, memory=memory).cut(start=5, whence=1).save('tmp3', overwrite=True) + outfile1 = MDF(input_file, memory=memory).cut(stop=3, whence=1).save('tmp1', overwrite=True) + outfile2 = MDF(input_file, memory=memory).cut(start=3, stop=5, whence=1).save('tmp2', overwrite=True) + outfile3 = MDF(input_file, memory=memory).cut(start=5, whence=1).save('tmp3', overwrite=True) - MDF.merge( - ['tmp1', 'tmp2', 'tmp3'], + outfile = MDF.merge( + [outfile1, outfile2, outfile3], MDF(input_file, memory='minimum').version, ).save('tmp', overwrite=True) equal = True with MDF(input_file, memory=memory) as mdf, \ - MDF('tmp', memory=memory) as mdf2: + MDF(outfile, memory=memory) as mdf2: for i, group in enumerate(mdf.groups): for j, _ in enumerate(group['channels'][1:], 1): @@ -491,19 +491,19 @@ def test_cut_relative(self): for memory in MEMORY: input_file = os.path.join('tmpdir_demo', mdfname) - MDF(input_file, memory=memory).cut(stop=3, whence=1).save('tmp1', overwrite=True) - MDF(input_file, memory=memory).cut(start=3, stop=5, whence=1).save('tmp2', overwrite=True) - MDF(input_file, memory=memory).cut(start=5, whence=1).save('tmp3', overwrite=True) + outfile1 = MDF(input_file, memory=memory).cut(stop=3, whence=1).save('tmp1', overwrite=True) + outfile2 = MDF(input_file, memory=memory).cut(start=3, stop=5, whence=1).save('tmp2', overwrite=True) + outfile3 = MDF(input_file, memory=memory).cut(start=5, whence=1).save('tmp3', overwrite=True) - MDF.merge( - ['tmp1', 'tmp2', 'tmp3'], + outfile = MDF.merge( + [outfile1, outfile2, outfile3], MDF(input_file, memory='minimum').version, ).save('tmp', overwrite=True) equal = True with MDF(input_file, memory=memory) as mdf, \ - MDF('tmp', memory=memory) as mdf2: + MDF(outfile, memory=memory) as mdf2: for name in set(mdf.channels_db) - {'time', 't'}: original = mdf.get(name) @@ -528,19 +528,19 @@ def test_cut_relative_array(self): for memory in MEMORY: input_file = os.path.join('tmpdir_array', mdfname) - MDF(input_file, memory=memory).cut(stop=3.1, whence=1).save('tmp1', overwrite=True) - MDF(input_file, memory=memory).cut(start=3.1, stop=5.1, whence=1).save('tmp2', overwrite=True) - MDF(input_file, memory=memory).cut(start=5.1, whence=1).save('tmp3', overwrite=True) + outfile1 = MDF(input_file, memory=memory).cut(stop=3.1, whence=1).save('tmp1', overwrite=True) + outfile2 = MDF(input_file, memory=memory).cut(start=3.1, stop=5.1, whence=1).save('tmp2', overwrite=True) + outfile3 = MDF(input_file, memory=memory).cut(start=5.1, whence=1).save('tmp3', overwrite=True) - MDF.merge( - ['tmp1', 'tmp2', 'tmp3'], + outfile = MDF.merge( + [outfile1, outfile2, outfile3], MDF(input_file, memory='minimum').version, ).save('tmp', overwrite=True) equal = True with MDF(input_file, memory=memory) as mdf, \ - MDF('tmp', memory=memory) as mdf2: + MDF(outfile, memory=memory) as mdf2: for i, group in enumerate(mdf.groups): for j, _ in enumerate(group['channels'][1:], 1): @@ -563,19 +563,19 @@ def test_cut_relative_array(self): for memory in MEMORY: input_file = os.path.join('tmpdir_array', mdfname) - MDF(input_file, memory=memory).cut(stop=3.1, whence=1).save('tmp1', overwrite=True) - MDF(input_file, memory=memory).cut(start=3.1, stop=5.1, whence=1).save('tmp2', overwrite=True) - MDF(input_file, memory=memory).cut(start=5.1, whence=1).save('tmp3', overwrite=True) + outfile1 = MDF(input_file, memory=memory).cut(stop=3.1, whence=1).save('tmp1', overwrite=True) + outfile2 = MDF(input_file, memory=memory).cut(start=3.1, stop=5.1, whence=1).save('tmp2', overwrite=True) + outfile3 = MDF(input_file, memory=memory).cut(start=5.1, whence=1).save('tmp3', overwrite=True) - MDF.merge( - ['tmp1', 'tmp2', 'tmp3'], + outfile = MDF.merge( + [outfile1, outfile2, outfile3], MDF(input_file, memory='minimum').version, ).save('tmp', overwrite=True) equal = True with MDF(input_file, memory=memory) as mdf, \ - MDF('tmp', memory=memory) as mdf2: + MDF(outfile, memory=memory) as mdf2: for name in set(mdf.channels_db) - {'time', 't'}: original = mdf.get(name) diff --git a/test/test_mdf23.py b/test/test_mdf23.py index bafc056e6..0c5705799 100644 --- a/test/test_mdf23.py +++ b/test/test_mdf23.py @@ -46,9 +46,9 @@ def test_read_mdf2_00(self): with MDF(version='2.00', memory=memory) as mdf: mdf.append([sig_int, sig_float], common_timebase=True) - mdf.save('tmp', overwrite=True) + outfile = mdf.save('tmp', overwrite=True) - with MDF('tmp', memory=memory) as mdf: + with MDF(outfile, memory=memory) as mdf: ret_sig_int = mdf.get(sig_int.name) ret_sig_float = mdf.get(sig_float.name) @@ -57,8 +57,6 @@ def test_read_mdf2_00(self): self.assertTrue(np.array_equal(ret_sig_float.samples, sig_float.samples)) - os.remove('tmp') - def test_read_mdf2_14(self): seed = np.random.randint(0, 2**31) @@ -83,9 +81,9 @@ def test_read_mdf2_14(self): for memory in MEMORY: with MDF(version='2.14', memory=memory) as mdf: mdf.append([sig_int, sig_float], common_timebase=True) - mdf.save('tmp', overwrite=True) + outfile = mdf.save('tmp', overwrite=True) - with MDF('tmp', memory=memory) as mdf: + with MDF(outfile, memory=memory) as mdf: ret_sig_int = mdf.get(sig_int.name) ret_sig_float = mdf.get(sig_float.name) @@ -94,8 +92,6 @@ def test_read_mdf2_14(self): self.assertTrue(np.array_equal(ret_sig_float.samples, sig_float.samples)) - os.remove('tmp') - def test_read_mdf3_00(self): seed = np.random.randint(0, 2**31) @@ -121,9 +117,9 @@ def test_read_mdf3_00(self): with MDF(version='3.00', memory=memory) as mdf: mdf.append([sig_int, sig_float], common_timebase=True) - mdf.save('tmp', overwrite=True) + outfile = mdf.save('tmp', overwrite=True) - with MDF('tmp', memory=memory) as mdf: + with MDF(outfile, memory=memory) as mdf: ret_sig_int = mdf.get(sig_int.name) ret_sig_float = mdf.get(sig_float.name) @@ -132,8 +128,6 @@ def test_read_mdf3_00(self): self.assertTrue(np.array_equal(ret_sig_float.samples, sig_float.samples)) - os.remove('tmp') - def test_read_mdf3_10(self): seed = np.random.randint(0, 2**31) @@ -158,9 +152,9 @@ def test_read_mdf3_10(self): for memory in MEMORY: with MDF(version='3.10', memory=memory) as mdf: mdf.append([sig_int, sig_float], common_timebase=True) - mdf.save('tmp', overwrite=True) + outfile = mdf.save('tmp', overwrite=True) - with MDF('tmp', memory=memory) as mdf: + with MDF(outfile, memory=memory) as mdf: ret_sig_int = mdf.get(sig_int.name) ret_sig_float = mdf.get(sig_float.name) @@ -169,8 +163,6 @@ def test_read_mdf3_10(self): self.assertTrue(np.array_equal(ret_sig_float.samples, sig_float.samples)) - os.remove('tmp') - if __name__ == '__main__': unittest.main() diff --git a/test/test_mdf4.py b/test/test_mdf4.py index a0d7f7430..6b5af02b5 100644 --- a/test/test_mdf4.py +++ b/test/test_mdf4.py @@ -41,9 +41,9 @@ def test_read_mdf4_00(self): with MDF(version='4.00', memory=memory) as mdf: mdf.append([sig_int, sig_float], common_timebase=True) - mdf.save('tmp', overwrite=True) + outfile = mdf.save('tmp', overwrite=True) - with MDF('tmp', memory=memory) as mdf: + with MDF(outfile, memory=memory) as mdf: ret_sig_int = mdf.get(sig_int.name) ret_sig_float = mdf.get(sig_float.name) @@ -52,9 +52,7 @@ def test_read_mdf4_00(self): self.assertTrue(np.array_equal(ret_sig_float.samples, sig_float.samples)) - os.remove('tmp') - - def test_read_mdf4_10(self): + def test_read_mdf4_10(self): seed = np.random.randint(0, 2**31) @@ -78,9 +76,9 @@ def test_read_mdf4_10(self): for memory in MEMORY: with MDF(version='4.10', memory=memory) as mdf: mdf.append([sig_int, sig_float], common_timebase=True) - mdf.save('tmp', overwrite=True) + outfile = mdf.save('tmp', overwrite=True) - with MDF('tmp', memory=memory) as mdf: + with MDF(outfile, memory=memory) as mdf: ret_sig_int = mdf.get(sig_int.name) ret_sig_float = mdf.get(sig_float.name) @@ -89,8 +87,6 @@ def test_read_mdf4_10(self): self.assertTrue(np.array_equal(ret_sig_float.samples, sig_float.samples)) - os.remove('tmp') - if __name__ == '__main__': unittest.main() From fe25aa1a27140e112b06f87090221d8bc00765d4 Mon Sep 17 00:00:00 2001 From: danielhrisca Date: Sun, 31 Dec 2017 11:27:33 +0200 Subject: [PATCH 077/117] python 2 expects a mandatory argument for os.listdir --- benchmarks/bench.py | 52 ++++++++++++++++++++++----------------------- test/test_mdf.py | 2 +- 2 files changed, 27 insertions(+), 27 deletions(-) diff --git a/benchmarks/bench.py b/benchmarks/bench.py index 1b0105e55..2d429c1d2 100644 --- a/benchmarks/bench.py +++ b/benchmarks/bench.py @@ -560,15 +560,15 @@ def main(path, text_output, fmt): output.append('* 36424 channels\n\n') tests = ( - partial(open_mdf3, memory='full'), - partial(open_mdf3, memory='low'), - partial(open_mdf3, memory='minimum'), +# partial(open_mdf3, memory='full'), +# partial(open_mdf3, memory='low'), +# partial(open_mdf3, memory='minimum'), # open_reader3, # open_reader3_compression, # open_reader3_nodata, - partial(open_mdf4, memory='full'), - partial(open_mdf4, memory='low'), - partial(open_mdf4, memory='minimum'), +# partial(open_mdf4, memory='full'), +# partial(open_mdf4, memory='low'), +# partial(open_mdf4, memory='minimum'), # open_reader4, # open_reader4_compression, # open_reader4_nodata, @@ -586,15 +586,15 @@ def main(path, text_output, fmt): output.extend(table_end(fmt)) tests = ( - partial(save_mdf3, memory='full'), - partial(save_mdf3, memory='low'), - partial(save_mdf3, memory='minimum'), +# partial(save_mdf3, memory='full'), +# partial(save_mdf3, memory='low'), +# partial(save_mdf3, memory='minimum'), # save_reader3, # save_reader3_nodata, # save_reader3_compression, - partial(save_mdf4, memory='full'), - partial(save_mdf4, memory='low'), - partial(save_mdf4, memory='minimum'), +# partial(save_mdf4, memory='full'), +# partial(save_mdf4, memory='low'), +# partial(save_mdf4, memory='minimum'), # save_reader4, # save_reader4_nodata, # save_reader4_compression, @@ -612,15 +612,15 @@ def main(path, text_output, fmt): output.extend(table_end(fmt)) tests = ( - partial(get_all_mdf3, memory='full'), - partial(get_all_mdf3, memory='low'), - partial(get_all_mdf3, memory='minimum'), +# partial(get_all_mdf3, memory='full'), +# partial(get_all_mdf3, memory='low'), +# partial(get_all_mdf3, memory='minimum'), # get_all_reader3, # get_all_reader3_nodata, # get_all_reader3_compression, - partial(get_all_mdf4, memory='full'), - partial(get_all_mdf4, memory='low'), - partial(get_all_mdf4, memory='minimum'), +# partial(get_all_mdf4, memory='full'), +# partial(get_all_mdf4, memory='low'), +# partial(get_all_mdf4, memory='minimum'), # get_all_reader4, # get_all_reader4_nodata, # get_all_reader4_compression, @@ -638,12 +638,12 @@ def main(path, text_output, fmt): output.extend(table_end(fmt)) tests = ( - partial(convert_v3_v4, memory='full'), - partial(convert_v3_v4, memory='low'), - partial(convert_v3_v4, memory='minimum'), - partial(convert_v4_v3, memory='full'), - partial(convert_v4_v3, memory='low'), - partial(convert_v4_v3, memory='minimum'), +# partial(convert_v3_v4, memory='full'), +# partial(convert_v3_v4, memory='low'), +# partial(convert_v3_v4, memory='minimum'), +# partial(convert_v4_v3, memory='full'), +# partial(convert_v4_v3, memory='low'), +# partial(convert_v4_v3, memory='minimum'), ) if tests: @@ -661,13 +661,13 @@ def main(path, text_output, fmt): partial(merge_v3, memory='full'), partial(merge_v3, memory='low'), partial(merge_v3, memory='minimum'), -# merge_reader_v3, + merge_reader_v3, # merge_reader_v3_compress, # merge_reader_v3_nodata, partial(merge_v4, memory='full'), partial(merge_v4, memory='low'), partial(merge_v4, memory='minimum'), -# merge_reader_v4, + merge_reader_v4, # merge_reader_v4_nodata, # merge_reader_v4_compress, ) diff --git a/test/test_mdf.py b/test/test_mdf.py index 4635e7d92..0ace0fe06 100644 --- a/test/test_mdf.py +++ b/test/test_mdf.py @@ -59,7 +59,7 @@ def tearDownClass(cls): shutil.rmtree('tmpdir_demo', True) shutil.rmtree('tmpdir_array', True) os.remove('test.zip') - for filename in os.listdir(): + for filename in os.listdir(os.getcwd()): if os.path.isfile(filename) and filename.startswith('tmp'): os.remove(filename) From aa71e16d35050ac34f66a65f7843655916953ad2 Mon Sep 17 00:00:00 2001 From: danielhrisca Date: Tue, 2 Jan 2018 11:04:54 +0200 Subject: [PATCH 078/117] mdf version 2 and 3 compliance fixes --- asammdf/mdf_v2_v3.py | 7 ++++--- test/test_mdf.py | 4 ++-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/asammdf/mdf_v2_v3.py b/asammdf/mdf_v2_v3.py index b0c1bd3b8..d88e5df0d 100644 --- a/asammdf/mdf_v2_v3.py +++ b/asammdf/mdf_v2_v3.py @@ -1149,7 +1149,7 @@ def append(self, offset += t_size ch_cntr += 1 - if self._compact_integers_on_append: + if self._compact_integers_on_append and self.version >= '3.10': compacted_signals = [ {'signal': sig} for sig in simple_signals @@ -1325,9 +1325,9 @@ def append(self, additional_byte_offset = 0 if signal.samples.dtype.kind == 'u': - data_type = v23c.DATA_TYPE_UNSIGNED_INTEL + data_type = v23c.DATA_TYPE_UNSIGNED else: - data_type = v23c.DATA_TYPE_SIGNED_INTEL + data_type = v23c.DATA_TYPE_SIGNED texts = {} if len(name) >= 32 and self.version >= '2.10': @@ -2908,6 +2908,7 @@ def save(self, dst='', overwrite=None, compression=0): overwrite, compression, ) + return output_file def _save_with_metadata(self, dst, overwrite, compression): diff --git a/test/test_mdf.py b/test/test_mdf.py index 0ace0fe06..f041c9dd4 100644 --- a/test/test_mdf.py +++ b/test/test_mdf.py @@ -152,12 +152,12 @@ def test_read_array(self): def test_convert(self): print("MDF convert tests") - for enable in (True, False): + for enable in (True, ): configure(enable, enable) for out in SUPPORTED_VERSIONS[1:]: for mdfname in os.listdir('tmpdir_demo'): - for memory in MEMORY: + for memory in MEMORY[-1:]: input_file = os.path.join('tmpdir_demo', mdfname) if MDF(input_file).version == '2.00': continue From bc9f334542d0cd1cb18ffebdde01a874d9e00d22 Mon Sep 17 00:00:00 2001 From: danielhrisca Date: Tue, 2 Jan 2018 12:55:26 +0200 Subject: [PATCH 079/117] fix appending of text conversion with empty strings in mdf version 4 fix mdf version 4 text block when source string is empty --- asammdf/mdf_v2_v3.py | 2 +- asammdf/mdf_v4.py | 17 +++++++---------- asammdf/v4_blocks.py | 8 ++++++-- 3 files changed, 14 insertions(+), 13 deletions(-) diff --git a/asammdf/mdf_v2_v3.py b/asammdf/mdf_v2_v3.py index d88e5df0d..96026f02a 100644 --- a/asammdf/mdf_v2_v3.py +++ b/asammdf/mdf_v2_v3.py @@ -2570,7 +2570,7 @@ def get(self, conv_texts = grp['texts']['conversion_tab'][ch_nr] texts = [] for i in range(nr): - key = 'text_{}'.format(i), + key = 'text_{}'.format(i) if key in conv_texts: text = conv_texts[key].get('text', b'') texts.append(text) diff --git a/asammdf/mdf_v4.py b/asammdf/mdf_v4.py index 1ff6286c9..dcf94ee21 100644 --- a/asammdf/mdf_v4.py +++ b/asammdf/mdf_v4.py @@ -1583,7 +1583,7 @@ def append(self, signals, source_info='Python', common_timebase=False): address = tell() conv_texts_tab['text_{}'.format(i)] = address write(bytes(block)) - if info.get('default', b''): + if 'default' in info: block = TextBlock( text=info['default'], meta=False, @@ -1594,7 +1594,6 @@ def append(self, signals, source_info='Python', common_timebase=False): address = tell() conv_texts_tab['default_addr'] = address write(bytes(block)) - kargs['default_addr'] = 0 kargs['links_nr'] = len(raw) + 5 block = ChannelConversion(**kargs) if memory != 'minimum': @@ -1610,7 +1609,7 @@ def append(self, signals, source_info='Python', common_timebase=False): upper = info['upper'] texts = info['phys'] kargs['ref_param_nr'] = len(upper) - kargs['default_addr'] = info.get('default', 0) +# kargs['default_addr'] = info.get('default', 0) kargs['links_nr'] = len(lower) + 5 for i, (u_, l_, t_) in enumerate(zip(upper, lower, texts)): @@ -1627,8 +1626,7 @@ def append(self, signals, source_info='Python', common_timebase=False): else: address = tell() conv_texts_tab['text_{}'.format(i)] = address - write(bytes(block)) - if info.get('default', b''): + if 'default' in info: block = TextBlock( text=info['default'], meta=False, @@ -1639,8 +1637,9 @@ def append(self, signals, source_info='Python', common_timebase=False): address = tell() conv_texts_tab['default_addr'] = address write(bytes(block)) - kargs['default_addr'] = 0 + block = ChannelConversion(**kargs) + if memory != 'minimum': gp_conv.append(block) else: @@ -1790,7 +1789,7 @@ def append(self, signals, source_info='Python', common_timebase=False): address = tell() conv_texts_tab['text_{}'.format(i)] = address write(bytes(block)) - if info.get('default', b''): + if 'default' in info: block = TextBlock( text=info['default'], meta=False, @@ -1801,7 +1800,6 @@ def append(self, signals, source_info='Python', common_timebase=False): address = tell() conv_texts_tab['default_addr'] = address write(bytes(block)) - kargs['default_addr'] = 0 kargs['links_nr'] = len(raw) + 5 block = ChannelConversion(**kargs) @@ -1837,7 +1835,7 @@ def append(self, signals, source_info='Python', common_timebase=False): address = tell() conv_texts_tab['text_{}'.format(i)] = address write(bytes(block)) - if info.get('default', b''): + if 'default' in info: block = TextBlock( text=info['default'], meta=False, @@ -1848,7 +1846,6 @@ def append(self, signals, source_info='Python', common_timebase=False): address = tell() conv_texts_tab['default_addr'] = address write(bytes(block)) - kargs['default_addr'] = 0 block = ChannelConversion(**kargs) if memory != 'minimum': gp_conv.append(block) diff --git a/asammdf/v4_blocks.py b/asammdf/v4_blocks.py index 588164734..9885ec1b0 100644 --- a/asammdf/v4_blocks.py +++ b/asammdf/v4_blocks.py @@ -1943,8 +1943,12 @@ def __init__(self, **kargs): align = size % 8 if align: self['block_len'] = size + v4c.COMMON_SIZE + 8 - align - elif text and text[-1] not in (0, b'\0'): - self['block_len'] = size + v4c.COMMON_SIZE + 8 + else: + if text: + if text[-1] not in (0, b'\0'): + self['block_len'] += 8 + else: + self['block_len'] += 8 def __bytes__(self): fmt = v4c.FMT_TEXT_BLOCK.format(self['block_len'] - v4c.COMMON_SIZE) From 3d7df172f0451036a0d0cdc886e4b7679375d596 Mon Sep 17 00:00:00 2001 From: danielhrisca Date: Tue, 2 Jan 2018 13:27:02 +0200 Subject: [PATCH 080/117] fix error in text conversion --- asammdf/mdf_v2_v3.py | 27 ++++++++++++++++++++------- asammdf/mdf_v4.py | 1 - 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/asammdf/mdf_v2_v3.py b/asammdf/mdf_v2_v3.py index 96026f02a..4ad1e3b7a 100644 --- a/asammdf/mdf_v2_v3.py +++ b/asammdf/mdf_v2_v3.py @@ -2569,13 +2569,26 @@ def get(self, conv_texts = grp['texts']['conversion_tab'][ch_nr] texts = [] - for i in range(nr): - key = 'text_{}'.format(i) - if key in conv_texts: - text = conv_texts[key].get('text', b'') - texts.append(text) - else: - texts.append(b'') + if memory != 'minimum': + for i in range(nr): + key = 'text_{}'.format(i) + if key in conv_texts: + text = conv_texts[key]['text'] + texts.append(text) + else: + texts.append(b'') + else: + for i in range(nr): + key = 'text_{}'.format(i) + if key in conv_texts: + block = TextBlock( + address=conv_texts[key], + stream=stream, + ) + text = block['text'] + texts.append(text) + else: + texts.append(b'') texts = array(texts) lower = [ diff --git a/asammdf/mdf_v4.py b/asammdf/mdf_v4.py index dcf94ee21..bf78b257e 100644 --- a/asammdf/mdf_v4.py +++ b/asammdf/mdf_v4.py @@ -1817,7 +1817,6 @@ def append(self, signals, source_info='Python', common_timebase=False): upper = info['upper'] texts = info['phys'] kargs['ref_param_nr'] = len(upper) - kargs['default_addr'] = info.get('default', 0) kargs['links_nr'] = len(lower) + 5 for i, (u_, l_, t_) in enumerate(zip(upper, lower, texts)): From b9d6c9b95efc256df9ae80516463285281a55487 Mon Sep 17 00:00:00 2001 From: danielhrisca Date: Tue, 2 Jan 2018 13:49:47 +0200 Subject: [PATCH 081/117] fix error in appending range to text conversion --- asammdf/mdf_v4.py | 3 +-- asammdf/v4_blocks.py | 4 ++-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/asammdf/mdf_v4.py b/asammdf/mdf_v4.py index bf78b257e..a2125e115 100644 --- a/asammdf/mdf_v4.py +++ b/asammdf/mdf_v4.py @@ -1449,8 +1449,6 @@ def append(self, signals, source_info='Python', common_timebase=False): if sig.samples.dtype.kind in 'ui' ] - - max_itemsize = 1 dtype_ = dtype(uint8) @@ -1626,6 +1624,7 @@ def append(self, signals, source_info='Python', common_timebase=False): else: address = tell() conv_texts_tab['text_{}'.format(i)] = address + write(bytes(block)) if 'default' in info: block = TextBlock( text=info['default'], diff --git a/asammdf/v4_blocks.py b/asammdf/v4_blocks.py index 9885ec1b0..568bea1b1 100644 --- a/asammdf/v4_blocks.py +++ b/asammdf/v4_blocks.py @@ -1913,8 +1913,8 @@ def __init__(self, **kargs): self['text'] = text = stream.read(size) if self['id'] not in (b'##TX', b'##MD'): - message = 'Expected "##TX" or "##MD" block but found "{}"' - raise MdfException(message.format(self['id'])) + message = 'Expected "##TX" or "##MD" block @{} but found "{}"' + raise MdfException(message.format(hex(address), self['id'])) else: From 7557ce9d922231dc928a70d6bb3728de8c089605 Mon Sep 17 00:00:00 2001 From: danielhrisca Date: Tue, 2 Jan 2018 18:34:47 +0200 Subject: [PATCH 082/117] specify channels by name or by (name, group index, channel index) in the filter and select methods --- asammdf/mdf.py | 113 ++++++++++++++++++++++++------------------- asammdf/mdf_v2_v3.py | 33 ++++--------- asammdf/mdf_v4.py | 43 ++++++---------- 3 files changed, 88 insertions(+), 101 deletions(-) diff --git a/asammdf/mdf.py b/asammdf/mdf.py index c6a14dc6b..39117ded5 100644 --- a/asammdf/mdf.py +++ b/asammdf/mdf.py @@ -484,7 +484,8 @@ def filter(self, channels, memory=None): Parameters ---------- channels : list - list of channel names to be filtered + list of items to be filtered; each item can be a channel name string + or (channel_name, group index, channel index) list or tuple memory : str memory option for filtered mdf; default None in which case the original file's memory option is used @@ -498,48 +499,53 @@ def filter(self, channels, memory=None): # group channels by group index gps = {} - excluded_channels = defaultdict(list) - for ch in channels: - if ch in self.channels_db: - for group, index in self.channels_db[ch]: + + for item in channels: + if isinstance(item, (list, tuple)): + if len(item) != 3: + raise MdfException( + 'The items used for filtering must be strings or ' + '(string, int, int) triplets' + ) + else: + group, index = self._validate_channel_selection(*item) if group not in gps: gps[group] = set() gps[group].add(index) - if self.version in MDF2_VERSIONS + MDF3_VERSIONS: - grp = self.groups[group] - dep = grp['channel_dependencies'][index] - if dep: + else: + name = item + group, index = self._validate_channel_selection(name) + if group not in gps: + gps[group] = set() + gps[group].add(index) + + for group_index, indexes in gps.items(): + grp = self.groups[group_index] + excluded_channels = set() + for index in indexes: + if self.version in MDF2_VERSIONS + MDF3_VERSIONS: + dep = grp['channel_dependencies'][index] + if dep: + for ch_nr, gp_nr in dep.referenced_channels: + if gp_nr == group: + excluded_channels.add(ch_nr) + else: + dependencies = grp['channel_dependencies'][index] + if dependencies is None: + continue + if all(dep['id'] == b'##CN' + if not isinstance(dep, int) else True + for dep in dependencies): + channels = grp['channels'] + for ch in dependencies: + excluded_channels.add(channels.index(ch)) + else: + for dep in dependencies: for ch_nr, gp_nr in dep.referenced_channels: if gp_nr == group: - excluded_channels[group].append(ch_nr) - else: - grp = self.groups[group] - dependencies = grp['channel_dependencies'][index] - if dependencies is None: - continue - if all(dep['id'] == b'##CN' - if not isinstance(dep, int) else True - for dep in dependencies): - channels = grp['channels'] - for ch in dependencies: - excluded_channels[group].append(channels.index(ch)) - else: - for dep in dependencies: - for ch_nr, gp_nr in dep.referenced_channels: - if gp_nr == group: - excluded_channels[group].append(ch_nr) - else: - message = ('MDF filter error: ' - 'Channel "{}" not found, it will be ignored') - warn(message.format(ch)) - continue - - for group in excluded_channels: - excluded_indexes = excluded_channels[group] - if group in gps: - for index in excluded_indexes: - if index in gps[group]: - gps[group].remove(index) + excluded_channels.add(ch_nr) + + gps[group_index] = gps[group_index] - excluded_channels if memory is not None: if memory not in ('full', 'low', 'minimum'): @@ -789,7 +795,8 @@ def select(self, channels, dataframe=False): Parameters ---------- channels : list - list of channel names to be filtered + list of items to be filtered; each item can be a channel name string + or (channel_name, group index, channel index) list or tuple dataframe: bool return a pandas DataFrame instead of a list of Signals; in this case the signals will be interpolated using the union of all @@ -798,23 +805,31 @@ def select(self, channels, dataframe=False): Returns ------- signals : list - lsit of *Signal* objects based on the input channel list + list of *Signal* objects based on the input channel list """ # group channels by group index gps = {} - for ch in channels: - if ch in self.channels_db: - for group, index in self.channels_db[ch]: + + for item in channels: + if isinstance(item, (list, tuple)): + if len(item) != 3: + raise MdfException( + 'The items used for filtering must be strings or ' + '(string, int, int) triplets' + ) + else: + group, index = self._validate_channel_selection(*item) if group not in gps: - gps[group] = [] - gps[group].append(index) + gps[group] = set() + gps[group].add(index) else: - message = ('MDF filter error: ' - 'Channel "{}" not found, it will be ignored') - warn(message.format(ch)) - continue + name = item + group, index = self._validate_channel_selection(name) + if group not in gps: + gps[group] = set() + gps[group].add(index) # append filtered channels to new MDF signals = {} diff --git a/asammdf/mdf_v2_v3.py b/asammdf/mdf_v2_v3.py index 4ad1e3b7a..3ac772fe2 100644 --- a/asammdf/mdf_v2_v3.py +++ b/asammdf/mdf_v2_v3.py @@ -520,38 +520,23 @@ def _validate_channel_selection(self, name=None, group=None, index=None): message = message.format(name, gp_nr) warnings.warn(message) else: - group_valid = False for gp_nr, ch_nr in self.channels_db[name]: if gp_nr == group: - group_valid = True if index is None: break elif index == ch_nr: break else: - if group_valid: - gp_nr, ch_nr = self.channels_db[name][group] - message = ('You have selected channel index "{}"' - 'of group "{}" for channel "{}", but ' - 'this channel index is invalid. Using ' - 'first occurance of "{}" in this group' - ' at index "{}"') - message = message.format( - index, - group, - name, - name, - ch_nr, - ) + if index is None: + message = 'Channel "{}" not found in group {}' + message = message.format(name, group) else: - gp_nr, ch_nr = self.channels_db[name][0] - message = ('You have selected group "{}" for ' - 'channel "{}", but this channel was not' - ' found in this group, or this group ' - 'index does not exist. Using first ' - 'occurance of "{}" from group "{}"') - message = message.format(group, name, name, gp_nr) - warnings.warn(message) + message = ( + 'Channel "{}" not found in group {} ' + 'at index {}' + ) + message = message.format(name, group, index) + raise MdfException(message) return gp_nr, ch_nr def _read(self): diff --git a/asammdf/mdf_v4.py b/asammdf/mdf_v4.py index a2125e115..7ae5d36e8 100644 --- a/asammdf/mdf_v4.py +++ b/asammdf/mdf_v4.py @@ -1198,45 +1198,32 @@ def _validate_channel_selection(self, name=None, group=None, index=None): if group is None: gp_nr, ch_nr = self.channels_db[name][0] if len(self.channels_db[name]) > 1: - message = ('Multiple occurances for channel "{}". ' - 'Using first occurance from data group {}. ' - 'Provide both "group" and "index" arguments' - ' to select another data group') + message = ( + 'Multiple occurances for channel "{}". ' + 'Using first occurance from data group {}. ' + 'Provide both "group" and "index" arguments' + ' to select another data group' + ) message = message.format(name, gp_nr) warnings.warn(message) else: - group_valid = False for gp_nr, ch_nr in self.channels_db[name]: if gp_nr == group: - group_valid = True if index is None: break elif index == ch_nr: break else: - if group_valid: - gp_nr, ch_nr = self.channels_db[name][group] - message = ('You have selected channel index "{}"' - 'of group "{}" for channel "{}", but ' - 'this channel index is invalid. Using ' - 'first occurance of "{}" in this group' - ' at index "{}"') - message = message.format( - index, - group, - name, - name, - ch_nr, - ) + if index is None: + message = 'Channel "{}" not found in group {}' + message = message.format(name, group) else: - gp_nr, ch_nr = self.channels_db[name][0] - message = ('You have selected group "{}" for ' - 'channel "{}", but this channel was not' - ' found in this group, or this group ' - 'index does not exist. Using first ' - 'occurance of "{}" from group "{}"') - message = message.format(group, name, name, gp_nr) - warnings.warn(message) + message = ( + 'Channel "{}" not found in group {} ' + 'at index {}' + ) + message = message.format(name, group, index) + raise MdfException(message) return gp_nr, ch_nr def append(self, signals, source_info='Python', common_timebase=False): From 642fe5e0cd89c123ec8929740ddf69dd0212d6eb Mon Sep 17 00:00:00 2001 From: danielhrisca Date: Wed, 3 Jan 2018 20:04:09 +0200 Subject: [PATCH 083/117] specify channels by name or by (name, group index, channel index) in the filter and select methods - proper implementation --- asammdf/mdf.py | 121 +++++++++++++++++++++++++++---- asammdf/mdf_v2_v3.py | 56 +++++++++++++++ asammdf/mdf_v4.py | 57 +++++++++++++++ test/test_mdf.py | 35 ++++----- test/test_mdf23.py | 168 ------------------------------------------- test/test_mdf4.py | 92 ------------------------ 6 files changed, 240 insertions(+), 289 deletions(-) delete mode 100644 test/test_mdf23.py delete mode 100644 test/test_mdf4.py diff --git a/asammdf/mdf.py b/asammdf/mdf.py index 39117ded5..bda4927a9 100644 --- a/asammdf/mdf.py +++ b/asammdf/mdf.py @@ -484,8 +484,13 @@ def filter(self, channels, memory=None): Parameters ---------- channels : list - list of items to be filtered; each item can be a channel name string - or (channel_name, group index, channel index) list or tuple + list of items to be filtered; each item can be : + + * a channel name string + * (channel_name, group index, channel index) list or tuple + * (channel name, group index) list or tuple + * (None, group index, channel index) lsit or tuple + memory : str memory option for filtered mdf; default None in which case the original file's memory option is used @@ -495,6 +500,46 @@ def filter(self, channels, memory=None): mdf : MDF new MDF file + Examples + -------- + >>> from asammdf import MDF, Signal + >>> import numpy as np + >>> t = np.arange(5) + >>> s = np.ones(5) + >>> mdf = MDF() + >>> for i in range(4): + ... sigs = [Signal(s*(i*10+j), t, name='SIG') for j in range(1,4)] + ... mdf.append(sigs) + ... + >>> filtered = mdf.filter(['SIG', ('SIG', 3, 1), ['SIG', 2], (None, 1, 2)]) + >>> for gp_nr, ch_nr in filtered.channels_db['SIG']: + ... print(filtered.get(group=gp_nr, index=ch_nr)) + ... + + + + + """ # group channels by group index @@ -502,10 +547,11 @@ def filter(self, channels, memory=None): for item in channels: if isinstance(item, (list, tuple)): - if len(item) != 3: + if len(item) not in (2, 3): raise MdfException( - 'The items used for filtering must be strings or ' - '(string, int, int) triplets' + 'The items used for filtering must be strings, ' + 'or they must match the first 3 argumens of the get ' + 'method' ) else: group, index = self._validate_channel_selection(*item) @@ -795,8 +841,13 @@ def select(self, channels, dataframe=False): Parameters ---------- channels : list - list of items to be filtered; each item can be a channel name string - or (channel_name, group index, channel index) list or tuple + list of items to be filtered; each item can be : + + * a channel name string + * (channel_name, group index, channel index) list or tuple + * (channel name, group index) list or tuple + * (None, group index, channel index) lsit or tuple + dataframe: bool return a pandas DataFrame instead of a list of Signals; in this case the signals will be interpolated using the union of all @@ -807,40 +858,84 @@ def select(self, channels, dataframe=False): signals : list list of *Signal* objects based on the input channel list + Examples + -------- + >>> from asammdf import MDF, Signal + >>> import numpy as np + >>> t = np.arange(5) + >>> s = np.ones(5) + >>> mdf = MDF() + >>> for i in range(4): + ... sigs = [Signal(s*(i*10+j), t, name='SIG') for j in range(1,4)] + ... mdf.append(sigs) + ... + >>> # select SIG group 0 default index 1 default, SIG group 3 index 1, SIG group 2 index 1 default and channel index 2 from group 1 + ... + >>> mdf.select(['SIG', ('SIG', 3, 1), ['SIG', 2], (None, 1, 2)]) + [ + , + , + , + ] + """ # group channels by group index gps = {} + indexes = [] + for item in channels: if isinstance(item, (list, tuple)): - if len(item) != 3: + if len(item) not in (2, 3): raise MdfException( - 'The items used for filtering must be strings or ' - '(string, int, int) triplets' + 'The items used for filtering must be strings, ' + 'or they must match the first 3 argumens of the get ' + 'method' ) else: group, index = self._validate_channel_selection(*item) + indexes.append((group, index)) if group not in gps: gps[group] = set() gps[group].add(index) else: name = item group, index = self._validate_channel_selection(name) + indexes.append((group, index)) if group not in gps: gps[group] = set() gps[group].add(index) - # append filtered channels to new MDF signals = {} for group in gps: grp = self.groups[group] data = self._load_group_data(grp) for index in gps[group]: signal = self.get(group=group, index=index, data=data) - signals[signal.name] = signal + signals[(group, index)] = signal - signals = [signals[channel] for channel in channels] + signals = [signals[pair] for pair in indexes] if dataframe: times = [s.timestamps for s in signals] diff --git a/asammdf/mdf_v2_v3.py b/asammdf/mdf_v2_v3.py index 3ac772fe2..444ead50d 100644 --- a/asammdf/mdf_v2_v3.py +++ b/asammdf/mdf_v2_v3.py @@ -2324,6 +2324,62 @@ def get(self, * if the group index is out of range * if the channel index is out of range + Examples + -------- + >>> from asammdf import MDF, Signal + >>> import numpy as np + >>> t = np.arange(5) + >>> s = np.ones(5) + >>> mdf = MDF(version='3.30') + >>> for i in range(4): + ... sigs = [Signal(s*(i*10+j), t, name='Sig') for j in range(1, 4)] + ... mdf.append(sigs) + ... + >>> # first group and channel index of the specified channel name + ... + >>> mdf.get('Sig') + UserWarning: Multiple occurances for channel "Sig". Using first occurance from data group 4. Provide both "group" and "index" arguments to select another data group + + >>> # first channel index in the specified group + ... + >>> mdf.get('Sig', 1) + + >>> # channel named Sig from group 1 channel index 2 + ... + >>> mdf.get('Sig', 1, 2) + + >>> # channel index 1 or group 2 + ... + >>> mdf.get(None, 2, 1) + + >>> mdf.get(group=2, index=1) + + """ gp_nr, ch_nr = self._validate_channel_selection( name, diff --git a/asammdf/mdf_v4.py b/asammdf/mdf_v4.py index 7ae5d36e8..f4ca83fe8 100644 --- a/asammdf/mdf_v4.py +++ b/asammdf/mdf_v4.py @@ -1224,6 +1224,7 @@ def _validate_channel_selection(self, name=None, group=None, index=None): ) message = message.format(name, group, index) raise MdfException(message) + return gp_nr, ch_nr def append(self, signals, source_info='Python', common_timebase=False): @@ -2872,6 +2873,62 @@ def get(self, * if the group index is out of range * if the channel index is out of range + Examples + -------- + >>> from asammdf import MDF, Signal + >>> import numpy as np + >>> t = np.arange(5) + >>> s = np.ones(5) + >>> mdf = MDF(version='4.10') + >>> for i in range(4): + ... sigs = [Signal(s*(i*10+j), t, name='Sig') for j in range(1, 4)] + ... mdf.append(sigs) + ... + >>> # first group and channel index of the specified channel name + ... + >>> mdf.get('Sig') + UserWarning: Multiple occurances for channel "Sig". Using first occurance from data group 4. Provide both "group" and "index" arguments to select another data group + + >>> # first channel index in the specified group + ... + >>> mdf.get('Sig', 1) + + >>> # channel named Sig from group 1 channel index 2 + ... + >>> mdf.get('Sig', 1, 2) + + >>> # channel index 1 or group 2 + ... + >>> mdf.get(None, 2, 1) + + >>> mdf.get(group=2, index=1) + + """ gp_nr, ch_nr = self._validate_channel_selection( name, diff --git a/test/test_mdf.py b/test/test_mdf.py index f041c9dd4..3a8c75ab2 100644 --- a/test/test_mdf.py +++ b/test/test_mdf.py @@ -26,7 +26,7 @@ class TestMDF(unittest.TestCase): - def test_measurement(self): + def etest_measurement(self): self.assertTrue(MDF) @classmethod @@ -55,7 +55,7 @@ def setUpClass(cls): ) @classmethod - def tearDownClass(cls): + def etearDownClass(cls): shutil.rmtree('tmpdir_demo', True) shutil.rmtree('tmpdir_array', True) os.remove('test.zip') @@ -63,7 +63,7 @@ def tearDownClass(cls): if os.path.isfile(filename) and filename.startswith('tmp'): os.remove(filename) - def test_read(self): + def etest_read(self): print("MDF read tests") @@ -87,7 +87,7 @@ def test_read(self): self.assertTrue(ret) - def test_get_channel_comment_v4(self): + def etest_get_channel_comment_v4(self): print("MDF get channel comment tests") ret = True @@ -106,7 +106,7 @@ def test_get_channel_comment_v4(self): self.assertTrue(ret) - def test_get_channel_units(self): + def etest_get_channel_units(self): print("MDF get channel units tests") ret = True @@ -126,7 +126,7 @@ def test_get_channel_units(self): self.assertTrue(ret) - def test_read_array(self): + def etest_read_array(self): print("MDF read array tests") @@ -149,7 +149,7 @@ def test_read_array(self): self.assertTrue(ret) - def test_convert(self): + def etest_convert(self): print("MDF convert tests") for enable in (True, ): @@ -186,14 +186,15 @@ def test_convert(self): self.assertTrue(equal) - def test_merge(self): + def etest_merge(self): print("MDF merge tests") configure(False, False) for out in SUPPORTED_VERSIONS: for mdfname in os.listdir('tmpdir_demo'): - for memory in MEMORY: + for memory in MEMORY[:1]: + input_file = os.path.join('tmpdir_demo', mdfname) files = [input_file, ] * 4 @@ -243,7 +244,7 @@ def test_merge(self): self.assertTrue(equal) - def test_merge_array(self): + def etest_merge_array(self): print("MDF merge array tests") configure(False, False) @@ -297,7 +298,7 @@ def test_merge_array(self): self.assertTrue(equal) - def test_cut_absolute(self): + def etest_cut_absolute(self): print("MDF cut absolute tests") configure(False, False) @@ -306,6 +307,8 @@ def test_cut_absolute(self): for memory in MEMORY: input_file = os.path.join('tmpdir_demo', mdfname) + print(input_file, memory) + outfile1 = MDF(input_file, memory=memory).cut(stop=2).save('tmp1', overwrite=True) outfile2 = MDF(input_file, memory=memory).cut(start=2, stop=6).save('tmp2', overwrite=True) outfile3 = MDF(input_file, memory=memory).cut(start=6).save('tmp3', overwrite=True) @@ -373,7 +376,7 @@ def test_cut_absolute(self): self.assertTrue(equal) - def test_cut_absolute_array(self): + def etest_cut_absolute_array(self): print("MDF cut absolute array tests") configure(False, False) @@ -445,7 +448,7 @@ def test_cut_absolute_array(self): self.assertTrue(equal) - def test_cut_relative(self): + def etest_cut_relative(self): print("MDF cut relative tests") configure(False, False) @@ -519,7 +522,7 @@ def test_cut_relative(self): self.assertTrue(equal) - def test_cut_relative_array(self): + def etest_cut_relative_array(self): print("MDF cut relative array tests") configure(False, False) @@ -685,7 +688,7 @@ def test_filter_array(self): self.assertTrue(equal) - def test_save(self): + def etest_save(self): print("MDF save tests") compressions = [0, 1, 2] @@ -729,7 +732,7 @@ def test_save(self): self.assertTrue(equal) - def test_save_array(self): + def etest_save_array(self): print("MDF save array tests") compressions = [0, 1, 2] diff --git a/test/test_mdf23.py b/test/test_mdf23.py deleted file mode 100644 index 0c5705799..000000000 --- a/test/test_mdf23.py +++ /dev/null @@ -1,168 +0,0 @@ -#!/usr/bin/env python -from __future__ import print_function -import os -import unittest - -import numpy as np - -from utils import MEMORY -from asammdf import MDF, MDF23, Signal, configure - -CHANNEL_LEN = 10000 - -configure(integer_compacting=True, - split_data_blocks=True, - split_threshold=260, - overwrite=True) - - -class TestMDF23(unittest.TestCase): - - def test_measurement(self): - self.assertTrue(MDF23) - - def test_read_mdf2_00(self): - - seed = np.random.randint(0, 2**31) - - np.random.seed(seed) - print('Read 2.00 using seed =', seed) - - sig_int = Signal( - np.random.randint(-2**15, -1, CHANNEL_LEN), - np.arange(CHANNEL_LEN), - name='Integer Channel', - unit='unit1', - ) - - sig_float = Signal( - np.random.random(CHANNEL_LEN), - np.arange(CHANNEL_LEN), - name='Float Channel', - unit='unit2', - ) - - for memory in MEMORY: - - with MDF(version='2.00', memory=memory) as mdf: - mdf.append([sig_int, sig_float], common_timebase=True) - outfile = mdf.save('tmp', overwrite=True) - - with MDF(outfile, memory=memory) as mdf: - ret_sig_int = mdf.get(sig_int.name) - ret_sig_float = mdf.get(sig_float.name) - - self.assertTrue(np.array_equal(ret_sig_int.samples, - sig_int.samples)) - self.assertTrue(np.array_equal(ret_sig_float.samples, - sig_float.samples)) - - def test_read_mdf2_14(self): - - seed = np.random.randint(0, 2**31) - - np.random.seed(seed) - print('Read 2.14 using seed =', seed) - - sig_int = Signal( - np.random.randint(-2**29, 2**29, CHANNEL_LEN), - np.arange(CHANNEL_LEN), - name='Integer Channel', - unit='unit1', - ) - - sig_float = Signal( - np.random.random(CHANNEL_LEN), - np.arange(CHANNEL_LEN), - name='Float Channel', - unit='unit2', - ) - - for memory in MEMORY: - with MDF(version='2.14', memory=memory) as mdf: - mdf.append([sig_int, sig_float], common_timebase=True) - outfile = mdf.save('tmp', overwrite=True) - - with MDF(outfile, memory=memory) as mdf: - ret_sig_int = mdf.get(sig_int.name) - ret_sig_float = mdf.get(sig_float.name) - - self.assertTrue(np.array_equal(ret_sig_int.samples, - sig_int.samples)) - self.assertTrue(np.array_equal(ret_sig_float.samples, - sig_float.samples)) - - def test_read_mdf3_00(self): - - seed = np.random.randint(0, 2**31) - - np.random.seed(seed) - print('Read 3.00 using seed =', seed) - - sig_int = Signal( - np.random.randint(-2**16, 2**16, CHANNEL_LEN, np.int32), - np.arange(CHANNEL_LEN), - name='Integer Channel', - unit='unit1', - ) - - sig_float = Signal( - np.random.random(CHANNEL_LEN), - np.arange(CHANNEL_LEN), - name='Float Channel', - unit='unit2', - ) - - for memory in MEMORY: - - with MDF(version='3.00', memory=memory) as mdf: - mdf.append([sig_int, sig_float], common_timebase=True) - outfile = mdf.save('tmp', overwrite=True) - - with MDF(outfile, memory=memory) as mdf: - ret_sig_int = mdf.get(sig_int.name) - ret_sig_float = mdf.get(sig_float.name) - - self.assertTrue(np.array_equal(ret_sig_int.samples, - sig_int.samples)) - self.assertTrue(np.array_equal(ret_sig_float.samples, - sig_float.samples)) - - def test_read_mdf3_10(self): - - seed = np.random.randint(0, 2**31) - - np.random.seed(seed) - print('Read 3.10 using seed =', seed) - - sig_int = Signal( - np.random.randint(-2**9, 2**7, CHANNEL_LEN), - np.arange(CHANNEL_LEN), - name='Integer Channel', - unit='unit1', - ) - - sig_float = Signal( - np.random.random(CHANNEL_LEN), - np.arange(CHANNEL_LEN), - name='Float Channel', - unit='unit2', - ) - - for memory in MEMORY: - with MDF(version='3.10', memory=memory) as mdf: - mdf.append([sig_int, sig_float], common_timebase=True) - outfile = mdf.save('tmp', overwrite=True) - - with MDF(outfile, memory=memory) as mdf: - ret_sig_int = mdf.get(sig_int.name) - ret_sig_float = mdf.get(sig_float.name) - - self.assertTrue(np.array_equal(ret_sig_int.samples, - sig_int.samples)) - self.assertTrue(np.array_equal(ret_sig_float.samples, - sig_float.samples)) - - -if __name__ == '__main__': - unittest.main() diff --git a/test/test_mdf4.py b/test/test_mdf4.py deleted file mode 100644 index 6b5af02b5..000000000 --- a/test/test_mdf4.py +++ /dev/null @@ -1,92 +0,0 @@ -#!/usr/bin/env python -from __future__ import print_function -import os -import unittest - -import numpy as np - -from utils import MEMORY -from asammdf import MDF, MDF4, Signal - -CHANNEL_LEN = 100000 - - -class TestMDF4(unittest.TestCase): - - def test_measurement(self): - self.assertTrue(MDF4) - - def test_read_mdf4_00(self): - - seed = np.random.randint(0, 2**31) - - np.random.seed(seed) - print('Read 4.00 using seed =', seed) - - sig_int = Signal( - np.random.randint(-2**31, 2**31, CHANNEL_LEN), - np.arange(CHANNEL_LEN), - name='Integer Channel', - unit='unit1', - ) - - sig_float = Signal( - np.random.random(CHANNEL_LEN), - np.arange(CHANNEL_LEN), - name='Float Channel', - unit='unit2', - ) - - for memory in MEMORY: - - with MDF(version='4.00', memory=memory) as mdf: - mdf.append([sig_int, sig_float], common_timebase=True) - outfile = mdf.save('tmp', overwrite=True) - - with MDF(outfile, memory=memory) as mdf: - ret_sig_int = mdf.get(sig_int.name) - ret_sig_float = mdf.get(sig_float.name) - - self.assertTrue(np.array_equal(ret_sig_int.samples, - sig_int.samples)) - self.assertTrue(np.array_equal(ret_sig_float.samples, - sig_float.samples)) - - def test_read_mdf4_10(self): - - seed = np.random.randint(0, 2**31) - - np.random.seed(seed) - print('Read 4.10 using seed =', seed) - - sig_int = Signal( - np.random.randint(-2**31, 2**31, CHANNEL_LEN), - np.arange(CHANNEL_LEN), - name='Integer Channel', - unit='unit1', - ) - - sig_float = Signal( - np.random.random(CHANNEL_LEN), - np.arange(CHANNEL_LEN), - name='Float Channel', - unit='unit2', - ) - - for memory in MEMORY: - with MDF(version='4.10', memory=memory) as mdf: - mdf.append([sig_int, sig_float], common_timebase=True) - outfile = mdf.save('tmp', overwrite=True) - - with MDF(outfile, memory=memory) as mdf: - ret_sig_int = mdf.get(sig_int.name) - ret_sig_float = mdf.get(sig_float.name) - - self.assertTrue(np.array_equal(ret_sig_int.samples, - sig_int.samples)) - self.assertTrue(np.array_equal(ret_sig_float.samples, - sig_float.samples)) - - -if __name__ == '__main__': - unittest.main() From 417fc623f2d2fb11a962dc0e724faf897f33893f Mon Sep 17 00:00:00 2001 From: danielhrisca Date: Wed, 3 Jan 2018 20:10:50 +0200 Subject: [PATCH 084/117] fix botched test files --- test/test_mdf.py | 30 ++++---- test/test_mdf23.py | 168 +++++++++++++++++++++++++++++++++++++++++++++ test/test_mdf4.py | 92 +++++++++++++++++++++++++ 3 files changed, 275 insertions(+), 15 deletions(-) create mode 100644 test/test_mdf23.py create mode 100644 test/test_mdf4.py diff --git a/test/test_mdf.py b/test/test_mdf.py index 3a8c75ab2..c690c3ea2 100644 --- a/test/test_mdf.py +++ b/test/test_mdf.py @@ -26,7 +26,7 @@ class TestMDF(unittest.TestCase): - def etest_measurement(self): + def test_measurement(self): self.assertTrue(MDF) @classmethod @@ -55,7 +55,7 @@ def setUpClass(cls): ) @classmethod - def etearDownClass(cls): + def tearDownClass(cls): shutil.rmtree('tmpdir_demo', True) shutil.rmtree('tmpdir_array', True) os.remove('test.zip') @@ -63,7 +63,7 @@ def etearDownClass(cls): if os.path.isfile(filename) and filename.startswith('tmp'): os.remove(filename) - def etest_read(self): + def test_read(self): print("MDF read tests") @@ -87,7 +87,7 @@ def etest_read(self): self.assertTrue(ret) - def etest_get_channel_comment_v4(self): + def test_get_channel_comment_v4(self): print("MDF get channel comment tests") ret = True @@ -106,7 +106,7 @@ def etest_get_channel_comment_v4(self): self.assertTrue(ret) - def etest_get_channel_units(self): + def test_get_channel_units(self): print("MDF get channel units tests") ret = True @@ -126,7 +126,7 @@ def etest_get_channel_units(self): self.assertTrue(ret) - def etest_read_array(self): + def test_read_array(self): print("MDF read array tests") @@ -149,7 +149,7 @@ def etest_read_array(self): self.assertTrue(ret) - def etest_convert(self): + def test_convert(self): print("MDF convert tests") for enable in (True, ): @@ -186,7 +186,7 @@ def etest_convert(self): self.assertTrue(equal) - def etest_merge(self): + def test_merge(self): print("MDF merge tests") configure(False, False) @@ -244,7 +244,7 @@ def etest_merge(self): self.assertTrue(equal) - def etest_merge_array(self): + def test_merge_array(self): print("MDF merge array tests") configure(False, False) @@ -298,7 +298,7 @@ def etest_merge_array(self): self.assertTrue(equal) - def etest_cut_absolute(self): + def test_cut_absolute(self): print("MDF cut absolute tests") configure(False, False) @@ -376,7 +376,7 @@ def etest_cut_absolute(self): self.assertTrue(equal) - def etest_cut_absolute_array(self): + def test_cut_absolute_array(self): print("MDF cut absolute array tests") configure(False, False) @@ -448,7 +448,7 @@ def etest_cut_absolute_array(self): self.assertTrue(equal) - def etest_cut_relative(self): + def test_cut_relative(self): print("MDF cut relative tests") configure(False, False) @@ -522,7 +522,7 @@ def etest_cut_relative(self): self.assertTrue(equal) - def etest_cut_relative_array(self): + def test_cut_relative_array(self): print("MDF cut relative array tests") configure(False, False) @@ -688,7 +688,7 @@ def test_filter_array(self): self.assertTrue(equal) - def etest_save(self): + def test_save(self): print("MDF save tests") compressions = [0, 1, 2] @@ -732,7 +732,7 @@ def etest_save(self): self.assertTrue(equal) - def etest_save_array(self): + def test_save_array(self): print("MDF save array tests") compressions = [0, 1, 2] diff --git a/test/test_mdf23.py b/test/test_mdf23.py new file mode 100644 index 000000000..0c5705799 --- /dev/null +++ b/test/test_mdf23.py @@ -0,0 +1,168 @@ +#!/usr/bin/env python +from __future__ import print_function +import os +import unittest + +import numpy as np + +from utils import MEMORY +from asammdf import MDF, MDF23, Signal, configure + +CHANNEL_LEN = 10000 + +configure(integer_compacting=True, + split_data_blocks=True, + split_threshold=260, + overwrite=True) + + +class TestMDF23(unittest.TestCase): + + def test_measurement(self): + self.assertTrue(MDF23) + + def test_read_mdf2_00(self): + + seed = np.random.randint(0, 2**31) + + np.random.seed(seed) + print('Read 2.00 using seed =', seed) + + sig_int = Signal( + np.random.randint(-2**15, -1, CHANNEL_LEN), + np.arange(CHANNEL_LEN), + name='Integer Channel', + unit='unit1', + ) + + sig_float = Signal( + np.random.random(CHANNEL_LEN), + np.arange(CHANNEL_LEN), + name='Float Channel', + unit='unit2', + ) + + for memory in MEMORY: + + with MDF(version='2.00', memory=memory) as mdf: + mdf.append([sig_int, sig_float], common_timebase=True) + outfile = mdf.save('tmp', overwrite=True) + + with MDF(outfile, memory=memory) as mdf: + ret_sig_int = mdf.get(sig_int.name) + ret_sig_float = mdf.get(sig_float.name) + + self.assertTrue(np.array_equal(ret_sig_int.samples, + sig_int.samples)) + self.assertTrue(np.array_equal(ret_sig_float.samples, + sig_float.samples)) + + def test_read_mdf2_14(self): + + seed = np.random.randint(0, 2**31) + + np.random.seed(seed) + print('Read 2.14 using seed =', seed) + + sig_int = Signal( + np.random.randint(-2**29, 2**29, CHANNEL_LEN), + np.arange(CHANNEL_LEN), + name='Integer Channel', + unit='unit1', + ) + + sig_float = Signal( + np.random.random(CHANNEL_LEN), + np.arange(CHANNEL_LEN), + name='Float Channel', + unit='unit2', + ) + + for memory in MEMORY: + with MDF(version='2.14', memory=memory) as mdf: + mdf.append([sig_int, sig_float], common_timebase=True) + outfile = mdf.save('tmp', overwrite=True) + + with MDF(outfile, memory=memory) as mdf: + ret_sig_int = mdf.get(sig_int.name) + ret_sig_float = mdf.get(sig_float.name) + + self.assertTrue(np.array_equal(ret_sig_int.samples, + sig_int.samples)) + self.assertTrue(np.array_equal(ret_sig_float.samples, + sig_float.samples)) + + def test_read_mdf3_00(self): + + seed = np.random.randint(0, 2**31) + + np.random.seed(seed) + print('Read 3.00 using seed =', seed) + + sig_int = Signal( + np.random.randint(-2**16, 2**16, CHANNEL_LEN, np.int32), + np.arange(CHANNEL_LEN), + name='Integer Channel', + unit='unit1', + ) + + sig_float = Signal( + np.random.random(CHANNEL_LEN), + np.arange(CHANNEL_LEN), + name='Float Channel', + unit='unit2', + ) + + for memory in MEMORY: + + with MDF(version='3.00', memory=memory) as mdf: + mdf.append([sig_int, sig_float], common_timebase=True) + outfile = mdf.save('tmp', overwrite=True) + + with MDF(outfile, memory=memory) as mdf: + ret_sig_int = mdf.get(sig_int.name) + ret_sig_float = mdf.get(sig_float.name) + + self.assertTrue(np.array_equal(ret_sig_int.samples, + sig_int.samples)) + self.assertTrue(np.array_equal(ret_sig_float.samples, + sig_float.samples)) + + def test_read_mdf3_10(self): + + seed = np.random.randint(0, 2**31) + + np.random.seed(seed) + print('Read 3.10 using seed =', seed) + + sig_int = Signal( + np.random.randint(-2**9, 2**7, CHANNEL_LEN), + np.arange(CHANNEL_LEN), + name='Integer Channel', + unit='unit1', + ) + + sig_float = Signal( + np.random.random(CHANNEL_LEN), + np.arange(CHANNEL_LEN), + name='Float Channel', + unit='unit2', + ) + + for memory in MEMORY: + with MDF(version='3.10', memory=memory) as mdf: + mdf.append([sig_int, sig_float], common_timebase=True) + outfile = mdf.save('tmp', overwrite=True) + + with MDF(outfile, memory=memory) as mdf: + ret_sig_int = mdf.get(sig_int.name) + ret_sig_float = mdf.get(sig_float.name) + + self.assertTrue(np.array_equal(ret_sig_int.samples, + sig_int.samples)) + self.assertTrue(np.array_equal(ret_sig_float.samples, + sig_float.samples)) + + +if __name__ == '__main__': + unittest.main() diff --git a/test/test_mdf4.py b/test/test_mdf4.py new file mode 100644 index 000000000..6b5af02b5 --- /dev/null +++ b/test/test_mdf4.py @@ -0,0 +1,92 @@ +#!/usr/bin/env python +from __future__ import print_function +import os +import unittest + +import numpy as np + +from utils import MEMORY +from asammdf import MDF, MDF4, Signal + +CHANNEL_LEN = 100000 + + +class TestMDF4(unittest.TestCase): + + def test_measurement(self): + self.assertTrue(MDF4) + + def test_read_mdf4_00(self): + + seed = np.random.randint(0, 2**31) + + np.random.seed(seed) + print('Read 4.00 using seed =', seed) + + sig_int = Signal( + np.random.randint(-2**31, 2**31, CHANNEL_LEN), + np.arange(CHANNEL_LEN), + name='Integer Channel', + unit='unit1', + ) + + sig_float = Signal( + np.random.random(CHANNEL_LEN), + np.arange(CHANNEL_LEN), + name='Float Channel', + unit='unit2', + ) + + for memory in MEMORY: + + with MDF(version='4.00', memory=memory) as mdf: + mdf.append([sig_int, sig_float], common_timebase=True) + outfile = mdf.save('tmp', overwrite=True) + + with MDF(outfile, memory=memory) as mdf: + ret_sig_int = mdf.get(sig_int.name) + ret_sig_float = mdf.get(sig_float.name) + + self.assertTrue(np.array_equal(ret_sig_int.samples, + sig_int.samples)) + self.assertTrue(np.array_equal(ret_sig_float.samples, + sig_float.samples)) + + def test_read_mdf4_10(self): + + seed = np.random.randint(0, 2**31) + + np.random.seed(seed) + print('Read 4.10 using seed =', seed) + + sig_int = Signal( + np.random.randint(-2**31, 2**31, CHANNEL_LEN), + np.arange(CHANNEL_LEN), + name='Integer Channel', + unit='unit1', + ) + + sig_float = Signal( + np.random.random(CHANNEL_LEN), + np.arange(CHANNEL_LEN), + name='Float Channel', + unit='unit2', + ) + + for memory in MEMORY: + with MDF(version='4.10', memory=memory) as mdf: + mdf.append([sig_int, sig_float], common_timebase=True) + outfile = mdf.save('tmp', overwrite=True) + + with MDF(outfile, memory=memory) as mdf: + ret_sig_int = mdf.get(sig_int.name) + ret_sig_float = mdf.get(sig_float.name) + + self.assertTrue(np.array_equal(ret_sig_int.samples, + sig_int.samples)) + self.assertTrue(np.array_equal(ret_sig_float.samples, + sig_float.samples)) + + +if __name__ == '__main__': + unittest.main() From b4cab8bba79c743090bba5e96cabb4f3ff07a13a Mon Sep 17 00:00:00 2001 From: danielhrisca Date: Wed, 3 Jan 2018 20:25:59 +0200 Subject: [PATCH 085/117] implement iterator over the MDF object and package level configuration option --- asammdf/__init__.py | 13 ++++++++++++- asammdf/mdf.py | 19 +++++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/asammdf/__init__.py b/asammdf/__init__.py index 7004e80ac..dba311c65 100644 --- a/asammdf/__init__.py +++ b/asammdf/__init__.py @@ -22,9 +22,14 @@ def configure( integer_compacting=None, split_data_blocks=None, split_threshold=None, - overwrite=None): + overwrite=None, + iter_channels=None): """ configure asammdf parameters + Note + ---- + this is not thread safe + Parameters ---------- integer_compacting : bool @@ -40,6 +45,9 @@ def configure( the data groups' records size overwrite : bool default option for save method's overwrite argument + iter_channels : bool + default option to yield channels instead of pandas DataFrame when + iterating over the MDF objects """ @@ -56,3 +64,6 @@ def configure( if overwrite is not None: MDF23._overwrite = bool(overwrite) MDF4._overwrite = bool(overwrite) + + if iter_channels is not None: + MDF.iter_channels = bool(iter_channels) diff --git a/asammdf/mdf.py b/asammdf/mdf.py index bda4927a9..7c6792925 100644 --- a/asammdf/mdf.py +++ b/asammdf/mdf.py @@ -48,6 +48,8 @@ class MDF(object): """ + _iter_channels = True + def __init__(self, name=None, memory='full', version='4.10'): if name: if os.path.isfile(name): @@ -129,6 +131,23 @@ def _excluded_channels(self, index): return excluded_channels + def __iter__(self): + if self._iter_channels: + for i, group in enumerate(self.groups): + try: + master_index = self.masters_db[i] + except KeyError: + master_index = -1 + + for j, _ in enumerate(group['channels']): + if j == master_index: + continue + yield self.get(group=i, index=j) + else: + for dataframe in self.iter_to_pandas(): + yield dataframe + + def convert(self, to, memory='full'): """convert MDF to other versions From 0fb9e17c59424d703f15084edd75a2daa669fe32 Mon Sep 17 00:00:00 2001 From: danielhrisca Date: Wed, 3 Jan 2018 20:32:47 +0200 Subject: [PATCH 086/117] remove unused import and make codacy happy --- asammdf/mdf.py | 1 - test/test_mdf23.py | 1 - test/test_mdf4.py | 1 - 3 files changed, 3 deletions(-) diff --git a/asammdf/mdf.py b/asammdf/mdf.py index 7c6792925..c10a7e3ff 100644 --- a/asammdf/mdf.py +++ b/asammdf/mdf.py @@ -3,7 +3,6 @@ import csv import os -from collections import defaultdict from warnings import warn from functools import reduce from struct import unpack diff --git a/test/test_mdf23.py b/test/test_mdf23.py index 0c5705799..3ca297583 100644 --- a/test/test_mdf23.py +++ b/test/test_mdf23.py @@ -1,6 +1,5 @@ #!/usr/bin/env python from __future__ import print_function -import os import unittest import numpy as np diff --git a/test/test_mdf4.py b/test/test_mdf4.py index 6b5af02b5..7c4ec93f0 100644 --- a/test/test_mdf4.py +++ b/test/test_mdf4.py @@ -1,6 +1,5 @@ #!/usr/bin/env python from __future__ import print_function -import os import unittest import numpy as np From ee192e8f9e00d2920227717386ff9df62b1f569e Mon Sep 17 00:00:00 2001 From: danielhrisca Date: Wed, 3 Jan 2018 20:44:56 +0200 Subject: [PATCH 087/117] use the proper class static attribute for the option to iteretare channels or pandas dataframes --- asammdf/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/asammdf/__init__.py b/asammdf/__init__.py index dba311c65..97a8943d7 100644 --- a/asammdf/__init__.py +++ b/asammdf/__init__.py @@ -66,4 +66,4 @@ def configure( MDF4._overwrite = bool(overwrite) if iter_channels is not None: - MDF.iter_channels = bool(iter_channels) + MDF._iter_channels = bool(iter_channels) From b3f8b669b53fe37bc8d7cad0b877600fed05759b Mon Sep 17 00:00:00 2001 From: danielhrisca Date: Thu, 4 Jan 2018 10:21:34 +0200 Subject: [PATCH 088/117] added __len__, __contains__ and whereis methods to MDF class --- asammdf/mdf.py | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/asammdf/mdf.py b/asammdf/mdf.py index c10a7e3ff..f4c678571 100644 --- a/asammdf/mdf.py +++ b/asammdf/mdf.py @@ -130,6 +130,9 @@ def _excluded_channels(self, index): return excluded_channels + def __contains__(self, channel): + return channel in self.channels_db + def __iter__(self): if self._iter_channels: for i, group in enumerate(self.groups): @@ -146,6 +149,11 @@ def __iter__(self): for dataframe in self.iter_to_pandas(): yield dataframe + def __len__(self): + return sum( + len(channel_ocurrences) + for channel_ocurrences in self.channels_db.values() + ) def convert(self, to, memory='full'): """convert MDF to other versions @@ -969,6 +977,33 @@ def select(self, channels, dataframe=False): return signals + def whereis(self, channel): + """ get ocurrences of channel name in the file + + Parameters + ---------- + channel : str + channel name string + + Returns + ------- + ocurrences : tuple + + + Examples + -------- + >>> mdf = MDF(file_name) + >>> mdf.whereis('VehicleSpeed') # "VehicleSpeed" exists in the file + ((1, 2), (2, 4)) + >>> mdf.whereis('VehicleSPD') # "VehicleSPD" doesn't exist in the file + () + + """ + if channel in self: + return tuple(self.channels_db[channel]) + else: + return tuple() + if __name__ == '__main__': pass From 3512df9c752bb54dd8ad780571845696a0bc5a8f Mon Sep 17 00:00:00 2001 From: danielhrisca Date: Thu, 4 Jan 2018 13:10:28 +0200 Subject: [PATCH 089/117] code style changes --- asammdf/mdf.py | 53 +++++++---- asammdf/mdf_v2_v3.py | 160 ++++++++++++++++++++------------ asammdf/mdf_v4.py | 211 ++++++++++++++++++++++++++++++------------- asammdf/signal.py | 178 +++++++++++++++++++++--------------- 4 files changed, 389 insertions(+), 213 deletions(-) diff --git a/asammdf/mdf.py b/asammdf/mdf.py index f4c678571..218a06758 100644 --- a/asammdf/mdf.py +++ b/asammdf/mdf.py @@ -3,6 +3,7 @@ import csv import os +import sys from warnings import warn from functools import reduce from struct import unpack @@ -17,6 +18,10 @@ from .v2_v3_blocks import Channel as ChannelV3 from .v4_blocks import TextBlock as TextBlockV4 +PYVERSION = sys.version_info[0] +if PYVERSION > 2: + from past.builtins import long + MDF2_VERSIONS = ('2.00', '2.10', '2.14') MDF3_VERSIONS = ('3.00', '3.10', '3.20', '3.30') MDF4_VERSIONS = ('4.00', '4.10', '4.11') @@ -118,7 +123,7 @@ def _excluded_channels(self, index): if dependencies is None: continue if all(dep['id'] == b'##CN' - if not isinstance(dep, int) else True + if not isinstance(dep, (int, long)) else True for dep in dependencies): for ch in dependencies: excluded_channels.add(channels.index(ch)) @@ -173,8 +178,10 @@ def convert(self, to, memory='full'): """ if to not in SUPPORTED_VERSIONS: - message = ('Unknown output mdf version "{}".' - ' Available versions are {}') + message = ( + 'Unknown output mdf version "{}".' + ' Available versions are {}' + ) warn(message.format(to, SUPPORTED_VERSIONS)) return else: @@ -444,15 +451,19 @@ def export(self, fmt, filename=None): writer = csv.writer(csvfile, delimiter=';') ch_nr = len(grp['channels']) - channels = [self.get(group=i, index=j, data=data) - for j in range(ch_nr)] + channels = [ + self.get(group=i, index=j, data=data) + for j in range(ch_nr) + ] master_index = self.masters_db[i] cycles = grp['channel_group']['cycles_nr'] names_row = ['Channel', ] - names_row += ['{} [{}]'.format(ch.name, ch.unit) - for ch in channels] + names_row += [ + '{} [{}]'.format(ch.name, ch.unit) + for ch in channels + ] writer.writerow(names_row) comment_row = ['comment', ] @@ -460,8 +471,10 @@ def export(self, fmt, filename=None): writer.writerow(comment_row) master_row = ['Is master', ] - master_row += ['x' if j == master_index else '' - for j in range(ch_nr)] + master_row += [ + 'x' if j == master_index else '' + for j in range(ch_nr) + ] writer.writerow(master_row) vals = [np.array(range(cycles), dtype=np.uint32), ] @@ -606,7 +619,7 @@ def filter(self, channels, memory=None): if dependencies is None: continue if all(dep['id'] == b'##CN' - if not isinstance(dep, int) else True + if not isinstance(dep, (int, long)) else True for dep in dependencies): channels = grp['channels'] for ch in dependencies: @@ -683,8 +696,10 @@ def merge(files, outversion='4.10', memory='full'): ] if not len(set(len(file.groups) for file in files)) == 1: - message = ("Can't merge files: " - "difference in number of data groups") + message = ( + "Can't merge files: " + "difference in number of data groups" + ) raise MdfException(message) merged = MDF( @@ -695,8 +710,10 @@ def merge(files, outversion='4.10', memory='full'): for i, groups in enumerate(zip(*(file.groups for file in files))): channels_nr = set(len(group['channels']) for group in groups) if not len(channels_nr) == 1: - message = ("Can't merge files: " - "different channel number for data groups {}") + message = ( + "Can't merge files: " + "different channel number for data groups {}" + ) raise MdfException(message.format(i)) signals = [] @@ -723,7 +740,7 @@ def merge(files, outversion='4.10', memory='full'): channel_texts = grp['texts']['channels'][j] if channel_texts and \ 'long_name_addr' in channel_texts: - address = grp['texts']['channels'][j]['long_name_addr'] + address = channel_texts['long_name_addr'] block = TextBlockV3( address=address, @@ -758,8 +775,10 @@ def merge(files, outversion='4.10', memory='full'): else: names = set(ch.name for ch in channels) if not len(names) == 1: - message = ("Can't merge files: " - "different channel names for data group {}") + message = ( + "Can't merge files: " + "different channel names for data group {}" + ) raise MdfException(message.format(i)) if j in excluded_channels: diff --git a/asammdf/mdf_v2_v3.py b/asammdf/mdf_v2_v3.py index 444ead50d..ce9913e55 100644 --- a/asammdf/mdf_v2_v3.py +++ b/asammdf/mdf_v2_v3.py @@ -277,15 +277,23 @@ def _prepare_record(self, group): if memory == 'minimum': channel_texts = grp['texts']['channels'][original_index] if channel_texts and 'long_name_addr' in channel_texts: - address = grp['texts']['channels'][original_index]['long_name_addr'] + address = channel_texts['long_name_addr'] block = TextBlock( address=address, stream=stream, ) - name = block['text'].decode('latin-1').strip(' \r\n\t\0') + name = ( + block['text'] + .decode('latin-1') + .strip(' \r\n\t\0') + ) else: - name = new_ch['short_name'].decode('latin-1').strip(' \r\n\t\0') + name = ( + new_ch['short_name'] + .decode('latin-1') + .strip(' \r\n\t\0') + ) name = name.split('\\')[0] else: name = new_ch.name @@ -496,8 +504,10 @@ def _validate_channel_selection(self, name=None, group=None, index=None): """ if name is None: if group is None or index is None: - message = ('Invalid arguments for channel selection: ' - 'must give "name" or, "group" and "index"') + message = ( + 'Invalid arguments for channel selection: ' + 'must give "name" or, "group" and "index"' + ) raise MdfException(message) else: gp_nr, ch_nr = group, index @@ -513,10 +523,12 @@ def _validate_channel_selection(self, name=None, group=None, index=None): if group is None: gp_nr, ch_nr = self.channels_db[name][0] if len(self.channels_db[name]) > 1: - message = ('Multiple occurances for channel "{}". ' - 'Using first occurance from data group {}. ' - 'Provide both "group" and "index" arguments' - ' to select another data group') + message = ( + 'Multiple occurances for channel "{}". ' + 'Using first occurance from data group {}. ' + 'Provide both "group" and "index" arguments' + ' to select another data group' + ) message = message.format(name, gp_nr) warnings.warn(message) else: @@ -555,9 +567,11 @@ def _read(self): ) self.header = HeaderBlock(stream=stream) - self.version = self.identification['version_str'] \ - .decode('latin-1') \ + self.version = ( + self.identification['version_str'] + .decode('latin-1') .strip(' \n\t\0') + ) self.file_history = TextBlock( address=self.header['comment_addr'], @@ -925,8 +939,8 @@ def append(self, common_timebase=False): """Appends a new data group. - For channel dependencies type Signals, the *samples* attribute must be a - numpy.recarray + For channel dependencies type Signals, the *samples* attribute must be + a numpy.recarray Parameters ---------- @@ -1006,26 +1020,26 @@ def append(self, # be saved as new signals. simple_signals = [ sig for sig in signals - if len(sig.samples.shape) <= 1 and - sig.samples.dtype.names is None + if len(sig.samples.shape) <= 1 + and sig.samples.dtype.names is None ] composed_signals = [ sig for sig in signals - if len(sig.samples.shape) > 1 or - sig.samples.dtype.names + if len(sig.samples.shape) > 1 + or sig.samples.dtype.names ] # mdf version 4 structure channels and CANopen types will be saved to # new channel groups new_groups_signals = [ sig for sig in composed_signals - if sig.samples.dtype.names and - sig.samples.dtype.names[0] != sig.name + if sig.samples.dtype.names + and sig.samples.dtype.names[0] != sig.name ] composed_signals = [ sig for sig in composed_signals - if not sig.samples.dtype.names or - sig.samples.dtype.names[0] == sig.name + if not sig.samples.dtype.names + or sig.samples.dtype.names[0] == sig.name ] if simple_signals or composed_signals: @@ -1224,7 +1238,7 @@ def append(self, texts = {} info = signal.info - if info and 'raw' in info and not info['raw'].dtype.kind == 'S': + if info and 'raw' in info and info['raw'].dtype.kind != 'S': kargs = {} kargs['conversion_type'] = v23c.CONVERSION_TYPE_VTAB raw = info['raw'] @@ -1406,7 +1420,7 @@ def append(self, texts = {} info = signal.info - if info and 'raw' in info and not info['raw'].dtype.kind == 'S': + if info and 'raw' in info and info['raw'].dtype.kind != 'S': kargs = {} kargs['conversion_type'] = v23c.CONVERSION_TYPE_VTAB raw = info['raw'] @@ -1678,8 +1692,8 @@ def append(self, ch_cntr += 1 - for i, (name, samples) in enumerate(zip(component_names, - component_samples)): + for i, (name, samples) in enumerate( + zip(component_names, component_samples)): for _, item in gp['texts'].items(): item.append(None) @@ -1926,8 +1940,9 @@ def append(self, ch_cntr += 1 names = signal.samples.dtype.names - if names == ('ms', - 'days'): + if names == ( + 'ms', + 'days'): block = TextBlock(text='From mdf v4 CANopen Time channel') if memory == 'minimum': address = tell() @@ -1935,14 +1950,15 @@ def append(self, gp_texts['channel_group'][-1] = {'comment_addr': address} else: gp_texts['channel_group'][-1] = {'comment_addr': block} - elif names == ('ms', - 'min', - 'hour', - 'day', - 'month', - 'year', - 'summer_time', - 'day_of_week'): + elif names == ( + 'ms', + 'min', + 'hour', + 'day', + 'month', + 'year', + 'summer_time', + 'day_of_week'): block = TextBlock(text='From mdf v4 CANopen Date channel') if memory == 'minimum': address = tell() @@ -2318,7 +2334,7 @@ def get(self, Raises ------ - MdfError : + MdfException : * if the channel name is not found * if the group index is out of range @@ -2583,9 +2599,15 @@ def get(self, v23c.CONVERSION_TYPE_TABX): nr = conversion['ref_param_nr'] - raw_vals = [conversion['raw_{}'.format(i)] for i in range(nr)] + raw_vals = [ + conversion['raw_{}'.format(i)] + for i in range(nr) + ] raw_vals = array(raw_vals) - phys = [conversion['phys_{}'.format(i)] for i in range(nr)] + phys = [ + conversion['phys_{}'.format(i)] + for i in range(nr) + ] phys = array(phys) if conversion_type == v23c.CONVERSION_TYPE_TABI: vals = interp(vals, raw_vals, phys) @@ -2601,7 +2623,10 @@ def get(self, for i in range(nr) ] raw_vals = array(raw_vals) - phys = [conversion['text_{}'.format(i)] for i in range(nr)] + phys = [ + conversion['text_{}'.format(i)] + for i in range(nr) + ] phys = array(phys) info = {'raw': raw_vals, 'phys': phys} @@ -2644,8 +2669,9 @@ def get(self, upper = array(upper) info = {'lower': lower, 'upper': upper, 'phys': texts} - elif conversion_type in (v23c.CONVERSION_TYPE_EXPO, - v23c.CONVERSION_TYPE_LOGH): + elif conversion_type in ( + v23c.CONVERSION_TYPE_EXPO, + v23c.CONVERSION_TYPE_LOGH): if conversion_type == v23c.CONVERSION_TYPE_EXPO: func = log else: @@ -2913,16 +2939,19 @@ def info(self): ch_type = 'master' else: ch_type = 'value' - inf['channel {}'.format(j)] = 'name="{}" type={}'.format(name, ch_type) + inf['channel {}'.format(j)] = 'name="{}" type={}'.format( + name, + ch_type, + ) return info def save(self, dst='', overwrite=None, compression=0): """Save MDF to *dst*. If *dst* is not provided the the destination file name is the MDF name. If overwrite is *True* then the destination file - is overwritten, otherwise the file name is appended with '_', were - '' is the first counter that produces a new file name (that does - not already exist in the filesystem). + is overwritten, otherwise the file name is appended with '_', + were '' is the first counter that produces a new file name (that + does not already exist in the filesystem). Parameters ---------- @@ -2968,9 +2997,9 @@ def save(self, dst='', overwrite=None, compression=0): def _save_with_metadata(self, dst, overwrite, compression): """Save MDF to *dst*. If *dst* is not provided the the destination file name is the MDF name. If overwrite is *True* then the destination file - is overwritten, otherwise the file name is appended with '_', were - '' is the first counter that produces a new file name (that does - not already exist in the filesystem). + is overwritten, otherwise the file name is appended with '_', + were '' is the first counter that produces a new file name (that + does not already exist in the filesystem). Parameters ---------- @@ -3004,8 +3033,10 @@ def _save_with_metadata(self, dst, overwrite, compression): self.file_history = TextBlock(text=text) if self.name is None and dst == '': - message = ('Must specify a destination file name ' - 'for MDF created from scratch') + message = ( + 'Must specify a destination file name ' + 'for MDF created from scratch' + ) raise MdfException(message) dst = dst if dst else self.name @@ -3019,8 +3050,10 @@ def _save_with_metadata(self, dst, overwrite, compression): break else: cntr += 1 - message = ('Destination file "{}" already exists ' - 'and "overwrite" is False. Saving MDF file as "{}"') + message = ( + 'Destination file "{}" already exists ' + 'and "overwrite" is False. Saving MDF file as "{}"' + ) message = message.format(dst, name) warnings.warn(message) dst = name @@ -3278,9 +3311,9 @@ def _save_with_metadata(self, dst, overwrite, compression): def _save_without_metadata(self, dst, overwrite, compression): """Save MDF to *dst*. If *dst* is not provided the the destination file name is the MDF name. If overwrite is *True* then the destination file - is overwritten, otherwise the file name is appended with '_', were - '' is the first counter that produces a new file name (that does - not already exist in the filesystem). + is overwritten, otherwise the file name is appended with '_', + were '' is the first counter that produces a new file name (that + does not already exist in the filesystem). Parameters ---------- @@ -3329,8 +3362,10 @@ def _save_without_metadata(self, dst, overwrite, compression): # data block in the soource MDF file. if self.name is None and dst == '': - message = ('Must specify a destination file name ' - 'for MDF created from scratch') + message = ( + 'Must specify a destination file name ' + 'for MDF created from scratch' + ) raise MdfException(message) dst = dst if dst else self.name @@ -3344,8 +3379,10 @@ def _save_without_metadata(self, dst, overwrite, compression): break else: cntr += 1 - message = ('Destination file "{}" already exists ' - 'and "overwrite" is False. Saving MDF file as "{}"') + message = ( + 'Destination file "{}" already exists ' + 'and "overwrite" is False. Saving MDF file as "{}"' + ) message = message.format(dst, name) warnings.warn(message) dst = name @@ -3537,7 +3574,10 @@ def _save_without_metadata(self, dst, overwrite, compression): del gp['temp_channel_conversions'] del gp['temp_channel_extensions'] - orig_addr = [gp['data_group']['data_block_addr'] for gp in self.groups] + orig_addr = [ + gp['data_group']['data_block_addr'] + for gp in self.groups + ] address = tell() gp_rec_ids = [] for i, gp in enumerate(self.groups): diff --git a/asammdf/mdf_v4.py b/asammdf/mdf_v4.py index f4ca83fe8..1798e2d1f 100644 --- a/asammdf/mdf_v4.py +++ b/asammdf/mdf_v4.py @@ -922,9 +922,9 @@ def _prepare_record(self, group): ch_type = new_ch['channel_type'] dependency_list = grp['channel_dependencies'][original_index] if memory == 'minimum': + channel_texts = grp['texts']['channels'][original_index] block = TextBlock( - address=grp['texts']['channels'] - [original_index]['name_addr'], + address=channel_texts['name_addr'], stream=stream, ) name = block['text'].decode('utf-8').strip(' \r\n\t\0') @@ -1051,9 +1051,9 @@ def _get_not_byte_aligned_data(self, data, group, ch_nr): byte_offset = channel['byte_offset'] bit_count = channel['bit_count'] - dependency_list = group['channel_dependencies'][ch_nr] - if dependency_list and isinstance(dependency_list[0], ChannelArrayBlock): - ca_block = dependency_list[0] + dependencies = group['channel_dependencies'][ch_nr] + if dependencies and isinstance(dependencies[0], ChannelArrayBlock): + ca_block = dependencies[0] size = bit_count >> 3 shape = tuple( @@ -1061,7 +1061,7 @@ def _get_not_byte_aligned_data(self, data, group, ch_nr): for i in range(ca_block['dims']) ) if ca_block['byte_offset_base'] // size > 1 and len(shape) == 1: - shape += (ca_block['byte_offset_base'] // size,) + shape += (ca_block['byte_offset_base'] // size, ) dim = 1 for d in shape: dim *= d @@ -1181,8 +1181,10 @@ def _validate_channel_selection(self, name=None, group=None, index=None): """ if name is None: if group is None or index is None: - message = ('Invalid arguments for channel selection: ' - 'must give "name" or, "group" and "index"') + message = ( + 'Invalid arguments for channel selection: ' + 'must give "name" or, "group" and "index"' + ) raise MdfException(message) else: gp_nr, ch_nr = group, index @@ -1231,8 +1233,8 @@ def append(self, signals, source_info='Python', common_timebase=False): """ Appends a new data group. - For channel dependencies type Signals, the *samples* attribute must be a - numpy.recarray + For channel dependencies type Signals, the *samples* attribute must be + a numpy.recarray Parameters ---------- @@ -1299,12 +1301,13 @@ def append(self, signals, source_info='Python', common_timebase=False): # be saved as new signals. simple_signals = [ sig for sig in signals - if len(sig.samples.shape) <= 1 and sig.samples.dtype.names is None + if len(sig.samples.shape) <= 1 + and sig.samples.dtype.names is None ] composed_signals = [ sig for sig in signals - if len(sig.samples.shape) > 1 or - sig.samples.dtype.names + if len(sig.samples.shape) > 1 + or sig.samples.dtype.names ] dg_cntr = len(self.groups) @@ -1595,7 +1598,6 @@ def append(self, signals, source_info='Python', common_timebase=False): upper = info['upper'] texts = info['phys'] kargs['ref_param_nr'] = len(upper) -# kargs['default_addr'] = info.get('default', 0) kargs['links_nr'] = len(lower) + 5 for i, (u_, l_, t_) in enumerate(zip(upper, lower, texts)): @@ -2594,9 +2596,11 @@ def extract_attachment(self, index): if flags & v4c.FLAG_AT_EMBEDDED: data = attachment.extract() - file_path = texts['file_name_addr']['text'] \ - .decode('utf-8') \ + file_path = ( + texts['file_name_addr']['text'] + .decode('utf-8') .strip(' \n\t\0') + ) out_path = os.path.dirname(file_path) if out_path: if not os.path.exists(out_path): @@ -2609,24 +2613,28 @@ def extract_attachment(self, index): else: # for external attachments read the file and return the content if flags & v4c.FLAG_AT_MD5_VALID: - file_path = texts['file_name_addr']['text'] \ - .decode('utf-8') \ + file_path = ( + texts['file_name_addr']['text'] + .decode('utf-8') .strip(' \n\t\0') + ) data = open(file_path, 'rb').read() md5_worker = md5() md5_worker.update(data) md5_sum = md5_worker.digest() if attachment['md5_sum'] == md5_sum: - if texts['mime_addr']['text'] \ - .decode('utf-8') \ - .startswith('text'): + if (texts['mime_addr']['text'] + .decode('utf-8') + .startswith('text')): with open(file_path, 'r') as f: data = f.read() return data else: - message = ('ATBLOCK md5sum="{}" ' - 'and external attachment data ({}) ' - 'md5sum="{}"') + message = ( + 'ATBLOCK md5sum="{}" ' + 'and external attachment data ({}) ' + 'md5sum="{}"' + ) message = message.format( attachment['md5_sum'], file_path, @@ -2634,9 +2642,9 @@ def extract_attachment(self, index): ) warnings.warn(message) else: - if texts['mime_addr']['text'] \ - .decode('utf-8') \ - .startswith('text'): + if (texts['mime_addr']['text'] + .decode('utf-8') + .startswith('text')): mode = 'r' else: mode = 'rb' @@ -2861,13 +2869,13 @@ def get(self, The *Signal* samples are: * numpy recarray for channels that have composition/channel - array address or for channel of type BYTEARRAY, CANOPENDATE, - CANOPENTIME + array address or for channel of type BYTEARRAY, + CANOPENDATE, CANOPENTIME * numpy array for all the rest Raises ------ - MdfError : + MdfException : * if the channel name is not found * if the group index is out of range @@ -2994,7 +3002,9 @@ def get(self, arrays = [] name = channel.name - if all(isinstance(dep, (Channel, int, long)) for dep in dependency_list): + if all( + isinstance(dep, (Channel, int, long)) + for dep in dependency_list): # structure channel composition if memory == 'minimum': names = [] @@ -3020,7 +3030,10 @@ def get(self, for name_ in names ] - types = [(name_, arr.dtype) for name_, arr in zip(names, arrays)] + types = [ + (name_, arr.dtype) + for name_, arr in zip(names, arrays) + ] if PYVERSION == 2: types = fix_dtype_fields(types) types = dtype(types) @@ -3100,15 +3113,30 @@ def get(self, for i in range(dims_nr): ch_nr, dg_nr = ca_block.referenced_channels[i] if memory == 'minimum': - axisname = self.groups[dg_nr]['texts']['channels'][ch_nr]['name_addr'] + axisname = ( + self.groups[dg_nr] + ['texts'] + ['channels'] + [ch_nr] + ['name_addr'] + ) block = TextBlock( address=axisname, stream=stream, ) - axisname = block['text'].decode('utf-8').strip(' \t\n\r\0') + axisname = ( + block['text'] + .decode('utf-8') + .strip(' \t\n\r\0') + ) axisname = axisname.split('\\')[0] else: - axisname = self.groups[dg_nr]['channels'][ch_nr].name + axisname = ( + self.groups[dg_nr] + ['channels'] + [ch_nr] + .name + ) shape = (ca_block['dim_size_{}'.format(i)],) axis_values = self.get( group=dg_nr, @@ -3148,15 +3176,30 @@ def get(self, for i in range(dims_nr): ch_nr, dg_nr = ca_block.referenced_channels[i] if memory == 'minimum': - axisname = self.groups[dg_nr]['texts']['channels'][ch_nr]['name_addr'] + axisname = ( + self.groups[dg_nr] + ['texts'] + ['channels'] + [ch_nr] + ['name_addr'] + ) block = TextBlock( address=axisname, stream=stream, ) - axisname = block['text'].decode('utf-8').strip(' \t\n\r\0') + axisname = ( + block['text'] + .decode('utf-8') + .strip(' \t\n\r\0') + ) axisname = axisname.split('\\')[0] else: - axisname = self.groups[dg_nr]['channels'][ch_nr].name + axisname = ( + self.groups[dg_nr] + ['channels'] + [ch_nr] + .name + ) shape = (ca_block['dim_size_{}'.format(i)],) axis_values = self.get( group=dg_nr, @@ -3204,7 +3247,11 @@ def get(self, data_type = channel['data_type'] if vals.dtype.kind not in 'ui' and (bit_offset or not bits == size * 8): - vals = self._get_not_byte_aligned_data(data, grp, ch_nr) + vals = self._get_not_byte_aligned_data( + data, + grp, + ch_nr, + ) else: if bit_offset: dtype_ = vals.dtype @@ -3237,7 +3284,10 @@ def get(self, vals |= masks - vals = vals.astype(' Date: Tue, 9 Jan 2018 09:12:47 +0200 Subject: [PATCH 090/117] changes after initial review in issue #32 --- asammdf/__init__.py | 20 ++++++++++---------- asammdf/mdf.py | 38 +++++++++++++++++--------------------- asammdf/mdf_v2_v3.py | 12 ++++++------ asammdf/mdf_v4.py | 14 +++++++------- asammdf/signal.py | 6 +++--- documentation/examples.rst | 20 ++++++++++---------- documentation/mdf.rst | 14 +++++++------- documentation/mdf23.rst | 8 ++++---- documentation/mdf4.rst | 8 ++++---- 9 files changed, 68 insertions(+), 72 deletions(-) diff --git a/asammdf/__init__.py b/asammdf/__init__.py index 97a8943d7..b24b2cd5e 100644 --- a/asammdf/__init__.py +++ b/asammdf/__init__.py @@ -1,8 +1,8 @@ # -*- coding: utf-8 -*- """ asammdf is a parser and editor for ASAM MDF files """ -from .mdf_v2_v3 import MDF23 -from .mdf_v4 import MDF4 +from .mdf_v2_v3 import MDF_V2_V3 +from .mdf_v4 import MDF_V4 from .mdf import MDF, SUPPORTED_VERSIONS from .signal import Signal from .version import __version__ @@ -11,8 +11,8 @@ '__version__', 'configure', 'MDF', - 'MDF23', - 'MDF4', + 'MDF_V2_V3', + 'MDF_V4', 'Signal', 'SUPPORTED_VERSIONS', ] @@ -52,18 +52,18 @@ def configure( """ if integer_compacting is not None: - MDF23._compact_integers_on_append = bool(integer_compacting) - MDF4._compact_integers_on_append = bool(integer_compacting) + MDF_V2_V3._compact_integers_on_append = bool(integer_compacting) + MDF_V4._compact_integers_on_append = bool(integer_compacting) if split_threshold is not None: - MDF4._split_threshold = int(split_threshold) + MDF_V4._split_threshold = int(split_threshold) if split_data_blocks is not None: - MDF4._split_data_blocks = bool(split_data_blocks) + MDF_V4._split_data_blocks = bool(split_data_blocks) if overwrite is not None: - MDF23._overwrite = bool(overwrite) - MDF4._overwrite = bool(overwrite) + MDF_V2_V3._overwrite = bool(overwrite) + MDF_V4._overwrite = bool(overwrite) if iter_channels is not None: MDF._iter_channels = bool(iter_channels) diff --git a/asammdf/mdf.py b/asammdf/mdf.py index 218a06758..530d1c940 100644 --- a/asammdf/mdf.py +++ b/asammdf/mdf.py @@ -139,26 +139,9 @@ def __contains__(self, channel): return channel in self.channels_db def __iter__(self): - if self._iter_channels: - for i, group in enumerate(self.groups): - try: - master_index = self.masters_db[i] - except KeyError: - master_index = -1 - - for j, _ in enumerate(group['channels']): - if j == master_index: - continue - yield self.get(group=i, index=j) - else: - for dataframe in self.iter_to_pandas(): - yield dataframe - - def __len__(self): - return sum( - len(channel_ocurrences) - for channel_ocurrences in self.channels_db.values() - ) + # the default is to yield from iter_channels + for signal in self.iter_channels(): + yield signal def convert(self, to, memory='full'): """convert MDF to other versions @@ -800,7 +783,20 @@ def merge(files, outversion='4.10', memory='full'): return merged - def iter_to_pandas(self): + def iter_channels(self): + """ generator that yields a `Signal` for each non-master channel""" + for i, group in enumerate(self.groups): + try: + master_index = self.masters_db[i] + except KeyError: + master_index = -1 + + for j, _ in enumerate(group['channels']): + if j == master_index: + continue + yield self.get(group=i, index=j) + + def iter_groups(self): """ generator that yields channel groups as pandas DataFrames""" for i, gp in enumerate(self.groups): diff --git a/asammdf/mdf_v2_v3.py b/asammdf/mdf_v2_v3.py index ce9913e55..ab811f644 100644 --- a/asammdf/mdf_v2_v3.py +++ b/asammdf/mdf_v2_v3.py @@ -72,10 +72,10 @@ if PYVERSION == 2: from .utils import bytes -__all__ = ['MDF23', ] +__all__ = ['MDF_V2_V3', ] -class MDF23(object): +class MDF_V2_V3(object): """If the *name* exist it will be loaded otherwise an empty file will be created that can be later saved to disk @@ -965,14 +965,14 @@ def append(self, >>> s1 = Signal(samples=s1, timstamps=t, unit='+', name='Positive') >>> s2 = Signal(samples=s2, timstamps=t, unit='-', name='Negative') >>> s3 = Signal(samples=s3, timstamps=t, unit='flts', name='Floats') - >>> mdf = MDF3('new.mdf') + >>> mdf = MDF_V2_V3('new.mdf') >>> mdf.append([s1, s2, s3], 'created by asammdf v1.1.0') >>> # case 2: VTAB conversions from channels inside another file - >>> mdf1 = MDF3('in.mdf') + >>> mdf1 = MDF_V2_V3('in.mdf') >>> ch1 = mdf1.get("Channel1_VTAB") >>> ch2 = mdf1.get("Channel2_VTABR") >>> sigs = [ch1, ch2] - >>> mdf2 = MDF3('out.mdf') + >>> mdf2 = MDF_V2_V3('out.mdf') >>> mdf2.append(sigs, 'created by asammdf v1.1.0') """ @@ -2894,7 +2894,7 @@ def info(self): Examples -------- - >>> mdf = MDF3('test.mdf') + >>> mdf = MDF_V2_V3('test.mdf') >>> mdf.info() """ diff --git a/asammdf/mdf_v4.py b/asammdf/mdf_v4.py index 1798e2d1f..4f7cd3cfc 100644 --- a/asammdf/mdf_v4.py +++ b/asammdf/mdf_v4.py @@ -90,10 +90,10 @@ else: from past.builtins import long -__all__ = ['MDF4', ] +__all__ = ['MDF_V4', ] -class MDF4(object): +class MDF_V4(object): """If the *name* exist it will be memorised otherwise an empty file will be created that can be later saved to disk @@ -3922,7 +3922,7 @@ def info(self): Examples -------- - >>> mdf = MDF4('test.mdf') + >>> mdf = MDF_V4('test.mdf') >>> mdf.info() @@ -4112,9 +4112,9 @@ def _save_with_metadata(self, dst, overwrite, compression): data = self._load_group_data(gp) - if MDF4._split_data_blocks: + if MDF_V4._split_data_blocks: samples_size = gp['channel_group']['samples_byte_nr'] - split_size = MDF4._split_threshold // samples_size + split_size = MDF_V4._split_threshold // samples_size split_size *= samples_size if split_size == 0: chunks = 1 @@ -4598,9 +4598,9 @@ def _save_without_metadata(self, dst, overwrite, compression): data = self._load_group_data(gp) - if MDF4._split_data_blocks: + if MDF_V4._split_data_blocks: samples_size = gp['channel_group']['samples_byte_nr'] - split_size = MDF4._split_threshold // samples_size + split_size = MDF_V4._split_threshold // samples_size split_size *= samples_size if split_size == 0: chunks = 1 diff --git a/asammdf/signal.py b/asammdf/signal.py index 6bf8657fb..d3156a078 100644 --- a/asammdf/signal.py +++ b/asammdf/signal.py @@ -319,9 +319,9 @@ def cut(self, start=None, stop=None): stop_ = np.searchsorted(self.timestamps, stop, side='right') if stop_ == start_: - if len(self.timestamps) and \ - stop >= self.timestamps[0] and \ - start <= self.timestamps[-1]: + if (len(self.timestamps) + and stop >= self.timestamps[0] + and start <= self.timestamps[-1]): # start and stop are found between 2 signal samples # so return the previous sample result = Signal( diff --git a/documentation/examples.rst b/documentation/examples.rst index 541e3e3c4..63b8081ff 100644 --- a/documentation/examples.rst +++ b/documentation/examples.rst @@ -58,17 +58,17 @@ Working with MDF unit='f8') # create empty MDf version 4.00 file - mdf4 = MDF(version='4.10') + MDF_V4 = MDF(version='4.10') # append the 3 signals to the new file signals = [s_uint8, s_int32, s_float64] - mdf4.append(signals, 'Created by Python') + MDF_V4.append(signals, 'Created by Python') # save new file - mdf4.save('my_new_file.mf4', overwrite=True) + MDF_V4.save('my_new_file.mf4', overwrite=True) # convert new file to mdf version 3.10 with lower possible RAM usage - mdf3 = mdf4.convert(to='3.10', memory='minimum') + mdf3 = MDF_V4.convert(to='3.10', memory='minimum') print(mdf3.version) # get the float signal @@ -76,18 +76,18 @@ Working with MDF print(sig) # cut measurement from 0.3s to end of measurement - mdf4_cut = mdf4.cut(start=0.3) - mdf4_cut.get('Float64_Signal').plot() + MDF_V4_cut = MDF_V4.cut(start=0.3) + MDF_V4_cut.get('Float64_Signal').plot() # cut measurement from start of measurement to 0.4s - mdf4_cut = mdf4.cut(stop=0.45) - mdf4_cut.get('Float64_Signal').plot() + MDF_V4_cut = MDF_V4.cut(stop=0.45) + MDF_V4_cut.get('Float64_Signal').plot() # filter some signals from the file - mdf4 = mdf4.filter(['Int32_Signal', 'Uint8_Signal']) + MDF_V4 = MDF_V4.filter(['Int32_Signal', 'Uint8_Signal']) # save using zipped transpose deflate blocks - mdf4.save('out.mf4', compression=2, overwrite=True) + MDF_V4.save('out.mf4', compression=2, overwrite=True) Working with Signal diff --git a/documentation/mdf.rst b/documentation/mdf.rst index a3fef2a9a..46749663c 100644 --- a/documentation/mdf.rst +++ b/documentation/mdf.rst @@ -21,9 +21,9 @@ MDF === -This class acts as a proxy for the MDF23 and MDF4 classes. -All attribute access is delegated to the underlying *_mdf* attribute (MDF23 or MDF4 object). -See MDF23 and MDF4 for available extra methods. +This class acts as a proxy for the MDF_V2_V3 and MDF_V4 classes. +All attribute access is delegated to the underlying *_mdf* attribute (MDF_V2_V3 or MDF_V4 object). +See MDF_V2_V3 and MDF_V4 for available extra methods. An empty MDF file is created if the *name* argument is not provided. If the *name* argument is provided then the file must exist in the filesystem, otherwise an exception is raised. @@ -40,14 +40,14 @@ Best practice is to use the MDF as a context manager. This way all resources are :members: -MDF23 and MDF4 classes ----------------------- +MDF_V2_V3 and MDF_V4 classes +---------------------------- .. toctree:: :maxdepth: 1 - mdf23 - mdf4 + MDF_V2_V3 + MDF_V4 Notes about *memory* argument ----------------------------- diff --git a/documentation/mdf23.rst b/documentation/mdf23.rst index a3c3a1075..dc80eb792 100644 --- a/documentation/mdf23.rst +++ b/documentation/mdf23.rst @@ -16,10 +16,10 @@ .. role:: orange .. role:: brown -.. _mdf23: +.. _MDF_V2_V3: -MDF23 -===== +MDF_V2_V3 +========= asammdf tries to emulate the mdf structure using Python builtin data types. @@ -63,7 +63,7 @@ The *master_db* attibute is a dictionary that holds the *channel index* of the API --- -.. autoclass:: asammdf.mdf_v2_v3.MDF23 +.. autoclass:: asammdf.mdf_v2_v3.MDF_V2_V3 :members: :noindex: diff --git a/documentation/mdf4.rst b/documentation/mdf4.rst index 4e2a8c59c..1ba7e2df6 100644 --- a/documentation/mdf4.rst +++ b/documentation/mdf4.rst @@ -16,10 +16,10 @@ .. role:: orange .. role:: brown -.. _mdf4: +.. _MDF_V4: -MDF4 -==== +MDF_V4 +====== asammdf tries to emulate the mdf structure using Python builtin data types. @@ -72,7 +72,7 @@ The *master_db* attibute is a dictionary that holds the *channel index* of the API --- -.. autoclass:: asammdf.mdf_v4.MDF4 +.. autoclass:: asammdf.mdf_v4.MDF_V4 :members: :noindex: From 66ef59113d552b0715d6d171cc115ff0af1b243d Mon Sep 17 00:00:00 2001 From: danielhrisca Date: Tue, 9 Jan 2018 09:25:27 +0200 Subject: [PATCH 091/117] fix import error due to typo --- asammdf/mdf.py | 14 +++++++------- documentation/examples.rst | 20 ++++++++++---------- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/asammdf/mdf.py b/asammdf/mdf.py index 530d1c940..2757b4790 100644 --- a/asammdf/mdf.py +++ b/asammdf/mdf.py @@ -11,8 +11,8 @@ import numpy as np from pandas import DataFrame -from .mdf_v2_v3 import MDF23 -from .mdf_v4 import MDF4 +from .mdf_v2_v3 import MDF_V2_V3 +from .mdf_v4 import MDF_V4 from .utils import MdfException from .v2_v3_blocks import TextBlock as TextBlockV3 from .v2_v3_blocks import Channel as ChannelV3 @@ -66,11 +66,11 @@ def __init__(self, name=None, memory='full', version='4.10'): version = str(version) version = '{}.{}'.format(version[0], version[1:]) if version in MDF3_VERSIONS: - self._mdf = MDF23(name, memory) + self._mdf = MDF_V2_V3(name, memory) elif version in MDF4_VERSIONS: - self._mdf = MDF4(name, memory) + self._mdf = MDF_V4(name, memory) elif version in MDF2_VERSIONS: - self._mdf = MDF23(name, memory) + self._mdf = MDF_V2_V3(name, memory) else: message = ('"{}" is not a supported MDF file; ' '"{}" file version was found') @@ -79,12 +79,12 @@ def __init__(self, name=None, memory='full', version='4.10'): raise MdfException('File "{}" does not exist'.format(name)) else: if version in MDF2_VERSIONS + MDF3_VERSIONS: - self._mdf = MDF23( + self._mdf = MDF_V2_V3( version=version, memory=memory, ) elif version in MDF4_VERSIONS: - self._mdf = MDF4( + self._mdf = MDF_V4( version=version, memory=memory, ) diff --git a/documentation/examples.rst b/documentation/examples.rst index 63b8081ff..541e3e3c4 100644 --- a/documentation/examples.rst +++ b/documentation/examples.rst @@ -58,17 +58,17 @@ Working with MDF unit='f8') # create empty MDf version 4.00 file - MDF_V4 = MDF(version='4.10') + mdf4 = MDF(version='4.10') # append the 3 signals to the new file signals = [s_uint8, s_int32, s_float64] - MDF_V4.append(signals, 'Created by Python') + mdf4.append(signals, 'Created by Python') # save new file - MDF_V4.save('my_new_file.mf4', overwrite=True) + mdf4.save('my_new_file.mf4', overwrite=True) # convert new file to mdf version 3.10 with lower possible RAM usage - mdf3 = MDF_V4.convert(to='3.10', memory='minimum') + mdf3 = mdf4.convert(to='3.10', memory='minimum') print(mdf3.version) # get the float signal @@ -76,18 +76,18 @@ Working with MDF print(sig) # cut measurement from 0.3s to end of measurement - MDF_V4_cut = MDF_V4.cut(start=0.3) - MDF_V4_cut.get('Float64_Signal').plot() + mdf4_cut = mdf4.cut(start=0.3) + mdf4_cut.get('Float64_Signal').plot() # cut measurement from start of measurement to 0.4s - MDF_V4_cut = MDF_V4.cut(stop=0.45) - MDF_V4_cut.get('Float64_Signal').plot() + mdf4_cut = mdf4.cut(stop=0.45) + mdf4_cut.get('Float64_Signal').plot() # filter some signals from the file - MDF_V4 = MDF_V4.filter(['Int32_Signal', 'Uint8_Signal']) + mdf4 = mdf4.filter(['Int32_Signal', 'Uint8_Signal']) # save using zipped transpose deflate blocks - MDF_V4.save('out.mf4', compression=2, overwrite=True) + mdf4.save('out.mf4', compression=2, overwrite=True) Working with Signal From 467495080ace7f72dd23c1682a1c83c192243d6c Mon Sep 17 00:00:00 2001 From: danielhrisca Date: Tue, 9 Jan 2018 09:31:12 +0200 Subject: [PATCH 092/117] fix new class names in tests --- test/test_mdf23.py | 4 ++-- test/test_mdf4.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/test/test_mdf23.py b/test/test_mdf23.py index 3ca297583..cf9bfb63f 100644 --- a/test/test_mdf23.py +++ b/test/test_mdf23.py @@ -5,7 +5,7 @@ import numpy as np from utils import MEMORY -from asammdf import MDF, MDF23, Signal, configure +from asammdf import MDF, MDF_V2_V3, Signal, configure CHANNEL_LEN = 10000 @@ -18,7 +18,7 @@ class TestMDF23(unittest.TestCase): def test_measurement(self): - self.assertTrue(MDF23) + self.assertTrue(MDF_V2_V3) def test_read_mdf2_00(self): diff --git a/test/test_mdf4.py b/test/test_mdf4.py index 7c4ec93f0..d6b9420cb 100644 --- a/test/test_mdf4.py +++ b/test/test_mdf4.py @@ -5,7 +5,7 @@ import numpy as np from utils import MEMORY -from asammdf import MDF, MDF4, Signal +from asammdf import MDF, MDF_V4, Signal CHANNEL_LEN = 100000 @@ -13,7 +13,7 @@ class TestMDF4(unittest.TestCase): def test_measurement(self): - self.assertTrue(MDF4) + self.assertTrue(MDF_V4) def test_read_mdf4_00(self): From ece636c2548bee81fc152d2ad1c288148da88c49 Mon Sep 17 00:00:00 2001 From: danielhrisca Date: Tue, 9 Jan 2018 09:48:24 +0200 Subject: [PATCH 093/117] fix documentation --- documentation/mdf.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/documentation/mdf.rst b/documentation/mdf.rst index 46749663c..880e9719f 100644 --- a/documentation/mdf.rst +++ b/documentation/mdf.rst @@ -46,8 +46,8 @@ MDF_V2_V3 and MDF_V4 classes .. toctree:: :maxdepth: 1 - MDF_V2_V3 - MDF_V4 + mdf23 + mdf4 Notes about *memory* argument ----------------------------- From b9430787c6db0f928aa73107d102835f5101c4a2 Mon Sep 17 00:00:00 2001 From: danielhrisca Date: Tue, 9 Jan 2018 12:05:50 +0200 Subject: [PATCH 094/117] add skip_master argument to iter_channels --- asammdf/mdf.py | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/asammdf/mdf.py b/asammdf/mdf.py index 2757b4790..5754bbeef 100644 --- a/asammdf/mdf.py +++ b/asammdf/mdf.py @@ -783,8 +783,15 @@ def merge(files, outversion='4.10', memory='full'): return merged - def iter_channels(self): - """ generator that yields a `Signal` for each non-master channel""" + def iter_channels(self, skip_master=True): + """ generator that yields a `Signal` for each non-master channel + + Parameters + ---------- + skip_master : bool + do not yield master channels; default True + + """ for i, group in enumerate(self.groups): try: master_index = self.masters_db[i] @@ -792,7 +799,7 @@ def iter_channels(self): master_index = -1 for j, _ in enumerate(group['channels']): - if j == master_index: + if skip_master and j == master_index: continue yield self.get(group=i, index=j) From 0e30917d44c1e9776281058ce3953dd45276c8b8 Mon Sep 17 00:00:00 2001 From: danielhrisca Date: Tue, 9 Jan 2018 12:06:47 +0200 Subject: [PATCH 095/117] remove iter_channels configuration option --- asammdf/__init__.py | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/asammdf/__init__.py b/asammdf/__init__.py index b24b2cd5e..db1dd9d42 100644 --- a/asammdf/__init__.py +++ b/asammdf/__init__.py @@ -22,8 +22,7 @@ def configure( integer_compacting=None, split_data_blocks=None, split_threshold=None, - overwrite=None, - iter_channels=None): + overwrite=None): """ configure asammdf parameters Note @@ -45,9 +44,6 @@ def configure( the data groups' records size overwrite : bool default option for save method's overwrite argument - iter_channels : bool - default option to yield channels instead of pandas DataFrame when - iterating over the MDF objects """ @@ -64,6 +60,3 @@ def configure( if overwrite is not None: MDF_V2_V3._overwrite = bool(overwrite) MDF_V4._overwrite = bool(overwrite) - - if iter_channels is not None: - MDF._iter_channels = bool(iter_channels) From 6bf548842f6a10679ea2dac97ba28350d28d0939 Mon Sep 17 00:00:00 2001 From: danielhrisca Date: Wed, 10 Jan 2018 09:20:52 +0200 Subject: [PATCH 096/117] create separate MDF2 and MDF3 classes for disambiguation --- asammdf/__init__.py | 22 ++++++++++++---------- asammdf/mdf.py | 22 ++++++++++++++-------- asammdf/mdf_v2.py | 18 ++++++++++++++++++ asammdf/{mdf_v2_v3.py => mdf_v3.py} | 12 ++++++------ asammdf/mdf_v4.py | 14 +++++++------- asammdf/signal.py | 7 ++++++- documentation/mdf.rst | 12 ++++++------ documentation/{mdf23.rst => mdf3.rst} | 8 ++++---- documentation/mdf4.rst | 8 ++++---- test/test_mdf23.py | 5 +++-- test/test_mdf4.py | 6 +++--- 11 files changed, 83 insertions(+), 51 deletions(-) create mode 100644 asammdf/mdf_v2.py rename asammdf/{mdf_v2_v3.py => mdf_v3.py} (99%) rename documentation/{mdf23.rst => mdf3.rst} (97%) diff --git a/asammdf/__init__.py b/asammdf/__init__.py index db1dd9d42..da82f7991 100644 --- a/asammdf/__init__.py +++ b/asammdf/__init__.py @@ -1,8 +1,9 @@ # -*- coding: utf-8 -*- """ asammdf is a parser and editor for ASAM MDF files """ -from .mdf_v2_v3 import MDF_V2_V3 -from .mdf_v4 import MDF_V4 +from .mdf_v2 import MDF2 +from .mdf_v3 import MDF3 +from .mdf_v4 import MDF4 from .mdf import MDF, SUPPORTED_VERSIONS from .signal import Signal from .version import __version__ @@ -11,8 +12,9 @@ '__version__', 'configure', 'MDF', - 'MDF_V2_V3', - 'MDF_V4', + 'MDF2' + 'MDF3', + 'MDF4', 'Signal', 'SUPPORTED_VERSIONS', ] @@ -48,15 +50,15 @@ def configure( """ if integer_compacting is not None: - MDF_V2_V3._compact_integers_on_append = bool(integer_compacting) - MDF_V4._compact_integers_on_append = bool(integer_compacting) + MDF3._compact_integers_on_append = bool(integer_compacting) + MDF4._compact_integers_on_append = bool(integer_compacting) if split_threshold is not None: - MDF_V4._split_threshold = int(split_threshold) + MDF4._split_threshold = int(split_threshold) if split_data_blocks is not None: - MDF_V4._split_data_blocks = bool(split_data_blocks) + MDF4._split_data_blocks = bool(split_data_blocks) if overwrite is not None: - MDF_V2_V3._overwrite = bool(overwrite) - MDF_V4._overwrite = bool(overwrite) + MDF3._overwrite = bool(overwrite) + MDF4._overwrite = bool(overwrite) diff --git a/asammdf/mdf.py b/asammdf/mdf.py index 5754bbeef..6b5f82856 100644 --- a/asammdf/mdf.py +++ b/asammdf/mdf.py @@ -11,8 +11,9 @@ import numpy as np from pandas import DataFrame -from .mdf_v2_v3 import MDF_V2_V3 -from .mdf_v4 import MDF_V4 +from .mdf_v2 import MDF2 +from .mdf_v3 import MDF3 +from .mdf_v4 import MDF4 from .utils import MdfException from .v2_v3_blocks import TextBlock as TextBlockV3 from .v2_v3_blocks import Channel as ChannelV3 @@ -66,11 +67,11 @@ def __init__(self, name=None, memory='full', version='4.10'): version = str(version) version = '{}.{}'.format(version[0], version[1:]) if version in MDF3_VERSIONS: - self._mdf = MDF_V2_V3(name, memory) + self._mdf = MDF3(name, memory) elif version in MDF4_VERSIONS: - self._mdf = MDF_V4(name, memory) + self._mdf = MDF4(name, memory) elif version in MDF2_VERSIONS: - self._mdf = MDF_V2_V3(name, memory) + self._mdf = MDF2(name, memory) else: message = ('"{}" is not a supported MDF file; ' '"{}" file version was found') @@ -78,13 +79,18 @@ def __init__(self, name=None, memory='full', version='4.10'): else: raise MdfException('File "{}" does not exist'.format(name)) else: - if version in MDF2_VERSIONS + MDF3_VERSIONS: - self._mdf = MDF_V2_V3( + if version in MDF2_VERSIONS: + self._mdf = MDF3( + version=version, + memory=memory, + ) + elif version in MDF3_VERSIONS: + self._mdf = MDF3( version=version, memory=memory, ) elif version in MDF4_VERSIONS: - self._mdf = MDF_V4( + self._mdf = MDF4( version=version, memory=memory, ) diff --git a/asammdf/mdf_v2.py b/asammdf/mdf_v2.py new file mode 100644 index 000000000..2f24664cb --- /dev/null +++ b/asammdf/mdf_v2.py @@ -0,0 +1,18 @@ +# -*- coding: utf-8 -*- +""" ASAM MDF version 2 file format module """ + +from __future__ import division, print_function + +from .mdf_v3 import MDF3 + + +__all__ = ['MDF2', ] + + +# MDF versions 2 and 3 share the same implementation +class MDF2(MDF3): + pass + + +if __name__ == '__main__': + pass diff --git a/asammdf/mdf_v2_v3.py b/asammdf/mdf_v3.py similarity index 99% rename from asammdf/mdf_v2_v3.py rename to asammdf/mdf_v3.py index ab811f644..12ddf320f 100644 --- a/asammdf/mdf_v2_v3.py +++ b/asammdf/mdf_v3.py @@ -72,10 +72,10 @@ if PYVERSION == 2: from .utils import bytes -__all__ = ['MDF_V2_V3', ] +__all__ = ['MDF3', ] -class MDF_V2_V3(object): +class MDF3(object): """If the *name* exist it will be loaded otherwise an empty file will be created that can be later saved to disk @@ -965,14 +965,14 @@ def append(self, >>> s1 = Signal(samples=s1, timstamps=t, unit='+', name='Positive') >>> s2 = Signal(samples=s2, timstamps=t, unit='-', name='Negative') >>> s3 = Signal(samples=s3, timstamps=t, unit='flts', name='Floats') - >>> mdf = MDF_V2_V3('new.mdf') + >>> mdf = MDF3('new.mdf') >>> mdf.append([s1, s2, s3], 'created by asammdf v1.1.0') >>> # case 2: VTAB conversions from channels inside another file - >>> mdf1 = MDF_V2_V3('in.mdf') + >>> mdf1 = MDF3('in.mdf') >>> ch1 = mdf1.get("Channel1_VTAB") >>> ch2 = mdf1.get("Channel2_VTABR") >>> sigs = [ch1, ch2] - >>> mdf2 = MDF_V2_V3('out.mdf') + >>> mdf2 = MDF3('out.mdf') >>> mdf2.append(sigs, 'created by asammdf v1.1.0') """ @@ -2894,7 +2894,7 @@ def info(self): Examples -------- - >>> mdf = MDF_V2_V3('test.mdf') + >>> mdf = MDF3('test.mdf') >>> mdf.info() """ diff --git a/asammdf/mdf_v4.py b/asammdf/mdf_v4.py index 4f7cd3cfc..1798e2d1f 100644 --- a/asammdf/mdf_v4.py +++ b/asammdf/mdf_v4.py @@ -90,10 +90,10 @@ else: from past.builtins import long -__all__ = ['MDF_V4', ] +__all__ = ['MDF4', ] -class MDF_V4(object): +class MDF4(object): """If the *name* exist it will be memorised otherwise an empty file will be created that can be later saved to disk @@ -3922,7 +3922,7 @@ def info(self): Examples -------- - >>> mdf = MDF_V4('test.mdf') + >>> mdf = MDF4('test.mdf') >>> mdf.info() @@ -4112,9 +4112,9 @@ def _save_with_metadata(self, dst, overwrite, compression): data = self._load_group_data(gp) - if MDF_V4._split_data_blocks: + if MDF4._split_data_blocks: samples_size = gp['channel_group']['samples_byte_nr'] - split_size = MDF_V4._split_threshold // samples_size + split_size = MDF4._split_threshold // samples_size split_size *= samples_size if split_size == 0: chunks = 1 @@ -4598,9 +4598,9 @@ def _save_without_metadata(self, dst, overwrite, compression): data = self._load_group_data(gp) - if MDF_V4._split_data_blocks: + if MDF4._split_data_blocks: samples_size = gp['channel_group']['samples_byte_nr'] - split_size = MDF_V4._split_threshold // samples_size + split_size = MDF4._split_threshold // samples_size split_size *= samples_size if split_size == 0: chunks = 1 diff --git a/asammdf/signal.py b/asammdf/signal.py index d3156a078..63158a405 100644 --- a/asammdf/signal.py +++ b/asammdf/signal.py @@ -533,7 +533,12 @@ def __ne__(self, other): return self.__apply_func(other, '__ne__') def __iter__(self): - return zip(self.samples, self.timestamps) + for item in ( + self.samples, + self.timestamps, + self.unit, + self.name): + yield item def __reversed__(self): return enumerate(zip(reversed(self.samples), reversed(self.timestamps))) diff --git a/documentation/mdf.rst b/documentation/mdf.rst index 880e9719f..3f6bea118 100644 --- a/documentation/mdf.rst +++ b/documentation/mdf.rst @@ -21,9 +21,9 @@ MDF === -This class acts as a proxy for the MDF_V2_V3 and MDF_V4 classes. -All attribute access is delegated to the underlying *_mdf* attribute (MDF_V2_V3 or MDF_V4 object). -See MDF_V2_V3 and MDF_V4 for available extra methods. +This class acts as a proxy for the MDF3 and MDF4 classes. +All attribute access is delegated to the underlying *_mdf* attribute (MDF2, MDF3 or MDF4 object). +See MDF3 and MDF4 for available extra methods (MDF2 and MDF3 share the same implementation). An empty MDF file is created if the *name* argument is not provided. If the *name* argument is provided then the file must exist in the filesystem, otherwise an exception is raised. @@ -40,13 +40,13 @@ Best practice is to use the MDF as a context manager. This way all resources are :members: -MDF_V2_V3 and MDF_V4 classes ----------------------------- +MDF3 and MDF4 classes +--------------------- .. toctree:: :maxdepth: 1 - mdf23 + mdf3 mdf4 Notes about *memory* argument diff --git a/documentation/mdf23.rst b/documentation/mdf3.rst similarity index 97% rename from documentation/mdf23.rst rename to documentation/mdf3.rst index dc80eb792..7f3f834b7 100644 --- a/documentation/mdf23.rst +++ b/documentation/mdf3.rst @@ -16,10 +16,10 @@ .. role:: orange .. role:: brown -.. _MDF_V2_V3: +.. _MDF3: -MDF_V2_V3 -========= +MDF3 +==== asammdf tries to emulate the mdf structure using Python builtin data types. @@ -63,7 +63,7 @@ The *master_db* attibute is a dictionary that holds the *channel index* of the API --- -.. autoclass:: asammdf.mdf_v2_v3.MDF_V2_V3 +.. autoclass:: asammdf.mdf_v3.MDF3 :members: :noindex: diff --git a/documentation/mdf4.rst b/documentation/mdf4.rst index 1ba7e2df6..20c607d94 100644 --- a/documentation/mdf4.rst +++ b/documentation/mdf4.rst @@ -16,10 +16,10 @@ .. role:: orange .. role:: brown -.. _MDF_V4: +.. _MDF4: -MDF_V4 -====== +MDF4 +==== asammdf tries to emulate the mdf structure using Python builtin data types. @@ -72,7 +72,7 @@ The *master_db* attibute is a dictionary that holds the *channel index* of the API --- -.. autoclass:: asammdf.mdf_v4.MDF_V4 +.. autoclass:: asammdf.mdf_v4.MDF4 :members: :noindex: diff --git a/test/test_mdf23.py b/test/test_mdf23.py index cf9bfb63f..f9bc969c3 100644 --- a/test/test_mdf23.py +++ b/test/test_mdf23.py @@ -5,7 +5,7 @@ import numpy as np from utils import MEMORY -from asammdf import MDF, MDF_V2_V3, Signal, configure +from asammdf import MDF, MDF2, MDF3, Signal, configure CHANNEL_LEN = 10000 @@ -18,7 +18,8 @@ class TestMDF23(unittest.TestCase): def test_measurement(self): - self.assertTrue(MDF_V2_V3) + self.assertTrue(MDF2) + self.assertTrue(MDF3) def test_read_mdf2_00(self): diff --git a/test/test_mdf4.py b/test/test_mdf4.py index d6b9420cb..40c0b75e7 100644 --- a/test/test_mdf4.py +++ b/test/test_mdf4.py @@ -5,7 +5,7 @@ import numpy as np from utils import MEMORY -from asammdf import MDF, MDF_V4, Signal +from asammdf import MDF, MDF4, Signal CHANNEL_LEN = 100000 @@ -13,7 +13,7 @@ class TestMDF4(unittest.TestCase): def test_measurement(self): - self.assertTrue(MDF_V4) + self.assertTrue(MDF4) def test_read_mdf4_00(self): @@ -51,7 +51,7 @@ def test_read_mdf4_00(self): self.assertTrue(np.array_equal(ret_sig_float.samples, sig_float.samples)) - def test_read_mdf4_10(self): + def test_read_mdf4_10(self): seed = np.random.randint(0, 2**31) From 180702c2288b105fa10462d855cd529d4a6bddb9 Mon Sep 17 00:00:00 2001 From: danielhrisca Date: Wed, 10 Jan 2018 20:47:35 +0200 Subject: [PATCH 097/117] fix error in mat export --- asammdf/mdf.py | 1 + benchmarks/bench.py | 60 ++++++++++++++++++++++----------------------- 2 files changed, 31 insertions(+), 30 deletions(-) diff --git a/asammdf/mdf.py b/asammdf/mdf.py index 6b5f82856..3581efff5 100644 --- a/asammdf/mdf.py +++ b/asammdf/mdf.py @@ -485,6 +485,7 @@ def export(self, fmt, filename=None): channel = 'DataGroup_{}_{}' for i, grp in enumerate(self.groups): + master_index = self.masters_db.get(i, -1) data = self._load_group_data(grp) for j, _ in enumerate(grp['channels']): sig = self.get( diff --git a/benchmarks/bench.py b/benchmarks/bench.py index 2d429c1d2..f46da4151 100644 --- a/benchmarks/bench.py +++ b/benchmarks/bench.py @@ -560,18 +560,18 @@ def main(path, text_output, fmt): output.append('* 36424 channels\n\n') tests = ( -# partial(open_mdf3, memory='full'), -# partial(open_mdf3, memory='low'), -# partial(open_mdf3, memory='minimum'), -# open_reader3, + partial(open_mdf3, memory='full'), + partial(open_mdf3, memory='low'), + partial(open_mdf3, memory='minimum'), + open_reader3, # open_reader3_compression, -# open_reader3_nodata, -# partial(open_mdf4, memory='full'), -# partial(open_mdf4, memory='low'), -# partial(open_mdf4, memory='minimum'), -# open_reader4, + open_reader3_nodata, + partial(open_mdf4, memory='full'), + partial(open_mdf4, memory='low'), + partial(open_mdf4, memory='minimum'), + open_reader4, # open_reader4_compression, -# open_reader4_nodata, + open_reader4_nodata, ) if tests: @@ -586,15 +586,15 @@ def main(path, text_output, fmt): output.extend(table_end(fmt)) tests = ( -# partial(save_mdf3, memory='full'), -# partial(save_mdf3, memory='low'), -# partial(save_mdf3, memory='minimum'), + partial(save_mdf3, memory='full'), + partial(save_mdf3, memory='low'), + partial(save_mdf3, memory='minimum'), # save_reader3, # save_reader3_nodata, # save_reader3_compression, -# partial(save_mdf4, memory='full'), -# partial(save_mdf4, memory='low'), -# partial(save_mdf4, memory='minimum'), + partial(save_mdf4, memory='full'), + partial(save_mdf4, memory='low'), + partial(save_mdf4, memory='minimum'), # save_reader4, # save_reader4_nodata, # save_reader4_compression, @@ -612,15 +612,15 @@ def main(path, text_output, fmt): output.extend(table_end(fmt)) tests = ( -# partial(get_all_mdf3, memory='full'), -# partial(get_all_mdf3, memory='low'), -# partial(get_all_mdf3, memory='minimum'), + partial(get_all_mdf3, memory='full'), + partial(get_all_mdf3, memory='low'), + partial(get_all_mdf3, memory='minimum'), # get_all_reader3, # get_all_reader3_nodata, # get_all_reader3_compression, -# partial(get_all_mdf4, memory='full'), -# partial(get_all_mdf4, memory='low'), -# partial(get_all_mdf4, memory='minimum'), + partial(get_all_mdf4, memory='full'), + partial(get_all_mdf4, memory='low'), + partial(get_all_mdf4, memory='minimum'), # get_all_reader4, # get_all_reader4_nodata, # get_all_reader4_compression, @@ -638,12 +638,12 @@ def main(path, text_output, fmt): output.extend(table_end(fmt)) tests = ( -# partial(convert_v3_v4, memory='full'), -# partial(convert_v3_v4, memory='low'), -# partial(convert_v3_v4, memory='minimum'), -# partial(convert_v4_v3, memory='full'), -# partial(convert_v4_v3, memory='low'), -# partial(convert_v4_v3, memory='minimum'), + partial(convert_v3_v4, memory='full'), + partial(convert_v3_v4, memory='low'), + partial(convert_v3_v4, memory='minimum'), + partial(convert_v4_v3, memory='full'), + partial(convert_v4_v3, memory='low'), + partial(convert_v4_v3, memory='minimum'), ) if tests: @@ -661,13 +661,13 @@ def main(path, text_output, fmt): partial(merge_v3, memory='full'), partial(merge_v3, memory='low'), partial(merge_v3, memory='minimum'), - merge_reader_v3, +# merge_reader_v3, # merge_reader_v3_compress, # merge_reader_v3_nodata, partial(merge_v4, memory='full'), partial(merge_v4, memory='low'), partial(merge_v4, memory='minimum'), - merge_reader_v4, +# merge_reader_v4, # merge_reader_v4_nodata, # merge_reader_v4_compress, ) From bd555ea04119877904d30eebe0a13f5f6b35292c Mon Sep 17 00:00:00 2001 From: danielhrisca Date: Thu, 11 Jan 2018 10:42:49 +0200 Subject: [PATCH 098/117] fix error when appending signals with big endian byte order --- asammdf/mdf_v3.py | 7 ++++ asammdf/mdf_v4.py | 80 +++++++++++++++++++++++++++++++++++++++----- asammdf/utils.py | 38 ++++++++++++++++----- asammdf/v4_blocks.py | 2 +- 4 files changed, 110 insertions(+), 17 deletions(-) diff --git a/asammdf/mdf_v3.py b/asammdf/mdf_v3.py index 12ddf320f..c0894164a 100644 --- a/asammdf/mdf_v3.py +++ b/asammdf/mdf_v3.py @@ -1001,6 +1001,13 @@ def append(self, else: t = t_ + if self.version < '3.00': + if t.dtype.byteorder == '>': + t = t.byteswap().newbyteorder() + for signal in signals: + if signal.samples.dtype.byteorder == '>': + signal.samples = signal.samples.byteswap().newbyteorder() + if self.version >= '3.00': channel_size = v23c.CN_DISPLAYNAME_BLOCK_SIZE elif self.version >= '2.10': diff --git a/asammdf/mdf_v4.py b/asammdf/mdf_v4.py index 1798e2d1f..d016dacd0 100644 --- a/asammdf/mdf_v4.py +++ b/asammdf/mdf_v4.py @@ -1391,6 +1391,13 @@ def append(self, signals, source_info='Python', common_timebase=False): gp_conv.append(None) gp_source.append(SourceInformation()) + if memory == 'minimum': + name_addr = gp_texts['channels'][-1]['name_addr'] + unit_addr = gp_texts['channels'][-1]['unit_addr'] + else: + name_addr = 0 + unit_addr = 0 + # time channel t_type, t_size = fmt_to_datatype(t.dtype) kargs = { @@ -1405,7 +1412,8 @@ def append(self, signals, source_info='Python', common_timebase=False): 'lower_limit': t[0] if cycles_nr else 0, 'upper_limit': t[-1] if cycles_nr else 0, 'flags': v4c.FLAG_PHY_RANGE_OK | v4c.FLAG_VAL_RANGE_OK, - 'name_addr': gp_texts['channels'][-1]['name_addr'], + 'name_addr': name_addr, + 'unit_addr': unit_addr, } ch = Channel(**kargs) ch.name = name = 't' @@ -1654,6 +1662,13 @@ def append(self, signals, source_info='Python', common_timebase=False): write(bytes(block)) gp_source.append(address) + if memory == 'minimum': + name_addr = gp_texts['channels'][-1]['name_addr'] + unit_addr = gp_texts['channels'][-1].get('unit_addr', 0) + else: + name_addr = 0 + unit_addr = 0 + # compute additional byte offset for large records size if signal.samples.dtype.kind == 'u': data_type = v4c.DATA_TYPE_UNSIGNED_INTEL @@ -1669,7 +1684,8 @@ def append(self, signals, source_info='Python', common_timebase=False): 'max_raw_value': max_val if min_val <= max_val else 0, 'lower_limit': min_val if min_val <= max_val else 0, 'upper_limit': max_val if min_val <= max_val else 0, - 'name_addr': gp_texts['channels'][-1]['name_addr'], + 'name_addr': name_addr, + 'unit_addr': unit_addr, } if min_val > max_val: kargs['flags'] = 0 @@ -1860,6 +1876,13 @@ def append(self, signals, source_info='Python', common_timebase=False): write(bytes(block)) gp_source.append(address) + if memory == 'minimum': + name_addr = gp_texts['channels'][-1]['name_addr'] + unit_addr = gp_texts['channels'][-1].get('unit_addr', 0) + else: + name_addr = 0 + unit_addr = 0 + # compute additional byte offset for large records size s_type, s_size = fmt_to_datatype(signal.samples.dtype) byte_size = max(s_size // 8, 1) @@ -1874,7 +1897,8 @@ def append(self, signals, source_info='Python', common_timebase=False): 'max_raw_value': max_val if min_val <= max_val else 0, 'lower_limit': min_val if min_val <= max_val else 0, 'upper_limit': max_val if min_val <= max_val else 0, - 'name_addr': gp_texts['channels'][-1]['name_addr'], + 'name_addr': name_addr, + 'unit_addr': unit_addr, } if min_val > max_val: kargs['flags'] = 0 @@ -2004,6 +2028,13 @@ def append(self, signals, source_info='Python', common_timebase=False): # there is no chanel dependency gp_dep.append(None) + if memory == 'minimum': + name_addr = gp_texts['channels'][-1]['name_addr'] + unit_addr = gp_texts['channels'][-1].get('unit_addr', 0) + else: + name_addr = 0 + unit_addr = 0 + # add channel block kargs = { 'channel_type': v4c.CHANNEL_TYPE_VALUE, @@ -2016,7 +2047,8 @@ def append(self, signals, source_info='Python', common_timebase=False): 'lower_limit': 0, 'upper_limit': 0, 'flags': 0, - 'name_addr': gp_texts['channels'][-1]['name_addr'], + 'name_addr': name_addr, + 'unit_addr': unit_addr, } ch = Channel(**kargs) ch.name = name @@ -2093,6 +2125,13 @@ def append(self, signals, source_info='Python', common_timebase=False): write(bytes(block)) gp_source.append(address) + if memory == 'minimum': + name_addr = gp_texts['channels'][-1]['name_addr'] + unit_addr = gp_texts['channels'][-1].get('unit_addr', 0) + else: + name_addr = 0 + unit_addr = 0 + # add channel block kargs = { 'channel_type': v4c.CHANNEL_TYPE_VALUE, @@ -2105,7 +2144,8 @@ def append(self, signals, source_info='Python', common_timebase=False): 'lower_limit': 0, 'upper_limit': 0, 'flags': 0, - 'name_addr': gp_texts['channels'][-1]['name_addr'], + 'name_addr': name_addr, + 'unit_addr': unit_addr, } ch = Channel(**kargs) ch.name = name @@ -2175,6 +2215,13 @@ def append(self, signals, source_info='Python', common_timebase=False): else: gp_source.append(0) + if memory == 'minimum': + name_addr = gp_texts['channels'][-1]['name_addr'] + unit_addr = gp_texts['channels'][-1].get('unit_addr', 0) + else: + name_addr = 0 + unit_addr = 0 + # add channel block min_val, max_val = get_min_max(signal.samples) kargs = { @@ -2188,7 +2235,8 @@ def append(self, signals, source_info='Python', common_timebase=False): 'lower_limit': min_val if min_val <= max_val else 0, 'upper_limit': max_val if min_val <= max_val else 0, 'flags': v4c.FLAG_PHY_RANGE_OK | v4c.FLAG_VAL_RANGE_OK, - 'name_addr': gp_texts['channels'][-1]['name_addr'], + 'name_addr': name_addr, + 'unit_addr': unit_addr, } ch = Channel(**kargs) @@ -2329,6 +2377,13 @@ def append(self, signals, source_info='Python', common_timebase=False): s_type, s_size = fmt_to_datatype(samples.dtype) + if memory == 'minimum': + name_addr = gp_texts['channels'][-1]['name_addr'] + unit_addr = gp_texts['channels'][-1].get('unit_addr', 0) + else: + name_addr = 0 + unit_addr = 0 + # add channel block kargs = { 'channel_type': v4c.CHANNEL_TYPE_VALUE, @@ -2341,7 +2396,8 @@ def append(self, signals, source_info='Python', common_timebase=False): 'lower_limit': 0, 'upper_limit': 0, 'flags': 0, - 'name_addr': gp_texts['channels'][-1]['name_addr'], + 'name_addr': name_addr, + 'unit_addr': unit_addr, } ch = Channel(**kargs) ch.name = name @@ -2422,6 +2478,13 @@ def append(self, signals, source_info='Python', common_timebase=False): dep = ChannelArrayBlock(**kargs) gp_dep.append([dep, ]) + if memory == 'minimum': + name_addr = gp_texts['channels'][-1]['name_addr'] + unit_addr = gp_texts['channels'][-1].get('unit_addr', 0) + else: + name_addr = 0 + unit_addr = 0 + # add components channel min_val, max_val = get_min_max(samples) s_type, s_size = fmt_to_datatype(samples.dtype) @@ -2437,7 +2500,8 @@ def append(self, signals, source_info='Python', common_timebase=False): 'lower_limit': min_val if min_val <= max_val else 0, 'upper_limit': max_val if min_val <= max_val else 0, 'flags': v4c.FLAG_PHY_RANGE_OK | v4c.FLAG_VAL_RANGE_OK, - 'name_addr': gp_texts['channels'][-1]['name_addr'], + 'name_addr': name_addr, + 'unit_addr': unit_addr, } channel = Channel(**kargs) diff --git a/asammdf/utils.py b/asammdf/utils.py index a1b79e4dd..3b882cead 100644 --- a/asammdf/utils.py +++ b/asammdf/utils.py @@ -149,14 +149,26 @@ def fmt_to_datatype(fmt, version=3): if version < 4: if fmt.kind == 'u': - data_type = v3c.DATA_TYPE_UNSIGNED + if fmt.byteorder in ('=<'): + data_type = v3c.DATA_TYPE_UNSIGNED + else: + data_type = v3c.DATA_TYPE_UNSIGNED_MOTOROLA elif fmt.kind == 'i': - data_type = v3c.DATA_TYPE_SIGNED + if fmt.byteorder in ('=<'): + data_type = v3c.DATA_TYPE_SIGNED + else: + data_type = v3c.DATA_TYPE_SIGNED_MOTOROLA elif fmt.kind == 'f': - if size == 32: - data_type = v3c.DATA_TYPE_FLOAT + if fmt.byteorder in ('=<'): + if size == 32: + data_type = v3c.DATA_TYPE_FLOAT + else: + data_type = v3c.DATA_TYPE_DOUBLE else: - data_type = v3c.DATA_TYPE_DOUBLE + if size == 32: + data_type = v3c.DATA_TYPE_FLOAT_MOTOROLA + else: + data_type = v3c.DATA_TYPE_DOUBLE_MOTOROLA elif fmt.kind in 'SV': data_type = v3c.DATA_TYPE_STRING else: @@ -164,12 +176,22 @@ def fmt_to_datatype(fmt, version=3): data_type = v3c.DATA_TYPE_BYTEARRAY elif version == 4: + if fmt.kind == 'u': - data_type = v4c.DATA_TYPE_UNSIGNED_INTEL + if fmt.byteorder in ('=<'): + data_type = v4c.DATA_TYPE_UNSIGNED_INTEL + else: + data_type = v4c.DATA_TYPE_UNSIGNED_MOTOROLA elif fmt.kind == 'i': - data_type = v4c.DATA_TYPE_SIGNED_INTEL + if fmt.byteorder in ('=<'): + data_type = v4c.DATA_TYPE_SIGNED_INTEL + else: + data_type = v4c.DATA_TYPE_SIGNED_MOTOROLA elif fmt.kind == 'f': - data_type = v4c.DATA_TYPE_REAL_INTEL + if fmt.byteorder in ('=<'): + data_type = v4c.DATA_TYPE_REAL_INTEL + else: + data_type = v4c.DATA_TYPE_REAL_MOTOROLA elif fmt.kind in 'SV': data_type = v4c.DATA_TYPE_STRING_LATIN_1 else: diff --git a/asammdf/v4_blocks.py b/asammdf/v4_blocks.py index 568bea1b1..8ee0a33fd 100644 --- a/asammdf/v4_blocks.py +++ b/asammdf/v4_blocks.py @@ -245,7 +245,7 @@ def __init__(self, **kargs): self['source_addr'] = 0 self['conversion_addr'] = 0 self['data_block_addr'] = 0 - self['unit_addr'] = 0 + self['unit_addr'] = kargs.get('unit_addr', 0) self['comment_addr'] = 0 self['channel_type'] = kargs['channel_type'] self['sync_type'] = kargs.get('sync_type', 0) From 78d0e5bc46c721edf15e5d1719a01a0e03b41285 Mon Sep 17 00:00:00 2001 From: danielhrisca Date: Fri, 12 Jan 2018 22:37:37 +0200 Subject: [PATCH 099/117] fix errors in export method --- asammdf/mdf.py | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/asammdf/mdf.py b/asammdf/mdf.py index 3581efff5..e88d64429 100644 --- a/asammdf/mdf.py +++ b/asammdf/mdf.py @@ -109,11 +109,8 @@ def _excluded_channels(self, index): group = self.groups[index] excluded_channels = set() - try: - master_index = self.masters_db[index] - excluded_channels.add(master_index) - except KeyError: - pass + master_index = self.masters_db.get(index, -1) + excluded_channels.add(master_index) channels = group['channels'] @@ -407,7 +404,7 @@ def export(self, fmt, filename=None): ws.write(1, 0, 'comment', bold) ws.write(2, 0, 'is master', bold) - master_index = self.masters_db[i] + master_index = self.masters_db.get(i, -1) for j in range(grp['channel_group']['cycles_nr']): ws.write(j + 3, 0, str(j)) @@ -416,8 +413,10 @@ def export(self, fmt, filename=None): sig = self.get(group=i, index=j, data=data) col = j + 1 - sig_description = '{} [{}]'.format(sig.name, - sig.unit) + sig_description = '{} [{}]'.format( + sig.name, + sig.unit, + ) comment = sig.comment if sig.comment else '' ws.write(0, col, sig_description) ws.write(1, col, comment) @@ -445,7 +444,7 @@ def export(self, fmt, filename=None): for j in range(ch_nr) ] - master_index = self.masters_db[i] + master_index = self.masters_db.get(i, -1) cycles = grp['channel_group']['cycles_nr'] names_row = ['Channel', ] @@ -622,9 +621,8 @@ def filter(self, channels, memory=None): gps[group_index] = gps[group_index] - excluded_channels - if memory is not None: - if memory not in ('full', 'low', 'minimum'): - memory = self.memory + if memory is None or memory not in ('full', 'low', 'minimum'): + memory = self.memory mdf = MDF( version=self.version, @@ -853,7 +851,7 @@ def resample(self, raster, memory=None): """ - if memory is None: + if memory is None or memory not in ('full', 'low', 'minimum'): memory = self.memory mdf = MDF( From b2a607ec4d780836dc3d8e219914c97eb17d3e02 Mon Sep 17 00:00:00 2001 From: danielhrisca Date: Fri, 12 Jan 2018 23:06:06 +0200 Subject: [PATCH 100/117] avoid "future" package dependency --- asammdf/mdf.py | 9 +++------ asammdf/mdf_v4.py | 22 +++++++++------------- 2 files changed, 12 insertions(+), 19 deletions(-) diff --git a/asammdf/mdf.py b/asammdf/mdf.py index e88d64429..ec4fc8204 100644 --- a/asammdf/mdf.py +++ b/asammdf/mdf.py @@ -18,10 +18,9 @@ from .v2_v3_blocks import TextBlock as TextBlockV3 from .v2_v3_blocks import Channel as ChannelV3 from .v4_blocks import TextBlock as TextBlockV4 +from .v4_blocks import ChannelArrayBlock PYVERSION = sys.version_info[0] -if PYVERSION > 2: - from past.builtins import long MDF2_VERSIONS = ('2.00', '2.10', '2.14') MDF3_VERSIONS = ('3.00', '3.10', '3.20', '3.30') @@ -125,8 +124,7 @@ def _excluded_channels(self, index): for dependencies in group['channel_dependencies']: if dependencies is None: continue - if all(dep['id'] == b'##CN' - if not isinstance(dep, (int, long)) else True + if all(not isinstance(dep, ChannelArrayBlock) for dep in dependencies): for ch in dependencies: excluded_channels.add(channels.index(ch)) @@ -607,8 +605,7 @@ def filter(self, channels, memory=None): dependencies = grp['channel_dependencies'][index] if dependencies is None: continue - if all(dep['id'] == b'##CN' - if not isinstance(dep, (int, long)) else True + if all(not isinstance(dep, ChannelArrayBlock) for dep in dependencies): channels = grp['channels'] for ch in dependencies: diff --git a/asammdf/mdf_v4.py b/asammdf/mdf_v4.py index d016dacd0..1d5eaa43a 100644 --- a/asammdf/mdf_v4.py +++ b/asammdf/mdf_v4.py @@ -87,8 +87,6 @@ PYVERSION = sys.version_info[0] if PYVERSION == 2: from .utils import bytes -else: - from past.builtins import long __all__ = ['MDF4', ] @@ -409,9 +407,7 @@ def _read(self): continue for dep in dep_list: - if isinstance(dep, (Channel, int, long)): - break - else: + if isinstance(dep, ChannelArrayBlock): conditions = ( dep['ca_type'] == v4c.CA_TYPE_LOOKUP, dep['links_nr'] == 4 * dep['dims'] + 1, @@ -423,6 +419,8 @@ def _read(self): ch_addr = dep['scale_axis_{}_ch_addr'.format(i)] ref_channel = self._ch_map[ch_addr] dep.referenced_channels.append(ref_channel) + else: + break if self.memory == 'full': self.close() @@ -3066,8 +3064,7 @@ def get(self, arrays = [] name = channel.name - if all( - isinstance(dep, (Channel, int, long)) + if all(not isinstance(dep, ChannelArrayBlock) for dep in dependency_list): # structure channel composition if memory == 'minimum': @@ -4963,10 +4960,10 @@ def _save_without_metadata(self, dst, overwrite, compression): if gp['channel_dependencies'][j]: block = gp['channel_dependencies'][j][0] - if isinstance(block, (int, long)): - channel['component_addr'] = block - else: + if isinstance(block, (ChannelArrayBlock, Channel)): channel['component_addr'] = block.address + else: + channel['component_addr'] = block group_channels = gp['channels'] if group_channels: @@ -4979,7 +4976,7 @@ def _save_without_metadata(self, dst, overwrite, compression): while j < len(gp['channels']): dep_list = gp['channel_dependencies'][j] if dep_list and all( - isinstance(dep, (int, long)) for dep in dep_list): + not isinstance(dep, ChannelArrayBlock) for dep in dep_list): dep = chans[j+1] @@ -5076,8 +5073,7 @@ def _save_without_metadata(self, dst, overwrite, compression): for gp in self.groups: for dep_list in gp['channel_dependencies']: if dep_list: - if all( - isinstance(dep, ChannelArrayBlock) + if all(isinstance(dep, ChannelArrayBlock) for dep in dep_list): for dep in dep_list: for i, (ch_nr, gp_nr) in enumerate(dep.referenced_channels): From ca6108c7fd5014c93f96afaed0fa280f34ae5ea0 Mon Sep 17 00:00:00 2001 From: danielhrisca Date: Mon, 15 Jan 2018 14:21:06 +0200 Subject: [PATCH 101/117] warn in case of unsupported export option --- asammdf/mdf.py | 6 ++ benchmarks/bench.py | 195 ++++++++++++++++++++++---------------------- 2 files changed, 102 insertions(+), 99 deletions(-) diff --git a/asammdf/mdf.py b/asammdf/mdf.py index 3581efff5..95d978d46 100644 --- a/asammdf/mdf.py +++ b/asammdf/mdf.py @@ -505,6 +505,12 @@ def export(self, fmt, filename=None): long_field_names=True, do_compression=True, ) + else: + message = ( + 'Unsopported export type "{}". ' + 'Please select "csv", "excel", "hdf5" or "mat"' + ) + warn(message.format(fmt)) def filter(self, channels, memory=None): """ return new *MDF* object that contains only the channels listed in diff --git a/benchmarks/bench.py b/benchmarks/bench.py index f46da4151..73dc951ed 100644 --- a/benchmarks/bench.py +++ b/benchmarks/bench.py @@ -118,8 +118,8 @@ def __exit__(self, type_, value, tracebackobj): return True -def open_mdf3(path, output, fmt, memory): - os.chdir(path) +def open_mdf3(output, fmt, memory): + with Timer('Open file', 'asammdf {} {} mdfv3'.format(asammdf_version, memory), fmt) as timer: @@ -127,8 +127,8 @@ def open_mdf3(path, output, fmt, memory): output.send([timer.output, timer.error]) -def open_mdf4(path, output, fmt, memory): - os.chdir(path) +def open_mdf4(output, fmt, memory): + with Timer('Open file', 'asammdf {} {} mdfv4'.format(asammdf_version, memory), fmt) as timer: @@ -136,8 +136,8 @@ def open_mdf4(path, output, fmt, memory): output.send([timer.output, timer.error]) -def save_mdf3(path, output, fmt, memory): - os.chdir(path) +def save_mdf3(output, fmt, memory): + x = MDF(r'test.mdf', memory=memory) with Timer('Save file', 'asammdf {} {} mdfv3'.format(asammdf_version, memory), @@ -146,8 +146,8 @@ def save_mdf3(path, output, fmt, memory): output.send([timer.output, timer.error]) -def save_mdf4(path, output, fmt, memory): - os.chdir(path) +def save_mdf4(output, fmt, memory): + x = MDF(r'test.mf4', memory=memory) with Timer('Save file', 'asammdf {} {} mdfv4'.format(asammdf_version, memory), @@ -156,8 +156,8 @@ def save_mdf4(path, output, fmt, memory): output.send([timer.output, timer.error]) -def get_all_mdf3(path, output, fmt, memory): - os.chdir(path) +def get_all_mdf3(output, fmt, memory): + x = MDF(r'test.mdf', memory=memory,) with Timer('Get all channels', 'asammdf {} {} mdfv3'.format(asammdf_version, memory), @@ -168,8 +168,8 @@ def get_all_mdf3(path, output, fmt, memory): output.send([timer.output, timer.error]) -def get_all_mdf4(path, output, fmt, memory): - os.chdir(path) +def get_all_mdf4(output, fmt, memory): + x = MDF(r'test.mf4', memory=memory,) with Timer('Get all channels', 'asammdf {} {} mdfv4'.format(asammdf_version, memory), @@ -180,8 +180,8 @@ def get_all_mdf4(path, output, fmt, memory): output.send([timer.output, timer.error]) -def convert_v3_v4(path, output, fmt, memory): - os.chdir(path) +def convert_v3_v4(output, fmt, memory): + with MDF(r'test.mdf', memory=memory,) as x: with Timer('Convert file', 'asammdf {} {} v3 to v4'.format( @@ -193,8 +193,8 @@ def convert_v3_v4(path, output, fmt, memory): output.send([timer.output, timer.error]) -def convert_v4_v3(path, output, fmt, memory): - os.chdir(path) +def convert_v4_v3(output, fmt, memory): + with MDF(r'test.mf4', memory=memory,) as x: with Timer('Convert file', 'asammdf {} {} v4 to v3'.format( @@ -207,8 +207,8 @@ def convert_v4_v3(path, output, fmt, memory): output.send([timer.output, timer.error]) -def merge_v3(path, output, fmt, memory): - os.chdir(path) +def merge_v3(output, fmt, memory): + files = [r'test.mdf', ] * 2 with Timer('Merge files', 'asammdf {} {} v3'.format(asammdf_version, memory), @@ -217,9 +217,9 @@ def merge_v3(path, output, fmt, memory): output.send([timer.output, timer.error]) -def merge_v4(path, output, fmt, memory): +def merge_v4(output, fmt, memory): files = [r'test.mf4', ] * 2 - os.chdir(path) + with Timer('Merge files', 'asammdf {} {} v4'.format(asammdf_version, memory), fmt) as timer: @@ -232,8 +232,8 @@ def merge_v4(path, output, fmt, memory): # -def open_reader3(path, output, fmt): - os.chdir(path) +def open_reader3(output, fmt): + with Timer('Open file', 'mdfreader {} mdfv3'.format(mdfreader_version), fmt) as timer: @@ -241,8 +241,8 @@ def open_reader3(path, output, fmt): output.send([timer.output, timer.error]) -def open_reader3_nodata(path, output, fmt): - os.chdir(path) +def open_reader3_nodata(output, fmt): + with Timer('Open file', 'mdfreader {} noDataLoading mdfv3'.format(mdfreader_version), fmt) as timer: @@ -250,8 +250,8 @@ def open_reader3_nodata(path, output, fmt): output.send([timer.output, timer.error]) -def open_reader3_compression(path, output, fmt): - os.chdir(path) +def open_reader3_compression(output, fmt): + with Timer('Open file', 'mdfreader {} compress mdfv3'.format(mdfreader_version), fmt) as timer: @@ -259,8 +259,8 @@ def open_reader3_compression(path, output, fmt): output.send([timer.output, timer.error]) -def open_reader4(path, output, fmt): - os.chdir(path) +def open_reader4(output, fmt): + with Timer('Open file', 'mdfreader {} mdfv4'.format(mdfreader_version), fmt) as timer: @@ -268,8 +268,8 @@ def open_reader4(path, output, fmt): output.send([timer.output, timer.error]) -def open_reader4_nodata(path, output, fmt): - os.chdir(path) +def open_reader4_nodata(output, fmt): + with Timer('Open file', 'mdfreader {} noDataLoading mdfv4'.format(mdfreader_version), fmt) as timer: @@ -277,8 +277,8 @@ def open_reader4_nodata(path, output, fmt): output.send([timer.output, timer.error]) -def open_reader4_compression(path, output, fmt): - os.chdir(path) +def open_reader4_compression(output, fmt): + with Timer('Open file', 'mdfreader {} compress mdfv4'.format(mdfreader_version), fmt) as timer: @@ -286,8 +286,8 @@ def open_reader4_compression(path, output, fmt): output.send([timer.output, timer.error]) -def save_reader3(path, output, fmt): - os.chdir(path) +def save_reader3(output, fmt): + x = MDFreader(r'test.mdf') with Timer('Save file', 'mdfreader {} mdfv3'.format(mdfreader_version), @@ -296,8 +296,8 @@ def save_reader3(path, output, fmt): output.send([timer.output, timer.error]) -def save_reader3_nodata(path, output, fmt): - os.chdir(path) +def save_reader3_nodata(output, fmt): + x = MDFreader(r'test.mdf', noDataLoading=True) with Timer('Save file', 'mdfreader {} noDataLoading mdfv3'.format(mdfreader_version), @@ -306,8 +306,8 @@ def save_reader3_nodata(path, output, fmt): output.send([timer.output, timer.error]) -def save_reader3_compression(path, output, fmt): - os.chdir(path) +def save_reader3_compression(output, fmt): + x = MDFreader(r'test.mdf', compression='blosc') with Timer('Save file', 'mdfreader {} compress mdfv3'.format(mdfreader_version), @@ -316,8 +316,8 @@ def save_reader3_compression(path, output, fmt): output.send([timer.output, timer.error]) -def save_reader4(path, output, fmt): - os.chdir(path) +def save_reader4(output, fmt): + x = MDFreader(r'test.mf4') with Timer('Save file', 'mdfreader {} mdfv4'.format(mdfreader_version), @@ -326,8 +326,8 @@ def save_reader4(path, output, fmt): output.send([timer.output, timer.error]) -def save_reader4_nodata(path, output, fmt): - os.chdir(path) +def save_reader4_nodata(output, fmt): + x = MDFreader(r'test.mf4', noDataLoading=True) with Timer('Save file', 'mdfreader {} noDataLoading mdfv4'.format(mdfreader_version), @@ -336,8 +336,8 @@ def save_reader4_nodata(path, output, fmt): output.send([timer.output, timer.error]) -def save_reader4_compression(path, output, fmt): - os.chdir(path) +def save_reader4_compression(output, fmt): + x = MDFreader(r'test.mf4', compression='blosc') with Timer('Save file', 'mdfreader {} compress mdfv4'.format(mdfreader_version), @@ -346,8 +346,8 @@ def save_reader4_compression(path, output, fmt): output.send([timer.output, timer.error]) -def get_all_reader3(path, output, fmt): - os.chdir(path) +def get_all_reader3(output, fmt): + x = MDFreader(r'test.mdf') with Timer('Get all channels', 'mdfreader {} mdfv3'.format(mdfreader_version), @@ -357,8 +357,8 @@ def get_all_reader3(path, output, fmt): output.send([timer.output, timer.error]) -def get_all_reader3_nodata(path, output, fmt): - os.chdir(path) +def get_all_reader3_nodata(output, fmt): + x = MDFreader(r'test.mdf', noDataLoading=True) with Timer('Get all channels', 'mdfreader {} nodata mdfv3'.format(mdfreader_version), @@ -368,8 +368,8 @@ def get_all_reader3_nodata(path, output, fmt): output.send([timer.output, timer.error]) -def get_all_reader3_compression(path, output, fmt): - os.chdir(path) +def get_all_reader3_compression(output, fmt): + x = MDFreader(r'test.mdf', compression='blosc') with Timer('Get all channels', 'mdfreader {} compress mdfv3'.format(mdfreader_version), @@ -382,8 +382,8 @@ def get_all_reader3_compression(path, output, fmt): output.send([timer.output, timer.error]) -def get_all_reader4(path, output, fmt): - os.chdir(path) +def get_all_reader4(output, fmt): + x = MDFreader(r'test.mf4') with Timer('Get all channels', 'mdfreader {} mdfv4'.format(mdfreader_version), @@ -393,8 +393,8 @@ def get_all_reader4(path, output, fmt): output.send([timer.output, timer.error]) -def get_all_reader4_nodata(path, output, fmt): - os.chdir(path) +def get_all_reader4_nodata(output, fmt): + x = MDFreader(r'test.mf4', noDataLoading=True) with Timer('Get all channels', 'mdfreader {} nodata mdfv4'.format(mdfreader_version), @@ -404,8 +404,8 @@ def get_all_reader4_nodata(path, output, fmt): output.send([timer.output, timer.error]) -def get_all_reader4_compression(path, output, fmt): - os.chdir(path) +def get_all_reader4_compression(output, fmt): + x = MDFreader(r'test.mf4', compression='blosc') with Timer('Get all channels', 'mdfreader {} compress mdfv4'.format(mdfreader_version), @@ -415,8 +415,8 @@ def get_all_reader4_compression(path, output, fmt): output.send([timer.output, timer.error]) -def merge_reader_v3(path, output, fmt): - os.chdir(path) +def merge_reader_v3(output, fmt): + files = [r'test.mdf', ] * 2 with Timer('Merge files', 'mdfreader {} v3'.format(mdfreader_version), @@ -429,8 +429,8 @@ def merge_reader_v3(path, output, fmt): output.send([timer.output, timer.error]) -def merge_reader_v3_compress(path, output, fmt): - os.chdir(path) +def merge_reader_v3_compress(output, fmt): + files = [r'test.mdf', ] * 2 with Timer('Merge files', 'mdfreader {} compress v3'.format(mdfreader_version), @@ -443,8 +443,8 @@ def merge_reader_v3_compress(path, output, fmt): output.send([timer.output, timer.error]) -def merge_reader_v3_nodata(path, output, fmt): - os.chdir(path) +def merge_reader_v3_nodata(output, fmt): + files = [r'test.mdf', ] * 2 with Timer('Merge files', 'mdfreader {} nodata v3'.format(mdfreader_version), @@ -457,9 +457,9 @@ def merge_reader_v3_nodata(path, output, fmt): output.send([timer.output, timer.error]) -def merge_reader_v4(path, output, fmt): +def merge_reader_v4(output, fmt): files = [r'test.mf4', ] * 2 - os.chdir(path) + with Timer('Merge files', 'mdfreader {} v4'.format(mdfreader_version), fmt) as timer: @@ -471,8 +471,8 @@ def merge_reader_v4(path, output, fmt): output.send([timer.output, timer.error]) -def merge_reader_v4_compress(path, output, fmt): - os.chdir(path) +def merge_reader_v4_compress(output, fmt): + files = [r'test.mf4', ] * 2 with Timer('Merge files', 'mdfreader {} compress v4'.format(mdfreader_version), @@ -484,8 +484,8 @@ def merge_reader_v4_compress(path, output, fmt): x1.mergeMdf(x2) output.send([timer.output, timer.error]) -def merge_reader_v4_nodata(path, output, fmt): - os.chdir(path) +def merge_reader_v4_nodata(output, fmt): + files = [r'test.mf4', ] * 2 with Timer('Merge files', 'mdfreader {} nodata v4'.format(mdfreader_version), @@ -525,14 +525,11 @@ def table_end(fmt='rst'): return ['', ] -def main(path, text_output, fmt): +def main(text_output, fmt): listen, send = multiprocessing.Pipe() output = MyList() errors = [] - if not path: - path = os.path.dirname(__file__) - installed_ram = round(psutil.virtual_memory().total / 1024 / 1024 / 1024) output.append('Benchmark environment\n') @@ -564,20 +561,20 @@ def main(path, text_output, fmt): partial(open_mdf3, memory='low'), partial(open_mdf3, memory='minimum'), open_reader3, -# open_reader3_compression, + open_reader3_compression, open_reader3_nodata, partial(open_mdf4, memory='full'), partial(open_mdf4, memory='low'), partial(open_mdf4, memory='minimum'), open_reader4, -# open_reader4_compression, + open_reader4_compression, open_reader4_nodata, ) if tests: output.extend(table_header('Open file', fmt)) for func in tests: - thr = multiprocessing.Process(target=func, args=(path, send, fmt)) + thr = multiprocessing.Process(target=func, args=(send, fmt)) thr.start() thr.join() result, err = listen.recv() @@ -589,21 +586,21 @@ def main(path, text_output, fmt): partial(save_mdf3, memory='full'), partial(save_mdf3, memory='low'), partial(save_mdf3, memory='minimum'), -# save_reader3, -# save_reader3_nodata, -# save_reader3_compression, + save_reader3, + save_reader3_nodata, + save_reader3_compression, partial(save_mdf4, memory='full'), partial(save_mdf4, memory='low'), partial(save_mdf4, memory='minimum'), -# save_reader4, -# save_reader4_nodata, -# save_reader4_compression, + save_reader4, + save_reader4_nodata, + save_reader4_compression, ) if tests: output.extend(table_header('Save file', fmt)) for func in tests: - thr = multiprocessing.Process(target=func, args=(path, send, fmt)) + thr = multiprocessing.Process(target=func, args=(send, fmt)) thr.start() thr.join() result, err = listen.recv() @@ -615,21 +612,21 @@ def main(path, text_output, fmt): partial(get_all_mdf3, memory='full'), partial(get_all_mdf3, memory='low'), partial(get_all_mdf3, memory='minimum'), -# get_all_reader3, -# get_all_reader3_nodata, -# get_all_reader3_compression, + get_all_reader3, + get_all_reader3_nodata, + get_all_reader3_compression, partial(get_all_mdf4, memory='full'), partial(get_all_mdf4, memory='low'), partial(get_all_mdf4, memory='minimum'), -# get_all_reader4, -# get_all_reader4_nodata, -# get_all_reader4_compression, + get_all_reader4, + get_all_reader4_nodata, + get_all_reader4_compression, ) if tests: output.extend(table_header('Get all channels (36424 calls)', fmt)) for func in tests: - thr = multiprocessing.Process(target=func, args=(path, send, fmt)) + thr = multiprocessing.Process(target=func, args=(send, fmt)) thr.start() thr.join() result, err = listen.recv() @@ -649,7 +646,7 @@ def main(path, text_output, fmt): if tests: output.extend(table_header('Convert file', fmt)) for func in tests: - thr = multiprocessing.Process(target=func, args=(path, send, fmt)) + thr = multiprocessing.Process(target=func, args=(send, fmt)) thr.start() thr.join() result, err = listen.recv() @@ -661,21 +658,21 @@ def main(path, text_output, fmt): partial(merge_v3, memory='full'), partial(merge_v3, memory='low'), partial(merge_v3, memory='minimum'), -# merge_reader_v3, -# merge_reader_v3_compress, -# merge_reader_v3_nodata, + merge_reader_v3, + merge_reader_v3_compress, + merge_reader_v3_nodata, partial(merge_v4, memory='full'), partial(merge_v4, memory='low'), partial(merge_v4, memory='minimum'), -# merge_reader_v4, -# merge_reader_v4_nodata, -# merge_reader_v4_compress, + merge_reader_v4, + merge_reader_v4_nodata, + merge_reader_v4_compress, ) if tests: output.extend(table_header('Merge files', fmt)) for func in tests: - thr = multiprocessing.Process(target=func, args=(path, send, fmt)) + thr = multiprocessing.Process(target=func, args=(send, fmt)) thr.start() thr.join() result, err = listen.recv() @@ -696,7 +693,7 @@ def main(path, text_output, fmt): with open(file, 'w') as out: out.write('\n'.join(output)) - os.chdir(path) + for file in ('x.mdf', 'x.mf4'): try: os.remove(file) @@ -728,4 +725,4 @@ def _cmd_line_parser(): cmd_parser = _cmd_line_parser() args = cmd_parser.parse_args(sys.argv[1:]) - main(args.path, args.text_output, args.format) + main(args.text_output, args.format) From 5e560944640d3c2bd38a361e4e88f5da39550c5c Mon Sep 17 00:00:00 2001 From: danielhrisca Date: Tue, 16 Jan 2018 09:38:37 +0200 Subject: [PATCH 102/117] small pylint fix --- asammdf/mdf_v4.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/asammdf/mdf_v4.py b/asammdf/mdf_v4.py index 1d5eaa43a..8445225af 100644 --- a/asammdf/mdf_v4.py +++ b/asammdf/mdf_v4.py @@ -857,7 +857,7 @@ def _load_signal_data(self, address): 'but found id="{}"') message = message.format(hex(address), blk_id) warnings.warn(message) - return + return b'' address = data_list['next_dl_addr'] data = b''.join(data) elif blk_id == b'##CN': @@ -2717,6 +2717,7 @@ def extract_attachment(self, index): os.chdir(current_path) message = 'Exception during attachment extraction: ' + repr(err) warnings.warn(message) + return b'' def get_channel_unit(self, name=None, group=None, index=None): """Gets channel unit. From fcf24d47206f927a710f61218620bb2c69f88367 Mon Sep 17 00:00:00 2001 From: danielhrisca Date: Wed, 17 Jan 2018 15:01:57 +0200 Subject: [PATCH 103/117] memory and speed optimizations for MDF4 --- asammdf/mdf.py | 12 +- asammdf/mdf_v4.py | 1319 ++++++++++++++++++++++++------------------ asammdf/v4_blocks.py | 43 +- 3 files changed, 805 insertions(+), 569 deletions(-) diff --git a/asammdf/mdf.py b/asammdf/mdf.py index a98332801..b89567a4c 100644 --- a/asammdf/mdf.py +++ b/asammdf/mdf.py @@ -14,9 +14,10 @@ from .mdf_v2 import MDF2 from .mdf_v3 import MDF3 from .mdf_v4 import MDF4 -from .utils import MdfException +from .utils import MdfException, get_text_v3, get_text_v4 from .v2_v3_blocks import TextBlock as TextBlockV3 from .v2_v3_blocks import Channel as ChannelV3 +from .v4_blocks import Channel as ChannelV4 from .v4_blocks import TextBlock as TextBlockV4 from .v4_blocks import ChannelArrayBlock @@ -752,14 +753,11 @@ def merge(files, outversion='4.10', memory='full'): else: stream = file._tempfile - address = grp['texts']['channels'][j]['name_addr'] - - block = TextBlockV4( - address=address, + channel = ChannelV4( + address=grp['channels'][j], stream=stream, ) - name = block['text'] - name = name.decode('utf-8').strip(' \r\n\t\0') + name = get_text_v4(channel['name_addr'], stream) name = name.split('\\')[0] names.append(name) names = set(names) diff --git a/asammdf/mdf_v4.py b/asammdf/mdf_v4.py index 8445225af..660965d75 100644 --- a/asammdf/mdf_v4.py +++ b/asammdf/mdf_v4.py @@ -53,6 +53,7 @@ get_fmt, get_min_max, get_unique_name, + get_text_v4, ) from .v4_blocks import ( AttachmentBlock, @@ -157,6 +158,7 @@ def __init__(self, name=None, memory='full', version='4.10'): self._ch_map = {} self._master_channel_cache = {} + self._si_map = {} # used for appending when memory=False self._tempfile = TemporaryFile() @@ -279,9 +281,6 @@ def _read(self): # channel_group is lsit to allow uniform handling of all texts # in save method grp['texts'] = { - 'channels': [], - 'sources': [], - 'conversions': [], 'conversion_tab': [], 'channel_group': [], } @@ -425,6 +424,9 @@ def _read(self): if self.memory == 'full': self.close() + self._si_map = None + self._ch_map = None + def _read_channels( self, ch_addr, @@ -464,29 +466,23 @@ def _read_channels( conv_tabx_texts = {} # read text fields for channel conversions - conv_texts = {} - if conv: - for key in ('name_addr', 'unit_addr', 'comment_addr'): - address = conv[key] + if memory != 'minimum': + address = conv['name_addr'] if address: - if memory == 'minimum': - conv_texts[key] = address - else: - conv_texts[key] = TextBlock( - address=address, - stream=stream, - ) - if 'formula_addr' in conv: - address = conv['formula_addr'] - if memory == 'minimum': - conv_texts['formula_addr'] = address - else: - if address: - block = TextBlock(address=address, stream=stream) - conv_texts['formula_addr'] = block - else: - conv_texts['formula_addr'] = None + conv.name = get_text_v4(address, stream) + + address = conv['unit_addr'] + if address: + conv.unit = get_text_v4(address, stream) + + address = conv['comment_addr'] + if address: + conv.comment = get_text_v4(address, stream) + + address = conv.get('formula_addr', 0) + if address: + conv.formula = get_text_v4(address, stream) if conv['conversion_type'] in v4c.TABULAR_CONVERSIONS: if conv['conversion_type'] == v4c.CONVERSION_TYPE_TTAB: @@ -564,73 +560,62 @@ def _read_channels( else: grp['texts']['conversion_tab'].append(None) - if conv_texts: - grp['texts']['conversions'].append(conv_texts) - else: - grp['texts']['conversions'].append(None) - # read source block and create source information object - source_texts = {} address = channel['source_addr'] if address: - source = SourceInformation( - address=address, - stream=stream, - ) if memory == 'minimum': +# self._si_map[address] = address grp['channel_sources'].append(address) else: - grp['channel_sources'].append(source) + stream.seek(address, v4c.SEEK_START) + raw_bytes = stream.read(v4c.SI_BLOCK_SIZE) + if raw_bytes in self._si_map: + grp['channel_sources'].append(self._si_map[raw_bytes]) + else: + source = SourceInformation( + raw_bytes=raw_bytes, + ) + grp['channel_sources'].append(source) - # read text fields for channel sources - for key in ('name_addr', - 'path_addr', - 'comment_addr'): - address = source[key] - if address: - if memory == 'minimum': - source_texts[key] = address - else: - block = TextBlock(address=address, stream=stream) - source_texts[key] = block + address = source['name_addr'] + if address: + source.name = get_text_v4(address, stream) + address = source['path_addr'] + if address: + source.path = get_text_v4(address, stream) + address = source['comment_addr'] + if address: + source.comment = get_text_v4(address, stream) + self._si_map[raw_bytes] = source - if source_texts: - grp['texts']['sources'].append(source_texts) - else: - grp['texts']['sources'].append(None) else: if memory == 'minimum': grp['channel_sources'].append(0) else: grp['channel_sources'].append(None) - grp['texts']['sources'].append(None) - # read text fields for channel - channel_texts = {} - grp['texts']['channels'].append(channel_texts) - for key in ('name_addr', 'comment_addr', 'unit_addr'): - address = channel[key] + if memory != 'minimum': + address = channel['unit_addr'] if address: - if memory == 'minimum': - channel_texts[key] = address - else: - channel_texts[key] = TextBlock( - address=address, - stream=stream, - ) - # update channel object name and block_size attributes - if memory == 'minimum': - block = TextBlock( - address=channel_texts['name_addr'], - stream=stream, - ) - name = block['text'].decode('utf-8') - else: - name = channel_texts['name_addr']['text'].decode('utf-8') - name = name.split('\\')[0] + channel.unit = get_text_v4(address, stream) + + address = channel['comment_addr'] + if address: + block = TextBlock( + address=address, + stream=stream, + ) + name = ( + block['text'] + .decode('utf-8') + .split('\\')[0] + .strip(' \t\n\r\0') + ) + channel.comment = name + channel.comment_type = block['id'] + + channel.name = name = get_text_v4(channel['name_addr'], stream) - name = name.strip(' \t\n\r\0') - channel.name = name if name not in self.channels_db: self.channels_db[name] = [] self.channels_db[name].append((dg_cntr, ch_cntr)) @@ -920,13 +905,16 @@ def _prepare_record(self, group): ch_type = new_ch['channel_type'] dependency_list = grp['channel_dependencies'][original_index] if memory == 'minimum': - channel_texts = grp['texts']['channels'][original_index] block = TextBlock( - address=channel_texts['name_addr'], + address=new_ch['name_addr'], stream=stream, ) - name = block['text'].decode('utf-8').strip(' \r\n\t\0') - name = name.split('\\')[0] + name = ( + block['text'] + .decode('utf-8') + .strip(' \r\n\t\0') + .split('\\')[0] + ) else: name = new_ch.name @@ -1308,6 +1296,7 @@ def append(self, signals, source_info='Python', common_timebase=False): or sig.samples.dtype.names ] + dg_cntr = len(self.groups) gp = {} @@ -1316,9 +1305,6 @@ def append(self, signals, source_info='Python', common_timebase=False): gp['channel_sources'] = gp_source = [] gp['channel_dependencies'] = gp_dep = [] gp['texts'] = gp_texts = { - 'channels': [], - 'sources': [], - 'conversions': [], 'conversion_tab': [], 'channel_group': [], } @@ -1336,8 +1322,6 @@ def append(self, signals, source_info='Python', common_timebase=False): # setup all blocks related to the time master channel # time channel texts - for key in ('channels', 'sources', 'channel_group', 'conversions'): - gp['texts'][key].append({}) for key in ('conversion_tab',): gp['texts'][key].append(None) @@ -1346,52 +1330,43 @@ def append(self, signals, source_info='Python', common_timebase=False): write = file.write tell = file.tell - block = TextBlock(text='t', meta=False) - if memory != 'minimum': - gp_texts['channels'][-1]['name_addr'] = block - else: - address = tell() - gp_texts['channels'][-1]['name_addr'] = address + if memory == 'minimum': + block = TextBlock(text='t', meta=False) + channel_name_addr = tell() write(bytes(block)) - block = TextBlock(text='s', meta=False) - if memory != 'minimum': - gp_texts['channels'][-1]['unit_addr'] = block - else: - address = tell() - gp_texts['channels'][-1]['unit_addr'] = address + if memory == 'minimum': + block = TextBlock(text='s', meta=False) + channel_unit_addr = tell() write(bytes(block)) - si_text = TextBlock(text=source_info, meta=False) if memory == 'minimum': - address = tell() - si_text.address = address - write(bytes(si_text)) - gp_texts['sources'][-1]['name_addr'] = address - gp_texts['sources'][-1]['path_addr'] = address - gp_texts['channel_group'][-1]['acq_name_addr'] = address - gp_texts['channel_group'][-1]['comment_addr'] = address + block = TextBlock(text=source_info, meta=False) + source_text_address = tell() + write(bytes(block)) else: - gp_texts['sources'][-1]['name_addr'] = si_text - gp_texts['sources'][-1]['path_addr'] = si_text - gp_texts['channel_group'][-1]['acq_name_addr'] = si_text - gp_texts['channel_group'][-1]['comment_addr'] = si_text + source_text_address = 0 + + source_block = SourceInformation( + name_addr=source_text_address, + path_addr=source_text_address, + ) + source_block.name = source_block.path = source_info + + source_info_address = tell() + write(bytes(source_block)) # conversion and source for time channel if memory == 'minimum': gp_conv.append(0) - - address = tell() - block = SourceInformation() - write(bytes(block)) - gp_source.append(address) + gp_source.append(source_info_address) else: gp_conv.append(None) - gp_source.append(SourceInformation()) + gp_source.append(source_block) if memory == 'minimum': - name_addr = gp_texts['channels'][-1]['name_addr'] - unit_addr = gp_texts['channels'][-1]['unit_addr'] + name_addr = channel_name_addr + unit_addr = channel_unit_addr else: name_addr = 0 unit_addr = 0 @@ -1414,12 +1389,14 @@ def append(self, signals, source_info='Python', common_timebase=False): 'unit_addr': unit_addr, } ch = Channel(**kargs) - ch.name = name = 't' + name = 't' if memory == 'minimum': address = tell() write(bytes(ch)) gp_channels.append(address) else: + ch.name = name + ch.unit = 's' gp_channels.append(ch) if name not in self.channels_db: @@ -1512,30 +1489,26 @@ def append(self, signals, source_info='Python', common_timebase=False): max_val = signal_d['max'] name = signal.name - for key in ('channels', 'sources'): - gp['texts'][key].append({}) - for key in ('conversion_tab', 'conversions'): - gp['texts'][key].append(None) + gp['texts']['conversion_tab'].append(None) - block = TextBlock(text=name, meta=False) if memory == 'minimum': - address = tell() - gp_texts['channels'][-1]['name_addr'] = address + block = TextBlock(text=name, meta=False) + channel_name_address = tell() write(bytes(block)) - gp_texts['sources'][-1]['name_addr'] = si_text.address - gp_texts['sources'][-1]['path_addr'] = si_text.address - else: - gp_texts['channels'][-1]['name_addr'] = block - gp_texts['sources'][-1]['name_addr'] = si_text - gp_texts['sources'][-1]['path_addr'] = si_text - if signal.unit: - block = TextBlock(text=signal.unit, meta=False) - if memory == 'minimum': - address = tell() - gp_texts['channels'][-1]['unit_addr'] = address + + if signal.unit: + block = TextBlock(text=signal.unit, meta=False) + channel_unit_address = tell() write(bytes(block)) else: - gp_texts['channels'][-1]['unit_addr'] = block + channel_unit_address = 0 + + if signal.comment: + block = TextBlock(text=signal.comment, meta=False) + channel_comment_address = tell() + write(bytes(block)) + else: + channel_comment_address = 0 # conversions for channel info = signal.info @@ -1653,19 +1626,18 @@ def append(self, signals, source_info='Python', common_timebase=False): # source for channel if memory != 'minimum': - gp_source.append(SourceInformation()) + gp_source.append(source_block) else: - address = tell() - block = SourceInformation() - write(bytes(block)) - gp_source.append(address) + gp_source.append(source_info_address) if memory == 'minimum': - name_addr = gp_texts['channels'][-1]['name_addr'] - unit_addr = gp_texts['channels'][-1].get('unit_addr', 0) + name_addr = channel_name_address + unit_addr = channel_unit_address + comment_addr = channel_comment_address else: name_addr = 0 unit_addr = 0 + comment_addr = 0 # compute additional byte offset for large records size if signal.samples.dtype.kind == 'u': @@ -1684,14 +1656,17 @@ def append(self, signals, source_info='Python', common_timebase=False): 'upper_limit': max_val if min_val <= max_val else 0, 'name_addr': name_addr, 'unit_addr': unit_addr, + 'comment_addr': comment_addr, } if min_val > max_val: kargs['flags'] = 0 else: kargs['flags'] = v4c.FLAG_PHY_RANGE_OK | v4c.FLAG_VAL_RANGE_OK ch = Channel(**kargs) - ch.name = name if memory != 'minimum': + ch.name = name + ch.unit = signal.unit + ch.comment = signal.comment gp_channels.append(ch) else: address = tell() @@ -1720,36 +1695,30 @@ def append(self, signals, source_info='Python', common_timebase=False): # first add the signals in the simple signal list for signal in simple_signals: name = signal.name - for key in ('channels', 'sources'): - gp['texts'][key].append({}) - for key in ('conversion_tab', 'conversions'): - gp['texts'][key].append(None) + gp['texts']['conversion_tab'].append(None) - block = TextBlock(text=name, meta=False) - if memory != 'minimum': - gp_texts['channels'][-1]['name_addr'] = block - else: - address = tell() + if memory == 'minimum': + block = TextBlock(text=name, meta=False) + channel_name_address = tell() write(bytes(block)) - gp_texts['channels'][-1]['name_addr'] = address - if signal.unit: - block = TextBlock( - text=signal.unit, - meta=False, - ) - if memory != 'minimum': - gp_texts['channels'][-1]['unit_addr'] = block - else: - address = tell() + + if signal.unit: + block = TextBlock( + text=signal.unit, + meta=False, + ) + + channel_unit_address = tell() write(bytes(block)) - gp_texts['channels'][-1]['unit_addr'] = address + else: + channel_unit_address = 0 - if memory != 'minimum': - gp_texts['sources'][-1]['name_addr'] = si_text - gp_texts['sources'][-1]['path_addr'] = si_text - else: - gp_texts['sources'][-1]['name_addr'] = si_text.address - gp_texts['sources'][-1]['path_addr'] = si_text.address + if signal.comment: + block = TextBlock(text=signal.comment, meta=False) + channel_comment_address = tell() + write(bytes(block)) + else: + channel_comment_address = 0 # conversions for channel info = signal.info @@ -1867,19 +1836,18 @@ def append(self, signals, source_info='Python', common_timebase=False): # source for channel if memory != 'minimum': - gp_source.append(SourceInformation()) + gp_source.append(source_block) else: - block = SourceInformation() - address = tell() - write(bytes(block)) - gp_source.append(address) + gp_source.append(source_info_address) if memory == 'minimum': - name_addr = gp_texts['channels'][-1]['name_addr'] - unit_addr = gp_texts['channels'][-1].get('unit_addr', 0) + name_addr = channel_name_address + unit_addr = channel_unit_address + comment_addr = channel_comment_address else: name_addr = 0 unit_addr = 0 + comment_addr = 0 # compute additional byte offset for large records size s_type, s_size = fmt_to_datatype(signal.samples.dtype) @@ -1897,14 +1865,17 @@ def append(self, signals, source_info='Python', common_timebase=False): 'upper_limit': max_val if min_val <= max_val else 0, 'name_addr': name_addr, 'unit_addr': unit_addr, + 'comment_addr': comment_addr, } if min_val > max_val: kargs['flags'] = 0 else: kargs['flags'] = v4c.FLAG_PHY_RANGE_OK | v4c.FLAG_VAL_RANGE_OK ch = Channel(**kargs) - ch.name = name if memory != 'minimum': + ch.name = name + ch.unit = signal.unit + ch.comment = signal.comment gp_channels.append(ch) else: address = tell() @@ -1977,36 +1948,26 @@ def append(self, signals, source_info='Python', common_timebase=False): s_size = byte_size << 3 # add channel texts - for key in ('channels', 'sources'): - gp['texts'][key].append({}) - for key in ('conversion_tab', 'conversions'): - gp['texts'][key].append(None) + gp['texts']['conversion_tab'].append(None) - block = TextBlock(text=name, meta=False) - if memory != 'minimum': - gp_texts['channels'][-1]['name_addr'] = block - else: - address = tell() + if memory == 'minimum': + block = TextBlock(text=name, meta=False) + channel_name_address = tell() write(bytes(block)) - gp_texts['channels'][-1]['name_addr'] = address - if signal.unit: - block = TextBlock( - text=signal.unit, - meta=False, - ) - if memory != 'minimum': - gp_texts['channels'][-1]['unit_addr'] = block - else: - address = tell() + if signal.unit: + block = TextBlock( + text=signal.unit, + meta=False, + ) + channel_unit_address = tell() write(bytes(block)) - gp_texts['channels'][-1]['unit_addr'] = address - if memory != 'minimum': - gp_texts['sources'][-1]['name_addr'] = si_text - gp_texts['sources'][-1]['path_addr'] = si_text - else: - gp_texts['sources'][-1]['name_addr'] = si_text.address - gp_texts['sources'][-1]['path_addr'] = si_text.address + if signal.comment: + block = TextBlock(text=signal.comment, meta=False) + channel_comment_address = tell() + write(bytes(block)) + else: + channel_comment_address = 0 # add channel conversion if memory != 'minimum': @@ -2014,24 +1975,22 @@ def append(self, signals, source_info='Python', common_timebase=False): else: gp_conv.append(0) - # source for time if memory != 'minimum': - gp_source.append(SourceInformation()) + gp_source.append(source_block) else: - address = tell() - block = SourceInformation() - write(bytes(block)) - gp_source.append(address) + gp_source.append(source_info_address) - # there is no chanel dependency + # there is no channel dependency gp_dep.append(None) if memory == 'minimum': - name_addr = gp_texts['channels'][-1]['name_addr'] - unit_addr = gp_texts['channels'][-1].get('unit_addr', 0) + name_addr = channel_name_address + unit_addr = channel_unit_address + comment_addr = channel_comment_address else: name_addr = 0 unit_addr = 0 + comment_addr = 0 # add channel block kargs = { @@ -2047,10 +2006,13 @@ def append(self, signals, source_info='Python', common_timebase=False): 'flags': 0, 'name_addr': name_addr, 'unit_addr': unit_addr, + 'comment_addr': comment_addr, } ch = Channel(**kargs) - ch.name = name if memory != 'minimum': + ch.name = name + ch.unit = signal.unit + ch.comment = signal.comment gp_channels.append(ch) else: address = tell() @@ -2070,7 +2032,7 @@ def append(self, signals, source_info='Python', common_timebase=False): ch_cntr += 1 - elif names and names[0] != signal.name: + elif names and names[0] != name: # here we have a structure channel composition field_name = get_unique_name(field_names, name) @@ -2078,36 +2040,26 @@ def append(self, signals, source_info='Python', common_timebase=False): # first we add the structure channel # add channel texts - for key in ('channels', 'sources'): - gp['texts'][key].append({}) - for key in ('conversion_tab', 'conversions'): - gp['texts'][key].append(None) + gp['texts']['conversion_tab'].append(None) - block = TextBlock(text=name, meta=False) - if memory != 'minimum': - gp_texts['channels'][-1]['name_addr'] = block - else: - address = tell() + if memory == 'minimum': + block = TextBlock(text=name, meta=False) + channel_name_address = tell() write(bytes(block)) - gp_texts['channels'][-1]['name_addr'] = address - if signal.unit: - block = TextBlock( - text=signal.unit, - meta=False, - ) - if memory != 'minimum': - gp_texts['channels'][-1]['unit_addr'] = block - else: - address = tell() + + if signal.unit: + block = TextBlock(text=signal.unit, meta=False) + channel_unit_address = tell() write(bytes(block)) - gp_texts['channels'][-1]['unit_addr'] = address + else: + channel_unit_address = 0 - if memory != 'minimum': - gp_texts['sources'][-1]['name_addr'] = si_text - gp_texts['sources'][-1]['path_addr'] = si_text - else: - gp_texts['sources'][-1]['name_addr'] = si_text.address - gp_texts['sources'][-1]['path_addr'] = si_text.address + if signal.comment: + block = TextBlock(text=signal.comment, meta=False) + channel_comment_address = tell() + write(bytes(block)) + else: + channel_comment_address = 0 # add channel conversion if memory != 'minimum': @@ -2116,19 +2068,18 @@ def append(self, signals, source_info='Python', common_timebase=False): gp_conv.append(0) if memory != 'minimum': - gp_source.append(SourceInformation()) + gp_source.append(source_block) else: - address = tell() - block = SourceInformation() - write(bytes(block)) - gp_source.append(address) + gp_source.append(source_info_address) if memory == 'minimum': - name_addr = gp_texts['channels'][-1]['name_addr'] - unit_addr = gp_texts['channels'][-1].get('unit_addr', 0) + name_addr = channel_name_address + unit_addr = channel_unit_address + comment_addr = channel_comment_address else: name_addr = 0 unit_addr = 0 + comment_addr = 0 # add channel block kargs = { @@ -2144,10 +2095,13 @@ def append(self, signals, source_info='Python', common_timebase=False): 'flags': 0, 'name_addr': name_addr, 'unit_addr': unit_addr, + 'comment_addr': comment_addr, } ch = Channel(**kargs) - ch.name = name if memory != 'minimum': + ch.name = name + ch.unit = signal.unit + ch.comment = signal.comment gp_channels.append(ch) else: address = tell() @@ -2181,25 +2135,26 @@ def append(self, signals, source_info='Python', common_timebase=False): types.append((field_name, samples.dtype)) # add channel texts - for key in ('channels', 'sources'): - gp['texts'][key].append({}) - for key in ('conversion_tab', 'conversions'): - gp['texts'][key].append(None) + gp['texts']['conversion_tab'].append(None) - block = TextBlock(text=name, meta=False) - if memory != 'minimum': - gp_texts['channels'][-1]['name_addr'] = block - else: - address = tell() + if memory == 'minimum': + block = TextBlock(text=name, meta=False) + channel_name_address = tell() write(bytes(block)) - gp_texts['channels'][-1]['name_addr'] = address - if memory != 'minimum': - gp_texts['sources'][-1]['name_addr'] = si_text - gp_texts['sources'][-1]['path_addr'] = si_text - else: - gp_texts['sources'][-1]['name_addr'] = si_text.address - gp_texts['sources'][-1]['path_addr'] = si_text.address + if signal.unit: + block = TextBlock(text=signal.unit, meta=False) + channel_unit_address = tell() + write(bytes(block)) + else: + channel_unit_address = 0 + + if signal.comment: + block = TextBlock(text=signal.comment, meta=False) + channel_comment_address = tell() + write(bytes(block)) + else: + channel_comment_address = 0 # add channel conversion if memory != 'minimum': @@ -2207,18 +2162,20 @@ def append(self, signals, source_info='Python', common_timebase=False): else: gp_conv.append(0) - # source for time + # source if memory != 'minimum': - gp_source.append(None) + gp_source.append(source_block) else: - gp_source.append(0) + gp_source.append(source_info_address) if memory == 'minimum': - name_addr = gp_texts['channels'][-1]['name_addr'] - unit_addr = gp_texts['channels'][-1].get('unit_addr', 0) + name_addr = channel_name_address + unit_addr = channel_unit_address + comment_addr = channel_comment_address else: name_addr = 0 unit_addr = 0 + comment_addr = 0 # add channel block min_val, max_val = get_min_max(signal.samples) @@ -2235,11 +2192,13 @@ def append(self, signals, source_info='Python', common_timebase=False): 'flags': v4c.FLAG_PHY_RANGE_OK | v4c.FLAG_VAL_RANGE_OK, 'name_addr': name_addr, 'unit_addr': unit_addr, + 'comment_addr': comment_addr, } ch = Channel(**kargs) - - ch.name = name if memory != 'minimum': + ch.name = name + ch.unit = signal.unit + ch.comment = signal.comment gp_channels.append(ch) dep_list.append(ch) else: @@ -2327,36 +2286,26 @@ def append(self, signals, source_info='Python', common_timebase=False): # first we add the structure channel # add channel texts - for key in ('channels', 'sources'): - gp['texts'][key].append({}) - for key in ('conversion_tab', 'conversions'): - gp['texts'][key].append(None) + gp['texts']['conversion_tab'].append(None) - block = TextBlock(text=name, meta=False) - if memory != 'minimum': - gp_texts['channels'][-1]['name_addr'] = block - else: - address = tell() + if memory == 'minimum': + block = TextBlock(text=name, meta=False) + channel_name_address = tell() write(bytes(block)) - gp_texts['channels'][-1]['name_addr'] = address - if signal.unit: - block = TextBlock( - text=signal.unit, - meta=False, - ) - if memory != 'minimum': - gp_texts['channels'][-1]['unit_addr'] = block - else: - address = tell() + + if signal.unit: + block = TextBlock(text=signal.unit, meta=False) + channel_unit_address = tell() write(bytes(block)) - gp_texts['channels'][-1]['unit_addr'] = address + else: + channel_unit_address = 0 - if memory != 'minimum': - gp_texts['sources'][-1]['name_addr'] = si_text - gp_texts['sources'][-1]['path_addr'] = si_text - else: - gp_texts['sources'][-1]['name_addr'] = si_text.address - gp_texts['sources'][-1]['path_addr'] = si_text.address + if signal.comment: + block = TextBlock(text=signal.comment, meta=False) + channel_comment_address = tell() + write(bytes(block)) + else: + channel_comment_address = 0 # add channel conversion if memory != 'minimum': @@ -2364,23 +2313,22 @@ def append(self, signals, source_info='Python', common_timebase=False): else: gp_conv.append(0) - # source for time + # source for channel if memory != 'minimum': - gp_source.append(SourceInformation()) + gp_source.append(source_block) else: - address = tell() - block = SourceInformation() - write(bytes(block)) - gp_source.append(address) - - s_type, s_size = fmt_to_datatype(samples.dtype) + gp_source.append(source_info_address) if memory == 'minimum': - name_addr = gp_texts['channels'][-1]['name_addr'] - unit_addr = gp_texts['channels'][-1].get('unit_addr', 0) + name_addr = channel_name_address + unit_addr = channel_unit_address + comment_addr = channel_comment_address else: name_addr = 0 unit_addr = 0 + comment_addr = 0 + + s_type, s_size = fmt_to_datatype(samples.dtype) # add channel block kargs = { @@ -2396,10 +2344,13 @@ def append(self, signals, source_info='Python', common_timebase=False): 'flags': 0, 'name_addr': name_addr, 'unit_addr': unit_addr, + 'comment_addr': comment_addr, } ch = Channel(**kargs) - ch.name = name if memory != 'minimum': + ch.name = name + ch.unit = signal.unit + ch.comment = signal.comment gp_channels.append(ch) else: address = tell() @@ -2429,26 +2380,26 @@ def append(self, signals, source_info='Python', common_timebase=False): fields.append(samples) types.append((field_name, samples.dtype, shape)) - # add composed parent signal texts - for key in ('channels', 'sources'): - gp['texts'][key].append({}) - for key in ('conversion_tab', 'conversions'): - gp['texts'][key].append(None) + gp['texts']['conversion_tab'].append(None) - block = TextBlock(text=name, meta=False) - if memory != 'minimum': - gp_texts['channels'][-1]['name_addr'] = block - else: - address = tell() + if memory == 'minimum': + block = TextBlock(text=name, meta=False) + channel_name_address = tell() write(bytes(block)) - gp_texts['channels'][-1]['name_addr'] = address - if memory != 'minimum': - gp_texts['sources'][-1]['name_addr'] = si_text - gp_texts['sources'][-1]['path_addr'] = si_text - else: - gp_texts['sources'][-1]['name_addr'] = si_text.address - gp_texts['sources'][-1]['path_addr'] = si_text.address + if signal.unit: + block = TextBlock(text=signal.unit, meta=False) + channel_unit_address = tell() + write(bytes(block)) + else: + channel_unit_address = 0 + + if signal.comment: + block = TextBlock(text=signal.comment, meta=False) + channel_comment_address = tell() + write(bytes(block)) + else: + channel_comment_address = 0 # add channel conversion if memory != 'minimum': @@ -2456,14 +2407,20 @@ def append(self, signals, source_info='Python', common_timebase=False): else: gp_conv.append(0) - # source for time + # source for channel if memory != 'minimum': - gp_source.append(SourceInformation()) + gp_source.append(source_block) else: - address = tell() - block = SourceInformation() - write(bytes(block)) - gp_source.append(address) + gp_source.append(source_info_address) + + if memory == 'minimum': + name_addr = channel_name_address + unit_addr = channel_unit_address + comment_addr = channel_comment_address + else: + name_addr = 0 + unit_addr = 0 + comment_addr = 0 # add channel dependency block kargs = { @@ -2476,13 +2433,6 @@ def append(self, signals, source_info='Python', common_timebase=False): dep = ChannelArrayBlock(**kargs) gp_dep.append([dep, ]) - if memory == 'minimum': - name_addr = gp_texts['channels'][-1]['name_addr'] - unit_addr = gp_texts['channels'][-1].get('unit_addr', 0) - else: - name_addr = 0 - unit_addr = 0 - # add components channel min_val, max_val = get_min_max(samples) s_type, s_size = fmt_to_datatype(samples.dtype) @@ -2500,16 +2450,19 @@ def append(self, signals, source_info='Python', common_timebase=False): 'flags': v4c.FLAG_PHY_RANGE_OK | v4c.FLAG_VAL_RANGE_OK, 'name_addr': name_addr, 'unit_addr': unit_addr, + 'comment_addr': comment_addr, } - channel = Channel(**kargs) - channel.name = name + ch = Channel(**kargs) if memory != 'minimum': - gp_channels.append(channel) + ch.name = name + ch.unit = signal.unit + ch.comment = signal.comment + gp_channels.append(ch) else: address = tell() - write(bytes(channel)) + write(bytes(ch)) gp_channels.append(address) parent_dep.referenced_channels.append((ch_cntr, dg_cntr)) @@ -2533,6 +2486,7 @@ def append(self, signals, source_info='Python', common_timebase=False): } gp['channel_group'] = ChannelGroup(**kargs) gp['size'] = cycles_nr * offset + gp['texts']['channel_group'].append(None) # data group gp['data_group'] = DataGroup() @@ -2768,40 +2722,45 @@ def get_channel_unit(self, name=None, group=None, index=None): else: stream = self._tempfile - conv_texts = grp['texts']['conversions'][ch_nr] - channel_texts = grp['texts']['channels'][ch_nr] + channel = grp['channels'][ch_nr] + conversion = grp['channel_conversions'][ch_nr] - if conv_texts and 'unit_addr' in conv_texts: - if not self.memory == 'minimum': - unit = conv_texts['unit_addr'] - else: + if self.memory == 'minimum': + + channel = Channel( + address=channel, + stream=stream, + ) + + if conversion: + conversion = ChannelConversion( + address=conversion, + stream=stream, + ) + + address = ( + conversion and conversion['unit_addr'] + or channel['unit_addr'] + or 0 + ) + + if address: unit = TextBlock( - address=conv_texts['unit_addr'], + address=address, stream=stream, ) - if PYVERSION == 3: - try: - unit = unit['text'].decode('utf-8').strip(' \n\t\0') - except UnicodeDecodeError: - unit = '' - else: - unit = unit['text'].strip(' \n\t\0') - else: - # search for physical unit in channel texts - if 'unit_addr' in channel_texts: - if not self.memory == 'minimum': - unit = channel_texts['unit_addr'] - else: - unit = TextBlock( - address=channel_texts['unit_addr'], - stream=stream, - ) if PYVERSION == 3: unit = unit['text'].decode('utf-8').strip(' \n\t\0') else: unit = unit['text'].strip(' \n\t\0') else: unit = '' + else: + unit = ( + conversion and conversion.unit + or channel.unit + or '' + ) return unit @@ -2849,33 +2808,46 @@ def get_channel_comment(self, name=None, group=None, index=None): grp = self.groups[gp_nr] - channel_texts = grp['texts']['channels'][ch_nr] - if grp['data_location'] == v4c.LOCATION_ORIGINAL_FILE: stream = self._file else: stream = self._tempfile - if 'comment_addr' in channel_texts: - if self.memory == 'minimum': - comment = TextBlock( - address=channel_texts['comment_addr'], + channel = grp['channels'][ch_nr] + + if self.memory == 'minimum': + channel = Channel( + address=channel, + stream=stream, + ) + + address = channel['comment_addr'] + if address: + comment_block = TextBlock( + address=address, stream=stream, ) + comment = ( + comment_block['text'] + .decode('utf-8') + .strip(' \r\n\t\0') + ) + if comment_block['id'] == b'##MD': + match = TX.search(comment) + if match: + comment = match.group('text') + else: + comment = '' else: - comment = channel_texts['comment_addr'] - - if comment['id'] == b'##MD': - comment = comment['text'].decode('utf-8').strip(' \n\t\0') + comment = '' + else: + comment = channel.comment + if channel.comment_type == b'##MD': match = TX.search(comment) if match: comment = match.group('text') else: comment = '' - else: - comment = comment['text'].decode('utf-8') - else: - comment = '' return comment @@ -3028,11 +3000,15 @@ def get(self, conversion = None if name is None: name = TextBlock( - address=grp['texts']['channels'][ch_nr]['name_addr'], + address=channel['name_addr'], stream=stream, ) - name = name['text'].decode('utf-8').strip(' \r\t\n\0') - name = name.split('\\')[0] + name = ( + name['text'] + .decode('utf-8') + .strip(' \r\t\n\0') + .split('\\')[0] + ) channel.name = name else: channel = grp['channels'][ch_nr] @@ -3077,13 +3053,7 @@ def get(self, stream=stream, ) - block = TextBlock( - address=channel['name_addr'], - stream=stream, - ) - - name_ = block['text'].decode('utf-8') - name_ = name_.split('\\')[0].strip(' \n\r\t\0') + name_ = get_text_v4(channel['name_addr'], stream) names.append(name_) else: names = [ch.name for ch in dependency_list] @@ -3175,23 +3145,14 @@ def get(self, for i in range(dims_nr): ch_nr, dg_nr = ca_block.referenced_channels[i] if memory == 'minimum': - axisname = ( - self.groups[dg_nr] - ['texts'] - ['channels'] - [ch_nr] - ['name_addr'] - ) - block = TextBlock( - address=axisname, + channel = Channel( + address=self.groups[dg_nr]['channels'][ch_nr], stream=stream, ) - axisname = ( - block['text'] - .decode('utf-8') - .strip(' \t\n\r\0') + axisname = get_text_v4( + channel['name_addr'], + stream, ) - axisname = axisname.split('\\')[0] else: axisname = ( self.groups[dg_nr] @@ -3238,23 +3199,14 @@ def get(self, for i in range(dims_nr): ch_nr, dg_nr = ca_block.referenced_channels[i] if memory == 'minimum': - axisname = ( - self.groups[dg_nr] - ['texts'] - ['channels'] - [ch_nr] - ['name_addr'] - ) - block = TextBlock( - address=axisname, + channel = Channel( + address=self.groups[dg_nr]['channels'][ch_nr], stream=stream, ) - axisname = ( - block['text'] - .decode('utf-8') - .strip(' \t\n\r\0') + axisname = get_text_v4( + channel['name_addr'], + stream, ) - axisname = axisname.split('\\')[0] else: axisname = ( self.groups[dg_nr] @@ -3524,20 +3476,10 @@ def get(self, elif conversion_type == v4c.CONVERSION_TYPE_ALG: if not memory == 'minimum': - block = ( - grp['texts'] - ['conversions'] - [ch_nr] - ['formula_addr'] - ) - formula = ( - block['text'] - .decode('utf-8') - .strip(' \n\t\0') - ) + formula = conversion.formula else: block = TextBlock( - address=grp['texts']['conversions'][ch_nr]['formula_addr'], + address=conversion['formula_addr'], stream=stream, ) formula = ( @@ -3803,62 +3745,48 @@ def get(self, res = vals else: # search for unit in conversion texts - conv_texts = grp['texts']['conversions'][ch_nr] - channel_texts = grp['texts']['channels'][ch_nr] - if conv_texts and 'unit_addr' in conv_texts: - if not memory == 'minimum': - unit = conv_texts['unit_addr'] - else: - unit = TextBlock( - address=conv_texts['unit_addr'], + if memory == 'minimum': + + address = ( + conversion and conversion['unit_addr'] + or channel['unit_addr'] + or 0 + ) + if address: + unit = get_text_v4( + address=address, stream=stream, ) - if PYVERSION == 3: - try: - unit = unit['text'].decode('utf-8').strip(' \n\t\0') - except UnicodeDecodeError: - unit = '' - else: - unit = unit['text'].strip(' \n\t\0') - else: - # search for physical unit in channel texts - if 'unit_addr' in channel_texts: - if not memory == 'minimum': - unit = channel_texts['unit_addr'] - else: - unit = TextBlock( - address=channel_texts['unit_addr'], - stream=stream, - ) - if PYVERSION == 3: - unit = unit['text'].decode('utf-8').strip(' \n\t\0') - else: - unit = unit['text'].strip(' \n\t\0') else: unit = '' - # get the channel commment if available - if 'comment_addr' in channel_texts: - if memory == 'minimum': - comment = TextBlock( - address=channel_texts['comment_addr'], + address = channel['comment_addr'] + if address: + comment = get_text_v4( + address=address, stream=stream, ) - else: - comment = channel_texts['comment_addr'] - if comment['id'] == b'##MD': - comment = comment['text'].decode('utf-8').strip(' \n\t\0') + if channel.comment_type == b'##MD': + match = TX.search(comment) + if match: + comment = match.group('text') + else: + comment = '' + else: + comment = '' + else: + unit = ( + conversion and conversion.unit + or channel.unit + or '' + ) + comment = channel.comment + if channel.comment_type == b'##MD': match = TX.search(comment) if match: comment = match.group('text') - else: - comment = '' - else: - comment = comment['text'].decode('utf-8') - else: - comment = '' t = self.get_master(gp_nr, data) @@ -4010,12 +3938,15 @@ def info(self): stream=stream, ) name = TextBlock( - address=gp['texts']['channels'][j]['name_addr'], + address=channel['name_addr'], stream=stream, ) - name = name['text'].decode('utf-8').strip(' \r\t\n\0') - name = name.split('\\')[0] - channel.name = name + name = ( + name['text'] + .decode('utf-8') + .strip(' \r\t\n\0') + .split('\\')[0] + ) else: name = channel.name @@ -4340,6 +4271,8 @@ def _save_with_metadata(self, dst, overwrite, compression): v4c.CONVERSION_TYPE_TRANS, ) + si_map = {} + # go through each data group and append the rest of the blocks for i, gp in enumerate(self.groups): # write TXBLOCK's @@ -4358,16 +4291,156 @@ def _save_with_metadata(self, dst, overwrite, compression): address += tx_block['block_len'] blocks.append(tx_block) + for channel in gp['channels']: + if channel.name: + tx_block = TextBlock(text=channel.name) + text = tx_block['text'] + if text in defined_texts: + channel['name_addr'] = defined_texts[text] + else: + channel['name_addr'] = address + defined_texts[text] = address + tx_block.address = address + address += tx_block['block_len'] + blocks.append(tx_block) + else: + channel['name_addr'] = 0 + + if channel.unit: + tx_block = TextBlock(text=channel.unit) + text = tx_block['text'] + if text in defined_texts: + channel['unit_addr'] = defined_texts[text] + else: + channel['unit_addr'] = address + defined_texts[text] = address + tx_block.address = address + address += tx_block['block_len'] + blocks.append(tx_block) + else: + channel['unit_addr'] = 0 + + if channel.comment: + meta = channel.comment_type == b'##MD' + tx_block = TextBlock(text=channel.comment, meta=meta) + text = tx_block['text'] + if text in defined_texts: + channel['comment_addr'] = defined_texts[text] + else: + channel['comment_addr'] = address + defined_texts[text] = address + tx_block.address = address + address += tx_block['block_len'] + blocks.append(tx_block) + else: + channel['comment_addr'] = 0 + + for source in gp['channel_sources']: + if source: + if source.name: + tx_block = TextBlock(text=source.name) + text = tx_block['text'] + if text in defined_texts: + source['name_addr'] = defined_texts[text] + else: + source['name_addr'] = address + defined_texts[text] = address + tx_block.address = address + address += tx_block['block_len'] + blocks.append(tx_block) + else: + source['name_addr'] = 0 + + if source.path: + tx_block = TextBlock(text=source.path) + text = tx_block['text'] + if text in defined_texts: + source['path_addr'] = defined_texts[text] + else: + source['path_addr'] = address + defined_texts[text] = address + tx_block.address = address + address += tx_block['block_len'] + blocks.append(tx_block) + else: + source['path_addr'] = 0 + + if source.comment: + tx_block = TextBlock(text=source.comment) + text = tx_block['text'] + if text in defined_texts: + source['comment_addr'] = defined_texts[text] + else: + source['comment_addr'] = address + defined_texts[text] = address + tx_block.address = address + address += tx_block['block_len'] + blocks.append(tx_block) + else: + source['comment_addr'] = 0 + + for conversion in gp['channel_conversions']: + if conversion: + if conversion.name: + tx_block = TextBlock(text=conversion.name) + text = tx_block['text'] + if text in defined_texts: + conversion['name_addr'] = defined_texts[text] + else: + conversion['name_addr'] = address + defined_texts[text] = address + tx_block.address = address + address += tx_block['block_len'] + blocks.append(tx_block) + else: + conversion['name_addr'] = 0 + + if conversion.unit: + tx_block = TextBlock(text=conversion.unit) + text = tx_block['text'] + if text in defined_texts: + conversion['unit_addr'] = defined_texts[text] + else: + conversion['unit_addr'] = address + defined_texts[text] = address + tx_block.address = address + address += tx_block['block_len'] + blocks.append(tx_block) + else: + conversion['unit_addr'] = 0 + + if conversion.comment: + tx_block = TextBlock(text=conversion.comment) + text = tx_block['text'] + if text in defined_texts: + conversion['comment_addr'] = defined_texts[text] + else: + conversion['comment_addr'] = address + defined_texts[text] = address + tx_block.address = address + address += tx_block['block_len'] + blocks.append(tx_block) + else: + conversion['comment_addr'] = 0 + + if conversion['conversion_type'] == v4c.CONVERSION_TYPE_ALG and conversion.formula: + tx_block = TextBlock(text=conversion.formula) + text = tx_block['text'] + if text in defined_texts: + conversion['formula_addr'] = defined_texts[text] + else: + conversion['formula_addr'] = address + defined_texts[text] = address + tx_block.address = address + address += tx_block['block_len'] + blocks.append(tx_block) + # channel conversions for j, conv in enumerate(gp['channel_conversions']): if conv: conv.address = address - conv_texts = gp['texts']['conversions'][j] - if conv_texts: - for key, text_block in conv_texts.items(): - conv[key] = text_block.address - conv['inv_conv_addr'] = 0 + conv['inv_conv_addr'] = 0 if conv['conversion_type'] in tab_conversion: for key in gp['texts']['conversion_tab'][j]: @@ -4385,17 +4458,12 @@ def _save_with_metadata(self, dst, overwrite, compression): # channel sources for j, source in enumerate(gp['channel_sources']): if source: - source.address = address - source_texts = gp['texts']['sources'][j] - - for key in ('name_addr', 'path_addr', 'comment_addr'): - if source_texts and key in source_texts: - source[key] = source_texts[key].address - else: - source[key] = 0 - - address += source['block_len'] - blocks.append(source) + source_id = id(source) + if source_id not in si_map: + source.address = address + address += source['block_len'] + blocks.append(source) + si_map[source_id] = 0 # channel data gp_sd = gp['signal_data'] = [] @@ -4431,18 +4499,10 @@ def _save_with_metadata(self, dst, overwrite, compression): for j, (channel, signal_data) in enumerate( zip(gp['channels'], gp['signal_data'])): channel.address = address - channel_texts = gp['texts']['channels'][j] address += channel['block_len'] blocks.append(channel) - for key in ('comment_addr', 'unit_addr'): - if key in channel_texts: - channel[key] = channel_texts[key].address - else: - channel[key] = 0 - channel['name_addr'] = channel_texts['name_addr'].address - if not gp['channel_conversions'][j]: channel['conversion_addr'] = 0 else: @@ -4815,8 +4875,14 @@ def _save_without_metadata(self, dst, overwrite, compression): v4c.CONVERSION_TYPE_TRANS, ) + si_map = {} + # go through each data group and append the rest of the blocks for i, gp in enumerate(self.groups): + gp['temp_channels'] = ch_addrs = [] + gp['temp_channel_conversions'] = cc_addrs = [] + gp['temp_channel_sources'] = si_addrs = [] + if gp['data_location'] == v4c.LOCATION_ORIGINAL_FILE: stream = self._file else: @@ -4826,7 +4892,7 @@ def _save_without_metadata(self, dst, overwrite, compression): # write TXBLOCK's for item_list in temp_texts.values(): for dict_ in item_list: - if dict_ is None: + if not dict_: continue for key, tx_block in dict_.items(): # text blocks can be shared @@ -4843,56 +4909,159 @@ def _save_without_metadata(self, dst, overwrite, compression): dict_[key] = address write(bytes(block)) - # channel conversions - gp['temp_channel_conversions'] = [] - for j, conv in enumerate(gp['channel_conversions']): - if conv: - - address = tell() - gp['temp_channel_conversions'].append(address) - conv = ChannelConversion( - address=conv, - stream=stream, - ) - - conv.address = address - conv_texts = temp_texts['conversions'][j] + for source in gp['channel_sources']: + if source: + stream.seek(source, v4c.SEEK_START) + raw_bytes = stream.read(v4c.SI_BLOCK_SIZE) + if raw_bytes in si_map: + si_addrs.append(si_map[raw_bytes]) + else: + source = SourceInformation( + raw_bytes=raw_bytes, + ) + + if source['name_addr']: + tx_block = TextBlock( + address=source['name_addr'], + stream=stream, + ) + text = tx_block['text'] + if text in defined_texts: + source['name_addr'] = defined_texts[text] + else: + address = tell() + source['name_addr'] = address + defined_texts[text] = address + tx_block.address = address + write(bytes(tx_block)) + else: + source['name_addr'] = 0 - if conv_texts: + if source.path: + tx_block = TextBlock( + address=source['path_addr'], + stream=stream, + ) + text = tx_block['text'] + if text in defined_texts: + source['path_addr'] = defined_texts[text] + else: + address = tell() + source['path_addr'] = address + defined_texts[text] = address + tx_block.address = address + write(bytes(tx_block)) + else: + source['path_addr'] = 0 - for key, text_block in conv_texts.items(): - conv[key] = text_block - conv['inv_conv_addr'] = 0 + if source['comment_addr']: + tx_block = TextBlock( + address=source['comment_addr'], + stream=stream, + ) + text = tx_block['text'] + if text in defined_texts: + source['comment_addr'] = defined_texts[text] + else: + address = tell() + source['comment_addr'] = address + defined_texts[text] = address + tx_block.address = address + write(bytes(tx_block)) + else: + source['comment_addr'] = 0 - if conv['conversion_type'] in tab_conversion: - for key in temp_texts['conversion_tab'][j]: - conv[key] = temp_texts['conversion_tab'][j][key] - write(bytes(conv)) + address = tell() + si_addrs.append(address) + si_map[raw_bytes] = address + write(bytes(source)) else: - gp['temp_channel_conversions'].append(0) - - # channel sources - gp['temp_channel_sources'] = [] - for j, source in enumerate(gp['channel_sources']): - if source: - address = tell() - gp['temp_channel_sources'].append(address) - source_texts = temp_texts['sources'][j] + si_addrs.append(0) - source = SourceInformation( - address=source, + for j, conversion in enumerate(gp['channel_conversions']): + if conversion: + conversion = ChannelConversion( + address=conversion, stream=stream, ) + + if conversion['name_addr']: + tx_block = TextBlock( + address=conversion['name_addr'], + stream=stream, + ) + text = tx_block['text'] + if text in defined_texts: + conversion['name_addr'] = defined_texts[text] + else: + address = tell() + conversion['name_addr'] = address + defined_texts[text] = address + tx_block.address = address + write(bytes(tx_block)) + else: + conversion['name_addr'] = 0 + + if conversion['unit_addr']: + tx_block = TextBlock( + address=conversion['unit_addr'], + stream=stream, + ) + text = tx_block['text'] + if text in defined_texts: + conversion['unit_addr'] = defined_texts[text] + else: + address = tell() + conversion['unit_addr'] = address + defined_texts[text] = address + tx_block.address = address + write(bytes(tx_block)) + else: + conversion['unit_addr'] = 0 - for key in ('name_addr', 'path_addr', 'comment_addr'): - if source_texts and key in source_texts: - source[key] = source_texts[key] + if conversion['comment_addr']: + tx_block = TextBlock( + address=conversion['comment_addr'], + stream=stream, + ) + text = tx_block['text'] + if text in defined_texts: + conversion['comment_addr'] = defined_texts[text] else: - source[key] = 0 + address = tell() + conversion['comment_addr'] = address + defined_texts[text] = address + tx_block.address = address + write(bytes(tx_block)) + else: + conversion['comment_addr'] = 0 - write(bytes(source)) + if conversion['conversion_type'] == v4c.CONVERSION_TYPE_ALG and conversion['formula_addr']: + tx_block = TextBlock( + address=conversion['formula_addr'], + stream=stream, + ) + text = tx_block['text'] + if text in defined_texts: + conversion['formula_addr'] = defined_texts[text] + else: + address = tell() + conversion['formula_addr'] = address + defined_texts[text] = address + tx_block.address = address + write(bytes(tx_block)) + + elif conversion['conversion_type'] in tab_conversion: + for key in temp_texts['conversion_tab'][j]: + conversion[key] = temp_texts['conversion_tab'][j][key] + + conversion['inv_conv_addr'] = 0 + + address = tell() + cc_addrs.append(address) + write(bytes(conversion)) else: - gp['temp_channel_sources'].append(0) + cc_addrs.append(0) # channel dependecies temp_deps = [] @@ -4921,28 +5090,72 @@ def _save_without_metadata(self, dst, overwrite, compression): blocks = [] chans = [] address = blocks_start_addr = tell() - gp['temp_channels'] = ch_addrs = [] + gp['channel_group']['first_ch_addr'] = address + + for j, channel in enumerate(gp['channels']): channel = Channel( address=channel, stream=stream, ) channel.address = address - channel_texts = temp_texts['channels'][j] - ch_addrs.append(address) + chans.append(channel) + blocks.append(channel) address += channel['block_len'] - blocks.append(channel) - chans.append(channel) - for key in ('comment_addr', 'unit_addr'): - if key in channel_texts: - channel[key] = channel_texts[key] + if channel['name_addr']: + tx_block = TextBlock( + address=channel['name_addr'], + stream=stream, + ) + text = tx_block['text'] + if text in defined_texts: + channel['name_addr'] = defined_texts[text] else: - channel[key] = 0 - channel['name_addr'] = channel_texts['name_addr'] + channel['name_addr'] = address + defined_texts[text] = address + tx_block.address = address + address += tx_block['block_len'] + blocks.append(tx_block) + else: + channel['name_addr'] = 0 + + if channel['unit_addr']: + tx_block = TextBlock( + address=channel['unit_addr'], + stream=stream, + ) + text = tx_block['text'] + if text in defined_texts: + channel['unit_addr'] = defined_texts[text] + else: + channel['unit_addr'] = address + defined_texts[text] = address + tx_block.address = address + address += tx_block['block_len'] + blocks.append(tx_block) + else: + channel['unit_addr'] = 0 + + if channel['comment_addr']: + tx_block = TextBlock( + address=channel['comment_addr'], + stream=stream, + ) + text = tx_block['text'] + if text in defined_texts: + channel['comment_addr'] = defined_texts[text] + else: + channel['comment_addr'] = address + defined_texts[text] = address + tx_block.address = address + address += tx_block['block_len'] + blocks.append(tx_block) + else: + channel['comment_addr'] = 0 channel['conversion_addr'] = gp['temp_channel_conversions'][j] channel['source_addr'] = gp['temp_channel_sources'][j] diff --git a/asammdf/v4_blocks.py b/asammdf/v4_blocks.py index 8ee0a33fd..d2f6811f6 100644 --- a/asammdf/v4_blocks.py +++ b/asammdf/v4_blocks.py @@ -156,12 +156,12 @@ def __bytes__(self): class Channel(dict): """ CNBLOCK class""" - __slots__ = ['address', 'name'] + __slots__ = ['address', 'name', 'unit', 'comment', 'comment_type'] def __init__(self, **kargs): super(Channel, self).__init__() - self.name = '' + self.name = self.unit = self.comment = self.comment_type = '' if 'stream' in kargs: @@ -672,11 +672,13 @@ def __bytes__(self): class ChannelConversion(dict): """CCBLOCK class""" - __slots__ = ['address', ] + __slots__ = ['address', 'name', 'unit', 'comment', 'formula'] def __init__(self, **kargs): super(ChannelConversion, self).__init__() + self.name = self.unit = self.comment = self.formula = '' + if 'stream' in kargs: self.address = address = kargs['address'] stream = kargs['stream'] @@ -692,7 +694,7 @@ def __init__(self, **kargs): block = stream.read(self['block_len'] - v4c.COMMON_SIZE) - conv = unpack_from('B', block, self['links_nr'] * 8)[0] + conv = unpack_from(' Date: Wed, 17 Jan 2018 15:07:04 +0200 Subject: [PATCH 104/117] forgot to update utils.py --- asammdf/utils.py | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/asammdf/utils.py b/asammdf/utils.py index 3b882cead..51141c3fd 100644 --- a/asammdf/utils.py +++ b/asammdf/utils.py @@ -4,6 +4,7 @@ ''' import itertools +from struct import unpack from numpy import ( amin, @@ -18,6 +19,7 @@ 'get_fmt', 'get_min_max', 'get_unique_name', + 'get_text_v4', 'fix_dtype_fields', 'fmt_to_datatype', 'pair', @@ -40,6 +42,29 @@ def bytes(obj): else: raise +def get_text_v3(address, stream): + stream.seek(address + 2) + size = unpack(' Date: Thu, 18 Jan 2018 11:51:06 +0200 Subject: [PATCH 105/117] implement save for MDF3 for full and low options --- asammdf/mdf.py | 27 +- asammdf/mdf_v3.py | 711 +++++++++++++++++++--------------------- asammdf/v2_v3_blocks.py | 74 ++++- benchmarks/bench.py | 2 + 4 files changed, 417 insertions(+), 397 deletions(-) diff --git a/asammdf/mdf.py b/asammdf/mdf.py index b89567a4c..94ce35eaf 100644 --- a/asammdf/mdf.py +++ b/asammdf/mdf.py @@ -729,23 +729,20 @@ def merge(files, outversion='4.10', memory='full'): else: stream = file._tempfile - channel_texts = grp['texts']['channels'][j] - if channel_texts and \ - 'long_name_addr' in channel_texts: - address = channel_texts['long_name_addr'] - - block = TextBlockV3( - address=address, - stream=stream, - ) - name = block['text'] + channel = ChannelV3( + address=grp['channels'][j], + stream=stream, + ) + + if channel['long_name_addr']: + name = get_text_v3(channel['long_name_addr'], stream) else: - channel = ChannelV3( - address=grp['channels'][j], - stream=stream, + name = ( + channel['short_name'] + .decode('latin-1') + .strip(' \r\n\t\0') + .split('\\')[0] ) - name = channel['short_name'] - name = name.decode('latin-1').strip(' \r\n\t\0') else: grp = file.groups[i] if grp['data_location'] == 0: diff --git a/asammdf/mdf_v3.py b/asammdf/mdf_v3.py index c0894164a..0d33e605d 100644 --- a/asammdf/mdf_v3.py +++ b/asammdf/mdf_v3.py @@ -12,6 +12,7 @@ from functools import partial, reduce from itertools import product from tempfile import TemporaryFile +from struct import unpack, unpack_from from numexpr import evaluate from numpy import ( @@ -48,6 +49,7 @@ get_fmt, get_min_max, get_unique_name, + get_text_v3, pair, ) from .v2_v3_blocks import ( @@ -275,26 +277,15 @@ def _prepare_record(self, group): data_type = new_ch['data_type'] bit_count = new_ch['bit_count'] if memory == 'minimum': - channel_texts = grp['texts']['channels'][original_index] - if channel_texts and 'long_name_addr' in channel_texts: - address = channel_texts['long_name_addr'] - - block = TextBlock( - address=address, - stream=stream, - ) - name = ( - block['text'] - .decode('latin-1') - .strip(' \r\n\t\0') - ) + if new_ch.get('long_name_addr', 0): + name = get_text_v3(new_ch['long_name_addr'], stream) else: name = ( new_ch['short_name'] .decode('latin-1') .strip(' \r\n\t\0') + .split('\\')[0] ) - name = name.split('\\')[0] else: name = new_ch.name @@ -582,6 +573,8 @@ def _read(self): # needed for linking dependency blocks to referenced channels after # the file is loaded ch_map = {} + ce_map = {} + cc_map = {} # go to first date group dg_addr = self.header['first_dg_addr'] @@ -621,7 +614,6 @@ def _read(self): grp['channel_extensions'] = [] grp['data_block'] = None grp['texts'] = { - 'channels': [], 'conversion_tab': [], 'channel_group': [], } @@ -669,7 +661,6 @@ def _read(self): ch_cntr = 0 grp_chs = grp['channels'] grp_conv = grp['channel_conversions'] - grp_ch_texts = grp['texts']['channels'] while ch_addr: # read channel block and create channel object @@ -694,14 +685,23 @@ def _read(self): # read conversion block address = new_ch['conversion_addr'] if address: - new_conv = ChannelConversion( - address=address, - stream=stream, - ) - if memory != 'minimum': - grp_conv.append(new_conv) - else: + stream.seek(address, v23c.SEEK_START) + raw_bytes = stream.read(v23c.CE_BLOCK_SIZE) + if memory == 'minimum': + new_conv = ChannelConversion( + raw_bytes=raw_bytes, + ) grp_conv.append(address) + else: + if raw_bytes in cc_map: + new_conv = cc_map[raw_bytes] + else: + new_conv = new_conv = ChannelConversion( + raw_bytes=raw_bytes, + ) + if new_conv['conversion_type'] != v23c.CONVERSION_TYPE_VTABR: + cc_map[raw_bytes] = new_conv + grp_conv.append(new_conv) else: new_conv = None if memory != 'minimum': @@ -733,54 +733,44 @@ def _read(self): grp['texts']['conversion_tab'].append(None) address = new_ch['source_depend_addr'] + if memory != 'minimum': if address: - block = ChannelExtension( - address=address, - stream=stream, - ) - grp['channel_extensions'].append(block) + stream.seek(address, v23c.SEEK_START) + raw_bytes = stream.read(v23c.CE_BLOCK_SIZE) + + if raw_bytes in ce_map: + grp['channel_extensions'].append(ce_map[raw_bytes]) + else: + block = ChannelExtension( + raw_bytes=raw_bytes, + ) + grp['channel_extensions'].append(block) + ce_map[raw_bytes] = block else: grp['channel_extensions'].append(None) else: grp['channel_extensions'].append(address) # read text fields for channel - ch_texts = {} - for key in ( - 'long_name_addr', - 'comment_addr', - 'display_name_addr'): - address = new_ch.get(key, 0) - if address: - if memory != 'minimum': - ch_texts[key] = TextBlock( - address=address, - stream=stream, - ) - else: - ch_texts[key] = address - - if ch_texts: - grp_ch_texts.append(ch_texts) + address = new_ch.get('long_name_addr', 0) + if address: + new_ch.name = name = get_text_v3(address, stream) else: - grp_ch_texts.append(None) + new_ch.name = name = ( + new_ch['short_name'] + .decode('latin-1') + .strip(' \n\t\0') + .split('\\')[0] + ) - # update channel object name and block_size attributes - if new_ch.get('long_name_addr', 0): - if memory != 'minimum': - name = ch_texts['long_name_addr']['text'] - else: - block = TextBlock( - address=ch_texts['long_name_addr'], - stream=stream, - ) - name = block['text'] - else: - name = new_ch['short_name'] - name = name.decode('latin-1').strip(' \n\t\0') - name = name.split('\\')[0] - new_ch.name = name + address = new_ch.get('comment_addr', 0) + if address: + new_ch.comment = get_text_v3(address, stream) + + address = new_ch.get('display_name_addr', 0) + if address: + new_ch.display_name = get_text_v3(address, stream) if name in self.channels_db: self.channels_db[name].append((dg_cntr, ch_cntr)) @@ -1020,6 +1010,28 @@ def append(self, write = file.write tell = file.tell + cc_map = {} + + kargs = { + 'module_nr': 0, + 'module_address': 0, + 'type': v23c.SOURCE_ECU, + 'description': b'Channel inserted by Python Script', + } + ce_block = ChannelExtension(**kargs) + if memory == 'minimum': + ce_address = tell() + write(bytes(ce_block)) + + if acquisition_info: + acq_block = TextBlock(text=acquisition_info) + if memory == 'minimum': + acq_address = tell() + write(bytes(acq_block)) + else: + acq_block = None + acq_address = 0 + # split regular from composed signals. Composed signals have recarray # samples or multimendional ndarray. # The regular signals will be first added to the group. @@ -1058,7 +1070,6 @@ def append(self, gp['channel_extensions'] = gp_source = [] gp['channel_dependencies'] = gp_dep = [] gp['texts'] = gp_texts = { - 'channels': [], 'conversion_tab': [], 'channel_group': [], } @@ -1072,20 +1083,15 @@ def append(self, offset = 0 field_names = set() - # setup all blocks related to the time master channel + cg_texts = {} + gp_texts['channel_group'].append(cg_texts) + if memory == 'minimum': + cg_texts['comment_addr'] = acq_address + else: + cg_texts['comment_addr'] = acq_block # time channel texts - for _, item in gp_texts.items(): - item.append(None) - - gp_texts['channel_group'][-1] = {} - block = TextBlock(text=acquisition_info) - if memory != 'minimum': - gp_texts['channel_group'][-1]['comment_addr'] = block - else: - address = tell() - gp_texts['channel_group'][-1]['comment_addr'] = address - write(bytes(block)) + gp_texts['conversion_tab'].append(None) # conversion for time channel kargs = { @@ -1103,19 +1109,10 @@ def append(self, write(bytes(block)) # source for time - kargs = { - 'module_nr': 0, - 'module_address': 0, - 'type': v23c.SOURCE_ECU, - 'description': b'Channel inserted by Python Script', - } - block = ChannelExtension(**kargs) if memory != 'minimum': - gp_source.append(block) + gp_source.append(ce_block) else: - address = tell() - gp_source.append(address) - write(bytes(block)) + gp_source.append(ce_address) # time channel t_type, t_size = fmt_to_datatype(t.dtype) @@ -1228,20 +1225,6 @@ def append(self, max_val = signal_d['max'] name = signal.name - for _, item in gp['texts'].items(): - item.append(None) - - texts = {} - if len(name) >= 32 and self.version >= '2.10': - block = TextBlock(text=name) - if memory != 'minimum': - texts['long_name_addr'] = block - else: - address = tell() - texts['long_name_addr'] = address - write(bytes(block)) - if texts: - gp_texts['channels'][-1] = texts texts = {} info = signal.info @@ -1278,7 +1261,6 @@ def append(self, address = tell() texts[key] = address write(bytes(block)) - else: if min_val <= max_val: min_phy_value = min_val @@ -1294,7 +1276,9 @@ def append(self, } if texts: - gp_texts['conversion_tab'][-1] = texts + gp_texts['conversion_tab'].append(texts) + else: + gp_texts['conversion_tab'].append(None) block = ChannelConversion(**kargs) if memory != 'minimum': @@ -1305,19 +1289,10 @@ def append(self, write(bytes(block)) # source for channel - kargs = { - 'module_nr': 0, - 'module_address': 0, - 'type': v23c.SOURCE_ECU, - 'description': b'Channel inserted by Python Script', - } - block = ChannelExtension(**kargs) if memory != 'minimum': - gp_source.append(block) + gp_source.append(ce_block) else: - address = tell() - gp_source.append(address) - write(bytes(block)) + gp_source.append(ce_address) # compute additional byte offset for large records size current_offset = offset + bit_offset @@ -1335,27 +1310,27 @@ def append(self, else: data_type = v23c.DATA_TYPE_SIGNED - texts = {} - if len(name) >= 32 and self.version >= '2.10': - short_name = (name[:31] + '\0').encode('latin-1') - if memory != 'minimum': - texts['long_name_addr'] = TextBlock(text=name) - else: - address = tell() - texts['long_name_addr'] = address - block = TextBlock(text=name) - write(bytes(block)) + if memory == 'minimum' and len(name) >= 32 and self.version >= '2.10': + block = TextBlock(text=name) + long_name_address = tell() + write(bytes(block)) else: - short_name = name.encode('latin-1') - - if texts: - gp_texts['channels'][-1] = texts - - channel_texts = gp_texts['channels'][-1] - if channel_texts: - long_name_addr = channel_texts.get('long_name_addr', 0) + long_name_address = 0 + comment = signal.comment + if comment: + if len(comment) >= 128: + description = b'\0' + if memory == 'minimum': + block = TextBlock(text=comment) + comment_address = tell() + write(bytes(block)) + else: + description = (comment[:127] + '\0').encode('latin-1') + comment_address = 0 else: - long_name_addr = 0 + description = b'\0' + comment_address = 0 + short_name = (name[:31] + '\0').encode('latin-1') kargs = { 'short_name': short_name, @@ -1368,17 +1343,15 @@ def append(self, 'aditional_byte_offset': additional_byte_offset, 'long_name_addr': long_name_addr, 'block_len': channel_size, + 'comment_addr': comment_address, + 'description': description, } - comment = signal.comment - if comment: - comment = comment.encode('latin-1') - if len(comment) >= 128: - comment = comment[:127] + b'\0' - kargs['description'] = comment channel = Channel(**kargs) - channel.name = name + if memory != 'minimum': + channel.name = name + channel.comment = signal.comment gp_channels.append(channel) else: address = tell() @@ -1405,23 +1378,7 @@ def append(self, # first add the signals in the simple signal list for signal in simple_signals: - # channels texts name = signal.name - for _, item in gp['texts'].items(): - item.append(None) - - texts = {} - if len(name) >= 32 and self.version >= '2.10': - block = TextBlock(text=name) - if memory != 'minimum': - texts['long_name_addr'] = block - else: - address = tell() - texts['long_name_addr'] = address - write(bytes(block)) - if texts: - gp_texts['channels'][-1] = texts - # conversions for channel min_val, max_val = get_min_max(signal.samples) @@ -1459,7 +1416,6 @@ def append(self, address = tell() texts[key] = address write(bytes(block)) - else: if min_val <= max_val: min_phy_value = min_val @@ -1475,7 +1431,9 @@ def append(self, } if texts: - gp_texts['conversion_tab'][-1] = texts + gp_texts['conversion_tab'].append(texts) + else: + gp_texts['conversion_tab'].append(None) block = ChannelConversion(**kargs) if memory != 'minimum': @@ -1486,19 +1444,10 @@ def append(self, write(bytes(block)) # source for channel - kargs = { - 'module_nr': 0, - 'module_address': 0, - 'type': v23c.SOURCE_ECU, - 'description': b'Channel inserted by Python Script', - } - block = ChannelExtension(**kargs) if memory != 'minimum': - gp_source.append(block) + gp_source.append(ce_block) else: - address = tell() - gp_source.append(address) - write(bytes(block)) + gp_source.append(ce_address) # compute additional byte offset for large records size if offset > v23c.MAX_UINT16: @@ -1509,16 +1458,27 @@ def append(self, additional_byte_offset = 0 s_type, s_size = fmt_to_datatype(signal.samples.dtype) - if len(name) >= 32: - short_name = (name[:31] + '\0').encode('latin-1') + if memory == 'minimum' and len(name) >= 32 and self.version >= '2.10': + block = TextBlock(text=name) + long_name_address = tell() + write(bytes(block)) else: - short_name = name.encode('latin-1') - - channel_texts = gp_texts['channels'][-1] - if channel_texts: - long_name_addr = channel_texts.get('long_name_addr', 0) + long_name_address = 0 + comment = signal.comment + if comment: + if len(comment) >= 128: + description = b'\0' + if memory == 'minimum': + block = TextBlock(text=comment) + comment_address = tell() + write(bytes(block)) + else: + description = (comment[:127] + '\0').encode('latin-1') + comment_address = 0 else: - long_name_addr = 0 + description = b'\0' + comment_address = 0 + short_name = (name[:31] + '\0').encode('latin-1') kargs = { 'short_name': short_name, @@ -1529,20 +1489,17 @@ def append(self, 'start_offset': start_bit_offset, 'bit_count': s_size, 'aditional_byte_offset': additional_byte_offset, - 'long_name_addr': long_name_addr, + 'long_name_addr': long_name_address, 'block_len': channel_size, + 'comment_addr': comment_address, + 'description': description, } - comment = signal.comment - if comment: - if len(comment) >= 128: - comment = (comment[:127] + '\0').encode('latin-1') - else: - comment = comment.encode('latin-1') - kargs['description'] = comment channel = Channel(**kargs) - channel.name = name if memory != 'minimum': + channel.name = name + channel.comment = signal.comment + gp_channels.append(channel) gp_channels.append(channel) else: address = tell() @@ -1605,21 +1562,7 @@ def append(self, component_samples.extend(new_samples) component_names.extend(names[1:]) - # add composed parent signal texts - for _, item in gp['texts'].items(): - item.append(None) - - texts = {} - if len(name) >= 32 and self.version >= '2.10': - block = TextBlock(text=name) - if memory != 'minimum': - texts['long_name_addr'] = block - else: - address = tell() - texts['long_name_addr'] = address - write(bytes(block)) - if texts: - gp_texts['channels'][-1] = texts + gp_texts['conversion_tab'].append(None) # composed parent has no conversion if memory != 'minimum': @@ -1627,20 +1570,11 @@ def append(self, else: gp_conv.append(0) - # add parent and components sources - kargs = { - 'module_nr': 0, - 'module_address': 0, - 'type': v23c.SOURCE_ECU, - 'description': b'Channel inserted by Python Script', - } - block = ChannelExtension(**kargs) + # source for channel if memory != 'minimum': - gp_source.append(block) + gp_source.append(ce_block) else: - address = tell() - gp_source.append(address) - write(bytes(block)) + gp_source.append(ce_address) min_val, max_val = get_min_max(samples) @@ -1653,15 +1587,27 @@ def append(self, start_bit_offset = offset additional_byte_offset = 0 - if len(name) >= 32: - short_name = (name[:31] + '\0').encode('latin-1') + if memory == 'minimum' and len(name) >= 32 and self.version >= '2.10': + block = TextBlock(text=name) + long_name_address = tell() + write(bytes(block)) else: - short_name = name.encode('latin-1') - channel_texts = gp_texts['channels'][-1] - if channel_texts: - long_name_addr = channel_texts.get('long_name_addr', 0) + long_name_address = 0 + comment = signal.comment + if comment: + if len(comment) >= 128: + description = b'\0' + if memory == 'minimum': + block = TextBlock(text=comment) + comment_address = tell() + write(bytes(block)) + else: + description = (comment[:127] + '\0').encode('latin-1') + comment_address = 0 else: - long_name_addr = 0 + description = b'\0' + comment_address = 0 + short_name = (name[:31] + '\0').encode('latin-1') kargs = { 'short_name': short_name, @@ -1672,21 +1618,16 @@ def append(self, 'start_offset': start_bit_offset, 'bit_count': s_size, 'aditional_byte_offset': additional_byte_offset, - 'long_name_addr': long_name_addr, + 'long_name_addr': long_name_address, 'block_len': channel_size, + 'comment_addr': comment_address, + 'description': description, } - comment = signal.comment - if comment: - if len(comment) >= 128: - comment = (comment[:127] + '\0').encode('latin-1') - else: - comment = comment.encode('latin-1') - kargs['description'] = comment channel = Channel(**kargs) - channel.name = name - channel.name = name if memory != 'minimum': + channel.name = name + channel.comment = signal.comment gp_channels.append(channel) else: address = tell() @@ -1701,38 +1642,33 @@ def append(self, for i, (name, samples) in enumerate( zip(component_names, component_samples)): - for _, item in gp['texts'].items(): - item.append(None) + gp_texts['conversion_tab'].append(None) - texts = {} - if len(name) >= 32 and self.version >= '2.10': + if memory == 'minimum' and len(name) >= 32 and self.version >= '2.10': block = TextBlock(text=name) - if memory != 'minimum': - texts['long_name_addr'] = block - else: - address = tell() - texts['long_name_addr'] = address - write(bytes(block)) - if texts: - gp_texts['channels'][-1] = texts + long_name_address = tell() + write(bytes(block)) + else: + long_name_address = 0 + if i < sd_nr: + dep_pair = ch_cntr, dg_cntr + parent_dep.referenced_channels.append(dep_pair) + description = b'\0' + else: + description = '{} - axis {}'.format(signal.name, name) + description = description.encode('latin-1') + comment_address = 0 + short_name = (name[:31] + '\0').encode('latin-1') min_val, max_val = get_min_max(samples) s_type, s_size = fmt_to_datatype(samples.dtype) shape = samples.shape[1:] - kargs = { - 'module_nr': 0, - 'module_address': 0, - 'type': v23c.SOURCE_ECU, - 'description': b'Channel inserted by Python Script', - } - block = ChannelExtension(**kargs) + # source for channel if memory != 'minimum': - gp_source.append(block) + gp_source.append(ce_block) else: - address = tell() - gp_source.append(address) - write(bytes(block)) + gp_source.append(ce_address) if memory != 'minimum': gp_conv.append(None) @@ -1747,15 +1683,6 @@ def append(self, start_bit_offset = offset additional_byte_offset = 0 - if len(name) >= 32: - short_name = (name[:31] + '\0').encode('latin-1') - else: - short_name = name.encode('latin-1') - channel_texts = gp_texts['channels'][-1] - if channel_texts: - long_name_addr = channel_texts.get('long_name_addr', 0) - else: - long_name_addr = 0 kargs = { 'short_name': short_name, 'channel_type': v23c.CHANNEL_TYPE_VALUE, @@ -1765,18 +1692,21 @@ def append(self, 'start_offset': start_bit_offset, 'bit_count': s_size, 'aditional_byte_offset': additional_byte_offset, - 'long_name_addr': long_name_addr, + 'long_name_addr': long_name_address, 'block_len': channel_size, + 'comment_addr': comment_address, + 'description': description, } channel = Channel(**kargs) - channel.name = name if memory != 'minimum': + channel.name = name gp_channels.append(channel) else: address = tell() gp_channels.append(address) write(bytes(channel)) + size = s_size for dim in shape: size *= dim @@ -1796,14 +1726,6 @@ def append(self, gp_dep.append(None) - if i < sd_nr: - dep_pair = ch_cntr, dg_cntr - parent_dep.referenced_channels.append(dep_pair) - else: - description = '{} - axis {}'.format(signal.name, name) - description = description.encode('latin-1') - channel['description'] = description - ch_cntr += 1 # channel group @@ -1858,7 +1780,6 @@ def append(self, gp['channel_extensions'] = gp_source = [] gp['channel_dependencies'] = gp_dep = [] gp['texts'] = gp_texts = { - 'channels': [], 'conversion_tab': [], 'channel_group': [], } @@ -1872,11 +1793,8 @@ def append(self, offset = 0 field_names = set() - # setup all blocks related to the time master channel - # time channel texts - for _, item in gp_texts.items(): - item.append(None) + gp_texts['conversion_tab'].append(None) # conversion for time channel kargs = { @@ -1886,27 +1804,18 @@ def append(self, 'max_phy_value': t[-1] if cycles_nr else 0, } block = ChannelConversion(**kargs) - if memory == 'minimum': + if memory != 'minimum': + gp_conv.append(block) + else: address = tell() - write(bytes(block)) gp_conv.append(address) - else: - gp_conv.append(ChannelConversion(**kargs)) + write(bytes(block)) # source for time - kargs = { - 'module_nr': 0, - 'module_address': 0, - 'type': v23c.SOURCE_ECU, - 'description': b'Channel inserted by Python Script', - } - block = ChannelExtension(**kargs) if memory != 'minimum': - gp_source.append(block) + gp_source.append(ce_block) else: - address = tell() - gp_source.append(address) - write(bytes(block)) + gp_source.append(ce_address) # time channel t_type, t_size = fmt_to_datatype(t.dtype) @@ -1950,13 +1859,13 @@ def append(self, if names == ( 'ms', 'days'): - block = TextBlock(text='From mdf v4 CANopen Time channel') + acq_block = TextBlock(text='From mdf v4 CANopen Time channel') if memory == 'minimum': - address = tell() + acq_address = tell() write(bytes(block)) - gp_texts['channel_group'][-1] = {'comment_addr': address} + gp_texts['channel_group'].append({'comment_addr': acq_address}) else: - gp_texts['channel_group'][-1] = {'comment_addr': block} + gp_texts['channel_group'].append({'comment_addr': acq_block}) elif names == ( 'ms', 'min', @@ -1966,37 +1875,37 @@ def append(self, 'year', 'summer_time', 'day_of_week'): - block = TextBlock(text='From mdf v4 CANopen Date channel') + acq_block = TextBlock(text='From mdf v4 CANopen Date channel') if memory == 'minimum': - address = tell() + acq_address = tell() write(bytes(block)) - gp_texts['channel_group'][-1] = {'comment_addr': address} + gp_texts['channel_group'].append({'comment_addr': acq_address}) else: - gp_texts['channel_group'][-1] = {'comment_addr': block} + gp_texts['channel_group'].append({'comment_addr': acq_block}) else: text = 'From mdf v4 structure channel composition' - block = TextBlock(text=text) + acq_block = TextBlock(text=text) if memory == 'minimum': - address = tell() + acq_address = tell() write(bytes(block)) - gp_texts['channel_group'][-1] = {'comment_addr': address} + gp_texts['channel_group'].append({'comment_addr': acq_address}) else: - gp_texts['channel_group'][-1] = {'comment_addr': block} + gp_texts['channel_group'].append({'comment_addr': acq_block}) for name in names: samples = signal.samples[name] - # channels texts - for _, item in gp['texts'].items(): - item.append(None) + gp_texts['conversion_tab'].append(None) - texts = {} - if len(name) >= 32 and self.version >= '2.10': + if memory == 'minimum' and len(name) >= 32 and self.version >= '2.10': block = TextBlock(text=name) - texts['long_name_addr'] = block - if texts: - gp_texts['channels'][-1] = texts + long_name_address = tell() + write(bytes(block)) + else: + long_name_address = 0 + comment_address = 0 + short_name = (name[:31] + '\0').encode('latin-1') # conversions for channel min_val, max_val = get_min_max(samples) @@ -2016,19 +1925,10 @@ def append(self, write(bytes(block)) # source for channel - kargs = { - 'module_nr': 0, - 'module_address': 0, - 'type': v23c.SOURCE_ECU, - 'description': b'Channel inserted by Python Script', - } - block = ChannelExtension(**kargs) if memory != 'minimum': - gp_source.append(block) + gp_source.append(ce_block) else: - address = tell() - gp_source.append(address) - write(bytes(block)) + gp_source.append(ce_address) # compute additional byte offset for large records size if offset > v23c.MAX_UINT16: @@ -2038,15 +1938,7 @@ def append(self, start_bit_offset = offset additional_byte_offset = 0 s_type, s_size = fmt_to_datatype(samples.dtype) - if len(name) >= 32: - short_name = (name[:31] + '\0').encode('latin-1') - else: - short_name = name.encode('latin-1') - channel_texts = gp_texts['channels'][-1] - if channel_texts: - long_name_addr = channel_texts.get('long_name_addr', 0) - else: - long_name_addr = 0 + kargs = { 'short_name': short_name, 'channel_type': v23c.CHANNEL_TYPE_VALUE, @@ -2056,13 +1948,16 @@ def append(self, 'start_offset': start_bit_offset, 'bit_count': s_size, 'aditional_byte_offset': additional_byte_offset, - 'long_name_addr': long_name_addr, + 'long_name_addr': long_name_address, 'block_len': channel_size, + 'comment_addr': comment_address, + 'description': description, } channel = Channel(**kargs) - channel.name = name + if memory != 'minimum': + channel.name = name gp_channels.append(channel) else: address = tell() @@ -2215,7 +2110,11 @@ def get_channel_unit(self, name=None, group=None, index=None): conversion = grp['channel_conversions'][ch_nr] if conversion: - unit = conversion['unit'].decode('latin-1').strip(' \n\t\0') + unit = ( + conversion['unit'] + .decode('latin-1') + .strip(' \n\t\0') + ) else: unit = '' @@ -2276,8 +2175,21 @@ def get_channel_comment(self, name=None, group=None, index=None): else: channel = grp['channels'][ch_nr] - comment = channel['description'].decode('latin-1') - comment = comment.strip(' \t\n\0') + if memory == 'minimum': + comment = '' + if channel['comment_addr']: + comment = get_text_v3(channel['comment_addr'], stream) + else: + comment = channel.comment + description = ( + channel['description'] + .decode('latin-1') + .strip(' \t\n\0') + ) + if comment: + comment = '{}\n{}'.format(comment, description) + else: + comment = description return comment @@ -2440,15 +2352,14 @@ def get(self, conversion = None if name is None: if channel.get('long_name_addr', 0): - name = TextBlock( - address=channel['long_name_addr'], - stream=stream, - ) - name = name['text'] + name = get_text_v3(channel['long_name_addr'], stream) else: - name = channel['short_name'] - name = name.decode('utf-8').strip(' \r\t\n\0') - name = name.split('\\')[0] + name = ( + channel['short_name'] + .decode('latin-1') + .strip(' \n\t\0') + .split('\\')[0] + ) channel.name = name dep = grp['channel_dependencies'][ch_nr] @@ -2739,8 +2650,22 @@ def get(self, unit = conversion['unit'].decode('latin-1').strip(' \n\t\0') else: unit = '' - comment = channel['description'].decode('latin-1') - comment = comment.strip(' \t\n\0') + + if memory == 'minimum': + comment = '' + if channel['comment_addr']: + comment = get_text_v3(channel['comment_addr'], stream) + else: + comment = channel.comment + description = ( + channel['description'] + .decode('latin-1') + .strip(' \t\n\0') + ) + if comment: + comment = '{}\n{}'.format(comment, description) + else: + comment = description t = self.get_master(gp_nr, data) @@ -2932,15 +2857,14 @@ def info(self): stream=stream, ) if channel.get('long_name_addr', 0): - name = TextBlock( - address=channel['long_name_addr'], - stream=stream, - ) - name = name['text'] + name = get_text_v3(channel['long_name_addr'], stream) else: - name = channel['short_name'] - name = name.decode('utf-8').strip(' \r\t\n\0') - name = name.split('\\')[0] + name = ( + channel['short_name'] + .decode('utf-8') + .strip(' \r\t\n\0') + .split('\\')[0] + ) if channel['channel_type'] == v23c.CHANNEL_TYPE_MASTER: ch_type = 'master' @@ -3104,6 +3028,9 @@ def _save_with_metadata(self, dst, overwrite, compression): blocks.append(self.file_history) address += self.file_history['block_len'] + ce_map = {} + cc_map = {} + # DataGroup # put them first in the block list so they will be written first to # disk this way, in case of memory=False, we can safely @@ -3142,28 +3069,85 @@ def _save_with_metadata(self, dst, overwrite, compression): blocks.append(tx_block) address += tx_block['block_len'] + for channel in gp['channels']: + comment = channel.comment + if comment: + if len(comment) >= 128: + channel['description'] = b'\0' + tx_block = TextBlock(text=comment) + text = tx_block['text'] + if text in defined_texts: + channel['comment_addr'] = defined_texts[text].address + else: + channel['comment_addr'] = address + defined_texts[text] = tx_block + tx_block.address = address + blocks.append(tx_block) + address += tx_block['block_len'] + else: + channel['description'] = (comment[:127] + '\0').encode('latin-1') + channel['comment_addr'] = 0 + if self.version >= '2.10': + if len(channel.name) >= 32: + tx_block = TextBlock(text=channel.name) + text = tx_block['text'] + if text in defined_texts: + channel['long_name_addr'] = defined_texts[text].address + else: + channel['long_name_addr'] = address + defined_texts[text] = tx_block + tx_block.address = address + blocks.append(tx_block) + address += tx_block['block_len'] + else: + channel['long_name_addr'] = 0 + if 'display_name_addr' in channel: + if channel.display_name: + tx_block = TextBlock(text=channel.display_name) + text = tx_block['text'] + if text in defined_texts: + channel['display_name_addr'] = defined_texts[text].address + else: + channel['display_name_addr'] = address + defined_texts[text] = tx_block + tx_block.address = address + blocks.append(tx_block) + address += tx_block['block_len'] + else: + channel['display_name_addr'] = 0 + # ChannelConversions cc = gp['channel_conversions'] for i, conv in enumerate(cc): if conv is None: continue - conv.address = address if conv['conversion_type'] == v23c.CONVERSION_TYPE_VTABR: + conv.address = address pairs = gp_texts['conversion_tab'][i].items() for key, item in pairs: conv[key] = item.address - blocks.append(conv) - address += conv['block_len'] + blocks.append(conv) + address += conv['block_len'] + else: + cc_id = id(cc) + if cc_id not in cc_map: + conv.address = address + cc_map[cc_id] = conv + blocks.append(conv) + address += conv['block_len'] # Channel Extension cs = gp['channel_extensions'] for source in cs: if source: - source.address = address - blocks.append(source) - address += source['block_len'] + source_id = id(source) + if source_id not in ce_map: + source.address = address + ce_map[source_id] = source + blocks.append(source) + address += source['block_len'] # Channel Dependency cd = gp['channel_dependencies'] @@ -3174,21 +3158,12 @@ def _save_with_metadata(self, dst, overwrite, compression): address += dep['block_len'] # Channels - ch_texts = gp_texts['channels'] for i, channel in enumerate(gp['channels']): channel.address = address - channel_texts = ch_texts[i] blocks.append(channel) address += channel['block_len'] - if channel_texts: - for key in ('long_name_addr', - 'comment_addr', - 'display_name_addr'): - if key in channel_texts: - channel[key] = channel_texts[key].address - channel['conversion_addr'] = cc[i].address if cc[i] else 0 if cs[i]: channel['source_depend_addr'] = cs[i].address diff --git a/asammdf/v2_v3_blocks.py b/asammdf/v2_v3_blocks.py index abc8a94ed..db4340213 100644 --- a/asammdf/v2_v3_blocks.py +++ b/asammdf/v2_v3_blocks.py @@ -115,12 +115,12 @@ class Channel(dict): b'CN' ''' - __slots__ = ['name', 'address'] + __slots__ = ['name', 'address', 'comment', 'display_name'] def __init__(self, **kargs): super(Channel, self).__init__() - self.name = '' + self.name = self.display_name = self.comment = '' try: stream = kargs['stream'] @@ -355,15 +355,27 @@ class ChannelConversion(dict): def __init__(self, **kargs): super(ChannelConversion, self).__init__() - try: - stream = kargs['stream'] - self.address = address = kargs['address'] - stream.seek(address, SEEK_START) - block = stream.read(4) - (self['id'], - self['block_len']) = unpack('<2sH', block) - size = self['block_len'] - block = stream.read(size - 4) + if 'raw_bytes' in kargs or 'stream' in kargs: + try: + self.address = 0 + block = kargs['raw_bytes'] + (self['id'], + self['block_len']) = unpack_from( + '<2sH', + block, + ) + size = self['block_len'] + block = block[4:] + + except KeyError: + stream = kargs['stream'] + self.address = address = kargs['address'] + stream.seek(address, SEEK_START) + block = stream.read(4) + (self['id'], + self['block_len']) = unpack('<2sH', block) + size = self['block_len'] + block = stream.read(size - 4) (self['range_flag'], self['min_phy_value'], @@ -465,7 +477,8 @@ def __init__(self, **kargs): message = 'Expected "CC" block but found "{}"' raise MdfException(message.format(self['id'])) - except KeyError: + else: + self.address = 0 self['id'] = 'CC'.encode('latin-1') @@ -857,7 +870,40 @@ class ChannelExtension(dict): def __init__(self, **kargs): super(ChannelExtension, self).__init__() - try: + if 'raw_bytes' in kargs: + + (self['id'], + self['block_len'], + self['type']) = unpack_from( + v23c.FMT_SOURCE_COMMON, + kargs['raw_bytes'], + ) + if self['type'] == v23c.SOURCE_ECU: + (self['module_nr'], + self['module_address'], + self['description'], + self['ECU_identification'], + self['reserved0']) = unpack_from( + v23c.FMT_SOURCE_EXTRA_ECU, + kargs['raw_bytes'], + 6, + ) + elif self['type'] == v23c.SOURCE_VECTOR: + (self['CAN_id'], + self['CAN_ch_index'], + self['message_name'], + self['sender_name'], + self['reserved0']) = unpack_from( + v23c.FMT_SOURCE_EXTRA_VECTOR, + kargs['raw_bytes'], + 6, + ) + + if self['id'] != b'CE': + message = 'Expected "CE" block but found "{}"' + raise MdfException(message.format(self['id'])) + + elif 'stream' in kargs: stream = kargs['stream'] self.address = address = kargs['address'] stream.seek(address, SEEK_START) @@ -882,7 +928,7 @@ def __init__(self, **kargs): message = 'Expected "CE" block but found "{}"' raise MdfException(message.format(self['id'])) - except KeyError: + else: self.address = 0 self['id'] = b'CE' diff --git a/benchmarks/bench.py b/benchmarks/bench.py index 73dc951ed..a4cae975e 100644 --- a/benchmarks/bench.py +++ b/benchmarks/bench.py @@ -526,6 +526,8 @@ def table_end(fmt='rst'): def main(text_output, fmt): + if os.path.dirname(__file__): + os.chdir(os.path.dirname(__file__)) listen, send = multiprocessing.Pipe() output = MyList() errors = [] From 3f382e9814633fdc69483e482fea94b347ec6708 Mon Sep 17 00:00:00 2001 From: danielhrisca Date: Thu, 18 Jan 2018 13:24:22 +0200 Subject: [PATCH 106/117] implement save for MDF3 for minimum option --- asammdf/mdf.py | 2 +- asammdf/mdf_v3.py | 195 +++++++++++++++++++++++++++++----------------- 2 files changed, 126 insertions(+), 71 deletions(-) diff --git a/asammdf/mdf.py b/asammdf/mdf.py index 94ce35eaf..3109cd0d4 100644 --- a/asammdf/mdf.py +++ b/asammdf/mdf.py @@ -734,7 +734,7 @@ def merge(files, outversion='4.10', memory='full'): stream=stream, ) - if channel['long_name_addr']: + if channel.get('long_name_addr', 0): name = get_text_v3(channel['long_name_addr'], stream) else: name = ( diff --git a/asammdf/mdf_v3.py b/asammdf/mdf_v3.py index 0d33e605d..20765004a 100644 --- a/asammdf/mdf_v3.py +++ b/asammdf/mdf_v3.py @@ -685,8 +685,10 @@ def _read(self): # read conversion block address = new_ch['conversion_addr'] if address: - stream.seek(address, v23c.SEEK_START) - raw_bytes = stream.read(v23c.CE_BLOCK_SIZE) + stream.seek(address + 2, v23c.SEEK_START) + size = unpack(' Date: Thu, 18 Jan 2018 15:59:38 +0200 Subject: [PATCH 107/117] more optimizations --- asammdf/mdf.py | 7 +-- asammdf/mdf_v3.py | 98 ++++++++++++++++++++--------------------- asammdf/mdf_v4.py | 32 +++++++++++--- asammdf/v4_blocks.py | 39 +++++++++++----- asammdf/v4_constants.py | 8 ++++ 5 files changed, 112 insertions(+), 72 deletions(-) diff --git a/asammdf/mdf.py b/asammdf/mdf.py index 3109cd0d4..1acd48639 100644 --- a/asammdf/mdf.py +++ b/asammdf/mdf.py @@ -168,7 +168,7 @@ def convert(self, to, memory='full'): ' Available versions are {}' ) warn(message.format(to, SUPPORTED_VERSIONS)) - return + out = None else: out = MDF(version=to, memory=memory) @@ -192,7 +192,8 @@ def convert(self, to, memory='full'): source_info.format(self.version, to), common_timebase=True, ) - return out + + return out def cut(self, start=None, stop=None, whence=0): """convert MDF to other versions @@ -231,7 +232,7 @@ def cut(self, start=None, stop=None, whence=0): index=master_index, samples_only=True, ) - if len(master): + if master.size: timestamps.append(master[0]) first_timestamp = np.amin(timestamps) if start is not None: diff --git a/asammdf/mdf_v3.py b/asammdf/mdf_v3.py index 20765004a..f878b415d 100644 --- a/asammdf/mdf_v3.py +++ b/asammdf/mdf_v3.py @@ -1012,8 +1012,6 @@ def append(self, write = file.write tell = file.tell - cc_map = {} - kargs = { 'module_nr': 0, 'module_address': 0, @@ -2182,7 +2180,7 @@ def get_channel_comment(self, name=None, group=None, index=None): else: channel = grp['channels'][ch_nr] - if memory == 'minimum': + if self.memory == 'minimum': comment = '' if channel['comment_addr']: comment = get_text_v3(channel['comment_addr'], stream) @@ -3076,53 +3074,6 @@ def _save_with_metadata(self, dst, overwrite, compression): blocks.append(tx_block) address += tx_block['block_len'] - for channel in gp['channels']: - comment = channel.comment - if comment: - if len(comment) >= 128: - channel['description'] = b'\0' - tx_block = TextBlock(text=comment) - text = tx_block['text'] - if text in defined_texts: - channel['comment_addr'] = defined_texts[text].address - else: - channel['comment_addr'] = address - defined_texts[text] = tx_block - tx_block.address = address - blocks.append(tx_block) - address += tx_block['block_len'] - else: - channel['description'] = (comment[:127] + '\0').encode('latin-1') - channel['comment_addr'] = 0 - if self.version >= '2.10': - if len(channel.name) >= 32: - tx_block = TextBlock(text=channel.name) - text = tx_block['text'] - if text in defined_texts: - channel['long_name_addr'] = defined_texts[text].address - else: - channel['long_name_addr'] = address - defined_texts[text] = tx_block - tx_block.address = address - blocks.append(tx_block) - address += tx_block['block_len'] - else: - channel['long_name_addr'] = 0 - if 'display_name_addr' in channel: - if channel.display_name: - tx_block = TextBlock(text=channel.display_name) - text = tx_block['text'] - if text in defined_texts: - channel['display_name_addr'] = defined_texts[text].address - else: - channel['display_name_addr'] = address - defined_texts[text] = tx_block - tx_block.address = address - blocks.append(tx_block) - address += tx_block['block_len'] - else: - channel['display_name_addr'] = 0 - # ChannelConversions cc = gp['channel_conversions'] for i, conv in enumerate(cc): @@ -3167,10 +3118,55 @@ def _save_with_metadata(self, dst, overwrite, compression): # Channels for i, channel in enumerate(gp['channels']): channel.address = address - blocks.append(channel) address += channel['block_len'] + comment = channel.comment + if comment: + if len(comment) >= 128: + channel['description'] = b'\0' + tx_block = TextBlock(text=comment) + text = tx_block['text'] + if text in defined_texts: + channel['comment_addr'] = defined_texts[text].address + else: + channel['comment_addr'] = address + defined_texts[text] = tx_block + tx_block.address = address + blocks.append(tx_block) + address += tx_block['block_len'] + else: + channel['description'] = (comment[:127] + '\0').encode('latin-1') + channel['comment_addr'] = 0 + if self.version >= '2.10': + if len(channel.name) >= 32: + tx_block = TextBlock(text=channel.name) + text = tx_block['text'] + if text in defined_texts: + channel['long_name_addr'] = defined_texts[text].address + else: + channel['long_name_addr'] = address + defined_texts[text] = tx_block + tx_block.address = address + blocks.append(tx_block) + address += tx_block['block_len'] + else: + channel['long_name_addr'] = 0 + if 'display_name_addr' in channel: + if channel.display_name: + tx_block = TextBlock(text=channel.display_name) + text = tx_block['text'] + if text in defined_texts: + channel['display_name_addr'] = defined_texts[text].address + else: + channel['display_name_addr'] = address + defined_texts[text] = tx_block + tx_block.address = address + blocks.append(tx_block) + address += tx_block['block_len'] + else: + channel['display_name_addr'] = 0 + channel['conversion_addr'] = cc[i].address if cc[i] else 0 if cs[i]: channel['source_depend_addr'] = cs[i].address diff --git a/asammdf/mdf_v4.py b/asammdf/mdf_v4.py index 660965d75..6f9770a8a 100644 --- a/asammdf/mdf_v4.py +++ b/asammdf/mdf_v4.py @@ -159,6 +159,7 @@ def __init__(self, name=None, memory='full', version='4.10'): self._ch_map = {} self._master_channel_cache = {} self._si_map = {} + self._cc_map = {} # used for appending when memory=False self._tempfile = TemporaryFile() @@ -426,6 +427,7 @@ def _read(self): self._si_map = None self._ch_map = None + self._cc_map = None def _read_channels( self, @@ -456,8 +458,27 @@ def _read_channels( # read conversion block and create channel conversion object address = channel['conversion_addr'] if address: - conv = ChannelConversion(address=address, stream=stream) + if memory == 'minimum': + conv = ChannelConversion( + address=address, + stream=stream, + ) + conv_type = conv['conversion_type'] + else: + stream.seek(address+8) + size = unpack(' Date: Fri, 19 Jan 2018 11:02:30 +0200 Subject: [PATCH 108/117] Pylint improvements --- asammdf/mdf.py | 83 ++++++++-------- asammdf/mdf_v3.py | 185 ++++++++++++++++++----------------- asammdf/mdf_v4.py | 92 +++++++++--------- asammdf/utils.py | 232 ++++++++++++++++++++++++++++---------------- benchmarks/bench.py | 14 ++- test/test_mdf23.py | 5 + 6 files changed, 345 insertions(+), 266 deletions(-) diff --git a/asammdf/mdf.py b/asammdf/mdf.py index 1acd48639..cf5a015a0 100644 --- a/asammdf/mdf.py +++ b/asammdf/mdf.py @@ -127,8 +127,8 @@ def _excluded_channels(self, index): continue if all(not isinstance(dep, ChannelArrayBlock) for dep in dependencies): - for ch in dependencies: - excluded_channels.add(channels.index(ch)) + for channel in dependencies: + excluded_channels.add(channels.index(channel)) else: for dep in dependencies: for ch_nr, gp_nr in dep.referenced_channels: @@ -173,13 +173,13 @@ def convert(self, to, memory='full'): out = MDF(version=to, memory=memory) # walk through all groups and get all channels - for i, gp in enumerate(self.groups): + for i, group in enumerate(self.groups): sigs = [] excluded_channels = self._excluded_channels(i) - data = self._load_group_data(gp) + data = self._load_group_data(group) - for j, _ in enumerate(gp['channels']): + for j, _ in enumerate(group['channels']): if j in excluded_channels: continue else: @@ -192,7 +192,7 @@ def convert(self, to, memory='full'): source_info.format(self.version, to), common_timebase=True, ) - + return out def cut(self, start=None, stop=None, whence=0): @@ -244,13 +244,13 @@ def cut(self, start=None, stop=None, whence=0): del timestamps # walk through all groups and get all channels - for i, gp in enumerate(self.groups): + for i, group in enumerate(self.groups): sigs = [] excluded_channels = self._excluded_channels(i) - data = self._load_group_data(gp) + data = self._load_group_data(group) - for j, _ in enumerate(gp['channels']): + for j, _ in enumerate(group['channels']): if j in excluded_channels: continue sig = self.get( @@ -336,9 +336,9 @@ def export(self, fmt, filename=None): else: if not name.endswith('.hdf'): name = os.path.splitext(name)[0] + '.hdf' - with HDF5(name, 'w') as f: + with HDF5(name, 'w') as hdf: # header information - group = f.create_group(os.path.basename(name)) + group = hdf.create_group(os.path.basename(name)) if self.version in MDF2_VERSIONS + MDF3_VERSIONS: for item in header_items: @@ -350,7 +350,7 @@ def export(self, fmt, filename=None): # that will hold the name of the master channel for i, grp in enumerate(self.groups): group_name = r'/' + 'DataGroup_{}'.format(i + 1) - group = f.create_group(group_name) + group = hdf.create_group(group_name) master_index = self.masters_db.get(i, -1) @@ -376,9 +376,9 @@ def export(self, fmt, filename=None): return else: excel_name = os.path.splitext(name)[0] - nr = len(self.groups) + count = len(self.groups) for i, grp in enumerate(self.groups): - print('Exporting group {} of {}'.format(i + 1, nr)) + print('Exporting group {} of {}'.format(i + 1, count)) data = self._load_group_data(grp) @@ -387,27 +387,24 @@ def export(self, fmt, filename=None): workbook = xlsxwriter.Workbook(wb_name) bold = workbook.add_format({'bold': True}) - ws = workbook.add_worksheet("Information") - if self.version in MDF2_VERSIONS + MDF3_VERSIONS: + sheet = workbook.add_worksheet(group_name) for j, item in enumerate(header_items): - ws.write(j, 0, item.title(), bold) - ws.write(j, 1, self.header[item].decode('latin-1')) - - ws = workbook.add_worksheet(group_name) + sheet.write(j, 0, item.title(), bold) + sheet.write(j, 1, self.header[item].decode('latin-1')) # the sheet header has 3 rows # the channel name and unit 'YY [xx]' # the channel comment # the flag for data grup master channel - ws.write(0, 0, 'Channel', bold) - ws.write(1, 0, 'comment', bold) - ws.write(2, 0, 'is master', bold) + sheet.write(0, 0, 'Channel', bold) + sheet.write(1, 0, 'comment', bold) + sheet.write(2, 0, 'is master', bold) master_index = self.masters_db.get(i, -1) for j in range(grp['channel_group']['cycles_nr']): - ws.write(j + 3, 0, str(j)) + sheet.write(j + 3, 0, str(j)) for j, _ in enumerate(grp['channels']): sig = self.get(group=i, index=j, data=data) @@ -418,19 +415,19 @@ def export(self, fmt, filename=None): sig.unit, ) comment = sig.comment if sig.comment else '' - ws.write(0, col, sig_description) - ws.write(1, col, comment) + sheet.write(0, col, sig_description) + sheet.write(1, col, comment) if j == master_index: - ws.write(2, col, 'x') - ws.write_column(3, col, sig.samples.astype(str)) + sheet.write(2, col, 'x') + sheet.write_column(3, col, sig.samples.astype(str)) workbook.close() elif fmt == 'csv': csv_name = os.path.splitext(name)[0] - nr = len(self.groups) + count = len(self.groups) for i, grp in enumerate(self.groups): - print('Exporting group {} of {}'.format(i + 1, nr)) + print('Exporting group {} of {}'.format(i + 1, count)) data = self._load_group_data(grp) group_name = 'DataGroup_{}'.format(i + 1) @@ -616,8 +613,8 @@ def filter(self, channels, memory=None): if all(not isinstance(dep, ChannelArrayBlock) for dep in dependencies): channels = grp['channels'] - for ch in dependencies: - excluded_channels.add(channels.index(ch)) + for channel in dependencies: + excluded_channels.add(channels.index(channel)) else: for dep in dependencies: for ch_nr, gp_nr in dep.referenced_channels: @@ -771,16 +768,16 @@ def merge(files, outversion='4.10', memory='full'): if j in excluded_channels: continue - sigs = [ + signals_to_merge = [ file.get(group=i, index=j, data=data) for file, data in zip(files, groups_data) ] - sig = sigs[0] - for s in sigs[1:]: - sig = sig.extend(s) + signal = signals_to_merge[0] + for merged_signal in signals_to_merge[1:]: + signal = signal.extend(merged_signal) - signals.append(sig) + signals.append(signal) if signals: merged.append(signals, common_timebase=True) @@ -810,8 +807,8 @@ def iter_channels(self, skip_master=True): def iter_groups(self): """ generator that yields channel groups as pandas DataFrames""" - for i, gp in enumerate(self.groups): - data = self._load_group_data(gp) + for i, group in enumerate(self.groups): + data = self._load_group_data(group) master_index = self.masters_db.get(i, None) if master_index is None: pandas_dict = {} @@ -822,7 +819,7 @@ def iter_groups(self): data=data, ) pandas_dict = {master.name: master.samples} - for j, _ in enumerate(gp['channels']): + for j, _ in enumerate(group['channels']): if j == master_index: continue sig = self.get( @@ -859,13 +856,13 @@ def resample(self, raster, memory=None): ) # walk through all groups and get all channels - for i, gp in enumerate(self.groups): + for i, group in enumerate(self.groups): sigs = [] excluded_channels = self._excluded_channels(i) - data = self._load_group_data(gp) + data = self._load_group_data(group) - for j, _ in enumerate(gp['channels']): + for j, _ in enumerate(group['channels']): if j in excluded_channels: continue sig = self.get( diff --git a/asammdf/mdf_v3.py b/asammdf/mdf_v3.py index f878b415d..db3d99011 100644 --- a/asammdf/mdf_v3.py +++ b/asammdf/mdf_v3.py @@ -9,10 +9,10 @@ import warnings from collections import defaultdict from copy import deepcopy -from functools import partial, reduce +from functools import reduce from itertools import product from tempfile import TemporaryFile -from struct import unpack, unpack_from +from struct import unpack from numexpr import evaluate from numpy import ( @@ -45,12 +45,11 @@ from .utils import ( MdfException, fix_dtype_fields, - fmt_to_datatype, - get_fmt, + fmt_to_datatype_v3, + get_fmt_v3, get_min_max, get_unique_name, get_text_v3, - pair, ) from .v2_v3_blocks import ( Channel, @@ -67,12 +66,11 @@ ) from .version import __version__ -get_fmt = partial(get_fmt, version=3) -fmt_to_datatype = partial(fmt_to_datatype, version=3) - PYVERSION = sys.version_info[0] if PYVERSION == 2: + # pylint: disable=W0622 from .utils import bytes + # pylint: enable=W0622 __all__ = ['MDF3', ] @@ -140,6 +138,9 @@ def __init__(self, name=None, memory='full', version='3.30'): self._tempfile.write(b'\0') self._file = None + self.attachments = None + self.file_comment = None + if name: self._file = open(self.name, 'rb') self._read() @@ -307,7 +308,7 @@ def _prepare_record(self, group): next_byte_aligned_position = parent_start_offset + size size = size // 8 if next_byte_aligned_position <= record_size: - dtype_pair = (name, get_fmt(data_type, size)) + dtype_pair = (name, get_fmt_v3(data_type, size)) types.append(dtype_pair) parents[original_index] = name, bit_offset @@ -334,7 +335,7 @@ def _prepare_record(self, group): size = 1 if next_byte_aligned_position <= record_size: - dtype_pair = (name, get_fmt(data_type, size)) + dtype_pair = (name, get_fmt_v3(data_type, size)) types.append(dtype_pair) parents[original_index] = name, bit_offset @@ -445,7 +446,7 @@ def _get_not_byte_aligned_data(self, data, group, ch_nr): vals = fromarrays([vals, extra], dtype=dtype(types)) vals = vals.tostring() - fmt = get_fmt(channel['data_type'], size) + fmt = get_fmt_v3(channel['data_type'], size) if size <= byte_count: types = [ ('vals', fmt), @@ -580,14 +581,17 @@ def _read(self): dg_addr = self.header['first_dg_addr'] # read each data group sequentially while dg_addr: - gp = DataGroup(address=dg_addr, stream=stream) - record_id_nr = gp['record_id_nr'] - cg_nr = gp['cg_nr'] - cg_addr = gp['first_cg_addr'] - data_addr = gp['data_block_addr'] + data_group = DataGroup( + address=dg_addr, + stream=stream, + ) + record_id_nr = data_group['record_id_nr'] + cg_nr = data_group['cg_nr'] + cg_addr = data_group['first_cg_addr'] + data_addr = data_group['data_block_addr'] # read trigger information if available - trigger_addr = gp['trigger_addr'] + trigger_addr = data_group['trigger_addr'] if trigger_addr: trigger = TriggerBlock( address=trigger_addr, @@ -819,7 +823,7 @@ def _read(self): if memory == 'full': # read data block of the current data group - dat_addr = gp['data_block_addr'] + dat_addr = data_group['data_block_addr'] if dat_addr: seek(dat_addr, v23c.SEEK_START) data = read(total_size) @@ -863,7 +867,7 @@ def _read(self): self.groups.extend(new_groups) # go to next data group - dg_addr = gp['next_dg_addr'] + dg_addr = data_group['next_dg_addr'] # finally update the channel depency references for grp in self.groups: @@ -899,18 +903,18 @@ def add_trigger(self, trigger comment """ - gp = self.groups[group] - trigger, trigger_text = gp['trigger'] + group = self.groups[group] + trigger, trigger_text = group['trigger'] if trigger: - nr = trigger['trigger_event_nr'] + count = trigger['trigger_event_nr'] trigger['trigger_event_nr'] += 1 trigger['block_len'] += 24 - trigger['trigger_{}_time'.format(nr)] = timestamp - trigger['trigger_{}_pretime'.format(nr)] = pre_time - trigger['trigger_{}_posttime'.format(nr)] = post_time + trigger['trigger_{}_time'.format(count)] = timestamp + trigger['trigger_{}_pretime'.format(count)] = pre_time + trigger['trigger_{}_posttime'.format(count)] = post_time if trigger_text is None and comment: trigger_text = TextBlock(text=comment) - gp['trigger'][1] = trigger_text + group['trigger'][1] = trigger_text else: trigger = TriggerBlock( trigger_event_nr=1, @@ -923,7 +927,7 @@ def add_trigger(self, else: trigger_text = None - gp['trigger'] = [trigger, trigger_text] + group['trigger'] = [trigger, trigger_text] def append(self, signals, @@ -974,10 +978,10 @@ def append(self, # check if the signals have a common timebase # if not interpolate the signals using the union of all timbases - t_ = signals[0].timestamps + timestamps = signals[0].timestamps if not common_timebase: - for s in signals[1:]: - if not array_equal(s.timestamps, t_): + for signal in signals[1:]: + if not array_equal(signal.timestamps, timestamps): different = True break else: @@ -985,17 +989,13 @@ def append(self, if different: times = [s.timestamps for s in signals] - t = reduce(union1d, times).flatten().astype(float64) - signals = [s.interp(t) for s in signals] + timestamps = reduce(union1d, times).flatten().astype(float64) + signals = [s.interp(timestamps) for s in signals] times = None - else: - t = t_ - else: - t = t_ if self.version < '3.00': - if t.dtype.byteorder == '>': - t = t.byteswap().newbyteorder() + if timestamps.dtype.byteorder == '>': + timestamps = timestamps.byteswap().newbyteorder() for signal in signals: if signal.samples.dtype.byteorder == '>': signal.samples = signal.samples.byteswap().newbyteorder() @@ -1075,7 +1075,7 @@ def append(self, } self.groups.append(gp) - cycles_nr = len(t) + cycles_nr = len(timestamps) fields = [] types = [] parents = {} @@ -1097,8 +1097,8 @@ def append(self, kargs = { 'conversion_type': v23c.CONVERSION_TYPE_NONE, 'unit': b's', - 'min_phy_value': t[0] if cycles_nr else 0, - 'max_phy_value': t[-1] if cycles_nr else 0, + 'min_phy_value': timestamps[0] if cycles_nr else 0, + 'max_phy_value': timestamps[-1] if cycles_nr else 0, } block = ChannelConversion(**kargs) if memory != 'minimum': @@ -1115,14 +1115,14 @@ def append(self, gp_source.append(ce_address) # time channel - t_type, t_size = fmt_to_datatype(t.dtype) + t_type, t_size = fmt_to_datatype_v3(timestamps.dtype) kargs = { 'short_name': b't', 'channel_type': v23c.CHANNEL_TYPE_MASTER, 'data_type': t_type, 'start_offset': 0, - 'min_raw_value': t[0] if cycles_nr else 0, - 'max_raw_value': t[-1] if cycles_nr else 0, + 'min_raw_value': timestamps[0] if cycles_nr else 0, + 'max_raw_value': timestamps[-1] if cycles_nr else 0, 'bit_count': t_size, 'block_len': channel_size, } @@ -1145,8 +1145,8 @@ def append(self, # time channel doesn't have channel dependencies gp_dep.append(None) - fields.append(t) - types.append((name, t.dtype)) + fields.append(timestamps) + types.append((name, timestamps.dtype)) field_names.add(name) offset += t_size @@ -1458,7 +1458,7 @@ def append(self, else: start_bit_offset = offset additional_byte_offset = 0 - s_type, s_size = fmt_to_datatype(signal.samples.dtype) + s_type, s_size = fmt_to_datatype_v3(signal.samples.dtype) if memory == 'minimum' and len(name) >= 32 and self.version >= '2.10': block = TextBlock(text=name) @@ -1581,7 +1581,7 @@ def append(self, min_val, max_val = get_min_max(samples) - s_type, s_size = fmt_to_datatype(samples.dtype) + s_type, s_size = fmt_to_datatype_v3(samples.dtype) # compute additional byte offset for large records size if offset > v23c.MAX_UINT16: additional_byte_offset = (offset - v23c.MAX_UINT16) >> 3 @@ -1666,7 +1666,7 @@ def append(self, short_name = (name[:31] + '\0').encode('latin-1') min_val, max_val = get_min_max(samples) - s_type, s_size = fmt_to_datatype(samples.dtype) + s_type, s_size = fmt_to_datatype_v3(samples.dtype) shape = samples.shape[1:] # source for channel @@ -1790,7 +1790,7 @@ def append(self, } self.groups.append(gp) - cycles_nr = len(t) + cycles_nr = len(timestamps) fields = [] types = [] parents = {} @@ -1805,8 +1805,8 @@ def append(self, kargs = { 'conversion_type': v23c.CONVERSION_TYPE_NONE, 'unit': b's', - 'min_phy_value': t[0] if cycles_nr else 0, - 'max_phy_value': t[-1] if cycles_nr else 0, + 'min_phy_value': timestamps[0] if cycles_nr else 0, + 'max_phy_value': timestamps[-1] if cycles_nr else 0, } block = ChannelConversion(**kargs) if memory != 'minimum': @@ -1823,14 +1823,14 @@ def append(self, gp_source.append(ce_address) # time channel - t_type, t_size = fmt_to_datatype(t.dtype) + t_type, t_size = fmt_to_datatype_v3(timestamps.dtype) kargs = { 'short_name': b't', 'channel_type': v23c.CHANNEL_TYPE_MASTER, 'data_type': t_type, 'start_offset': 0, - 'min_raw_value': t[0] if cycles_nr else 0, - 'max_raw_value': t[-1] if cycles_nr else 0, + 'min_raw_value': timestamps[0] if cycles_nr else 0, + 'max_raw_value': timestamps[-1] if cycles_nr else 0, 'bit_count': t_size, 'block_len': channel_size, } @@ -1853,8 +1853,8 @@ def append(self, # time channel doesn't have channel dependencies gp_dep.append(None) - fields.append(t) - types.append((name, t.dtype)) + fields.append(timestamps) + types.append((name, timestamps.dtype)) field_names.add(name) offset += t_size @@ -1942,7 +1942,7 @@ def append(self, else: start_bit_offset = offset additional_byte_offset = 0 - s_type, s_size = fmt_to_datatype(samples.dtype) + s_type, s_size = fmt_to_datatype_v3(samples.dtype) kargs = { 'short_name': short_name, @@ -2595,6 +2595,7 @@ def get(self, elif conversion_type in ( v23c.CONVERSION_TYPE_EXPO, v23c.CONVERSION_TYPE_LOGH): + # pylint: disable=C0103 if conversion_type == v23c.CONVERSION_TYPE_EXPO: func = log else: @@ -2615,6 +2616,7 @@ def get(self, raise ValueError(message) elif conversion_type == v23c.CONVERSION_TYPE_RAT: + # pylint: disable=unused-variable,C0103 P1 = conversion['P1'] P2 = conversion['P2'] P3 = conversion['P3'] @@ -2626,6 +2628,7 @@ def get(self, vals = evaluate(v23c.RAT_CONV_TEXT) elif conversion_type == v23c.CONVERSION_TYPE_POLY: + # pylint: disable=unused-variable,C0103 P1 = conversion['P1'] P2 = conversion['P2'] P3 = conversion['P3'] @@ -2643,6 +2646,7 @@ def get(self, vals = evaluate(v23c.POLY_CONV_LONG_TEXT) elif conversion_type == v23c.CONVERSION_TYPE_FORMULA: + # pylint: disable=unused-variable,C0103 formula = conversion['formula'].decode('latin-1') formula = formula.strip(' \n\t\0') X1 = vals @@ -2672,20 +2676,24 @@ def get(self, else: comment = description - t = self.get_master(gp_nr, data) + timestamps = self.get_master(gp_nr, data) res = Signal( samples=vals, - timestamps=t, + timestamps=timestamps, unit=unit, name=channel.name, comment=comment, info=info, ) - if raster and t: - tx = linspace(0, t[-1], int(t[-1] / raster)) - res = res.interp(tx) + if raster and timestamps: + new_timestamps = linspace( + 0, + timestamps[-1], + int(timestamps[-1] / raster), + ) + res = res.interp(new_timestamps) return res @@ -2948,6 +2956,7 @@ def _save_with_metadata(self, dst, overwrite, compression): API as mdf version 4 files """ + # pylint: disable=unused-argument if self.file_history is None: self.file_history = TextBlock(text=''' @@ -3041,6 +3050,12 @@ def _save_with_metadata(self, dst, overwrite, compression): # disk this way, in case of memory=False, we can safely # restore he original data block address gp_rec_ids = [] + + original_data_block_addrs = [ + group['data_group']['data_block_addr'] + for group in self.groups + ] + for gp in self.groups: dg = gp['data_group'] gp_rec_ids.append(dg['record_id_nr']) @@ -3177,9 +3192,11 @@ def _save_with_metadata(self, dst, overwrite, compression): else: channel['ch_depend_addr'] = 0 - for channel, next_channel in pair(gp['channels']): - channel['next_ch_addr'] = next_channel.address - next_channel['next_ch_addr'] = 0 + count = len(gp['channels']) + if count: + for i in range(count-1): + gp['channels'][i]['next_ch_addr'] = gp['channels'][i+1].address + gp['channels'][-1]['next_ch_addr'] = 0 # ChannelGroup cg = gp['channel_group'] @@ -3210,21 +3227,16 @@ def _save_with_metadata(self, dst, overwrite, compression): address += trigger['block_len'] # DataBlock - original_data_addr = gp['data_group']['data_block_addr'] + if self.memory == 'full': + blocks.append(gp['data_block']) + else: + blocks.append(self._load_group_data(gp)) + if gp['size']: gp['data_group']['data_block_addr'] = address else: gp['data_group']['data_block_addr'] = 0 address += gp['size'] - gp_rec_ids[idx] * gp['channel_group']['cycles_nr'] - if self.memory == 'full': - blocks.append(gp['data_block']) - else: - # trying to call bytes([gp, address]) will result in an - # exceptionthat be used as a flag for non existing data - # block in caseof memory=False, the address is - # the actual addressof the data group's data within the - # original file - blocks.append([gp, original_data_addr]) # update referenced channels addresses in the channel dependecies for gp in self.groups: @@ -3256,20 +3268,14 @@ def _save_with_metadata(self, dst, overwrite, compression): self.header['program_addr'] = 0 for block in blocks: - try: - write(bytes(block)) - except: - # this will only be executed for data blocks when - # memory=False - gp, address = block - # restore data block address from original file so that - # future calls to get will still work after the save - gp['data_group']['data_block_addr'] = address - data = self._load_group_data(gp) - write(data) + write(bytes(block)) - for gp, rec_id in zip(self.groups, gp_rec_ids): + for gp, rec_id, original_address in zip( + self.groups, + gp_rec_ids, + original_data_block_addrs): gp['data_group']['record_id_nr'] = rec_id + gp['data_group']['data_block_addr'] = original_address if self.memory == 'low' and dst == self.name: self.close() @@ -3285,7 +3291,6 @@ def _save_with_metadata(self, dst, overwrite, compression): self.attachments = [] self.file_comment = None - self._ch_map = {} self._master_channel_cache = {} self._tempfile = TemporaryFile() @@ -3311,6 +3316,7 @@ def _save_without_metadata(self, dst, overwrite, compression): API as mdf version 4 files """ + # pylint: disable=unused-argument if self.file_history is None: self.file_history = TextBlock(text=''' @@ -3681,7 +3687,6 @@ def _save_without_metadata(self, dst, overwrite, compression): self.attachments = [] self.file_comment = None - self._ch_map = {} self._master_channel_cache = {} self._tempfile = TemporaryFile() diff --git a/asammdf/mdf_v4.py b/asammdf/mdf_v4.py index 6f9770a8a..b823324f1 100644 --- a/asammdf/mdf_v4.py +++ b/asammdf/mdf_v4.py @@ -49,8 +49,8 @@ from .utils import ( MdfException, fix_dtype_fields, - fmt_to_datatype, - get_fmt, + fmt_to_datatype_v4, + get_fmt_v4, get_min_max, get_unique_name, get_text_v4, @@ -75,8 +75,6 @@ ) from .version import __version__ -get_fmt = partial(get_fmt, version=4) -fmt_to_datatype = partial(fmt_to_datatype, version=4) MASTER_CHANNELS = ( v4c.CHANNEL_TYPE_MASTER, @@ -87,7 +85,9 @@ PYVERSION = sys.version_info[0] if PYVERSION == 2: + # pylint: disable=W0622 from .utils import bytes + # pylint: enable=W0622 __all__ = ['MDF4', ] @@ -234,10 +234,13 @@ def _read(self): # read file history fh_addr = self.header['file_history_addr'] while fh_addr: - fh = FileHistory(address=fh_addr, stream=stream) - fh_text = TextBlock(address=fh['comment_addr'], stream=stream) - self.file_history.append((fh, fh_text)) - fh_addr = fh['next_fh_addr'] + history_block = FileHistory(address=fh_addr, stream=stream) + history_text = TextBlock( + address=history_block['comment_addr'], + stream=stream, + ) + self.file_history.append((history_block, history_text)) + fh_addr = history_block['next_fh_addr'] # read attachments at_addr = self.header['first_attachment_addr'] @@ -523,7 +526,7 @@ def _read_channels( conv_tabx_texts['text_{}'.format(i)] = block else: conv_tabx_texts['text_{}'.format(i)] = None - if not conv_type == v4c.CONVERSION_TYPE_TTAB: + if conv_type != v4c.CONVERSION_TYPE_TTAB: address = conv.get('default_addr', 0) if address: if memory == 'minimum': @@ -585,7 +588,6 @@ def _read_channels( address = channel['source_addr'] if address: if memory == 'minimum': -# self._si_map[address] = address grp['channel_sources'].append(address) else: stream.seek(address, v4c.SEEK_START) @@ -976,7 +978,7 @@ def _prepare_record(self, group): next_byte_aligned_position = parent_start_offset + size if next_byte_aligned_position <= record_size: - dtype_pair = name, get_fmt(data_type, size) + dtype_pair = name, get_fmt_v4(data_type, size) types.append(dtype_pair) parents[original_index] = name, bit_offset @@ -1004,7 +1006,7 @@ def _prepare_record(self, group): for d in shape: dim *= d - dtype_pair = name, get_fmt(data_type, size), shape + dtype_pair = name, get_fmt_v4(data_type, size), shape types.append(dtype_pair) current_parent = name @@ -1138,7 +1140,7 @@ def _get_not_byte_aligned_data(self, data, group, ch_nr): vals = fromarrays([vals, extra], dtype=dtype(types)) vals = vals.tostring() - fmt = get_fmt(channel['data_type'], size) + fmt = get_fmt_v4(channel['data_type'], size) if size <= byte_count: types = [ ('vals', fmt), @@ -1343,7 +1345,7 @@ def append(self, signals, source_info='Python', common_timebase=False): # time channel texts for key in ('conversion_tab',): - gp['texts'][key].append(None) + gp_texts[key].append(None) memory = self.memory file = self._tempfile @@ -1392,7 +1394,7 @@ def append(self, signals, source_info='Python', common_timebase=False): unit_addr = 0 # time channel - t_type, t_size = fmt_to_datatype(t.dtype) + t_type, t_size = fmt_to_datatype_v4(t.dtype) kargs = { 'channel_type': v4c.CHANNEL_TYPE_MASTER, 'data_type': t_type, @@ -1509,7 +1511,7 @@ def append(self, signals, source_info='Python', common_timebase=False): max_val = signal_d['max'] name = signal.name - gp['texts']['conversion_tab'].append(None) + gp_texts['conversion_tab'].append(None) if memory == 'minimum': block = TextBlock(text=name, meta=False) @@ -1642,7 +1644,7 @@ def append(self, signals, source_info='Python', common_timebase=False): gp_conv.append(0) if conv_texts_tab: - gp['texts']['conversion_tab'][-1] = conv_texts_tab + gp_texts['conversion_tab'][-1] = conv_texts_tab # source for channel if memory != 'minimum': @@ -1715,7 +1717,7 @@ def append(self, signals, source_info='Python', common_timebase=False): # first add the signals in the simple signal list for signal in simple_signals: name = signal.name - gp['texts']['conversion_tab'].append(None) + gp_texts['conversion_tab'].append(None) if memory == 'minimum': block = TextBlock(text=name, meta=False) @@ -1852,7 +1854,7 @@ def append(self, signals, source_info='Python', common_timebase=False): gp_conv.append(0) if conv_texts_tab: - gp['texts']['conversion_tab'][-1] = conv_texts_tab + gp_texts['conversion_tab'][-1] = conv_texts_tab # source for channel if memory != 'minimum': @@ -1870,7 +1872,7 @@ def append(self, signals, source_info='Python', common_timebase=False): comment_addr = 0 # compute additional byte offset for large records size - s_type, s_size = fmt_to_datatype(signal.samples.dtype) + s_type, s_size = fmt_to_datatype_v4(signal.samples.dtype) byte_size = max(s_size // 8, 1) min_val, max_val = get_min_max(signal.samples) kargs = { @@ -1968,7 +1970,7 @@ def append(self, signals, source_info='Python', common_timebase=False): s_size = byte_size << 3 # add channel texts - gp['texts']['conversion_tab'].append(None) + gp_texts['conversion_tab'].append(None) if memory == 'minimum': block = TextBlock(text=name, meta=False) @@ -2060,7 +2062,7 @@ def append(self, signals, source_info='Python', common_timebase=False): # first we add the structure channel # add channel texts - gp['texts']['conversion_tab'].append(None) + gp_texts['conversion_tab'].append(None) if memory == 'minimum': block = TextBlock(text=name, meta=False) @@ -2148,14 +2150,14 @@ def append(self, signals, source_info='Python', common_timebase=False): samples = signal.samples[name] - s_type, s_size = fmt_to_datatype(samples.dtype) + s_type, s_size = fmt_to_datatype_v4(samples.dtype) byte_size = s_size >> 3 fields.append(samples) types.append((field_name, samples.dtype)) # add channel texts - gp['texts']['conversion_tab'].append(None) + gp_texts['conversion_tab'].append(None) if memory == 'minimum': block = TextBlock(text=name, meta=False) @@ -2306,7 +2308,7 @@ def append(self, signals, source_info='Python', common_timebase=False): # first we add the structure channel # add channel texts - gp['texts']['conversion_tab'].append(None) + gp_texts['conversion_tab'].append(None) if memory == 'minimum': block = TextBlock(text=name, meta=False) @@ -2348,7 +2350,7 @@ def append(self, signals, source_info='Python', common_timebase=False): unit_addr = 0 comment_addr = 0 - s_type, s_size = fmt_to_datatype(samples.dtype) + s_type, s_size = fmt_to_datatype_v4(samples.dtype) # add channel block kargs = { @@ -2400,7 +2402,7 @@ def append(self, signals, source_info='Python', common_timebase=False): fields.append(samples) types.append((field_name, samples.dtype, shape)) - gp['texts']['conversion_tab'].append(None) + gp_texts['conversion_tab'].append(None) if memory == 'minimum': block = TextBlock(text=name, meta=False) @@ -2455,7 +2457,7 @@ def append(self, signals, source_info='Python', common_timebase=False): # add components channel min_val, max_val = get_min_max(samples) - s_type, s_size = fmt_to_datatype(samples.dtype) + s_type, s_size = fmt_to_datatype_v4(samples.dtype) byte_size = max(s_size // 8, 1) kargs = { 'channel_type': v4c.CHANNEL_TYPE_VALUE, @@ -2506,7 +2508,7 @@ def append(self, signals, source_info='Python', common_timebase=False): } gp['channel_group'] = ChannelGroup(**kargs) gp['size'] = cycles_nr * offset - gp['texts']['channel_group'].append(None) + gp_texts['channel_group'].append(None) # data group gp['data_group'] = DataGroup() @@ -2759,8 +2761,8 @@ def get_channel_unit(self, name=None, group=None, index=None): ) address = ( - conversion and conversion['unit_addr'] - or channel['unit_addr'] + conversion and conversion['unit_addr'] + or channel['unit_addr'] or 0 ) @@ -2777,8 +2779,8 @@ def get_channel_unit(self, name=None, group=None, index=None): unit = '' else: unit = ( - conversion and conversion.unit - or channel.unit + conversion and conversion.unit + or channel.unit or '' ) @@ -3061,7 +3063,8 @@ def get(self, arrays = [] name = channel.name - if all(not isinstance(dep, ChannelArrayBlock) + if all( + not isinstance(dep, ChannelArrayBlock) for dep in dependency_list): # structure channel composition if memory == 'minimum': @@ -3170,7 +3173,7 @@ def get(self, stream=stream, ) axisname = get_text_v4( - channel['name_addr'], + channel['name_addr'], stream, ) else: @@ -3224,7 +3227,7 @@ def get(self, stream=stream, ) axisname = get_text_v4( - channel['name_addr'], + channel['name_addr'], stream, ) else: @@ -3254,7 +3257,7 @@ def get(self, if channel['channel_type'] in (v4c.CHANNEL_TYPE_VIRTUAL, v4c.CHANNEL_TYPE_VIRTUAL_MASTER): data_type = channel['data_type'] - ch_dtype = dtype(get_fmt(data_type, 8)) + ch_dtype = dtype(get_fmt_v4(data_type, 8)) vals = arange(cycles_nr, dtype=ch_dtype) else: @@ -3551,7 +3554,7 @@ def get(self, else: res.append(default) size = max(bits >> 3, 1) - ch_fmt = get_fmt(channel['data_type'], size) + ch_fmt = get_fmt_v4(channel['data_type'], size) vals = array(res).astype(ch_fmt) # else FLOAT channel @@ -3565,7 +3568,7 @@ def get(self, else: res.append(default) size = max(bits >> 3, 1) - ch_fmt = get_fmt(channel['data_type'], size) + ch_fmt = get_fmt_v4(channel['data_type'], size) vals = array(res).astype(ch_fmt) elif conversion_type == v4c.CONVERSION_TYPE_TABX: @@ -4930,7 +4933,7 @@ def _save_without_metadata(self, dst, overwrite, compression): write(bytes(block)) for source in gp['channel_sources']: - if source: + if source: stream.seek(source, v4c.SEEK_START) raw_bytes = stream.read(v4c.SI_BLOCK_SIZE) if raw_bytes in si_map: @@ -4939,7 +4942,7 @@ def _save_without_metadata(self, dst, overwrite, compression): source = SourceInformation( raw_bytes=raw_bytes, ) - + if source['name_addr']: tx_block = TextBlock( address=source['name_addr'], @@ -5004,7 +5007,7 @@ def _save_without_metadata(self, dst, overwrite, compression): address=conversion, stream=stream, ) - + if conversion['name_addr']: tx_block = TextBlock( address=conversion['name_addr'], @@ -5110,7 +5113,7 @@ def _save_without_metadata(self, dst, overwrite, compression): blocks = [] chans = [] address = blocks_start_addr = tell() - + gp['channel_group']['first_ch_addr'] = address @@ -5307,7 +5310,8 @@ def _save_without_metadata(self, dst, overwrite, compression): for gp in self.groups: for dep_list in gp['channel_dependencies']: if dep_list: - if all(isinstance(dep, ChannelArrayBlock) + if all( + isinstance(dep, ChannelArrayBlock) for dep in dep_list): for dep in dep_list: for i, (ch_nr, gp_nr) in enumerate(dep.referenced_channels): diff --git a/asammdf/utils.py b/asammdf/utils.py index 51141c3fd..767e9b2ec 100644 --- a/asammdf/utils.py +++ b/asammdf/utils.py @@ -3,7 +3,6 @@ asammdf utility functions and classes ''' -import itertools from struct import unpack from numpy import ( @@ -16,13 +15,14 @@ __all__ = [ 'MdfException', - 'get_fmt', + 'get_fmt_v3', + 'get_fmt_v4', 'get_min_max', 'get_unique_name', 'get_text_v4', 'fix_dtype_fields', - 'fmt_to_datatype', - 'pair', + 'fmt_to_datatype_v3', + 'fmt_to_datatype_v4', 'bytes', ] @@ -31,7 +31,7 @@ class MdfException(Exception): """MDF Exception class""" pass - +# pylint: disable=W0622 def bytes(obj): """ Python 2 compatibility function """ try: @@ -41,8 +41,25 @@ def bytes(obj): return obj else: raise +# pylint: enable=W0622 def get_text_v3(address, stream): + """ faster way extract string from mdf versions 2 and 3 TextBlock + + Parameters + ---------- + address : int + TextBlock address + stream : handle + file IO handle + + Returns + ------- + text : str + unicode string + + """ + stream.seek(address + 2) size = unpack(' (s0,s1), (s1,s2), (s2, s3), ...""" - current, next_ = itertools.tee(iterable) - next(next_, None) - return zip(current, next_) +def fmt_to_datatype_v4(fmt): + """convert numpy dtype format string to mdf version 4 channel data + type and size + + Parameters + ---------- + fmt : numpy.dtype + numpy data type + + Returns + ------- + data_type, size : int, int + integer data type as defined by ASAM MDF and bit size + + """ + size = fmt.itemsize * 8 + + if fmt.kind == 'u': + if fmt.byteorder in '=<': + data_type = v4c.DATA_TYPE_UNSIGNED_INTEL + else: + data_type = v4c.DATA_TYPE_UNSIGNED_MOTOROLA + elif fmt.kind == 'i': + if fmt.byteorder in '=<': + data_type = v4c.DATA_TYPE_SIGNED_INTEL + else: + data_type = v4c.DATA_TYPE_SIGNED_MOTOROLA + elif fmt.kind == 'f': + if fmt.byteorder in '=<': + data_type = v4c.DATA_TYPE_REAL_INTEL + else: + data_type = v4c.DATA_TYPE_REAL_MOTOROLA + elif fmt.kind in 'SV': + data_type = v4c.DATA_TYPE_STRING_LATIN_1 + else: + # here we have arrays + data_type = v4c.DATA_TYPE_BYTEARRAY + + return data_type, size def get_unique_name(used_names, name): diff --git a/benchmarks/bench.py b/benchmarks/bench.py index a4cae975e..b68440c75 100644 --- a/benchmarks/bench.py +++ b/benchmarks/bench.py @@ -307,13 +307,17 @@ def save_reader3_nodata(output, fmt): def save_reader3_compression(output, fmt): - - x = MDFreader(r'test.mdf', compression='blosc') with Timer('Save file', 'mdfreader {} compress mdfv3'.format(mdfreader_version), - fmt) as timer: - x.write(r'x.mdf') - output.send([timer.output, timer.error]) + fmt) as outer_timer: + x = MDFreader(r'test.mdf', compression='blosc') + with Timer('Save file', + 'mdfreader {} compress mdfv3'.format(mdfreader_version), + fmt) as timer: + x.write(r'x.mdf') + output.send([timer.output, timer.error]) + if outer_timer.error: + output.send([timer.output, timer.error]) def save_reader4(output, fmt): diff --git a/test/test_mdf23.py b/test/test_mdf23.py index f9bc969c3..84b783c0d 100644 --- a/test/test_mdf23.py +++ b/test/test_mdf23.py @@ -43,6 +43,7 @@ def test_read_mdf2_00(self): ) for memory in MEMORY: + print(memory) with MDF(version='2.00', memory=memory) as mdf: mdf.append([sig_int, sig_float], common_timebase=True) @@ -79,6 +80,7 @@ def test_read_mdf2_14(self): ) for memory in MEMORY: + print(memory) with MDF(version='2.14', memory=memory) as mdf: mdf.append([sig_int, sig_float], common_timebase=True) outfile = mdf.save('tmp', overwrite=True) @@ -114,6 +116,7 @@ def test_read_mdf3_00(self): ) for memory in MEMORY: + print(memory) with MDF(version='3.00', memory=memory) as mdf: mdf.append([sig_int, sig_float], common_timebase=True) @@ -154,6 +157,8 @@ def test_read_mdf3_10(self): mdf.append([sig_int, sig_float], common_timebase=True) outfile = mdf.save('tmp', overwrite=True) + print(memory) + with MDF(outfile, memory=memory) as mdf: ret_sig_int = mdf.get(sig_int.name) ret_sig_float = mdf.get(sig_float.name) From 6478992d25e2d46bdc94b0752b66d9a6c87d2b38 Mon Sep 17 00:00:00 2001 From: danielhrisca Date: Mon, 22 Jan 2018 13:05:48 +0200 Subject: [PATCH 109/117] try to use chardet if installed in case of incorrect string encoding --- asammdf/mdf_v4.py | 91 ++++++++++++++++++++++++++++++++++------------- asammdf/utils.py | 34 ++++++++++++++---- 2 files changed, 95 insertions(+), 30 deletions(-) diff --git a/asammdf/mdf_v4.py b/asammdf/mdf_v4.py index b823324f1..820043ecd 100644 --- a/asammdf/mdf_v4.py +++ b/asammdf/mdf_v4.py @@ -359,7 +359,22 @@ def _read(self): if memory == 'full': grp['data_location'] = v4c.LOCATION_MEMORY dat_addr = group['data_block_addr'] - data = self._read_data_block(address=dat_addr, stream=stream) + + if record_id_nr == 0: + size = channel_group['samples_byte_nr'] + size *= channel_group['cycles_nr'] + else: + size = sum( + (gp['channel_group']['samples_byte_nr'] + record_id_nr) + * gp['channel_group']['cycles_nr'] + for gp in new_groups + ) + + data = self._read_data_block( + address=dat_addr, + stream=stream, + size=size, + ) if record_id_nr == 0: grp = new_groups[0] @@ -690,7 +705,7 @@ def _read_channels( return ch_cntr, composition - def _read_data_block(self, address, stream): + def _read_data_block(self, address, stream, size=-1): """read and aggregate data blocks for a given data group Returns @@ -698,6 +713,7 @@ def _read_data_block(self, address, stream): data : bytes aggregated raw data """ + orig = address if address: stream.seek(address, v4c.SEEK_START) id_string = stream.read(4) @@ -711,31 +727,50 @@ def _read_data_block(self, address, stream): data = data['data'] # or a DataList elif id_string == b'##DL': - data = [] - while address: - dl = DataList(address=address, stream=stream) - for i in range(dl['links_nr'] - 1): - addr = dl['data_block_addr{}'.format(i)] - stream.seek(addr, v4c.SEEK_START) - id_string = stream.read(4) - if id_string == b'##DT': - block = DataBlock(stream=stream, address=addr) - data.append(block['data']) - elif id_string == b'##DZ': - block = DataZippedBlock( - stream=stream, - address=addr, - ) - data.append(block['data']) - elif id_string == b'##DL': - data.append( - self._read_data_block( + if size >= 0: + data = bytearray(size) + view = memoryview(data) + position = 0 + while address: + dl = DataList(address=address, stream=stream) + for i in range(dl['links_nr'] - 1): + addr = dl['data_block_addr{}'.format(i)] + stream.seek(addr, v4c.SEEK_START) + id_string = stream.read(4) + if id_string == b'##DT': + _, dim, __ = unpack('<4s2Q', stream.read(20)) + dim -= 24 + position += stream.readinto(view[position: position+dim]) + elif id_string == b'##DZ': + block = DataZippedBlock( + stream=stream, address=addr, + ) + uncompressed_size = block['original_size'] + view[position: position+uncompressed_size] = block['data'] + position += uncompressed_size + address = dl['next_dl_addr'] + + else: + + data = [] + while address: + dl = DataList(address=address, stream=stream) + for i in range(dl['links_nr'] - 1): + addr = dl['data_block_addr{}'.format(i)] + stream.seek(addr, v4c.SEEK_START) + id_string = stream.read(4) + if id_string == b'##DT': + block = DataBlock(stream=stream, address=addr) + data.append(block['data']) + elif id_string == b'##DZ': + block = DataZippedBlock( stream=stream, + address=addr, ) - ) - address = dl['next_dl_addr'] - data = b''.join(data) + data.append(block['data']) + address = dl['next_dl_addr'] + data = b''.join(data) # or a header list elif id_string == b'##HL': hl = HeaderList(address=address, stream=stream) @@ -1091,6 +1126,8 @@ def _get_not_byte_aligned_data(self, data, group, ch_nr): vals = fromstring(data, dtype=dtype(types)) + vals.setflags(write=False) + vals = vals['vals'] if channel['data_type'] not in big_endian_types: @@ -3119,6 +3156,8 @@ def get(self, else: record = grp['record'] + record.setflags(write=False) + vals = record[parent] else: vals = self._get_not_byte_aligned_data(data, grp, ch_nr) @@ -3278,6 +3317,8 @@ def get(self, else: record = grp['record'] + record.setflags(write=False) + vals = record[parent] bits = channel['bit_count'] size = vals.dtype.itemsize @@ -3912,6 +3953,8 @@ def get_master(self, index, data=None): if memory == 'full': group['record'] = record + + record.setflags(write=False) t = record[parent] else: t = self._get_not_byte_aligned_data( diff --git a/asammdf/utils.py b/asammdf/utils.py index 767e9b2ec..9c2ed2b20 100644 --- a/asammdf/utils.py +++ b/asammdf/utils.py @@ -3,6 +3,8 @@ asammdf utility functions and classes ''' +import warnings + from struct import unpack from numpy import ( @@ -43,6 +45,7 @@ def bytes(obj): raise # pylint: enable=W0622 + def get_text_v3(address, stream): """ faster way extract string from mdf versions 2 and 3 TextBlock @@ -70,6 +73,7 @@ def get_text_v3(address, stream): ) return text + def get_text_v4(address, stream): """ faster way extract string from mdf version 4 TextBlock @@ -86,15 +90,33 @@ def get_text_v4(address, stream): unicode string """ + stream.seek(address + 8) size = unpack(' Date: Mon, 22 Jan 2018 13:29:58 +0200 Subject: [PATCH 110/117] fix python 2.7 error --- asammdf/v4_blocks.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/asammdf/v4_blocks.py b/asammdf/v4_blocks.py index b6f0663bb..3b556d978 100644 --- a/asammdf/v4_blocks.py +++ b/asammdf/v4_blocks.py @@ -1278,6 +1278,9 @@ def __init__(self, **kargs): self['links_nr'] = 0 self['data'] = kargs['data'] + if PYVERSION_MAJOR < 30 and isinstance(self['data'], bytearray): + self['data'] = str(self['data']) + def __bytes__(self): fmt = v4c.FMT_DATA_BLOCK.format(self['block_len'] - v4c.COMMON_SIZE) if PYVERSION_MAJOR >= 36: From 1a70713ed64120f67731912eef3034e12b9c8f34 Mon Sep 17 00:00:00 2001 From: danielhrisca Date: Tue, 23 Jan 2018 09:37:13 +0200 Subject: [PATCH 111/117] fix error in case of invalidation bytes --- asammdf/mdf_v4.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/asammdf/mdf_v4.py b/asammdf/mdf_v4.py index 820043ecd..e53937d22 100644 --- a/asammdf/mdf_v4.py +++ b/asammdf/mdf_v4.py @@ -3795,7 +3795,7 @@ def get(self, if channel['flags'] & ( v4c.FLAG_INVALIDATION_BIT_VALID | v4c.FLAG_ALL_SAMPLES_VALID) == v4c.FLAG_INVALIDATION_BIT_VALID: ch_invalidation_pos = channel['pos_invalidation_bit'] - pos_byte, pos_offset = divmod(ch_invalidation_pos) + pos_byte, pos_offset = divmod(ch_invalidation_pos, 8) mask = 1 << pos_offset inval_bytes = record['invalidation_bytes'] From ba744170c115c322f923b16ceb61c51de56dfa22 Mon Sep 17 00:00:00 2001 From: danielhrisca Date: Tue, 23 Jan 2018 10:14:55 +0200 Subject: [PATCH 112/117] fix error in case of invalidation bytes for python 2.7 --- asammdf/mdf_v4.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/asammdf/mdf_v4.py b/asammdf/mdf_v4.py index e53937d22..97a3f1d75 100644 --- a/asammdf/mdf_v4.py +++ b/asammdf/mdf_v4.py @@ -1067,7 +1067,7 @@ def _prepare_record(self, group): dtype_pair = '', 'a{}'.format(gap) types.append(dtype_pair) - dtype_pair = 'invalidation_bytes', 'a{}'.format(invalidation_bytes_nr) + dtype_pair = 'invalidation_bytes', 'u1', invalidation_bytes_nr types.append(dtype_pair) if PYVERSION == 2: types = fix_dtype_fields(types) From 7c36b1cec22bdbe6085b1d37dc90e33e88dcfaeb Mon Sep 17 00:00:00 2001 From: danielhrisca Date: Thu, 25 Jan 2018 22:03:00 +0200 Subject: [PATCH 113/117] fix error when record has invalidation bits and the accessed channel is a virtual channel --- asammdf/mdf_v4.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/asammdf/mdf_v4.py b/asammdf/mdf_v4.py index 97a3f1d75..feabcec0f 100644 --- a/asammdf/mdf_v4.py +++ b/asammdf/mdf_v4.py @@ -3299,6 +3299,7 @@ def get(self, ch_dtype = dtype(get_fmt_v4(data_type, 8)) vals = arange(cycles_nr, dtype=ch_dtype) + record = None else: try: parent, bit_offset = parents[ch_nr] @@ -3798,6 +3799,10 @@ def get(self, pos_byte, pos_offset = divmod(ch_invalidation_pos, 8) mask = 1 << pos_offset + if record is None: + record = fromstring(data, dtype=dtypes) + record.setflags(write=False) + inval_bytes = record['invalidation_bytes'] inval_index = array( [bytes_[pos_byte] & mask for bytes_ in inval_bytes] From 9dd34cc095643db511e63b2728e8ff5b3bdc5bc0 Mon Sep 17 00:00:00 2001 From: danielhrisca Date: Mon, 29 Jan 2018 18:00:43 +0200 Subject: [PATCH 114/117] fix handling of file names in save method --- asammdf/mdf_v3.py | 6 ++++-- asammdf/mdf_v4.py | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/asammdf/mdf_v3.py b/asammdf/mdf_v3.py index db3d99011..f26dc0532 100644 --- a/asammdf/mdf_v3.py +++ b/asammdf/mdf_v3.py @@ -2985,7 +2985,8 @@ def _save_with_metadata(self, dst, overwrite, compression): raise MdfException(message) dst = dst if dst else self.name - dst = os.path.splitext(dst)[0] + '.mdf' + if not dst.endswith(('mdf', 'MDF')) + dst = dst + '.mdf' if overwrite is False: if os.path.isfile(dst): cntr = 0 @@ -3360,7 +3361,8 @@ def _save_without_metadata(self, dst, overwrite, compression): raise MdfException(message) dst = dst if dst else self.name - dst = os.path.splitext(dst)[0] + '.mdf' + if not dst.endswith(('mdf', 'MDF')) + dst = dst + '.mdf' if overwrite is False: if os.path.isfile(dst): cntr = 0 diff --git a/asammdf/mdf_v4.py b/asammdf/mdf_v4.py index feabcec0f..b52c606d2 100644 --- a/asammdf/mdf_v4.py +++ b/asammdf/mdf_v4.py @@ -4109,7 +4109,8 @@ def _save_with_metadata(self, dst, overwrite, compression): raise MdfException(message) dst = dst if dst else self.name - dst = os.path.splitext(dst)[0] + '.mf4' + dif not dst.endswith(('mf4', 'MF4')) + dst = dst + '.mf4' if overwrite is False: if os.path.isfile(dst): cntr = 0 @@ -4724,7 +4725,8 @@ def _save_without_metadata(self, dst, overwrite, compression): raise MdfException(message) dst = dst if dst else self.name - dst = os.path.splitext(dst)[0] + '.mf4' + if not dst.endswith(('mf4', 'MF4')) + dst = dst + '.mf4' if overwrite is False: if os.path.isfile(dst): cntr = 0 From 87ac550ad6af229a861b7a0e273754afb3b6b768 Mon Sep 17 00:00:00 2001 From: danielhrisca Date: Mon, 29 Jan 2018 18:09:42 +0200 Subject: [PATCH 115/117] fix typo --- asammdf/mdf_v3.py | 4 ++-- asammdf/mdf_v4.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/asammdf/mdf_v3.py b/asammdf/mdf_v3.py index f26dc0532..6d9475a03 100644 --- a/asammdf/mdf_v3.py +++ b/asammdf/mdf_v3.py @@ -2985,7 +2985,7 @@ def _save_with_metadata(self, dst, overwrite, compression): raise MdfException(message) dst = dst if dst else self.name - if not dst.endswith(('mdf', 'MDF')) + if not dst.endswith(('mdf', 'MDF')): dst = dst + '.mdf' if overwrite is False: if os.path.isfile(dst): @@ -3361,7 +3361,7 @@ def _save_without_metadata(self, dst, overwrite, compression): raise MdfException(message) dst = dst if dst else self.name - if not dst.endswith(('mdf', 'MDF')) + if not dst.endswith(('mdf', 'MDF')): dst = dst + '.mdf' if overwrite is False: if os.path.isfile(dst): diff --git a/asammdf/mdf_v4.py b/asammdf/mdf_v4.py index b52c606d2..596c06b9b 100644 --- a/asammdf/mdf_v4.py +++ b/asammdf/mdf_v4.py @@ -4109,7 +4109,7 @@ def _save_with_metadata(self, dst, overwrite, compression): raise MdfException(message) dst = dst if dst else self.name - dif not dst.endswith(('mf4', 'MF4')) + dif not dst.endswith(('mf4', 'MF4')): dst = dst + '.mf4' if overwrite is False: if os.path.isfile(dst): @@ -4725,7 +4725,7 @@ def _save_without_metadata(self, dst, overwrite, compression): raise MdfException(message) dst = dst if dst else self.name - if not dst.endswith(('mf4', 'MF4')) + if not dst.endswith(('mf4', 'MF4')): dst = dst + '.mf4' if overwrite is False: if os.path.isfile(dst): From 6731b0f98871efa173190bbc7ec52cb4d5dd6657 Mon Sep 17 00:00:00 2001 From: danielhrisca Date: Mon, 29 Jan 2018 18:12:42 +0200 Subject: [PATCH 116/117] and a second typo --- asammdf/mdf_v4.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/asammdf/mdf_v4.py b/asammdf/mdf_v4.py index 596c06b9b..33652c16e 100644 --- a/asammdf/mdf_v4.py +++ b/asammdf/mdf_v4.py @@ -4109,7 +4109,7 @@ def _save_with_metadata(self, dst, overwrite, compression): raise MdfException(message) dst = dst if dst else self.name - dif not dst.endswith(('mf4', 'MF4')): + if not dst.endswith(('mf4', 'MF4')): dst = dst + '.mf4' if overwrite is False: if os.path.isfile(dst): From 8fdbca412fc370f2357035d76a00487c4d051b48 Mon Sep 17 00:00:00 2001 From: Jack Jester-Weinstein Date: Mon, 29 Jan 2018 21:40:46 -0800 Subject: [PATCH 117/117] Use numpy.where for signed non-byte-sized integers The MDF3.get method was in master was masking irrelevant bits from non-byte-sized integers and then relying on numpy.ndarray.astype to convert back to signed. Since numpy only has byte-sized data types, this meant that the wrong two's complement was used (e.g. 2**16 rather than 2**14 for a 14-bit integer encoded in a np.uint16). This change computes two's complement for non-byte-sized signed integers using numpy.where. --- asammdf/mdf_v3.py | 30 ++++++++---------------------- asammdf/mdf_v4.py | 20 ++------------------ asammdf/utils.py | 25 +++++++++++++++++++++++++ 3 files changed, 35 insertions(+), 40 deletions(-) diff --git a/asammdf/mdf_v3.py b/asammdf/mdf_v3.py index 6d9475a03..0f26c7707 100644 --- a/asammdf/mdf_v3.py +++ b/asammdf/mdf_v3.py @@ -44,6 +44,7 @@ from .signal import Signal from .utils import ( MdfException, + as_non_byte_sized_signed_int, fix_dtype_fields, fmt_to_datatype_v3, get_fmt_v3, @@ -2454,29 +2455,14 @@ def get(self, vals = vals >> bit_offset if not bits == size * 8: - mask = (1 << bits) - 1 - if vals.flags.writeable: - vals &= mask - else: - vals = vals & mask - if data_type in v23c.SIGNED_INT: - - size = vals.dtype.itemsize - - masks = ones( - cycles_nr, - dtype=dtype('> (bits - 1)).astype(dtype('> (bits - 1)).astype(dtype('> bit_length - 1, # sign bit as a truth series (True when negative) + (2**bit_length - truncated_integers) * -1, # when negative, do two's complement + truncated_integers) # when positive, return the truncated int