Browse Source

Changed clock to fix DT at it 0 issue

rparedis 3 years ago
parent
commit
e6138e32a3

+ 1 - 1
examples/scripts/SinGen/SinGen_tkinter_experiment.py

@@ -10,7 +10,7 @@ import tkinter as tk
 root = tk.Tk()
 root = tk.Tk()
 sinGen = SinGen("SinGen")
 sinGen = SinGen("SinGen")
 sim = Simulator(sinGen)
 sim = Simulator(sinGen)
-sim.setProgressBar()
+# sim.setProgressBar()
 sim.setRealTime()
 sim.setRealTime()
 sim.setRealTimePlatformTk(root)
 sim.setRealTimePlatformTk(root)
 sim.setDeltaT(0.3)
 sim.setDeltaT(0.3)

+ 4 - 6
src/CBD/Core.py

@@ -259,7 +259,6 @@ class BaseBlock:
         return list(self.__inputs.values())
         return list(self.__inputs.values())
 
 
     def getInputPortNames(self):
     def getInputPortNames(self):
-        # return self.__nameLinks
         return list(self.__inputs.keys())
         return list(self.__inputs.keys())
 
 
     def getInputPortByName(self, name):
     def getInputPortByName(self, name):
@@ -354,8 +353,7 @@ class BaseBlock:
         """
         """
         name_output = "OUT1" if name_output is None else name_output
         name_output = "OUT1" if name_output is None else name_output
         port = self.getOutputPortByName(name_output)
         port = self.getOutputPortByName(name_output)
-        curIt = port.count()
-        port.set(Signal(self.getClock().getTime(curIt), value))
+        port.set(Signal(self.getClock().getTime(), value))
 
 
     def getSignalHistory(self, name_output=None):
     def getSignalHistory(self, name_output=None):
         """
         """
@@ -724,7 +722,7 @@ class CBD(BaseBlock):
             formalisms/simulators, the Clock's outputs should be replaced with the
             formalisms/simulators, the Clock's outputs should be replaced with the
             corresponding simulator's clock without loss of generality.
             corresponding simulator's clock without loss of generality.
         """
         """
-        self.addBlock(Clock("%s-clock" % prefix, start_time))
+        self.addBlock(Clock("%s-clock" % prefix, delta_t, start_time))
         self.addBlock(ConstantBlock("%s-delta" % prefix, delta_t))
         self.addBlock(ConstantBlock("%s-delta" % prefix, delta_t))
         self.addConnection("%s-delta" % prefix, "%s-clock" % prefix, input_port_name='h')
         self.addConnection("%s-delta" % prefix, "%s-clock" % prefix, input_port_name='h')
 
 
@@ -745,7 +743,7 @@ class CBD(BaseBlock):
                 block.getBlockName() not in self.getOutputPortNames() + self.getInputPortNames():
                 block.getBlockName() not in self.getOutputPortNames() + self.getInputPortNames():
             self.__blocks.append(block)
             self.__blocks.append(block)
             self.__blocksDict[block.getBlockName()] = block
             self.__blocksDict[block.getBlockName()] = block
-            if isinstance(block, (Clock, DummyClock)):
+            if isinstance(block, Clock):
                 self.__clock = block
                 self.__clock = block
         else:
         else:
             logger = logging.getLogger("CBD")
             logger = logging.getLogger("CBD")
@@ -956,4 +954,4 @@ class CBD(BaseBlock):
         return name
         return name
 
 
 
 
-from CBD.lib.std import Clock, ConstantBlock, DummyClock
+from CBD.lib.std import Clock, ConstantBlock

+ 1 - 0
src/CBD/converters/latexify/CBD2Latex.py

@@ -259,6 +259,7 @@ class CBD2Latex:
 						deqs.append(eq)
 						deqs.append(eq)
 			for deq in deqs:
 			for deq in deqs:
 				# prevent cyclic dependency
 				# prevent cyclic dependency
+				# TODO: maybe refactor part of the equation?
 				if deq.rhs.contains(deq.lhs):
 				if deq.rhs.contains(deq.lhs):
 					continue
 					continue
 				if deq.lhs not in outputs:
 				if deq.lhs not in outputs:

+ 1 - 1
src/CBD/lib/endpoints.py

@@ -56,7 +56,7 @@ class SignalCollectorBlock(CollectorBlock):
 		self.buffer_size = buffer_size
 		self.buffer_size = buffer_size
 
 
 	def compute(self, curIteration):
 	def compute(self, curIteration):
