rparedis 5 лет назад
Родитель
Сommit
17ddfc5891

Разница между файлами не показана из-за своего большого размера
+ 1 - 1
examples/AGV/AGV.drawio


+ 161 - 18
examples/AGV/AGV.py

@@ -1,38 +1,134 @@
 #!/usr/bin/python3
 # This file was automatically generated from drawio2cbd with the command:
-#   /home/red/git/DrawioConvert/__main__.py AGV.drawio -Sargv -e AGV -F CBD -E delta=0.1 -t 100
+#   /home/red/git/DrawioConvert/__main__.py -F CBD -E delta=0.001 -aSgrvs -t 100 AGV.drawio -e AGVVirtual
 
 from CBD.CBD import *
 from CBD.lib.std import *
 from ev3 import _PI as PI
 from ev3 import *
+from env import PathBlock
+from CBD.lib.endpoints import *
+
+DELTA_T = 0.001
+
+class OdometryBase(CBD):
+    def __init__(self, block_name, r=(0.03), d=(0.18)):
+        CBD.__init__(self, block_name, input_ports=['phiLdot', 'heading', 'phiRdot'], output_ports=['ydot', 'xdot'])
+
+        # Create the Blocks
+        self.addBlock(ConstantBlock("r", value=(r)))
+        self.addBlock(GenericBlock("sin", block_operator=("sin")))
+        self.addBlock(GenericBlock("cos", block_operator=("cos")))
+        self.addBlock(AdderBlock("B-OUZVyqj9DiQNmVnVL9-16"))
+        self.addBlock(ConstantBlock("half", value=(0.5)))
+        self.addBlock(ProductBlock("div2"))
+        self.addBlock(ProductBlock("mulX"))
+        self.addBlock(ProductBlock("mulY"))
+        self.addBlock(ProductBlock("mulSin"))
+        self.addBlock(ProductBlock("mulCos"))
+
+        # Create the Connections
+        self.addConnection("phiLdot", "B-OUZVyqj9DiQNmVnVL9-16", input_port_name='IN1')
+        self.addConnection("phiRdot", "B-OUZVyqj9DiQNmVnVL9-16", input_port_name='IN2')
+        self.addConnection("half", "div2", output_port_name='OUT1', input_port_name='IN1')
+        self.addConnection("B-OUZVyqj9DiQNmVnVL9-16", "div2", output_port_name='OUT1', input_port_name='IN2')
+        self.addConnection("mulX", "ydot", output_port_name='OUT1')
+        self.addConnection("div2", "mulX", output_port_name='OUT1', input_port_name='IN1')
+        self.addConnection("div2", "mulY", output_port_name='OUT1', input_port_name='IN1')
+        self.addConnection("mulY", "xdot", output_port_name='OUT1')
+        self.addConnection("heading", "sin", input_port_name='IN1')
+        self.addConnection("heading", "cos", input_port_name='IN1')
+        self.addConnection("mulSin", "mulX", output_port_name='OUT1', input_port_name='IN2')
+        self.addConnection("sin", "mulSin", output_port_name='OUT1', input_port_name='IN1')
+        self.addConnection("r", "mulSin", output_port_name='OUT1', input_port_name='IN2')
+        self.addConnection("r", "mulCos", output_port_name='OUT1', input_port_name='IN1')
+        self.addConnection("mulCos", "mulY", output_port_name='OUT1', input_port_name='IN2')
+        self.addConnection("cos", "mulCos", output_port_name='OUT1', input_port_name='IN2')
+
+
+class Odometry(CBD):
+    def __init__(self, block_name, initial=(0,0,0), wheel_radius=(0.03), wheel_axis=(0.18)):
+        CBD.__init__(self, block_name, input_ports=['phiLdot', 'phiRdot'], output_ports=['y', 'heading', 'x'])
+
+        # Create the Blocks
+        self.addBlock(IntegratorBlock("int_w"))
+        self.addBlock(ConstantBlock("delta", value=(DELTA_T)))
+        self.addBlock(OdometryBase("base", r=(wheel_radius)))
+        self.addBlock(IntegratorBlock("int_x"))
+        self.addBlock(IntegratorBlock("int_y"))
+        self.addBlock(ConstantBlock("init_x", value=(initial[0])))
+        self.addBlock(ConstantBlock("init_y", value=(initial[1])))
+        self.addBlock(OdometryW("OCegTr4naEkMIVMNTQIZ-73", r=(wheel_radius), d=(wheel_axis)))
+        self.addBlock(ConstantBlock("init_w", value=(initial[2])))
+
+        # Create the Connections
+        self.addConnection("delta", "int_w", output_port_name='OUT1', input_port_name='delta_t')
+        self.addConnection("delta", "int_y", output_port_name='OUT1', input_port_name='delta_t')
+        self.addConnection("delta", "int_x", output_port_name='OUT1', input_port_name='delta_t')
+        self.addConnection("int_w", "heading", output_port_name='OUT1')
+        self.addConnection("int_w", "base", output_port_name='OUT1', input_port_name='heading')
+        self.addConnection("phiLdot", "base", input_port_name='phiLdot')
+        self.addConnection("phiLdot", "OCegTr4naEkMIVMNTQIZ-73", input_port_name='phiLdot')
+        self.addConnection("phiRdot", "base", input_port_name='phiRdot')
+        self.addConnection("phiRdot", "OCegTr4naEkMIVMNTQIZ-73", input_port_name='phiRdot')
+        self.addConnection("base", "int_x", output_port_name='xdot', input_port_name='IN1')
+        self.addConnection("base", "int_y", output_port_name='ydot', input_port_name='IN1')
+        self.addConnection("int_x", "x", output_port_name='OUT1')
+        self.addConnection("int_y", "y", output_port_name='OUT1')
+        self.addConnection("OCegTr4naEkMIVMNTQIZ-73", "int_w", output_port_name='wdot', input_port_name='IN1')
+        self.addConnection("init_w", "int_w", output_port_name='OUT1', input_port_name='IC')
+        self.addConnection("init_y", "int_y", output_port_name='OUT1', input_port_name='IC')
+        self.addConnection("init_x", "int_x", output_port_name='OUT1', input_port_name='IC')
+
+
+class OdometryW(CBD):
+    def __init__(self, block_name, d=(0.18), r=(0.03)):
+        CBD.__init__(self, block_name, input_ports=['phiLdot', 'phiRdot'], output_ports=['wdot'])
+
+        # Create the Blocks
+        self.addBlock(ConstantBlock("rneg", value=(-r)))
+        self.addBlock(NegatorBlock("OCegTr4naEkMIVMNTQIZ-39"))
+        self.addBlock(AdderBlock("OCegTr4naEkMIVMNTQIZ-43"))
+        self.addBlock(ProductBlock("multr"))
+        self.addBlock(ConstantBlock("invd", value=(1.0/d)))
+        self.addBlock(ProductBlock("multd"))
+
+        # Create the Connections
+        self.addConnection("phiRdot", "OCegTr4naEkMIVMNTQIZ-39", input_port_name='IN1')
+        self.addConnection("phiLdot", "OCegTr4naEkMIVMNTQIZ-43", input_port_name='IN1')
+        self.addConnection("OCegTr4naEkMIVMNTQIZ-39", "OCegTr4naEkMIVMNTQIZ-43", output_port_name='OUT1', input_port_name='IN2')
+        self.addConnection("OCegTr4naEkMIVMNTQIZ-43", "multr", output_port_name='OUT1', input_port_name='IN1')
+        self.addConnection("rneg", "multr", output_port_name='OUT1', input_port_name='IN2')
+        self.addConnection("invd", "multd", output_port_name='OUT1', input_port_name='IN1')
+        self.addConnection("multr", "multd", output_port_name='OUT1', input_port_name='IN2')
+        self.addConnection("multd", "wdot", output_port_name='OUT1')
 
