Distributed Bi Directional Flow Electrical Interface - nasa/gunns GitHub Wiki

Table of Contents

Introduction

This page describes the generic bi-directional flow electrical interface provided with the GUNNS repository. This is a generic C++ model to determine the electrical current direction across a bus between two separate power models. This code has no dependencies on GUNNS, Trick, or any other libraries besides ANSI-standard C++. It is intended for use in both GUNNS/Trick and non-GUNNS/Trick simulations and power models.

The code for this interface is in gunns/aspects/electrical/PowerBus/GunnsElectDistributed2WayBus.hh, .cpp, and its base class is in gunns/core/GunnsDistributed2WayBusBase.hh, .cpp. For use in GUNNS models, this interface is wrapped by the GUNNS link GunnsElectDistributedIf. Non-GUNNS models should wrap this in a custom code layer that integrates this into their model and simulation environment.

For each electrical connection between distributed models, a GunnsElectDistributed2WayBus is instantiated in each model, on its side of the interface. The GunnsElectDistributed2WayBus is designed to integrate with another instance of itself, its counterpart in the other model. They communicate with data objects that are transported between them by the distributed simulation data network such as High Level Architecture or Functional Mock-up Interface. The paired GunnsElectDistributed2WayBus negotiate and handshake which side of the interface is supplying voltage and power flow to the other side, based on the available voltage supplies in each local power model. This allows distributed modeling of a power bus that can the change direction of electrical current during runtime. This can also be used to model fixed, single-direction interfaces.

Distributed Models Example

Below we illustrate separate power models for Vehicles A and B in Simulations A and B. The blue <-> symbol denotes the instances of GunnsElectDistributed2WayBus, and we show the flow of data across the distributed data exchange network (in this case, HLA). The models can be chained; in this case there is a Simulation Z with a power model interface to the interface AZ object in Simulation A, and likewise interface BC in Simulation B is interfaced to a Simulation C. Simulations C and Z could also interface, creating a loop. In this example, each vehicle has an internal power supply (such as from batteries or solar arrays) that feed the main bus through its regulator. These regulators can be in various states of readiness to supply power to each interface.

Distributed_Vehicle_Power_Example

Quick Summary of Use

  • Instantiate one of these GunnsElectDistributed2WayBus objects at each location in your power model that needs to supply power to or receive power from an external model.
  • During simulation initialization:
    • call createSupplyData() for every voltage supply in your power model that can supply power to this interface location, including other instances of GunnsElectDistributed2WayBus.
    • call initialize() once.
  • Prior to each power model main step, read this interface's mInData from the mOutData of the other side via the data transfer system.
  • During each power model main step:
    • Each voltage supply (such as the regulators in the above example) should update its GunnsElectDistributed2WayBusSupplyData that describes its ability to supply power to the GunnsElectDistributed2WayBus, as often as is needed to keep them synchronized.
    • call processInputs once,
    • call update one or more times as needed to sync the interface with the local power model state.
    • call isInDemandRole() as needed to get whether the interface is currently in the Supply or Demand role.
    • call getRemoteSupply() to get the voltage supplied by the remote model to the local model, and apply that as a voltage source boundary condition in the local model at this interface location.
    • call getRemoteLoad() to get the constant-power load demanded by the remote model from the local model, and apply that as a power load boundary condition in the local model at this interface location.
  • After each power model main step, write this interface's mOutData to the mInData of the other side via the data transfer system (HLA, etc.).

Interfaces

Local Code Interfaces

