| | 390 | |
|---|
| | 391 | |
|---|
| | 392 | |
|---|
| | 393 | def _inh_adaptingmarkov_generator_python(self, a, bq, tau, t, t_stop, array=False): |
|---|
| | 394 | |
|---|
| | 395 | """ |
|---|
| | 396 | Returns a SpikeList whose spikes are an inhomogeneous |
|---|
| | 397 | realization (dynamic rate) of the so-called adapting markov |
|---|
| | 398 | process (see references). The implementation uses the thinning |
|---|
| | 399 | method, as presented in the references. |
|---|
| | 400 | |
|---|
| | 401 | This is the 1d implementation, with no relative refractoriness. |
|---|
| | 402 | For the 2d implementation with relative refractoriness, |
|---|
| | 403 | see the inh_2dadaptingmarkov_generator. |
|---|
| | 404 | |
|---|
| | 405 | Inputs: |
|---|
| | 406 | a,bq - arrays of the parameters of the hazard function where a[i] and bq[i] |
|---|
| | 407 | will be active on interval [t[i],t[i+1]] |
|---|
| | 408 | tau - the time constant of adaptation (in milliseconds). |
|---|
| | 409 | t - an array specifying the time bins (in milliseconds) at which to |
|---|
| | 410 | specify the rate |
|---|
| | 411 | t_stop - length of time to simulate process (in ms) |
|---|
| | 412 | array - if True, a numpy array of sorted spikes is returned, |
|---|
| | 413 | rather than a SpikeList object. |
|---|
| | 414 | |
|---|
| | 415 | Note: |
|---|
| | 416 | - t_start=t[0] |
|---|
| | 417 | |
|---|
| | 418 | - a is in units of Hz. Typical values are available |
|---|
| | 419 | in Fig. 1 of Muller et al 2007, a~5-80Hz (low to high stimulus) |
|---|
| | 420 | |
|---|
| | 421 | - bq here is taken to be the quantity b*q_s in Muller et al 2007, is thus |
|---|
| | 422 | dimensionless, and has typical values bq~3.0-1.0 (low to high stimulus) |
|---|
| | 423 | |
|---|
| | 424 | - tau_s has typical values on the order of 100 ms |
|---|
| | 425 | |
|---|
| | 426 | |
|---|
| | 427 | References: |
|---|
| | 428 | |
|---|
| | 429 | Eilif Muller, Lars Buesing, Johannes Schemmel, and Karlheinz Meier |
|---|
| | 430 | Spike-Frequency Adapting Neural Ensembles: Beyond Mean Adaptation and Renewal Theories |
|---|
| | 431 | Neural Comput. 2007 19: 2958-3010. |
|---|
| | 432 | |
|---|
| | 433 | Devroye, L. (1986). Non-uniform random variate generation. New York: Springer-Verlag. |
|---|
| | 434 | |
|---|
| | 435 | Examples: |
|---|
| | 436 | |
|---|
| | 437 | See also: |
|---|
| | 438 | inh_poisson_generator, inh_gamma_generator, inh_2dadaptingmarkov_generator |
|---|
| | 439 | |
|---|
| | 440 | """ |
|---|
| | 441 | |
|---|
| | 442 | from numpy import shape |
|---|
| | 443 | |
|---|
| | 444 | if shape(t)!=shape(a) or shape(a)!=shape(bq): |
|---|
| | 445 | raise ValueError('shape mismatch: t,a,b must be of the same shape') |
|---|
| | 446 | |
|---|
| | 447 | # get max rate and generate poisson process to be thinned |
|---|
| | 448 | rmax = numpy.max(a) |
|---|
| | 449 | ps = self.poisson_generator(rmax, t_start=t[0], t_stop=t_stop, array=True) |
|---|
| | 450 | |
|---|
| | 451 | isi = numpy.zeros_like(ps) |
|---|
| | 452 | isi[1:] = ps[1:]-ps[:-1] |
|---|
| | 453 | isi[0] = ps[0] #-0.0 # assume spike at 0.0 |
|---|
| | 454 | |
|---|
| | 455 | # return empty if no spikes |
|---|
| | 456 | if len(ps) == 0: |
|---|
| | 457 | return SpikeTrain(numpy.array([]), t_start=t[0],t_stop=t_stop) |
|---|
| | 458 | |
|---|
| | 459 | |
|---|
| | 460 | # gen uniform rand on 0,1 for each spike |
|---|
| | 461 | rn = numpy.array(self.rng.uniform(0, 1, len(ps))) |
|---|
| | 462 | |
|---|
| | 463 | # instantaneous a,bq for each spike |
|---|
| | 464 | |
|---|
| | 465 | idx=numpy.searchsorted(t,ps)-1 |
|---|
| | 466 | spike_a = a[idx] |
|---|
| | 467 | spike_bq = bq[idx] |
|---|
| | 468 | |
|---|
| | 469 | keep = numpy.zeros(shape(ps),bool) |
|---|
| | 470 | |
|---|
| | 471 | # thin spikes |
|---|
| | 472 | |
|---|
| | 473 | i = 0 |
|---|
| | 474 | t_last = 0.0 |
|---|
| | 475 | t_i = 0 |
|---|
| | 476 | # initial adaptation state is unadapted, i.e. large t_s |
|---|
| | 477 | t_s = 1000*tau |
|---|
| | 478 | |
|---|
| | 479 | while(i<len(ps)): |
|---|
| | 480 | # find index in "t" time, without searching whole array each time |
|---|
| | 481 | t_i = numpy.searchsorted(t[t_i:],ps[i],'right')-1+t_i |
|---|
| | 482 | |
|---|
| | 483 | # evolve adaptation state |
|---|
| | 484 | t_s+=isi[i] |
|---|
| | 485 | |
|---|
| | 486 | if rn[i]<a[t_i]*numpy.exp(-bq[t_i]*numpy.exp(-t_s/tau))/rmax: |
|---|
| | 487 | # keep spike |
|---|
| | 488 | keep[i] = True |
|---|
| | 489 | # remap t_s state |
|---|
| | 490 | t_s = -tau*numpy.log(numpy.exp(-t_s/tau)+1) |
|---|
| | 491 | i+=1 |
|---|
| | 492 | |
|---|
| | 493 | |
|---|
| | 494 | spike_train = ps[keep] |
|---|
| | 495 | |
|---|
| | 496 | if array: |
|---|
| | 497 | return spike_train |
|---|
| | 498 | |
|---|
| | 499 | return SpikeTrain(spike_train, t_start=t[0],t_stop=t_stop) |
|---|
| | 500 | |
|---|
| | 501 | |
|---|
| | 502 | # use slow python implementation for the time being |
|---|
| | 503 | # TODO: provide optimized C/weave implementation if possible |
|---|
| | 504 | |
|---|
| | 505 | |
|---|
| | 506 | inh_adaptingmarkov_generator = _inh_adaptingmarkov_generator_python |
|---|
| | 507 | |
|---|
| | 508 | |
|---|
| | 509 | def _inh_2Dadaptingmarkov_generator_python(self, a, bq, tau_s, tau_r, qrqs, t, t_stop, array=False): |
|---|
| | 510 | |
|---|
| | 511 | """ |
|---|
| | 512 | Returns a SpikeList whose spikes are an inhomogeneous |
|---|
| | 513 | realization (dynamic rate) of the so-called 2D adapting markov |
|---|
| | 514 | process (see references). 2D implies the process has two |
|---|
| | 515 | states, an adaptation state, and a refractory state, both of |
|---|
| | 516 | which affect its probability to spike. The implementation |
|---|
| | 517 | uses the thinning method, as presented in the references. |
|---|
| | 518 | |
|---|
| | 519 | For the 1d implementation, with no relative refractoriness, |
|---|
| | 520 | see the inh_adaptingmarkov_generator. |
|---|
| | 521 | |
|---|
| | 522 | Inputs: |
|---|
| | 523 | a,bq - arrays of the parameters of the hazard function where a[i] and bq[i] |
|---|
| | 524 | will be active on interval [t[i],t[i+1]] |
|---|
| | 525 | tau_s - the time constant of adaptation (in milliseconds). |
|---|
| | 526 | tau_r - the time constant of refractoriness (in milliseconds). |
|---|
| | 527 | qrqs - the ratio of refractoriness conductance to adaptation conductance. |
|---|
| | 528 | typically on the order of 200. |
|---|
| | 529 | t - an array specifying the time bins (in milliseconds) at which to |
|---|
| | 530 | specify the rate |
|---|
| | 531 | t_stop - length of time to simulate process (in ms) |
|---|
| | 532 | array - if True, a numpy array of sorted spikes is returned, |
|---|
| | 533 | rather than a SpikeList object. |
|---|
| | 534 | |
|---|
| | 535 | Note: |
|---|
| | 536 | - t_start=t[0] |
|---|
| | 537 | |
|---|
| | 538 | - a is in units of Hz. Typical values are available |
|---|
| | 539 | in Fig. 1 of Muller et al 2007, a~5-80Hz (low to high stimulus) |
|---|
| | 540 | |
|---|
| | 541 | - bq here is taken to be the quantity b*q_s in Muller et al 2007, is thus |
|---|
| | 542 | dimensionless, and has typical values bq~3.0-1.0 (low to high stimulus) |
|---|
| | 543 | |
|---|
| | 544 | - qrqs is the quantity q_r/q_s in Muller et al 2007, |
|---|
| | 545 | where a value of qrqs = 3124.0nS/14.48nS = 221.96 was used. |
|---|
| | 546 | |
|---|
| | 547 | - tau_s has typical values on the order of 100 ms |
|---|
| | 548 | - tau_r has typical values on the order of 2 ms |
|---|
| | 549 | |
|---|
| | 550 | |
|---|
| | 551 | References: |
|---|
| | 552 | |
|---|
| | 553 | Eilif Muller, Lars Buesing, Johannes Schemmel, and Karlheinz Meier |
|---|
| | 554 | Spike-Frequency Adapting Neural Ensembles: Beyond Mean Adaptation and Renewal Theories |
|---|
| | 555 | Neural Comput. 2007 19: 2958-3010. |
|---|
| | 556 | |
|---|
| | 557 | Devroye, L. (1986). Non-uniform random variate generation. New York: Springer-Verlag. |
|---|
| | 558 | |
|---|
| | 559 | Examples: |
|---|
| | 560 | |
|---|
| | 561 | See also: |
|---|
| | 562 | inh_poisson_generator, inh_gamma_generator, inh_adaptingmarkov_generator |
|---|
| | 563 | |
|---|
| | 564 | """ |
|---|
| | 565 | |
|---|
| | 566 | from numpy import shape |
|---|
| | 567 | |
|---|
| | 568 | if shape(t)!=shape(a) or shape(a)!=shape(bq): |
|---|
| | 569 | raise ValueError('shape mismatch: t,a,b must be of the same shape') |
|---|
| | 570 | |
|---|
| | 571 | # get max rate and generate poisson process to be thinned |
|---|
| | 572 | rmax = numpy.max(a) |
|---|
| | 573 | ps = self.poisson_generator(rmax, t_start=t[0], t_stop=t_stop, array=True) |
|---|
| | 574 | |
|---|
| | 575 | isi = numpy.zeros_like(ps) |
|---|
| | 576 | isi[1:] = ps[1:]-ps[:-1] |
|---|
| | 577 | isi[0] = ps[0] #-0.0 # assume spike at 0.0 |
|---|
| | 578 | |
|---|
| | 579 | # return empty if no spikes |
|---|
| | 580 | if len(ps) == 0: |
|---|
| | 581 | return SpikeTrain(numpy.array([]), t_start=t[0],t_stop=t_stop) |
|---|
| | 582 | |
|---|
| | 583 | |
|---|
| | 584 | # gen uniform rand on 0,1 for each spike |
|---|
| | 585 | rn = numpy.array(self.rng.uniform(0, 1, len(ps))) |
|---|
| | 586 | |
|---|
| | 587 | # instantaneous a,bq for each spike |
|---|
| | 588 | |
|---|
| | 589 | idx=numpy.searchsorted(t,ps)-1 |
|---|
| | 590 | spike_a = a[idx] |
|---|
| | 591 | spike_bq = bq[idx] |
|---|
| | 592 | |
|---|
| | 593 | keep = numpy.zeros(shape(ps),bool) |
|---|
| | 594 | |
|---|
| | 595 | # thin spikes |
|---|
| | 596 | |
|---|
| | 597 | i = 0 |
|---|
| | 598 | t_last = 0.0 |
|---|
| | 599 | t_i = 0 |
|---|
| | 600 | # initial adaptation state is unadapted, i.e. large t_s |
|---|
| | 601 | t_s = 1000*tau_s |
|---|
| | 602 | t_r = 1000*tau_s |
|---|
| | 603 | |
|---|
| | 604 | while(i<len(ps)): |
|---|
| | 605 | # find index in "t" time, without searching whole array each time |
|---|
| | 606 | t_i = numpy.searchsorted(t[t_i:],ps[i],'right')-1+t_i |
|---|
| | 607 | |
|---|
| | 608 | # evolve adaptation state |
|---|
| | 609 | t_s+=isi[i] |
|---|
| | 610 | t_r+=isi[i] |
|---|
| | 611 | |
|---|
| | 612 | if rn[i]<a[t_i]*numpy.exp(-bq[t_i]*(numpy.exp(-t_s/tau_s)+qrqs*numpy.exp(-t_r/tau_r)))/rmax: |
|---|
| | 613 | # keep spike |
|---|
| | 614 | keep[i] = True |
|---|
| | 615 | # remap t_s state |
|---|
| | 616 | t_s = -tau_s*numpy.log(numpy.exp(-t_s/tau_s)+1) |
|---|
| | 617 | t_r = -tau_r*numpy.log(numpy.exp(-t_r/tau_r)+1) |
|---|
| | 618 | i+=1 |
|---|
| | 619 | |
|---|
| | 620 | |
|---|
| | 621 | spike_train = ps[keep] |
|---|
| | 622 | |
|---|
| | 623 | if array: |
|---|
| | 624 | return spike_train |
|---|
| | 625 | |
|---|
| | 626 | return SpikeTrain(spike_train, t_start=t[0],t_stop=t_stop) |
|---|
| | 627 | |
|---|
| | 628 | |
|---|
| | 629 | # use slow python implementation for the time being |
|---|
| | 630 | # TODO: provide optimized C/weave implementation if possible |
|---|
| | 631 | |
|---|
| | 632 | |
|---|
| | 633 | inh_2Dadaptingmarkov_generator = _inh_2Dadaptingmarkov_generator_python |
|---|
| | 634 | |
|---|
| | 635 | |
|---|
| | 636 | |
|---|
| | 637 | |
|---|
| | 638 | |
|---|