calibration¶
Calibration Module¶
The calibration module of this library is used to generate the metadata necessary configure and run calibration workflows for different assets/devices.
- The metadata follows the general logic of the library by implementing the three core classes:
A fourth class Calibration
,
specific to the Calibration module, is also implemented to keep track of the calibration metrics.
This class was written to be aligned to the Calibration class in aind-data-schemas.
An application example will be provided below.
While we use the base AindBehaviorSessionModel
class to keep track of the session metadata,
both AindBehaviorRigModel
and AindBehaviorTaskLogicModel
are
expected to be sub-classed to specify the necessary dependencies of the calibration workflow.
Sub-classing Calibration
¶
Sub-classing Calibration
boils down to providing a subtype of the input and output fields.
These fields are expected to be of a sub-type of ~pydantic.BaseModel and define the structure of the calibration outcome.
Conceptually, input is the pre-process data that resulted from the calibration workflow (i.e. the weight of delivered water),
whereas output is used to represent a post-processed version of the calibration outcome (e.g. a linear model that relates valve-opening times to water volume).
An example of a sub-class of Calibration is provided below:
from pydantic import BaseModel, Field
from typing import List, Literal
from aind_behavior_services.calibration import Calibration
class BarContainer(BaseModel):
baz: string = Field(..., description="Baz value")
bar: float = Field(..., description="Bar value")
class DeviceCalibrationInput(BaseModel):
measured_foo: List[int] = Field(..., description="Measurements of Foo")
bar_container: List[BarContainer] = Field(..., description="Bar container")
class DeviceCalibrationOutput(BaseModel):
param_a = float = Field(default=1, description="Parameter A")
param_b = float = Field(default=0, description="Parameter B")
class DeviceCalibration(Calibration):
device_name: Literal["MyDevice"] = "MyDevice"
description: Literal["Stores the calibration of a device"] = "Stores the calibration of a device"
input: DeviceCalibrationInput = Field(..., title="Input of the calibration")
output: DeviceCalibrationOutput = Field(..., title="Output of the calibration")
Sub-classing AindBehaviorRigModel
¶
We adopt the following pattern to sub-class the AindBehaviorRigModel
class:
from aind_behavior_services.rig import AindBehaviorRigModel, Device
RIG_VERSION = "1.0.0" # Use SemVer
class FooDevice(Device):
calibration: DeviceCalibration = Field(..., title="Calibration of the device foo")
class CalibrationRig(AindBehaviorRigModel):
version: Literal[RIG_VERSION] = RIG_VERSION
device_foo: FooDevice = Field(..., title="Device Foo")
device_bar: Device = Field(..., title="Device Bar")
For an example see aind_behavior_services.calibration.olfactometer.CalibrationRig
.
Sub-classing AindBehaviorTaskLogicModel
¶
The same way a AindBehaviorTaskLogicModel
is used to define
the settings to run a behavior task, it is also used to define the settings to run a calibration workflow.
It will thus follow an identical sub-classing pattern:
from aind_behavior_services.task_logic import AindBehaviorTaskLogicModel, TaskParameters
TASK_LOGIC_VERSION = "0.1.0"
class CalibrationParameters(TaskParameters):
n_iterations: int = Field(default=10, description="Number of iterations to run the calibration")
channels_to_calibrate: List[Literal[1,2,3]] = Field(default=[1], description="List of channels to calibrate")
class CalibrationLogic(AindBehaviorTaskLogicModel):
name: Literal["CalibrationLogic"] = "CalibrationLogic
version: Literal[TASK_LOGIC_VERSION] = TASK_LOGIC_VERSION
task_parameters: CalibrationParameters = Field(default=CalibrationParameters(), title="Task parameters", validate_default=True)
For an example see aind_behavior_services.calibration.olfactometer.CalibrationLogic
.
- aind_manipulator
- load_cells
- olfactometer
- water_valve
- treadmill