メインコンテンツへスキップ
アップロードの前に、サイクラーからの生データを Ionworks データフォーマットに変換する必要があります。ionworksdata ライブラリは、一般的なバッテリーサイクラーのファイルを読み取り、形式を自動検出し、単位、タイムスタンプ、列名を正規化します。
pip install ionworksdata

サポートされるサイクラー

ionworksdata は可能な限りファイル形式を自動検出し、標準列を持つ polars DataFrame を生成します。
サイクラーファイル種別
Arbin.csv.xlsx.res
BaSyTec.csv
BioLogic.mpt.mpr.txt
Maccor.txt.csv.xls.xlsx
Neware.csv.xls.xlsx(マルチシート対応、CSV では Latin-1 へ自動フォールバック)
Novonix.csv
Repower.csv
汎用 CSV.csv(認識される列ヘッダーまたはカスタムマッピングを持つ任意の CSV)
汎用 Parquet.parquet(認識される列ヘッダーまたはカスタムマッピングを持つ任意の parquet ファイル)
BDF (Battery Data Format).bdf.bdf.gz.bdf.parquet.csv
import ionworksdata as iwd

df = iwd.read.time_series("my_test.mpt", "biologic")

カスタム列マッピング

CSV が非標準の列名を使用している場合は、extra_column_mappings で標準名にマップします。明示的にマップした列については、リーダーは自動検出をスキップし、値はリスケールなしでそのまま使用されます。
import ionworksdata as iwd

df = iwd.read.time_series(
    "my_data.csv",
    "csv",
    extra_column_mappings={
        "vCell": "Voltage [V]",
        "iCell": "Current [A]",
        "t": "Time [s]",
        "Tcell": "Temperature [degC]",
    },
)
部分的なマッピングも機能します。マップしない標準列は引き続き自動検出されます:
df = iwd.read.time_series(
    "my_data.csv",
    "csv",
    extra_column_mappings={"vCell": "Voltage [V]"},
)
カスタムのテストセットアップや独自仕様のサイクラーから来た CSV では extra_column_mappings を使用してください。マップされた値はそのまま保持され、単位変換やスケーリングは適用されません。このパラメータを使う前に、データが期待される標準単位(V、A、s、°C)になっていることを確認してください。

汎用 parquet ファイル

BDF 仕様に従わない parquet ファイルには、汎用 parquet リーダーを使用します。これは CSV リーダーの列検出戦略をミラーし、電圧、電流、時間、温度の一般的なエイリアスを認識しますが、parquet は強く型付けされていて列名が曖昧でないため、テキスト解析関連の処理はスキップします。区切り文字、エンコーディング、引用符の処理は不要です。 すでに parquet にエクスポートされたサイクラーデータ(例: 社内パイプラインや他のツールからのもの)を Ionworks データフォーマットに正規化したい場合に使用してください。 すべての .parquet ファイルは自動検出されます。リーダーを明示的に指定することもできます:
import ionworksdata as iwd

# Auto-detected by extension
df = iwd.read.time_series("cell.parquet")

# Or call the reader directly
df = iwd.read.parquet("cell.parquet")
ファイルが非標準の列名を使用している場合は、CSV リーダーと同じように extra_column_mappings を渡します:
df = iwd.read.parquet(
    "cell.parquet",
    extra_column_mappings={
        "vCell": "Voltage [V]",
        "iCell": "Current [A]",
        "t": "Time [s]",
    },
)
BDF の parquet ファイル(.bdf.parquet)は引き続き BDF リーダーにルーティングされます。汎用 parquet リーダーは BDF でない .parquet ファイルのフォールバックとしてのみ使用されます。

Battery Data Format (BDF)

ionworksdata は Battery Data Alliance が定義する Battery Data Format (BDF) のファイルを読み書きできます。CSV、gzip 圧縮 CSV、parquet のすべてのバリアントがサポートされます。ファイルはヘッダーまたは拡張子(.bdf.bdf.gz.bdf.parquet)で自動検出されます。
import ionworksdata as iwd

# Read
df = iwd.read.bdf("cell.bdf")
df = iwd.read.time_series("cell.bdf.parquet")  # via the generic entrypoint

# Write
iwd.write.bdf(df, "out.bdf")                  # CSV with preferred labels
iwd.write.bdf(df, "out.bdf.gz")               # gzipped CSV
iwd.write.bdf(df, "out.bdf.parquet")          # parquet
iwd.write.bdf(df, "out.bdf", use_machine_readable_names=True)
BDF は電流の符号規約を強制しません。リーダーは読み込み時に電流を Ionworks の規約(正 = 放電)に正規化するため、反対の IEC 規約に従うサードパーティの BDF ファイルは自動的に反転されます。ライターは入力 DataFrame の規約をそのまま出力します。放電が正の出力を保証する必要がある場合は、まず transform.set_positive_current_for_discharge でデータを通してください。

EIS とインピーダンスデータ

計測機ファイル種別
BioLogic.mpt.mpr.txt(インピーダンス列を含むファイル)
Gamry.dta(ZCURVE テーブル)
インピーダンスデータは Frequency [Hz]Z_Re [Ohm]Z_Im [Ohm]Z_Mod [Ohm]Z_Phase [deg] 列に読み込まれます。
import ionworksdata as iwd

df = iwd.read.gamry("eis_measurement.dta")
完全な列仕様と符号規約はデータフォーマットページを参照してください。

トラブルシューティング

不正な電流符号規約