-		time = self.getClock().getTime(curIteration)
+		time = self.getClock().getTime()
 		value = self.getInputSignal(curIteration, "IN1").value
 		value = self.getInputSignal(curIteration, "IN1").value
 		self._data.append((time, value))
 		self._data.append((time, value))
 		if self.buffer_size > 0:
 		if self.buffer_size > 0:

+ 2 - 2
src/CBD/lib/io.py

@@ -154,7 +154,7 @@ class ReadCSV(BaseBlock):
 			raise ValueError("A repeating CSV series must not start at time 0")
 			raise ValueError("A repeating CSV series must not start at time 0")
 
 
 	def compute(self, curIteration):
 	def compute(self, curIteration):
-		time = self.getClock().getTime(curIteration)
+		time = self.getClock().getTime()
 		T = self.data[self.time_col][-1]
 		T = self.data[self.time_col][-1]
 		L = len(self.data[self.time_col])
 		L = len(self.data[self.time_col])
 		data = {k: self.data[k] for k in self.data if k != self.time_col}
 		data = {k: self.data[k] for k in self.data if k != self.time_col}
@@ -240,6 +240,6 @@ class WriteCSV(BaseBlock):
 
 
 	def compute(self, curIteration):
 	def compute(self, curIteration):
 		inputs = { col: self.getInputSignal(curIteration, col).value for col in self.columns if col != self.time_col }
 		inputs = { col: self.getInputSignal(curIteration, col).value for col in self.columns if col != self.time_col }
-		inputs[self.time_col] = self.getClock().getTime(curIteration)
+		inputs[self.time_col] = self.getClock().getTime()
 
 
 		self.writer.writerow(inputs)
 		self.writer.writerow(inputs)

+ 38 - 127
src/CBD/lib/std.py

@@ -15,7 +15,7 @@ __all__ = ['ConstantBlock', 'NegatorBlock', 'InverterBlock',
            'MultiplexerBlock', 'SplitBlock',
            'MultiplexerBlock', 'SplitBlock',
            'DelayBlock', 'DeltaTBlock', 'TimeBlock', 'LoggingBlock',
            'DelayBlock', 'DeltaTBlock', 'TimeBlock', 'LoggingBlock',
            'AddOneBlock', 'DerivatorBlock', 'IntegratorBlock',
            'AddOneBlock', 'DerivatorBlock', 'IntegratorBlock',
-           'Clock', 'DummyClock', 'SequenceBlock']
+           'Clock', 'SequenceBlock']
 
 
 class ConstantBlock(BaseBlock):
 class ConstantBlock(BaseBlock):
 	"""
 	"""
@@ -876,8 +876,8 @@ class TimeBlock(BaseBlock):
 		BaseBlock.__init__(self, block_name, [], ["OUT1", "relative"])
 		BaseBlock.__init__(self, block_name, [], ["OUT1", "relative"])
 
 
 	def compute(self, curIteration):
 	def compute(self, curIteration):
-		time = self.getClock().getTime(curIteration)
-		rel_time = self.getClock().getRelativeTime(curIteration)
+		time = self.getClock().getTime()
+		rel_time = self.getClock().getRelativeTime()
 		self.appendToSignal(time)
 		self.appendToSignal(time)
 		self.appendToSignal(rel_time, "relative")
 		self.appendToSignal(rel_time, "relative")
 
 
@@ -907,7 +907,7 @@ class LoggingBlock(BaseBlock):
 
 
 	def compute(self, curIteration):
 	def compute(self, curIteration):
 		if self.getInputSignal(curIteration, "IN1").value:
 		if self.getInputSignal(curIteration, "IN1").value:
-			simtime = str(self.getClock().getTime(-1))
+			simtime = str(self.getClock().getTime())
 			if self.__lev == logging.WARNING:
 			if self.__lev == logging.WARNING:
 				self.__logger.warning("[" + simtime + "]  " + self.__string, extra={"block": self})
 				self.__logger.warning("[" + simtime + "]  " + self.__string, extra={"block": self})
 			elif self.__lev == logging.ERROR:
 			elif self.__lev == logging.ERROR:
@@ -1025,21 +1025,23 @@ class IntegratorBlock(CBD):
 		self.addConnection("sumState", "OUT1")
 		self.addConnection("sumState", "OUT1")
 
 
 
 
-class Clock(CBD):
+class Clock(BaseBlock):
 	"""
 	"""
 	System clock. **Must be present in a simulation model.**
 	System clock. **Must be present in a simulation model.**
 
 
 	Args:
 	Args:
