Recruiting different population ratios in V1 using orientation components: a biphoton study

A feature of MotionClouds is the ability to precisely tune the precision of information following the principal axes. One which is particularly relevant for the primary visual cortical area of primates (area V1) is to tune the otirentation mean and bandwidth.

To install the necessary libraries, check out the documentation.

summary of the biphoton protocol

For the biphoton experiment:

  • The refresh rate of the screen is 70Hz and stimulation for 5 times 1s, which makes 350 images.
  • for the spatial frequency 0.125 cyc/deg is optimal (between 0.01 and 0.16).
  • for the temporal frequency 2 cyc/sec is optimal (between 0.8 and 4 sic/sec), we manipulate $B_V$ to get a qualitative estimate.

This is part of a larger study to tune orientation bandwidth.

Let's summarize this:

  • Presentation of stimuli with a circular disk during 250 ms ON then 250ms OFF
  • fixed parameters:
  • mean spatial frequency tuned for optimal neural tuning,
  • spatial frequency bandwidth tuned for optimal neural tuning,
  • temporal frequency bandwidth tuned for optimal neural tuning (TODO),
  • parameters:
  • 12 orientations including cardinals (TO BE DONE AT THE PRESENTATION SOFTWARE LEVEL)
  • 7 orientation bandwidths (infinite, pi/2, pi/4, pi/8, pi/16, pi/32, dirac),
  • 2 bandwidth in speed: dynamic (B_V=.5) or static (STATIC TO BE DONE AT THE PRESENTATION SOFTWARE LEVEL BY TAKING ONE FRAME of the DYNAMIC STIMULUS)
  • 3 different seeds: 42, 1973 and 2015 (completely arbitrary)

Grand total for one block is (12 orientations times 6 BWo + 1) * (Dyn / stat) * 0.5s :

In [3]:
%%writefile ../files/2014-11-10_balaV1-protocol/2018-11-22_biphoton_protocol.py
#!/usr/bin/env python3
# -*- coding: utf-8 -*
import numpy as np
import MotionClouds as mc
import os

viewingDistance = 12.3 # cm
screen_height_cm = 26.8 # cm
#un deg / cm
print('visual angle of the screen', 2*np.arctan(screen_height_cm/2/viewingDistance)*180/np.pi, ' degrees')
print('degrees per centimeter', 2*np.arctan(screen_height_cm/2/viewingDistance)*180/np.pi/screen_height_cm)

#screen_height_px = 1024 # pixels 
screen_height_px = 512 # pixels 
deg_per_px = 2*np.arctan(screen_height_cm/2/viewingDistance)*180/np.pi/screen_height_px
print('degrees per pixel', deg_per_px)

fps = 60 # frames per second
T = 1 # duration of one period in second

mc.N_X, mc.N_Y, mc.N_frame = screen_height_px, screen_height_px, int(fps*T)

print('width of these motion clouds (', mc.N_X, ', ', mc.N_Y, ')')
print('width of stimulus in degrees', mc.N_X * deg_per_px)
phi_sf_0 = 3 # Optimal spatial frequency [cpd]
print('Optimal spatial frequency in cycles per degree', phi_sf_0)
print('Optimal spatial frequency in cycles per window = ', phi_sf_0 *  mc.N_X * deg_per_px)
sf_0 = phi_sf_0 * deg_per_px
print('cycles per pixel = ', sf_0)

# Experimental constants 
contrast = 1.
B_sf = 0.1*sf_0 # 0.1   # BW spat. freq.
B_ft = .1 # BW temp. freq.

B_V = B_ft/sf_0     # BW in speed ("plane thickness")
print('B_V = ', B_V)
theta = 0.0   # Central orientation
# generate all files
dry_run = True
dry_run = False

#downscale = 1
fx, fy, ft = mc.get_grids(mc.N_X, mc.N_Y, mc.N_frame)

name = '2018-11-22_biphoton'
vext = '.png'
mc.figpath = '.'
try:
    os.mkdir(os.path.join(mc.figpath, name))
except:
    pass
print('-'*50)
print('Starting protocol')
print('-'*50)
for B_theta in [np.pi/32, np.pi/16, np.pi/8, np.pi/4]: #, np.pi/2, np.inf]: # 2, 5.5, 11, 23, 45]:
    if B_theta == np.inf: B_theta_str = 'inf'
    else: B_theta_str = str(int(np.ceil(B_theta*180/np.pi)))
    for seed in [42, 1973]:
        name_ = name + '_B_theta_' + B_theta_str
        name_ += '_seed_' + str(seed)
        print('Cooking:', name_)
        if not dry_run:
            if not(os.path.isfile(os.path.join(mc.figpath, name, name_ + vext))) and not(os.path.isfile(os.path.join(mc.figpath, name, name_))):
                mc_i = mc.envelope_gabor(fx, fy, ft, 
                                         V_X=0., V_Y=0., B_V=B_V, 
                                         sf_0=sf_0, B_sf=B_sf, 
                                         theta=0., B_theta=B_theta)
                im = mc.random_cloud(mc_i)
                im = mc.rectif(im, contrast=contrast, verbose=True)
                # TERRIBLE HACK ! setting 2 corner pixels to 0 and 1 to ensure contrast is well preserved...
                im[0, 0, :] = 0.
                im[-1, -1, :] = 1.
                mc.anim_save(im, os.path.join(mc.figpath, name, name_), T_movie=T, vext=vext)
            else:
                print(' MC ' + os.path.join(mc.figpath, name, name_) + ' already done')
        else:
            print(' MC ' + os.path.join(mc.figpath, name, name_) + ' skipped  (dry run)')
Overwriting ../files/2014-11-10_balaV1-protocol/2018-11-22_biphoton_protocol.py
In [4]:
%%writefile  ../files/2014-11-10_balaV1-protocol/2018-11-22_biphoton_protocol.sh
#!/usr/bin/env bash
NAME=2018-11-22_biphoton
cd ../files/2014-11-10_balaV1-protocol
rm -fr `echo $NAME`_protocol.zip `echo $NAME`
echo 'start generating files'
ipython3 `echo $NAME`_protocol.py
echo 'done generating files'
zip `echo $NAME`_protocol.zip `echo $NAME`_protocol.* `echo $NAME`_protocol.sh `echo $NAME`/* `echo $NAME`/**/*
rm -fr `echo $NAME`
cd ../..
Overwriting ../files/2014-11-10_balaV1-protocol/2018-11-22_biphoton_protocol.sh
In [ ]:
!sh ../files/2014-11-10_balaV1-protocol/2017-04-19_biphoton_protocol.sh

some book keeping for the notebook

In [4]:
%load_ext version_information
%version_information numpy, scipy, matplotlib, MotionClouds
Out[4]:
Software Version
Python 3.6.5 64bit [GCC 4.2.1 Compatible Apple LLVM 9.1.0 (clang-902.0.39.2)]
IPython 7.1.1
OS Darwin 18.2.0 x86_64 i386 64bit
numpy 1.15.4
scipy 1.1.0
matplotlib 3.0.2
MotionClouds 20180606
Thu Nov 15 12:15:47 2018 CET