def _test_normalization(Simulator, sys, rng, normalizer, l1_lower, lower, radius=5.0, dt=0.0001, T=1.0): l1_norms = np.empty(len(sys)) for i, sub in enumerate(decompose_states(sys)): response = impulse(sub, dt=dt, length=int(T / dt)) assert np.allclose(response[-10:], 0) l1_norms[i] = radius * np.sum(abs(response * dt)) with Network() as model: stim = nengo.Node(output=lambda t: rng.choice([-radius, radius]) if t < T/2 else radius) tau = 0.02 subnet = LinearNetwork(sys, n_neurons=1, synapse=tau, dt=dt, input_synapse=tau, radii=radius, normalizer=normalizer, neuron_type=nengo.neurons.Direct()) nengo.Connection(stim, subnet.input, synapse=None) p = nengo.Probe(subnet.x.output, synapse=None) assert ((l1_lower*subnet.info['radii'] <= l1_norms) | ((l1_norms <= 1e-6) & (subnet.info['radii'] <= 1e-6))).all() assert (l1_norms <= subnet.info['radii'] + 1e-4).all() with Simulator(model, dt=dt) as sim: sim.run(T) # lower bound includes both approximation error and the gap between # random {-1, 1} flip-flop inputs and the true worst-case input worst_x = np.max(abs(sim.data[p]), axis=0) assert (lower <= worst_x+1e-6).all() assert (worst_x <= 1+1e-6).all()
def test_state_norm(plt): # Choose a filter, timestep, and number of simulation timesteps sys = Alpha(0.1) dt = 0.000001 length = 2000000 # Modify the state-space to read out the state vector A, B, C, D = sys2ss(sys) old_C = C C = np.eye(len(A)) D = np.zeros((len(A), B.shape[1])) response = np.empty((length, len(C))) for i in range(len(C)): # Simulate the state vector response[:, i] = impulse((A, B, C[i, :], D[i, :]), dt, length) # Check that the power of each state equals the H2-norm of each state # The analog case is the same after scaling since dt is approx 0. actual = norm(response, axis=0) * dt assert np.allclose(actual, state_norm(cont2discrete(sys, dt))) assert np.allclose(actual, state_norm(sys) * np.sqrt(dt)) plt.figure() plt.plot(response[:, 0], label="$x_0$") plt.plot(response[:, 1], label="$x_1$") plt.plot(np.dot(response, old_C.T), label="$y$") plt.legend()
def test_box_filter(width, normalized): length = 20 steps = width + 1 sys = BoxFilter(width, normalized) y = impulse(sys, dt=None, length=length) amplitude = 1.0 / steps if normalized else 1.0 y_ideal = amplitude * np.asarray([1]*steps + [0]*(length - steps)) assert np.allclose(y, y_ideal)
def test_pade_delay(c): dt = 0.001 length = 1000 sys = PureDelay(c, order=4) response = impulse(sys, dt, length) offset = 10 assert np.allclose( (np.argmax(response[offset:])+offset), c*length, atol=100)
def test_highpass(tau, order): sys = Highpass(tau, order) length = 1000 dt = 0.001 response = impulse(sys, dt, length) dft = np.fft.rfft(response, axis=0) p = abs(dft) # Check that the power is monotonically increasing assert np.allclose(np.sort(p), p)
def test_bandpass(freq, Q): sys = Bandpass(freq, Q) length = 10000 dt = 0.0001 response = impulse(sys, dt, length) dft = np.fft.rfft(response, axis=0) freqs = np.fft.rfftfreq(length, d=dt) cp = abs(dft).cumsum() # Check that the cumulative power reaches its mean at Q frequency np.allclose(freqs[np.where(cp >= cp[-1] / 2)[0][0]], Q)
def test_l1_norm_unknown(sys): # These impulse responses have zero-crossings which makes computing their # exact L1-norm infeasible without simulation. dt = 0.0001 length = 500000 response = impulse(sys, dt=dt, length=length) assert np.allclose(response[-10:], 0) l1_est = np.sum(abs(response) * dt) desired_rtol = 1e-6 l1, rtol = l1_norm(sys, rtol=desired_rtol, max_length=2*length) assert np.allclose(l1, l1_est, rtol=1e-3) assert rtol <= desired_rtol
def test_radii(Simulator, seed, plt): sys = canonical(PureDelay(0.1, order=4)) dt = 0.001 T = 0.3 plt.figure() # Precompute the exact bounds for an impulse stimulus radii = [] for sub in decompose_states(sys): response = impulse(sub, dt=dt, length=int(T / dt)) amplitude = np.max(abs(response)) assert amplitude >= 1e-6 # otherwise numerical issues radii.append(amplitude) plt.plot(response / amplitude, linestyle='--') with Network(seed=seed) as model: # Impulse stimulus stim = nengo.Node(output=lambda t: 1 / dt if t <= dt else 0) # Set explicit radii for controllable realization subnet = LinearNetwork(sys, n_neurons=1, synapse=0.2, input_synapse=0.2, dt=dt, radii=radii, normalizer=Controllable(), neuron_type=nengo.neurons.Direct()) nengo.Connection(stim, subnet.input, synapse=None) p = nengo.Probe(subnet.x.output, synapse=None) assert subnet.info == {} sim = nengo.Simulator(model, dt=dt) sim.run(T) plt.plot(sim.data[p], lw=5, alpha=0.5) assert np.allclose(np.max(abs(sim.data[p]), axis=0), 1, atol=1e-3)
def test_pure_delay(steps): length = 20 sys = DiscreteDelay(steps) y = impulse(sys, dt=None, length=length) assert np.allclose(y, [0]*steps + [1] + [0]*(length - steps - 1))