This describes the public attributes and methods in GunnsElectDistributed2WayBus that the local power model can use:

  • GunnsElectDistributed2WayBusSupplyData* createSupplyData(): This creates an interface for a voltage supply in the local model to communicate when and how much voltage it can supply to the interface location. The interface instance of GunnsElectDistributed2WayBusSupplyData is constructed, owned, and deleted by the GunnsElectDistributed2WayBus. This method returns the address of the GunnsElectDistributed2WayBusSupplyData, whose attributes the local voltage supply model can set. This should be called once for each voltage supply that could conceivably supply power to and regulate the bus voltage at the interface location. Since this interface also acts as a bus voltage regulation (in Demand mode) this may include other instances of this interface, for chaining strings of these interfaces together (3 or more distributed models, etc.). You may also register zero supplies with this interface - such an interface will never be able to enter Supply mode, and would represent a model that contains no voltage regulation and can only receive power from other models. The members of GunnsElectDistributed2WayBusSupplyData are listed below. Each voltage supply in the model should drive these terms based on its current state:

    • bool mAvailable: The local model should set this true whenever the voltage supply is ready and will regulate the bus voltage at the interface location, should it be needed. This should be false if for any reason the voltage supply cannot supply & regulate the bus voltage at the interface location, such as an open circuit in between, or the regulator is disabled, tripped off, reverse biased, current limiting, etc. Note that when a voltage regulator is current-limiting, this flag should be false.
    • float mMaximumVoltage: in units of volts, this is the maximum voltage that the voltage supply can output, i.e. the ideal regulated voltage under no load. You may or may not choose to model the droop of the regulator's output voltage under load, and the voltage drop across the circuit to this interface location. Regardless of whether those voltage losses are modeled, this value should be the ideal regulated voltage.
  • void initialize(const std::string& name = "", const bool isPrimarySide = false, const float voltage = 0.0): This initializes the interface model. This should be called exactly once during simulation startup, and before any calls to the various update functions. The arguments to this function are described below:

    • isPrimarySide: This determines the initial Supply or Demand role of this side of the interface. The Primary side (true) starts in Supply role, and Secondary (false) starts in Demand role. The roles will switch as needed during run, so this flag is only used to avoid a role switch and start transient on the initial transition to run, if needed.
    • voltage: in units of Volts, this is the initial voltage at the interface location. This helps the Supply side send a valid voltage value on its first data output to the other side, to reduce or avoid the initial run start transient.
  • void processInputs(): This should be called exactly once during each local power model main step, and before any calls to update() during the local power model main step. This function updates the frame counters in the interface data, and measures the amount of round-trip lag in the interface. The round-trip lag measurement is used in update() to optimize the timing of role switches and avoid excess oscillation.

  • void update(const float localVoltage, const float localPowerDemand): This is the main interface logic update function. It should only be called after processInputs() during each local power model main step. It can be called as many times as needed during the local power model main step to ensure that this is updated with the latest & most valid local voltage and power demand. Some power models may run an internal loop within each model main step to iterate on the circuit solution; this could be called with the results of each iteration, and so on. The arguments to this function are detailed below:

    • localVoltage: in units of Volts, this is the actual voltage at the interface location. When the interface is in Supply role, this will be the local power model's solution of the voltage at the interface location, across the circuit from the voltage regulators, accounting for circuit losses, etc. When in Demand role, this argument is ignored by the function.
    • localPowerDemand: in units of Watts, this is actual power demanded by the local power model from the remote model at the interface location when in the Demand role. When in Supply role, this argument is ignored by the function.
  • float getRemoteLoad(): This returns the constant-power load, in Watts, that should be applied at this interface location in the local model. When this interface is in the Supply role, this will be the demanded power value from the other side of the interface. When this interface is in the Demand role, this will be zero.

  • float getRemoteSupply(): This returns the voltage that should be applied at this interface location in the local model. This should always be modeled in the local model as a dioded voltage source, able to flow into the local model, but not out of it. Normally when this interface is in the Demand role, this will be the highest voltage source available to the local model, and will control the local power bus to this voltage and flow current to it. Normally when this interface is in the Supply role, the local model will have at least one higher voltage supply that is controlling the local power bus, and the current through this interface voltage source will be zero. However, should the other local voltage supplies suddenly be disabled, this interface voltage source is available to immediately control the bus voltage, and this will be followed by the interface switching to the Demand role.

