Skip to content

Core Interface module

Core interface module for EthoPy.

This module provides the base interface for hardware interaction and configuration of hardware based on setup index.

Configuration

Bases: Manual

DataJoint table for saving setup configurations for each session.

Source code in src/ethopy/core/interface.py
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
@interface.schema
class Configuration(dj.Manual):
    """DataJoint table for saving setup configurations for each session."""

    definition = """
    # Session behavior configuration info
    -> experiment.Session
    """

    class Port(dj.Part):
        """Port configuration table."""

        definition = """
        # Probe identity
        -> Configuration
        port                     : tinyint                      # port id
        type="Lick"              : varchar(24)                 # port type
        ---
        ready=0                  : tinyint                      # ready flag
        response=0               : tinyint                      # response flag
        reward=0                 : tinyint                      # reward flag
        discription              : varchar(256)
        """

    class Ball(dj.Part):
        """Ball configuration table."""

        definition = """
        # Ball information
        -> Configuration
        ---
        ball_radius=0.125        : float                   # in meters
        material="styrofoam"     : varchar(64)             # ball material
        coupling="bearings"      : enum('bearings','air')  # mechanical coupling
        discription              : varchar(256)
        """

    class Screen(dj.Part):
        """Screen configuration table."""

        definition = """
        # Screen information
        -> Configuration
        screen_idx               : tinyint
        ---
        intensity                : tinyint UNSIGNED
        distance         : float
        center_x         : float
        center_y         : float
        aspect           : float
        size             : float
        fps                      : tinyint UNSIGNED
        resolution_x             : smallint
        resolution_y             : smallint
        description              : varchar(256)
        """

    class Speaker(dj.Part):
        """Speaker configuration table."""

        definition = """
        # Speaker information
        speaker_idx             : tinyint
        -> Configuration
        ---
        sound_freq=10000        : int           # in Hz
        duration=500            : int           # in ms
        volume=50               : tinyint       # 0-100 percentage
        discription             : varchar(256)
        """

Ball

Bases: Part

Ball configuration table.

Source code in src/ethopy/core/interface.py
472
473
474
475
476
477
478
479
480
481
482
483
class Ball(dj.Part):
    """Ball configuration table."""

    definition = """
    # Ball information
    -> Configuration
    ---
    ball_radius=0.125        : float                   # in meters
    material="styrofoam"     : varchar(64)             # ball material
    coupling="bearings"      : enum('bearings','air')  # mechanical coupling
    discription              : varchar(256)
    """

Port

Bases: Part

Port configuration table.

Source code in src/ethopy/core/interface.py
457
458
459
460
461
462
463
464
465
466
467
468
469
470
class Port(dj.Part):
    """Port configuration table."""

    definition = """
    # Probe identity
    -> Configuration
    port                     : tinyint                      # port id
    type="Lick"              : varchar(24)                 # port type
    ---
    ready=0                  : tinyint                      # ready flag
    response=0               : tinyint                      # response flag
    reward=0                 : tinyint                      # reward flag
    discription              : varchar(256)
    """

Screen

Bases: Part

Screen configuration table.

Source code in src/ethopy/core/interface.py
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
class Screen(dj.Part):
    """Screen configuration table."""

    definition = """
    # Screen information
    -> Configuration
    screen_idx               : tinyint
    ---
    intensity                : tinyint UNSIGNED
    distance         : float
    center_x         : float
    center_y         : float
    aspect           : float
    size             : float
    fps                      : tinyint UNSIGNED
    resolution_x             : smallint
    resolution_y             : smallint
    description              : varchar(256)
    """

Speaker

Bases: Part

Speaker configuration table.

Source code in src/ethopy/core/interface.py
505
506
507
508
509
510
511
512
513
514
515
516
517
class Speaker(dj.Part):
    """Speaker configuration table."""

    definition = """
    # Speaker information
    speaker_idx             : tinyint
    -> Configuration
    ---
    sound_freq=10000        : int           # in Hz
    duration=500            : int           # in ms
    volume=50               : tinyint       # 0-100 percentage
    discription             : varchar(256)
    """

