diff --git a/doc/api.md b/doc/api.md index 0fb3401..0d85fd0 100644 --- a/doc/api.md +++ b/doc/api.md @@ -34,5 +34,5 @@ api/electrochemistry/reference_electrode.md api/loaders/baseloader.md api/loaders/eclabloader.md api/loaders/gamryloader.md -api/loaders/column_names.md +api/loaders/eclab_fields.md ``` diff --git a/doc/api/loaders/column_names.md b/doc/api/loaders/column_names.md deleted file mode 100644 index aa25cc4..0000000 --- a/doc/api/loaders/column_names.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -github_url: https://github.com/echemdb/unitpackage/blob/master/unitpackage/loaders/column_names.py ---- - -# `unitpackage.loaders.column_names` -```{eval-rst} -.. automodule:: unitpackage.loaders.column_names - :members: -``` diff --git a/doc/api/loaders/eclab_fields.md b/doc/api/loaders/eclab_fields.md new file mode 100644 index 0000000..6d2b04d --- /dev/null +++ b/doc/api/loaders/eclab_fields.md @@ -0,0 +1,9 @@ +--- +github_url: https://github.com/echemdb/unitpackage/blob/master/unitpackage/loaders/eclab_fields.py +--- + +# `unitpackage.loaders.eclab_fields` +```{eval-rst} +.. automodule:: unitpackage.loaders.eclab_fields + :members: +``` diff --git a/doc/news/from_loaders.rst b/doc/news/from_loaders.rst new file mode 100644 index 0000000..447708b --- /dev/null +++ b/doc/news/from_loaders.rst @@ -0,0 +1,6 @@ +**Added:** + +* Added `device` parameter to `Entry.from_csv()` to select instrument-specific loaders (e.g., ``device='eclab'`` for BioLogic MPT files, ``device='gamry'`` for Gamry DTA files). +* Added `BaseLoader.metadata` property, which returns file structure information (loader name, delimiter, decimal, header, column headers) stored as ``dsvDescription`` in the entry's metadata. +* Added `EchemdbEntry.from_mpt()` classmethod to load BioLogic EC-Lab MPT files with automatic field updates, renaming, and filtering. +* Added `eclab_fields.py` module (renamed from ``column_names.py``) containing ``biologic_fields`` and ``biologic_fields_alt_names`` for standardized electrochemistry field definitions. diff --git a/doc/news/load-metadata.rst b/doc/news/load-metadata.rst index f334198..240b689 100644 --- a/doc/news/load-metadata.rst +++ b/doc/news/load-metadata.rst @@ -5,7 +5,7 @@ * Added `MetadataDescriptor` class for enhanced metadata handling with dict and attribute-style access. * Added `Entry.default_metadata_key` class attribute to control metadata access patterns in subclasses. * Added `Entry._default_metadata` property to access the appropriate metadata subset. -* Added `encoding`, `header_lines`, `column_header_lines`, `decimal`, and `delimiters` parameters to `Entry.from_csv()` for handling complex CSV formats. +* Added `encoding`, `header_lines`, `column_header_lines`, `decimal`, `delimiters`, and `device` parameters to `Entry.from_csv()` for handling complex CSV formats and instrument-specific file types. * Added `create_tabular_resource_from_csv()` to create resources from CSV files with auto-detection of standard vs. complex formats. * Added `create_df_resource_from_csv()` for creating pandas dataframe resources from CSV files with custom formats. * Added `create_df_resource_from_df()` for creating resources directly from pandas DataFrames. diff --git a/doc/usage/load_and_save.md b/doc/usage/load_and_save.md index 7edde18..723d497 100644 --- a/doc/usage/load_and_save.md +++ b/doc/usage/load_and_save.md @@ -109,6 +109,50 @@ csv_entry.fields For even more complex file formats from laboratory equipment, see the [Loaders](loaders.md) section. +### From specific device file formats + +Files from laboratory equipment (devices) often have complex structures with lengthy headers, non-standard delimiters, and instrument-specific column names. +`Entry.from_csv` supports a `device` parameter that selects the appropriate loader for the file format. + +For example, loading a BioLogic EC-Lab MPT file: + +```{code-cell} ipython3 +from unitpackage.entry import Entry + +entry = Entry.from_csv(csvname='../../test/loader_data/eclab_cv.mpt', device='eclab') +entry +``` + +The loader automatically detects headers and delimiters. The resulting entry contains the raw column names from the instrument: + +```{code-cell} ipython3 +entry.fields +``` + +Information on the file structure is stored in the entry's metadata under `dsvDescription`: + +```{code-cell} ipython3 +entry.metadata['dsvDescription']['loader'] +``` + +#### Domain-specific loading + +For submodules such as `echemdb`, convenience methods provide additional processing. +`EchemdbEntry.from_mpt` loads an MPT file and then updates the fields with units, renames them to short standardized names, and keeps only the most relevant columns for electrochemistry: + +```{code-cell} ipython3 +from unitpackage.database.echemdb_entry import EchemdbEntry + +entry = EchemdbEntry.from_mpt('../../test/loader_data/eclab_cv.mpt') +entry.df.head() +``` + +The fields now have units, short names, and a reference to the original BioLogic column name: + +```{code-cell} ipython3 +entry.fields +``` + From a pandas DataFrame: ```{code-cell} ipython3 diff --git a/unitpackage/database/echemdb_entry.py b/unitpackage/database/echemdb_entry.py index 1bb5ef4..06c5dc5 100644 --- a/unitpackage/database/echemdb_entry.py +++ b/unitpackage/database/echemdb_entry.py @@ -102,6 +102,78 @@ def __repr__(self): """ return f"Echemdb({self.identifier!r})" + @classmethod + def from_mpt(cls, csvname, encoding=None): + r""" + Return an :class:`~unitpackage.database.echemdb_entry.EchemdbEntry` from a BioLogic EC-Lab MPT file. + + The file is parsed with the ECLabLoader. Fields are updated with + units from ``biologic_fields`` + and renamed according to + ``biologic_fields_alt_names`` + (both defined in :mod:`unitpackage.loaders.eclab_fields`). + The original field names are preserved as ``originalName``. + + Only columns whose original names appear in + ``biologic_fields_alt_names`` + are kept; all other columns are removed. + + EXAMPLES:: + + >>> entry = EchemdbEntry.from_mpt('test/loader_data/eclab_cv.mpt') + >>> entry + Echemdb('eclab_cv') + + >>> entry.df.head() # doctest: +NORMALIZE_WHITESPACE + t E I cycle + 0 86.761598 0.849737 0.001722 1.0 + 1 86.772598 0.849149 -0.003851 1.0 + ... + + Fields have units and the original BioLogic column names:: + + >>> [f for f in entry.fields if f.name == 'E'] # doctest: +NORMALIZE_WHITESPACE + [{'name': 'E', 'type': 'number', 'description': 'WE potential versus REF.', + 'unit': 'V', 'dimension': 'E', 'originalName': 'Ewe/V'}] + + >>> [f for f in entry.fields if f.name == 't'] # doctest: +NORMALIZE_WHITESPACE + [{'name': 't', 'type': 'number', 'description': 'Time.', + 'unit': 's', 'dimension': 't', 'originalName': 'time/s'}] + + >>> [f for f in entry.fields if f.name == 'I'] # doctest: +NORMALIZE_WHITESPACE +ELLIPSIS + [{'name': 'I', 'type': 'number', 'description': ..., + 'unit': 'mA', 'dimension': 'I', 'originalName': '/mA'}] + + The loader metadata is stored in the entry's metadata:: + + >>> entry.metadata['dsvDescription']['loader'] + 'ECLabLoader' + + >>> entry.metadata['dsvDescription']['header'] # doctest: +NORMALIZE_WHITESPACE +ELLIPSIS + 'EC-Lab ASCII FILE\nNb header lines : 62...' + + """ + from unitpackage.loaders.eclab_fields import ( + biologic_fields, + biologic_fields_alt_names, + ) + + entry = cls.from_csv(csvname=csvname, encoding=encoding, device="eclab") + entry = entry.update_fields(biologic_fields) + entry = entry.rename_fields( + biologic_fields_alt_names, keep_original_name_as="originalName" + ) + + # Only keep columns that were renamed via biologic_fields_alt_names + columns_to_remove = [ + f.name + for f in entry.fields + if f.name not in biologic_fields_alt_names.values() + ] + entry = entry.remove_columns(*columns_to_remove) + + return entry + @property def bibliography(self): r""" diff --git a/unitpackage/entry.py b/unitpackage/entry.py index 09951dc..41f016e 100644 --- a/unitpackage/entry.py +++ b/unitpackage/entry.py @@ -1085,7 +1085,7 @@ def update_fields(self, fields): return type(self)(resource=new_resource) @classmethod - def from_csv( + def from_csv( # pylint: disable=too-many-locals cls, csvname, encoding=None, @@ -1093,10 +1093,18 @@ def from_csv( column_header_lines=None, decimal=None, delimiters=None, + device=None, ): r""" Returns an entry constructed from a CSV. + The file is always parsed through a loader which captures the file's + structure (delimiter, decimal separator, header, column headers) in the + entry's metadata under ``dsvDescription``. + + A ``device`` can be specified to select a device-specific loader + (e.g., ``'eclab'`` or ``'gamry'``). + EXAMPLES:: >>> from unitpackage.entry import Entry @@ -1104,9 +1112,12 @@ def from_csv( >>> entry Entry('from_csv') - >>> entry.resource # doctest: +NORMALIZE_WHITESPACE - {'name': 'from_csv', - ... + The loader's file structure information is stored in the metadata:: + + >>> entry.metadata['dsvDescription']['loader'] + 'BaseLoader' + >>> entry.metadata['dsvDescription']['delimiter'] + ',' .. important:: Upper case filenames are converted to lower case entry identifiers! @@ -1117,45 +1128,51 @@ def from_csv( >>> entry Entry('uppercase') - Casing in the filename is preserved in the metadata:: - - >>> entry.resource # doctest: +NORMALIZE_WHITESPACE - {'name': 'uppercase', - 'type': 'table', - 'path': 'UpperCase.csv', - ... - CSV with a more complex structure, such as multiple header lines can be constructed:: >>> entry = Entry.from_csv(csvname='examples/from_csv/from_csv_multiple_headers.csv', column_header_lines=2) - >>> entry.resource # doctest: +NORMALIZE_WHITESPACE - {'name': 'from_csv_multiple_headers', - 'type': 'table', - 'data': [], - 'format': 'pandas', - 'mediatype': 'application/pandas', - 'schema': {'fields': [{'name': 'E / V', 'type': 'integer'}, - {'name': 'j / A / cm2', 'type': 'integer'}]}} + >>> entry.fields # doctest: +NORMALIZE_WHITESPACE + [{'name': 'E / V', 'type': 'integer'}, + {'name': 'j / A / cm2', 'type': 'integer'}] - """ - from unitpackage.local import create_tabular_resource_from_csv - - # pylint: disable=duplicate-code - resource = create_tabular_resource_from_csv( - csvname=csvname, - encoding=encoding, - header_lines=header_lines, - column_header_lines=column_header_lines, - decimal=decimal, - delimiters=delimiters, - ) + A device-specific loader can be used to parse instrument files:: + >>> entry = Entry.from_csv(csvname='test/loader_data/eclab_cv.mpt', device='eclab') + >>> entry + Entry('eclab_cv') + + >>> entry.df # doctest: +NORMALIZE_WHITESPACE + mode ox/red error ... (Q-Qo)/C I Range P/W + 0 2 1 0 ... 0.000000e+00 41 0.000001 + 1 2 0 0 ... -3.622761e-08 41 -0.000003 + ... + + >>> entry.metadata['dsvDescription']['loader'] + 'ECLabLoader' + >>> entry.metadata['dsvDescription']['delimiter'] + '\t' + + """ from pathlib import Path - if resource.name == "memory": - resource.name = Path( - csvname - ).stem.lower() # Use stem (filename without extension) + from unitpackage.loaders.baseloader import BaseLoader + from unitpackage.local import create_df_resource_from_df + + dialect = { + "header_lines": header_lines, + "column_header_lines": column_header_lines, + "decimal": decimal, + "delimiters": delimiters, + } + + loader_cls = BaseLoader.create(device) if device else BaseLoader + + with open(csvname, "r", encoding=encoding or "utf-8") as f: + loader = loader_cls(f, **dialect) + + resource = create_df_resource_from_df(loader.df) + resource.name = Path(csvname).stem.lower() + resource.custom["metadata"] = {"dsvDescription": loader.metadata} return cls(resource) diff --git a/unitpackage/loaders/baseloader.py b/unitpackage/loaders/baseloader.py index 37f0e5b..da23330 100644 --- a/unitpackage/loaders/baseloader.py +++ b/unitpackage/loaders/baseloader.py @@ -28,9 +28,9 @@ # ******************************************************************** # This file is part of unitpackage. # -# Copyright (C) 2025 Albert Engstfeld -# Copyright (C) 2022 Johannes Hermann -# Copyright (C) 2022 Julian Rüth +# Copyright (C) 2025-2026 Albert Engstfeld +# Copyright (C) 2025 Johannes Hermann +# Copyright (C) 2025 Julian Rüth # # unitpackage is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -129,8 +129,36 @@ def file(self): return StringIO(self._file) - @staticmethod - def create(device=None): + @classmethod + def _loaders(cls): + r""" + A dictionary of known loaders. + """ + return { + "eclab": __import__( + "unitpackage.loaders.eclabloader" + ).loaders.eclabloader.ECLabLoader, + "gamry": __import__( + "unitpackage.loaders.gamryloader" + ).loaders.gamryloader.GamryLoader, + } + + @classmethod + def known_loaders(cls): + r""" + A list of known loaders. Refer to the documentation for details + on supported file types for the individual Loaders. + + EXAMPLES:: + + >>> BaseLoader.known_loaders() + ['eclab', 'gamry'] + + """ + return list(cls._loaders().keys()) + + @classmethod + def create(cls, device=None): r""" Calls a specific `loader` based on a given device. @@ -152,18 +180,21 @@ def create(device=None): 0 2 0 0.1 0 0 1 2 1 1.4 5 1 - """ - if device == "eclab": - from unitpackage.loaders.eclabloader import ECLabLoader + An unknown device loader provides a list with supported Loaders:: - return ECLabLoader + >>> BaseLoader.create('unknown_device') # doctest: +NORMALIZE_WHITESPACE + Traceback (most recent call last): + ... + KeyError: "Device wth name 'unknown_device' is not in the list of supported Loaders (['eclab', 'gamry'])'." - if device == "gamry": - from unitpackage.loaders.gamryloader import GamryLoader + """ + if device in BaseLoader.known_loaders(): - return GamryLoader + return cls._loaders()[device] - raise KeyError(f"Device wth name '{device}' is unknown to the loader'.") + raise KeyError( + f"Device wth name '{device}' is not in the list of supported Loaders ({cls.known_loaders()})'." + ) @property def header_lines(self): @@ -233,8 +264,10 @@ def header(self): ) @property - def metadata(self): # pylint: disable=abstract-method - r"""A dict containing the metadata of the file found in its header. + def metadata(self): + r"""A dict describing the structure of the loaded DSV file, including + the dialect (delimiter, decimal separator), header content, and + column header names. EXAMPLES:: @@ -243,13 +276,27 @@ def metadata(self): # pylint: disable=abstract-method ... 0,0 ... 1,1''') >>> csv = BaseLoader(file) - >>> csv.metadata - Traceback (most recent call last): - ... - NotImplementedError + >>> csv.metadata # doctest: +NORMALIZE_WHITESPACE + {'loader': 'BaseLoader', + 'delimiter': ',', + 'decimal': '.', + 'headerLines': 0, + 'columnHeaderLines': 1, + 'header': '', + 'columnHeaders': 'a,b\n', + 'columnHeaderNames': ['a', 'b']} """ - raise NotImplementedError + return { + "loader": type(self).__name__, + "delimiter": self.delimiter, + "decimal": self.decimal, + "headerLines": self.header_lines, + "columnHeaderLines": self.column_header_lines, + "header": self.header.read(), + "columnHeaders": self.column_headers.read(), + "columnHeaderNames": self.column_header_names, + } @property def column_header_lines(self): diff --git a/unitpackage/loaders/column_names.py b/unitpackage/loaders/eclab_fields.py similarity index 68% rename from unitpackage/loaders/column_names.py rename to unitpackage/loaders/eclab_fields.py index afd3f4e..aa26a64 100644 --- a/unitpackage/loaders/column_names.py +++ b/unitpackage/loaders/eclab_fields.py @@ -1,9 +1,9 @@ -r"""Fields describing specific csv data, such as biologic MPT files.""" +r"""Description of fields found in biologic MPT files.""" # ******************************************************************** # This file is part of unitpackage. # -# Copyright (C) 2024-2025 Albert Engstfeld +# Copyright (C) 2024-2026 Albert Engstfeld # Copyright (C) 2024 Justus Leist # # unitpackage is free software: you can redistribute it and/or modify @@ -25,422 +25,427 @@ "name": "Ri/Ohm", "unit": "Ohm", "dimension": "R", - "description": "apparent resistance", + "description": "Apparent resistance.", }, { "name": "-Im(Z)/Ohm", "unit": "Ohm", "dimension": "-Im(Z)", - "description": "-imaginary part of Z", + "description": "-Imaginary part of Z.", }, { "name": "-Im(Zce)/Ohm", "unit": "Ohm", "dimension": "-Im(Zce)", - "description": "-imaginary part of Z of CE vs ref", + "description": "-Imaginary part of Z of CE vs ref.", }, { "name": "-Im(Zwe-ce)/Ohm", "unit": "Ohm", "dimension": "-Im(Zwe-ce)", - "description": "-imaginary part of Z of WE vs CE", + "description": "-Imaginary part of Z of WE vs CE.", }, { "name": "(Q-Qo)/C", "unit": "C", "dimension": "Q", - "description": "charge from the beginning of the experiment", + "description": "Charge from the beginning of the experiment.", }, { "name": "(Q-Qo)/mA.h", "unit": "mA h", "dimension": "Q", - "description": "charge from the beginning of the experiment", + "description": "Charge from the beginning of the experiment.", }, { "name": "/V", "unit": "V", "dimension": "E", - "description": "averaged potential of CE versus REF", + "description": "Averaged potential of CE versus REF.", }, { "name": "/V", "unit": "V", "dimension": "E", - "description": "averaged voltage (WE vs. REF)", + "description": "Averaged voltage (WE vs. REF).", }, { "name": "/mA", "unit": "mA", "dimension": "I", - "description": "average current over the potential step (calculated from I = dQ/dt", + "description": "Average current over the potential step (calculated from I = dQ/dt).", }, { "name": "|Ece|/V", "unit": "V", "dimension": "E", - "description": "module of Ece (Note:Impedance related)", + "description": "Module of Ece (Note:Impedance related).", }, { "name": "|Energy|/W.h", "unit": "W h", "dimension": "E", - "description": "module of Energy (Note:Impedance related)", + "description": "Module of Energy (Note:Impedance related).", }, { "name": "|Ewe|/V", "unit": "V", "dimension": "E", - "description": "module of Ewe (Note:Impedance related", + "description": "Module of Ewe (Note:Impedance related).", }, { "name": "|I|/A", "unit": "A", "dimension": "I", - "description": "module of I (Note:Impedance related", + "description": "Module of I (Note:Impedance related).", }, { "name": "|Y|/Ohm-1", "unit": "S", "dimension": "|Y|", - "description": "Admittance magnitude (in Ω-1", + "description": "Admittance magnitude (in Ω-1).", + }, + { + "name": "|Z|/Ohm", + "unit": "Ohm", + "dimension": "|Z|", + "description": "Phase of Z.", }, - {"name": "|Z|/Ohm", "unit": "Ohm", "dimension": "|Z|", "description": "Phase of Z"}, { "name": "|Zce|/Ohm", "unit": "Ohm", "dimension": "|Zce|", - "description": "Phase of Zce", + "description": "Phase of Zce.", }, { "name": "|Zwe-ce|/Ohm", "unit": "Ohm", "dimension": "|Zwe-ce|", - "description": "Phase of Zwe-ce", + "description": "Phase of Zwe-ce.", }, { "name": "Analog IN 1/V", "unit": "V", "dimension": "V", - "description": "Additional analog input 1", + "description": "Additional analog input 1.", }, { "name": "Analog IN 2/V", "unit": "V", "dimension": "V", - "description": "Additional analog input 2", + "description": "Additional analog input 2.", }, { "name": "Analog IN 3/V", "unit": "V", "dimension": "V", - "description": "Additional analog input 3 (for VMP only)", + "description": "Additional analog input 3 (for VMP only).", }, { "name": "Capacitance charge/µF", "unit": "uF", "dimension": "C", - "description": "Capacitance charge", + "description": "Capacitance charge.", }, { "name": "Capacitance discharge/µF", "unit": "uF", "dimension": "C", - "description": "Capacitance discharge", + "description": "Capacitance discharge.", }, { "name": "Capacity/mA.h", "unit": "mA h", "dimension": "Q", - "description": "Capacity", + "description": "Capacity.", }, { "name": "charge time/s", "unit": "s", "dimension": "t", - "description": "Charge time: time elapsed during each charge (I>0) reset to 0 at the end of each discharge", + "description": "Charge time: time elapsed during each charge (I>0) reset to 0 at the end of each discharge.", }, { "name": "Conductivity/S.cm-1", "unit": "S cm-1", "dimension": "sigma", - "description": "Conductivity", + "description": "Conductivity.", }, { "name": "control changes", - "description": "Control changes, State byte (bit n°5) ", + "description": "Control changes, State byte (bit n°5).", }, { "name": "control/mA", "unit": "mA", "dimension": "I", - "description": "Ictrl: current control", + "description": "Ictrl: current control.", }, { "name": "control/V", "unit": "V", "dimension": "V", - "description": "Ectrl: potential control ", + "description": "Ectrl: potential control.", }, { "name": "control/V/mA", "unit": "V mA-1", "dimension": "V / I", - "description": "Ectrl/Ictrl: potential or current control ", + "description": "Ectrl/Ictrl: potential or current control.", }, { "name": "counter inc.", - "description": "Experiment counter value has changed (bit n°8)", + "description": "Experiment counter value has changed (bit n°8).", }, { "name": "Cp-2/µF-2", "unit": "uF-2", "dimension": "C-2", - "description": "Inverse of square capacitance calculated using an R/C (parallel) equivalent circuit ", + "description": "Inverse of square capacitance calculated using an R/C (parallel) equivalent circuit.", }, { "name": "Cp/µF", "unit": "uF", "dimension": "C", - "description": "Capacitance calculated using an R/C (parallel) equivalent circuit ", + "description": "Capacitance calculated using an R/C (parallel) equivalent circuit.", }, { "name": "Cs-2/µF-2", "unit": "uF-2", "dimension": "Cs⁻²", - "description": "Inverse of square capacitanc calculated using an R+C (series) equivalent circuit", + "description": "Inverse of square capacitanc calculated using an R+C (series) equivalent circuit.", }, { "name": "Cs/µF", "unit": "uF", "dimension": "C", - "description": "Capacitance calculated using an R+C (series) equivalent circuit", + "description": "Capacitance calculated using an R+C (series) equivalent circuit.", }, - {"name": "cycle number", "description": "Cycle number"}, + {"name": "cycle number", "description": "Cycle number."}, { "name": "cycle time/s", "unit": "s", "dimension": "t", - "description": "Cycle time: time elapsed during each cycle", + "description": "Cycle time: time elapsed during each cycle.", }, { "name": "d(Q-Qo)/dE/mA.h/V", "unit": "mA h/V", "dimension": "d(Q-Qo)/dE", - "description": "Incremental (or differential) capacity over the potential dE during charge or discharge", + "description": "Incremental (or differential) capacity over the potential dE during charge or discharge.", }, { "name": "dI/dt/mA/s", "unit": "mA/s", "dimension": "dI/dt", - "description": "Differential current over time (for potentio technique only) ", + "description": "Differential current over time (for potentio technique only).", }, { "name": "discharge time/s", "unit": "s", "dimension": "t", - "description": "Discharge time : time elapsed during each discharge (I<0) reset to 0 at the end of each charge", + "description": "Discharge time : time elapsed during each discharge (I<0) reset to 0 at the end of each charge.", }, { "name": "dQ/C", "unit": "C", "dimension": "dQ", - "description": "charge increment between two recorded values", + "description": "Charge increment between two recorded values.", }, { "name": "dq/mA.h", "unit": "mA·h", "dimension": "dq", - "description": "dq: charge on a potential step", + "description": "Dq: charge on a potential step.", }, { "name": "dQ/mA.h", "unit": "mA·h", "dimension": "dQ", - "description": "dQ: charge on a cycle", + "description": "DQ: charge on a cycle.", }, { "name": "Ece/V", "unit": "V", "dimension": "E", - "description": "potential control ", + "description": "Potential control.", }, { "name": "Ecell/V", "unit": "V", "dimension": "U", - "description": "Ecell: WE versus CE potential", + "description": "Ecell: WE versus CE potential.", }, { "name": "Efficiency/%", "unit": "pct", "dimension": "Efficiency", - "description": "Efficiency: Q discharge/Q charge ", + "description": "Efficiency: Q discharge/Q charge.", }, { "name": "Energy charge/W.h", "unit": "W h", "dimension": "E", - "description": "Energy charge: E*I*t for I>0 ", + "description": "Energy charge: E*I*t for I>0.", }, { "name": "Energy discharge/W.h", "unit": "W h", "dimension": "E", - "description": "Energy discharge: E*I*t for I<0", + "description": "Energy discharge: E*I*t for I<0.", }, { "name": "Energy/W.h", "unit": "W h", "dimension": "E", - "description": "Energy: in CPW calculated by E*I*t", + "description": "Energy: in CPW calculated by E*I*t.", }, - {"name": "error", "description": "error"}, + {"name": "error", "description": "Error."}, { "name": "Ewe-Ece/V", "unit": "V", "dimension": "U", - "description": "Ewe-Ece: WE versus CE potential ", + "description": "Ewe-Ece: WE versus CE potential.", }, { "name": "Ewe/V", "unit": "V", "dimension": "E", - "description": "WE potential versus REF", + "description": "WE potential versus REF.", }, - {"name": "freq/Hz", "unit": "Hz", "dimension": "f", "description": "Frequency"}, - {"name": "half cycle", "description": "Half cycle of CV"}, - {"name": "I Range", "description": "The current range"}, + {"name": "freq/Hz", "unit": "Hz", "dimension": "f", "description": "Frequency."}, + {"name": "half cycle", "description": "Half cycle of CV."}, + {"name": "I Range", "description": "The current range."}, { "name": "I/mA", "unit": "mA", "dimension": "I", - "description": "Instantaneous current", + "description": "Instantaneous current.", }, { "name": "Im(Y)/Ohm-1", "unit": "S", "dimension": "Im(Y)", - "description": "-Im(Y):-imaginary part of Y (in Ω-1)", + "description": "-Im(Y):-imaginary part of Y (in Ω-1).", }, { "name": "mode", - "description": "Mode = Intentio/Potentio/Relax, State byte (bits n°1 and 2) ", + "description": "Mode = Intentio/Potentio/Relax, State byte (bits n°1 and 2).", }, - {"name": "Ns changes", "description": "Changes of Ns, State byte (bit n°6)"}, + {"name": "Ns changes", "description": "Changes of Ns, State byte (bit n°6)."}, {"name": "Ns", "description": ""}, - {"name": "NSD Ewe/%", "unit": "pct", "description": "NSD Ewe"}, - {"name": "NSD I/%", "unit": "pct", "description": "NSD I"}, - {"name": "NSR Ewe/%", "unit": "pct", "description": "NSR Ewe"}, - {"name": "NSR I/%", "unit": "pct", "description": "NSR I"}, - {"name": "ox/red", "description": "ox or red"}, + {"name": "NSD Ewe/%", "unit": "pct", "description": "NSD Ewe."}, + {"name": "NSD I/%", "unit": "pct", "description": "NSD I."}, + {"name": "NSR Ewe/%", "unit": "pct", "description": "NSR Ewe."}, + {"name": "NSR I/%", "unit": "pct", "description": "NSR I."}, + {"name": "ox/red", "description": "Ox or red."}, { "name": "P/W", "unit": "W", "dimension": "P", - "description": "Power: in CPW, calculated by E*I", + "description": "Power: in CPW, calculated by E*I.", }, { "name": "Phase(Y)/deg", "unit": "deg", "dimension": "Phase(Y)", - "description": "Admittance phase (in degrees)", + "description": "Admittance phase (in degrees).", }, { "name": "Phase(Z)/deg", "unit": "deg", "dimension": "Phase(Z)", - "description": "Phase of Z", + "description": "Phase of Z.", }, { "name": "Phase(Zce)/deg", "unit": "deg", "dimension": "Phase(Zce)", - "description": "Phase of Zce", + "description": "Phase of Zce.", }, { "name": "Phase(Zwe-ce)/deg", "unit": "deg", "dimension": "Phase(Zwe-ce)", - "description": "Phase of Zwe-ce", + "description": "Phase of Zwe-ce.", }, { "name": "Q charge/discharge/mA.h", "unit": "mA h", "dimension": "Q", - "description": "Q charge/discharge: Q for a charge/discharge cycle reinitialized every cycle", + "description": "Q charge/discharge: Q for a charge/discharge cycle reinitialized every cycle.", }, { "name": "Q charge/mA.h", "unit": "mA h", "dimension": "Q", - "description": "Q charge: Q for a charge cycle reinitialized every cycle", + "description": "Q charge: Q for a charge cycle reinitialized every cycle.", }, { "name": "Q charge/mA.h/g", "unit": "mA h/g", "dimension": "Q / m", - "description": "Q charge: Q for a charge cycle reinitialized every cycle", + "description": "Q charge: Q for a charge cycle reinitialized every cycle.", }, { "name": "Q discharge/mA.h", "unit": "mA h", "dimension": "Q", - "description": "Q discharge: Q for a discharge cycle reinitialized every cycle", + "description": "Q discharge: Q for a discharge cycle reinitialized every cycle.", }, { "name": "Q discharge/mA.h/g", "unit": "mA h / g", "dimension": "Q / m", - "description": "Q discharge: Q for a discharge cycle reinitialized every cycle", + "description": "Q discharge: Q for a discharge cycle reinitialized every cycle.", }, - {"name": "R/Ohm", "unit": "Ohm", "dimension": "R", "description": "Resistance"}, + {"name": "R/Ohm", "unit": "Ohm", "dimension": "R", "description": "Resistance."}, {"name": "Rcmp/Ohm", "unit": "Ohm", "dimension": "R"}, { "name": "Re(Y)/Ohm-1", "unit": "S", "dimension": "Re(Y)", - "description": "Re(Y): real part of Y (in Ω-1)", + "description": "Re(Y): real part of Y (in Ω-1).", }, { "name": "Re(Z)/Ohm", "unit": "Ohm", "dimension": "Re(Z)", - "description": "Re(Z): real part of Z", + "description": "Re(Z): real part of Z.", }, { "name": "Re(Zce)/Ohm", "unit": "Ohm", "dimension": "Re(Zce)", - "description": "Re(Z): real part of Zce", + "description": "Re(Z): real part of Zce.", }, { "name": "Re(Zwe-ce)/Ohm", "unit": "Ohm", "dimension": "Re(Zwe-ce)", - "description": "Re(Z): real part of Zwe-ce", + "description": "Re(Z): real part of Zwe-ce.", }, { "name": "step time/s", "unit": "s", "dimension": "t", - "description": "Step time: time elapsed ", + "description": "Step time: time elapsed.", }, { "name": "THD Ewe/%", "unit": "pct", "dimension": "THD Ewe", - "description": "Total Harmonic Distortion of Ewe", + "description": "Total Harmonic Distortion of Ewe.", }, { "name": "THD I/%", "unit": "pct", "dimension": "THD I", - "description": "Total Harmonic Distortion of I", + "description": "Total Harmonic Distortion of I.", }, - {"name": "time/s", "unit": "s", "dimension": "t", "description": "time"}, - {"name": "x", "description": "x: normalized charge "}, - {"name": "z cycle", "description": "z cycle"}, + {"name": "time/s", "unit": "s", "dimension": "t", "description": "Time."}, + {"name": "x", "description": "X: normalized charge."}, + {"name": "z cycle", "description": "Z cycle."}, ] biologic_fields_alt_names = { @@ -453,4 +458,6 @@ "-Im(Z)/Ohm": "-Im(Z)", "freq/Hz": "f", "Phase(Z)/deg": "Phase(Z)", + "Ece/V": "E_CE", + "cycle number": "cycle", }