問題: 測定データをアップロードする際に、次のようなエラーが発生する:
Current sign convention error: positive current appears to be charge, not discharge.
解決策: Ionworks は 正の電流 = 放電負の電流 = 充電 を想定しています。サイクラーが反対の規約を使用している場合は、アップロード前にデータを変換します:
import ionworksdata as iwd

data = iwd.transform.set_positive_current_for_discharge(data)

曖昧な電流符号規約

問題: 測定データをアップロードする際に、次のようなエラーが発生する:
Current sign convention error: the sign convention is ambiguous.
これは、すべての電流値が同じ符号を持っており、正が充電か放電かをバリデータが判定できない場合に発生します。 解決策: 同じ変換を使用します。電圧応答解析(両方の符号規約で OCV-R 等価回路モデルを当てはめる)を用いて、すべての電流が同じ符号を共有していても充電と放電の方向を推論します:
import ionworksdata as iwd

data = iwd.transform.set_positive_current_for_discharge(data)
自動アプローチでデータに対してうまく動作しない(例えば平坦な電圧プロファイル)場合は、サイクラーのステップ種別列に基づいて符号を手動で適用できます:
import polars as pl

# Replace "Step type" and "charge" with your cycler's column name
# and step-type label (e.g. "CC_Charge", "Charge", "C", etc.)
data = data.with_columns(
    pl.when(pl.col("Step type") == "charge")
    .then(-pl.col("Current [A]").abs())
    .otherwise(pl.col("Current [A]").abs())
    .alias("Current [A]")
)

充電と放電の累積列が入れ替わっている

問題: validate_strict=True でアップロードする際に、次のようなエラーが発生する:
Column ‘Discharge capacity [A.h]’ disagrees with the running integral of ‘max(I, 0)’ over time by up to 96.4% (exceeds 10% tolerance).
…そして、報告されている Discharge capacity [A.h] が充電半波を追跡しているように見え、Charge capacity [A.h] でも同じく反転した挙動が見られる。これは一部のハーフセル出力や、2 つの累積列を逆にラベル付けするサイクラー設定で発生します。 解決策: fix_swapped_charge_discharge_columns を使用して、各列を電流(およびエネルギーの場合は電力)の台形積分と比較し、入れ替えた割り当てが許容範囲内で、そのままの割り当てが許容範囲外の場合にペアの名前を変更します。
import ionworksdata as iwd

# Required prerequisite — without a known sign convention, "Discharge" vs
# "Charge" has no ground-truth meaning to compare against.
data = iwd.transform.set_positive_current_for_discharge(data)

# Inspects "Discharge/Charge capacity [A.h]" and, when present,
# "Discharge/Charge energy [W.h]". Returns `data` unchanged when no swap
# is warranted.
data = iwd.transform.fix_swapped_charge_discharge_columns(data)
変換には Time [s]Step countCurrent [A] の列が必要で、エネルギーペアには Power [W](または Power [W] がない場合は Voltage [V] * Current [A])を使用します。デフォルトの tolerance は相対誤差 10 % です。データに対してより厳しい/緩い閾値が必要な場合は、別の値を渡してください:
data = iwd.transform.fix_swapped_charge_discharge_columns(data, tolerance=0.05)
この関数は、正の電流が放電に対応しない場合はラベルの入れ替えを拒否します。既知の符号規約がなければどちらの列がどちらかを判別する手段がなく、入れ替えは本物の符号規約バグをマスクしてしまうためです。最初に set_positive_current_for_discharge を実行してください。

時間が累積でない

問題: 各サイクルで時間が 0 にリセットされる。 解決策: 累積時間オフセットを追跡します:
cumulative_time_offset = 0.0
for cycle_num, cycle_df in df.group_by("Cycle from cycler"):
    cycle_df = cycle_df.with_columns(
        (pl.col("Time [s]") + cumulative_time_offset).alias("Time [s]")
    )
    cumulative_time_offset = cycle_df["Time [s]"].max()

ステップカウントが累積でない

問題: 各サイクルでステップカウントがリセットされる。 解決策: サイクル間でステップカウントオフセットを追跡します:
step_offset = 0
for cycle_num, cycle_df in df.group_by("Cycle count"):
    cycle_df = cycle_df.with_columns(
        (pl.col("Step from cycler") + step_offset).alias("Step count")
    )
    step_offset = cycle_df["Step count"].max() + 1

容量列の欠落

問題: 容量の計算に失敗する。 解決策: 容量を計算する前に Time [s]Current [A]Voltage [V] の列があることを確認してください。

UTF-8 でない CSV ファイル(例: Neware)

問題: Neware の CSV ファイルの読み込みがエンコーディングエラーで失敗する。 解決策: Neware リーダーは UTF-8 デコードが失敗した場合に自動的に Latin-1 にフォールバックするため、ほとんどの場合アクションは不要です:
import ionworksdata as iwd

df = iwd.read.time_series("neware_data.csv", "neware")
エンコーディングを明示的に制御するには:
df = iwd.read.time_series(
    "neware_data.csv",
    "neware",
    options={"file_encoding": "latin-1"},
)

次のステップ

データフォーマット

認識される列、単位、符号規約の完全なリファレンスです。

データのアップロード

準備したデータをセル仕様、インスタンス、測定としてアップロードします。

ionworksdata API リファレンス

readwritetransformstepsload の完全なリファレンスです。

GitHub の ionworksdata

問題を報告したり、ソースを閲覧したりできます。