-DELTA_T = 0.1
 
 class Controller(CBD):
     def __init__(self, block_name, T=(50)):
-        super().__init__(block_name, input_ports=['color'], output_ports=['velocity', 'heading'])
+        CBD.__init__(self, block_name, input_ports=['color'], output_ports=['velocity', 'heading'])
 
         # Create the Blocks
         self.addBlock(ConstantBlock("v", value=(0.1)))
         self.addBlock(ConstantBlock("threshold", value=(-T)))
         self.addBlock(AdderBlock("sum"))
-        self.addBlock(ProductBlock("mult"))
-        self.addBlock(PID("PID"))
+        self.addBlock(ClampBlock("limit", min=(-1), max=(1)))
+        self.addBlock(ProductBlock("gOsFvuXVd93uCKtzi7wK-4"))
+        self.addBlock(ConstantBlock("gamma", value=(PI/2)))
 
         # Create the Connections
         self.addConnection("v", "velocity", output_port_name='OUT1')
-        self.addConnection("v", "mult", output_port_name='OUT1', input_port_name='IN1')
         self.addConnection("color", "sum", input_port_name='IN1')
         self.addConnection("threshold", "sum", output_port_name='OUT1', input_port_name='IN2')
-        self.addConnection("mult", "PID", output_port_name='OUT1', input_port_name='IN1')
-        self.addConnection("sum", "mult", output_port_name='OUT1', input_port_name='IN2')
-        self.addConnection("PID", "heading", output_port_name='OUT1')
+        self.addConnection("sum", "limit", output_port_name='OUT1', input_port_name='IN1')
+        self.addConnection("limit", "gOsFvuXVd93uCKtzi7wK-4", output_port_name='OUT1', input_port_name='IN1')
+        self.addConnection("gOsFvuXVd93uCKtzi7wK-4", "heading", output_port_name='OUT1')
+        self.addConnection("gamma", "gOsFvuXVd93uCKtzi7wK-4", output_port_name='OUT1', input_port_name='IN2')
 
 
 class PID(CBD):