Interface

Base interface class for hardware interaction in experimental setups.

This class manages hardware interfaces including ports, cameras, and other peripherals. It provides methods for stimulus delivery, reward management, and hardware control.

Attributes:

Name Type Description
port int

Current active port

resp_tmst int

Response timestamp

ready_dur int

Ready duration

activity_tmst int

Activity timestamp

ready_tmst int

Ready state timestamp

pulse_rew Dict[int, Dict]

Reward pulse settings by port

ports List[Port]

List of available ports

response List

List of responses

duration Dict[int, float]

Duration settings by port

ready bool

Ready state flag

timer_ready Timer

Timer for ready state

weight_per_pulse Dict[int, float]

Calibration weights per pulse

pulse_dur Dict[int, float]

Pulse durations by port

channels Dict[str, Any]

Channel mappings

position_dur int

Position duration

Source code in src/ethopy/core/interface.py
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
class Interface:
    """Base interface class for hardware interaction in experimental setups.

    This class manages hardware interfaces including ports, cameras, and other
    peripherals.
    It provides methods for stimulus delivery, reward management, and hardware control.

    Attributes:
        port (int): Current active port
        resp_tmst (int): Response timestamp
        ready_dur (int): Ready duration
        activity_tmst (int): Activity timestamp
        ready_tmst (int): Ready state timestamp
        pulse_rew (Dict[int, Dict]): Reward pulse settings by port
        ports (List[Port]): List of available ports
        response (List): List of responses
        duration (Dict[int, float]): Duration settings by port
        ready (bool): Ready state flag
        timer_ready (Timer): Timer for ready state
        weight_per_pulse (Dict[int, float]): Calibration weights per pulse
        pulse_dur (Dict[int, float]): Pulse durations by port
        channels (Dict[str, Any]): Channel mappings
        position_dur (int): Position duration

    """

    def __init__(
        self,
        exp: Optional = None,
        beh: Optional = None,
        callbacks: bool = True,
    ) -> None:
        """Initialize the interface with experiment and behavior objects.

        Args:
            exp: Experiment object containing parameters and logger
            beh: Behavior object for tracking responses
            callbacks: Whether to enable callback functions

        """
        # Initialize basic attributes
        self.callbacks = callbacks
        self.beh = beh
        self.exp = exp
        self.logger = exp.logger if exp else None
        self.position = Port()
        self.position_tmst: int = 0
        self.camera = None
        self.ports: List[Port] = []
        self.pulse_rew: Dict[int, Dict] = {}
        self.duration: Dict[int, float] = {}
        self.weight_per_pulse: Dict[int, float] = {}
        self.pulse_dur: Dict[int, float] = {}

        # Initialize timing variables
        self.port: int = 0
        self.resp_tmst: int = 0
        self.ready_dur: int = 0
        self.activity_tmst: int = 0
        self.ready_tmst: int = 0
        self.position_dur: int = 0

        # Initialize state variables
        self.ready: bool = False
        self.timer_ready = Timer()
        self.response: List[Any] = []

        if exp and hasattr(exp, "params"):
            self._initialize_hardware()

    def _initialize_hardware(self) -> None:
        """Initialize hardware components based on setup configuration.

        This method sets up ports and camera if configured in the experiment parameters.
        """
        # Initialize ports
        port_configs = self.logger.get(
            schema="interface",
            table="SetupConfiguration.Port",
            key=f"setup_conf_idx={self.exp.setup_conf_idx}",
            as_dict=True,
        )

        for port_config in port_configs:
            self.ports.append(Port(**port_config))

        self.ports = np.array(self.ports)
        self.proximity_ports = np.array(
            [p.port for p in self.ports if p.type == "Proximity"]
        )
        self.rew_ports = np.array([p.port for p in self.ports if p.reward])

        # Initialize camera if configured
        self._initialize_camera()

    def _initialize_camera(self) -> None:
        """Initialize camera if configured in setup."""
        setup_cameras = self.logger.get(
            schema="interface",
            table="SetupConfiguration.Camera",
            fields=["setup_conf_idx"],
        )

        if self.exp.setup_conf_idx in setup_cameras:
            camera_params = self.logger.get(
                schema="interface",
                table="SetupConfiguration.Camera",
                key=f"setup_conf_idx={self.exp.setup_conf_idx}",
                as_dict=True,
            )[0]

            camera_class = getattr(
                import_module("Interfaces.Camera"), camera_params["discription"]
            )

            self.camera = camera_class(
                filename=f"{self.logger.trial_key['animal_id']}"
                f"_{self.logger.trial_key['session']}",
                logger=self.logger,
                logger_timer=self.logger.logger_timer,
                video_aim=camera_params.pop("video_aim"),
                **camera_params,
            )

    def give_liquid(self, port: int, duration: Optional[float] = 0) -> None:
        """Deliver liquid reward through specified port.

        Args:
            port: Port number for delivery
            duration: Duration of delivery in milliseconds

        """

    def give_odor(self, odor_idx: int, duration: float) -> None:
        """Deliver odor stimulus.

        Args:
            odor_idx: Index of odor to deliver
            duration: Duration of delivery in milliseconds

        """

    def give_sound(self, sound_freq: float, duration: float, dutycycle: float) -> None:
        """Generate sound stimulus.

        Args:
            sound_freq: Frequency of sound in Hz
            duration: Duration of sound in milliseconds
            dutycycle: Duty cycle for sound generation (0-1)

        """

    def in_position(self) -> Tuple[bool, float]:
        """Check if subject is in correct position.

        Returns:
            Tuple of (position status, position time)

        """
        return True, 0

    def create_pulse(self, port: int, duration: float) -> None:
        """Create a pulse for stimulus delivery.

        Args:
            port: Port number for pulse
            duration: Duration of pulse in milliseconds

        """

    def sync_out(self, state: bool = False) -> None:
        """Send synchronization signal.

        Args:
            state: Synchronization state to set

        """

    def set_operation_status(self, operation_status: bool) -> None:
        """Set operation status of interface.

        Args:
            operation_status: Status to set

        """

    def cleanup(self) -> None:
        """Clean up interface resources."""

    def release(self) -> None:
        """Release hardware resources, especially camera."""
        if self.camera:
            log.info("Release camear" * 10)
            if self.camera.recording.is_set():
                self.camera.stop_rec()

    def load_calibration(self) -> None:
        """Load port calibration data from database.

        This method loads the most recent calibration data for each reward port,
        including pulse durations and weights.

        Raises:
            RuntimeError: If no calibration data is found

        """
        for port in list(set(self.rew_ports)):
            self.pulse_rew[port] = dict()
            key = dict(setup=self.logger.setup, port=port)
            dates = self.logger.get(
                schema="interface",
                table="PortCalibration.Liquid",
                key=key,
                fields=["date"],
                order_by="date",
            )
            if np.size(dates) < 1:
                log.error("No PortCalibration found!")
                self.exp.quit = True
                break

            key["date"] = dates[-1]  # use most recent calibration

            self.pulse_dur[port], pulse_num, weight = self.logger.get(
                schema="interface",
                table="PortCalibration.Liquid",
                key=key,
                fields=["pulse_dur", "pulse_num", "weight"],
            )
            self.weight_per_pulse[port] = np.divide(weight, pulse_num)

    def calc_pulse_dur(self, reward_amount: float) -> Dict[int, float]:
        """Calculate pulse duration for desired reward amount.

        Args:
            reward_amount: Desired reward amount in microliters

        Returns:
            Dictionary mapping ports to actual reward amounts

        """
        actual_rew = {}
        for port in self.rew_ports:
            if reward_amount not in self.pulse_rew[port]:
                self.duration[port] = np.interp(
                    reward_amount / 1000,
                    self.weight_per_pulse[port],
                    self.pulse_dur[port],
                )
                self.pulse_rew[port][reward_amount] = (
                    np.max((np.min(self.weight_per_pulse[port]), reward_amount / 1000))
                    * 1000
                )  # in uL
            actual_rew[port] = self.pulse_rew[port][reward_amount]
        return actual_rew

    def _channel2port(self, channel: Optional[int], category: str = "Proximity"):
        """Convert channel number to port object.

        Args:
            channel: Channel number to convert
            category: Port category to match

        Returns:
            Corresponding port or None if not found

        """
        port = reverse_lookup(self.channels[category], channel) if channel else 0
        if port:
            port = self.ports[Port(type=category, port=port) == self.ports][0]
        return port

