Skip to content

Commit

Permalink
Remove ADAravis Deadtime Lookup Table (#305)
Browse files Browse the repository at this point in the history
* Remove ADAravis Deadtime Lookup Table

* Add comment explaining aravis deadtime
  • Loading branch information
callumforrester authored May 17, 2024
1 parent 5bcac12 commit 91e0e6f
Show file tree
Hide file tree
Showing 4 changed files with 13 additions and 178 deletions.
6 changes: 1 addition & 5 deletions src/ophyd_async/epics/areadetector/aravis.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

from bluesky.protocols import HasHints, Hints

from ophyd_async.core import DirectoryProvider, StandardDetector, TriggerInfo
from ophyd_async.core import DirectoryProvider, StandardDetector
from ophyd_async.epics.areadetector.controllers.aravis_controller import (
AravisController,
)
Expand Down Expand Up @@ -45,10 +45,6 @@ def __init__(
name=name,
)

async def _prepare(self, value: TriggerInfo) -> None:
await self.drv.fetch_deadtime()
await super()._prepare(value)

def get_external_trigger_gpio(self):
return self._controller.gpio_number

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@
)
from ophyd_async.epics.areadetector.utils import ImageMode, stop_busy_record

# The deadtime of an ADaravis controller varies depending on the exact model of camera.
# Ideally we would maximize performance by dynamically retrieving the deadtime at
# runtime. See https://github.com/bluesky/ophyd-async/issues/308
_HIGHEST_POSSIBLE_DEADTIME = 1961e-6


class AravisController(DetectorControl):
GPIO_NUMBER = Literal[1, 2, 3, 4]
Expand All @@ -23,7 +28,7 @@ def __init__(self, driver: AravisDriver, gpio_number: GPIO_NUMBER) -> None:
self.gpio_number = gpio_number

def get_deadtime(self, exposure: float) -> float:
return self._drv.dead_time or 0
return _HIGHEST_POSSIBLE_DEADTIME

