Tutorial 4 - A metrological datastream

In this tutorial we introduce the new metrologically enabled agents. We initialize an agent, which generates an infinite sine signal. The signal is generated from the built-in class MetrologicalSineGenerator which delivers on each call one timestamp and one value each with associated uncertainties.

The MetrologicalSineGeneratorAgent is based on the new class agentMET4FOF.metrological_agents.MetrologicalAgent. We only adapt the methods init_parameters() and agent_loop(). This we need to hand over an instance of the signal generating class and to generate the actual samples. The rest of the buffering and plotting logic is encapsulated inside the new base classes.

[2]:
# %load tutorial_4_metrological_streams.py
from agentMET4FOF.agents import AgentNetwork
from agentMET4FOF.metrological_agents import MetrologicalAgent, MetrologicalMonitorAgent
from agentMET4FOF.metrological_streams import (
    MetrologicalDataStreamMET4FOF,
    MetrologicalSineGenerator,
)
from agentMET4FOF.utils import Backend


class MetrologicalSineGeneratorAgent(MetrologicalAgent):
    """An agent streaming a sine signal

    Takes samples from an instance of :py:class:`MetrologicalSineGenerator` and pushes
    them sample by sample to connected agents via its output channel.
    """

    # The datatype of the stream will be MetrologicalSineGenerator.
    _stream: MetrologicalDataStreamMET4FOF

    def init_parameters(
        self,
        signal: MetrologicalDataStreamMET4FOF = MetrologicalSineGenerator(),
        **kwargs
    ):
        """Initialize the input data stream

        Parameters
        ----------
        signal : MetrologicalDataStreamMET4FOF
            the underlying signal for the generator
        """
        self._stream = signal
        super().init_parameters()
        self.set_output_data(channel="default", metadata=self._stream.metadata)

    def agent_loop(self):
        """Model the agent's behaviour

        On state *Running* the agent will extract sample by sample the input
        datastream's content and push it into its output buffer.
        """
        if self.current_state == "Running":
            self.set_output_data(channel="default", data=self._stream.next_sample())
            super().agent_loop()


def demonstrate_metrological_stream():

    # start agent network server
    agent_network = AgentNetwork(backend=Backend.MESA)

    # Initialize signal generating class outside of agent framework.
    signal = MetrologicalSineGenerator()

    # Initialize metrologically enabled agent taking name from signal source metadata.
    source_name = signal.metadata.metadata["device_id"]
    source_agent = agent_network.add_agent(
        name=source_name, agentType=MetrologicalSineGeneratorAgent
    )
    source_agent.init_parameters(signal)

    # Initialize metrologically enabled plotting agent.
    monitor_agent = agent_network.add_agent(
        "Metrological plot including measurement uncertainties",
        agentType=MetrologicalMonitorAgent,
        buffer_size=50,
    )

    # Bind agents.
    source_agent.bind_output(monitor_agent)

    # Set all agents states to "Running".
    agent_network.set_running_state()

    # Allow for shutting down the network after execution.
    return agent_network


if __name__ == "__main__":
    demonstrate_metrological_stream()


|------------------------------------------------------------|
|                                                            |
| Your agent network is starting up. Open your browser and   |
| visit the agentMET4FOF dashboard on http://127.0.0.1:8050/ |
|                                                            |
|------------------------------------------------------------|

SET STATE: Running
[2022-02-03 21:09:14.499774] (SineGenerator): INITIALIZED
[2022-02-03 21:09:14.500004] (Metrological plot including measurement uncertainties): INITIALIZED
[2022-02-03 21:09:14.500050] (SineGenerator): Connected output module: Metrological plot including measurement uncertainties|