commit
a503944e2d
@ -124,6 +124,7 @@ sim_R_o_nocool = 0.5 # K/W thermal resistance oven -> environment
|
|||||||
sim_R_o_cool = 0.05 # K/W " with cooling
|
sim_R_o_cool = 0.05 # K/W " with cooling
|
||||||
sim_R_ho_noair = 0.1 # K/W thermal resistance heat element -> oven
|
sim_R_ho_noair = 0.1 # K/W thermal resistance heat element -> oven
|
||||||
sim_R_ho_air = 0.05 # K/W " with internal air circulation
|
sim_R_ho_air = 0.05 # K/W " with internal air circulation
|
||||||
|
sim_speedup_factor = 1000
|
||||||
|
|
||||||
|
|
||||||
########################################################################
|
########################################################################
|
||||||
@ -155,7 +156,7 @@ kiln_must_catch_up = True
|
|||||||
# or 100% off because the kiln is too hot. No integral builds up
|
# or 100% off because the kiln is too hot. No integral builds up
|
||||||
# outside the window. The bigger you make the window, the more
|
# outside the window. The bigger you make the window, the more
|
||||||
# integral you will accumulate. This should be a positive integer.
|
# integral you will accumulate. This should be a positive integer.
|
||||||
pid_control_window = 5 #degrees
|
pid_control_window = 5 #degrees
|
||||||
|
|
||||||
# thermocouple offset
|
# thermocouple offset
|
||||||
# If you put your thermocouple in ice water and it reads 36F, you can
|
# If you put your thermocouple in ice water and it reads 36F, you can
|
||||||
|
|||||||
38
lib/oven.py
38
lib/oven.py
@ -362,6 +362,9 @@ class Oven(threading.Thread):
|
|||||||
self.reset()
|
self.reset()
|
||||||
self.save_automatic_restart_state()
|
self.save_automatic_restart_state()
|
||||||
|
|
||||||
|
def get_start_time(self):
|
||||||
|
return datetime.datetime.now() - datetime.timedelta(milliseconds = self.runtime * 1000)
|
||||||
|
|
||||||
def kiln_must_catch_up(self):
|
def kiln_must_catch_up(self):
|
||||||
'''shift the whole schedule forward in time by one time_step
|
'''shift the whole schedule forward in time by one time_step
|
||||||
to wait for the kiln to catch up'''
|
to wait for the kiln to catch up'''
|
||||||
@ -371,11 +374,11 @@ class Oven(threading.Thread):
|
|||||||
# kiln too cold, wait for it to heat up
|
# kiln too cold, wait for it to heat up
|
||||||
if self.target - temp > config.pid_control_window:
|
if self.target - temp > config.pid_control_window:
|
||||||
log.info("kiln must catch up, too cold, shifting schedule")
|
log.info("kiln must catch up, too cold, shifting schedule")
|
||||||
self.start_time = datetime.datetime.now() - datetime.timedelta(milliseconds = self.runtime * 1000)
|
self.start_time = self.get_start_time()
|
||||||
# kiln too hot, wait for it to cool down
|
# kiln too hot, wait for it to cool down
|
||||||
if temp - self.target > config.pid_control_window:
|
if temp - self.target > config.pid_control_window:
|
||||||
log.info("kiln must catch up, too hot, shifting schedule")
|
log.info("kiln must catch up, too hot, shifting schedule")
|
||||||
self.start_time = datetime.datetime.now() - datetime.timedelta(milliseconds = self.runtime * 1000)
|
self.start_time = self.get_start_time()
|
||||||
|
|
||||||
def update_runtime(self):
|
def update_runtime(self):
|
||||||
|
|
||||||
@ -524,6 +527,7 @@ class SimulatedOven(Oven):
|
|||||||
self.R_o_nocool = config.sim_R_o_nocool
|
self.R_o_nocool = config.sim_R_o_nocool
|
||||||
self.R_ho_noair = config.sim_R_ho_noair
|
self.R_ho_noair = config.sim_R_ho_noair
|
||||||
self.R_ho = self.R_ho_noair
|
self.R_ho = self.R_ho_noair
|
||||||
|
self.speedup_factor = config.sim_speedup_factor
|
||||||
|
|
||||||
# set temps to the temp of the surrounding environment
|
# set temps to the temp of the surrounding environment
|
||||||
self.t = config.sim_t_env # deg C or F temp of oven
|
self.t = config.sim_t_env # deg C or F temp of oven
|
||||||
@ -535,6 +539,20 @@ class SimulatedOven(Oven):
|
|||||||
self.start()
|
self.start()
|
||||||
log.info("SimulatedOven started")
|
log.info("SimulatedOven started")
|
||||||
|
|
||||||
|
# runtime is in sped up time, start_time is actual time of day
|
||||||
|
def get_start_time(self):
|
||||||
|
return datetime.datetime.now() - datetime.timedelta(milliseconds = self.runtime * 1000 / self.speedup_factor)
|
||||||
|
|
||||||
|
def update_runtime(self):
|
||||||
|
runtime_delta = datetime.datetime.now() - self.start_time
|
||||||
|
if runtime_delta.total_seconds() < 0:
|
||||||
|
runtime_delta = datetime.timedelta(0)
|
||||||
|
|
||||||
|
self.runtime = runtime_delta.total_seconds() * self.speedup_factor
|
||||||
|
|
||||||
|
def update_target_temp(self):
|
||||||
|
self.target = self.profile.get_target_temperature(self.runtime)
|
||||||
|
|
||||||
def heating_energy(self,pid):
|
def heating_energy(self,pid):
|
||||||
# using pid here simulates the element being on for
|
# using pid here simulates the element being on for
|
||||||
# only part of the time_step
|
# only part of the time_step
|
||||||
@ -558,9 +576,11 @@ class SimulatedOven(Oven):
|
|||||||
self.board.temp_sensor.simulated_temperature = self.t
|
self.board.temp_sensor.simulated_temperature = self.t
|
||||||
|
|
||||||
def heat_then_cool(self):
|
def heat_then_cool(self):
|
||||||
|
now_simulator = self.start_time + datetime.timedelta(milliseconds = self.runtime * 1000)
|
||||||
pid = self.pid.compute(self.target,
|
pid = self.pid.compute(self.target,
|
||||||
self.board.temp_sensor.temperature() +
|
self.board.temp_sensor.temperature() +
|
||||||
config.thermocouple_offset)
|
config.thermocouple_offset, now_simulator)
|
||||||
|
|
||||||
heat_on = float(self.time_step * pid)
|
heat_on = float(self.time_step * pid)
|
||||||
heat_off = float(self.time_step * (1 - pid))
|
heat_off = float(self.time_step * (1 - pid))
|
||||||
|
|
||||||
@ -572,7 +592,7 @@ class SimulatedOven(Oven):
|
|||||||
if heat_on > 0:
|
if heat_on > 0:
|
||||||
self.heat = heat_on
|
self.heat = heat_on
|
||||||
|
|
||||||
log.info("simulation: -> %dW heater: %.0f -> %dW oven: %.0f -> %dW env" % (int(self.p_heat * pid),
|
log.info("simulation: -> %dW heater: %.0f -> %dW oven: %.0f -> %dW env" % (int(self.p_heat * pid),
|
||||||
self.t_h,
|
self.t_h,
|
||||||
int(self.p_ho),
|
int(self.p_ho),
|
||||||
self.t,
|
self.t,
|
||||||
@ -599,7 +619,7 @@ class SimulatedOven(Oven):
|
|||||||
|
|
||||||
# we don't actually spend time heating & cooling during
|
# we don't actually spend time heating & cooling during
|
||||||
# a simulation, so sleep.
|
# a simulation, so sleep.
|
||||||
time.sleep(self.time_step)
|
time.sleep(self.time_step / self.speedup_factor)
|
||||||
|
|
||||||
|
|
||||||
class RealOven(Oven):
|
class RealOven(Oven):
|
||||||
@ -621,8 +641,9 @@ class RealOven(Oven):
|
|||||||
|
|
||||||
def heat_then_cool(self):
|
def heat_then_cool(self):
|
||||||
pid = self.pid.compute(self.target,
|
pid = self.pid.compute(self.target,
|
||||||
self.board.temp_sensor.temperature() +
|
self.board.temp_sensor.temperature +
|
||||||
config.thermocouple_offset)
|
config.thermocouple_offset, datetime.datetime.now())
|
||||||
|
|
||||||
heat_on = float(self.time_step * pid)
|
heat_on = float(self.time_step * pid)
|
||||||
heat_off = float(self.time_step * (1 - pid))
|
heat_off = float(self.time_step * (1 - pid))
|
||||||
|
|
||||||
@ -726,8 +747,7 @@ class PID():
|
|||||||
# settled on -50 to 50 and then divide by 50 at the end. This results
|
# settled on -50 to 50 and then divide by 50 at the end. This results
|
||||||
# in a larger PID control window and much more accurate control...
|
# in a larger PID control window and much more accurate control...
|
||||||
# instead of what used to be binary on/off control.
|
# instead of what used to be binary on/off control.
|
||||||
def compute(self, setpoint, ispoint):
|
def compute(self, setpoint, ispoint, now):
|
||||||
now = datetime.datetime.now()
|
|
||||||
timeDelta = (now - self.lastNow).total_seconds()
|
timeDelta = (now - self.lastNow).total_seconds()
|
||||||
|
|
||||||
window_size = 100
|
window_size = 100
|
||||||
|
|||||||
@ -33,7 +33,7 @@ class OvenWatcher(threading.Thread):
|
|||||||
self.recording = False
|
self.recording = False
|
||||||
self.notify_all(oven_state)
|
self.notify_all(oven_state)
|
||||||
time.sleep(self.oven.time_step)
|
time.sleep(self.oven.time_step)
|
||||||
|
|
||||||
def lastlog_subset(self,maxpts=50):
|
def lastlog_subset(self,maxpts=50):
|
||||||
'''send about maxpts from lastlog by skipping unwanted data'''
|
'''send about maxpts from lastlog by skipping unwanted data'''
|
||||||
totalpts = len(self.last_log)
|
totalpts = len(self.last_log)
|
||||||
|
|||||||
1
storage/profiles/test-fast.json
Normal file
1
storage/profiles/test-fast.json
Normal file
@ -0,0 +1 @@
|
|||||||
|
{"data": [[0, 200], [3600, 200], [10800, 2000], [14400, 2250], [16400, 2250], [19400, 70]], "type": "profile", "name": "test-fast"}
|
||||||
Loading…
Reference in New Issue
Block a user