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:
parent
13148a64de
commit
f50a641211
@ -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")
|
||||
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"Efficiency: {self.coulomb_efficiency.get():.1f}%"
|
||||
)
|
||||
# Update cycle info
|
||||
self.status_var.set(
|
||||
f"Cycle {self.cycle_count.get()} complete | "
|
||||
f"Discharge: {self.capacity_ah.get():.3f}Ah | "
|
||||
f"Charge: {self.charge_capacity.get():.3f}Ah | "
|
||||
f"Efficiency: {self.coulomb_efficiency.get():.1f}%"
|
||||
)
|
||||
self.root.update()
|
||||
|
||||
# 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)"))
|
||||
# Write cycle summary to log file
|
||||
self.write_cycle_summary()
|
||||
|
||||
# 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)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user