<html>
  <head>
    <meta content="text/html; charset=utf-8" http-equiv="Content-Type">
  </head>
  <body bgcolor="#FFFFFF" text="#000000">
    <br>
    Hi Terry,<br>
    <br>
    thank you very much for all your explanations, and please apologize
    that it took so long to respond. Your answer already helps a lot to
    understand Nengo a bit better, but please, let me ask some more
    questions, because I still don't know much about Nengo.<br>
    <br>
    First I would like to ask two questions concerning your example: Why
    did you choose a 2 dimensional ensemble instead of a 1 dimensional
    one for just one angle?<br>
    And secondly, you write in your example after the node "angle_to_pt"
    was connected to the ensemble "optic_tectum": "You now have neurons
    with tuning curves in different directions." If I look at the tuning
    curves, they look like a 2 dimensional version of the curves in the
    Nengo 1.4 documentation, chapter 1.1.4 and not like the ones in
    figure 6 in the Fischer and Pena paper. Therefore, why do I have
    tuning curves in different directions now?<br>
    <br>
    Please, let my say a few more words about the problem I want to
    simulate. The work of Fischer and Pena from 2011 will only be one
    part of the simulation.  I want to simulate the auditory system
    starting with two input nodes for the left and right ear with a
    sinus function including a phase difference as well as different
    amplitudes of the two input signals. The input nodes for the two
    ears could look like<br>
       # input of right and left ear<br>
        input_left = nengo.Node(lambda t: np.sin(frequency*2*math.pi*t))<br>
        input_right = nengo.Node(lambda t:
    0.8*np.sin(frequency*2*math.pi*t-phase_factor))<br>
    <br>
    The simulation should process these input signals and should end in
    the optic tectum as described for example by Masakazu Konishi in
    Scientific American in 1993. To do this, I want to use a simple
    model. First, I have to compute the interaural time difference of
    this input signals. For this purpose I want to use the delay class
    of the Nengo examples. I want to  connect the input nodes to an
    array of delay nodes with different delays and then the delay nodes
    to an array of ensembles. If the shift due to the delay and the
    phase factor add up to half the wavelength, the ensemble will only
    have a small activity, if they add up to a multiple of the
    wavelength, the ensemble will have a large activity. In this way I
    can get the phase or the interaural time difference.<br>
    <br>
    Here an simple example with 2 delay nodes and one ensemble<br>
        # delay nodes (currently I am using 40 delay nodes)<br>
        delay_1 = Delay(1, timesteps=1)   <br>
        delay_2 = Delay(1, timesteps=3) <br>
        delaynode_l1 = nengo.Node(output=delay_1.step) <br>
        delaynode_r1 = nengo.Node(output=delay_2.step) <br>
    <br>
       # connect input to delay nodes<br>
        nengo.Connection(input_left, delaynode_l1)<br>
        nengo.Connection(input_right, delaynode_r1) <br>
    <br>
       # connect the output of the delay nodes to an ensembles
    (currently I also have 40 ensembles)<br>
        ln = nengo.Ensemble(500, dimensions=1,radius=3)<br>
        nengo.Connection(delaynode_l1, ln)<br>
        nengo.Connection(delaynode_r1, ln)<br>
    <br>
    In the end I will have the activities of 40 ensembles. The ensemble
    with the largest activity will give an approximation for the phase
    and therefor also for the horizontal angle the sound comes from, but
    it would be better  to compute the average over all ensembles of the
    normalized activity times the angles each ensemble represents. <br>
    Therefore I think I can't use the ensemble of your example and I
    have to compute the average as in your weighted average approach
    example. <br>
    I hope you know what I mean, because my English is not  good and
    therefore it is difficult for me to explain, what I want to do. <br>
    I don't know if the way I try to compute the interaural time
    difference and the angle is a good way to do it. Do you have any
    idea how improve this or how to avoid the division in this case?<br>
    <br>
    <tt><span style="font-size:10pt"></span></tt>One more problem is
    that I also want is to compute the interaural level difference for
    the vertical angle of the direction the sound comes from. To get
    this difference I have to divide the amplitude values. Here I also
    have the problem of a division. Could it be that the problem with a
    division is the fact that in principle the denominator could be zero
    and that then a linear decoding is not working very well?<br>
    <br>
    In Nengo one can restrict the values of an ensemble with the radius
    parameter. Is it possible to restrict the values to a positive
    interval to avoid the zero and would this give better results?<br>
    <br>
    Thank you very much for your help and your patience with me.<br>
    <br>
    Best regards,<br>
    <br>
    Peer<br>
    <br>
    Am 11.02.2016 um 23:47 schrieb Terry Stewart:<br>
    <blockquote
