I would like to switch the output of a Node from a standard function to a nengo.process programmatically.
In practice, I would like to achieve this:
input_node = nengo.Node(
output=lambda t: np.sin(t) if t < learn_time else nengo.processes.WhiteSignal(60),
size_out=dimensions
)
but I am getting the following error when the switch occurs:
nengo.exceptions.SimulationError: Function '<lambda>' returned a value WhiteSignal(period=60, high=5, rms=0.5) of invalid type <class 'nengo.processes.WhiteSignal'>
Is there no way to return a nengo.process object so that it works normally as:
I guess I could always save the weights from the Connection I’m interested in and re-run the simulation with a new input node, but that would be a much bigger hassle.
You can achieve this functionality by creating your own custom process. Here’s some example code to do this:
import matplotlib.pyplot as plt
import numpy as np
import nengo
from nengo.processes import Process, WhiteSignal
# Custom process class
class SignalSwitchProcess(Process):
def __init__(self, t_switch, **kwargs):
super().__init__(default_size_in=0, **kwargs)
# Time at which to perform the switch between the two signals
self.t_switch = t_switch
# Signal to use pre-switch
self.preswitch_signal = np.sin
# Signal to use post-switch
self.postswitch_signal = WhiteSignal(60, 3)
def make_step(self, shape_in, shape_out, dt, rng, state):
# Call the `make_step` method of any Process used. The `make_step` method
# creates the function that is actually called when the simulator evaluates one
# timestep. In this instance, `self.postswitch_signal` is a `nengo.Process`, so
# we call the `make_step` method for that.
postswitch_step = self.postswitch_signal.make_step(shape_in, shape_out, dt, rng, state)
# The function returned to the simulator to call for this custom process
def step_signalswitch(t):
if t < self.t_switch:
return self.preswitch_signal(t * 3 * np.pi)
else:
return postswitch_step(t)
return step_signalswitch
# Define the Nengo model
with nengo.Network() as model:
# Make a nengo node with our custom process
in_node = nengo.Node(SignalSwitchProcess(2))
p_in = nengo.Probe(in_node)
# Run the simulation
with nengo.Simulator(model) as sim:
sim.run(5)
# Plot the figures
plt.figure()
plt.plot(sim.trange(), sim.data[p_in])
plt.show()
And here is some sample output:
Note that this code does not bother to deal with the discontinuity at $t=2s$ when the signal switches over from one to the other.
Let me know if you have any further questions regarding the code!
Note: This code has been super quickly slapped together, so it hard codes several function parameters, but you get the idea.
Perfect, I had actually landed on a very similar solution myself but had got blocked on wondering how to make the dimensions of my WhiteNoise sub-processes match the one defined in the node’s size_out.
This line postswitch_step = self.postswitch_signal.make_step(shape_in, shape_out, dt, rng, state)was the answer