-		block_name (str):   The name of the block.
-		start_time (float): Time at which the simulation starts. Defaults to 0.
+		block_name (str):       The name of the block.
+		start_delta (float):    Time delta at the start of the simulation. Defaults to 0.1.
+		start_time (float):     Time at which the simulation starts. Defaults to 0.
 
 
 	:Input Ports:
 	:Input Ports:
-		**h** -- The delta in-between timesteps. For fixed-rate simulations,
-		this must be linked up to a constant value (e.g. a :class:`ConstantBlock`).
+		**h** -- The delta for the next iteration. I.e., the time to wait until the next
+				 iteration can be computed.
 
 
 	:Output Ports:
 	:Output Ports:
 		- **time** -- The current simulation time.
 		- **time** -- The current simulation time.
 		- **rel_time** -- The relative simulation time, ignoring the start time.
 		- **rel_time** -- The relative simulation time, ignoring the start time.
+		- **delta_t** -- The current delta.
 
 
 	Warning:
 	Warning:
 		**Clock Usage Assumption:** When adding a (custom) clock to your model(s),
 		**Clock Usage Assumption:** When adding a (custom) clock to your model(s),
@@ -1047,8 +1049,8 @@ class Clock(CBD):
 		independent of the simulation algorithm used. I.e., changing the delay of a
 		independent of the simulation algorithm used. I.e., changing the delay of a
 		fixed-rate clock should only influence the accuracy of the signals, **not**
 		fixed-rate clock should only influence the accuracy of the signals, **not**
 		the correctness of the signals. It is forbidden to misuse these outputs for
 		the correctness of the signals. It is forbidden to misuse these outputs for
-		specific simulations (e.g., using the :code:`time` as a counter, using
-		:code:`delta` as a constant value...).
+		specific simulations (e.g., using the :code:`time` as a counter, assuming
+		:code:`delta_t` is a constant value...).
 
 
 		In other words, the clock is guaranteed to output a correct value and should
 		In other words, the clock is guaranteed to output a correct value and should
 		only be used in the context of "time". When exporting the CBD model to other
 		only be used in the context of "time". When exporting the CBD model to other
@@ -1058,147 +1060,56 @@ class Clock(CBD):
 	See Also:
 	See Also:
 		- :class:`TimeBlock`
 		- :class:`TimeBlock`
 		- :class:`DeltaTBlock`
 		- :class:`DeltaTBlock`
-		- :class:`DummyClock`
 	"""
 	"""
-	def __init__(self, block_name, start_time=0.0):
-		# TODO: simplify if start_time is 0
-		CBD.__init__(self, block_name, ["h"], ["time", "rel_time", "delta"])
+	def __init__(self, block_name, start_delta=0.1, start_time=0.0):
+		BaseBlock.__init__(self, block_name, ["h"], ["time", "rel_time", "delta_t"])
+		self.__start_delta = start_delta
 		self.__start_time = start_time
 		self.__start_time = start_time
+		self.__delta = self.__start_delta
+		self.__time = self.__start_time
 
 
-		self.addBlock(ConstantBlock("IC", start_time))
-		self.addBlock(DelayBlock("delay"))
-		self.addBlock(AdderBlock("TSum"))
-		self.addBlock(AdderBlock("STSum"))
-		self.addBlock(NegatorBlock("STNeg"))
-		self.addBlock(ConstantBlock("Past", 0.0))
-		self.addBlock(AdderBlock("PastSum"))
-
-		self.addConnection("h", "TSum")
-		self.addConnection("delay", "TSum")
-		self.addConnection("TSum", "delay", input_port_name='IN1')
-		self.addConnection("delay", "PastSum")
-		self.addConnection("Past", "PastSum")
-		self.addConnection("PastSum", "time")
-
-		self.addConnection("IC", "delay", input_port_name='IC')
+	def getDependencies(self, curIteration):
+		return []
 
 
-		self.addConnection("IC", "STNeg")
-		self.addConnection("PastSum", "STSum")
-		self.addConnection("STNeg", "STSum")
-		self.addConnection("STSum", "rel_time")
+	def compute(self, curIteration):
+		if curIteration > 0:
+			self.__delta = self.getInputSignal(curIteration - 1, "h").value
+		self.__time += self.__delta
 
 
-		self.addConnection("h", "delta")
+		self.appendToSignal(self.__time, "time")
+		self.appendToSignal(self.getRelativeTime(), "rel_time")
+		self.appendToSignal(self.__delta, "delta_t")
 
 
-	def getTime(self, curIt):
+	def getTime(self):
 		"""
 		"""
 		Gets the current time of the clock.
 		Gets the current time of the clock.
 		"""
 		"""
