Exemple #1
0
def test_similarity_transform():
    sys = Alpha(0.1)

    TA, TB, TC, TD = sys.transform(np.eye(2), np.eye(2)).ss
    A, B, C, D = sys2ss(sys)
    assert np.allclose(A, TA)
    assert np.allclose(B, TB)
    assert np.allclose(C, TC)
    assert np.allclose(D, TD)

    T = [[1, 1], [-0.5, 0]]
    rsys = sys.transform(T)
    assert ss_equal(rsys, sys.transform(T, inv(T)))

    TA, TB, TC, TD = rsys.ss
    assert not np.allclose(A, TA)
    assert not np.allclose(B, TB)
    assert not np.allclose(C, TC)
    assert np.allclose(D, TD)
    assert sys_equal(sys, (TA, TB, TC, TD))

    length = 1000
    dt = 0.001
    x_old = np.asarray(
        [sub.impulse(length=length, dt=dt) for sub in sys])
    x_new = np.asarray(
        [sub.impulse(length=length, dt=dt) for sub in rsys])

    # dot(T, x_new(t)) = x_old(t)
    assert np.allclose(np.dot(T, x_new), x_old)
Exemple #2
0
def test_identity(radii):
    sys = Alpha(0.1)

    identity = Identity()
    assert repr(identity) == "Identity()"

    I = np.eye(len(sys))
    realize_result = identity(sys, radii)
    assert realize_result.sys is sys
    assert np.allclose(realize_result.T, I * radii)
    assert np.allclose(realize_result.Tinv, inv(I * radii))

    rsys = realize_result.realization
    assert ss_equal(rsys, sys.transform(realize_result.T))

    # Check that it's still the same system, even though different matrices
    assert sys_equal(sys, rsys)
    if radii == 1:
        assert ss_equal(sys, rsys)
    else:
        assert not np.allclose(sys.B, rsys.B)
        assert not np.allclose(sys.C, rsys.C)

    # Check that the state vectors have scaled power
    assert np.allclose(state_norm(sys) / radii, state_norm(rsys))
Exemple #3
0
def test_impulse_dt():
    length = 1000
    sys = Alpha(0.1)
    # the dt should not alter the magnitude of the response
    assert np.allclose(
        max(sys.impulse(length, dt=0.001)),
        max(sys.impulse(length, dt=0.0005)),
        atol=1e-4)
Exemple #4
0
def test_mapping(Simulator, plt, seed):
    sys = Alpha(0.1)
    syn = Lowpass(0.01)
    gsyn = 2*syn  # scaled lowpass
    isyn = 2/s  # scaled integrator
    dt = 0.001

    ss = ss2sim(sys, syn, None)  # normal lowpass, continuous
    dss = ss2sim(sys, syn, dt)  # normal lowpass, discrete
    gss = ss2sim(sys, gsyn, None)  # scaled lowpass, continuous
    gdss = ss2sim(sys, gsyn, dt)  # scaled lowpass, discrete
    iss = ss2sim(sys, isyn, None)  # scaled integrator, continuous
    idss = ss2sim(sys, isyn, dt)  # scaled integrator, discrete
    assert ss.analog and gss.analog and iss.analog
    assert not (dss.analog or gdss.analog or idss.analog)

    with Network(seed=seed) as model:
        stim = nengo.Node(output=lambda t: np.sin(20*np.pi*t))

        probes = []
        for mapped, synapse in ((ss, syn), (dss, syn), (gss, gsyn),
                                (gdss, gsyn), (iss, isyn), (idss, isyn)):
            A, B, C, D = mapped.ss
            x = nengo.Node(size_in=2)
            y = nengo.Node(size_in=1)

            nengo.Connection(stim, x, transform=B, synapse=synapse)
            nengo.Connection(x, x, transform=A, synapse=synapse)
            nengo.Connection(x, y, transform=C, synapse=None)
            nengo.Connection(stim, y, transform=D, synapse=None)

            probes.append(nengo.Probe(y))

        p_stim = nengo.Probe(stim)

    pss, pdss, pgss, pgdss, piss, pidss = probes

    with Simulator(model, dt=dt) as sim:
        sim.run(1.0)

    expected = shift(sys.filt(sim.data[p_stim], dt))

    plt.plot(sim.trange(), sim.data[pss], label="Continuous", alpha=0.5)
    plt.plot(sim.trange(), sim.data[pdss], label="Discrete", alpha=0.5)
    plt.plot(sim.trange(), sim.data[pgss], label="Gain Cont.", alpha=0.5)
    plt.plot(sim.trange(), sim.data[pgdss], label="Gain Disc.", alpha=0.5)
    plt.plot(sim.trange(), sim.data[piss], label="Integ Cont.", alpha=0.5)
    plt.plot(sim.trange(), sim.data[pidss], label="Integ Disc.", alpha=0.5)
    plt.plot(sim.trange(), expected, label="Expected", linestyle='--')
    plt.legend()

    assert np.allclose(sim.data[pss], expected, atol=0.01)
    assert np.allclose(sim.data[pdss], expected)
    assert np.allclose(sim.data[pgss], expected, atol=0.01)
    assert np.allclose(sim.data[pgdss], expected)
    assert np.allclose(sim.data[piss], expected, atol=0.01)
    assert np.allclose(sim.data[pidss], expected)