__init__(exp=None, beh=None, callbacks=True)

Initialize the interface with experiment and behavior objects.

Parameters:

Name Type Description Default
exp Optional

Experiment object containing parameters and logger

None
beh Optional

Behavior object for tracking responses

None
callbacks bool

Whether to enable callback functions

True
Source code in src/ethopy/core/interface.py
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
def __init__(
    self,
    exp: Optional = None,
    beh: Optional = None,
    callbacks: bool = True,
) -> None:
    """Initialize the interface with experiment and behavior objects.

    Args:
        exp: Experiment object containing parameters and logger
        beh: Behavior object for tracking responses
        callbacks: Whether to enable callback functions

    """
    # Initialize basic attributes
    self.callbacks = callbacks
    self.beh = beh
    self.exp = exp
    self.logger = exp.logger if exp else None
    self.position = Port()
    self.position_tmst: int = 0
    self.camera = None
    self.ports: List[Port] = []
    self.pulse_rew: Dict[int, Dict] = {}
    self.duration: Dict[int, float] = {}
    self.weight_per_pulse: Dict[int, float] = {}
    self.pulse_dur: Dict[int, float] = {}

    # Initialize timing variables
    self.port: int = 0
    self.resp_tmst: int = 0
    self.ready_dur: int = 0
    self.activity_tmst: int = 0
    self.ready_tmst: int = 0
    self.position_dur: int = 0

    # Initialize state variables
    self.ready: bool = False
    self.timer_ready = Timer()
    self.response: List[Any] = []

    if exp and hasattr(exp, "params"):
        self._initialize_hardware()

