def test_filt_issue_nengo938(): # Testing related to nengo issue #938 # test combinations of _apply_filter / filt on nengo / nengolib # using a passthrough / (strictly) proper and y0=0 / y0=None # ... in an **ideal** world all of these would produce the same results # but we assert behaviour here so that it is at least documented # and so that we are alerted to any changes in these differences # https://github.com/nengo/nengo/issues/938 # https://github.com/nengo/nengo/issues/1124 sys_prop_nengo = nengo.LinearFilter([1], [1, 0]) sys_prop_nglib = LinearSystem(([1], [1, 0])) sys_pass_nengo = nengo.LinearFilter([1e-9, 1], [1, 0]) sys_pass_nglib = LinearSystem(([1e-9, 1], [1, 0])) u = np.asarray([1.0, 0.5, 0]) dt = 0.001 def filt_scipy(sys): return _apply_filter(sys, dt=dt, u=u) def filt_nengo(sys, y0): return sys.filt(u, dt=dt, y0=y0) # Strictly proper transfer function prop_nengo_apply = filt_scipy(sys_prop_nengo) prop_nglib_apply = filt_scipy(sys_prop_nglib) prop_nengo_filt0 = filt_nengo(sys_prop_nengo, y0=0) prop_nglib_filt0 = filt_nengo(sys_prop_nglib, y0=0) prop_nengo_filtN = filt_nengo(sys_prop_nengo, y0=None) prop_nglib_filtN = filt_nengo(sys_prop_nglib, y0=None) # => two equivalence classes _transclose(prop_nengo_apply, prop_nglib_apply) _transclose(prop_nengo_filt0, prop_nglib_filt0, prop_nglib_filtN) # One-step delay difference between these two classes _transclose(prop_nengo_apply[1:], prop_nengo_filt0[:-1]) # Passthrough transfer functions pass_nengo_apply = filt_scipy(sys_pass_nengo) pass_nglib_apply = filt_scipy(sys_pass_nglib) pass_nengo_filt0 = filt_nengo(sys_pass_nengo, y0=0) pass_nglib_filt0 = filt_nengo(sys_pass_nglib, y0=0) pass_nengo_filtN = filt_nengo(sys_pass_nengo, y0=None) pass_nglib_filtN = filt_nengo(sys_pass_nglib, y0=None) # => almost all are equivalent (except nengo with y0=None) _transclose(pass_nengo_apply, pass_nglib_apply, pass_nengo_filt0, pass_nglib_filt0, pass_nglib_filtN) assert not np.allclose(prop_nengo_filtN, pass_nengo_filtN) # And belongs to the same equivalence class as the very first _transclose(prop_nengo_apply, pass_nengo_apply)
def test_combined_delay(Simulator, allclose): # ensure that two sequential filters has the same output # as combining their individual discrete transfer functions nt = 50 tau = 0.005 dt = 0.001 sys1 = nengo.Lowpass(tau) (num,), den, _ = cont2discrete((sys1.num, sys1.den), dt=dt) sys2 = nengo.LinearFilter(np.poly1d(num) ** 2, np.poly1d(den) ** 2, analog=False) with nengo.Network() as model: u = nengo.Node(1) x = nengo.Node(size_in=1) nengo.Connection(u, x, synapse=sys1) p1 = nengo.Probe(x, synapse=sys1) p2 = nengo.Probe(u, synapse=sys2) with Simulator(model, dt=dt) as sim: sim.run_steps(nt) assert allclose(sim.data[p1], sim.data[p2]) # Both have two time-step delays: # for sys1, this comes from two levels of filtering # for sys2, this comes from one level of filtering + delay in sys2 assert allclose(sim.data[p1][:2], 0) assert not allclose(sim.data[p1][2], 0, record_rmse=False)
def test_from_parameters_force_width(self): # Create the mock signal and connection signal = SignalParameters(latching=True) rps = ReceptionParameters(nengo.LinearFilter([1.0], [0.5, 1.0]), 1) # Create the filter lpf = LinearFilter.from_parameters(signal, rps, width=2) assert lpf == LinearFilter(2, True, [1.0], [0.5, 1.0])
def test_filt(): u = np.asarray([1.0, 0, 0]) dt = 0.1 num, den = [1], [1, 2, 1] sys1 = nengo.LinearFilter(num, den) sys2 = LinearSystem((num, den)) # uses a different make_step y1 = sys1.filt(u, dt=dt, y0=0) y2 = sys2.filt(u, dt=dt, y0=0) assert np.allclose(y1, y2)
def test_linearfilter_extras(allclose): # This filter is just a gain, but caused index errors previously synapse = nengo.LinearFilter([3], [2]) assert allclose(synapse.filt([2.0]), 3) # differentiator should work properly diff = nengo.LinearFilter([1, -1], [1, 0], analog=False) assert allclose(diff.filt([1.0, -1.0, 2.0], y0=0), [1.0, -2.0, 3.0]) # Filtering an integer array should cast to a float x = np.arange(10, dtype=nengo.rc.int_dtype) synapse = nengo.LinearFilter([1], [0.005, 1]) assert synapse.filt(x).dtype == nengo.rc.float_dtype # Throw an error if non-float dtype shape = (1,) with pytest.raises(ValidationError, match="Only float data types"): synapse.make_state(shape, shape, dt=0.001, dtype=np.int32) with pytest.raises(ValidationError, match="Only float data types"): synapse.make_state(shape, shape, dt=0.001, dtype=np.complex64)
def test_lti_filter(num, den, t, rmse, tolerance): """Test the LTI filter.""" # Create the network with nengo.Network() as network: step = nengo.Node([1.0, -0.4]) probe = nengo.Probe(step, synapse=nengo.LinearFilter(num, den)) # Simulate with reference Nengo nsim = nengo.Simulator(network) nsim.run(t) # Simulate with SpiNNaker ssim = nengo_spinnaker.Simulator(network) with ssim: ssim.run(t) # Calculate the error error = nsim.data[probe] - ssim.data[probe] assert np.sqrt(np.mean(np.square(error))) <= rmse assert np.allclose(nsim.data[probe], ssim.data[probe], atol=tolerance)
def test_simulation(sys, Simulator, plt, seed): assert isinstance(sys, LinearSystem) old_sys = nengo.LinearFilter(sys.num, sys.den) assert sys == old_sys with Network() as model: stim = nengo.Node(output=nengo.processes.WhiteSignal( 1.0, high=10, seed=seed)) out_new = nengo.Node(size_in=2) out_old = nengo.Node(size_in=2) nengo.Connection(stim, out_new, transform=[[1], [-1]], synapse=sys) nengo.Connection(stim, out_old, transform=[[1], [-1]], synapse=old_sys) p_new = nengo.Probe(out_new) p_old = nengo.Probe(out_old) with Simulator(model) as sim: sim.run(1.0) plt.figure() plt.plot(sim.trange(), sim.data[p_new]) plt.plot(sim.trange(), sim.data[p_old]) assert np.allclose(sim.data[p_new], sim.data[p_old])
def make_sample(self, dt, d=1, rng=np.random): """Samples the process and advances the time. Parameters ---------- dt : float Timestep for each sample. d : int, optional The number of dimensions to return. Default: 1. rng : RandomState, optional Random number generator state. Returns ------- function A sample function that, when called, returns a 1d array of length ``d``. """ dist = nengo.dists.Gaussian(0., 1. / np.sqrt(dt)) output = np.zeros(d) step = nengo.LinearFilter([1], [1, 0]).make_step(dt, output, method='euler') return functools.partial(self.sample, dist, d, step, output, rng)
nengo.Connection(conf_sens[0], RS_pred_weighting[0]) nengo.Connection(conf_pred, RS_pred_weighting[1]) nengo.Connection(RS_mem_hat, RS_pred_weighting[2]) nengo.Connection(RS_pred_weighting, RS_sum, function=lambda x: (x[0] / (x[0] + x[1])) * x[2]) # Equation 16 # since the following does not work (improper transfer function) #nengo.Connection(RS_sum, Gv, # synapse=nengo.LinearFilter([7, 0], [0, 1])) nengo.Connection(RS_sum, Gv) nengo.Connection(RS_sum, Gv, transform=-1, synapse=Gv_synapse) # Equation 17 nengo.Connection(Gv, Hv, synapse=nengo.LinearFilter([35**2], [1, 2 * 0.8 * 35, 35**2])) # Equation 18 nengo.Connection(Hv, Av, transform=0.7) # Leaky Integrator, Fig 3 nengo.Connection(filt_leaky_integrator, leaky_integrator, synapse=leaky_int_synapse, transform=G_e) nengo.Connection(Av, leaky_integrator, synapse=leaky_int_synapse) nengo.Connection(leaky_integrator, filt_leaky_integrator, transform=G_int, synapse=nengo.LinearFilter([1], [1, 1 / tau_motor])) # Premotor system, Fig 1