Table of Contents

Step

What Is a Step?

A MachiningStep (MachiningStep) is a single computation unit in the HiNC simulation. By default, one step corresponds to one spindle revolution, but this interval is configurable via the Basic Simulation workflow.

Each step contains data for the time interval between two consecutive steps (from the previous step to the current step). Since this represents a period rather than an instant, many fields are simplified representations using prefixes like Average (Avg), Extremes (Min, Max), Range (Delta), and Maximum Absolute Value (MaxAbs).


Registering Custom Step Variables

A project can define its own step variables, each a formula over the step, on the Execution page — Step Variables — and every play reads them. A script registers variables for its session, and writes values a formula would be slow to give, such as a sum over every step before this one: a formula would read all the earlier steps again on every step.

Beyond default properties, you can register custom step variables using RegisterStepVariable:

RegisterStepVariable(
    "ChipVolume",          // key
    "Chip Volume",         // display name
    "mm3",                 // unit
    "F2",                  // format string
    (step) => step.ChipVolume_mm3  // value function
);

PlayNcFile("NC/file1.nc");

Parameters:

  • key: Unique identifier
  • name: Display name (shown in UI)
  • unit: Physical unit (can be null)
  • formatString: .NET numeric format string (can be null)
  • variableFunction: Lambda that computes the value from a step (can be null)

A variable is computed from the step whenever it is read — for a chart, the tool-path colors, Step Properties or a step file — and is never stored on the step. A value written onto the step under the same key (see Indexer Access) wins over the function. Any number reads as a number (int, float, decimal and the like; a bool reads as 1 or 0); anything else, or a function that throws on a step, reads as no value on that step, and each variable's first throw in the session is reported in the session messages.

Registering the same key again replaces its definition. A key named like a built-in step property (Feedrate_mmdmin …), a key under the reserved MC. prefix, or a key the project defines a step variable or a color tree under (Step Variables, whether or not its formula compiles; Color Trees, whether or not the tree registers) is not registered, and a unit the unit list does not name is shown without a unit; each is reported once in the session messages. A key registered before the project defined it is set aside, and comes back when the project's variable or tree is deleted or renamed. Registrations last for the session: the session after a Reset starts without them, so register them in the mission's script before the play.

Registered variables appear in the UI — under Custom in the Step Present Preference dialog, so that Step Properties can list them, and in the property picker of the Color Index Time Chart, which colors the tool path by the property it shows — and in output files from WriteStepFiles.

Indexer Access

Use the this[string] indexer to read/write custom data on a step:

SessionStepBuilt += (preStep, curStep) => {
    if (curStep != null)
        curStep["MyCustomField"] = someCalculation();
};

The indexer reads only what is written onto the step. A variable registered with a function is computed when the charts, Step Properties or a step file read it, so step["key"] of such a variable is null. A written value is a number or a string. Any number reads back as a double whatever type was written (int, float, decimal and the like; a bool as 1 or 0; a NaN as a NaN), and a string as itself, so a project's formula reads a written number with step["key"] as double? whatever numeric type the script wrote. Writing null takes the key off the step. A value of any other type is not stored, and the session messages say so once per key.

A written value lives in the run's step cache — the database file the run writes its step results to — as one row per step and key, not as a field of the step in memory. It is kept for the session and read back whenever the step is read: by a chart, the tool-path colors, Step Properties, a step file, or step["key"] in a later command of the mission. A recompute of the step physics leaves the written values as they were written, and names their keys in a session message: a value derived from the played physics is not recomputed.