-    def __init__(self, block_name, Kp=(0.3), Ki=(0.0), Kd=(0.5)):
-        super().__init__(block_name, input_ports=['IN1'], output_ports=['OUT1'])
+    def __init__(self, block_name, Kp=(0.03), Ki=(0.0), Kd=(0.05)):
+        CBD.__init__(self, block_name, input_ports=['IN1'], output_ports=['OUT1'])
 
         # Create the Blocks
         self.addBlock(ConstantBlock("Kp", value=(Kp)))
@@ -40,7 +136,7 @@ class PID(CBD):
         self.addBlock(ConstantBlock("Kd", value=(Kd)))
         self.addBlock(IntegratorBlock("int"))
         self.addBlock(DerivatorBlock("deriv"))
-        self.addBlock(ConstantBlock("delta_t", value=(0.01)))
+        self.addBlock(ConstantBlock("delta_t", value=(DELTA_T)))
         self.addBlock(ProductBlock("prod"))
         self.addBlock(ProductBlock("imult"))
         self.addBlock(ProductBlock("dmult"))
@@ -69,8 +165,8 @@ class PID(CBD):
 
 
 class DifferentialDrive(CBD):
-    def __init__(self, block_name, wheel_axis=(0.18), wheel_radius=(0.03), max_wheel_speed=(170/60*2*PI), p=(0.82)):
-        super().__init__(block_name, input_ports=['velocity', 'steering'], output_ports=['phiLdot', 'phiRdot'])
+    def __init__(self, block_name, wheel_axis=(0.18), wheel_radius=(0.03), max_wheel_speed=(170/60*2*PI), p=(0.85)):
+        CBD.__init__(self, block_name, input_ports=['velocity', 'steering'], output_ports=['phiLdot', 'phiRdot'])
 
         # Create the Blocks
         self.addBlock(ProductBlock("steeringMult"))