calc_pulse_dur(reward_amount)

Calculate pulse duration for desired reward amount.

Parameters:

Name Type Description Default
reward_amount float

Desired reward amount in microliters

required

Returns:

Type Description
Dict[int, float]

Dictionary mapping ports to actual reward amounts

Source code in src/ethopy/core/interface.py
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
def calc_pulse_dur(self, reward_amount: float) -> Dict[int, float]:
    """Calculate pulse duration for desired reward amount.

    Args:
        reward_amount: Desired reward amount in microliters

    Returns:
        Dictionary mapping ports to actual reward amounts

    """
    actual_rew = {}
    for port in self.rew_ports:
        if reward_amount not in self.pulse_rew[port]:
            self.duration[port] = np.interp(
                reward_amount / 1000,
                self.weight_per_pulse[port],
                self.pulse_dur[port],
            )
            self.pulse_rew[port][reward_amount] = (
                np.max((np.min(self.weight_per_pulse[port]), reward_amount / 1000))
                * 1000
            )  # in uL
        actual_rew[port] = self.pulse_rew[port][reward_amount]
    return actual_rew

cleanup()

Clean up interface resources.

Source code in src/ethopy/core/interface.py
212
213
def cleanup(self) -> None:
    """Clean up interface resources."""

create_pulse(port, duration)

Create a pulse for stimulus delivery.

Parameters:

Name Type Description Default
port int

Port number for pulse

required
duration float

Duration of pulse in milliseconds

required
Source code in src/ethopy/core/interface.py
187
188
189
190
191
192
193
194
def create_pulse(self, port: int, duration: float) -> None:
    """Create a pulse for stimulus delivery.

    Args:
        port: Port number for pulse
        duration: Duration of pulse in milliseconds

    """

