Skip to content
This repository was archived by the owner on May 8, 2025. It is now read-only.

Commit fb2d3bc

Browse files
Updated interval accuracy
1 parent 1d9567b commit fb2d3bc

File tree

1 file changed

+51
-17
lines changed

1 file changed

+51
-17
lines changed

PythonCLX_PIDSimulator.pyw

+51-17
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,42 @@ import tkinter as tk
22
import numpy as np
33
import matplotlib.pyplot as plt
44
import random
5+
import threading
6+
import time
57
from matplotlib import animation
68
from scipy.integrate import odeint
79
from pylogix import PLC
810

11+
class PeriodicInterval(threading.Thread):
12+
def __init__(self, task_function, period):
13+
super().__init__()
14+
self.daemon = True
15+
self.task_function = task_function
16+
self.period = period
17+
self.i = 0
18+
self.t0 = time.time()
19+
self.stopper=0
20+
self.start()
21+
22+
def sleep(self):
23+
self.i += 1
24+
delta = self.t0 + self.period * self.i - time.time()
25+
if delta > 0:
26+
time.sleep(delta)
27+
28+
def run(self):
29+
while self.stopper==0:
30+
self.task_function()
31+
self.sleep()
32+
33+
def stop(self):
34+
self.stopper=1
35+
36+
def starter(self):
37+
self.stopper=0
38+
self.i = 0
39+
self.t0 = time.time()
40+
941
class data(object):
1042
def __init__(self):
1143
self.PV = np.zeros(0)
@@ -28,10 +60,12 @@ class FOPDTModel(object):
2860
self.Gain, self.TimeConstant, self.DeadTime, self.Bias = ModelData
2961

3062
def calc(self,PV,ts):
31-
if (self.t-self.DeadTime*10) <= 0:
63+
if (ts-self.DeadTime*10) <= 0:
3264
um=0
65+
elif int(ts-self.DeadTime*10)>=len(self.CV):
66+
um=self.CV[-1]
3367
else:
34-
um=self.CV[self.t-int(self.DeadTime*10)]
68+
um=self.CV[int(ts-self.DeadTime*10)]
3569
dydt = (-(PV-self.Bias) + self.Gain * um)/(self.TimeConstant*10)
3670
return dydt
3771

@@ -52,11 +86,9 @@ def fopdtsetup():
5286
spstatus.set("")
5387
pvstatus.set("")
5488
cvstatus.set("")
55-
56-
def start():
57-
global looper
5889
comm.IPAddress = ip.get()
5990
comm.ProcessorSlot = int(slot.get())
91+
comm.SocketTimeout = 1
6092
button_start["state"] = "disabled"
6193
button_stop["state"] = "normal"
6294
button_trend["state"] = "normal"
@@ -66,7 +98,12 @@ def start():
6698
modeltc.configure(state="disabled")
6799
modeldt.configure(state="disabled")
68100
ambient.configure(state="disabled")
101+
102+
def thread_start():
103+
global looper
104+
looper = PeriodicInterval(start, 0.1)
69105

106+
def start():
70107
try:
71108
ret = comm.Read([cvtag.get(),sptag.get()])
72109
if ret[0].Status=='Success':
@@ -115,8 +152,6 @@ def start():
115152

116153
except Exception as e:
117154
pvstatus.set('An exception occurred: {}'.format(e))
118-
119-
looper=root.after(100, start)
120155

121156
def stop():
122157
button_start["state"] = "normal"
@@ -131,16 +166,17 @@ def stop():
131166
sptag.configure(state="normal")
132167
ambient.configure(state="normal")
133168
gData.livetrend=0
134-
root.after_cancel(looper)
169+
if 'looper' in globals():
170+
looper.stop()
135171
comm.Close()
136172

137173
def livetrend():
138174
#Set up the figure
139175
fig = plt.figure()
140176
ax = plt.axes(xlim=(0,100),ylim=(0, 100))
141-
SP, = ax.plot([], [], lw=2, label='SP')
142-
PV, = ax.plot([], [], lw=2, label='PV')
143-
CV, = ax.plot([], [], lw=2, label='CV')
177+
SP, = ax.plot([], [], lw=2, color="Red", label='SP')
178+
CV, = ax.plot([], [], lw=2, color="Green", label='CV')
179+
PV, = ax.plot([], [], lw=2, color="Blue", label='PV')
144180

145181
#Setup Func
146182
def init():
@@ -161,7 +197,7 @@ def livetrend():
161197
ax.set_xlim(0,max(x)*1.1)
162198
max_y=max(max(gData.PV),max(gData.CV),max(gData.SP))
163199
min_y=min(min(gData.PV),min(gData.CV),min(gData.SP))
164-
ax.set_ylim(min_y-10,max_y+10)
200+
ax.set_ylim(min_y-1,max_y+1)
165201
SP.set_data(x,gData.SP)
166202
CV.set_data(x,gData.CV)
167203
PV.set_data(x,gData.PV)
@@ -253,7 +289,7 @@ ambient.insert(5, "13.5")
253289

254290
#Buttons
255291
#Start Button Placement
256-
button_start = tk.Button(root, text="Start Simulator", command=lambda :[fopdtsetup(),start()])
292+
button_start = tk.Button(root, text="Start Simulator", command=lambda :[fopdtsetup(),thread_start()])
257293
button_start.grid(row=4,column=0,columnspan=1,padx=10 ,pady=2,sticky="NESW")
258294

259295
#Stop Button Placement
@@ -265,13 +301,11 @@ button_trend = tk.Button(root, text="Show Trend", command=lambda :[livetrend()])
265301
button_trend.grid(row=5,column=0,columnspan=2,padx=10 ,pady=2,sticky="NESW")
266302
button_trend["state"] = "disabled"
267303

268-
comm=PLC()
269-
270-
#default process
304+
#default setup
271305
params=0,0
272306
model= (modelgain.get(),modeltc.get(),modeldt.get(),13.1)
273307
process=FOPDTModel(params, model)
274-
275308
gData=data()
309+
comm=PLC()
276310

277311
root.mainloop()

0 commit comments

Comments
 (0)