move data formating scripts into this repo
This commit is contained in:
		
							parent
							
								
									a1cfee1955
								
							
						
					
					
						commit
						31444f919e
					
				
					 7 changed files with 490 additions and 0 deletions
				
			
		
							
								
								
									
										138
									
								
								scripts/cellmeta.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										138
									
								
								scripts/cellmeta.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,138 @@ | |||
| from chargefile import ChargeFile, SearchDirection | ||||
| 
 | ||||
| CYCLES_PER_STEP = 4 | ||||
| STEP_COUNT = 12 | ||||
| 
 | ||||
| 
 | ||||
| def charge_cylces_in_step(globalstep: int): | ||||
| 	cyclepoint = globalstep % STEP_COUNT | ||||
| 	if cyclepoint == 0: | ||||
| 		if (globalstep / STEP_COUNT) % 10 == 0: | ||||
| 			return 1 | ||||
| 		else: | ||||
| 			return 0 | ||||
| 	if cyclepoint == 9: | ||||
| 		return 1 | ||||
| 	if cyclepoint == 11: | ||||
| 		return CYCLES_PER_STEP | ||||
| 	return 0 | ||||
| 
 | ||||
| 
 | ||||
| def charge_cycles_at_step(globalstep: int,): | ||||
| 	count = 0 | ||||
| 	for i in range(globalstep): | ||||
| 		count += charge_cylces_in_step(i) | ||||
| 	return count | ||||
| 
 | ||||
| 
 | ||||
| def thermal_cylces_in_step(globalstep: int, substep: int = -1): | ||||
| 	cyclepoint = globalstep % STEP_COUNT | ||||
| 	if cyclepoint == 0: | ||||
| 		if (globalstep / STEP_COUNT) % 10 == 0: | ||||
| 			return 0 | ||||
| 		else: | ||||
| 			return CYCLES_PER_STEP | ||||
| 	if cyclepoint == 2: | ||||
| 		return CYCLES_PER_STEP | ||||
| 	if cyclepoint == 4: | ||||
| 		return CYCLES_PER_STEP | ||||
| 	if cyclepoint == 6: | ||||
| 		return CYCLES_PER_STEP | ||||
| 	if cyclepoint == 8: | ||||
| 		return CYCLES_PER_STEP | ||||
| 	if cyclepoint == 10: | ||||
| 		return CYCLES_PER_STEP | ||||
| 	if cyclepoint == 11: | ||||
| 		return 1 | ||||
| 	return 0 | ||||
| 
 | ||||
| 
 | ||||
| def thermal_cycles_at_step(globalstep: int, substep: int): | ||||
| 	count = 0 | ||||
| 	for i in range(globalstep - 1): | ||||
| 		count += thermal_cylces_in_step(globalstep) | ||||
| 	count += thermal_cylces_in_step(globalstep, substep) | ||||
| 	return count | ||||
| 
 | ||||
| 
 | ||||
| non_charge_cycle_cell = list(range(4, 7)) | ||||
| non_thermal_cycle_cell = list(range(11, 21)) | ||||
| cell_thermal_range = { | ||||
| 	0: [35, 55], | ||||
| 	1: [35, 55], | ||||
| 	2: [35, 55], | ||||
| 	3: [35, 55], | ||||
| 	4: [35, 55], | ||||
| 	5: [35, 55], | ||||
| 	6: [35, 55], | ||||
| 	7: [35, 45], | ||||
| 	8: [35, 45], | ||||
| 	9: [35, 45], | ||||
| 	10: [35, 45], | ||||
| 	11: [35, 35], | ||||
| 	12: [35, 35], | ||||
| 	13: [35, 35], | ||||
| 	14: [45, 45], | ||||
| 	15: [45, 45], | ||||
| 	16: [45, 45], | ||||
| 	17: [35, 55], | ||||
| 	18: [35, 55], | ||||
| 	19: [35, 55], | ||||
| 	20: [35, 55], | ||||
| } | ||||
| 
 | ||||