@@ -82,7 +178,7 @@ class DifferentialDrive(CBD):
         self.addBlock(NegatorBlock("neg"))
         self.addBlock(ProductBlock("leftMult"))
         self.addBlock(ProductBlock("rightMult"))
-        self.addBlock(ConstantBlock("WheelRadius", value=(wheel_radius)))
+        self.addBlock(ConstantBlock("WheelRadius", value=(1.0/wheel_radius)))
         self.addBlock(ClampBlock("leftClamp", min=(-p*max_wheel_speed), max=(p*max_wheel_speed)))
         self.addBlock(ClampBlock("rightClamp", min=(-p*max_wheel_speed), max=(p*max_wheel_speed)))
 
@@ -107,12 +203,12 @@ class DifferentialDrive(CBD):
 
 
 class AGV(CBD):
-    def __init__(self, block_name):
-        super().__init__(block_name, input_ports=[], output_ports=[])
+    def __init__(self, block_name, wheel_radius=(0.03), wheel_axis=(0.18)):
+        CBD.__init__(self, block_name, input_ports=[], output_ports=[])
 
         # Create the Blocks
         self.addBlock(Controller("Controller", T=(50)))
-        self.addBlock(DifferentialDrive("StaticPlant"))
+        self.addBlock(DifferentialDrive("StaticPlant", wheel_axis=(wheel_axis), wheel_radius=(wheel_radius)))
         self.addBlock(ReflectionSensorBlock("colorSensor", port_name=('1')))
         self.addBlock(MotorActuatorBlock("LeftMotor", port_name=('B')))
         self.addBlock(MotorActuatorBlock("RightMotor", port_name=('C')))
@@ -125,3 +221,50 @@ class AGV(CBD):
         self.addConnection("StaticPlant", "LeftMotor", output_port_name='phiLdot', input_port_name='IN1')
 
 
+class AGVVirtual(CBD):
+    def __init__(self, block_name, wheel_radius=(0.03), wheel_axis=(0.18), path_file=("paths/falcon.csv"), initial=(0, 0, 0)):
+        CBD.__init__(self, block_name, input_ports=[], output_ports=[])
+
+        # Create the Blocks
+        self.addBlock(Controller("Controller", T=(20)))
+        self.addBlock(DifferentialDrive("StaticPlant", wheel_axis=(wheel_axis), wheel_radius=(wheel_radius)))
+        self.addBlock(PathBlock("environment", path_file=(path_file)))
+        self.addBlock(PositionCollectorBlock("plot"))
+        self.addBlock(Odometry("vKpeSHbH8nwqUBcX28lP-0", initial=(initial)))
+        self.addBlock(SignalCollectorBlock("headingPlot"))
+
+        # Create the Connections
+        self.addConnection("Controller", "StaticPlant", output_port_name='heading', input_port_name='steering')
+        self.addConnection("Controller", "StaticPlant", output_port_name='velocity', input_port_name='velocity')
+        self.addConnection("environment", "Controller", output_port_name='color', input_port_name='color')
+        self.addConnection("StaticPlant", "vKpeSHbH8nwqUBcX28lP-0", output_port_name='phiLdot', input_port_name='phiLdot')
+        self.addConnection("StaticPlant", "vKpeSHbH8nwqUBcX28lP-0", output_port_name='phiRdot', input_port_name='phiRdot')
+        self.addConnection("vKpeSHbH8nwqUBcX28lP-0", "plot", output_port_name='x', input_port_name='X')
+        self.addConnection("vKpeSHbH8nwqUBcX28lP-0", "environment", output_port_name='x', input_port_name='x')
+        self.addConnection("vKpeSHbH8nwqUBcX28lP-0", "plot", output_port_name='y', input_port_name='Y')
+        self.addConnection("vKpeSHbH8nwqUBcX28lP-0", "environment", output_port_name='y', input_port_name='y')
+        self.addConnection("environment", "headingPlot", output_port_name='offset', input_port_name='IN1')
+
+
+class Test(CBD):
+    def __init__(self, block_name):
+        CBD.__init__(self, block_name, input_ports=[], output_ports=[])
+
+        # Create the Blocks
+        self.addBlock(Controller("Controller", T=(50)))
+        self.addBlock(SignalCollectorBlock("plot"))
+        self.addBlock(SignalCollectorBlock("headingPlot"))
+        self.addBlock(TimeBlock("x_KHUbakK0q4-W2-4amr-0"))
+        self.addBlock(DifferentialDrive("StaticPlant", wheel_axis=(0.18), wheel_radius=(0.03)))
+        self.addBlock(Odometry("mYLcSpGE1b6euuJ7r4uY-0", initial=([0, -3, 0])))
+
+        # Create the Connections
+        self.addConnection("x_KHUbakK0q4-W2-4amr-0", "Controller", output_port_name='OUT1', input_port_name='color')
+        self.addConnection("Controller", "StaticPlant", output_port_name='velocity', input_port_name='velocity')
+        self.addConnection("Controller", "StaticPlant", output_port_name='heading', input_port_name='steering')
+        self.addConnection("StaticPlant", "mYLcSpGE1b6euuJ7r4uY-0", output_port_name='phiLdot', input_port_name='phiLdot')
+        self.addConnection("StaticPlant", "mYLcSpGE1b6euuJ7r4uY-0", output_port_name='phiRdot', input_port_name='phiRdot')
+        self.addConnection("mYLcSpGE1b6euuJ7r4uY-0", "headingPlot", output_port_name='y', input_port_name='IN1')
+        self.addConnection("mYLcSpGE1b6euuJ7r4uY-0", "plot", output_port_name='x', input_port_name='IN1')
+
+

