Switching Node output to nengo.process object

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:

input_node = nengo.Node(
            output=nengo.processes.WhiteSignal(60),
            size_out=dimensions
            )

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.

Thanks for any help you’ll be able to give me!

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:
image

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. :smile:

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 :slight_smile:

If anyone else may need it in the future, here is my implementation of switching between two Process instances (I made my generate_sines() function into a Process too as it was much cleaner): https://github.com/Tioz90/Learning-to-approximate-functions-using-niobium-doped-strontium-titanate-memristors/blob/469f7aa82ce37b48e1764e3b5d19a8ba5335a356/memristor_nengo/extras.py#L33