| cell_group_table = { | ||||
| 	0: 0, | ||||
| 	1: 0, | ||||
| 	2: 0, | ||||
| 	3: 0, | ||||
| 	4: 1, | ||||
| 	5: 1, | ||||
| 	6: 1, | ||||
| 	7: 2, | ||||
| 	8: 2, | ||||
| 	9: 2, | ||||
| 	10: 2, | ||||
| 	11: 3, | ||||
| 	12: 3, | ||||
| 	13: 3, | ||||
| 	14: 4, | ||||
| 	15: 4, | ||||
| 	16: 4, | ||||
| 	17: 5, | ||||
| 	18: 5, | ||||
| 	19: 5, | ||||
| 	20: 5, | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| class CellMeta: | ||||
| 	def __init__(self, cellid: int, globalstep: int, substep: int, charge_files: list[ChargeFile], total_cells: int): | ||||
| 		closest_avg = None | ||||
| 		closest_charge = None | ||||
| 		if cellid not in non_charge_cycle_cell: | ||||
| 			closest_avg = ChargeFile.FindClosest(charge_files, globalstep, -1) | ||||
| 			closest_charge = ChargeFile.FindClosest(charge_files, globalstep, cellid) | ||||
| 		if closest_charge is not None: | ||||
| 			assert closest_charge.cell == cellid | ||||
| 
 | ||||
| 		total_charge_cells = 0 | ||||
| 		for i in range(total_cells): | ||||
| 			if i not in non_charge_cycle_cell: | ||||
| 				total_charge_cells += 1 | ||||
| 
 | ||||
| 		self.cell_group = cell_group_table[cellid] | ||||
| 		self.charge_cycles = charge_cycles_at_step(globalstep) if cellid not in non_charge_cycle_cell else 0 | ||||
| 		self.thermal_cycles = thermal_cycles_at_step(globalstep, substep) if cellid not in non_thermal_cycle_cell else 0 | ||||
| 		self.last_avg_cap = abs(closest_avg.capacity) / total_charge_cells if closest_avg is not None else -1 | ||||
| 		self.last_avg_cap_step = closest_avg.step if closest_avg is not None else -1 | ||||
| 		self.last_cap = abs(closest_charge.capacity) if closest_charge is not None else -1 | ||||
| 		self.last_cap_step = closest_charge.step if closest_charge is not None else -1 | ||||
| 		self.thermal_range = cell_thermal_range[cellid] | ||||
| 		if cellid not in non_charge_cycle_cell: | ||||
| 			self.soc = ChargeFile.GetSoc(charge_files, globalstep, cellid, total_charge_cells) | ||||
| 			self.cap_esitmate = ChargeFile.GetCapacityEsitmate(charge_files, globalstep, cellid, total_charge_cells) | ||||
| 		else: | ||||
| 			self.soc = -1 | ||||
| 			self.cap_esitmate = -1 | ||||
| 		self.soc_estimate = -1 | ||||
							
								
								
									
										177
									
								
								scripts/chargefile.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										177
									
								
								scripts/chargefile.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,177 @@ | |||
| import csv | ||||
| 
 | ||||
| from parseerror import ParseError | ||||
| import os | ||||
| import enum | ||||
| 
 | ||||
| 
 | ||||
| class SearchDirection(enum.Enum): | ||||
| 	CLOSEST = 0 | ||||
| 	PREVIOUS_ONLY = 1 | ||||
| 	FORWARD_ONLY = 2 | ||||
| 
 | ||||
| 
 | ||||
| def calc_capacity(charge_curve: list[dict]): | ||||
| 	capacity = 0.0 | ||||
| 	prev_time = -1 | ||||
| 	prev_current = -1 | ||||
| 	total_t = 0 | ||||
| 	for entry in charge_curve: | ||||
| 		if prev_time > 0: | ||||
| 			delta_s = entry['time'] - prev_time | ||||
| 			current = (entry['current'] + prev_current) / 2 | ||||
| 			capacity += current * (delta_s / (60.0 * 60.0)) | ||||
| 			total_t += delta_s | ||||
| 		prev_time = entry['time'] | ||||
| 		prev_current = entry['current'] | ||||
| 	return capacity | ||||
| 
 | ||||
| 
 | ||||
| class ChargeFile: | ||||
| 	def __init__(self, filename: str): | ||||
| 		self.start_voltage = 0.0 | ||||
| 		self.end_voltage = 0.0 | ||||
| 		self.capacity = 0.0 | ||||
| 		self.cell = -1 | ||||
| 		self.discharge = False | ||||
| 		self.current = 0.0 | ||||
| 		self.full_cycle = False | ||||
| 		self.step = 0 | ||||
| 
 | ||||
| 		if os.path.split(filename)[1].startswith("single_cell_charge") or os.path.split(filename)[1].startswith("single_cell_discharge"): | ||||
| 			tokens = filename.split('.')[0].split('_') | ||||
| 			self.step = int(tokens[-2]) | ||||
| 			self.cell = int(tokens[-1]) | ||||
| 		elif os.path.split(filename)[1].startswith("charge_for"): | ||||
| 			self.step = int(filename.split('.')[0].split('_')[-1]) | ||||
| 		else: | ||||
| 			raise ParseError(f"File name {os.path.split(filename)[1]} not in the expected sheme for ChargeFile") | ||||
| 
 | ||||
| 		with open(filename, newline='') as csvfile: | ||||
| 			reader = csv.reader(csvfile, delimiter=',', quotechar='"') | ||||
| 			reader.__next__() | ||||
| 			timestr = reader.__next__()[0] | ||||
| 			if timestr != "time": | ||||
| 				raise ParseError(f"Expected time got {timestr}") | ||||
| 			charge_curve = list() | ||||
| 			for row in reader: | ||||
| 				charge_curve.append({'time': int(row[0]), 'voltage': float(row[1]), 'current': float(row[2])}) | ||||
| 			self.current = charge_curve[int(len(charge_curve) / 2)]['current'] | ||||
| 			self.discharge = self.current < 0 | ||||
| 			self.start_voltage = charge_curve[0]['voltage'] | ||||
| 			self.end_voltage = charge_curve[-1]['voltage'] | ||||
| 			self.capacity = calc_capacity(charge_curve) | ||||
| 			self.full_cycle = self.start_voltage > 4.05 and self.end_voltage < 3.15 or self.start_voltage < 3.15 and self.end_voltage > 4.05 | ||||
| 
 | ||||
| 	@staticmethod | ||||
| 	def FindClosest(charge_files: list, step: int, cellid: int = -1, full_cycle=True, direction=SearchDirection.CLOSEST): | ||||
| 		closest_file = None | ||||
| 		for charge_file in charge_files: | ||||
| 			if charge_file.cell != cellid: | ||||
| 				continue | ||||
| 			if direction == SearchDirection.PREVIOUS_ONLY and charge_file.step > step: | ||||
| 				continue | ||||
| 			if direction == SearchDirection.FORWARD_ONLY and charge_file.step < step: | ||||
| 				continue | ||||
| 			if not full_cycle or charge_file.full_cycle: | ||||
| 				if closest_file is not None: | ||||
| 					if abs(step - closest_file.step) > abs(step - charge_file.step): | ||||
| 						closest_file = charge_file | ||||
| 					elif abs(step - closest_file.step) == abs(step - charge_file.step) and step > closest_file.step and not closest_file.discharge: | ||||
| 						if (step > closest_file.step and not closest_file.discharge) or (step < closest_file.step and closest_file.discharge): | ||||
| 							closest_file = charge_file | ||||
| 				else: | ||||
| 					closest_file = charge_file | ||||
| 		return closest_file | ||||
| 
 | ||||
| 	@staticmethod | ||||
| 	def GetSoc(charge_files: list, step: int, cellid: int, cell_count: int) -> float: | ||||
| 
 | ||||
| 		common_closest_full = ChargeFile.FindClosest(charge_files, step, -1, True, SearchDirection.PREVIOUS_ONLY) | ||||
| 		specific_closest_full = ChargeFile.FindClosest(charge_files, step, cellid, True, SearchDirection.PREVIOUS_ONLY) | ||||
| 
 | ||||
| 		if specific_closest_full is None and common_closest_full is None: | ||||
| 			return -1.0 | ||||
| 
 | ||||
| 		if common_closest_full is None: | ||||
| 			closest_full = specific_closest_full | ||||
| 		elif specific_closest_full is None: | ||||
| 			closest_full = common_closest_full | ||||
| 		elif step - specific_closest_full.step < step - common_closest_full.step: | ||||
| 			closest_full = specific_closest_full | ||||
| 		else: | ||||
| 			closest_full = common_closest_full | ||||
| 
 | ||||
| 		full_cap = closest_full.capacity | ||||
| 		if closest_full.cell == -1: | ||||
| 			full_cap = full_cap / cell_count | ||||
| 
 | ||||
| 		if closest_full.discharge: | ||||
| 			charge_counter = 0.0 | ||||
| 		else: | ||||
| 			charge_counter = full_cap | ||||
| 
 | ||||
| 		accepted_count = 0 | ||||
| 		end_voltage = closest_full.end_voltage | ||||
| 
 | ||||
| 		for charge_file in charge_files: | ||||
| 			if charge_file.step <= step and charge_file.step > closest_full.step: | ||||
| 				accepted_count += 1 | ||||
| 				if charge_file.cell == -1: | ||||
| 					charge_counter += charge_file.capacity / cell_count | ||||
| 				else: | ||||
| 					charge_counter += charge_file.capacity | ||||
| 				end_voltage = charge_file.end_voltage | ||||
| 				if end_voltage > 4.15: | ||||
| 					charge_counter = full_cap | ||||
| 				elif end_voltage < 3.15: | ||||
| 					charge_counter = 0 | ||||
| 
 | ||||
| 		soc = charge_counter / abs(full_cap) | ||||
| 
 | ||||
| 		if soc > 1.05 or soc < -0.05: | ||||
| 			return -1 | ||||
| 
 | ||||
| 		assert not (end_voltage < 3.4 and soc > 0.8) | ||||
| 		assert not (end_voltage > 4.0 and soc < 0.6) | ||||
| 		assert not (soc < -0.1 or soc > 1.1) | ||||
| 
 | ||||
| 		return soc | ||||
| 
 | ||||
| 	def GetCommonCapacityEstimate(charge_files: list, step: int) -> tuple[float, int] | None: | ||||
| 		prev_charge = ChargeFile.FindClosest(charge_files, step, -1, True, SearchDirection.PREVIOUS_ONLY) | ||||
| 		next_charge = ChargeFile.FindClosest(charge_files, step, -1, True, SearchDirection.FORWARD_ONLY) | ||||
| 
 | ||||
| 		if prev_charge is None and next_charge is None: | ||||
| 			return None | ||||
| 		if prev_charge is None: | ||||
| 			return (abs(next_charge.capacity), next_charge.step - step) | ||||
| 		if next_charge is None: | ||||
| 			return (abs(prev_charge.capacity), step - prev_charge.step) | ||||
| 
 | ||||
| 		return ((abs(next_charge.capacity) - abs(prev_charge.capacity)) * ((step - prev_charge.step) / (next_charge.step - prev_charge.step)) + abs(prev_charge.capacity), | ||||
| 			min(step - prev_charge.step, next_charge.step - step)) | ||||
| 
 | ||||
| 	def GetCapacityEsitmate(charge_files: list, step: int, cellid: int, cell_count: int) -> float: | ||||
| 		prev_charge = ChargeFile.FindClosest(charge_files, step, cellid, True, SearchDirection.PREVIOUS_ONLY) | ||||
| 		next_charge = ChargeFile.FindClosest(charge_files, step, cellid, True, SearchDirection.FORWARD_ONLY) | ||||
| 
 | ||||
| 		common_cap = ChargeFile.GetCommonCapacityEstimate(charge_files, step) | ||||
| 		if prev_charge is None and next_charge is None: | ||||
| 			if common_cap is None: | ||||
| 				return -1 | ||||
| 			return common_cap[0] / cell_count | ||||
| 
 | ||||
| 		if prev_charge is not None and next_charge is not None: | ||||
| 			single_charge_estimate = (abs(next_charge.capacity) - abs(prev_charge.capacity)) * ((step - prev_charge.step) / (next_charge.step - prev_charge.step)) | ||||
| 			single_charge_estimate += abs(prev_charge.capacity) | ||||
| 			if common_cap is None or min(step - prev_charge.step, next_charge.step - step) < common_cap[1]: | ||||
| 				return single_charge_estimate | ||||
| 			common_cap_at_prev = ChargeFile.GetCommonCapacityEstimate(charge_files, prev_charge.step) | ||||
| 			common_cap_at_next = ChargeFile.GetCommonCapacityEstimate(charge_files, next_charge.step) | ||||
| 			avg_delta = ((abs(prev_charge.capacity) - common_cap_at_prev[0] / cell_count) + (abs(next_charge.capacity) - common_cap_at_next[0] / cell_count)) / 2.0 | ||||
| 			return (common_cap[0] / cell_count) + avg_delta | ||||
| 
 | ||||
| 		singe_charge = prev_charge if prev_charge is not None else next_charge | ||||
| 		common_cap_at_single = ChargeFile.GetCommonCapacityEstimate(charge_files, singe_charge.step) | ||||
| 		return (common_cap[0] / cell_count) + (abs(singe_charge.capacity) - common_cap_at_single[0] / cell_count) | ||||
							
								
								
									
										65
									
								
								scripts/createdataset.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										65
									
								
								scripts/createdataset.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,65 @@ | |||
| import argparse | ||||
| import os | ||||
| from tqdm import tqdm | ||||
| import tarfile | ||||
| 
 | ||||
| from chargefile import ChargeFile | ||||
| from spectrafile import SpectraFile | ||||
| from soc_estimation import add_soc_estimate | ||||
| 
 | ||||
| 
 | ||||
| if __name__ == "__main__": | ||||
| 	parser = argparse.ArgumentParser("KissExpiramentCreateDataset") | ||||
| 	parser.add_argument('--data', '-d', required=True, help="Data input directory") | ||||
| 	parser.add_argument('--out', '-o', required=True, help="output directory") | ||||
| 	args = parser.parse_args() | ||||
| 
 | ||||
| 	filenames = [f for f in os.listdir(args.data) if os.path.isfile(os.path.join(args.data, f))] | ||||
| 	charge_filenames = [f for f in filenames if f.startswith("charge") or f.startswith("single_cell_")] | ||||
| 	spectra_filenames = [f for f in filenames if not f.startswith("charge") and not f.startswith("single_cell_") and not f.startswith("voltage_equlaization_") and f != "expiramentlog.csv"] | ||||
| 
 | ||||
| 	print(f"found {len(spectra_filenames)} spectra") | ||||
| 	print(f"found {len(charge_filenames)} charge/discharge sequences") | ||||
| 
 | ||||
| 	if not os.path.exists(args.out + ".tmp"): | ||||
| 		os.makedirs(args.out + ".tmp") | ||||
| 
 | ||||
| 	charge_files = list() | ||||
| 	for filename in charge_filenames: | ||||
| 		charge_files.append(ChargeFile(os.path.join(args.data, filename))) | ||||
| 
 | ||||
| 	cells = set() | ||||
| 	for filename in tqdm(spectra_filenames, desc="Finding cells"): | ||||
| 		tokens = filename.split('.')[0].split('-') | ||||
| 		cellid = int(tokens[1]) | ||||
| 		cells.add(cellid) | ||||
| 
 | ||||
| 	print(f"{len(cells)} cells where involved") | ||||
| 
 | ||||
| 	spectras = list() | ||||
| 
 | ||||
| 	for filename in tqdm(spectra_filenames, desc="Resolveing data"): | ||||
| 		tokens = filename.split('.')[0].split('-') | ||||
| 		step = int(tokens[0]) | ||||
| 		cellid = int(tokens[1]) | ||||
| 		substep = int(tokens[2]) | ||||
| 		sf = SpectraFile(os.path.join(args.data, filename), cellid, step, substep, charge_files, len(cells)) | ||||
| 		spectras.append(sf) | ||||
| 
 | ||||
| 	add_soc_estimate(spectras) | ||||
| 
 | ||||
| 	for spectra in spectras: | ||||
| 		spectra.write(args.out + ".tmp") | ||||
| 
 | ||||
| 	try: | ||||
| 		os.remove(f"{args.out}.tar") | ||||
| 	except FileNotFoundError: | ||||
| 		pass | ||||
| 	tar = tarfile.open(f"{args.out}.tar", mode="x") | ||||
| 	for filename in tqdm(os.listdir(args.out + ".tmp"), desc="Saveing data"): | ||||
| 		path = os.path.join(args.out + ".tmp", filename) | ||||
| 		tar.add(path, arcname=os.path.split(path)[-1]) | ||||
| 		os.remove(path) | ||||
| 	os.rmdir(args.out + ".tmp") | ||||
| 	tar.close() | ||||
| 
 | ||||
							
								
								
									
										35
									
								
								scripts/extractmeta.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								scripts/extractmeta.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,35 @@ | |||
| #!/bin/python | ||||
| 
 | ||||
| import tarfile | ||||
| from tqdm import tqdm | ||||
| from eisgenerator import EisSpectra | ||||
| import csv | ||||
| import argparse | ||||
| 
 | ||||
| if __name__ == "__main__": | ||||
| 	parser = argparse.ArgumentParser("KissExpiramentExtractMeta") | ||||
| 	parser.add_argument('--data', '-d', required=True, help="Data input tar file") | ||||
| 	parser.add_argument('--out', '-o', required=True, help="output file") | ||||
| 	args = parser.parse_args() | ||||
| 
 | ||||
| 	with open(args.out, 'w', newline='') as outfile: | ||||
| 		csvwriter = csv.writer(outfile, delimiter=',', quotechar='"', quoting=csv.QUOTE_MINIMAL) | ||||
| 		with tarfile.open(args.data, mode="r") as tar: | ||||
| 			master_labels = None | ||||
| 			rows = list() | ||||
| 			for file_info in tqdm(tar, desc="Extracting Metadata", total=len(list(tar))): | ||||
| 				if file_info.isfile(): | ||||
| 					filestr = tar.extractfile(file_info).read() | ||||
| 					spectra = EisSpectra.loadFromString(filestr) | ||||
| 					if master_labels is None: | ||||
| 						master_labels = spectra.labelNames | ||||
| 						master_labels_copy = master_labels.copy() | ||||
| 						for i in range(len(master_labels_copy)): | ||||
| 							print(master_labels_copy[i]) | ||||
| 							master_labels_copy[i] = master_labels_copy[i].strip(' "') | ||||
| 						csvwriter.writerow(master_labels_copy) | ||||
| 					elif master_labels != spectra.labelNames: | ||||
| 						print(f"Error: not all files in {args.data} have the same labelNames") | ||||
| 						exit(1) | ||||
| 					csvwriter.writerow(spectra.labels) | ||||
| 			tar.close() | ||||
							
								
								
									
										3
									
								
								scripts/parseerror.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								scripts/parseerror.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,3 @@ | |||
| class ParseError(Exception): | ||||
| 	def __init__(self, message): | ||||
| 		self.message = message | ||||
							
								
								
									
										32
									
								
								scripts/soc_estimation.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								scripts/soc_estimation.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,32 @@ | |||
| from scipy.optimize import curve_fit | ||||
| from scipy.interpolate import splrep, splev | ||||
| import csv | ||||
| import argparse | ||||
| import numpy | ||||
| import matplotlib.pyplot as plt | ||||
| from eisgenerator import EisSpectra | ||||
| import io | ||||
| import tarfile | ||||
| from tqdm import tqdm | ||||
| from spectrafile import SpectraFile | ||||
| 
 | ||||
| 
 | ||||
| def add_soc_estimate(spectras: list[SpectraFile]): | ||||
| 	data = [list(), list()] | ||||
| 
 | ||||
| 	for spectra in spectras: | ||||
| 		if not spectra.meta.soc <= 0: | ||||
| 			data[0].append(spectra.ocv) | ||||
| 			data[1].append(spectra.meta.soc) | ||||
| 
 | ||||
| 	ndata = numpy.asarray(data) | ||||
| 	ndata.sort(1) | ||||
| 
 | ||||
| 	knots = 9 | ||||
| 	qs = numpy.linspace(0, 1, knots)[1:-1] | ||||
| 	knots = numpy.quantile(ndata[0], qs) | ||||
| 	tck = splrep(ndata[0], ndata[1], t=knots, k=3) | ||||
| 	estimates = splev(ndata[0], tck) | ||||
| 
 | ||||
| 	for spectra in spectras: | ||||
| 		spectra.meta.soc_estimate = splev(spectra.ocv, tck) | ||||
							
								
								
									
										40
									
								
								scripts/spectrafile.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								scripts/spectrafile.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,40 @@ | |||
| import os | ||||
| 
 | ||||
| from cellmeta import CellMeta | ||||
| from eisgenerator import EisSpectra | ||||
| from parseerror import ParseError | ||||
| from chargefile import ChargeFile | ||||
| 
 | ||||
| 
 | ||||
| class SpectraFile: | ||||
| 	def __init__(self, filename: str, cellid: int, step: int, substep: int, charge_files: list[ChargeFile], total_cells: int): | ||||
| 		self.cellid = cellid | ||||
| 		self.step = step | ||||
| 		self.substep = substep | ||||
| 		self.filename = filename | ||||
| 		self.temperature = -1.0 | ||||
| 		self.ocv = -1.0 | ||||
| 		self.meta = CellMeta(cellid, step, substep, charge_files, total_cells) | ||||
| 		self.filename = os.path.split(filename)[1] | ||||
| 
 | ||||
| 		self.spectra = EisSpectra.loadFromDisk(filename) | ||||
| 		header = self.spectra.header.split('"')[1].split(',') | ||||
| 		self.temperature = float(header[2]) | ||||
| 		self.ocv = float(header[3]) | ||||
| 
 | ||||
| 		if int(header[0]) != step or int(header[1]) != cellid: | ||||
| 			raise ParseError(f"file name and file content of SpectraFile {filename} do not match") | ||||
| 
 | ||||
| 	def write(self, directory: str): | ||||
| 		metaList = [float(self.step), float(self.substep), float(self.cellid), float(self.meta.cell_group), float(self.temperature), float(self.ocv), | ||||
| 			float(self.meta.charge_cycles), float(self.meta.thermal_cycles), float(self.meta.last_avg_cap), float(self.meta.last_avg_cap_step), | ||||
| 			float(self.meta.last_cap), float(self.meta.last_cap_step), float(self.meta.cap_esitmate), float(self.meta.soc), float(self.meta.soc_estimate)] | ||||
| 		self.spectra.setLabels(metaList) | ||||
| 		self.spectra.model = "Unkown" | ||||
| 		meta_dsc_strings = ["step", "substep", "cellid", "cell_group", "temparature", "ocv", "charge_cycles", "thermal_cycles", | ||||
| 			"last_avg_cap", "last_avg_step", "last_cap", "last_cap_step", "cap_estimate", "soc", "soc_estimate"] | ||||
| 		self.spectra.headerDescription = "File origin" | ||||
| 		self.spectra.header = "CoinCellHell mesurement file" | ||||
| 		self.spectra.labelNames = meta_dsc_strings | ||||
| 		self.spectra.saveToDisk(os.path.join(directory, self.filename)) | ||||
| 
 | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Carl Philipp Klemm
						Carl Philipp Klemm