MainCode/adalm1000_logger.py aktualisiert

Make all measurements update live in the GUI

    Allow the stop button to immediately halt the test at any point in the cycle

    Still maintain proper cleanup and data saving when stopped
(Deepseek)
This commit is contained in:
Jan 2025-05-24 01:20:08 +02:00
parent 13148a64de
commit f50a641211

View File

@ -433,13 +433,25 @@ class BatteryTester:
return f"{hours:02d}:{minutes:02d}:{seconds:02d}"
def stop_test(self):
"""Request stop after current discharge phase completes"""
"""Request immediate stop of the test"""
if not self.test_running:
return
self.request_stop = True
self.status_var.set("Stop requested - will complete after current discharge phase")
self.test_running = False # This will break out of all test loops
self.measuring = False
# Immediately set device to safe state
if hasattr(self, 'dev'):
self.dev.channels['A'].mode = pysmu.Mode.HI_Z
self.dev.channels['A'].constant(0)
self.status_var.set("Test stopped immediately")
self.stop_button.config(state=tk.DISABLED)
self.start_button.config(state=tk.NORMAL)
# Finalize test data
self.root.after(100, self.finalize_test)
def center_window(self, window):
"""Center a window on screen"""
@ -455,12 +467,13 @@ class BatteryTester:
test_current = self.c_rate.get() * self.capacity.get()
while self.test_running and (self.continuous_mode or self.cycle_count.get() == 0):
# Zurücksetzen des Stop-Requests zu Beginn jedes Zyklus
# Reset stop request at start of each cycle
self.request_stop = False
# 1. Charge (constant current)
# 1. Charge phase (constant current)
self.test_phase.set("Charge")
self.status_var.set(f"Charging to {self.charge_cutoff.get()}V @ {test_current:.3f}A")
self.root.update() # Force UI update
self.measuring = True
self.dev.channels['B'].mode = pysmu.Mode.HI_Z
@ -470,14 +483,13 @@ class BatteryTester:
target_voltage = self.charge_cutoff.get()
self.last_update_time = time.time()
while self.test_running:
while self.test_running and not self.request_stop:
if not self.voltage_data:
time.sleep(0.1)
continue
current_voltage = self.voltage_data[-1]
measured_current = abs(self.current_data[-1])
time_elapsed = time.time() - self.last_update_time
# Update charge capacity
now = time.time()
@ -488,17 +500,17 @@ class BatteryTester:
self.status_var.set(
f"Charging: {current_voltage:.3f}V / {target_voltage}V | "
f"Current: {measured_current:.3f}A | "
f"Capacity: {self.charge_capacity.get():.4f}Ah | "
f"Time: {self.time_data[-1]:.1f}s"
f"Capacity: {self.charge_capacity.get():.4f}Ah"
)
self.root.update() # Force UI update
if current_voltage >= target_voltage:
if current_voltage >= target_voltage or self.request_stop:
break
time.sleep(0.5)
time.sleep(0.1) # More frequent checks
if not self.test_running:
return
if self.request_stop or not self.test_running:
break
# 2. Rest period after charge
self.test_phase.set("Resting (Post-Charge)")
@ -507,21 +519,22 @@ class BatteryTester:
self.dev.channels['A'].constant(0)
rest_end_time = time.time() + (self.rest_time.get() * 3600)
while time.time() < rest_end_time and self.test_running:
while time.time() < rest_end_time and self.test_running and not self.request_stop:
time_left = max(0, rest_end_time - time.time())
self.status_var.set(
f"Resting after charge | "
f"Time left: {time_left/60:.1f} min | "
f"Next: Final discharge to {self.discharge_cutoff.get()}V"
f"Time left: {time_left/60:.1f} min"
)
time.sleep(1)
self.root.update()
time.sleep(1) # Check every second for stop request
if not self.test_running:
return
if self.request_stop or not self.test_running:
break
# 3. Discharge (capacity measurement)
# 3. Discharge phase (capacity measurement)
self.test_phase.set("Discharge")
self.status_var.set(f"discharge to {self.discharge_cutoff.get()}V @ {test_current:.3f}A")
self.status_var.set(f"Discharging to {self.discharge_cutoff.get()}V @ {test_current:.3f}A")
self.root.update()
self.measuring = True
self.dev.channels['A'].mode = pysmu.Mode.SIMV
@ -529,7 +542,7 @@ class BatteryTester:
self.capacity_ah.set(0.0)
self.last_update_time = time.time()
while self.test_running:
while self.test_running and not self.request_stop:
if not self.current_data:
time.sleep(0.1)
continue
@ -537,105 +550,80 @@ class BatteryTester:
current_voltage = self.voltage_data[-1]
current_current = abs(self.current_data[-1])
# Kapazitätsberechnung
# Capacity calculation
now = time.time()
delta_t = now - self.last_update_time
self.last_update_time = now
self.capacity_ah.set(self.capacity_ah.get() + current_current * delta_t / 3600)
# Statusupdate
status_msg = (
self.status_var.set(
f"Discharging: {current_voltage:.3f}V / {self.discharge_cutoff.get()}V | "
f"Current: {current_current:.3f}A | "
f"Capacity: {self.capacity_ah.get():.4f}Ah"
)
if self.request_stop:
status_msg += " | FINALIZING - completing discharge..."
self.status_var.set(status_msg)
self.root.update()
if current_voltage <= self.discharge_cutoff.get() or self.request_stop:
break
time.sleep(0.5)
if self.request_stop:
time.sleep(0.5)
self.test_running = False
self.root.after(0, self.finalize_test)
return
time.sleep(0.1) # More frequent checks
# 4. Rest period after charge
if self.test_running:
# 4. Rest period after discharge (only if not stopping)
if self.test_running and not self.request_stop:
self.test_phase.set("Resting (Post-Discharge)")
self.measuring = False
self.dev.channels['A'].mode = pysmu.Mode.HI_Z
self.dev.channels['A'].constant(0)
rest_end_time = time.time() + (self.rest_time.get() * 3600)
while time.time() < rest_end_time and self.test_running:
while time.time() < rest_end_time and self.test_running and not self.request_stop:
time_left = max(0, rest_end_time - time.time())
self.status_var.set(
f"Resting after discharge | "
f"Time left: {time_left/60:.1f} min | "
f"Next: Charge to {self.charge_cutoff.get()}V"
f"Time left: {time_left/60:.1f} min"
)
self.root.update()
time.sleep(1)
if not self.test_running:
return
# Calculate Coulomb efficiency
if self.charge_capacity.get() > 0:
# Calculate Coulomb efficiency if not stopping
if not self.request_stop and self.charge_capacity.get() > 0:
efficiency = (self.capacity_ah.get() / self.charge_capacity.get()) * 100
self.coulomb_efficiency.set(efficiency)
self.cycle_count.set(self.cycle_count.get() + 1)
# Update GUI and show results
self.test_phase.set("Cycle Complete")
# Update cycle info
self.status_var.set(
f"Cycle {self.cycle_count.get()} complete | "
f"Discharge Capacity: {self.capacity_ah.get():.3f}Ah | "
f"Charge Capacity: {self.charge_capacity.get():.3f}Ah | "
f"Discharge: {self.capacity_ah.get():.3f}Ah | "
f"Charge: {self.charge_capacity.get():.3f}Ah | "
f"Efficiency: {self.coulomb_efficiency.get():.1f}%"
)
# Show summary dialog only for the first cycle or when stopping
if not self.continuous_mode or not self.test_running:
self.root.after(0, lambda: messagebox.showinfo("Cycle Complete",
f"Cycle {self.cycle_count.get()} complete\n\n"
f"Discharge Capacity: {self.capacity_ah.get():.3f}Ah\n"
f"Charge Capacity: {self.charge_capacity.get():.3f}Ah\n"
f"Coulomb Efficiency: {self.coulomb_efficiency.get():.1f}%\n\n"
f"({self.capacity_ah.get()/self.capacity.get()*100:.1f}% of rated capacity)"))
self.root.update()
# Write cycle summary to log file
self.write_cycle_summary()
# Reset capacities for next cycle
self.capacity_ah.set(0.0)
self.charge_capacity.set(0.0)
# Check if we should continue with another cycle
if self.continuous_mode and self.test_running:
# Short rest between cycles
# Short rest between cycles (only in continuous mode)
if self.continuous_mode and self.test_running and not self.request_stop:
rest_end_time = time.time() + (self.rest_time.get() * 3600)
while time.time() < rest_end_time and self.test_running:
while time.time() < rest_end_time and self.test_running and not self.request_stop:
time_left = max(0, rest_end_time - time.time())
self.test_phase.set("Resting Between Cycles")
self.status_var.set(
f"Resting between cycles | "
f"Time left: {time_left/60:.1f} min | "
f"Next cycle will start soon"
f"Time left: {time_left/60:.1f} min"
)
self.root.update()
time.sleep(1)
# Automatically stop the test after completion if not in continuous mode
if not self.continuous_mode:
self.root.after(0, self.stop_test)
# Finalize test if stopped or completed
self.root.after(0, self.finalize_test)
except Exception as e:
error_msg = str(e)
if self.root.winfo_exists():
self.root.after(0, lambda msg=error_msg: messagebox.showerror("Test Error", msg))
self.root.after(0, self.stop_test)
self.root.after(0, self.finalize_test)
def finalize_test(self):
"""Final cleanup after test completes or is stopped"""
@ -682,6 +670,26 @@ class BatteryTester:
self.voltage_label.config(text=voltage_text)
self._last_voltage_text = voltage_text
capacity_text = f"{self.capacity_ah.get():.4f}"
if not hasattr(self, '_last_capacity_text') or self._last_capacity_text != capacity_text:
self.capacity_label.config(text=capacity_text)
self._last_capacity_text = capacity_text
charge_capacity_text = f"{self.charge_capacity.get():.4f}"
if not hasattr(self, '_last_charge_capacity_text') or self._last_charge_capacity_text != charge_capacity_text:
self.charge_capacity_label.config(text=charge_capacity_text)
self._last_charge_capacity_text = charge_capacity_text
efficiency_text = f"{self.coulomb_efficiency.get():.1f}"
if not hasattr(self, '_last_efficiency_text') or self._last_efficiency_text != efficiency_text:
self.efficiency_label.config(text=efficiency_text)
self._last_efficiency_text = efficiency_text
cycle_text = f"{self.cycle_count.get()}"
if not hasattr(self, '_last_cycle_text') or self._last_cycle_text != cycle_text:
self.cycle_label.config(text=cycle_text)
self._last_cycle_text = cycle_text
current_text = f"{current:.4f}"
if not hasattr(self, '_last_current_text') or self._last_current_text != current_text:
self.current_label.config(text=current_text)