The following functions are in the base class, defined in gunns/core/GunnsDistributed2WayBusBase.hh:

  • bool isInDemandRole(): This returns true when the interface is currently in the Demand role, and false when it is in the Supply role.
  • unsigned int popNotification(GunnsDistributed2WayBusNotification& notification): This pops the latest notification off of the interface's internal notifications queue and sets the notification argument equal to it. This returns the number of notifications remaining in the queue, not including the returned notification. The notification itself is an object with the following attributes:
    • NotificationLevel mLevel: This is an enumeration of the severity of the notification: INFO, WARN, ERR, or NONE. Currently the interface only ever outputs INFO notifications on role swaps, and no WARN or ERR notifications, but we have these levels in the code in case they're needed in the future. If there are currently no notifications remaining in the queue, then the notification argument has its mLevel attribute set to NONE.
    • std::string mMessage: This is a string containing the details of the notification. If there are currently no notifications remaining in the queue, then this attribute is set to an empty string, "".
  • void forceDemandRole(): Calling this configures this interface to enter and remain in the Demand role, regardless of any other considerations. This would be useful for a 1-directional power interface that can only flow into this side of the interface.
  • void forceSupplyRole(): Calling this configures this interface to enter and remain in the Supply role, regardless of any other considerations. This would be useful for a 1-directional power interface that can only flow out of this side of the interface.
  • void resetForcedRole(): Calling this resets the forced Demand or Supply states above, and lets this interface follow its normal role decision logic.

Distributed Simulation Interfaces

Each GunnsElectDistributed2WayBus has 2 instances of the GunnsElectDistributed2WayBusInterfaceData class for communicating with its paired counterpart in the other simulation. These are called mOutData, for sending data out to the other side, and mInData, for receiving data from the other side. Each instance's mOutData should be written to the other side's mInData via the data exchange interface (HLA, etc.). The data contents are driven by the GunnsElectDistributed2WayBus, so the user doesn't need to interact with them. We detail the data attributes here for reference:

  • unsigned int mFrameCount: This is an integer that is incremented once per call to processInputs and is used to measure the round-trip lag frames on the data exchange interface.
  • unsigned int mFrameLoopback: This is a reflection of the received mFrameCount back to the other side. Each side measures teh round-trip interface lag by subtracting the received mFrameLoopback from the outgoing value of mFrameCount. The measured lag is used as a lock-out period after role switching, to prevent excessive oscillation in the roles.
  • bool mDemandMode: This is true when the sender is in the Demand role, and false when it is in the Supply role.
  • float mDemandPower: This is the power load, in Watts, demanded by the Demand role from the Supply role.
  • float mSupplyVoltage: This is the voltage supplied from each side to the other side. The Supply role sends the actual model voltage at the interface location to the other side, while the Demand mode sends the highest available voltage supply in its local model. These are used by the models to negotiate and handshake role switching, so that the Supply role is always on the side with the highest available voltage supply.

Assumptions & Limitations

  • The distributed models do not have to update at the same rate. However, conservation of energy is modeled more accurately if both models run at the same rate and use the same numerical integration of electrical current into charge. As an example, GUNNS power models traditionally run at 10 Hz (although this varies by project) and always use backwards-Euler integration.
  • It is assumed that only one side of the distributed interface has an active voltage source at any given time. In other words, the voltage of the distributed power bus is only regulated by one side of the interface at any given time. Which side is regulating can change, and the direction of power flow across the interface along with it, as voltage sources drop in and out of availability on both sides.
  • The transferred voltage and power values are assumed steady-state, and constant over each model step.
  • Only direct current is modeled, and this does not support alternating current.
  • The interface ignores time- and frequency-dependent effects like capacitance, inductance and impedance.
  • TBD (as we learn more from practice)