Output of a Probe, Node or Ensemble

Hi,

I am new to nengo. How can I get the output of a probe or a node or an ensemble so that I can apply algebraic operations on the data? I mean I want the data to be an array. In this simple code for example, is it possible to get the output of the probe as an array? Thanks.

model = nengo.Network()
with model:

        a = nengo.Node(np.sin, size_out=1)

        b = nengo.Node(None, size_in=1)

        nengo.Connection(a,b)

        C = nengo.Probe(b)

Hi @smjh1371, and welcome to the Nengo forums! :smiley:

From your question, it’s unclear whether you are asking in the context of NengoGUI (the browser-based GUI), or just Nengo (the simulator that you can run in the Python command line). I know it can be somewhat confusing, but Nengo can be used to refer to both. :laughing:

Since you are asking to do analysis on probe data, you are probably looking to include your Nengo networks in more complex systems. As such, my recommendation would be to write your Nengo code and run them from the Python command line, or to run it within a Jupyter notebook. The downside to these approaches is that you’ll need to manage the graphs and plots yourself (i.e., using a package like matplotlib). To get you started with this approach, all of the examples found on the Nengo documentation page are formatted as Jupyter notebooks. You can also find these examples in the Nengo codebase here.

The primary difference between a Nengo model that you run in the GUI and one that you run from the Python command line (or Jupyter notebook) is that you’ll need to invoke the Nengo simulator yourself (NengoGUI handles the simulator invocation for you). A quick example of this is as follows:

import nengo
import numpy as np

# Define Nengo network
with nengo.Network() as model:
    a = nengo.Node(lambda t: np.sin(t))
    b = nengo.Node(size_in=1)
    nengo.Connection(a, b)
    c = nengo.Probe(b)

# Create and start the Nengo simulator
with nengo.Simulator(model) as sim:
    sim.run(1)  # Run the simulator for 1s

After you create and run the simulator, you can then access probed data as follows:

t_values = sim.trange()  # Provides a numpy array with all of the timesteps in the probed data
probed_values = sim.data[c]  # Returns a numpy array with all of the probed data for probe `c`

The probed data will have shape TxD where T is the number of timesteps in the simulation (i.e., sim_runtime / sim.dt – where sim.dt defaults to 0.001s), and D is the dimensionality of the probed object. For example, in the code above, T = 1000 and D = 1 (the output size of b is 1).

If you put all of the code above into a single python file (e.g., like so: test_nengo_code.py (592 Bytes))
You can run the Nengo simulation from a terminal like so:

python test_nengo_code.py

If you include graphing and plotting code in the Python code, the plots will show up as additional windows when the code is run.

Working entirely within NengoGUI
If you want to work entirely in NengoGUI, then there’s no real way to get at the probed data. However, you can still perform arithmetic operations on data using Nengo nodes. Simply define the arithmetic operation as a function and create a node with that function as an input:

def my_func(x):
    return <some_arthimetic_operation>

import nengo
import numpy as np

# Define Nengo network
with nengo.Network() as model:
    a = nengo.Node(lambda t: np.sin(t))
    b = nengo.Node(size_in=1)
    nengo.Connection(a, b)
    c = nengo.Node(my_func)
    nengo.Connection(b, c, synapse=None)  # Set None as synapse to avoid filtering the data

Once you have done this, you can then pull up the plot of the c node to visualize the effect the arithmetic operation has on the “probed” data (i.e., the output of b in the code above). Note that this arithmetic operation will be computed at every timestep of the simulation.

Thank you for your thorough explanation. In fact as you said I was a bit confused about how to NengoGUI (the browser-based GUI), or just Nengo (the simulator that you can run in the Python command line). I’m actually trying to simulate a dynamic system which I already simulated in Python. Now I need to simulate that in the context of Nengo.

Ah! I see. From that description, I believe you would want to be building your networks to be able to run from the Python command line. One of the advantages of Nengo is that since it is programmed entirely in Python, integrating it with other Python code is relatively simple.

The process for this typically involves putting the interface code (or the code that calls the environment’s API) inside a nengo.Node. Although these examples are written for NengoGUI (since the visualization of the environment is easier in the GUI), they demonstrate how Nengo networks can be written to interact with external environments.

Actually my main problem now is how to put that code in Nengo.I don’t know how to implement my whole system in Nengo. If it’s possible, I want to implement my system both in Nengo GUI and in also use Nengo in Pycharm. Could you please elaborate more on what you said, " The process for this typically involves putting the interface code (or the code that calls the environment’s API) inside a nengo.Node".
I really appreciate your help.

Like I mentioned previously, it really depends on how you have programmed your environment. Let’s say, for example, that your environment has an update() function that updates the environment (i.e., runs it one step forward). Then, in your Nengo code, you’ll want to create a node something like this:

with model:
    env_node = nengo.Node(env.update, size_in=1)

The update function should take in two parameters. The first being the current timestep of the Nengo simulation, and the second being whatever the input value to the node is. The dimensionality of this input is the size of the size_in parameter. So, if you need a bigger (more elements in the vector) value to be passed to your environment, then increase the value provided to size_in.

You can also create a separate update function that calls the environment update function, something like this:

def do_step(t, x):
    ...  # Process 'x'
    env.set_value(x)  # Set the values in the environment
    env.update()

with model:
    env_node = nengo.Node(do_step, size_in=1)

If you want your Nengo model to use values provided by your environment, simply set that as the return value for the function that you provide to the env_node:

def do_step(t, x):
    ... 
    return env.value

Once you have your environment node created, you can then connect to it using standard connections. For example:

with model:
    nengo.Connection(ens1, env_node)

If you are using the node to get values from the environment, you can create a connection from the node to something in your network:

with model:
    nengo.Connection(env_node, ens2)

Note that you can create multiple “environment nodes” in your network.

Here’s a small test script with Nengo interacting with a very simple environment. All the environment does is print out the value it has stored to the screen every time the update function is called:
test_nengo_env.py (776 Bytes)

Since Nengo is programmed in Python, there really are an infinite number of ways to integrate Nengo into whatever system you have designed. It’s quite hard to say exactly how you, in particular, should integrate Nengo within the system you are designing. If you could provide some description as to what your system looks like, or how it is intended to function without Nengo, I might be able to provide more advice to you.

Thanks for your comments. It’s a nonlinear dynamic system with 13 states along with its controller. I used Runge-Kutta for integration. I have defined some other functions as well. I’m not sure if it’s enough description .

From your description of the system, you’ll probably want to have a node that both sets and gets values from the environment. As I described above, you can achieve all of this with the Nengo node, and I’ve updated the example code with a function and environment class that allows you to do this (both get and set values in some environment class):
test_nengo_env.py (1.5 KB)

You can use my Python file as a template, or feel free to write your own code. :smiley:

I should note that the file I included above can be run in the NengoGUI. All you need to do is comment out the code starting with the definition of the Nengo simulator object:

with nengo.Simulator(model) as sim:
    # Run the simulation
    sim.run(10)


# Plot some figures
plt.figure()
plt.plot(sim.trange(), sim.data[p_out])
plt.tight_layout()
plt.show()

Once all of the above code is commented out, you can load up the Python file in NengoGUI, and it should run from there with no issues.

I also recommend this NengoFPGA example that illustrates how to integrate a dynamical system with Nengo and have it running in NengoGUI. Note that if you don’t have a supported FPGA available, you won’t be able to run the code without changes, so I’ve modified the code for standard Nengo here:
test_nengo_pendulum.py (5.8 KB)

Thank you for your comments. I will give it a try and come back to you with questions for sure.

1 Like