+ 48 - 0
examples/AGV/AGV_experiment.py

@@ -0,0 +1,48 @@
+#!/usr/bin/python3
+# This file was automatically generated from drawio2cbd with the command:
+#   /home/red/git/DrawioConvert/__main__.py -F CBD -e AGVVirtual -E delta=0.1 -aSgrvs -t 100 AGV.drawio
+
+from ev3 import _PI as PI
+from ev3 import *
+from env import PathBlock
+from AGV import *
+from CBD.simulator import Simulator
+import matplotlib.pyplot as plt
+from CBD.realtime.plotting import PlotManager, LinePlot, follow
+
+DELTA_T = 0.005
+
+fig, ax1 = plt.subplots(1, 1)
+# fig, (ax1, ax2) = plt.subplots(2, 1)
+ax1.set_xlim((-4.5, 4.5))
+ax1.set_ylim((-3.5, 5.5))
+# ax1.set_xlim((0, 100))
+# ax1.set_ylim((-0.07, 0.1))
+# ax2.set_xlim((0, 100))
+# ax2.set_ylim((-3, -2.7))
+
+cbd = AGVVirtual("AGVVirtual", initial=[0, -3, 0])
+# cbd = Test("Test")
+
+path = cbd.findBlock("environment")[0].path
+ax1.plot([e[0] for e in path], [e[1] for e in path], color='red')
+
+manager = PlotManager()
+manager.register("plot", cbd.findBlock("plot")[0], (fig, ax1), LinePlot())
+# manager.register("heading", cbd.findBlock("headingPlot")[0], (fig, ax2), LinePlot())
+# manager.connect('plot', 'update', lambda d, axis=ax1: axis.set_xlim((min(d[0]), max(d[0]))))
+# manager.connect('plot', 'update', lambda d, axis=ax1: axis.set_ylim((min(d[1]), max(d[1]))))
+# manager.connect('heading', 'update', lambda d, axis=ax2: axis.set_xlim(follow(d[0], 10.0, lower_bound=0.0)))
+# manager.connect('heading', 'update', lambda d, axis=ax2: axis.set_ylim((min(d[1]), max(d[1]))))
+
+# Run the Simulation
+sim = Simulator(cbd)
+sim.setRealTime(scale=0.1)
+sim.setProgressBar()
+sim.setDeltaT(DELTA_T)
+sim.run(100.0)
+
+plt.show()
+
+# print(cbd.findBlock("Controller")[0].getSignal("velocity"))
+# print(cbd.findBlock("plot")[0].data_xy)