give_liquid(port, duration=0)

Deliver liquid reward through specified port.

Parameters:

Name Type Description Default
port int

Port number for delivery

required
duration Optional[float]

Duration of delivery in milliseconds

0
Source code in src/ethopy/core/interface.py
150
151
152
153
154
155
156
157
def give_liquid(self, port: int, duration: Optional[float] = 0) -> None:
    """Deliver liquid reward through specified port.

    Args:
        port: Port number for delivery
        duration: Duration of delivery in milliseconds

    """

give_odor(odor_idx, duration)

Deliver odor stimulus.

Parameters:

Name Type Description Default
odor_idx int

Index of odor to deliver

required
duration float

Duration of delivery in milliseconds

required
Source code in src/ethopy/core/interface.py
159
160
161
162
163
164
165
166
def give_odor(self, odor_idx: int, duration: float) -> None:
    """Deliver odor stimulus.

    Args:
        odor_idx: Index of odor to deliver
        duration: Duration of delivery in milliseconds

    """

give_sound(sound_freq, duration, dutycycle)

Generate sound stimulus.

Parameters:

Name Type Description Default
sound_freq float

Frequency of sound in Hz

required
duration float

Duration of sound in milliseconds

required
dutycycle float

Duty cycle for sound generation (0-1)

required
Source code in src/ethopy/core/interface.py
168
169
170
171
172
173
174
175
176
def give_sound(self, sound_freq: float, duration: float, dutycycle: float) -> None:
    """Generate sound stimulus.

    Args:
        sound_freq: Frequency of sound in Hz
        duration: Duration of sound in milliseconds
        dutycycle: Duty cycle for sound generation (0-1)

    """

in_position()

Check if subject is in correct position.

Returns:

Type Description
Tuple[bool, float]

Tuple of (position status, position time)

Source code in src/ethopy/core/interface.py
178
179
180
181
182
183
184
185
def in_position(self) -> Tuple[bool, float]:
    """Check if subject is in correct position.

    Returns:
        Tuple of (position status, position time)

    """
    return True, 0

load_calibration()

Load port calibration data from database.

This method loads the most recent calibration data for each reward port, including pulse durations and weights.

Raises:

Type Description
RuntimeError

If no calibration data is found

Source code in src/ethopy/core/interface.py
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
def load_calibration(self) -> None:
    """Load port calibration data from database.

    This method loads the most recent calibration data for each reward port,
    including pulse durations and weights.

    Raises:
        RuntimeError: If no calibration data is found

    """
    for port in list(set(self.rew_ports)):
        self.pulse_rew[port] = dict()
        key = dict(setup=self.logger.setup, port=port)
        dates = self.logger.get(
            schema="interface",
            table="PortCalibration.Liquid",
            key=key,
            fields=["date"],
            order_by="date",
        )
        if np.size(dates) < 1:
            log.error("No PortCalibration found!")
            self.exp.quit = True
            break

        key["date"] = dates[-1]  # use most recent calibration

        self.pulse_dur[port], pulse_num, weight = self.logger.get(
            schema="interface",
            table="PortCalibration.Liquid",
            key=key,
            fields=["pulse_dur", "pulse_num", "weight"],
        )
        self.weight_per_pulse[port] = np.divide(weight, pulse_num)

release()

Release hardware resources, especially camera.

Source code in src/ethopy/core/interface.py
215
216
217
218
219
220
def release(self) -> None:
    """Release hardware resources, especially camera."""
    if self.camera:
        log.info("Release camear" * 10)
        if self.camera.recording.is_set():
            self.camera.stop_rec()

set_operation_status(operation_status)

Set operation status of interface.

Parameters:

Name Type Description Default
operation_status bool

Status to set

required
Source code in src/ethopy/core/interface.py
204
205
206
207
208
209
210
def set_operation_status(self, operation_status: bool) -> None:
    """Set operation status of interface.

    Args:
        operation_status: Status to set

    """