What a write costs depends on when it happens. In the SessionStepBuilt handler it costs nothing extra: the value goes out with the step's own row, in the same transaction, and preStep["key"], for a key the handler wrote on the step just published, reads it from memory, not from the file. After the play, every step["key"] = value is one write to the step cache — one row, one transaction — and each write marks the charts and the colors of the key stale. A script that fills many steps afterwards, say in a loop over GetMachiningStep(i), should collect its writes as StepVariableWrite records (step index, key, value) and hand them to WriteStepVariables in one call: one transaction per 4,096 writes, and the charts and the colors are marked stale once per batch instead of once per write. ReadStepVariables reads a key back over a range of steps — from the begin index up to, not including, the end index — in one read, as a dictionary from step index to value; a step without a value has no entry. A single step["key"] read after the play is one row read, and none for a key nothing was ever written under.

// After the play: collect the writes, then hand them over in one call
// (one transaction per 4,096 writes) instead of writing step["key"] step by step.
var writes = new List<StepVariableWrite>();
for (int i = 0; i < StepCount; i++)
{
    var step = GetMachiningStep(i);
    if (step != null)
        writes.Add(new StepVariableWrite(i, "MyCustomField", someCalculation(step)));
}
WriteStepVariables(writes);

// Read the key back over a range: step index -> value (a double or a string)
var values = ReadStepVariables("MyCustomField", 0, StepCount);

Registering a Color Tree

RegisterStepColorTree registers a color tree for the session: a categorical step property whose value on a step is the id of the leaf the step falls into, with a color per leaf. How a tree sorts the steps and how its leaves are colored is in Color Trees. Picked in the Color Index Time Chart, it colors the tool path and the cut faces by leaf.

RegisterStepColorTree(new StepColorTree
{
    Key = "Load",
    Nodes =
    [
        new StepColorLeaf
        {
            Name = "Rapid",
            When = StepColorCondition.All(new StepColorTerm("IsRapid", StepColorOp.Eq, 1))
        },
        new StepColorLeaf { Name = "Cutting" }   // no When: every step that reaches it
    ]
});

PlayNcFile("NC/file1.nc");

The key follows the rules of RegisterStepVariable above: a built-in step property's key, a key under MC., or a key the project defines a step variable or a color tree under is not registered, and a key registered again in the session takes the new definition. The tree is copied and compiled when it is registered, so a change to the tree object afterwards changes nothing until it is registered again. A node without an id is numbered from the tree's NextId — 1, 2, 3… in tree order when the tree gives none, the same numbers every time the script runs. A tree without a key, with a term without a key, a comparison without a threshold, an id repeated or out of range, or an operation or a join this version does not know is not registered; one with warnings only, such as a list without a node that takes every step, is registered as it is. Each refusal and each warning is said once in the session messages, and a key a condition names that matches no step property is reported after the play. A leaf without Hue_deg gets a hue of its own. The tree goes with the session, as a registered variable does, and appears where one does: under Custom in the Step Present Preference dialog, in the Color Index Time Chart's property picker, and in the step files, as the leaf's id.


Accessing Step Data

GetMachiningStep

GetMachiningStep retrieves a step by index:

var step = GetMachiningStep(100);
if (step != null)
{
    Message($"ToolId={step.ToolId}, Force={step.MaxAbsForce_N} N");
}

StepCount

StepCount returns the total number of steps:

Message($"Total steps: {StepCount}");

Iterating All Steps

for (int i = 0; i < StepCount; i++)
{
    var step = GetMachiningStep(i);
    // process step...
}

Step Output Files

Steps can be exported to CSV using WriteStepFiles:

WriteStepFiles("Output/[NcName].step.csv");

The CSV contains all default properties plus any registered custom variables. The file can be read back with PlayCsvFile.

For waveform-level data (sub-step time resolution), use WriteShotFiles:

WriteShotFiles("Output/[NcName].shot.csv", 1);  // 1 ms time resolution

Dynamically Registered Variables (Training)

After executing TrainMillingPara or ReTrainMillingPara, two additional step variables are automatically registered for steps within the training region:

Variable Description
TrainingErrRatio Error metric between simulation and measurement for each step
AngleOffset_deg Cutter rotation phase difference between measured and simulated data, in degrees

See Also