You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Output calcs produce 0's at every other call #1009
I've noticed that subsystems can produce outputs = 0 on every other call to a system's output function. The final result of the simulation is correct; however if you are doing something like processing quaternions in the output function, a quaternion of all zeros is invalid and an error results (without some hacky handling of that situation).
In the code below, line 1 printouts alternate between 0 and 1 rather than printing 1 at each call.
importnumpyasnpimportcontrolasctdefoutput_sys_outputs(t, x, u, params):
print(u) # alternates between zero and 1returnuoutput_sys=ct.nlsys(updfcn=None, outfcn=output_sys_outputs, inputs=1, outputs=1, name="output_sys")
definput_sys_outputs(t, x, u, params):
return1input_sys=ct.nlsys(updfcn=None, outfcn=input_sys_outputs, outputs=1, inputs=0, name="input_sys")
# outputs just 1'sinput_sim=ct.input_output_response(input_sys, T=np.linspace(0, 1, 100))
system=ct.interconnect(
(input_sys, output_sys),
connections=[
['output_sys.u', 'input_sys.y']
],
inplist=[],
outlist=['output_sys.y']
)
timeseries=ct.input_output_response(system, T=np.linspace(0, 1, 100))
y=timeseries.outputsprint(y) # prints all 1's
The reason you are seeing the alternating pattern is that when you have an interconnected system, you have to propagate the external inputs through the block structure before computing the derivative (or the final output). This is implemented in the InterconnectedSystem._compute_static_io method.
Generally, the idea is that you take the external inputs and compute the outputs for each of the subsystems. Any subsystem that was connected to the external input and had a feedthrough term (eg, nonzero D matrix) will now have a different output vector (which you couldn't know until you propagated the input through). If any of the outputs changed, you need to compute the outputs again, until you either stop getting changes or you determine there is an algebraic loop (which you can do by limiting the number of interactions to the number of subsystems).
For your example above, the first thing that happens is _compute_static_io computes the outputs for all of the subsystems, which is based on the current state (empty in your case). At this point in time, we don't (yet) know what the internal inputs are, so anything that is not an external input is just set to zero. In your example above, this means that input_sys gets called with no inputs and then output_sys gets called with one input (set to zero => you see a zero printed). Once we know what all of the outputs are for the subsystems, we can then call the output function again, this time with the proper input (set to 1 => now you see a one). Since the system inputs haven't changed on this second call (input_sys sent out a 1 again), we know we are done and so we can proceed to compute the derivative and/or output.
There might be a better way to implement this, but I think that in any case you have to call the output functions multiple in order to propagate external inputs through the interconnected system.
Gotcha, thanks for the thorough explanation. I was recently working on something similar to python-control (then switched to python-control as soon as I found it!) where I re-arranged the list of subsystems to compute things in a 'causal' order (line 204 here: https://github.com/corbinklett/modsim/blob/main/modsim/main.py). Not sure how easy it is to scale or generalize this. Definitely interested to see how others solve it!
Activity
murrayrm commentedon Jun 8, 2024
The reason you are seeing the alternating pattern is that when you have an interconnected system, you have to propagate the external inputs through the block structure before computing the derivative (or the final output). This is implemented in the
InterconnectedSystem._compute_static_iomethod.Generally, the idea is that you take the external inputs and compute the outputs for each of the subsystems. Any subsystem that was connected to the external input and had a feedthrough term (eg, nonzero D matrix) will now have a different output vector (which you couldn't know until you propagated the input through). If any of the outputs changed, you need to compute the outputs again, until you either stop getting changes or you determine there is an algebraic loop (which you can do by limiting the number of interactions to the number of subsystems).
For your example above, the first thing that happens is
_compute_static_iocomputes the outputs for all of the subsystems, which is based on the current state (empty in your case). At this point in time, we don't (yet) know what the internal inputs are, so anything that is not an external input is just set to zero. In your example above, this means thatinput_sysgets called with no inputs and thenoutput_sysgets called with one input (set to zero => you see a zero printed). Once we know what all of the outputs are for the subsystems, we can then call the output function again, this time with the proper input (set to 1 => now you see a one). Since the system inputs haven't changed on this second call (input_syssent out a 1 again), we know we are done and so we can proceed to compute the derivative and/or output.There might be a better way to implement this, but I think that in any case you have to call the output functions multiple in order to propagate external inputs through the interconnected system.
corbinklett commentedon Jun 8, 2024
Gotcha, thanks for the thorough explanation. I was recently working on something similar to python-control (then switched to python-control as soon as I found it!) where I re-arranged the list of subsystems to compute things in a 'causal' order (line 204 here: https://github.com/corbinklett/modsim/blob/main/modsim/main.py). Not sure how easy it is to scale or generalize this. Definitely interested to see how others solve it!