Workflow: Sensor Data Mapping
This workflow covers mapping external sensor data (dynamometer, smart tool holder, accelerometer) to simulation toolpaths so that simulation steps can index real-world measurement data.
flowchart TD
Prepare["Prepare sensor CSV data"]
Configure["Configure time mapping"]
Simulate["Run simulation"]
Map["Map data to simulation steps"]
View["View mapped results"]
Synth["No controller log?<br>Synthesise the controller table<br>from the simulated timeline"]
Prepare --> Configure --> Simulate --> Map --> View
Simulate -.-> Synth -.-> Map
Overview
Data mapping associates external sensor measurements with simulated machining steps. After mapping, each step can reference real-world force, torque, and acceleration data for:
- Inspecting machining states
- Training milling coefficients (see Workflow: Milling Force Parameter Training)
- Calibrating milling coefficients
- Comparing simulated vs. measured forces
Depending on data volume and application, mapping is either one-to-one (each step maps to one data point) or one-to-many (each step maps to multiple data points from high-sampling-rate sensors).
The mapping is a handful of session-shell calls. In the web application the two file mappings are mission commands of their own and the other calls go into Script commands — From the web application — and when the controller wrote no log, the simulation's own timeline stands in for it — When there is no controller log. A file whose columns carry the vendor's own titles maps as it came, with those titles named on the command; only a unit other than the reader's calls for a converted copy — A vendor file.
1. Prepare Sensor CSV Data
Sensor Data Format
The sensor file is what the series mapper reads — Strategy C, Strategy D and the second layer of the two-layer chain. It needs a header row with one time column and the channels it carries:
| Channel | Accepted headers | Unit |
|---|---|---|
| Time | ActualTime, ActualDateTime, TimeTag or Time — the first of these present is the one read |
see below |
| Force (dynamometer) | Fx, Fy, Fz, or Workpiece.Fx, Workpiece.Fy, Workpiece.Fz |
N |
| Moment (smart tool holder) | Mx, My, Mz, or Holder.Mx, Holder.My, Holder.Mz |
N·m |
| Acceleration | Ax, Ay, Az |
g — read as g-units; no step property or chart of the product uses this channel |
ActualTime,Mx,My,Mz
18:23:54.703,-0.02923,0.10733,0.00409
18:23:54.704,0.04155,-0.04457,0.00448
...
A time cell takes one of three forms. A plain number is seconds. <hours>:<minutes>:<seconds>.<fraction>
is a timecode — a time of day when the recorder writes its clock that way. A cell that carries a
date is an absolute instant, rebased through the project's mapping anchor: the anchor is set
once, to 00:00 of the day of the first absolute instant any conversion in the project sees, so a
same-day recording also becomes a time of day. The anchor is saved with the project and is not
cleared by ClearTimeMappingData(); a project that anchored on one day and now maps a recording
made on another needs MappingAnchorDateTime = null; in a script before the run, or an explicit
value.
Numbers are read with a period as the decimal separator on every machine, whatever its language
settings — the same way the product writes them; a recorder that exports 11,5 needs converting.
A channel the file does not carry reads NaN. Any other column is ignored by this reader — it keeps time, force, moment and acceleration and nothing else. A column that should reach the steps as a custom field belongs in the controller file below, whose extra columns are embedded into the steps, or in a CSV played directly (Strategy B).
Controller Data Format (for Two-Layer Mapping)
The controller CSV must contain FileNo, LineNo and one of three time columns:
FileNo,LineNo,ActualTimecode,ActualDateTime,MC.X,MC.Y,MC.Z,...
1,6,00:00:00.030,2026-03-16 15:57:45.559000,0,0,0.37,...
| Time column | What it carries |
|---|---|
ActualTimecode |
The run-relative timecode written by WriteStepFiles(API). ActualDateTime, the absolute controller instant, rides beside it and is optional. |
ActualTime |
The legacy single column, still read. A bare timecode cell is used as-is; an absolute date-time cell is rebased through the mapping anchor's converter. |
EndTimecode |
The simulated end timecode, used as a fallback when neither of the above parses. Files written before that rename carry AccumulatedTime, which is also accepted. |
A header row with none of the three is refused by name rather than mapped to nothing. A file this product exported carries the first pair, not the legacy column — which is why a step file plays back and maps without editing its headers.
FileNo and LineNo are both 1-based. FileNo numbers the files in the order the play enters
them: the main program is 1, the first subprogram it calls is 2, and every call is a file of its own
— a subprogram called twice takes a new number on its second call. The counter rewinds at every
Reset, so the numbering is the same on every run. LineNo is the line within that file.
Several rows may carry the same (FileNo, LineNo). The line's steps then take times interpolated
linearly from the first row's time to the last row's, the two end steps keeping the rows' own times;
one row per line stamps every step of the line with that one time. Every other column — the machine
coordinates MC.X … MC.C excepted — becomes a step variable: its values are embedded into each
step of the line, interpolated the same way, and the column is registered under its title (no unit,
format G4), so the charts, the tool-path colors and Step Properties can pick it as soon as the
mapping is done. A column registered before the mapping — with
RegisterStepVariable and a name, unit and format of your own —
keeps that registration. A column named like a built-in step property (Feedrate_mmdmin, ToolId,
…), or under the reserved MC. prefix (an axis beyond MC.C), is not mapped: the step keeps its own value, and the mapping names such columns in one session
message; rename the column in the CSV header to map it. A step file this product wrote carries the
built-in properties as simulated values, so mapping one back adds only its other columns.
Column Titles Are Configurable
The headers in the two tables above are the defaults, not a requirement on the file. Each mapping call takes a configuration that names the file's own titles, one per column the reader looks up — MapSingleCsvConfig(API) for the controller file, MapSeriesCsvConfig(API) for the sensor file:
MapSingleByCsvFile("Mapping/controller.csv", new MapSingleCsvConfig {
FileNoTag = "ProgramNo", LineNoTag = "BlockNo", ActualTimeTag = "Timestamp" });
MapSeriesByCsvFile("Mapping/sensor.csv",
new MapSeriesCsvConfig { TimeTag = "Clock", MzTag = "Tq" });
Only the columns that differ need naming; a tag left alone keeps its default, and a blanked tag is its default again.
| File | Tag | Default title |
|---|---|---|
| Controller | FileNoTag, LineNoTag |
FileNo, LineNo |
| Controller | ActualTimecodeTag, ActualDateTimeTag |
ActualTimecode, ActualDateTime |
| Controller | ActualTimeTag |
ActualTime |
| Controller | SimTimeTag |
EndTimecode — AccumulatedTime is accepted with it only while the tag is left at this default |
| Controller | MachineCoordinatePrefix |
MC. — the machine-coordinate columns are the prefix plus X, Y, Z, A, B, C |
| Sensor | TimeTag |
ActualTime, then ActualDateTime, TimeTag, Time |
| Sensor | FxTag, FyTag, FzTag |
Fx … or Workpiece.Fx … |
| Sensor | MxTag, MyTag, MzTag |
Mx … or Holder.Mx … |
| Sensor | AxTag, AyTag, AzTag |
Ax, Ay, Az |
Two rules differ between the files. In the controller file a tag simply replaces the title, and
the three time sources keep their order — a log with one time column is mapped by naming it in
ActualTimeTag, whose cell may be a timecode or a date-bearing instant. In the sensor file a
tag left at its default keeps every accepted header of its row above and the channel stays
optional, while a changed tag is looked up exactly and the file must carry it: a header row
without it is refused with the title named, so a mistyped title cannot pass for a channel the
recording does not have.
A controller column the configuration names is consumed; every other column is still embedded into the steps under its own title — one named like a built-in step property excepted, as above — so renaming a tag never renames a custom field.
2. Configure Time Mapping
Strategy A: One-to-One Mapping (MapSingleByCsvFile)
MapSingleByCsvFile reads a file in the controller format above and uses time interpolation to map each data row to one simulation step.
PlayNcFile("NC/file1.nc");
MapSingleByCsvFile("Data/controller.csv");
Strategy B: One-to-One via PlayCsvFile
PlayCsvFile can drive the simulation directly from CSV data, where each row becomes one step. Every column the play does not read as a command rides the row's step and is registered as a step variable, so the charts can pick it; a column named like a built-in step property, or under the reserved MC. prefix, is left out, and the play names those columns once in the session messages.
PlayCsvFile("Data/controller.csv");
Strategy C: One-to-Many Global Mapping (MapSeriesByCsvFile)
For high-sampling-rate data, first establish ActualTime via one-to-one mapping, then map the series:
PlayNcFile("NC/file1.nc");
MapSingleByCsvFile("Data/controller.csv"); // establishes ActualTime
MapSeriesByCsvFile("Data/sensor.csv"); // maps high-rate series
Strategy D: One-to-Many Local Mapping (Anchor-Based)
For mapping a recording onto specific segments of the NC path, with the segment's ends anchored in the program itself.
Step 1 — Name the recording windows. Each key pairs a file with a time window of it; the window is stretched linearly over the steps the anchors select, which is what corrects the drift the tip in §4 describes.
ClearTimeMappingData();
AddTimeDataByFile("lineA", "Mapping/sensor1.csv", "18:25:51.7100", "18:26:12.9910");
AddTimeDataByFile("lineB", "Mapping/sensor1.csv", "18:26:30.5750", "18:27:12.2880");
A window's ends are seconds, timecodes, or date-bearing instants. A key already in the table is not
replaced — the call returns false.
Step 2 — Anchor the segments in the NC program. The anchors are C# calls written into the
program's own comments. The runner's comment syntax takes the comment out of the block first —
parentheses on a Fanuc-family controller (Fanuc, Mazak, Syntec), ; to the end of the line on
Siemens, //, ; or parentheses on Heidenhain — and the script syntax then takes the script out of
the comment's text by two markers: @@ for a script that runs before the block's motion, @@^
for one that runs after it. The two markers are settings of that syntax rather than fixed
characters — Script Commands in NC Code.
G01 X13. F20 (@@LineSelection("lineA", FirstTouch, ShiftTime_s(2), LineEnd, ShiftDistance_mm(-1));)
G01 X25. F10 (@@LineSelection("lineB", FirstTouch, null, LastTouch, null);)
For a segment across several lines, open it before the first line's motion with BeginSelection
and close it after the last line's with EndSelection:
G01 Z-0.2 F1500 (@@BeginSelection("region1", FirstTouch, null);)
...
G01 X10. Y10. (@@^EndSelection("region1", LineEnd, null);)
A parenthesised comment runs from the first ( to the last ) on the line, so the parentheses
inside the call are no problem — but keep the anchor the only parenthesised text on its line, since a
second comment on the same line would be swallowed into the script. On Siemens the same anchor is
written after ;:
G01 X13. F20 ;@@LineSelection("lineA", FirstTouch, null, LineEnd, null);
The names in the calls — FirstTouch, LineEnd, ShiftTime_s, null — are the session shell's.
An embedded script compiles against the same references and imports as a Script command, so
whatever a Script command can call, an anchor can call too. Five rules decide whether an anchor
does what it looks like it does:
FirstTouchlooks forward from the Begin anchor. The first-contact search starts at the step where the anchored line begins and runs to the End anchor, so a Begin anchor may sit on the first feed line of the segment rather than on the line that actually reaches the stock.LastTouchsearches backward from the End anchor the same way. A segment in which the search finds no contact step maps nothing, and nothing says so.- One key opens and closes once until a Reset, within one program. A second
EndSelectionon a key already closed, or anEndSelectionwhoseBeginSelectionnever ran, throws when the line ends; the run reports it at that line asLine-End--Exception, and that segment is not mapped. A program that plays the same segment twice needs two keys. A begin that no end has closed is dropped when the session starts its next program — the mission's next Program File, or the nextPlayNcFileof a Script command — so a key's two anchors belong in one program and the subprograms it calls. - Reset clears the anchors; a Stop does not. The host that holds the selections is emptied when
the session is reset, with the per-step mapped samples; the key → window table of Step 1 and the
mapping anchor date are not, which is why
ClearTimeMappingData()opens the script. A Start after a Stop with no Reset between plays the mission again on the same session: a key the stopped run had closed keeps the segment that run selected, and the replay reportsLine-End--Exceptionat itsEndSelection; a key the stopped run left open — it stopped between the key's two anchors — is dropped as the replay starts, so the replay's ownBeginSelectionandEndSelectionpair. To map the program again, press Reset before the Start. - The anchors need no licence feature of their own — but packages 3.2.7 to 3.2.31 ran them only
under
NcComposition: without it the first embedded script reportedScript--NotLicensedonce and every further one was skipped silently, so the anchors selected nothing and nothing was mapped. Later packages run them unconditionally, as 3.1 did. - An anchor that does not compile is reported on its step as
Script-Compile--Error; the mission's compile check covers Script commands only, not the comments in a program.
Anchor Flags:
| Flag | Description |
|---|---|
LineBegin |
Motion start point of the line |
LineEnd |
Motion end point of the line |
FirstTouch |
First contact with the workpiece |
LastTouch |
Last contact with the workpiece |
Offset Options:
| Offset | Description |
|---|---|
null |
No offset |
ShiftTime_s(<seconds>) |
Time-based offset (positive = forward) |
ShiftDistance_mm(<mm>) |
Distance-based offset (positive = forward) |
Warning
;@… was the marker of the previous runner. On Siemens, or inside parentheses on a Fanuc-family
controller, a comment holding it is an ordinary comment and the anchor does nothing; written bare on
a Fanuc-family controller it is leftover text and the build also warns UnparsedText--Remaining.
Either way the build warns CsScript-Marker--Legacy once per NC file, naming the file and the
first line where ;@ stands before a call or an assignment. Rewrite the marker as @@ inside the
controller's comment: (@@…) on a Fanuc-family controller and on Heidenhain, ;@@… on Siemens.
Two reports date a build from before the anchors worked on the SoftNc runner. An anchored step
reporting Script-Run--Exception (“BeginSelection has to be used in Command Source File”) is a
runner that did not yet publish the line boundary the selection calls rely on: the anchors were
parsed and ran, and mapped nothing. An anchored line reporting Syntax-Build--Exception with the
run turning into rapid traverses is older still: the block carrying the marker lost its motion word
and played as the previous modal rapid. On either build, map with the two-layer chain — a real
controller log or a synthesised controller table
(When there is no controller log).
Map on Selection End
EnableMapOnSelectionEnd controls automatic mapping when a selection ends (default: true):
EnableMapOnSelectionEnd = true; // EndSelection triggers Map automatically
Clearing Mapping Data
The key → window table of Strategy D and the mapping anchor are saved with the project and survive a Reset; the per-step mapped samples and the anchors in the program do not — the next run rebuilds them. Clear the table before adding to it, so a re-run does not find its keys already taken:
ClearTimeMappingData();
The anchor date is not part of what this clears — see Sensor Data Format.
3. Run Simulation
PlayNcFile("NC/file1.nc");
Note
Why interpret NC code instead of playing CSV directly? The system NC interpreter produces more accurate simulation paths than direct controller CSV playback, which has limited sampling resolution that distorts tool paths.
4. Map Data
After simulation, apply the mapping strategy chosen in step 2. For the two-layer chained approach:
// Chain 1: Controller data → simulation steps (via FileNo/LineNo → ActualTime)
MapSingleByCsvFile("Data/controller.csv");
// Chain 2: Sensor data → simulation steps (via ActualTime → sensor readings)
MapSeriesByCsvFile("Data/sensor.csv");
The chaining works because:
- Simulation steps and controller data share
FileNo/LineNoanchors - Controller data and sensor data share
ActualTimeanchors - After chaining, simulation steps can index sensor data
The second call walks the steps the first one stamped and pairs each with the samples of one cycle
after its end — a spindle revolution under the default SpindleCycle sampling mode, one flute's arc
under FluteCycle. A step whose window holds no sample — outside the recording, or inside a
dropout — is left unmapped and counted once in the Map-ShotGap--StepsSkipped warning.
Tip
Due to machine acceleration/deceleration, simulation time and actual time diverge over longer durations. Anchor-based linear projection corrects for this drift.
5. View Mapped Results
After mapping, each step carries its samples. In the web application they show in three places — the sensor cycle charts of the selected step, the step properties derived from the samples, and the run's messages — set out in From the web application; a mapped step property also colours the workpiece in the 3D scene when it is the Color Index chart's key.
Export mapped results from a script:
WriteStepFiles("Output/[NcName].step.csv");
WriteShotFiles("Output/[NcName].shot.csv", 1);
Complete Two-Layer Mapping Example
// Configure resolution
MachiningResolution_mm = 0.125;
EnablePhysics = true;
// Clear any previous mapping data
ClearTimeMappingData();
// Run simulation using NC interpreter for accurate paths
PlayNcFile("NC/machining.nc");
// Map controller data (contains FileNo, LineNo, ActualTime)
MapSingleByCsvFile("Data/controller.csv");
// Map high-rate sensor data (contains ActualTime and force/torque)
MapSeriesByCsvFile("Data/sensor.csv");
// Export results
WriteStepFiles("Output/[NcName].step.csv");
From the web application
The two file mappings are mission commands of their own: Map Single By CSV File and Map Series By CSV File, in the Mapping category of Add Command (The Other Commands). Each carries its file and that file's column titles, and the sensor one the cycle sampling mode. The other calls above go into Script commands, evaluated against the running session like any mission script (The Other Commands). The files live in the project folder, uploaded through the file routes (Files and Named Roots).
The shape is the two mapping commands after the Program File, in the same List:
▸ Mapping
Script [clear] ClearTimeMappingData();
Program File NC/machining.nc
Map Single By CSV File Mapping/controller.csv
Map Series By CSV File Mapping/sensor.csv
The session shell is one object for the whole run and every command is evaluated against it in
order, so this list is the same thing as the
complete example written into one Script command with
PlayNcFile in the middle. The order matters the same way: the controller file gives the steps
their actual times, and the sensor file is paired through those times. Strategy D is a Script with
the AddTimeDataByFile calls before the Program File and no mapping command after it, the anchors
in the program triggering the mapping.
Over HTTP the mission is built one entry at a time (Project Construction §3):
| Step | Request |
|---|---|
| Add a mapping entry | POST /api/Mission/list-command/entries/{listPath} with {"CommandType": "mapsinglebycsvfile"} or "mapseriesbycsvfile", positioned like the Script entry below. |
| Set its file and column titles | GET /api/Mission/commands/{path}/fields lists the fields — relFile, then one per column title (fileNoTag, actualTimeTag, … / timeTag, mxTag, …), and cycleSamplingMode with its options on the sensor command. PUT /api/Mission/commands/{path}/fields/{key} takes the bare JSON value: "Mapping/controller.csv", "Timestamp", "FluteCycle". A value that is not a member of the option list is refused. |
| Add a Script entry | POST /api/Mission/list-command/entries/{listPath} with {"CommandType": "script", "IsEnabled": true, "InsertIndex": n} — n is the position inside the list, 0 first; left out, the entry goes last. The reply's path addresses the entry from then on; GET /api/Mission/list-command/entries lists the mission with every path. |
| Write the script | PUT /api/Mission/commands/{path}/script with {"ScriptText": "…", "Title": "…"}. The reply carries a contentHash; a later PUT may send it back as ExpectedContentHash, and is then refused with 409 content_hash_mismatch if the script was edited elsewhere in between. |
| Check it compiles | POST /api/Mission/compile-check compiles every enabled Script command and answers isValid and a scripts array with, per script, its path, title, hasErrors and diagnostics (id, severity, message, line, column); POST /api/Mission/commands/{path}/compile-check checks one. A start while an enabled script has an error is refused with code: "script_compile_error" — Replay Acceptance §2. |
| Save | POST /api/Project/save — the script text and title are written into the project file. |
Where the result shows:
- The sensor cycle charts of the selected step. Select a step — a click on a strip chart or on
the tool path, or
POST /api/execution/cl-strip/select-stepwith{"stepIndex": n}— and the Step Info column's Sensor Spindle Moment Cycle plots that step'sMx,My,Mzsamples against time over its one-cycle window, Sensor Cutting Force Cycle itsFx,Fy,Fz. Both charts are switched on under Preference › Optional Nodes & Charts and are off by default (Inspecting a Step). Over HTTP the same series isGET /api/execution/cycle-line/sensor-spindle-moment, answering{hasData, ts, xs, ys, zs}, andGET /api/execution/cycle-line/dynamometer-forcefor the force;hasDatafalse is a step with no samples. - The step properties the samples derive.
AvgAbsTorqueByMapping_Nmis the mean absoluteMzof the step's samples andAvgMomentXyByMapping_Nmthe mean bending magnitude;AvgAbsTorqueErrorRatioWithMappingandAvgMomentXyErrorRatioWithMappingare (simulated − measured) / measured, empty where the measured value is below 0.1 N·m. Pick them in the Step Properties chooser, or plot one along the run in the Color Index chart's property picker (Watching the Run); over HTTPGET /api/execution/step-propertieslists the keys, and the strip-chart request of Replay Acceptance §4 returns the series for any of them. These four are physics keys: they are listed and plotted only while physics is enabled for the run (the mission's Enable Physics setting). - The messages, in the
shelllist ofGET /api/Execution/messages.CsvEmbed--BeginandCsvEmbed--Donebracket the controller layer.Map-ShotGap--StepsSkippedis a warning counting the steps whose one-cycle window held no sample: the steps outside the recording, which a recording that does not cover the whole program produces as a matter of course, plus any dropout inside it.TimeShotFile--NotFoundis a missing sensor file, andTimeShotFile--ReadFaileda sensor file whose header row lacks the time column or a column title the command names, with the missing title in the message. A controller file that cannot be read, or lacks its file-number, line-number or time column, has no message of its own; it faults whatever called the mapping. From a mapping command that isMap-SingleCsv--Fault(Map-SeriesCsv--Faultfor the sensor file, after itsTimeShotFile--ReadFailed), from a scriptScriptCommand-Run--Fault— each with the missing header named, and each leaving the mission to go on to its next entry.
When there is no controller log
The first layer of the chain exists to give each step a real-clock time. When the controller wrote
no log, the simulation's own timeline stands in for it: every step already carries FileNo,
LineNo and its simulated end time, and all a controller table has to add is the offset between
the simulation clock and the recording's clock.
Take the timeline from the run. The step file that Post-Execution's Step Files Output or
WriteStepFiles writes has the columns — FileNo, LineNo, EndTimecode, and an ActualTimecode
written as null on an unmapped run — and the controller reader takes it as it is, falling back to
EndTimecode when the actual-time cells do not parse. For a job with subprograms take the timeline
from the strip-chart request below rather than the step files: the step writer reopens a program's
file each time the play returns to it, so a main program that calls a subprogram keeps only the rows
after the return. Over HTTP,
GET /api/execution/strip-chart?aspect=Individual&inspectingKey=FileNo&xValueCategory=IndexByTime&widthHint=0&dispBegin=0&dispEnd=<count>
returns the end time of every step in xs and its FileNo in items[0].max; the same request with
inspectingKey=LineNo gives the line. Each key is posted first as the project's inspecting key
(POST /api/execution/inspecting-key, Replay Acceptance §2): the answer
says pending: true until the host has filled that key's values, and a key that is not the
project's answers empty items; post the key the project held before back when done, while the
project's key is still the one you posted.
Add the offset. Write ActualTimecode as EndTimecode + offset on every row, as a timecode
(hh:mm:ss.fff), and keep FileNo and LineNo. The offset is the recording's clock reading at
simulated time zero: a time of day when the recorder writes its clock, seconds when it counts from
its own start.
Or shift the recording instead of the table. When the recording's time column carries absolute
date-times, no table has to be written at all. Leave the step file as it is — the controller reader
gives each step its simulated EndTimecode — and set the mapping anchor to the recording's clock
reading at simulated time zero before mapping; the sensor reader turns every absolute sample time
into its distance from the anchor, which then lands on the simulated clock:
MappingAnchorDateTime = new DateTime(2025, 3, 4, 10, 0, 3, 750); // recording clock at simulated zero
MapSingleByCsvFile("Output/finishing.nc.step.csv"); // the program's own step file
MapSeriesByCsvFile("Mapping/sensor.csv");
Two conditions come with it. The step file has to come from a play whose ActualTimecode column is
null or already holds simulated timecodes: the controller reader prefers that column when it
parses, and a step file written after a mapping that stamped wall-clock times gives every step a
time outside the recording — the map then covers nothing, and says so only through
Map-ShotGap--StepsSkipped. And the first play of a new mission has no step file yet, since
Post-Execution writes it after the mapping script: play once with the mapping script switched off.
A subprogram played once keeps a complete step file of its own, which is the one to name; a
subprogram called several times keeps only its last call.
Find the offset by correlation, not from one peak. Put a simulated series and a measured one on
the same time grid — the simulated torque AvgAbsTorque_Nm over IndexByTime from the strip
chart or a step file, and the measured Mz — reduce each to its envelope (the largest magnitude in
each grid cell), and cross-correlate the two records whole; the lag at the maximum is the offset. A
single peak is not enough: a finishing path repeats every few seconds, and one peak matches every
repetition equally well, so a peak-to-peak alignment can land a whole pass early or late. Then run
the same correlation on the first half of the record and on the second half separately. The two
lags must agree; a lag that grows along the record means the machine's real timing and the
simulated one diverge (acceleration, dwells) and one offset cannot map the whole program: fit an
offset per stretch of the record and write each stretch's rows with its own, or use a real log.
A recording that stops partway maps as far as it goes: the steps after its end have no samples
in their windows and are reported once, with their count, as Map-ShotGap--StepsSkipped. That count
is the check — it should be the steps after the recording's end, not more.
Ask the vendor before trusting the file: the time base — which clock stamps the samples, at what rate, and whether it is the controller's clock or the sensor's own; the calibration — the factor from the file's numbers to N·m on each channel, and which channel is the torque about the tool axis; and the reference point of the bending channels — the height on the tool axis they are referred to, which is what the tool's observation point must be set to (Smart Tool Holder).
A vendor file
A sensor file rarely arrives with the headers of §1, and it does not have to: the mapping command (or the call's configuration, §1 Column Titles Are Configurable) names the vendor's own titles, so the file is mapped as it came. The substance is deciding which of the vendor's columns can honestly be named as the channels the reader gives them.
- Time. Name the vendor's time column as the Time Column (
TimeTag); its cells may be seconds,hh:mm:ss.fff, or a date-bearing instant, as §1 says. Keep whatever clock the vendor recorded — the controller table absorbs the offset. - Torque. The axial torque about the tool axis is the Moment Z Column (
MzTag), in N·m. It is the channel the torque step properties above compare against. - Bending. The Moment X / Y Columns are bending moments about the observation point, in N·m.
Name the vendor's bending channels there only when the vendor has stated their unit and the point
they are referred to: a bending moment of unknown reference height is a scaling error nothing
reports, and a raw strain reading is not a moment. Otherwise leave those two tags at their
defaults — a channel the file does not carry reads NaN, and the torque still maps.
HiNC's Mx is the moment about the X axis (see
What Mx, My and Mz Mean on
the Smart Tool Holder page); a vendor's “bending X” may be bending toward X, the moment about Y —
settle it with the push check before naming the column here. Only Map Series by CSV File reads
these tags; AddTimeDataByFile and the online setup-angle estimation read the built-in names
(
Mx,Holder.Mx,Spindle.Mx, andTime), so a converted copy with those headers works on every path. - Everything else — sample counters, status flags, the vendor's own computed columns — is dropped by this reader whatever it is called.
- A unit is not a title. Naming a column does not convert it: a torque in N·mm, or a force in kN, still has to be rescaled in a converted copy of the file. Keep the vendor's original beside it.
- A gain from a report is a last resort. When the file carries raw counts and the only calibration to hand is a report's extreme (“peak torque 12 N·m”), dividing the report's extreme by the raw extreme gives a gain that reproduces one number. Use it only when the vendor cannot supply the calibration, and record it in the project's README as an assumption, with the report and the raw extreme it came from, so it is replaced when the calibration arrives (Project Construction §7).
A four-row vendor file — Time in seconds, two bending channels of unstated reference, a torque in
N·m:
Time,BendX,BendY,Tq
0.000,-0.031,0.108,0.412
0.001,0.044,-0.045,0.398
0.002,0.012,0.061,0.421
0.003,-0.027,0.019,0.405
maps as it is with one title named — Time is already an accepted time header, and the bending
channels stay unnamed until their reference point is known:
MapSeriesByCsvFile("Mapping/vendor.csv", new MapSeriesCsvConfig { MzTag = "Tq" });
On the Map Series By CSV File command that is the Moment Z Column field set to Tq.
See Also
- Workflow: Milling Force Parameter Training — using mapped data for coefficient training
- Workflow: Basic Machining Simulation — basic simulation setup
- Project Construction — building the mission over HTTP, and recording assumptions
- Replay Acceptance over the HTTP API — the strip-chart request and the message inventory
- Driving the Web Service over HTTP — sign-in, reply envelope, file roots
- The Other Commands — the two mapping commands, and the Script command the other calls go into
- Inspecting a Step — the sensor cycle charts of the selected step
- Watching the Run — the Color Index chart that plots a mapped step property along the run
- Smart Tool Holder — the observation point the bending channels are referred to
- Script Commands in NC Code — the
@@/@@^markers the anchors are written with - Step — step data model
- SessionShell — SessionShell quick-reference
- Example Project: Mapping Controller and Sensor Data to Simulated NC Toolpaths and Updating Milling Coefficients — mapping demo example project
- Example Project: Training Milling Coefficients with a Dynamometer — dynamometer training example project