+ 68 - 0
examples/AGV/env.py

@@ -0,0 +1,68 @@
+"""
+Pure code-based environment building blocks for AGV simulation.
+"""
+from CBD.CBD import BaseBlock
+
+class PathBlock(BaseBlock):
+	def __init__(self, block_name, path_file, path_width=0.06, grace=0.002, black=0, grey=0, white=100):
+		BaseBlock.__init__(self, block_name, ["x", "y"], ["color", "offset"])
+
+		self.path_width = path_width
+		self.grace = grace
+		self.black = black
+		self.grey = grey
+		self.white = white
+
+		self.path = []
+		with open(path_file, 'r') as file:
+			for line in file:
+				try:
+					pos = [float(l.strip()) for l in line.split(',')]
+				except Exception as e:
+					continue
+				self.path.append(pos[:2])
+
+	def compute(self, curIteration):
+		position = self.getInputSignal(curIteration, "x").value, self.getInputSignal(curIteration, "y").value
+		color = self.white
+		offset = float('inf')
+
+		for i, p1 in enumerate(self.path):
+			p2 = self.path[i-1]
+
+			dist = self.distance_to_line(p2, p1, position)
+			if dist < offset:
+				offset = dist
+
+			if dist < (self.path_width / 2.0):
+				color = self.black
+			elif color == self.white and dist <= (self.path_width / 2.0 + self.grace):
+				color = self.grey
+
+		self.appendToSignal(color, "color")
+		self.appendToSignal(offset, "offset")
+
+	def distance_to_line(self, p1, p2, p3):
+		"""
+		Computes the distance from a point p3 to the line segment given by (p1, p2).
+		Implementation based upon:
+			https://stackoverflow.com/a/6853926
+		"""
+		px = p2[0] - p1[0]
+		py = p2[1] - p1[1]
+
+		norm = px * px + py * py
+
+		if norm == 0.0:
+			ud = 0.0
+		else:
+			ud = float((p3[0] - p1[0]) * px + (p3[1] - p1[1]) * py) / norm
+			ud = min(max(ud, 0.0), 1.0)  # limits line segment to endpoints
+
+		xd = p1[0] + ud * px
+		yd = p1[1] + ud * py
+
+		dx = xd - p3[0]
+		dy = yd - p3[1]
+
+		return (dx * dx + dy * dy) ** 0.5

+ 16 - 0
examples/AGV/paths/falcon.csv

@@ -0,0 +1,16 @@
+x, y
+-0.5, 1
+-1, 2
+-1, 5
+-2, 5
+-3, 1
+-3, -1
+-2, -3
+2, -3
+3, -1
+3, 1
+2, 5
+1, 5
+1, 2
+0.5, 1
+-0.5, 1

+ 43 - 0
examples/AGV/paths/show_path.py

@@ -0,0 +1,43 @@
+# Read a CSV path specification and plot the data
+import matplotlib.pyplot as plt
+
+# Read and parse the file
+filename = input('Enter a file: ')
+x = []
+y = []
+with open(filename, 'r') as file:
+    for line in file:
+        try:
+            pos = [float(l.strip()) for l in line.split(',')]
+        except Exception as e:
+            continue
+        x.append(pos[0])
+        y.append(pos[1])
+
+# Set the axis ranges
+padding = 0.5
+xmin = min(x)
+ymin = min(y)
+xmax = max(x)
+ymax = max(y)
+xrange = abs(xmax - xmin)
+yrange = abs(ymax - ymin)
+
+if xrange > yrange:
+    yoff = (xrange - yrange) / 2
+    ymin -= yoff
+    ymax += yoff
+elif yrange > xrange:
+    xoff = (yrange - xrange) / 2
+    xmin -= xoff
+    xmax += xoff
+
+xmin -= padding
+ymin -= padding
+xmax += padding
+ymax += padding
+
+# Plot the path
+plt.plot(x, y)
+plt.axis([xmin, xmax, ymin, ymax])
+plt.show()