Exemple #5
0
def test_modred(rng):
    dt = 0.001
    isys = Lowpass(0.05)
    noise = 0.5 * Lowpass(0.01) + 0.5 * Alpha(0.005)
    p = 0.999
    sys = p * isys + (1 - p) * noise

    T, Tinv, S = balanced_transformation(sys)
    balsys = sys.transform(T, Tinv)

    # Keeping just the best state should remove the 3 noise dimensions
    # Discarding the lowest state should do at least as well
    for keep_states in (S.argmax(),
                        list(set(range(len(sys))) - set((S.argmin(), )))):
        delsys = modred(balsys, keep_states)
        assert delsys.order_den == np.asarray(keep_states).size

        u = rng.normal(size=2000)

        expected = sys.filt(u, dt)
        actual = delsys.filt(u, dt)
        assert rmse(expected, actual) < 1e-4

        step = np.zeros(2000)
        step[50:] = 1.0
        dcsys = modred(balsys, keep_states, method='dc')
        assert np.allclose(dcsys.dcgain, balsys.dcgain)

        # use of shift related to nengo issue #938
        assert not sys.has_passthrough
        assert dcsys.has_passthrough
        expected = shift(sys.filt(step, dt))
        actual = dcsys.filt(step, dt)
        assert rmse(expected, actual) < 1e-4
Exemple #6
0
def test_non_siso_manipulation():
    sys = Alpha(0.1)
    A, B, C, D = sys.ss

    SIMO = LinearSystem((A, B, np.eye(len(A)), [[0], [0]]))
    assert not SIMO.is_SISO
    assert SIMO.size_in == 1
    assert SIMO.size_out == 2
    assert SIMO.shape == (2, 1)
    assert not SIMO.has_passthrough
    assert ss_equal(_eval(SIMO), SIMO)
    assert isinstance(str(SIMO), str)
    assert ss_equal(canonical(SIMO), SIMO)
    for sub1, sub2 in zip(sys, SIMO):
        assert ss_equal(sub1, sub2)

    MISO = LinearSystem((A, [[1, 1]], C, [[0, 1]]))
    assert not MISO.is_SISO
    assert MISO.size_in == 2
    assert MISO.size_out == 1
    assert MISO.shape == (1, 2)
    assert MISO.has_passthrough
    assert ss_equal(_eval(MISO), MISO)
    assert isinstance(str(MISO), str)

    MIMO = LinearSystem((A, [[1, 1]], np.eye(len(A)), np.zeros((2, 2))))
    assert not MIMO.is_SISO
    assert MIMO.size_in == MIMO.size_out == 2
    assert MIMO.shape == (2, 2)
    assert not MIMO.has_passthrough
    assert ss_equal(_eval(MIMO), MIMO)
    assert isinstance(str(MIMO), str)
    for sub1, sub2 in zip(MISO, MIMO):
        assert ss_equal(sub1, sub2)
