Skip to content

My First HSF Project Add a Dependency

Eric Mehiel edited this page Jan 3, 2024 · 20 revisions

A simple system with two Subsystems, a constraint, and now a dependency

Now that we have one subsystem with a constraint modeled in our scenario, we can turn to another important concept within the Horizon Simulation Framework Modeling Paradigm (HSF-MP), Dependencies. Recall from the tutorial on adding constraints we covered the HSF-MP fundamental concept of modularity to avoid model creep. Dependencies are a key concept to help the user avoid this toxic error when folks start modeling a system. Simply put, deciding where one subsystem model ends and where another subsystem model begins is difficult because sometimes those boundaries seem arbitrary or are not well defined in our code. But often, using a more disciplined systems engineering perspective, the subsystems have physical or electrical boundaries and have natural ways of being decomposed or compartmentalized. A common mistake is to combine different aspects of different subsystems into one subsystem. This is what we mean by model creep.

Subsystem interfaces

In our example, we can break things down using a Concept of Operations (or ConOps) approach. In this appraoch, we simply step through how the subsystems respond to an event. In our case, the camera subsystem is going to take pictures. Those pictures are then going to be stored in memory somewhere before being downlinked to the ground. It seems easy enough to define a memory state variable within the camera subsystem and then track when pictures are added to memory and then removed from memory when they are downlinked, right? But now, the camera subsystem model is actually modeling three distinct subsystems typical of a spacecraft; camera, data recorder, communications system. From a systems engineering perspective, we would never design all three systems simultaneously as one set of requirements. It would be better, and more disciplined, to design each subsystem independently and to define the interface between the subsystems. We would derive subsystem requirements based on flowing system level requirements through the subsystems and interfaces. This is where dependencies come in.

Dependencies Defined

In the HSF-MP, a Dependency is defined as:

A relationship between two subsystems. The purpose of the dependency is to allow subsystems to relay necessary information without requiring them to know the inner workings of each other. This allows the subsystems to be truly modular be limiting communication through a pre-specified interface. A dependency function is the relay of information from one subsystem to another. A dependency collector is a function that calls all dependency functions for specific subsystem and combines the data in a customizable way. It should be noted that there can be no circular dependencies in the model.

In the HSF-MP, Dependencies serve two purposes, they connect subsystems via an interface to decrease subsystem model creep. In this manner, Dependencies tell the HSF main algorithm the order to call the model subsystems so that data from any one subsystem is generated before it is may be needed by another. In this way, Dependencies also act like interfaces that can translate the state of one subsystem into information that is used by the dependent subsystem to determine its own state.

ADD A PICTURE OF DEPENDENT SUBSYSTEMS WITH SOME DESCRIPTION

  • use a 5-subsystem model in two assets
  • be sure to talk about how dependencies are between subsystems, not assets. Assets are a collection of subsystems with a dynamic state.
  • put together a glossary with links to reference definitions.

Compact models

Within the HSF-MP, a dependency is very similar to a subsystem interface. In our example, the camera generates an image file, the files is then stored on the data recorder. The camera doesn't care about how the image is stored or the other internal workings of the data recorder, and the data recorder really doesn't care where the image file came from. Be separating these subsystems, we can let each subsystem do what it knows how to do. In the HSF-MP, this concept is know as model compactness. Each model should be as compact and self-contained as possible. Compact models are easier to manage, reuse, and define. Designing compact models can be difficult and exactly where I draw my model boundary could be different then where you draw yours, but in either case, the line should be defensible and based on sound system engineering principles.

Dependencies as translators

Another way we think of dependencies within the HSF-MP is as a translator. The dependencies tell one subsystem how to translate the state of another subsystem into information it needs. As such, HSF dependencies are functional in nature and can be written in python. In the case of the camera and the data recorder, the camera model determines if an image was taken, the data recorder needs to know how large the file is and when the image was taken. The dependency between the two subsystems converts the image into the number of bits (and other relevant information) to store in the file on the data recorder. In this example, the dependency function translates what the camera taking an image means for the information stored on the data recorder.

Add a Dependency to the simulation

As with all scripting in HSF, the dependency function needs to be identified in the HSF XML Model file and the location of the Python script needs to be given. First, let's create a new simulation file and add an additional subsystem. Copy myFirstHSFSystemConstrain.xml and rename it myFirstHSFSystemDependency.xml. Now, add a new subsystem called dataBuffer as such:

Add a Data Buffer subsystem

<SUBSYSTEM
  subsystemName = "dataBuffer"
  type = "scripted"
  src = ..\..\..\..\samples\myFirstHSFProjectDependency\DataBuffer.py"
  className = "DataBuffer">
  <PARAMETER name ="bufferSize" type="double" value="500"/>
  <STATE type="double" name="DataBufferRatio" key="dataBufferFillRatio" value="0.0"/>
</SUBSYSTEM>

Add a DataBuffer Python Class

Using the Python subsystem template, add a new data buffer subsystem model. Call the class DataBuffer and name the file, DataBuffer.py. Save the file in the new folder you created for this tutorial. All of this is consistent with the xml code you added to the modified System file you created previously.

The relevant parts of the DataBuffer.py file should look like:

class DataBuffer(HSFSystem.Subsystem):

    def CanPerform(self, event, universe):
        return True

Add a Dependency to the System File

Add a new <DEPENDENCY> tag to the myFirstHSFSystem.xml file as follows:

<DEPENDENCY
    subsystemName = "SSDR"
    assetName = "Asset1"
    depSubsystemName = "EOSensor"
    depAssetName = "Asset1"
    fcnName="SSDR_asset1_from_EOSensor_asset1">
</DEPENDENCY>

In this case, CameraLook is dependent on DataBuffer

Add a Dependency Function to CameraLook.py

Strictly speaking, dependency functions can live anywhere within your python environment and subsystem models. But within the HSF-MP, you have two options. Option one, if your dependency is only a precedence dependency, meaning order of subsystem evaluation is important for generating state data and there is no functional relationship between the two dependent subsystems, do nothing besides define the dependency within the input file. Option two, there is a functional relationship between the two dependent subsystems, add a dependency function to the dependent subsystem. In this case, the data buffer is dependent on the camera (since the camera takes a picture which then determined the amount of data stored on the data buffer). So, we will add a dependency function to the DataBuffer.py file as:

Add:

BufferDepFunc = FuncEvent, Utilities.HSFProfile[System.Double] dep.Add("DataBufferFromCamera" + "." + self.Asset.Name, BufferDepFunc)

to the camera_look.py class definition, GetDependencyDictionary(self)

Also add the method

def BUFFERSUB_NewDataProfile_CAMERA_LOOKSUB(self, event): return event.State.GetProfile(self.PIXELS_KEY) / 500

Run Horizon and Review Results