Add a Custom Output System#

This example demonstrates how to build and register a new output system in MyoGestic.

By creating a subclass of the generic Output System Template, you can channel model predictions into any destination you like—such as a virtual environment or hardware device.

We Recommend Implementing any Additions in user_config.py

The user_config.py module is specifically designed for end-users to register and configure their own custom components such as models, features, and filters. This keeps your modifications modular, reduces conflicts with core MyoGestic settings, and simplifies upgrades in the future.

Important

By registering your addition in user_config.py, you ensure that your custom configuration stays separate from core MyoGestic functionality and remains compatible with future updates.

Example Overview#

  1. Create a custom output system class by inheriting from OutputSystemTemplate.

  2. Implement the required methods for processing and sending predictions.

  3. Register the output system into CONFIG_REGISTRY.

  4. (Optional) Test your new output system by selecting it in your MyoGestic workflow.

Notes on Implementation#

The class design follows the interface defined by Output System Template, requiring:

  • A constructor that takes in the main_window (as all QObject do) and a boolean flag for classification vs. regression.

  • Definitions for:

    • _process_prediction__classification(prediction: Any) -> Any

    • _process_prediction__regression(prediction: Any) -> Any

    • send_prediction(prediction: Any) -> None

    • closeEvent(event) -> None

Below, we provide a simplified demonstration that mirrors how you might adapt a neural rehabilitation device interface or a virtual hand interface. For further examples of fully featured implementations, see references in MyoGestic’s existing output systems.

Step 1: Define Your Custom Output System#

from typing import Any
from myogestic.gui.widgets.templates.output_system import OutputSystemTemplate


class MyCustomOutputSystem(OutputSystemTemplate):
    """
    A simple example output system for demonstration purposes.

    This class shows how to inherit from OutputSystemTemplate and implement
    the required abstract methods. It can send predictions to any desired
    interface or hardware, provided you adapt the methods below.
    """

    def __init__(self, main_window, prediction_is_classification: bool) -> None:
        """
        Initialize the custom output system.

        Parameters
        ----------
        main_window : Any
            The main window object containing a logger or other references.
        prediction_is_classification : bool
            Set to True for classification tasks, False for regression.
        """
        super().__init__(main_window, prediction_is_classification)
        # (Optional) Initialize sockets, signals, or other resources here

    def _process_prediction__classification(self, prediction: Any) -> Any:
        """
        Convert a classification prediction into a format suitable
        for your output system or interface.
        """
        # Replace with your own logic or mappings
        return f"Classification: {prediction}".encode("utf-8")

    def _process_prediction__regression(self, prediction: Any) -> Any:
        """
        Convert a regression prediction into a format suitable
        for your output system or interface.
        """
        # Replace with your own logic or mappings
        return f"Regression: {prediction}".encode("utf-8")

    def send_prediction(self, prediction: Any) -> None:
        """
        Send the processed prediction to your output destination.
        """
        processed = self.process_prediction(prediction)
        # For demonstration, we simply print the processed data
        self._main_window.logger.print(
            f"Sending: {processed}",
        )

    def close_event(self, event) -> None:
        """
        Handle any cleanup needed when your system closes.
        """
        # Close sockets, timers, or other resources here
        pass

Step 2: Register the Output System in CONFIG_REGISTRY#

from myogestic.utils.config import CONFIG_REGISTRY

CONFIG_REGISTRY.register_output_system(
    name="MyCustomOutputSystem", output_system=MyCustomOutputSystem
)

Example: Virtual Hand Interface#

 1from typing import Any
 2
 3from myogestic.gui.widgets.logger import LoggerLevel
 4from myogestic.gui.widgets.templates.output_system import OutputSystemTemplate
 5from myogestic.gui.widgets.visual_interfaces.virtual_hand_interface.setup_interface import (
 6    VirtualHandInterface_SetupInterface,
 7)
 8
 9PREDICTION2INTERFACE_MAP = {
10    -1: "Rejected Sample",
11    0: "[0, 0, 0, 0, 0, 0, 0, 0, 0]",
12    1: "[0, 0, 1, 0, 0, 0, 0, 0, 0]",
13    2: "[1, 0, 0, 0, 0, 0, 0, 0, 0]",
14    3: "[0, 0, 0, 1, 0, 0, 0, 0, 0]",
15    4: "[0, 0, 0, 0, 1, 0, 0, 0, 0]",
16    5: "[0, 0, 0, 0, 0, 1, 0, 0, 0]",
17    6: "[0.67, 1, 1, 1, 1, 1, 0, 0, 0]",
18    7: "[0.45, 1, 0.6, 0, 0, 0, 0, 0, 0]",
19    8: "[0.55, 1, 0.65, 0.65, 0, 0, 0, 0, 0]",
20}
21
22
23class VirtualHandInterface_OutputSystem(OutputSystemTemplate):
24    """Output system for the Virtual Hand Interface.
25
26    Parameters
27    ----------
28    main_window : MainWindow
29        The main window object.
30    prediction_is_classification : bool
31        Whether the prediction is a classification or regression.
32    """
33
34    def __init__(self, main_window, prediction_is_classification: bool) -> None:
35        super().__init__(main_window, prediction_is_classification)
36
37        if self._main_window.selected_visual_interface is None:
38            self._main_window.logger.print(
39                "No visual interface selected.", level=LoggerLevel.ERROR
40            )
41            raise ValueError("No visual interface selected.")
42
43        if not isinstance(
44            self._main_window.selected_visual_interface.setup_interface_ui,
45            VirtualHandInterface_SetupInterface,
46        ):
47            raise ValueError(
48                "The virtual interface must be the Virtual Hand Interface."
49                f"Got {type(self._main_window.selected_visual_interface)}."
50            )
51
52        self._outgoing_message_signal = (
53            self._main_window.selected_visual_interface.outgoing_message_signal
54        )
55
56    def _process_prediction__classification(self, prediction: Any) -> bytes:
57        """Process the prediction for classification."""
58        return PREDICTION2INTERFACE_MAP[prediction].encode("utf-8")
59
60    def _process_prediction__regression(self, prediction: Any) -> bytes:
61        """Process the prediction for regression."""
62        return str(prediction).encode("utf-8")
63
64    def send_prediction(self, prediction: Any) -> None:
65        """Send the prediction to the visual interface."""
66        self._outgoing_message_signal.emit(self.process_prediction(prediction))
67
68    def close_event(self, event):
69        """Close the output system."""
70        pass

Total running time of the script: (0 minutes 0.368 seconds)

Estimated memory usage: 528 MB

Gallery generated by Sphinx-Gallery