sync_out(state=False)

Send synchronization signal.

Parameters:

Name Type Description Default
state bool

Synchronization state to set

False
Source code in src/ethopy/core/interface.py
196
197
198
199
200
201
202
def sync_out(self, state: bool = False) -> None:
    """Send synchronization signal.

    Args:
        state: Synchronization state to set

    """

Port dataclass

Dataclass representing a hardware port configuration.

Attributes:

Name Type Description
port int

Port identifier

type str

Port type (e.g., 'Lick', 'Proximity')

ready bool

Whether port is in ready state

reward bool

Whether port can deliver rewards

response bool

Whether port accepts responses

invert bool

Whether to invert port signal

state bool

Current port state

Source code in src/ethopy/core/interface.py
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
@dataclass
class Port:
    """Dataclass representing a hardware port configuration.

    Attributes:
        port (int): Port identifier
        type (str): Port type (e.g., 'Lick', 'Proximity')
        ready (bool): Whether port is in ready state
        reward (bool): Whether port can deliver rewards
        response (bool): Whether port accepts responses
        invert (bool): Whether to invert port signal
        state (bool): Current port state

    """

    port: int = datafield(compare=True, default=0, hash=True)
    type: str = datafield(compare=True, default="", hash=True)
    ready: bool = datafield(compare=False, default=False)
    reward: bool = datafield(compare=False, default=False)
    response: bool = datafield(compare=False, default=False)
    invert: bool = datafield(compare=False, default=False)
    state: bool = datafield(compare=False, default=False)

    def __init__(self, **kwargs):
        """Initialize the instance with the given keyword arguments.

        This constructor dynamically sets the attributes of the instance
        based on the provided keyword arguments. Only attributes that are
        defined as fields of the class will be set.
        """
        names = set([f.name for f in fields(self)])
        for k, v in kwargs.items():
            if k in names:
                setattr(self, k, v)

__init__(**kwargs)

Initialize the instance with the given keyword arguments.

This constructor dynamically sets the attributes of the instance based on the provided keyword arguments. Only attributes that are defined as fields of the class will be set.

Source code in src/ethopy/core/interface.py
322
323
324
325
326
327
328
329
330
331
332
def __init__(self, **kwargs):
    """Initialize the instance with the given keyword arguments.

    This constructor dynamically sets the attributes of the instance
    based on the provided keyword arguments. Only attributes that are
    defined as fields of the class will be set.
    """
    names = set([f.name for f in fields(self)])
    for k, v in kwargs.items():
        if k in names:
            setattr(self, k, v)

PortCalibration

Bases: Manual

Liquid delivery calibration sessions for each port with water availability.

Source code in src/ethopy/core/interface.py
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
@interface.schema
class PortCalibration(dj.Manual):
    """Liquid delivery calibration sessions for each port with water availability."""

    definition = """
    # Liquid delivery calibration sessions for each port with water availability
    setup                        : varchar(256)  # Setup name
    port                         : tinyint       # port id
    date                         : date # session date (only one per day is allowed)
    """

    class Liquid(dj.Part):
        """Datajoint table for volume per pulse duty cycle estimation."""

        definition = """
        # Data for volume per pulse duty cycle estimation
        -> PortCalibration
        pulse_dur                    : int       # duration of pulse in ms
        ---
        pulse_num                    : int       # number of pulses
        weight                       : float     # weight of total liquid released in gr
        timestamp=CURRENT_TIMESTAMP  : timestamp # timestamp
        pressure=0                   : float     # air pressure (PSI)
        """

    class Test(dj.Part):
        """Datajoint table for Lick Test."""

        definition = """
        # Lick timestamps
        setup                        : varchar(256)                 # Setup name
        port                         : tinyint                      # port id
        timestamp=CURRENT_TIMESTAMP  : timestamp
        ___
        result=null                  : enum('Passed','Failed')
        pulses=null                  : int
        """

