Source code for panoptes.pocs.camera.simulator.ccd
import math
import random
import time
from abc import ABC
from contextlib import suppress
import astropy.units as u
from panoptes.pocs.camera.simulator.dslr import Camera as SimCamera
from panoptes.pocs.camera.sdk import AbstractSDKDriver, AbstractSDKCamera
from panoptes.utils.config.client import get_config
[docs]
class SDKDriver(AbstractSDKDriver):
def __init__(self, library_path=None, **kwargs):
# Get library loader to load libc, which should usually be present...
super().__init__(name='c', library_path=library_path, **kwargs)
[docs]
def get_SDK_version(self):
return "Simulated SDK Driver v0.001"
[docs]
def get_devices(self):
self.logger.debug(f'Getting camera device connection config for {self}')
camera_devices = dict()
for cam_info in get_config('cameras.devices'):
name = cam_info.get('name') or cam_info.get('model')
port = cam_info.get('port') or cam_info.get('serial_number')
camera_devices[name] = port
self.logger.trace(f'camera_devices={camera_devices!r}')
return camera_devices
[docs]
class Camera(AbstractSDKCamera, SimCamera, ABC):
def __init__(self,
name='Simulated SDK camera',
driver=SDKDriver,
target_temperature=0 * u.Celsius,
*args, **kwargs):
kwargs.update({'target_temperature': target_temperature})
super().__init__(name, driver, *args, **kwargs)
@AbstractSDKCamera.cooling_enabled.getter
def cooling_enabled(self):
return self._cooling_enabled
@AbstractSDKCamera.target_temperature.getter
def target_temperature(self):
return self._target_temperature
@property
def temperature(self):
now = time.monotonic()
delta_time = (now - self._last_time) / self._time_constant
if self.cooling_enabled:
limit_temp = max(self.target_temperature, self._min_temp)
else:
limit_temp = self._max_temp
delta_temp = limit_temp - self._last_temp
temperature = limit_temp - delta_temp * math.exp(-delta_time)
add_temp = random.uniform(-self._temp_var / 2, self._temp_var / 2)
temperature += random.uniform(-self._temp_var / 2, self._temp_var / 2)
self.logger.trace(f"Temp adding {add_temp:.02f} \t Total: {temperature:.02f} for {self}")
return temperature
@property
def cooling_power(self):
if self.cooling_enabled:
return 100.0 * float((self._max_temp - self.temperature) /
(self._max_temp - self._min_temp)) * u.percent
else:
return 0.0 * u.percent
[docs]
def connect(self):
self._is_cooled_camera = True
self._cooling_enabled = False
self._temperature = 5 * u.Celsius
self._max_temp = 25 * u.Celsius
self._min_temp = -15 * u.Celsius
self._temp_var = 0.05 * u.Celsius
self._time_constant = 0.25
self._last_temp = 25 * u.Celsius
self._last_time = time.monotonic()
self._connected = True
def _set_target_temperature(self, target):
# Upon init the camera won't have an existing temperature.
with suppress(AttributeError):
self._last_temp = self.temperature
self._last_time = time.monotonic()
if not isinstance(target, u.Quantity):
target = target * u.Celsius
self._target_temperature = target.to(u.Celsius)
def _set_cooling_enabled(self, enable):
self._last_temp = self.temperature
self._last_time = time.monotonic()
self._cooling_enabled = bool(enable)