|
@@ -197,6 +197,129 @@ Element function list_pop(list : Element):
|
|
|
String function readType(model : Element, name : String):
|
|
|
return reverseKeyLookup(model["metamodel"]["model"], dict_read_node(model["type_mapping"], model["model"][name]))!
|
|
|
|
|
|
+Boolean function solve_scc(model : Element, scc : Element):
|
|
|
+ Element m
|
|
|
+ Integer i
|
|
|
+ Integer j
|
|
|
+ String block
|
|
|
+ String blocktype
|
|
|
+ Element incoming
|
|
|
+ String selected
|
|
|
+ Float constant
|
|
|
+ Element t
|
|
|
+
|
|
|
+ // Construct the matrix first, with as many rows as there are variables
|
|
|
+ // Number of columns is 1 higher
|
|
|
+ i = 0
|
|
|
+ m = create_node()
|
|
|
+ while (i < read_nr_out(scc)):
|
|
|
+ j = 0
|
|
|
+ t = create_node()
|
|
|
+ while (j < (read_nr_out(scc) + 1)):
|
|
|
+ list_append(t, 0.0)
|
|
|
+ j = j + 1
|
|
|
+ list_append(m, t)
|
|
|
+ i = i + 1
|
|
|
+
|
|
|
+ log("Matrix ready!")
|
|
|
+ // Matrix initialized to 0.0
|
|
|
+ i = 0
|
|
|
+ while (i < read_nr_out(scc)):
|
|
|
+ log("Creating matrix row")
|
|
|
+ // First element of scc
|
|
|
+ block = cast_v2s(list_read(scc, i))
|
|
|
+ blocktype = readType(model, block)
|
|
|
+
|
|
|
+ // First write 1 in the current block
|
|
|
+ dict_overwrite(m[i], i, 1.0)
|
|
|
+
|
|
|
+ // Now check all blocks that are incoming
|
|
|
+ if (blocktype == "AdditionBlock"):
|
|
|
+ constant = 0.0
|
|
|
+ elif (blocktype == "MultiplyBlock"):
|
|
|
+ constant = 1.0
|
|
|
+ incoming = allIncomingAssociationInstances(model, block, "Link")
|
|
|
+
|
|
|
+ Integer index_to_write_constant
|
|
|
+ index_to_write_constant = -1
|
|
|
+ log("Iterating over incoming")
|
|
|
+ while (read_nr_out(incoming) > 0):
|
|
|
+ log("Iteration")
|
|
|
+ selected = readAssociationSource(model, set_pop(incoming))
|
|
|
+
|
|
|
+ if (set_in(scc, selected)):
|
|
|
+ // Part of the loop, so in the index of selected in scc
|
|
|
+ // Five options:
|
|
|
+ if (blocktype == "AdditionBlock"):
|
|
|
+ // 1) AdditionBlock
|
|
|
+ // Add the negative of this signal, which is as of yet unknown
|
|
|
+ // x = y + z --> x - y - z = 0
|
|
|
+ dict_overwrite(m[i], list_index_of(scc, selected), -1.0)
|
|
|
+ elif (blocktype == "MultiplyBlock"):
|
|
|
+ // 2) MultiplyBlock
|
|
|
+ if (index_to_write_constant != -1):
|
|
|
+ return False!
|
|
|
+ index_to_write_constant = list_index_of(scc, selected)
|
|
|
+ elif (blocktype == "NegatorBlock"):
|
|
|
+ // 3) NegatorBlock
|
|
|
+ // Add the positive of the signal, which is as of yet unknown
|
|
|
+ dict_overwrite(m[i], list_index_of(scc, selected), 1.0)
|
|
|
+ elif (blocktype == "DelayBlock"):
|
|
|
+ // 5) DelayBlock
|
|
|
+ // Just copies a single value
|
|
|
+ dict_overwrite(m[i], list_index_of(scc, selected), -1.0)
|
|
|
+ else:
|
|
|
+ // Block that cannot be handled
|
|
|
+ return False!
|
|
|
+ else:
|
|
|
+ // A constant, which we can assume is already computed and thus usable
|
|
|
+ if (blocktype == "AdditionBlock"):
|
|
|
+ constant = constant + v2f(read_attribute(model, selected, "signal"))
|
|
|
+ dict_overwrite(m[i], read_nr_out(scc), -constant)
|
|
|
+ elif (blocktype == "MultiplyBlock"):
|
|
|
+ constant = constant * v2f(read_attribute(model, selected, "signal"))
|
|
|
+ // Not written to constant part, as multiplies a variable
|
|
|
+
|
|
|
+ // Any other block is impossible:
|
|
|
+ // * Constant would never be part of a SCC
|
|
|
+ // * Delay would never get an incoming constant
|
|
|
+ // * Negation and Inverse only get 1 input, which is a variable in a loop
|
|
|
+ // * Integrator and Derivator never get an incoming constant
|
|
|
+
|
|
|
+ if (index_to_write_constant != -1):
|
|
|
+ dict_overwrite(m[i], index_to_write_constant, -constant)
|
|
|
+
|
|
|
+ i = i + 1
|
|
|
+
|
|
|
+ // Constructed a complete matrix, so we can start!
|
|
|
+ log("Constructed matrix to solve:")
|
|
|
+ log(matrix2string(m))
|
|
|
+
|
|
|
+ // Solve matrix now
|
|
|
+ eliminateGaussJordan(m)
|
|
|
+
|
|
|
+ // Now go over m and set signals for each element
|
|
|
+ // Assume that everything worked out...
|
|
|
+ i = 0
|
|
|
+ while (i < read_nr_out(m)):
|
|
|
+ block = scc[i]
|
|
|
+ unset_attribute(model, block, "signal")
|
|
|
+ instantiate_attribute(model, block, "signal", m[i][read_nr_out(scc)])
|
|
|
+ log((("Solved " + block) + " to ") + cast_v2s(m[i][read_nr_out(scc)]))
|
|
|
+ output((("SIM_PROBE " + cast_v2s(block)) + " ") + cast_v2s(m[i][read_nr_out(scc)]))
|
|
|
+
|
|
|
+ return True!
|
|
|
+
|
|
|
+Integer function list_index_of(lst : Element, elem : Element):
|
|
|
+ Integer i
|
|
|
+ i = 0
|
|
|
+ while (i < read_nr_out(lst)):
|
|
|
+ if (value_eq(list_read(lst, i), elem)):
|
|
|
+ return i!
|
|
|
+ else:
|
|
|
+ i = i + 1
|
|
|
+ return -1!
|
|
|
+
|
|
|
Void function step_simulation(model : Element, schedule : Element):
|
|
|
String time
|
|
|
Float signal
|
|
@@ -221,9 +344,10 @@ Void function step_simulation(model : Element, schedule : Element):
|
|
|
i = i + 1
|
|
|
|
|
|
if (list_len(scc) > 1):
|
|
|
- output("ALGEBRAIC_LOOP")
|
|
|
- // TODO solve if possible
|
|
|
- return !
|
|
|
+ log("Solving algebraic loop!")
|
|
|
+ if (bool_not(solve_scc(model, scc))):
|
|
|
+ output("ALGEBRAIC_LOOP")
|
|
|
+ return !
|
|
|
else:
|
|
|
block = set_pop(scc)
|
|
|
|