PyDPEET 0.2.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pydpeet/__init__.py +56 -0
- pydpeet/citations/__init__.py +7 -0
- pydpeet/citations/citeme.py +397 -0
- pydpeet/citations/html_writer.py +137 -0
- pydpeet/dev_utils/__init__.py +7 -0
- pydpeet/dev_utils/generate_inits/__init__.py +7 -0
- pydpeet/dev_utils/generate_inits/generate_inits.py +327 -0
- pydpeet/io/__init__.py +7 -0
- pydpeet/io/configs/__init__.py +7 -0
- pydpeet/io/configs/config.py +227 -0
- pydpeet/io/configs/const.py +1 -0
- pydpeet/io/convert.py +594 -0
- pydpeet/io/device/__init__.py +7 -0
- pydpeet/io/device/arbin_4_23_PV090331/__init__.py +7 -0
- pydpeet/io/device/arbin_4_23_PV090331/formatter.py +22 -0
- pydpeet/io/device/arbin_4_23_PV090331/mapper.py +18 -0
- pydpeet/io/device/arbin_4_23_PV090331/reader.py +68 -0
- pydpeet/io/device/arbin_8_00_PV221201/__init__.py +7 -0
- pydpeet/io/device/arbin_8_00_PV221201/formatter.py +26 -0
- pydpeet/io/device/arbin_8_00_PV221201/mapper.py +18 -0
- pydpeet/io/device/arbin_8_00_PV221201/reader.py +66 -0
- pydpeet/io/device/basytec_6_3_1_0/__init__.py +7 -0
- pydpeet/io/device/basytec_6_3_1_0/formatter.py +18 -0
- pydpeet/io/device/basytec_6_3_1_0/mapper.py +18 -0
- pydpeet/io/device/basytec_6_3_1_0/reader.py +54 -0
- pydpeet/io/device/digatron_4_20_6_236/__init__.py +7 -0
- pydpeet/io/device/digatron_4_20_6_236/formatter.py +27 -0
- pydpeet/io/device/digatron_4_20_6_236/mapper.py +18 -0
- pydpeet/io/device/digatron_4_20_6_236/reader.py +45 -0
- pydpeet/io/device/digatron_eis_4_20_6_236/__init__.py +7 -0
- pydpeet/io/device/digatron_eis_4_20_6_236/formatter.py +39 -0
- pydpeet/io/device/digatron_eis_4_20_6_236/mapper.py +18 -0
- pydpeet/io/device/digatron_eis_4_20_6_236/reader.py +42 -0
- pydpeet/io/device/neware_8_0_0_516/__init__.py +7 -0
- pydpeet/io/device/neware_8_0_0_516/formatter.py +31 -0
- pydpeet/io/device/neware_8_0_0_516/mapper.py +18 -0
- pydpeet/io/device/neware_8_0_0_516/reader.py +397 -0
- pydpeet/io/device/parstat_2_63_3/__init__.py +7 -0
- pydpeet/io/device/parstat_2_63_3/formatter.py +34 -0
- pydpeet/io/device/parstat_2_63_3/mapper.py +18 -0
- pydpeet/io/device/parstat_2_63_3/reader.py +34 -0
- pydpeet/io/device/safion_1_9/__init__.py +7 -0
- pydpeet/io/device/safion_1_9/formatter.py +25 -0
- pydpeet/io/device/safion_1_9/mapper.py +18 -0
- pydpeet/io/device/safion_1_9/reader.py +89 -0
- pydpeet/io/device/zahner/__init__.py +7 -0
- pydpeet/io/device/zahner/formatter.py +73 -0
- pydpeet/io/device/zahner/mapper.py +34 -0
- pydpeet/io/device/zahner/reader.py +46 -0
- pydpeet/io/device/zahner_new/__init__.py +7 -0
- pydpeet/io/device/zahner_new/formatter.py +72 -0
- pydpeet/io/device/zahner_new/mapper.py +50 -0
- pydpeet/io/device/zahner_new/reader.py +46 -0
- pydpeet/io/map.py +69 -0
- pydpeet/io/read.py +50 -0
- pydpeet/io/utils/__init__.py +7 -0
- pydpeet/io/utils/ext_path.py +34 -0
- pydpeet/io/utils/formatter_utils.py +429 -0
- pydpeet/io/utils/load_custom_module.py +33 -0
- pydpeet/io/utils/timing.py +36 -0
- pydpeet/io/write.py +99 -0
- pydpeet/process/__init__.py +7 -0
- pydpeet/process/analyze/__init__.py +7 -0
- pydpeet/process/analyze/average.py +297 -0
- pydpeet/process/analyze/capacity.py +208 -0
- pydpeet/process/analyze/configs/__init__.py +7 -0
- pydpeet/process/analyze/configs/battery_config.py +38 -0
- pydpeet/process/analyze/configs/ocv_config.py +177 -0
- pydpeet/process/analyze/configs/step_analyzer_config.py +178 -0
- pydpeet/process/analyze/cycle.py +63 -0
- pydpeet/process/analyze/efficiency.py +182 -0
- pydpeet/process/analyze/energy.py +51 -0
- pydpeet/process/analyze/extract/__init__.py +7 -0
- pydpeet/process/analyze/extract/dva_ica.py +224 -0
- pydpeet/process/analyze/extract/ocv.py +196 -0
- pydpeet/process/analyze/power.py +32 -0
- pydpeet/process/analyze/resistance.py +87 -0
- pydpeet/process/analyze/soc.py +418 -0
- pydpeet/process/analyze/soh.py +72 -0
- pydpeet/process/analyze/utils.py +122 -0
- pydpeet/process/merge/__init__.py +7 -0
- pydpeet/process/merge/series.py +274 -0
- pydpeet/process/sequence/__init__.py +7 -0
- pydpeet/process/sequence/configs/__init__.py +7 -0
- pydpeet/process/sequence/configs/config.py +17 -0
- pydpeet/process/sequence/step_analyzer.py +440 -0
- pydpeet/process/sequence/utils/__init__.py +7 -0
- pydpeet/process/sequence/utils/annotate/__init__.py +7 -0
- pydpeet/process/sequence/utils/annotate/annotate_primitives.py +419 -0
- pydpeet/process/sequence/utils/configs/CONFIG_Fallback.py +231 -0
- pydpeet/process/sequence/utils/configs/CONFIG_preprocessing.py +243 -0
- pydpeet/process/sequence/utils/configs/__init__.py +7 -0
- pydpeet/process/sequence/utils/console_prints/__init__.py +7 -0
- pydpeet/process/sequence/utils/console_prints/log_time.py +30 -0
- pydpeet/process/sequence/utils/postprocessing/__init__.py +7 -0
- pydpeet/process/sequence/utils/postprocessing/df_primitives_correction.py +166 -0
- pydpeet/process/sequence/utils/postprocessing/filter_df.py +168 -0
- pydpeet/process/sequence/utils/postprocessing/generate_instructions.py +297 -0
- pydpeet/process/sequence/utils/preprocessing/__init__.py +7 -0
- pydpeet/process/sequence/utils/preprocessing/calculate_thresholds.py +27 -0
- pydpeet/process/sequence/utils/processing/__init__.py +7 -0
- pydpeet/process/sequence/utils/processing/analyze_segments.py +368 -0
- pydpeet/process/sequence/utils/processing/attempt_to_merge_neighboring_segments.py +122 -0
- pydpeet/process/sequence/utils/processing/check_CV_results.py +226 -0
- pydpeet/process/sequence/utils/processing/check_power_zero_watt_segments.py +85 -0
- pydpeet/process/sequence/utils/processing/check_zero_length.py +117 -0
- pydpeet/process/sequence/utils/processing/split_in_segments.py +97 -0
- pydpeet/process/sequence/utils/processing/supress_smaller_segments.py +99 -0
- pydpeet/process/sequence/utils/processing/widen_constant_segments.py +185 -0
- pydpeet/process/sequence/utils/visualize/__init__.py +7 -0
- pydpeet/process/sequence/utils/visualize/visualize_data.py +288 -0
- pydpeet/res/__init__.py +7 -0
- pydpeet/settings.py +0 -0
- pydpeet/utils/__init__.py +7 -0
- pydpeet/utils/logging_style.py +28 -0
- pydpeet/version.py +0 -0
- pydpeet-0.2.0.dist-info/METADATA +85 -0
- pydpeet-0.2.0.dist-info/RECORD +122 -0
- pydpeet-0.2.0.dist-info/WHEEL +5 -0
- pydpeet-0.2.0.dist-info/licenses/AUTHORS.md +0 -0
- pydpeet-0.2.0.dist-info/licenses/LICENCE.md +27 -0
- pydpeet-0.2.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import pandas as pd
|
|
2
|
+
|
|
3
|
+
from pydpeet.io.configs.const import PANDAS_EXCEL_ENGINE
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def to_dataframe(input_path: str) -> tuple[pd.DataFrame, str]:
|
|
7
|
+
"""
|
|
8
|
+
Parses the input file from the Arbin Old Cycler into a pandas DataFrame.
|
|
9
|
+
|
|
10
|
+
Parameters:
|
|
11
|
+
input_path (str): Path to the input file.
|
|
12
|
+
|
|
13
|
+
Returns:
|
|
14
|
+
(pandas.DataFrame, str): A tuple containing the DataFrame with data and metadata as a string.
|
|
15
|
+
"""
|
|
16
|
+
# load Excel data
|
|
17
|
+
excel_data = pd.ExcelFile(input_path, engine=PANDAS_EXCEL_ENGINE)
|
|
18
|
+
|
|
19
|
+
return read_sheets(excel_data)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def read_sheets(excel_file: pd.ExcelFile) -> tuple[pd.DataFrame, str]:
|
|
23
|
+
# variables for the dataframe and String
|
|
24
|
+
"""
|
|
25
|
+
Reads data from all sheets in an Excel file and returns them as a tuple of a DataFrame and a string.
|
|
26
|
+
|
|
27
|
+
The first sheet that starts with "Channel" is used as the main data sheet. If there are more sheets with this name,
|
|
28
|
+
they are appended to the first sheet.
|
|
29
|
+
|
|
30
|
+
All sheets named "Info" are concatenated into a single string as metadata.
|
|
31
|
+
|
|
32
|
+
Parameters:
|
|
33
|
+
excel_file (pd.ExcelFile): The Excel file to read from.
|
|
34
|
+
|
|
35
|
+
Returns:
|
|
36
|
+
(pd.DataFrame, str): A tuple containing the DataFrame with data and metadata as a string.
|
|
37
|
+
"""
|
|
38
|
+
arbin_df = None
|
|
39
|
+
metadata_str = []
|
|
40
|
+
iterator = 0
|
|
41
|
+
|
|
42
|
+
# iterate all sheets
|
|
43
|
+
for sheet_name in excel_file.sheet_names:
|
|
44
|
+
# find sheet that starts with "Channel"
|
|
45
|
+
if sheet_name.startswith("Channel"):
|
|
46
|
+
# if it´s the first sheet, that starts with the channel, it gets added to df
|
|
47
|
+
if iterator == 0:
|
|
48
|
+
arbin_df = excel_file.parse(sheet_name, header=0)
|
|
49
|
+
# if it´s the second or higher Sheet, it will be appended without the header and the first row,
|
|
50
|
+
# because first row of 2nd sheet and last row of first sheet are the same
|
|
51
|
+
else:
|
|
52
|
+
# get Data from further Sheet(s)
|
|
53
|
+
# remove the first two rows (header and multiple row)
|
|
54
|
+
further_sheet_data = excel_file.parse(sheet_name, header=0).iloc[1:]
|
|
55
|
+
# concat both sheets into one
|
|
56
|
+
arbin_df = pd.concat([arbin_df, further_sheet_data], ignore_index=True)
|
|
57
|
+
iterator += 1
|
|
58
|
+
# combine all other sheets into a string as metadata
|
|
59
|
+
elif sheet_name.startswith("Info"):
|
|
60
|
+
# only metadata sheet in arbin Old is called "Info"
|
|
61
|
+
sheet_data = excel_file.parse(sheet_name, header=None) # no header
|
|
62
|
+
sheet_str = f"Sheet: {sheet_name}\n{sheet_data.to_string(index=False, header=False)}"
|
|
63
|
+
metadata_str.append(sheet_str)
|
|
64
|
+
|
|
65
|
+
# combine all metadata sheets into one string
|
|
66
|
+
metadata_str_combined = "\n\n".join(metadata_str)
|
|
67
|
+
|
|
68
|
+
return arbin_df, metadata_str_combined
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import pandas as pd
|
|
2
|
+
|
|
3
|
+
from pydpeet.io.utils.formatter_utils import (
|
|
4
|
+
absolute_time_timedate_typecast,
|
|
5
|
+
testtime_hours_to_seconds_with_string_interpretation,
|
|
6
|
+
)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def get_data_into_format(df: pd.DataFrame) -> pd.DataFrame:
|
|
10
|
+
"""
|
|
11
|
+
Format the given DataFrame into a standard format.
|
|
12
|
+
|
|
13
|
+
Parameters
|
|
14
|
+
----------
|
|
15
|
+
data_frame : pandas.DataFrame
|
|
16
|
+
The DataFrame to be formatted
|
|
17
|
+
|
|
18
|
+
Returns
|
|
19
|
+
-------
|
|
20
|
+
pandas.DataFrame
|
|
21
|
+
The formatted DataFrame
|
|
22
|
+
"""
|
|
23
|
+
df = testtime_hours_to_seconds_with_string_interpretation(df, True)
|
|
24
|
+
df = absolute_time_timedate_typecast(df)
|
|
25
|
+
|
|
26
|
+
return df
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# Map raw-data column names (left) to standardized column names (right)
|
|
2
|
+
COLUMN_MAP = {
|
|
3
|
+
"Record number": "Step_Count",
|
|
4
|
+
"Voltage(V)": "Voltage[V]",
|
|
5
|
+
"Current(A)": "Current[A]",
|
|
6
|
+
"Relative Time(h:min:s.ms)": "Test_Time[s]",
|
|
7
|
+
"Real Time(h:min:s.ms)": "Date_Time",
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
# Default columns of the standardized format
|
|
11
|
+
# which are not present in the raw data files.
|
|
12
|
+
MISSING_REQUIRED_COLUMNS = [
|
|
13
|
+
"Temperature[°C]",
|
|
14
|
+
"EIS_f[Hz]",
|
|
15
|
+
"EIS_Z_Real[Ohm]",
|
|
16
|
+
"EIS_Z_Imag[Ohm]",
|
|
17
|
+
"EIS_DC[A]",
|
|
18
|
+
]
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import pandas as pd
|
|
2
|
+
|
|
3
|
+
from pydpeet.io.configs.const import PANDAS_EXCEL_ENGINE
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def to_dataframe(input_path: str) -> tuple[pd.DataFrame, str]:
|
|
7
|
+
"""
|
|
8
|
+
Parses the input file from the Arbin Cycler into a pandas DataFrame.
|
|
9
|
+
|
|
10
|
+
Parameters:
|
|
11
|
+
input_path (str): Path to the input file.
|
|
12
|
+
|
|
13
|
+
Returns:
|
|
14
|
+
(pandas.DataFrame, str): A tuple containing the DataFrame with data and metadata as a string.
|
|
15
|
+
"""
|
|
16
|
+
# load Excel data
|
|
17
|
+
excel_data = pd.ExcelFile(input_path, engine=PANDAS_EXCEL_ENGINE)
|
|
18
|
+
|
|
19
|
+
return read_sheets(excel_data)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def read_sheets(excel_file: pd.ExcelFile) -> tuple[pd.DataFrame, str]:
|
|
23
|
+
"""
|
|
24
|
+
Reads data from all sheets in an Excel file and returns them as a tuple of a DataFrame and a string.
|
|
25
|
+
|
|
26
|
+
The first sheet that starts with "Detail" is used as the main data sheet. If there are more sheets with this name,
|
|
27
|
+
they are appended to the first sheet.
|
|
28
|
+
|
|
29
|
+
All other sheets are concatenated into a single string as metadata.
|
|
30
|
+
|
|
31
|
+
Parameters:
|
|
32
|
+
excel_file (pd.ExcelFile): The Excel file to read from.
|
|
33
|
+
|
|
34
|
+
Returns:
|
|
35
|
+
(pd.DataFrame, str): A tuple containing the DataFrame with data and metadata as a string.
|
|
36
|
+
"""
|
|
37
|
+
# variables for the dataframe and String
|
|
38
|
+
arbin_df = None
|
|
39
|
+
metadata_str = []
|
|
40
|
+
iterator = 0
|
|
41
|
+
|
|
42
|
+
# iterate all sheets
|
|
43
|
+
for sheet_name in excel_file.sheet_names:
|
|
44
|
+
# find sheet that starts with "Detail"
|
|
45
|
+
if sheet_name.startswith("Detail"):
|
|
46
|
+
# if it´s the first sheet, that starts with the channel, it gets added to df
|
|
47
|
+
if iterator == 0:
|
|
48
|
+
arbin_df = excel_file.parse(sheet_name, header=0)
|
|
49
|
+
# if it´s the second or higher Sheet, it will be appended without the header and the first row,
|
|
50
|
+
# because first row of 2nd sheet and last row of first sheet are the same
|
|
51
|
+
else:
|
|
52
|
+
# get Data from further Sheet(s)
|
|
53
|
+
# remove the first two rows (header and multiple row)
|
|
54
|
+
further_sheet_data = excel_file.parse(sheet_name, header=0).iloc[1:]
|
|
55
|
+
# concat bot sheets into one
|
|
56
|
+
arbin_df = pd.concat([arbin_df, further_sheet_data])
|
|
57
|
+
iterator += 1
|
|
58
|
+
else: # combine all other sheets into a string as metadata
|
|
59
|
+
sheet_data = excel_file.parse(sheet_name, header=None) # no header
|
|
60
|
+
sheet_str = f"Sheet: {sheet_name}\n{sheet_data.to_string(index=False, header=False)}"
|
|
61
|
+
metadata_str.append(sheet_str)
|
|
62
|
+
|
|
63
|
+
# combine all metadata sheets into one string
|
|
64
|
+
metadata_str_combined = "\n\n".join(metadata_str)
|
|
65
|
+
|
|
66
|
+
return arbin_df, metadata_str_combined
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import pandas as pd
|
|
2
|
+
|
|
3
|
+
from pydpeet.io.utils.formatter_utils import round_testtime, testtime_hours_to_seconds_direct
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def get_data_into_format(df: pd.DataFrame) -> pd.DataFrame:
|
|
7
|
+
"""
|
|
8
|
+
Takes a pandas DataFrame and applies two functions to it:
|
|
9
|
+
|
|
10
|
+
1. `testtime_hours_to_seconds_direct`: converts the "Test_Time[s]" column from hours to seconds with string interpretation.
|
|
11
|
+
2. `round_testtime`: rounds the "Test_Time[s]" column down to the nearest second.
|
|
12
|
+
|
|
13
|
+
Returns the modified DataFrame.
|
|
14
|
+
"""
|
|
15
|
+
df = testtime_hours_to_seconds_direct(df)
|
|
16
|
+
df = round_testtime(df)
|
|
17
|
+
|
|
18
|
+
return df
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# Map raw-data column names (left) to standardized column names (right)
|
|
2
|
+
COLUMN_MAP = {
|
|
3
|
+
"Time[h]": "Test_Time[s]",
|
|
4
|
+
"U[V]": "Voltage[V]",
|
|
5
|
+
"I[A]": "Current[A]",
|
|
6
|
+
"T1[°C]": "Temperature[°C]",
|
|
7
|
+
"Line": "Step_Count",
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
# Default columns of the standardized format
|
|
11
|
+
# which are not present in the raw data files.
|
|
12
|
+
MISSING_REQUIRED_COLUMNS = [
|
|
13
|
+
"Date_Time",
|
|
14
|
+
"EIS_f[Hz]",
|
|
15
|
+
"EIS_Z_Real[Ohm]",
|
|
16
|
+
"EIS_Z_Imag[Ohm]",
|
|
17
|
+
"EIS_DC[A]",
|
|
18
|
+
]
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
from io import StringIO
|
|
3
|
+
|
|
4
|
+
import pandas as pd
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def to_dataframe(input_path: str) -> tuple[pd.DataFrame, str]:
|
|
8
|
+
"""
|
|
9
|
+
Parses the input file from the basytec cycler into a pandas DataFrame.
|
|
10
|
+
It first converts the data portion to CSV format in memory.
|
|
11
|
+
|
|
12
|
+
Parameters:
|
|
13
|
+
input_path (str): Path to the input file.
|
|
14
|
+
|
|
15
|
+
Returns:
|
|
16
|
+
(pd.DataFrame, str): A tuple containing the DataFrame with the data and metadata as a string.
|
|
17
|
+
"""
|
|
18
|
+
with open(input_path, encoding="iso-8859-1") as file:
|
|
19
|
+
lines = file.readlines()
|
|
20
|
+
|
|
21
|
+
# Collect all metadata lines (those starting with '~')
|
|
22
|
+
metadata_lines = []
|
|
23
|
+
data_start_idx = 0
|
|
24
|
+
for idx, line in enumerate(lines):
|
|
25
|
+
if line.startswith("~"):
|
|
26
|
+
metadata_lines.append(line.strip())
|
|
27
|
+
else:
|
|
28
|
+
data_start_idx = idx
|
|
29
|
+
break
|
|
30
|
+
|
|
31
|
+
if not metadata_lines:
|
|
32
|
+
logging.warning("The file does not contain expected metadata lines starting with '~'.")
|
|
33
|
+
|
|
34
|
+
# The last metadata line is used as the header; remove it from metadata_lines.
|
|
35
|
+
header_line = metadata_lines.pop().lstrip("~").strip()
|
|
36
|
+
headers = header_line.split()
|
|
37
|
+
|
|
38
|
+
# Join the remaining metadata lines into a single string.
|
|
39
|
+
metadata_str = "\n".join(metadata_lines)
|
|
40
|
+
|
|
41
|
+
# Convert the remaining data lines into CSV format.
|
|
42
|
+
csv_lines = [",".join(headers)] # CSV header
|
|
43
|
+
for line in lines[data_start_idx:]:
|
|
44
|
+
line = line.strip()
|
|
45
|
+
if line: # Skip empty lines.
|
|
46
|
+
# Split on whitespace then join with commas.
|
|
47
|
+
csv_lines.append(",".join(line.split()))
|
|
48
|
+
|
|
49
|
+
csv_content = "\n".join(csv_lines)
|
|
50
|
+
|
|
51
|
+
# Use StringIO to read the CSV content into a DataFrame.
|
|
52
|
+
df = pd.read_csv(StringIO(csv_content))
|
|
53
|
+
|
|
54
|
+
return df, metadata_str
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import pandas as pd
|
|
2
|
+
|
|
3
|
+
from pydpeet.io.utils.formatter_utils import absolute_time_timedate_typecast, fix_time_format
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def get_data_into_format(df: pd.DataFrame) -> pd.DataFrame:
|
|
7
|
+
"""
|
|
8
|
+
Applies a series of transformations to the input DataFrame to
|
|
9
|
+
ensure that the "Date_Time" column is in the correct
|
|
10
|
+
datetime format. The time format is initially fixed using the specified
|
|
11
|
+
input format, and then typecast to pandas datetime objects.
|
|
12
|
+
|
|
13
|
+
Parameters
|
|
14
|
+
----------
|
|
15
|
+
data_frame : pd.DataFrame
|
|
16
|
+
The DataFrame to be formatted.
|
|
17
|
+
|
|
18
|
+
Returns
|
|
19
|
+
-------
|
|
20
|
+
pd.DataFrame
|
|
21
|
+
The formatted DataFrame with the "Date_Time"
|
|
22
|
+
column converted to datetime objects.
|
|
23
|
+
"""
|
|
24
|
+
fix_time_format(df, input_format="%d.%m.%Y %H:%M:%S")
|
|
25
|
+
absolute_time_timedate_typecast(df)
|
|
26
|
+
|
|
27
|
+
return df
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# Map raw-data column names (left) to standardized column names (right)
|
|
2
|
+
COLUMN_MAP = {
|
|
3
|
+
"Schritt Zeit": "Test_Time[s]",
|
|
4
|
+
"Spannung": "Voltage[V]",
|
|
5
|
+
"Strom": "Current[A]",
|
|
6
|
+
"Schritt Nr.": "Step_Count",
|
|
7
|
+
"Zeitstempel": "Date_Time",
|
|
8
|
+
"T_Batt": "Temperature[°C]",
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
# Default columns of the standardized format
|
|
12
|
+
# which are not present in the raw data files.
|
|
13
|
+
MISSING_REQUIRED_COLUMNS = [
|
|
14
|
+
"EIS_f[Hz]",
|
|
15
|
+
"EIS_Z_Real[Ohm]",
|
|
16
|
+
"EIS_Z_Imag[Ohm]",
|
|
17
|
+
"EIS_DC[A]",
|
|
18
|
+
]
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import pandas as pd
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def to_dataframe(input_path: str) -> tuple[pd.DataFrame, str]:
|
|
5
|
+
"""
|
|
6
|
+
Parses the input file from the Digatron Cycler into a pandas DataFrame.
|
|
7
|
+
|
|
8
|
+
Parameters:
|
|
9
|
+
input_path (str): Path to the input file.
|
|
10
|
+
|
|
11
|
+
Returns:
|
|
12
|
+
(pandas.DataFrame, str): A tuple containing the DataFrame with data and metadata as a string.
|
|
13
|
+
"""
|
|
14
|
+
metadata = []
|
|
15
|
+
|
|
16
|
+
# Open the file and process lines
|
|
17
|
+
with open(input_path, encoding="us-ascii") as file:
|
|
18
|
+
# Read metadata until the header line is found
|
|
19
|
+
line = file.readline()
|
|
20
|
+
while not line.startswith("Zeitstempel"):
|
|
21
|
+
metadata.append(line.strip())
|
|
22
|
+
line = file.readline()
|
|
23
|
+
|
|
24
|
+
# Extract headers and remaining data
|
|
25
|
+
headers = line.strip().split(";")
|
|
26
|
+
data_lines = [row.strip().split(";") for row in file if row.strip()]
|
|
27
|
+
|
|
28
|
+
# appending first string from datalines
|
|
29
|
+
metadata.append(";".join(data_lines.pop(0)))
|
|
30
|
+
|
|
31
|
+
# Join metadata into a single string
|
|
32
|
+
metadata_str = "\n".join(metadata)
|
|
33
|
+
|
|
34
|
+
# Create DataFrame
|
|
35
|
+
df = pd.DataFrame(data_lines, columns=headers)
|
|
36
|
+
|
|
37
|
+
# Convert numeric columns to appropriate types
|
|
38
|
+
for col in headers:
|
|
39
|
+
try:
|
|
40
|
+
df[col] = pd.to_numeric(df[col])
|
|
41
|
+
except ValueError:
|
|
42
|
+
# Leave non-numeric columns as is
|
|
43
|
+
pass
|
|
44
|
+
|
|
45
|
+
return df, metadata_str
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import pandas as pd
|
|
2
|
+
|
|
3
|
+
from pydpeet.io.utils.formatter_utils import (
|
|
4
|
+
absolute_time_timedate_typecast,
|
|
5
|
+
apply_convert_to_float_if_possible,
|
|
6
|
+
move_strings_from_column_to_metadata,
|
|
7
|
+
nan_to_none_in_column,
|
|
8
|
+
replace_empty_with_none_in_standard_columns,
|
|
9
|
+
round_testtime,
|
|
10
|
+
typecast,
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def get_data_into_format(df: pd.DataFrame) -> pd.DataFrame:
|
|
15
|
+
"""
|
|
16
|
+
Format the given DataFrame into a standard format.
|
|
17
|
+
|
|
18
|
+
Parameters
|
|
19
|
+
----------
|
|
20
|
+
data_frame : pandas.DataFrame
|
|
21
|
+
The DataFrame to be formatted
|
|
22
|
+
|
|
23
|
+
Returns
|
|
24
|
+
-------
|
|
25
|
+
pandas.DataFrame
|
|
26
|
+
The formatted DataFrame
|
|
27
|
+
"""
|
|
28
|
+
df = replace_empty_with_none_in_standard_columns(df)
|
|
29
|
+
typecast(df, "Step_Count", int)
|
|
30
|
+
df = apply_convert_to_float_if_possible(df, "Voltage[V]")
|
|
31
|
+
df = apply_convert_to_float_if_possible(df, "Current[A]")
|
|
32
|
+
df = round_testtime(df)
|
|
33
|
+
df = absolute_time_timedate_typecast(df)
|
|
34
|
+
typecast(df, "EIS_Z_Real[Ohm]", float)
|
|
35
|
+
typecast(df, "EIS_Z_Imag[Ohm]", float)
|
|
36
|
+
df = nan_to_none_in_column(df, "Current[A]")
|
|
37
|
+
df = move_strings_from_column_to_metadata(df, "Voltage[V]")
|
|
38
|
+
|
|
39
|
+
return df
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# Map raw-data column names (left) to standardized column names (right)
|
|
2
|
+
COLUMN_MAP = {
|
|
3
|
+
"Zreal1": "EIS_Z_Real[Ohm]",
|
|
4
|
+
"Zimg1": "EIS_Z_Imag[Ohm]",
|
|
5
|
+
"Zeitstempel": "Date_Time",
|
|
6
|
+
"Schritt Nr.": "Step_Count",
|
|
7
|
+
"Spannung": "Voltage[V]",
|
|
8
|
+
"Strom": "Current[A]",
|
|
9
|
+
"Progr. Zeit": "Test_Time[s]",
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
# Default columns of the standardized format
|
|
13
|
+
# which are not present in the raw data files.
|
|
14
|
+
MISSING_REQUIRED_COLUMNS = [
|
|
15
|
+
"Temperature[°C]",
|
|
16
|
+
"EIS_f[Hz]",
|
|
17
|
+
"EIS_DC[A]",
|
|
18
|
+
]
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import pandas as pd
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def to_dataframe(input_path: str) -> tuple[pd.DataFrame, str]:
|
|
5
|
+
"""
|
|
6
|
+
Parses the input file from the Digatron Cycler into a pandas DataFrame.
|
|
7
|
+
|
|
8
|
+
Parameters:
|
|
9
|
+
input_path (str): Path to the input file.
|
|
10
|
+
|
|
11
|
+
Returns:
|
|
12
|
+
(pandas.DataFrame, str): A tuple containing the DataFrame with data and metadata as a string.
|
|
13
|
+
"""
|
|
14
|
+
metadata = []
|
|
15
|
+
|
|
16
|
+
# Open the file and process lines
|
|
17
|
+
with open(input_path, encoding="iso-8859-1") as file:
|
|
18
|
+
# Read metadata until the header line is found
|
|
19
|
+
line = file.readline()
|
|
20
|
+
while not line.startswith("Zeitstempel"):
|
|
21
|
+
metadata.append(line.strip())
|
|
22
|
+
line = file.readline()
|
|
23
|
+
|
|
24
|
+
# Extract headers and remaining data
|
|
25
|
+
headers = line.strip().split(",")
|
|
26
|
+
# TODO: Why is this still here?
|
|
27
|
+
# for i in range(4):
|
|
28
|
+
# line = file.readline()
|
|
29
|
+
# metadata.append(line.strip())
|
|
30
|
+
|
|
31
|
+
data_lines = [row.strip().split(",") for row in file if row.strip()]
|
|
32
|
+
|
|
33
|
+
# appending first string from datalines
|
|
34
|
+
metadata.append(";".join(data_lines.pop(0)))
|
|
35
|
+
|
|
36
|
+
# Join metadata into a single string
|
|
37
|
+
metadata_str = "\n".join(metadata)
|
|
38
|
+
|
|
39
|
+
# Create DataFrame
|
|
40
|
+
df = pd.DataFrame(data_lines, columns=headers)
|
|
41
|
+
|
|
42
|
+
return df, metadata_str
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import pandas as pd
|
|
2
|
+
|
|
3
|
+
from pydpeet.io.utils.formatter_utils import (
|
|
4
|
+
absolute_time_timedate_typecast,
|
|
5
|
+
testtime_hours_to_seconds_with_string_interpretation,
|
|
6
|
+
typecast,
|
|
7
|
+
)
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def get_data_into_format(df: pd.DataFrame) -> pd.DataFrame:
|
|
11
|
+
"""
|
|
12
|
+
Format a DataFrame from a Neware cycler into a standard format.
|
|
13
|
+
|
|
14
|
+
The DataFrame is modified in-place.
|
|
15
|
+
|
|
16
|
+
Parameters
|
|
17
|
+
----------
|
|
18
|
+
data_frame : pd.DataFrame
|
|
19
|
+
DataFrame to be formatted
|
|
20
|
+
|
|
21
|
+
Returns
|
|
22
|
+
-------
|
|
23
|
+
pd.DataFrame
|
|
24
|
+
Formatted DataFrame
|
|
25
|
+
"""
|
|
26
|
+
testtime_hours_to_seconds_with_string_interpretation(df, True)
|
|
27
|
+
df = absolute_time_timedate_typecast(df)
|
|
28
|
+
typecast(df, "Step_Count", int)
|
|
29
|
+
typecast(df, "Temperature[°C]", float)
|
|
30
|
+
|
|
31
|
+
return df
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# Map raw-data column names (left) to standardized column names (right)
|
|
2
|
+
COLUMN_MAP = {
|
|
3
|
+
"step_id": "Step_Count",
|
|
4
|
+
"Voltage(V)": "Voltage[V]",
|
|
5
|
+
"Current[A] - record": "Current[A]",
|
|
6
|
+
"T1": "Temperature[°C]",
|
|
7
|
+
"Total Time": "Test_Time[s]",
|
|
8
|
+
"Date": "Date_Time",
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
# Default columns of the standardized format
|
|
12
|
+
# which are not present in the raw data files.
|
|
13
|
+
MISSING_REQUIRED_COLUMNS = [
|
|
14
|
+
"EIS_f[Hz]",
|
|
15
|
+
"EIS_Z_Real[Ohm]",
|
|
16
|
+
"EIS_Z_Imag[Ohm]",
|
|
17
|
+
"EIS_DC[A]",
|
|
18
|
+
]
|