cite="mid:CAL0ZbQFAHTqTbnPV8kdtosagN3F2oydcr-e0pMFVs1nn24Z3DQ@mail.gmail.com"
      type="cite">
      <div dir="ltr">Hello Peer,
        <div><br>
        </div>
        <div>Thank you for the context!  That helps a lot.  And, it
          turns out that with a couple slightly counter-intuitive
          tweaks, this sort of model is quite nicely suited for Nengo.</div>
        <div><br>
        </div>
        <div>The main thing we first need is to make tuning curves that
          look like Figure 6a of (Fischer and Pena, 2011).  These
          neurons have preferred directions that range between -100 and
          +100 degrees.  Preferred directions are called "encoders" in
          Nengo/NEF.  However, because Nengo allows you to generalize
          the idea of preferred directions up to hundreds of dimensions,
          we need to be explicit about exactly how we want to represent
          an angle.</div>
        <div><br>
        </div>
        <div>The easiest way is to think of the group of neurons (the
          optic tectum) as representing a two-dimensional space, and
          each neuron has some preferred direction in that space.  By
          default, Nengo will randomly distribute the neuron's encoders
          around that 2-dimensional space, although we can control that
          if we want to (e.g. we may want to distribute neurons more
          densely in the middle of the space, for example).  </div>
        <div><br>
        </div>
        <div>So, the code for making the optic_tectum is:</div>
        <div><br>
        </div>
        <div>    optic_tectum = nengo.Ensemble(n_neurons=500,
          dimensions=2)<br>
        </div>
        <div><br>
        </div>
        <div>Now, however, we want to provide input to that set of
          neurons.  We want that input to be an angle, and we want that
          angle to stimulate the neurons in a consistent way (i.e. when
          the input is an angle of 0, the neurons with preferred
          direction vectors near 0 should be stimulated).  We can do
          this with one Node for the input angle, and one Node to do the
          conversion into the represented space:</div>
        <div><br>
        </div>
        <div>    stim_angle = nengo.Node([0])<br>
        </div>
        <div>
          <div>    </div>
          <div>    import numpy as np</div>
          <div>    def convert_angle(t, x):</div>
          <div>        return np.sin(x[0]), np.cos(x[0])</div>
          <div>    angle_to_pt = nengo.Node(convert_angle, size_in=1)</div>
          <div>    nengo.Connection(stim_angle, angle_to_pt,
            synapse=None)</div>
        </div>
        <div><br>
        </div>
        <div>Now we connect that input into the optic_tectum</div>
        <div><br>
        </div>
        <div>    nengo.Connection(angle_to_pt, optic_tectum)<br>
        </div>
        <div><br>
        </div>
        <div>You now have neurons with tuning curves in different
          directions.  If you plot the spikes from the optic_tectum as
          you change the input stim_angle, you should see this
          behaviour.  Also, it's important to note that these neurons in
          Nengo have much more variety in their tuning curves (heights
          and widths) than the perfectly regular tuning curves done in
          Figure 6a.  We tend to keep a large degree of variability in
          our neurons.  You can control the width with the intercepts
          parameter, if you're interested in doing that.</div>
        <div><br>
        </div>
        <div>So all of that above was just to get the stimulus and
          neuron parameters set up right to give the sorts of tuning
          curves we want in the optic tectum.  Now we come to the part
          where we want to decode out from these tuning curves what the
          currently represented angle is.  In (Fischer and Pena, 2011),
          they do this: "The population vector is obtained by averaging
          the preferred direction vectors of neurons in the population,
          weighted by the firing rates of the neurons".  This is one way
          of decoding neural activity, but it's not the only way.</div>
        <div><br>
        </div>
        <div>In Nengo, when you ask it to compute a function, it finds
          the optimal way of weighting the outputs of neural activity to
          approximate that function.  Furthermore, it does this with a
          fixed set of linear weights -- i.e. it does not require that
          division step in the weighted average.  So let's try it the
          standard Nengo way, and then compare that to the weighted
          average approach.</div>
        <div><br>
        </div>
        <div>To do it the standard Nengo way, we define a function that
          goes from the represented 2-D space and decodes out the angle:</div>
        <div><br>
        </div>
        <div>
          <div>    decoded_angle = nengo.Node(None, size_in=1)   # a
            place to store the result</div>
          <div>    </div>
          <div>    # a function to map from 2-d space to an angle</div>
          <div>    def decode_angle(x):</div>
          <div>        return np.arctan2(x[0], x[1])</div>
          <div>    </div>
          <div>    # make the connection</div>
          <div>    nengo.Connection(optic_tectum, decoded_angle,
            function=decode_angle)<br>
          </div>
        </div>
        <div><br>
        </div>
        <div>This tells Nengo to find the optimal set of connection
          weights from the neurons to decode out the angle.  That is, it
          finds the vector d such that sum(a_i * d_i) best approximates
          the input angle.</div>
        <div><br>
        </div>
        <div>If you try running this, it works okay, but we we can make
          it do better.  In particular, right now Nengo is trying to
          approximate the function across the whole 2-D space, but we
          only need it to be good at a particular range of points.  If
          we tell Nengo to just focus on those points, it gets much
          better:</div>
        <div><br>
        </div>
        <div>
          <div>    decoded_angle = nengo.Node(None, size_in=1)</div>
          <div>    </div>
          <div>    def decode_angle(x):</div>
          <div>        return np.arctan2(x[0], x[1])</div>
          <div><br>
          </div>
          <div>    # define the set of points </div>
          <div>
            <div>    def make_pt():</div>
            <div>        theta = np.random.uniform(-2, 2)</div>
            <div>        return [np.sin(theta), np.cos(theta)]</div>
          </div>
          <div>    pts = [make_pt() for i in range(1000)]<br>
          </div>
          <div>        </div>
          <div>    nengo.Connection(optic_tectum, decoded_angle,
            function=decode_angle, eval_points=pts)</div>
        </div>
        <div><br>
        </div>
        <div>If you run this and plot the decoded_angle you'll see it
          very closely follows the stim_angle.</div>
        <div><br>
        </div>
        <div>However, it'd be good to also do the weighted average
          approach, so we can compare the two.  Doing that requires us
          to to know the angles for all the neurons, and do a weighted
          average of those angles (weighted by activity).  To do that,
          we explicitly define the angles for the neurons, and then do
          the math in a Node:</div>
        <div><br>
        </div>
        <div>    N = 500</div>
        <div><br>
        </div>
        <div>
          <div>    def make_pt():</div>
          <div>        theta = np.random.uniform(-2, 2)</div>
          <div>        return [np.sin(theta), np.cos(theta)]</div>
          <div>    </div>
          <div>    # generate random preferred direction vectors</div>
          <div>    encoders = np.array([make_pt() for i in range(N)])</div>
          <div>    </div>
        </div>
        <div>
          <div>    optic_tectum = nengo.Ensemble(n_neurons=N,
            dimensions=2, encoders=encoders)</div>
        </div>
        <div><br>
        </div>
        <div>    # compute the angle for each preferred direction vector</div>
        <div>
          <div>    angles = np.arctan2(encoders[:,0], encoders[:,1])</div>
          <div><br>
          </div>
          <div>    # compute the weighted average</div>
          <div>    def weighted_average(t, a):</div>
          <div>        total = np.sum(a)</div>
          <div>        if total == 0:</div>
          <div>            return 0</div>
          <div>        return np.sum(a*angles) / total</div>
          <div>    </div>
          <div>    computed = nengo.Node(weighted_average, size_in=N)</div>
          <div>    nengo.Connection(optic_tectum.neurons, computed,
            synapse=None)</div>
        </div>
        <div><br>
        </div>
        <div>Now we can plot "computed" (the approach used in  (Fischer
          and Pena, 2011)) and compare it to "decoded_angle" (the
          default approach used in Nengo).  In this case, the Nengo
          approach is more accurate, and it doesn't require any
          division! </div>
        <div><br>
        </div>
        <div>Here's a script that should let you directly compare the
          two approaches:</div>
        <div><br>
        </div>
        <div>-------------------</div>
        <div>
          <div>import nengo</div>
          <div>import numpy as np</div>
          <div><br>
          </div>
          <div>N = 500    # the number of neurons</div>
          <div><br>
          </div>
          <div>model = nengo.Network()</div>
          <div>with model:</div>
          <div>    stim_angle = nengo.Node([0])   # the input angle</div>
          <div>    </div>
          <div>    # convert the angle into a 2-D space</div>
          <div>    def convert_angle(t, x):</div>
          <div>        return np.sin(x[0]), np.cos(x[0])</div>
          <div>    angle_to_pt = nengo.Node(convert_angle, size_in=1)</div>
          <div>    nengo.Connection(stim_angle, angle_to_pt,
            synapse=None)</div>
          <div>    </div>
          <div>    # make a point in 2-D space that is at random angle</div>
          <div>    def make_pt():</div>
          <div>        theta = np.random.uniform(-2, 2)</div>
          <div>        return [np.sin(theta), np.cos(theta)]</div>
          <div>    </div>
          <div>    # the preferred direction vectors for the neurons</div>
          <div>    encoders = np.array([make_pt() for i in range(N)])</div>
          <div>    </div>
          <div>    # create the group of neurons</div>
          <div>    optic_tectum = nengo.Ensemble(n_neurons=N,
            dimensions=2, encoders=encoders)</div>
          <div>    </div>
          <div>    nengo.Connection(angle_to_pt, optic_tectum)</div>
          <div>    </div>
          <div>    </div>
          <div>    ### Standard Nengo/NEF Approach</div>
          <div>    </div>
          <div>    # decode out the angle in the optimal Nengo/NEF
            approach</div>
          <div>    decoded_angle = nengo.Node(None, size_in=1)</div>
          <div>    </div>
          <div>    # function that the neural connections should
            approximate</div>
          <div>    def decode_angle(x):</div>
          <div>        return np.arctan2(x[0], x[1])</div>
          <div>        </div>
          <div>    # define the set of values over which the approximate
            should be good</div>
          <div>    pts = [make_pt() for i in range(1000)]</div>
          <div>        </div>
          <div>    nengo.Connection(optic_tectum, decoded_angle,
            function=decode_angle, eval_points=pts)</div>
          <div>    </div>
          <div><br>
          </div>
          <div>    ### Weighted average approach</div>
          <div><br>
          </div>
          <div>    # determine the angles for each neuron</div>
          <div>    angles = np.arctan2(encoders[:,0], encoders[:,1])</div>
          <div>    # compute the weighted sum</div>
          <div>    def weighted_average(t, a):</div>
          <div>        total = np.sum(a)</div>
          <div>        if total == 0:</div>
          <div>            return 0</div>
          <div>        return np.sum(a*angles) / total</div>
          <div>    computed = nengo.Node(weighted_average, size_in=N)</div>
          <div>    </div>
          <div>    nengo.Connection(optic_tectum.neurons, computed,
            synapse=None)</div>
          <div>        </div>
          <div> ---------</div>
        </div>
        <div><br>
        </div>
        <div>So, the main differences between the Nengo/NEF approach
          rather than the weighted average approach are:</div>
        <div> - The Nengo/NEF approach gives a more accurate result</div>
        <div> - The Nengo/NEF approach handles variability in the tuning
          curves</div>
        <div> - The Nengo/NEF approach does not require division (which
          is complicated to biologically justify)</div>
        <div><br>
        </div>
        <div>In any case, while it's certainly possible to do the
          weighted average approach (using that "computed" Node defined
          above) in Nengo, we tend not to.  But it'd be interesting to
          do a more rigorous direct comparison in this case.</div>
        <div><br>
        </div>
        <div>Notice also that, right now, the neurons are being
          optimized to just figure out what the input angle is.  If you
          also want it to take into account some sort of bayesian prior,
          then all you have to do is put that into the decode_angle
          function.  This lets you implement a wide variety of possible
          priors.</div>
        <div><br>
        </div>
        <div>Does that help?  What I've presented here is definitely a
          very different way of thinking about things than is taken in
          (Fischer and Pena, 2011).  But hopefully I've shown a) how to
          implement their approach in Nengo, and b) that there are other
          ways of decoding information that are a little bit more
          flexible.  </div>
        <div><br>
        </div>
        <div>Let me know if that helps, and thank you again for the
          question!</div>
        <div><br>
        </div>
        <div>Terry</div>
        <div><br>
        </div>
      </div>
    </blockquote>
  </body>
</html>