-		# FIXME: this will produce wrong signals for all clock inputs and
-		#        all blocks in the clock itself
-		sig = self.getBlockByName("TSum").getSignalHistory("OUT1")
-		if curIt == 0 or len(sig) == 0:
-			return self.__start_time
-		return sig[curIt - 1].value
-
-	def getRelativeTime(self, curIt):
+		return self.__time
+
+	def getRelativeTime(self):
 		"""
 		"""
 		Gets the relative simulation time (ignoring the start time).
 		Gets the relative simulation time (ignoring the start time).
 		"""
 		"""
-		return self.getTime(curIt) - self.__start_time
+		return self.getTime() - self.__start_time
 
 
 	def setStartTime(self, start_time=0.0):
 	def setStartTime(self, start_time=0.0):
 		self.__start_time = start_time
 		self.__start_time = start_time
-		self.getBlockByName("IC").setValue(start_time)
 
 
 	def getDeltaT(self):
 	def getDeltaT(self):
-		dSig = self.getSignalHistory("delta")
-		if len(dSig) == 0:
-			return 0.0
-		return dSig[-1].value
+		return self.__delta
 
 
 	def reset(self):
 	def reset(self):
 		"""
 		"""
 		Resets the clock. Required for restarting a simulation.
 		Resets the clock. Required for restarting a simulation.
 		"""
 		"""
-		self.clearSignals()
-
-	def _rewind(self):
-		CBD._rewind(self)
-		time = self.getInputSignal(-1, "h").value
-		c = self.getBlockByName("Past")
-		c.setValue(c.getValue() - time)
-
-
-class DummyClock(BaseBlock):
-	"""
-	Dummy clock to be used in the tests. It contains the exact same functionality
-	as the actual fixed rate :class:`Clock`, but allows for testing without the
-	need for other correctly implemented blocks.
-
-	Args:
-		block_name (str):   The name of the block.
-		start_time (float): The tima at which the simulation starts. Defaults to 0.
-		delta (float):      The (fixed) time-delta between two iterations.
-
-	:Output Ports:
-		- **time** -- The current simulation time.
-		- **rel_time** -- The relative simulation time, ignoring the start time.
-		- **delta** -- The delay between two clock "ticks".
-
-	Warning:
-		Only use this block in the tests!
-
-	See Also:
-		- :class:`TimeBlock`
-		- :class:`DeltaTBlock`
-		- :class:`Clock`
-    """
-	def __init__(self, block_name, start_time=0.0, delta=0.1):
-		BaseBlock.__init__(self, block_name, [], ["time", "rel_time", "delta"])
-		self.__start_time = start_time
+		self.clearPorts()
 		self.__time = self.__start_time
 		self.__time = self.__start_time
-		self.__delta_t = delta
-
-	def compute(self, curIteration):
-		self.appendToSignal(self.__time, "time")
-		self.appendToSignal(self.__time - self.__start_time, "rel_time")
-		self.appendToSignal(self.__delta_t, "delta")
-		self.__time += self.__delta_t
-
-	def getTime(self, curIt):
-		"""
-		Obtains the current time of the clock.
-		"""
-		sig = self.getSignalHistory("time")
-		if curIt == 0 or len(sig) == 0:
-			return self.__start_time
-		return sig[curIt - 1].value + self.__delta_t
-
-	def getRelativeTime(self, curIt):
-		"""
-		Obtains the relative simulation time (ignoring the start time).
-		"""
-		return self.getTime(curIt) - self.__start_time
-
-	def getDeltaT(self):
-		"""
-		Obtains the time-delta.
-		"""
-		return self.__delta_t
-
-	def setDeltaT(self, dt):
-		"""
-		Sets the time-delta.
-		Args:
-			dt (float): New time delta.
-		"""
-		self.__delta_t = dt
-
-	def setStartTime(self, st):
-		self.__start_time = st
+		self.__delta = self.__start_delta
 
 
 	def _rewind(self):
 	def _rewind(self):
-		self.__start_time -= self.__delta_t
+		self.__time -= self.__delta
+		BaseBlock._rewind(self)
+		self.__delta = self.getInputSignal(-1, "h").value
 
 
 
 
 class SequenceBlock(BaseBlock):
 class SequenceBlock(BaseBlock):

+ 1 - 1
src/CBD/naivelog.py