async def arm(
self,
Expand Down
122 changes: 2 additions & 120 deletions src/ophyd_async/epics/areadetector/drivers/aravis_driver.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
from enum import Enum
from typing import Callable, Dict, Literal, Optional, Tuple
from typing import Literal

from ophyd_async.epics.areadetector.drivers import ADBase
from ophyd_async.epics.signal.signal import epics_signal_r, epics_signal_rw_rbv
from ophyd_async.epics.signal.signal import epics_signal_rw_rbv


class AravisTriggerMode(str, Enum):
Expand All @@ -22,113 +22,6 @@ class AravisTriggerMode(str, Enum):
AravisTriggerSource = Literal["Freerun", "Line1", "Line2", "Line3", "Line4"]


def _reverse_lookup(
model_deadtimes: Dict[float, Tuple[str, ...]],
) -> Callable[[str], float]:
def inner(pixel_format: str, model_name: str) -> float:
for deadtime, pixel_formats in model_deadtimes.items():
if pixel_format in pixel_formats:
return deadtime
raise ValueError(
f"Model {model_name} does not have a defined deadtime "
f"for pixel format {pixel_format}"
)

return inner


_deadtimes: Dict[str, Callable[[str, str], float]] = {
# cite: https://cdn.alliedvision.com/fileadmin/content/documents/products/cameras/Manta/techman/Manta_TechMan.pdf retrieved 2024-04-05 # noqa: E501
"Manta G-125": lambda _, __: 63e-6,
"Manta G-145": lambda _, __: 106e-6,
"Manta G-235": _reverse_lookup(
{
118e-6: (
"Mono8",
"Mono12Packed",
"BayerRG8",
"BayerRG12",
"BayerRG12Packed",
"YUV411Packed",
),
256e-6: ("Mono12", "BayerRG12", "YUV422Packed"),
390e-6: ("RGB8Packed", "BGR8Packed", "YUV444Packed"),
}
),
"Manta G-895": _reverse_lookup(
{
404e-6: (
"Mono8",
"Mono12Packed",
"BayerRG8",
"BayerRG12Packed",
"YUV411Packed",
),
542e-6: ("Mono12", "BayerRG12", "YUV422Packed"),
822e-6: ("RGB8Packed", "BGR8Packed", "YUV444Packed"),
}
),
"Manta G-2460": _reverse_lookup(
{
979e-6: (
"Mono8",
"Mono12Packed",
"BayerRG8",
"BayerRG12Packed",
"YUV411Packed",
),
1304e-6: ("Mono12", "BayerRG12", "YUV422Packed"),
1961e-6: ("RGB8Packed", "BGR8Packed", "YUV444Packed"),
}
),
# cite: https://cdn.alliedvision.com/fileadmin/content/documents/products/cameras/various/appnote/GigE/GigE-Cameras_AppNote_PIV-Min-Time-Between-Exposures.pdf retrieved 2024-04-05 # noqa: E501
"Manta G-609": lambda _, __: 47e-6,
# cite: https://cdn.alliedvision.com/fileadmin/content/documents/products/cameras/Mako/techman/Mako_TechMan_en.pdf retrieved 2024-04-05 # noqa: E501
"Mako G-040": _reverse_lookup(
{
101e-6: (
"Mono8",
"Mono12Packed",
"BayerRG8",
"BayerRG12Packed",
"YUV411Packed",
),
140e-6: ("Mono12", "BayerRG12", "YUV422Packed"),
217e-6: ("RGB8Packed", "BGR8Packed", "YUV444Packed"),
}
),
"Mako G-125": lambda _, __: 70e-6,
# Assume 12 bits: 10 bits = 275e-6
"Mako G-234": _reverse_lookup(
{
356e-6: (
"Mono8",
"BayerRG8",
"BayerRG12",
"BayerRG12Packed",
"YUV411Packed",
"YUV422Packed",
),
# Assume 12 bits: 10 bits = 563e-6
726e-6: ("RGB8Packed", "BRG8Packed", "YUV444Packed"),
}
),
"Mako G-507": _reverse_lookup(
{
270e-6: (
"Mono8",
"Mono12Packed",
"BayerRG8",
"BayerRG12Packed",
"YUV411Packed",
),
363e-6: ("Mono12", "BayerRG12", "YUV422Packed"),
554e-6: ("RGB8Packed", "BGR8Packed", "YUV444Packed"),
}
),
}


class AravisDriver(ADBase):
# If instantiating a new instance, ensure it is supported in the _deadtimes dict
"""Generic Driver supporting the Manta and Mako drivers.
Expand All @@ -142,15 +35,4 @@ def __init__(self, prefix: str, name: str = "") -> None:
AravisTriggerMode, prefix + "TriggerMode"
)
self.trigger_source = epics_signal_rw_rbv(str, prefix + "TriggerSource")
self.model = epics_signal_r(str, prefix + "Model_RBV")
self.pixel_format = epics_signal_rw_rbv(str, prefix + "PixelFormat")
self.dead_time: Optional[float] = None
super().__init__(prefix, name=name)

async def fetch_deadtime(self) -> None:
# All known in-use version B/C have same deadtime as non-B/C
model: str = (await self.model.get_value()).removesuffix("B").removesuffix("C")
if model not in _deadtimes:
raise ValueError(f"Model {model} does not have defined deadtimes")
pixel_format: str = await self.pixel_format.get_value()
self.dead_time = _deadtimes.get(model)(pixel_format, model)
56 changes: 4 additions & 52 deletions tests/epics/areadetector/test_aravis.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,58 +24,12 @@ async def adaravis(
return adaravis


@pytest.mark.parametrize(
"model,pixel_format,deadtime",
[
("Manta G-125", "Mono12Packed", 63e-6),
("Manta G-125B", "Mono12Packed", 63e-6),
("Manta G-125", "Mono8", 63e-6),
("Manta G-125B", "Mono8", 63e-6),
("Manta G-235", "Mono8", 118e-6),
("Manta G-235B", "Mono8", 118e-6),
("Manta G-235", "RGB8Packed", 390e-6),
("Manta G-235B", "RGB8Packed", 390e-6),
("Manta G-609", "", 47e-6),
("Manta G-609", "foo", 47e-6),
("Manta G-609", None, 47e-6),
],
)
async def test_deadtime_fetched(
model: str,
pixel_format: str,
deadtime: float,
adaravis: AravisDetector,
):
set_mock_value(adaravis.drv.model, model)
set_mock_value(adaravis.drv.pixel_format, pixel_format)

await adaravis.drv.fetch_deadtime()
# deadtime invariant with exposure time
assert adaravis.controller.get_deadtime(0) == deadtime
assert adaravis.controller.get_deadtime(500) == deadtime


async def test_unknown_model_deadtime(
@pytest.mark.parametrize("exposure_time", [0.0, 0.1, 1.0, 10.0, 100.0])
async def test_deadtime_invariant_with_exposure_time(
exposure_time: float,
adaravis: AravisDetector,
):
set_mock_value(adaravis.drv.model, "FOO")

with pytest.raises(ValueError, match="Model FOO does not have defined deadtimes"):
await adaravis.drv.fetch_deadtime()


async def test_unknown_pixel_format_deadtime(
adaravis: AravisDetector,
):
set_mock_value(adaravis.drv.model, "Manta G-235")
set_mock_value(adaravis.drv.pixel_format, "BAR")

with pytest.raises(
ValueError,
match="Model Manta G-235 does not have a defined deadtime "
"for pixel format BAR",
):
await adaravis.drv.fetch_deadtime()
assert adaravis.controller.get_deadtime(exposure_time) == 1961e-6


async def test_trigger_source_set_to_gpio_line(adaravis: AravisDetector):
Expand Down Expand Up @@ -191,8 +145,6 @@ async def test_can_decribe_collect(adaravis: AravisDetector):


async def test_unsupported_trigger_excepts(adaravis: AravisDetector):
set_mock_value(adaravis.drv.model, "Manta G-125")
set_mock_value(adaravis.drv.pixel_format, "Mono12Packed")
with pytest.raises(
ValueError,
# str(EnumClass.value) handling changed in Python 3.11
Expand Down

0 comments on commit 91e0e6f

Please sign in to comment.