Exemple #7
0
def test_balreal():
    isys = Lowpass(0.05)
    noise = 0.5 * Lowpass(0.01) + 0.5 * Alpha(0.005)
    p = 0.8
    sys = p * isys + (1 - p) * noise

    T, Tinv, S = balanced_transformation(sys)
    assert np.allclose(inv(T), Tinv)
    assert np.allclose(S, hsvd(sys))

    balsys = sys.transform(T, Tinv)
    assert balsys == sys

    assert np.all(S >= 0)
    assert np.all(S[0] > 0.3)
    assert np.all(S[1:] < 0.05)
    assert np.allclose(sorted(S, reverse=True), S)

    P = control_gram(balsys)
    Q = observe_gram(balsys)

    diag = np.diag_indices(len(P))
    offdiag = np.ones_like(P, dtype=bool)
    offdiag[diag] = False
    offdiag = np.where(offdiag)

    assert np.allclose(P[diag], S)
    assert np.allclose(P[offdiag], 0)
    assert np.allclose(Q[diag], S)
    assert np.allclose(Q[offdiag], 0)
Exemple #8
0
def test_balred(rng):
    dt = 0.001
    sys = Alpha(0.01) + Lowpass(0.001)

    u = rng.normal(size=2000)
    expected = sys.filt(u, dt)

    def check(order, within, tol, method='del'):
        redsys = balred(sys, order, method=method)
        assert redsys.order_den <= order
        actual = redsys.filt(u, dt)
        assert abs(rmse(expected, actual) - within) < tol

    with warns(UserWarning):
        check(4, 0, 1e-13)
    with warns(UserWarning):
        check(3, 0, 1e-13)
    check(2, 0.03, 0.01)
    check(1, 0.3, 0.1)
Exemple #9
0
def test_grams():
    sys = 0.6 * Alpha(0.01) + 0.4 * Lowpass(0.05)

    A, B, C, D = sys2ss(sys)

    P = control_gram(sys)
    assert np.allclose(np.dot(A, P) + np.dot(P, A.T), -np.dot(B, B.T))
    assert matrix_rank(P) == len(P)  # controllable

    Q = observe_gram(sys)
    assert np.allclose(np.dot(A.T, Q) + np.dot(Q, A), -np.dot(C.T, C))
    assert matrix_rank(Q) == len(Q)  # observable
Exemple #10
0
def test_func_realize(radii):
    sys = Alpha(0.1)

    T = np.asarray([[1., 2.], [0, -1.]])

    for Tinv in (None, inv(T)):
        realize_result = _realize(sys, radii, T, Tinv)

        assert realize_result.sys is sys
        assert np.allclose(inv(realize_result.T), realize_result.Tinv)

        rsys = realize_result.realization
        assert ss_equal(rsys, sys.transform(realize_result.T))

        # Check that the state vector are related by T
        length = 1000
        dt = 0.001
        x_old = np.asarray([sub.impulse(length, dt) for sub in sys])
        x_new = np.asarray([sub.impulse(length, dt) for sub in rsys])

        r = np.atleast_2d(np.asarray(radii).T).T
        assert np.allclose(np.dot(T, x_new * r), x_old)
Exemple #11
0
def test_l1_norm_known():
    # Check that Lowpass has a norm of exactly 1
    l1, rtol = l1_norm(Lowpass(0.1))
    assert np.allclose(l1, 1)
    assert np.allclose(rtol, 0)

    # Check that passthrough is handled properly
    assert np.allclose(l1_norm(Lowpass(0.1) + 5)[0], 6)
    assert np.allclose(l1_norm(Lowpass(0.1) - 5)[0], 6)

    # Check that Alpha scaled by a has a norm of approximately abs(a)
    for a in (-2, 3):
        for desired_rtol in (1e-1, 1e-2, 1e-4, 1e-8):
            l1, rtol = l1_norm(a * Alpha(0.1), rtol=desired_rtol)
            assert np.allclose(l1, abs(a), rtol=rtol)
            assert rtol <= desired_rtol