+ 5 - 4
src/CBD/lib/endpoints.py

@@ -46,7 +46,8 @@ class SignalCollectorBlock(CollectorBlock):
 		The collected data, as a pair of lists; i.e. the unzipped form of
 		:code:`xs, ys`.
 		"""
-		return [x for x, _ in self.data], [y for _, y in self.data]
+		D = self.data[:]
+		return [x for x, _ in D], [y for _, y in D]
 
 
 class PositionCollectorBlock(CollectorBlock):
@@ -57,8 +58,7 @@ class PositionCollectorBlock(CollectorBlock):
 		CollectorBlock.__init__(self, name, ["X", "Y"], [])
 
 	def compute(self, curIteration):
-		x = self.getInputSignal(curIteration, "X").value
-		y = self.getInputSignal(curIteration, "Y").value
+		x, y = self.getInputSignal(curIteration, "X").value, self.getInputSignal(curIteration, "Y").value
 		self.data.append((x, y))
 
 	def clear(self):
@@ -70,7 +70,8 @@ class PositionCollectorBlock(CollectorBlock):
 		The collected data, as a pair of lists; i.e. the unzipped form of
 		:code:`xs, ys`.
 		"""
-		return [x for x, _ in self.data], [y for _, y in self.data]
+		D = self.data[:]
+		return [x for x, _ in D], [y for _, y in D]
 
 
 class StatisticsCollectorBlock(CollectorBlock):

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

@@ -405,7 +405,7 @@ class IntegratorBlock(CBD):
 		# self.addConnection("delayState", "sumState")
 		# self.addConnection("sumState", "OUT1")
 
-		# FORWARD DIFFERENCE:
+		# FORWARD EULER:
 		# self.addBlock(ProductBlock("mul"))
 		# self.addBlock(AdderBlock("sum"))
 		# self.addBlock(AdderBlock("sum_ic"))
@@ -423,7 +423,7 @@ class IntegratorBlock(CBD):
 		# self.addConnection("mul", "sum_ic")
 		# self.addConnection("sum", "OUT1")
 
-		# BACKWARD DIFFERENCE:
+		# BACKWARD EULER:
 		self.addBlock(ConstantBlock(block_name="zero", value=0))
 		self.addBlock(DelayBlock(block_name="delayIn"))
 		self.addBlock(ProductBlock(block_name="multDelta"))

+ 16 - 3
src/CBD/solver.py

@@ -235,14 +235,27 @@ class Matrix:
 
 	Numpy could be used to even further increase efficiency, but this increases the
 	required dependencies for external hardware systems (that may not provide these options).
+
+	Note:
+		Internally, the matrix is segmented into chunks of 500.000.000 items.
 	"""
 	def __init__(self, rows, cols):
 		self.rows = rows
 		self.cols = cols
-		self.data = [0] * (rows * cols)
+		self.size = rows * cols
+		self.__max_list_size = 500 * 1000 * 1000
+		self.data = [[0] * ((rows * cols) % self.__max_list_size)]
+		for r in range(self.size // self.__max_list_size):
+			self.data.append([0] * self.__max_list_size)
 
 	def __getitem__(self, idx):
-		return self.data[idx[0] * self.cols + idx[1]]
+		absolute = idx[0] * self.cols + idx[1]
+		outer = absolute // self.__max_list_size
+		inner = absolute % self.__max_list_size
+		return self.data[outer][inner]
 
 	def __setitem__(self, idx, value):
-		self.data[idx[0] * self.cols + idx[1]] = value
+		absolute = idx[0] * self.cols + idx[1]
+		outer = absolute // self.__max_list_size
+		inner = absolute % self.__max_list_size
+		self.data[outer][inner] = value