API
 
Loading...
Searching...
No Matches
__init__.py
Go to the documentation of this file.
1import logging
2import numpy as np
3
4import ImageStreamIOWrap
5import xconf
6
7from purepyindi2 import device, properties, constants
8from purepyindi2.messages import DefNumber, DefSwitch, DefText
9from magaox.indi.device import XDevice, BaseConfig
10from magaox.shmim import Image
11
12def create_if_not_exist_shmim(name, shape, dtype=np.float32):
13 """Create or verify a shared memory image (shmim) with the specified parameters.
14
15 Creates a new shared memory image if it does not exist, or verifies that an existing
16 image has the correct shape and data type. If an existing image has incompatible
17 parameters, it is destroyed and recreated.
18
19 Args:
20 name (str): The name of the shared memory image to create or access.
21 shape (tuple): The desired shape of the array as (height, width).
22 dtype (type, optional): The numpy data type for the array.
23 Defaults to np.float32 (FLOAT). Can also be np.float64 (DOUBLE).
24
25 Returns:
26 None
27
28 Note:
29 This function closes the connection to the shmim after creation/verification.
30 Other processes can open the shmim by its name independently.
31 """
32 img = ImageStreamIOWrap.Image()
33
34 # Check if the shmim exists
35 if img.open(name) == 40:
36 img.create(name, np.zeros(shape, dtype=dtype))
37 else:
38 # the shmim opened successfully, check if it has the right shape and dtype, if not destroy and recreate
39 if not (img.md.size[0] == shape[0] and img.md.size[1] == shape[1] and img.md.datatype == (ImageStreamIOWrap.ImageStreamIODataType.FLOAT if dtype == np.float32 else ImageStreamIOWrap.ImageStreamIODataType.DOUBLE)):
40 img.destroy()
41 img.create(name, np.zeros(shape, dtype=dtype))
42
43 # Close the connection to the shmim.
44 img.close()
45
46@xconf.config
47class aoSimConfig(BaseConfig):
48 """Configuration for the aoSim application.
49 """
50 num_modes : int = xconf.field(default=2, help="Number of modes to simulate in the AO system.")
51 lag : int = xconf.field(default=1, help="Lag in timesteps for DM command updates.")
52 noise : float = xconf.field(default=0.0, help="Amplitude of noise to add to the wavefront sensor measurements.")
53 frequency : float = xconf.field(default=0.5, help="Frequency in Hz at which the AO simulation loop runs.")
54
55class aoSim(XDevice):
56 """Adaptive Optics System Simulator.
57
58 The aoSim application provides a simulated modal AO system for testing and development.
59 """
60 config : aoSimConfig
61
62 def setup(self):
63 """Initialize the AO simulator application.
64
65 Sets up shared memory images for DM, WFS, and disturbance, initializes
66 simulation state variables, and configures the control loop parameters.
67 """
68
69 self._nmodes = self.config.num_modes
70
71 create_if_not_exist_shmim('aoSim_dm', [self._nmodes, 1], dtype=np.float32)
72 self._dm = Image('aoSim_dm')
73
74 create_if_not_exist_shmim('aoSim_wfs', [self._nmodes, 1], dtype=np.float32)
75 self._wfs = Image('aoSim_wfs')
76
77 create_if_not_exist_shmim('aoSim_disturbance', [self._nmodes, 1], dtype=np.float32)
78 self._disturbance = Image('aoSim_disturbance')
79
80 self._t = np.array([0], dtype=np.float32)
81 self._dt = np.array([0.01], dtype=np.float32)
82 self._current_disturbance = np.zeros((self._nmodes, 1), dtype=np.float32)
83 self._current_dm_state = np.zeros((self._nmodes, 1), dtype=np.float32)
84
85 self._lag = self.config.lag
86 self._dm_command_history = np.zeros((self._lag + 1, self._nmodes, 1), dtype=np.float32)
87
88 self._noise = self.config.noise
89 self._frequency = self.config.frequency
90 # Update the dm first so that the current shape in the shared memory is correct
91 # before the first WFS update, which relies on the current DM state.
92 self.update_dm()
93
94 sv = properties.SwitchVector(
95 name='reset',
96 rule=constants.SwitchRule.ONE_OF_MANY,
97 perm=constants.PropertyPerm.READ_WRITE,
98 )
99 sv.add_element(DefSwitch(name="toggle", _value=constants.SwitchState.OFF))
100 self.add_property(sv, callback=self.handle_reset)
101
102 self.log.info(f'aoSim app is fully setup.')
103
104 def handle_reset(self, existing_property, new_message):
105 if 'toggle' in new_message and new_message['toggle'] == constants.SwitchState.ON:
106 self._t = np.array([0], dtype=np.float32)
107
108 self._current_disturbance = np.zeros((self._nmodes, 1), dtype=np.float32)
109 self._current_dm_state = np.zeros((self._nmodes, 1), dtype=np.float32)
110 self._dm_command_history = np.zeros((self._lag + 1, self._nmodes, 1), dtype=np.float32)
111
112 self._wfs.write(np.zeros((self._nmodes, 1), dtype=np.float32))
113 self._disturbance.write(np.zeros((self._nmodes, 1), dtype=np.float32))
114 self._dm.write(np.zeros((self._nmodes, 1), dtype=np.float32))
115
116 self.update_dm()
117
118 existing_property['toggle'] = constants.SwitchState.OFF
119 self.update_property(existing_property)
120 self.log.info('AO simulation state has been reset.')
121
122 def update_dm(self):
123 """Update the deformable mirror state from its command history.
124 """
126 self._dm_command_history = np.roll(self._dm_command_history, shift=-1, axis=0)
127 self._dm_command_history[-1] = self._dm.get_data(wait=False)
128
129 def update_wfs(self):
130 """Update the wavefront sensor measurement in shared memory.
131 """
133 self.err += self._noise * np.random.randn(self._nmodes, 1).astype(np.float32)
134 self._wfs.write(self.err)
135
137 """Update the atmospheric/system disturbance for this timestep.
138 """
139 self._current_disturbance = 0.1 * np.sin(2 * np.pi * self._frequency * self._t) * np.ones((self._nmodes, 1), dtype=np.float32)
140 self._disturbance.write(self._current_disturbance)
141
142 def loop(self):
143 """Execute one iteration of the AO simulation loop.
144 """
145 self.update_dm()
146 self.update_disturbance()
147 self.update_wfs()
148
149 print('t={:.2f}, disturbance={:.3f}, dm_state={:.3f}, wfs={:.3f}'.format(self._t[0], self._current_disturbance[0,0], self._current_dm_state[0,0], self.err[0,0]))
150 self._t += self._dt
151
152main = aoSim.console_app
update_disturbance(self)
Definition __init__.py:136
handle_reset(self, existing_property, new_message)
Definition __init__.py:104
aoSimConfig config
Definition __init__.py:60
create_if_not_exist_shmim(name, shape, dtype=np.float32)
Definition __init__.py:12