Exemple #12
0
def test_state_norm(plt):
    # Choose a filter, timestep, and number of simulation timesteps
    sys = Alpha(0.1)
    dt = 0.000001
    length = 2000000
    assert np.allclose(dt * length, 2.0)

    # 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.
    response = sys.X.impulse(length, dt)
    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))

    step = int(0.002 / dt)
    plt.figure()
    plt.plot(response[::step, 0], label="$x_0$")
    plt.plot(response[::step, 1], label="$x_1$")
    plt.plot(np.dot(response[::step], sys.C.T), label="$y$")
    plt.legend()
Exemple #13
0
def test_sys_conversions():
    sys = Alpha(0.1)

    tf = sys2tf(sys)
    ss = sys2ss(sys)
    zpk = sys2zpk(sys)

    assert sys_equal(sys2ss(tf), ss)
    assert sys_equal(sys2ss(ss), ss)  # unchanged
    assert sys_equal(sys2tf(tf), tf)  # unchanged
    assert sys_equal(sys2tf(ss), tf)

    assert sys_equal(sys2zpk(zpk), zpk)  # sanity check
    assert sys_equal(sys2zpk(tf), zpk)  # sanity check
    assert sys_equal(sys2zpk(ss), zpk)
    assert sys_equal(sys2tf(zpk), tf)
    assert sys_equal(sys2ss(zpk), ss)

    # should also work with nengo's synapse types
    assert sys_equal(sys2zpk(nengo.Alpha(0.1)), zpk)
    assert sys_equal(sys2tf(nengo.Alpha(0.1)), tf)
    assert sys_equal(sys2ss(nengo.Alpha(0.1)), ss)

    # system can also be just a scalar
    assert sys_equal(sys2tf(2.0), (1, 0.5))
    assert np.allclose(sys2ss(5)[3], 5)
    assert sys_equal(sys2zpk(5), 5)

    with pytest.raises(ValueError):
        sys2ss(np.zeros(5))

    with pytest.raises(ValueError):
        sys2zpk(np.zeros(5))

    with pytest.raises(ValueError):
        sys2tf(np.zeros(5))

    with pytest.raises(ValueError):
        # _ss2tf(...): passthrough must be single element
        sys2tf(([], [], [], [1, 2]))
Exemple #14
0
        sub2 = LinearSystem((sys.A, B, I[i:i+1], np.zeros((1, 3))))
        _transclose(sub1.filt(u), sub2.filt(u), y[:, i])


def test_bad_filt():
    sys = PadeDelay(0.1, order=4).X
    with pytest.raises(ValueError):
        sys.filt(np.ones((4, 4)))
    with pytest.raises(ValueError):
        sys.filt(np.ones((4, 1)), filtfilt=True)
    with pytest.raises(ValueError):
        sys.filt(np.ones((4,)), copy=False)


@pytest.mark.parametrize("sys", [
    Lowpass(0.01), Alpha(0.2), LinearSystem(([1, 1], [0.01, 1]))])
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)
Exemple #15
0
def test_given_dt():
    process = WhiteSignal(1.0, high=10)
    assert EvalPoints(Alpha(0.1), process, dt=0.1).dt == 0.1
Exemple #16
0
def test_invalid_process():
    with pytest.raises(ValidationError):
        assert EvalPoints(Alpha(0.1), process=1)
