pntos-api 2.1.0.post0.dev0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,99 @@
1
+ """Python API of pntOS."""
2
+
3
+ from abc import ABC, abstractmethod
4
+
5
+ from pntos.api import CommonPlugin
6
+
7
+
8
+ class ControllerPlugin(CommonPlugin, ABC):
9
+ """
10
+ Controller plugin.
11
+
12
+ An implementation of a primary controller in charge of defining the usage of all other pntOS
13
+ plugins.
14
+
15
+ In ordinary operation, an app will import plugins, initialize a controller plugin, and then
16
+ call :meth:`pntos.api.ControllerPlugin.take_control` on the controller plugin, passing in a list of
17
+ ``plugins`` that it imported.
18
+
19
+ From that point forward, the controller is responsible for all activity. It may
20
+ use any or none of the plugins in the ``plugins`` list as desired. In general, it may do
21
+ anything it wants, within the following guidelines:
22
+
23
+ - The controller should not load new plugins - it should work with the ``plugins`` passed to it
24
+ in the :meth:`take_control` parameters.
25
+
26
+ - The controller must call :meth:`pntos.api.CommonPlugin.init_plugin` on any plugin it wishes to use prior
27
+ to using any other functionality on that plugin. The controller must pass a :class:`pntos.api.Mediator`
28
+ that the plugin may use to communicate back to the controller. This callback design allows the
29
+ controller to abstract away the concurrency model - in particular, a callback function may be
30
+ anything from a direct invocation of a Python function to a shim that utilizes IPC channels to
31
+ communicate to process-separated or machine-separated plugins.
32
+
33
+ Outside of these requirements, the controller defines any and all I/O it supports, which pntOS
34
+ plugins are loaded / used, and the type of fusion being done. The controller can be hard-coded
35
+ to support only a specific sensor configuration or written generically to support arbitrary
36
+ run-time environment sensing. Outside of some initialization in the app, the controller is the
37
+ conceptual "main" function.
38
+
39
+ When the controller is provided a :class:`pntos.api.PlatformIntegrationPlugin` as one of the plugins in
40
+ the ``plugins`` list passed to :meth:`take_control`, that indicates to the controller that
41
+ platform-specific control logic exists and must be used. In this case, the controller's primary
42
+ objective's are to:
43
+
44
+ - Pick the concurrency model being used (multiprocessed, multithreaded, coroutines,
45
+ single-threaded, etc.).
46
+ - Spin up the concurrency primitives to implement the chosen concurrency type.
47
+ - Provide a :class:`pntos.api.Mediator` to all plugins in their :meth:`pntos.api.CommonPlugin.init_plugin` call that
48
+ enables inter-plugin communication.
49
+
50
+ After that task is accomplished, the controller should call the
51
+ :meth:`pntos.api.PlatformIntegrationPlugin.take_control` function and allow the
52
+ :class:`pntos.api.PlatformIntegrationPlugin` (PIP) to actively call functions on the ``plugins`` list.
53
+ Once the :meth:`pntos.api.PlatformIntegrationPlugin.take_control` has been called, the controller must
54
+ lock/synchronize the controller's and the PIP's access to function calls in the ``plugins``
55
+ list, such that any action the PIP might take will not interfere with the controller's actions
56
+ (or, equivalently, actions that the mediator provided by the controller is taking). One simple
57
+ approach to synchronizing access to the plugins list across the controller and PIP is for the
58
+ plugins list provided to the PIP to be a facade that actually routes messages through to the
59
+ mediator, such that the mediator handles all requests and can synchronously dispatch them. More
60
+ efficient approaches exist, however, it is the responsibility of the controller to make sure
61
+ that all accesses the PIP makes to resources passed to it are synchronized with respect to the
62
+ controller's chosen concurrency primitive.
63
+ """
64
+
65
+ @abstractmethod
66
+ def take_control(
67
+ self,
68
+ plugins: list[CommonPlugin],
69
+ plugin_resources_locations: list[str | None] | None = None,
70
+ initial_config: str | None = None,
71
+ ) -> None:
72
+ """
73
+ Takes over primary control of the program from the app.
74
+
75
+ Takes over primary control of the program from the app, using the ``plugins`` to process
76
+ data, generate fused estimates, and ultimately produce and output PNT solutions.
77
+ :meth:`take_control` must use the plugins passed to it and construct a full pntOS system.
78
+ Please see the description of the :class:`pntos.api.PlatformIntegrationPlugin` (PIP) for a description
79
+ of duties of this function compared to the duties of the
80
+ :meth:`pntos.api.PlatformIntegrationPlugin.take_control` method (if a PIP is in the ``plugins`` list).
81
+
82
+ Args:
83
+ plugins (list[CommonPlugin]): An array of plugins available to the controller.
84
+ plugin_resources_locations (list[str | None] | None, optional): A list of strings
85
+ which represent a list of locations, one for each plugin in ``plugins``, where those
86
+ plugins may find auxiliary data if needed. The array can be ``None``,
87
+ otherwise the array is of the same length as ``plugins``. Each string may be
88
+ ``None``, filesystem paths, or adhere to some scheme, such as the URI scheme, for
89
+ defining the resource's location.
90
+ initial_config (str | None, optional): Represents a source of values to initialize the
91
+ primary pntOS configuration. This could be ``None`` or a ``str``. Examples of
92
+ possible values for the latter are:
93
+
94
+ 1. The entire config.
95
+ 2. A local file path on systems which support them.
96
+ 3. A string adhering to the URI scheme.
97
+ """
98
+
99
+ pass
@@ -0,0 +1,572 @@
1
+ """Python API of pntOS."""
2
+
3
+ from abc import ABC, abstractmethod
4
+ from dataclasses import dataclass
5
+ from typing import Any, TypeVar
6
+
7
+ from aspn23 import TypeTimestamp
8
+ from numpy import float64
9
+ from numpy.typing import NDArray
10
+
11
+ from .common import CommonPlugin, EstimateWithCovariance, Message
12
+ from .fusion_strategy import (
13
+ StandardFusionStrategy,
14
+ )
15
+ from .state_modeling import (
16
+ StandardMeasurementProcessor,
17
+ StandardStateBlock,
18
+ VirtualStateBlock,
19
+ )
20
+
21
+
22
+ @dataclass
23
+ class CrossCovariances:
24
+ """
25
+ A container for a set of covariances relating a StateBlock to one or more other StateBlocks.
26
+
27
+ For example, suppose that some StateBlock named ``A`` existed containing ``a`` states. Then this
28
+ structure could define the cross covariance of ``A`` with respect to other StateBlocks named
29
+ ``B`` (with ``b`` states) and ``C`` (with ``c`` states). In that case, :attr:`block_labels`
30
+ would be an array of 2 strings ``B`` and ``C``, and :attr:`cross_covariances` would be an array
31
+ of two matrices: the cross-covariance matrix of ``B`` and ``A``, with shape ``[b, a]`` and the
32
+ cross-covariance matrix of ``C`` and ``A`` with shape ``[c, a]``.
33
+
34
+ Attributes:
35
+ block_labels (list[str]): A list of labels of the :class:`pntos.api.StandardStateBlock` this
36
+ structure contains the cross-covariances for.
37
+ cross_covariances (list[NDArray[float64]]): A list of cross-covariance matrices between a single
38
+ StateBlock and the set of StateBlocks listed in :attr:`block_labels`.
39
+ """
40
+
41
+ block_labels: list[str]
42
+ """The labels of the state blocks that the entries in ``cross_covariances`` relate to.
43
+ """
44
+
45
+ cross_covariances: list[NDArray[float64]]
46
+ """The covariances between the state blocks.
47
+ """
48
+
49
+
50
+ class StandardFusionEngine(ABC):
51
+ """
52
+ An implementation of a fusion engine that supports the standard fusion model.
53
+
54
+ Assumes the system is described by discrete-time matrices and noise inputs are zero-mean white
55
+ Gaussian. In addition, all covariance matrices / mean vectors are descriptions of
56
+ jointly-Gaussian multivariate distributions. All noise sources are jointly-Gaussian distributed.
57
+
58
+ This object requires a :class:`pntos.api.StandardFusionStrategy` to work. Some implementations may be able
59
+ to provide their own. Others will require a strategy to be provided by setting the
60
+ :attr:`StandardFusionEngine.strategy` field. It is possible to check whether a fusion
61
+ engine needs to be provided a fusion strategy by checking the
62
+ :attr:`StandardFusionEngine.strategy` field (if it is ``None`` then this fusion engine
63
+ needs to be provided a strategy). While :attr:`StandardFusionEngine.strategy` is ``None``,
64
+ all other methods are unsafe to be called.
65
+
66
+ Note:
67
+ This class must have an operational ``__deepcopy__`` method. For most classes, the default
68
+ ``__deepcopy__`` method provided by Python will be sufficient. However, if the class has a
69
+ field which does not properly implement its own ``__deepcopy__`` (such as a C object wrapped
70
+ to Python), then the class will need to implement a custom ``__deepcopy__`` which properly
71
+ copies all fields.
72
+
73
+ Caution:
74
+ **Unstable**: This feature is unstable and is not yet considered part of the stable pntOS
75
+ API. Usage of this feature is highly discouraged in non-experimental code, and its
76
+ definition may change at any time.
77
+ """
78
+
79
+ @property
80
+ @abstractmethod
81
+ def time(self) -> TypeTimestamp:
82
+ """
83
+ Get the current time of the filter.
84
+
85
+ Returns:
86
+ TypeTimestamp
87
+ """
88
+ pass
89
+
90
+ @time.setter
91
+ @abstractmethod
92
+ def time(self, time: TypeTimestamp) -> None:
93
+ """Setter for the :meth:`pntos.api.StandardFusionEngine.time` property."""
94
+ pass
95
+
96
+ @property
97
+ @abstractmethod
98
+ def strategy(self) -> StandardFusionStrategy | None:
99
+ """
100
+ The underlying algorithm used for Bayesian inference.
101
+
102
+ Returns:
103
+ StandardFusionStrategy | None: The fusion strategy is the type of filter (EKF, UKF,
104
+ etc.).
105
+ """
106
+ pass
107
+
108
+ @strategy.setter
109
+ @abstractmethod
110
+ def strategy(self, strategy: StandardFusionStrategy) -> None:
111
+ """The setter for the :meth:`strategy` property on :class:`pntos.api.StandardFusionEngine`."""
112
+ pass
113
+
114
+ @property
115
+ @abstractmethod
116
+ def num_states(self) -> int:
117
+ """
118
+ Get the total number of states currently in the fusion engine.
119
+
120
+ Virtual state blocks do not affect this result.
121
+
122
+ Returns:
123
+ int: The total number of states currently in the fusion engine.
124
+ """
125
+ pass
126
+
127
+ @property
128
+ @abstractmethod
129
+ def state_block_labels(self) -> list[str] | None:
130
+ """
131
+ Get a list of :class:`pntos.api.StandardStateBlock` labels that have been added to this fusion engine.
132
+
133
+ Returns:
134
+ list[str] | None: A list of the :class:`pntos.api.StandardStateBlock` labels that have been added
135
+ to this fusion engine. Returns ``None`` if no state blocks have been added. Guaranteed
136
+ to not return ``None`` if :attr:`num_states` is a value other than 0.
137
+ """
138
+ pass
139
+
140
+ @abstractmethod
141
+ def add_state_block(
142
+ self,
143
+ block: StandardStateBlock,
144
+ initial_estimate_covariance: EstimateWithCovariance,
145
+ cross_covariances: CrossCovariances | None = None,
146
+ ) -> None:
147
+ """
148
+ Add the given :class:`pntos.api.StandardStateBlock` to the fusion engine.
149
+
150
+ This will expand the state vector being estimated by the value of :attr:`num_states`.
151
+
152
+ Args:
153
+ block (StandardStateBlock): The :class:`pntos.api.StandardStateBlock` to be added to the fusion
154
+ engine.
155
+ initial_estimate_covariance (EstimateWithCovariance): Contains the initial conditions of
156
+ the states, with ``initial_estimate_covariance.estimate`` being an Nx1 matrix and
157
+ ``initial_estimate_covariance.covariance`` being an NxN matrix, where N is
158
+ ``block.num_states``.
159
+ cross_covariances (CrossCovariances | None, optional): An optional parameter which, if
160
+ non-``None``, contains a description of the newly added StateBlock's cross
161
+ covariances with respect to a set of StateBlocks which already exist inside the
162
+ filter (specified by ``cross_covariances.block_labels``). If the
163
+ ``cross_covariance`` parameter is ``None``, cross covariance between the existing
164
+ states and the added states will be set to zeroes.
165
+ """
166
+ pass
167
+
168
+ @abstractmethod
169
+ def get_state_block_estimate(self, block_label: str) -> NDArray[float64] | None:
170
+ """
171
+ Get the estimate associated with a state block.
172
+
173
+ Find a :class:`pntos.api.StandardStateBlock` or :class:`pntos.api.VirtualStateBlock` within the fusion engine
174
+ matching ``block_label``, and return a copy of its current estimate vector.
175
+
176
+ Args:
177
+ block_label (str)
178
+
179
+ Returns:
180
+ NDArray[float64] | None: A copy of its current estimate vector. If ``block_label`` references a
181
+ virtual state block (VSB) this will return a converted estimate, converted into the VSBs
182
+ coordinate frame. Returns ``None`` if ``block_label`` does not correspond to a block
183
+ that has been added to the fusion engine. Guaranteed to not return ``None`` when
184
+ ``block_label`` is in the list returned by :attr:`state_block_labels` and
185
+ :attr:`strategy` is not ``None``.
186
+ """
187
+ pass
188
+
189
+ @abstractmethod
190
+ def get_state_block_covariance(self, block_label: str) -> NDArray[float64] | None:
191
+ """
192
+ Get the covariance associated with a state block.
193
+
194
+ Find a :class:`pntos.api.StandardStateBlock` or :class:`pntos.api.VirtualStateBlock` within the fusion engine
195
+ matching ``block_label``, and return a copy of its current covariance matrix.
196
+
197
+ Args:
198
+ block_label (str)
199
+
200
+ Returns:
201
+ NDArray[float64] | None: A copy of its current covariance matrix. If ``block_label`` references a
202
+ virtual state block (VSB) this will return a converted covariance, converted into the
203
+ VSBs coordinate frame. Returns ``None`` if ``block_label`` does not correspond to a
204
+ block that has been added to the fusion engine. Guaranteed to not return ``None`` when
205
+ ``block_label`` is in the list returned by :attr:`state_block_labels` and
206
+ :attr:`strategy` is not ``None``.
207
+ """
208
+ pass
209
+
210
+ @abstractmethod
211
+ def get_state_block_cross_covariance(
212
+ self, block_label1: str, block_label2: str
213
+ ) -> NDArray[float64] | None:
214
+ """
215
+ Get the cross covariance between the states associated with two state blocks.
216
+
217
+ Find the :class:`pntos.api.StandardStateBlock` s within the fusion engine matching ``block_label1``
218
+ and ``block_label2``, and return the cross-covariance matrix between them.
219
+
220
+ Args:
221
+ block_label1 (str)
222
+ block_label2 (str)
223
+
224
+ Returns:
225
+ NDArray[float64] | None: The cross-covariance matrix between ``block_label1`` and
226
+ ``block_label2``. Returns ``None`` if ``block_label1`` or ``block_label2`` do not
227
+ correspond to blocks that have been added to the fusion engine. Guaranteed to not return
228
+ ``None`` when both ``block_label1`` and ``block_label2`` are in the list returned by
229
+ :attr:`state_block_labels` and :attr:`strategy` is not ``None``.
230
+ """
231
+ pass
232
+
233
+ @abstractmethod
234
+ def set_state_block_estimate(
235
+ self, block_label: str, estimate: NDArray[float64]
236
+ ) -> None:
237
+ """
238
+ Update the estimate associated with a given state block.
239
+
240
+ Find a :class:`pntos.api.StandardStateBlock` within the fusion engine matching ``block_label``, and
241
+ change its current estimate vector.
242
+
243
+ Note:
244
+ This function may lead to performance degradation with some implementations and thus its
245
+ use is discouraged if other options are available.
246
+
247
+ Args:
248
+ block_label (str)
249
+ estimate (NDArray[float64])
250
+ """
251
+ pass
252
+
253
+ @abstractmethod
254
+ def set_state_block_covariance(
255
+ self, block_label: str, covariance: NDArray[float64]
256
+ ) -> None:
257
+ """
258
+ Update the covariance associated with a given state block.
259
+
260
+ Find a :class:`pntos.api.StandardStateBlock` within the fusion engine matching ``block_label``, and
261
+ change its current covariance matrix.
262
+
263
+ Note:
264
+ This function may lead to performance degradation with some implementations and thus its
265
+ use is discouraged if other options are available.
266
+
267
+ Args:
268
+ block_label (str)
269
+ covariance (NDArray[float64])
270
+ """
271
+ pass
272
+
273
+ @abstractmethod
274
+ def set_state_block_cross_covariance(
275
+ self, block_label1: str, block_label2: str, covariance: NDArray[float64]
276
+ ) -> None:
277
+ """
278
+ Update the covariance between two state blocks.
279
+
280
+ Find the :class:`pntos.api.StandardStateBlock` s within the fusion engine matching ``block_label1``
281
+ and ``block_label2``, and change the current covariance matrix between them.
282
+
283
+ Note:
284
+ This function may lead to performance degradation with some implementations and thus its
285
+ use is discouraged if other options are available.
286
+
287
+ Args:
288
+ block_label1 (str)
289
+ block_label2 (str)
290
+ covariance (NDArray[float64])
291
+ """
292
+ pass
293
+
294
+ @abstractmethod
295
+ def remove_state_block(self, block_label: str) -> None:
296
+ """
297
+ Remove the :class:`pntos.api.StandardStateBlock` matching ``block_label``.
298
+
299
+ This will reduce the state vector being estimated by the number of states that the block
300
+ represents.
301
+
302
+ Args:
303
+ block_label (str)
304
+ """
305
+ pass
306
+
307
+ @property
308
+ @abstractmethod
309
+ def virtual_state_block_target_labels(self) -> list[str] | None:
310
+ """
311
+ Gets a list of the target labels of virtual state blocks that have been added.
312
+
313
+ A label being returned by this list is not a guarantee that the virtual state block has a
314
+ valid source. For that, call :meth:`has_virtual_state_block`.
315
+
316
+ Returns:
317
+ list[str] | None: A list of the target labels of virtual state blocks that have been
318
+ added. Returns ``None`` if no virtual state blocks have been added to this fusion
319
+ engine.
320
+ """
321
+ pass
322
+
323
+ @abstractmethod
324
+ def has_virtual_state_block(self, vsb_target_label: str) -> bool:
325
+ """
326
+ Checks if the fusion engine has a :class:`pntos.api.VirtualStateBlock` with a matching target label.
327
+
328
+ Args:
329
+ vsb_target_label (str)
330
+
331
+ Returns:
332
+ bool: ``True`` if the fusion engine has a :class:`pntos.api.VirtualStateBlock` with a matching
333
+ target label, ``False`` if no virtual state block with matching target label exists or
334
+ if one exists but is not capable of generating an estimate. That is, the VSB's source
335
+ must exist and be in a continuous chain to a concrete state block which also exists in
336
+ the fusion engine in order to return ``True``.
337
+ """
338
+ pass
339
+
340
+ @abstractmethod
341
+ def add_virtual_state_block(self, virtual_state_block: VirtualStateBlock) -> None:
342
+ """
343
+ Add the given :class:`pntos.api.VirtualStateBlock` to the fusion engine.
344
+
345
+ A virtual state block (VSB) convert from an underlying block coordinate frame into the VSB
346
+ coordinate frame.
347
+
348
+ Args:
349
+ virtual_state_block (VirtualStateBlock)
350
+ """
351
+ pass
352
+
353
+ @abstractmethod
354
+ def remove_virtual_state_block(self, vsb_target_label: str) -> None:
355
+ """
356
+ Remove the :class:`pntos.api.VirtualStateBlock` matching ``vsb_target_label``.
357
+
358
+ Args:
359
+ vsb_target_label (str)
360
+ """
361
+ pass
362
+
363
+ @property
364
+ @abstractmethod
365
+ def measurement_processor_labels(self) -> list[str] | None:
366
+ """
367
+ Get a list of the labels of measurement processors that have been added.
368
+
369
+ Returns:
370
+ list[str] | None: list of labels of measurement processors that have been added. Returns
371
+ ``None`` if no measurement processors have been added to this fusion engine.
372
+ """
373
+ pass
374
+
375
+ @abstractmethod
376
+ def add_measurement_processor(
377
+ self, processor: StandardMeasurementProcessor
378
+ ) -> None:
379
+ """
380
+ Add a :class:`pntos.api.StandardMeasurementProcessor`.
381
+
382
+ This can be used to process future measurements that correspond to ``processor.label``.
383
+
384
+ Args:
385
+ processor (StandardMeasurementProcessor)
386
+ """
387
+ pass
388
+
389
+ @abstractmethod
390
+ def remove_measurement_processor(self, processor_label: str) -> None:
391
+ """
392
+ Remove a :class:`pntos.api.StandardMeasurementProcessor` previously added to the fusion engine.
393
+
394
+ Assumes a measurement processor was previously added via :meth:`add_measurement_processor`
395
+ with the label ``processor_label``.
396
+
397
+ Args:
398
+ processor_label (str)
399
+ """
400
+ pass
401
+
402
+ @abstractmethod
403
+ def propagate(self, time: TypeTimestamp) -> None:
404
+ """
405
+ Propagate the filter estimate forward in time.
406
+
407
+ May be evaluated lazily (when results are requested).
408
+
409
+ Args:
410
+ time (TypeTimestamp)
411
+ """
412
+ pass
413
+
414
+ @abstractmethod
415
+ def update(self, processor_label: str, message: Message) -> None:
416
+ """
417
+ Update the filter with the given measurement.
418
+
419
+ Will propagate first if needed to reach the time encoded inside the measurement.
420
+
421
+ Args:
422
+ processor_label (str)
423
+ message (Message)
424
+ """
425
+ pass
426
+
427
+ @abstractmethod
428
+ def peek_ahead(
429
+ self, time: TypeTimestamp, block_labels: list[str]
430
+ ) -> EstimateWithCovariance | None:
431
+ """
432
+ Calculates the estimate and covariance at a requested time.
433
+
434
+ Uses the state blocks listed in ``block_labels``, without changing the state of the fusion
435
+ engine or its underlying filter. Blocks are assembled in the order that the labels are
436
+ passed in.
437
+
438
+ If all of the following are true:
439
+
440
+ - ``time`` is equal to or after the filter time (which can be checked with :attr:`time`).
441
+ - All labels in ``block_labels`` correspond to a block that has been added to the fusion
442
+ engine (which can be checked with :attr:`state_block_labels`).
443
+ - ``block_labels`` has at least one element.
444
+
445
+ Then the result returned is guaranteed to not be ``None``. Otherwise, if any of the above
446
+ are false then the result will be ``None``.
447
+
448
+ Args:
449
+ time (TypeTimestamp)
450
+ block_labels (list[str]): An array of strings.
451
+
452
+ Returns:
453
+ EstimateWithCovariance | None
454
+ """
455
+ pass
456
+
457
+ @abstractmethod
458
+ def generate_x_and_p(
459
+ self, block_labels: list[str]
460
+ ) -> EstimateWithCovariance | None:
461
+ """
462
+ Generates the current estimate and covariance.
463
+
464
+ Estimate and covariance are built corresponding to a list of StateBlock labels. Blocks are
465
+ assembled in the order that the labels are passed in.
466
+
467
+ If all of the following are true:
468
+
469
+ - All labels in ``block_labels`` correspond to a block that has been added to the fusion
470
+ engine (which can be checked with :attr:`state_block_labels`).
471
+ - ``block_labels`` has at least one element.
472
+
473
+ Then the result returned is guaranteed to not be ``None``. Otherwise, if any of the above
474
+ are false then the result will be ``None``.
475
+
476
+ Args:
477
+ block_labels (list[str]): An array of strings.
478
+
479
+ Returns:
480
+ EstimateWithCovariance | None
481
+ """
482
+ pass
483
+
484
+ @abstractmethod
485
+ def give_state_block_aux_data(
486
+ self, block_label: str, aux: list[Message | None]
487
+ ) -> None:
488
+ """
489
+ Route a list of messages of aux data to a :class:`pntos.api.StandardStateBlock`.
490
+
491
+ Args:
492
+ block_label (str)
493
+ aux (list[Message | None])
494
+ """
495
+ pass
496
+
497
+ @abstractmethod
498
+ def give_measurement_processor_aux_data(
499
+ self, processor_label: str, aux: list[Message | None]
500
+ ) -> None:
501
+ """
502
+ Route a list of messages of aux data to a :class:`pntos.api.StandardMeasurementProcessor`.
503
+
504
+ Args:
505
+ processor_label (str)
506
+ aux (list[Message | None])
507
+ """
508
+ pass
509
+
510
+ @abstractmethod
511
+ def give_virtual_state_block_aux_data(
512
+ self, target_label: str, aux: list[Message | None]
513
+ ) -> None:
514
+ """
515
+ Route a list of messages of aux data to a :class:`pntos.api.VirtualStateBlock`.
516
+
517
+ Args:
518
+ target_label (str)
519
+ aux (list[Message | None])
520
+ """
521
+ pass
522
+
523
+
524
+ FusionEngineType = TypeVar('FusionEngineType', StandardFusionEngine, Any)
525
+ """Enumerates the types of fusion engines.
526
+
527
+ Currently only StandardFusionEngine is defined, but this TypeVar also includes "Any" in the type
528
+ list for future compatibility.
529
+ """
530
+
531
+
532
+ class FusionPlugin(CommonPlugin, ABC):
533
+ """
534
+ Plugin that provides a fusion engine.
535
+
536
+ A fusion engine allows data from multiple sensors to be integrated into a unified state
537
+ estimate.
538
+ """
539
+
540
+ @abstractmethod
541
+ def is_fusion_type_supported(self, fusion_type: type[FusionEngineType]) -> bool:
542
+ """
543
+ Check if the plugin supports a given type of fusion.
544
+
545
+ Args:
546
+ fusion_type (type[FusionEngineType])
547
+
548
+ Returns:
549
+ bool
550
+ """
551
+ pass
552
+
553
+ @abstractmethod
554
+ def new_fusion_engine(
555
+ self, fusion_type: type[FusionEngineType]
556
+ ) -> FusionEngineType | None:
557
+ """
558
+ Create a fusion engine.
559
+
560
+ Args:
561
+ fusion_type (type[FusionEngineType]): This parameter specifies the type of fusion engine that
562
+ will be returned.
563
+
564
+ Returns:
565
+ FusionEngineType | None: The ``fusion_type`` parameter specifies the type of fusion engine
566
+ that will be returned. For example, if the user passes in :class:`pntos.api.StandardFusionEngine`,
567
+ then an implementation of :class:`pntos.api.StandardFusionEngine` will be returned. Returns
568
+ ``None`` if ``fusion_type`` is not supported by this fusion plugin
569
+ (:meth:`is_fusion_type_supported` can be used to check the type before calling this
570
+ method). Otherwise the return is guaranteed to not be ``None``.
571
+ """
572
+ pass