-
Notifications
You must be signed in to change notification settings - Fork 20
Closed as not planned
Labels
resolution:wontfixThis will not be worked onThis will not be worked ontype:enhancementNew feature or enhancement visitble to usersNew feature or enhancement visitble to users
Milestone
Description
In the following we sketch an implementation of the future SDK data pipeline.
The design is originated from a users perspective, who might ask the question:
"I need to measure power on a certain point of my microgrid".
For now we only sketch the details for Meters. All other Component categories
may have analog though slightly different implementations respecting the hardware specifications
of the individual category.
class MicrogridClient:
"""
... this is the usual mg client, with the following new methods
"""
...
def get_meter(meter_id: int, sample_frequency: float).power -> Receiver[Power]:
"""
This method looks up if a stream of with the parameters (compenent_id, sample_frequency), is existing in
a dictionary and if not creates a new channel and stores it to the clients internal meter dictionary.
Usually raw data streams have timestamps that are not aligned to any equidistant time-grid.
Thus the incoming datastream will be resampled to `sample_frequency` in order
to simplify all following data stream operations. These are addition two datastreams
and scalar multiplication.
"""
...
# the following methods are supposed to be work analog to the previous one
def get_meter(...).current() ...
def get_meter(...).voltage() ...
def get_meter(...).frequency() ...
}
@dataclass
class LogicalMeterFormulas:
"""
Combines all formulas needed to calculate metrics from several physical meters combined
into a virtual meter
"""
current_formula: String
voltage_formula: String
frequency_formula: String
class Meter(ABC):
@property
@abstractmethod
def current(self) -> Receiver[Current]:
pass
@property
@abstractmethod
def voltage(self) -> Receiver[Voltage]:
pass
@property
@abstractmethod
def power(self) -> Receiver[Power]:
pass
class LogicalMeter(Meter): {
"""
The Logical Meter Class represents a Meter in a microgrid
that may or may not have a physical existence.
To calculate an output data stream, a formula has to be provided.
# TODO how do we define a formula? We want to be able to get the data sources purely from the formula!
If the meter is physically represented, this meter is used as the single data source
otherwise it will be calculated according by an user provided formula.
For most cases it's encouraged to use the per-defined formulas by using the get_grid_formula()
or get_load_formula() functions. These functions will in most cases auto-determine the working
formula by utilising the component graph.
It is recommended to use this meter if the user is interested in the grid consumption or location load,
without having prior information if the physical existence. This makes it possible to write reusable code
that can run across different locations, with different hardware setups.
It may also be used to calculate the total sum of meters that are connected to individual battery Racks
to measure the total power of the full battery system.
Usage Example:
```
# example formula string: "(c_id1 + c_id2)"
log_meter = LogicalMeter(micro_grid_client, get_grid_formulas())
lm_power_rx = log_meter.get_power();
```
"""
def __init__(self,
client: MicroGridClient,
formulas: MeterFormulas
):
"""
Initializes a logical meter.
If no meter, inverter or ev_charger instance is provided a new one will be created,
which can be returned by the `get_meters()`, `get_inverters()` or `get_ev_charger()` methods.
Note: No data stream is set up after calling this method.
"""
def get_power(self) -> Receiver<Power>:
"""
This method resamples the input power data streams from all meters
and combines the data streams according to operations defined in the user provided formula
"""
* create a new (tx, rx) pair
* parse the formula string into a formula tree
* get all (resampled) data streams from the micro grid api
that are represented as tokens in the power formula string,
i.e. call `client.get_meter_power(component_id, self.sample_frequency)`
for all component ids
* create a task that
* combines the channels according to the power_formula
and sends the result in the channels Sender
return rx
}Metadata
Metadata
Assignees
Labels
resolution:wontfixThis will not be worked onThis will not be worked ontype:enhancementNew feature or enhancement visitble to usersNew feature or enhancement visitble to users