Hi @vzanon, and welcome back to the Nengo forums.
I’m not entirely clear where you want to perform the analysis of these signals, so I’ll describe a few options. If you are looking to analyze the signals after the simulation has completed, the best way to do this is to use probes to obtain the signals, then use regular Python code to perform the analysis. As an example:
with nengo.Network() a model:
ens = nengo.Ensemble(...)
...
probe_ens = nengo.Probe(ens)
with nengo.Simulator(model) as sim:
sim.run(1)
probe_data = sim.data[probe_ens]
std_data = np.std(probe_data)
Note that in the approach above, you’ll be performing the analysis on data recorded for each timestep of the simulation. If you don’t want to do this, and only use data recorded at a specific interval, you can use the sample_every
parameter of the nengo.Probe
to do this:
probe_ens = nengo.Probe(ens, sample_every=0.1) # sample ens output every 0.1s
If you are looking to analyze the signal as the simulation is running, this is a little more complex. For this, the easiest is probably to put it in a nengo.Node
. However, you’ll need to take into account that the function you pass to the node is evaluated at every timestep of the simulation. So, if you want to calculate something like the STD, you’ll need it to maintain a history of some sort. This forum thread has an example of how one user accomplishes this.
The last way I can think of analyzing the data is using a spiking network to perform the analysis. This is an even more complex option than using a nengo.Node
since you’ll need to design a spiking network to do this. You’ll need a memory circuit to store all of the information, one set of ensemble to compute the mean, then more ensembles to perform the square function, and another ensemble to perform the summation and square root. The ensembles performing the mathematical formula to compute the STD are not too difficult to implement (it’ll be a triple layer network of ensembles), but the memory circuit to store the data points would be difficult to implement since it’ll require timing circuits to operate correctly. I would recommend not going this approach.
For nengo.Connection
s, this is not the case. In fact, both function
and transform
are used to do the same thing: solve for the connection’s weights. As an example, the following two pieces of code will result in the same connection weights:
# Connection with transform
with nengo.Network() as model:
ens = nengo.Ensemble(30, 1, seed=1)
out = nengo.Node(size_in=1)
conn = nengo.Connection(ens, out, transform=2)
p_conn = nengo.Probe(conn, "weights")
with nengo.Simulator(model) as sim:
sim.run(0.001)
print(sim.data[p_conn])
# Connection with function
with nengo.Network() as model:
ens = nengo.Ensemble(30, 1, seed=1)
out = nengo.Node(size_in=1)
conn = nengo.Connection(ens, out, function=lambda x: 2 * x)
p_conn = nengo.Probe(conn, "weights")
with nengo.Simulator(model) as sim:
sim.run(0.001)
print(sim.data[p_conn])
Functions are only evaluated at each timestep for nengo.Nodes
. Functions passed to nengo.Connection
s are used by Nengo during the weight solving step to solve for a set of weights that approximate the desired function over a specific input range. For single dimensional values, the default range is from -1 to 1. For multi-dimensional values, the default range are points within the unit hypersphere. All this is to say that after Nengo has done the weights solving, any input value that is provided to the ensemble (that is inside the range of values) will cause the output signal of the ensemble to approximate the desired function applied to the input value. One important note about this process is that once the weights have been solved for, the weights become static, and do not change over time (unless a learning rule is applied to it).
From your code, you’ve passed the np.std
function as a parameter to the nengo.Connection
’s function
parameter. This doesn’t (probably) have the effect you want it to have. Here’s what it actually does:
- By doing it this way, the initial weights that Nengo puts between
pre
andpost
will approximate the result of theinit_func
. Ostensively, this means that when the simulation first starts, the network will “compute” the STD function on the input signal, but because there’s a learning rule applied to that connection, the weights will slowly be modified to compute the identity (y=x) function instead. What this really means is that nothing in the network ends up computing the STD function. - Another issue is that the STD function is meant to be computed over a series of data points. In your code, however, the output of
pre
and the input topost
are single dimensional. This means that Nengo will try to solve for weights that compute the STD of a single dimensional vector (becausex
that is passed tonp.std(x)
is 1D).
If I understand what you are attempting to do, I think the approach you want to take is to use the nengo.Probe
s to collect the data, and then perform the STD analysis on it after the simulation has completed.