zenvolt-api / format_detector.py
happynickamazon's picture
Upload 45 files
dc610d2 verified
Raw History Blame Contribute Delete
6.8 kB
"""
Battery Data Format Detector
Auto-detects NASA vs Stanford format with validation.
MIT/Stanford Quality: Robust format detection with confidence scoring.
"""
import pandas as pd
import numpy as np
from typing import Literal, Dict
def detect_battery_format(
data: pd.DataFrame,
confidence_threshold: float = 0.8
) -> Dict[str, any]:
"""
Automatically detect battery data format (NASA vs Stanford).
NASA format: cycle_index, voltage, current, temperature, capacity
Stanford format: 99 columns of voltage discharge curve values
Parameters:
-----------
data : DataFrame
Battery data to detect format
confidence_threshold : float
Minimum confidence required (default 0.8)
Returns:
--------
dict: {
'format': 'nasa' | 'stanford' | 'unknown',
'confidence': float,
'reason': str,
'details': dict
}
"""
detection_scores = {
'nasa': 0.0,
'stanford': 0.0
}
details = {
'columns': list(data.columns),
'shape': data.shape,
'column_count': len(data.columns)
}
# Check 1: Column names
nasa_required_cols = {'cycle_index', 'voltage', 'current', 'temperature', 'capacity'}
nasa_cols_present = sum(1 for col in nasa_required_cols if col in data.columns)
if nasa_cols_present == 5:
detection_scores['nasa'] += 0.5 # Strong indicator
elif nasa_cols_present >= 3:
detection_scores['nasa'] += 0.3 # Moderate indicator
# Check 2: Column count
# Stanford has exactly 99 columns (voltage measurements)
if len(data.columns) == 99:
detection_scores['stanford'] += 0.4
elif len(data.columns) > 50: # Likely voltage array
detection_scores['stanford'] += 0.2
if len(data.columns) == 5:
detection_scores['nasa'] += 0.3
# Check 3: Data patterns
# Stanford values are small (voltage deltas, typically < 0.01)
# NASA values are absolute (voltage 3-4V, current 0-2A, etc.)
if len(data.columns) > 0:
first_col_values = data.iloc[:, 0].dropna()
if len(first_col_values) > 0:
first_col_mean = abs(first_col_values.mean())
first_col_max = abs(first_col_values.max())
# Stanford: small values (voltage deltas)
if first_col_max < 0.01:
detection_scores['stanford'] += 0.3
# NASA: larger values (cycle indices or voltages)
if first_col_max > 1.0:
detection_scores['nasa'] += 0.2
# Check 4: Row count
# Stanford typically has ~1000 cycles per cell
# NASA typically has ~168 cycles
if len(data) > 500:
detection_scores['stanford'] += 0.1
elif len(data) < 300:
detection_scores['nasa'] += 0.1
# Determine format
max_score = max(detection_scores['nasa'], detection_scores['stanford'])
if detection_scores['nasa'] > detection_scores['stanford'] and detection_scores['nasa'] >= confidence_threshold:
format_type = 'nasa'
confidence = detection_scores['nasa']
reason = f"NASA format detected: {nasa_cols_present}/5 required columns present"
elif detection_scores['stanford'] > detection_scores['nasa'] and detection_scores['stanford'] >= confidence_threshold:
format_type = 'stanford'
confidence = detection_scores['stanford']
reason = f"Stanford format detected: {len(data.columns)} columns (matrix format)"
else:
format_type = 'unknown'
confidence = max_score
reason = f"Format uncertain: NASA score={detection_scores['nasa']:.2f}, Stanford score={detection_scores['stanford']:.2f}"
details['detection_scores'] = detection_scores
return {
'format': format_type,
'confidence': confidence,
'reason': reason,
'details': details
}
def validate_format(data: pd.DataFrame, expected_format: str) -> Dict:
"""
Validate that data matches expected format.
Parameters:
-----------
data : DataFrame
Battery data
expected_format : str
'nasa' or 'stanford'
Returns:
--------
dict: Validation results
"""
errors = []
warnings = []
if expected_format == 'nasa':
# Check required columns
required = ['cycle_index', 'voltage', 'current', 'temperature', 'capacity']
missing = [col for col in required if col not in data.columns]
if missing:
errors.append(f"Missing required columns: {missing}")
# Check value ranges
if 'voltage' in data.columns:
v_min, v_max = data['voltage'].min(), data['voltage'].max()
if v_min < 0 or v_max > 5:
warnings.append(f"Unusual voltage range: {v_min:.2f}-{v_max:.2f}V")
if 'capacity' in data.columns:
if data['capacity'].min() < 0:
errors.append("Negative capacity values found")
elif expected_format == 'stanford':
# Check column count
if len(data.columns) != 99:
warnings.append(f"Expected 99 columns, got {len(data.columns)}")
# Check value ranges (should be small voltage deltas)
max_abs_value = abs(data.values).max()
if max_abs_value > 0.1:
warnings.append(f"Values seem large for Stanford format: max={max_abs_value:.4f}")
is_valid = len(errors) == 0
return {
'is_valid': is_valid,
'errors': errors,
'warnings': warnings
}
if __name__ == "__main__":
# Test format detection
print("Testing format detector...")
# Test NASA format
print("\n1. NASA B0005:")
nasa_data = pd.read_csv('./data/nasa_converted/B0005.csv')
result = detect_battery_format(nasa_data)
print(f" Format: {result['format']}")
print(f" Confidence: {result['confidence']:.2f}")
print(f" Reason: {result['reason']}")
# Test Stanford format
print("\n2. Stanford cell1 (original):")
stanford_data = pd.read_csv('./data/stanford/cell1.csv', header=None)
result = detect_battery_format(stanford_data)
print(f" Format: {result['format']}")
print(f" Confidence: {result['confidence']:.2f}")
print(f" Reason: {result['reason']}")
# Test Stanford converted
print("\n3. Stanford cell1 (converted):")
stanford_converted = pd.read_csv('./data/stanford_converted/cell1.csv')
result = detect_battery_format(stanford_converted)
print(f" Format: {result['format']}")
print(f" Confidence: {result['confidence']:.2f}")
print(f" Reason: {result['reason']}")
print("\n✅ Format detector test complete!")