Liquid

Bases: Part

Datajoint table for volume per pulse duty cycle estimation.

Source code in src/ethopy/core/interface.py
531
532
533
534
535
536
537
538
539
540
541
542
543
class Liquid(dj.Part):
    """Datajoint table for volume per pulse duty cycle estimation."""

    definition = """
    # Data for volume per pulse duty cycle estimation
    -> PortCalibration
    pulse_dur                    : int       # duration of pulse in ms
    ---
    pulse_num                    : int       # number of pulses
    weight                       : float     # weight of total liquid released in gr
    timestamp=CURRENT_TIMESTAMP  : timestamp # timestamp
    pressure=0                   : float     # air pressure (PSI)
    """

Test

Bases: Part

Datajoint table for Lick Test.

Source code in src/ethopy/core/interface.py
545
546
547
548
549
550
551
552
553
554
555
556
class Test(dj.Part):
    """Datajoint table for Lick Test."""

    definition = """
    # Lick timestamps
    setup                        : varchar(256)                 # Setup name
    port                         : tinyint                      # port id
    timestamp=CURRENT_TIMESTAMP  : timestamp
    ___
    result=null                  : enum('Passed','Failed')
    pulses=null                  : int
    """

SetupConfiguration

Bases: Lookup, Manual

DataJoint table for configuring the setup interfaces.

The user can define all harware configuration by defining only the setup index.

Source code in src/ethopy/core/interface.py
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
@interface.schema
class SetupConfiguration(dj.Lookup, dj.Manual):
    """DataJoint table for configuring the setup interfaces.

    The user can define all harware configuration by defining only the setup index.
    """

    definition = """
    # Setup configuration
    setup_conf_idx           : tinyint      # configuration version
    ---
    interface                : enum('DummyPorts','RPPorts', 'PCPorts', 'RPVR')
    discription              : varchar(256)
    """

    contents = [
        [0, "DummyPorts", "Simulation"],
    ]

    class Port(dj.Lookup, dj.Part):
        """Port configuration table."""

        definition = """
        # Probe identityrepeat_n = 1

        port                     : tinyint                      # port id
        type="Lick"              : enum('Lick','Proximity')     # port type
        -> SetupConfiguration
        ---
        ready=0                  : tinyint                      # ready flag
        response=0               : tinyint                      # response flag
        reward=0                 : tinyint                      # reward flag
        invert=0                 : tinyint                      # invert flag
        discription              : varchar(256)
        """

        contents = [
            [1, "Lick", 0, 0, 1, 1, 0, "probe"],
            [2, "Lick", 0, 0, 1, 1, 0, "probe"],
            [3, "Proximity", 0, 1, 0, 0, 0, "probe"],
        ]

    class Screen(dj.Lookup, dj.Part):
        """Screen configuration table."""

        definition = """
        # Screen information
        screen_idx               : tinyint
        -> SetupConfiguration
        ---
        intensity                : tinyint UNSIGNED
        distance                 : float
        center_x                 : float
        center_y                 : float
        aspect                   : float
        size                     : float
        fps                      : tinyint UNSIGNED
        resolution_x             : smallint
        resolution_y             : smallint
        description              : varchar(256)
        fullscreen               : tinyint
        """

        contents = [
            [1, 0, 64, 5.0, 0, -0.1, 1.66, 7.0, 30, 800, 480, "Simulation", 0],
        ]

    class Ball(dj.Lookup, dj.Part):
        """Ball configuration table."""

        definition = """
        # Ball information
        -> SetupConfiguration
        ---
        ball_radius=0.125        : float                   # in meters
        material="styrofoam"     : varchar(64)             # ball material
        coupling="bearings"      : enum('bearings','air')  # mechanical coupling
        discription              : varchar(256)
        """

    class Speaker(dj.Lookup, dj.Part):
        """Speaker configuration table."""

        definition = """
        # Speaker information
        speaker_idx             : tinyint
        -> SetupConfiguration
        ---
        sound_freq=10000        : int           # in Hz
        duration=500            : int           # in ms
        volume=50               : tinyint       # 0-100 percentage
        discription             : varchar(256)
        """

    class Camera(dj.Lookup, dj.Part):
        """Camera configuration table."""

        definition = """
        # Camera information
        camera_idx               : tinyint
        -> SetupConfiguration
        ---
        fps                      : tinyint UNSIGNED
        resolution_x             : smallint
        resolution_y             : smallint
        shutter_speed            : smallint
        iso                      : smallint
        file_format              : varchar(256)
        video_aim                : enum('eye','body','openfield')
        discription              : varchar(256)
        """

