Metadata-Version: 2.4
Name: celllib
Version: 0.2.0
Summary: Библиотека для обработки данных циклирования аккумуляторных ячеек
Project-URL: Homepage, https://github.com/JolyPug/celllib
Project-URL: Repository, https://github.com/JolyPug/celllib
Project-URL: Issues, https://github.com/JolyPug/celllib/issues
Author-email: dimaniche15@gmail.com
License-Expression: MIT
License-File: LICENSE
Classifier: Intended Audience :: Science/Research
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: Scientific/Engineering
Requires-Python: >=3.10
Requires-Dist: matplotlib>=3.7
Requires-Dist: numpy>=2.0
Requires-Dist: pandas>=2.0
Requires-Dist: scipy>=1.10
Provides-Extra: dev
Requires-Dist: pytest>=7.4; extra == 'dev'
Provides-Extra: excel
Requires-Dist: openpyxl>=3.1; extra == 'excel'
Description-Content-Type: text/markdown

# celllib

Библиотека для обработки данных циклирования аккумуляторных ячеек: разбивка
на циклы, ёмкость/энергия/CE, dQ/dV, кривая деградации, SPC и отбраковка,
валидация сырых логов.

## Установка

```bash
pip install -e ".[dev]"
# для чтения .xlsx (CLI): pip install -e ".[dev,excel]"
```

## CLI — отчёт без единой строчки Python

```bash
celllib analyze log.csv                                    # -> log_report.html
celllib analyze batch.xlsx --sheet raw_measurements \
    --cell-id-col cell_id --out batch_report.pdf
```

Если имена колонок в файле уже совпадают со схемой celllib — маппинг не
нужен, определяется автоматически (с проверкой, что колонка приводится к
нужному типу, а не просто совпадает по имени). Иначе:

```bash
celllib analyze log.csv --mapping mapping.json --out report.html
# mapping.json: {"time_s": "Test Time(s)", "voltage_v": "Voltage(V)", ...}
```

`--cell-id-col` (или колонка `cell_id`, если в файле больше одной ячейки)
переключает отчёт в батч-режим: сравнение партии, отбраковка по ёмкости,
профиль деградации (`fingerprint`), обучение и кросс-валидация RUL-модели —
или честное "недостаточно ячеек дошло до EOL", если обучить не на чем.
Формат отчёта — по расширению `--out` (`.html`/`.pdf`), HTML самодостаточен
(графики встроены как base64, без CDN), PDF — через matplotlib, без новых
зависимостей.

## Разработка и релизы

Вся разработка идёт в ветке `dev` (через PR туда — обычные коммиты).
`master` защищена: принимает изменения только через Pull Request из `dev`
с зелёным CI (`test (3.10)` … `test (3.13)`), прямой push запрещён.
Публикация на PyPI (`.github/workflows/publish.yml`) запускается созданием
GitHub Release из `master` — версия в `pyproject.toml` должна быть
предварительно поднята.

## Модель данных

Вся библиотека работает с одним `pandas.DataFrame`, приведённым к
канонической схеме (`celllib.schema`):

| колонка      | обязательна | описание                              |
|--------------|-------------|----------------------------------------|
| `time_s`     | да          | время от начала теста, с               |
| `voltage_v`  | да          | напряжение, В                          |
| `current_a`  | да          | ток, А (>0 заряд, <0 разряд)           |
| `cycle`      | да          | номер цикла                            |
| `step_type`  | нет         | `"charge"` / `"discharge"` / `"rest"`  |
| `capacity_ah`| нет         | накопленная ёмкость шага, А·ч          |
| `energy_wh`  | нет         | накопленная энергия шага, Вт·ч         |
| `temperature_c` | нет      | температура, °C                        |

Любой формат оборудования приводится к этой схеме через `celllib.io`:

```python
import celllib as cl

mapping = {
    "time_s": "Test Time(s)",
    "voltage_v": "Voltage(V)",
    "current_a": "Current(A)",
    "cycle": "Cycle Index",
}
df = cl.io.read_csv("raw_log.csv", mapping=mapping, step_type_from_current=True)
```

Дальше вся библиотека работает только с этой схемой — источник данных
её не интересует.

## Типичный пайплайн

```python
import celllib as cl

report = cl.validate.validate(df)
assert report["is_clean"]

summary = cl.cycling.summarize_cycles(df)
summary = cl.analysis.capacity_fade(summary)
fade = cl.analysis.fade_rate(summary)

limits = cl.qc.spc_individuals_limits(summary["discharge_capacity_ah"])
bad_cycles = cl.qc.spc_violations(summary["discharge_capacity_ah"])

cl.report.plot_fade_curve(summary)
cl.report.summary_table(summary, fade_stats=fade)
```

## Принципы

- **Чистые функции без состояния.** Каждая функция принимает DataFrame
  (или Series) и возвращает результат — никаких глобальных переменных,
  скрытых файлов или побочных эффектов.
- **Единая схема данных** развязывает обработку от формата оборудования.
- **Минимум зависимостей**: numpy, pandas, scipy, matplotlib — всё, что
  обычно уже есть в закрытом окружении.

## Модули

- `io` — чтение и приведение сырых логов к канонической схеме.
- `cycling` — разбивка на циклы, ёмкость, энергия, CE.
- `analysis` — dQ/dV, кривая деградации, скорость деградации.
- `qc` — SPC-карты (I-MR), поиск выбросов, отбраковка партии ячеек.
- `validate` — пропуски, немонотонность времени, разрывы выборки, диапазоны значений.
- `fingerprint` — эвристическое разложение деградации на LLI/LAM/рост сопротивления по dQ/dV.
- `rul` — прогноз ресурса по ранним циклам (Severson-style): признаки, разметка EOL, Ridge + cross-validation.
- `report` — графики (fade curve, CE, dQ/dV, SPC), сводные таблицы, автогенерация HTML/PDF-отчёта.
- `cli` — `celllib analyze` из терминала, обёртка над `report.save_report`.
- `utils` — общие численные хелперы (интерполяция на сетку).

## Тесты

```bash
pytest
```

## Проверка на реальных данных

`scripts/validate_real_data.py` прогоняет библиотеку на экспортированном
логе (лист `raw_measurements`) и сверяет посчитанную ёмкость/CE с готовым
эталоном (лист `cycle_summary`), если он есть:

```bash
python scripts/validate_real_data.py path/to/log.xlsx CELL_001
```

Скрипт также считает SPC-пределы и печатает сводную таблицу — по нему
удобно смотреть на реальных данных, что означают числа на выходе каждого
модуля.

Два момента, которые стоит понимать при работе с реальными логами:

- **Интегрирование ёмкости/энергии** учитывает типичный артефакт логов с
  фиксированным интервалом записи: первая точка нового шага (charge/
  discharge) обычно фиксируется на один интервал позже его фактического
  начала. `cycling.py` компенсирует это, продлевая трапецию до последней
  точки предыдущего сегмента — без этого ёмкость систематически
  занижается (в проверке на реальных данных ошибка уходила с ~3-4% до
  <0.1%, кроме самого первого сегмента в логе, где предыдущей точки
  просто нет).
- **`qc.spc_individuals_limits` / `spc_violations`** — это I-MR карта,
  она предполагает стабильный процесс без тренда. Применять её напрямую
  к кривой деградации ёмкости одной ячейки по циклам не стоит — тренд
  сам по себе даст много "нарушений". Годится для двух сценариев:
  сравнения ячеек партии между собой на фиксированном цикле
  (`qc.cross_cell_outliers`, см. пример в README выше) или для поиска
  резких точек разрыва во временном ряду одной ячейки после
  детрендирования.