Exemple #17
0
def test_alpha_whitesignal(Simulator, seed, rng, plt):
    # Pick test LinearSystem
    sys = Alpha(0.1)
    state = sys.X
    assert state.shape == (2, 1)

    # Pick test process
    n_steps = 1000
    dt = 0.01
    process = WhiteSignal(5.0, high=10, default_dt=dt, seed=seed)

    # Sample evaluation points
    dist = EvalPoints(state, process, n_steps=n_steps)
    assert dist.n_steps == n_steps
    assert dist.dt == dt  # taken from process
    assert isinstance(repr(dist), str)

    n_eval_points = 500
    eval_points = dist.sample(n_eval_points, 2, rng=rng)
    assert eval_points.shape == (n_eval_points, 2)

    # Sample encoders
    encoders = Encoders(state, process).sample(n_eval_points, 2, rng=rng)
    assert encoders.shape == (n_eval_points, 2)

    plt.figure()
    # plt.scatter(*encoders.T, label="Encoders")
    plt.scatter(*eval_points.T, s=2, marker='*', label="Eval Points")

    # Check that most evaluation points fall within radii
    x_m, zero, x_p = sorted(np.unique(encoders[:, 0]))
    assert np.allclose(-x_m, x_p)
    assert np.allclose(zero, 0)
    sl = (1 / x_m < eval_points[:, 0]) & (eval_points[:, 0] < 1 / x_p)
    assert np.count_nonzero(sl) / float(n_eval_points) >= 0.99

    y_m, zero, y_p = sorted(np.unique(encoders[:, 1]))
    assert np.allclose(zero, 0)
    assert np.allclose(-y_m, y_p)
    sl = (1 / y_m < eval_points[:, 1]) & (eval_points[:, 1] < 1 / y_p)
    assert np.count_nonzero(sl) / float(n_eval_points) >= 0.99

    # Simulate same process / system in nengo network
    with Network() as model:
        output = nengo.Node(output=process)
        probes = [nengo.Probe(output, synapse=sub) for sub in sys]

    with Simulator(model, dt=dt) as sim:
        sim.run(n_steps * dt)

    plt.scatter(sim.data[probes[0]],
                sim.data[probes[1]],
                s=1,
                alpha=0.5,
                label="Simulated")
    plt.legend()

    # Check that each eval_point is a subset / sample from the ideal
    ideal = np.asarray(
        [sim.data[probes[0]].squeeze(), sim.data[probes[1]].squeeze()]).T
    assert ideal.shape == (n_steps, 2)

    for pt in eval_points:
        dists = np.linalg.norm(ideal - pt[None, :], axis=1)
        assert dists.shape == (n_steps, )
        assert np.allclose(np.min(dists), 0)
Exemple #18
0
    diag = np.diag_indices(len(P))
    offdiag = np.ones_like(P, dtype=bool)
    offdiag[diag] = False
    offdiag = np.where(offdiag)

    assert np.allclose(P[diag], S)
    assert np.allclose(P[offdiag], 0)
    assert np.allclose(Q[diag], S)
    assert np.allclose(Q[offdiag], 0)


@pytest.mark.parametrize(
    "sys",
    [PadeDelay(0.1, 4), PadeDelay(0.2, 5, 5),
     Alpha(0.2)])
def test_hankel(sys):
    assert np.allclose(hsvd(sys), balanced_transformation(sys)[2])


def test_l1_norm_known():
    # Check that Lowpass has a norm of exactly 1
    l1, rtol = l1_norm(Lowpass(0.1))
    assert np.allclose(l1, 1)
    assert np.allclose(rtol, 0)

    # Check that passthrough is handled properly
    assert np.allclose(l1_norm(Lowpass(0.1) + 5)[0], 6)
    assert np.allclose(l1_norm(Lowpass(0.1) - 5)[0], 6)

    # Check that Alpha scaled by a has a norm of approximately abs(a)
Exemple #19
0
def test_sys_multiplication():
    # Check that alpha is just two lowpass multiplied together
    assert Lowpass(0.1) * Lowpass(0.1) == Alpha(0.1)
Exemple #20
0
        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 + eps).all()
    assert (worst_x <= 1 + eps).all()


def test_l1_repr():
    assert (repr(L1Norm(rtol=.1,
                        max_length=10)) == "L1Norm(rtol=0.1, max_length=10)")


@pytest.mark.parametrize("sys,lower", [(Lowpass(0.005), 1.0),
                                       (Alpha(0.01), 0.3),
                                       (Bandpass(50, 5), 0.05),
                                       (Highpass(0.01, 4), 0.1),
                                       (PadeDelay(0.1, 2, 2), 0.3)])
def test_hankel_normalization(Simulator, rng, sys, lower):
    _test_normalization(Simulator,
                        sys,
                        rng,
                        Hankel(),
                        l1_lower=0.5,
                        lower=lower)


@pytest.mark.parametrize("radius", [0.5, 5, 10])
@pytest.mark.parametrize("sys", [Lowpass(0.005)])
def test_normalization_radius(Simulator, rng, sys, radius):