Ball

Bases: Lookup, Part

Ball configuration table.

Source code in src/ethopy/core/interface.py
402
403
404
405
406
407
408
409
410
411
412
413
class Ball(dj.Lookup, dj.Part):
    """Ball configuration table."""

    definition = """
    # Ball information
    -> SetupConfiguration
    ---
    ball_radius=0.125        : float                   # in meters
    material="styrofoam"     : varchar(64)             # ball material
    coupling="bearings"      : enum('bearings','air')  # mechanical coupling
    discription              : varchar(256)
    """

Camera

Bases: Lookup, Part

Camera configuration table.

Source code in src/ethopy/core/interface.py
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
class Camera(dj.Lookup, dj.Part):
    """Camera configuration table."""

    definition = """
    # Camera information
    camera_idx               : tinyint
    -> SetupConfiguration
    ---
    fps                      : tinyint UNSIGNED
    resolution_x             : smallint
    resolution_y             : smallint
    shutter_speed            : smallint
    iso                      : smallint
    file_format              : varchar(256)
    video_aim                : enum('eye','body','openfield')
    discription              : varchar(256)
    """

Port

Bases: Lookup, Part

Port configuration table.

Source code in src/ethopy/core/interface.py
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
class Port(dj.Lookup, dj.Part):
    """Port configuration table."""

    definition = """
    # Probe identityrepeat_n = 1

    port                     : tinyint                      # port id
    type="Lick"              : enum('Lick','Proximity')     # port type
    -> SetupConfiguration
    ---
    ready=0                  : tinyint                      # ready flag
    response=0               : tinyint                      # response flag
    reward=0                 : tinyint                      # reward flag
    invert=0                 : tinyint                      # invert flag
    discription              : varchar(256)
    """

    contents = [
        [1, "Lick", 0, 0, 1, 1, 0, "probe"],
        [2, "Lick", 0, 0, 1, 1, 0, "probe"],
        [3, "Proximity", 0, 1, 0, 0, 0, "probe"],
    ]

Screen

Bases: Lookup, Part

Screen configuration table.

Source code in src/ethopy/core/interface.py
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
class Screen(dj.Lookup, dj.Part):
    """Screen configuration table."""

    definition = """
    # Screen information
    screen_idx               : tinyint
    -> SetupConfiguration
    ---
    intensity                : tinyint UNSIGNED
    distance                 : float
    center_x                 : float
    center_y                 : float
    aspect                   : float
    size                     : float
    fps                      : tinyint UNSIGNED
    resolution_x             : smallint
    resolution_y             : smallint
    description              : varchar(256)
    fullscreen               : tinyint
    """

    contents = [
        [1, 0, 64, 5.0, 0, -0.1, 1.66, 7.0, 30, 800, 480, "Simulation", 0],
    ]

Speaker

Bases: Lookup, Part

Speaker configuration table.

Source code in src/ethopy/core/interface.py
415
416
417
418
419
420
421
422
423
424
425
426
427
class Speaker(dj.Lookup, dj.Part):
    """Speaker configuration table."""

    definition = """
    # Speaker information
    speaker_idx             : tinyint
    -> SetupConfiguration
    ---
    sound_freq=10000        : int           # in Hz
    duration=500            : int           # in ms
    volume=50               : tinyint       # 0-100 percentage
    discription             : varchar(256)
    """