@@ -44,7 +44,7 @@ class ColoredFormatter(logging.Formatter):
 			levelname_color = COLOR_SEQ % (30 + COLORS[levelname]) + levelname + RESET_SEQ
 			levelname_color = COLOR_SEQ % (30 + COLORS[levelname]) + levelname + RESET_SEQ
 			record.levelname = levelname_color
 			record.levelname = levelname_color
 		if hasattr(record, "block"):
 		if hasattr(record, "block"):
-			record.simtime = record.block.getClock().getTime(-1)
+			record.simtime = record.block.getClock().getTime()
 			record.blockname = record.block.getPath()
 			record.blockname = record.block.getPath()
 		return logging.Formatter.format(self, record)
 		return logging.Formatter.format(self, record)
 
 

+ 1 - 1
src/CBD/preprocessing/rungekutta.py

@@ -81,7 +81,7 @@ class RKPreprocessor:
 			if RK.hasBlock(inp):
 			if RK.hasBlock(inp):
 				new_model.addConnection(inp, RK, input_port_name=inp)
 				new_model.addConnection(inp, RK, input_port_name=inp)
 		old_clock = original.getClock()
 		old_clock = original.getClock()
-		new_model.addBlock(Clock("clock", old_clock.getTime(0) - old_clock.getRelativeTime(0)))
+		new_model.addBlock(Clock("clock", old_clock.getDeltaT()))
 		new_model.addConnection("clock", RK, input_port_name='time', output_port_name='time')
 		new_model.addConnection("clock", RK, input_port_name='time', output_port_name='time')
 		new_model.addConnection("clock", RK, input_port_name='rel_time', output_port_name='rel_time')
 		new_model.addConnection("clock", RK, input_port_name='rel_time', output_port_name='rel_time')
 		if RK.hasBlock("h_new"):
 		if RK.hasBlock("h_new"):

+ 2 - 2
src/CBD/simulator.py

@@ -235,7 +235,7 @@ class Simulator:
 			- :func:`setDeltaT`
 			- :func:`setDeltaT`
 			- :class:`CBD.lib.std.Clock`
 			- :class:`CBD.lib.std.Clock`
 		"""
 		"""
-		return self.getClock().getTime(self.__sim_data[2])
+		return self.getClock().getTime()
 
 
 	def getRelativeTime(self):
 	def getRelativeTime(self):
 		"""
 		"""
@@ -248,7 +248,7 @@ class Simulator:
 			- :func:`setDeltaT`
 			- :func:`setDeltaT`
 			- :class:`CBD.lib.std.Clock`
 			- :class:`CBD.lib.std.Clock`
 		"""
 		"""
-		return self.getClock().getRelativeTime(self.__sim_data[2])
+		return self.getClock().getRelativeTime()
 
 
 	def getDeltaT(self):
 	def getDeltaT(self):
 		"""
 		"""

+ 1 - 1
src/test/basicCBDTest.py

@@ -19,7 +19,7 @@ class BasicCBDTestCase(unittest.TestCase):
 	def _run(self, num_steps=1, delta_t = 1.0):
 	def _run(self, num_steps=1, delta_t = 1.0):
 		self.sim.setDeltaT(delta_t)
 		self.sim.setDeltaT(delta_t)
 		self.sim.setTerminationTime(num_steps * delta_t)
 		self.sim.setTerminationTime(num_steps * delta_t)
-		self.CBD.addBlock(DummyClock("clock", delta=delta_t))
+		self.CBD.addFixedRateClock("clock", delta_t, )
 		self.sim.run()
 		self.sim.run()
 
 
 	def _getSignal(self, blockname, output_port = None):
 	def _getSignal(self, blockname, output_port = None):

+ 1 - 1
src/test/stdCBDTest.py

@@ -19,7 +19,7 @@ class StdCBDTestCase(unittest.TestCase):
 	def _run(self, num_steps=1, delta_t = 1.0):
 	def _run(self, num_steps=1, delta_t = 1.0):
 		self.sim.setDeltaT(delta_t)
 		self.sim.setDeltaT(delta_t)
 		self.sim.setTerminationTime(num_steps * delta_t)
 		self.sim.setTerminationTime(num_steps * delta_t)
-		self.CBD.addBlock(DummyClock("clock", delta=delta_t))
+		self.CBD.addFixedRateClock("clock", delta_t)
 		self.sim.run()
 		self.sim.run()
 
 
 	def _getSignal(self, blockname, output_port = None):
 	def _getSignal(self, blockname, output_port = None):