Table of Contents

Workflow: NC Optimization

This workflow describes how to generate optimized NC files from a physics-based simulation. The optimizer adjusts feed rates to keep physical quantities (spindle power, torque, thermal stress, cutting force) within specified safety limits while maximizing machining efficiency.

flowchart TD
    Prereq["Prerequisites<br>(simulation with physics,<br>cutting parameters)"]
    Config["Configure optimization options"]
    Simulate["Run simulation"]
    Output["Generate optimized NC files"]
    Verify["Verify optimization results"]

    Prereq --> Config --> Simulate --> Output --> Verify

1. Prerequisites

NC optimization requires a simulation environment with physics enabled and valid cutting parameters:

EnablePhysics = true;
LoadCuttingParaByFile("Material.mp");
Prerequisite Description
Physics enabled EnablePhysics must be true
Cutting parameters Workpiece must have loaded milling coefficients (see Workflow: Milling Force Parameter Training)
Valid tool definitions Tool geometry, flute count, and material properties configured
Note

Optimization is based on an ideal geometric model. If the workpiece is a casting or has installation errors, configure a conservatively larger workpiece geometry to prevent misidentification of cutting vs. non-cutting regions.


2. Configure Optimization Options

Feed Rate Control

Property Description Default
OptEnableFeedrate Enable sequential feed rate optimization true
OptEnableInterpolation Re-interpolation for smoother acceleration/deceleration
OptRapidFeed_mmdmin Feed rate for non-cutting regions (mm/min)
OptMinFeedrate_mmdmin Minimum cutting-region feed rate (mm/min)
OptMaxFeedrate_mmdmin Maximum cutting-region feed rate (mm/min)
OptMaxAcceleration_mmds2 Acceleration/deceleration limit (mm/s²)
OptFeedrateAssignmentRatio Re-interpolation trigger threshold

Extended Distance

Property Description
OptExtendedPreDistance_mm Pre-distance for equivalent calculation of cutting regions (mm)
OptExtendedPostDistance_mm Post-distance for equivalent calculation of cutting regions (mm)

Safety Factors (Physics-Based Constraints)

Property Description
OptSpindlePowerSafetyFactor Spindle power safety factor (0 = ignore)
OptSpindleTorqueSafetyFactor Spindle torque safety factor (0 = ignore)
OptThermalYieldSafetyFactor Thermal yield safety factor (0 = ignore)
OptPreferedForce_N Target cutting force (N)
Note

Target value = 100% / Safety factor. For example, a safety factor of 1.5 means the physical quantity targets ~67% of the limit.

Constraint Priority

In cutting regions, constraints are applied in this order:

  1. Direct feed rate constraints (min/max feed rate, min/max feed per tooth from tool settings)
  2. Acceleration/deceleration constraints (OptMaxAcceleration_mmds2)
  3. Physics-based constraints (spindle power, torque, thermal yield, preferred force)

When constraints at the same priority conflict, the lowest feed rate is used.

A floor above the ceiling neither fails nor lowers the feed: where the composed minimum feed per tooth exceeds the composed maximum — a minimum feed rate, a minimum feed per tooth or the cutter's minimum uncut chip thickness sitting above the maximum — the boundary collapses onto the minimum, and the step is solved there.

Script Command Example

OptEnableFeedrate = true;
OptEnableInterpolation = true;
OptRapidFeed_mmdmin = 4000;
OptMinFeedrate_mmdmin = 100;
OptMaxFeedrate_mmdmin = 4000;
OptMaxAcceleration_mmds2 = 10;
OptExtendedPreDistance_mm = 3;
OptExtendedPostDistance_mm = 2;
OptSpindlePowerSafetyFactor = 1.5;
OptSpindleTorqueSafetyFactor = 1.5;
OptThermalYieldSafetyFactor = 0;
OptPreferedForce_N = double.PositiveInfinity;

XML Configuration (NC Code Inline)

Optimization settings can be embedded in NC code comments:

N0110 X-3.064 Y6.378 (;@OptMaxAcceleration_mmds2=10;)
N0150 G01 X-3.068 Y40.776 (;@OptMaxAcceleration_mmds2=100; OptMaxFeedrate_mmdmin=12000;)

3. Run Simulation

Configuration can be interleaved between NC files. Settings apply to the files that follow:

OptRapidFeed_mmdmin = 4000;
PlayNcFile("NC/file1.nc");

OptRapidFeed_mmdmin = 8000;
PlayNcFile("NC/file2.nc");

Excluding Lines from Optimization

To preserve specific NC lines unchanged:

N0140 G03 X-2.66 Y38.193 I-103.796 J7.172 (;@Preserve();)

To exclude a range:

N0140 G03 X-2.66 Y38.193 (;@BeginPreserve();)
N0150 G01 X-3.068 Y40.776
N0160 X-3.555 Y43.338 (;@EndPreserve();)
Warning

Do not combine UpdateNcOptOption inside the SessionStepBuilt event with NC-embedded optimization commands. This may cause undefined behavior due to parallel computation.


4. Generate Optimized NC Files

OptimizeToFiles writes the optimized NC programs:

OptimizeToFiles("Cache/Opt-[NcName]");

The [NcName] template is replaced with each input NC file name.

What the Run Reports

An optimization reports itself to the Shell tab of the Session Messages panel, as a fixed sequence of rows:

Row Stage
Start NC optimization. the pass opens
Computing Optimized Feed by indivisual step.. the per-step feed solve
Optimization Feedrate built. the feed solve closed
Constrain feedrate By expaneded segment.. the extended-distance constraint
Constrain Feedrate By Acceleration.. the acceleration constraint
Build Compensation.. the compensation build
Regenerate NC commands.. the NC text is rewritten
File optimized: <path> one row per written file
Total N files optimized. the pass is over
optimization cache cleared. the step cache is released

Two of those stages tick while they work, and they are the only instrument for telling a slow optimization from a stopped one. The feed solve adds Computing Optimized Feed by indivisual step.. FileNo:<n>, LineNo:<m> every thousand steps solved — StepIndex:<i> instead, for a step that carries no source line — and the writer adds Now optimizing to: FileNo.<n>, LineNo.<m> every thousand lines written. Each names the source file and line the run has reached, so a ladder whose last row keeps advancing is a run still moving through the program, and one that has gone quiet without reaching Total N files optimized. is not. A stage with fewer than a thousand steps or lines to get through announces its start and then says nothing until it ends, so a short program crosses the whole ladder in near-silence.

Stop reaches inside an optimization. The transport's Stop is tested between every pair of stages, inside the per-step feed solve, and once per destination piece while files are written, so a stopped optimization halts at the next step or piece boundary rather than running to the end. The Shell ladder says so twice: the feed solve closes with Optimization Feed Process canceled. in place of Optimization Feedrate built., and an optimization canceled. row is added before the pass ends.

Important

A stopped optimization still ends on the green Total N files optimized. row a completed one ends on. That row is not a statement that the optimization finished — read the row above it. N counts the files the run had begun writing, so a Stop during the feed solve ends on Total 0 files optimized., and a Stop during writing counts the file it was in the middle of, which is left short.


5. Verify Optimization Results

Optimization Logs

The per-step log is written by default. Every optimization drops one .IndependentStepAdjustment.log beside each optimized NC file that had steps to solve, named after that optimized file, and it records which constraint limited each step. EnableIndividualStepAdjustmentLog is the switch that stops it being written:

EnableIndividualStepAdjustmentLog = false;

A stopped or failed optimization leaves that file short. Its buffered tail is written out only when the feed solve runs to completion; when the pass is cut off, the lines still in the buffer are dropped, and so is any step line held back in the ordering window waiting for a lower step index that never arrived. Batches reach the file at most once a second, so the missing tail can cover the last second of solving as well as the steps that were never reached. Read the log as a complete record only for a run whose feed solve closed with Optimization Feedrate built.

Each row of the .IndependentStepAdjustment.log file opens with the source NC file and line, the step index and the cutter location, then lists the feed per tooth every active criterion allowed:

Field Criterion
FrtByPreferedForce_mm target cutting force
FrtByYieldingStressRatio_mm yielding stress
FrtBySpindleTorqueRatio_mm spindle torque
FrtBySpindlePowerRatio_mm spindle power
FrtByThermalYieldingRatio_mm thermal yield
FrtByCustom_mm(n) the n-th custom criterion the script registered
FrtByReliefAngle_mm relief-face contact — see Relief Face Avoidance

The step's feed per tooth is the lowest of the first six; the relief-angle pass then runs on that value, so its row is the last word rather than one vote among the others.

Every row carries the solver's status for that criterion in brackets: Solved when the binary solve converged, Singular / OverIteration / Iterating when it did not, and — on the relief-angle row only — Acceptable, which means the relief face was clear at the feed already chosen, so that row states the feed instead of a limit on it. A criterion with no row at all was switched off (its safety factor is 0) or was not evaluable for that tool.

Three rows replace that list rather than joining it:

Field Meaning
FrtByUnTouched: inf the step cuts nothing, so no physical criterion applies
FeedrateByNoData_mmdmin: <feed> no tool or no milling coefficients on the step; it keeps its feed
StepFailed: <exception> the solve threw; the step keeps its simulated feed and is reported as an error — see When a Step Cannot Be Solved

Embedded Log Comments

Control embedded log verbosity with EmbeddedLogMode:

Mode Description
None No log comments
SimpleLog StepIndex on re-interpolated lines; LineNo on last interpolated line per original line
FullLog StepIndex and LineNo on all lines
Important

The mode is read by the legacy optimization path. While EnableSoftNcRunner is on and the session holds played NC — the default — the optimizer writes the SimpleLog shape whatever the mode says: every re-interpolated fragment carries its StepIndex, the last fragment of each source line adds that line's LineNo, and a line the optimizer did not split carries no note.

The note is written in the controller's comment grammar, so the optimized file stays legal for the control that reads it. On the Fanuc family it is parenthesized:

G01 X10.0 Y20.0 F500 (src(LineNo: 140, StepIndex: 256))

On Heidenhain it is a ; comment, because a TNC reads parentheses as code:

120 L X+35 Y-11.7 R0 F500 ;src(LineNo: 140, StepIndex: 256)

On a Heidenhain project a feed word the optimizer has to insert is also placed in the element order a TNC enforces — after the coordinate words, after the rotation direction DR+ / DR-, and after the radius compensation RL / RR / R0. A block that read L X+10 Y+20 RL comes back as L X+10 Y+20 RL F500.

Tracking Individual Step Constraints

To isolate which physical quantity limits each step, disable smoothing:

OptMaxAcceleration_mmds2 = double.PositiveInfinity;
OptFeedrateAssignmentRatio = 0;
OptExtendedPreDistance_mm = 0;
OptExtendedPostDistance_mm = 0;

The four smoothing settings are what this block changes. The per-step log is already on, and EmbeddedLogMode does not reach the pipeline that runs by default — see above.

Post-Optimization Simulation Differences

Optimized feed rates produce different interpolation points, causing:

  • Different simulation mesh errors
  • Surface morphology changes at the surface roughness level (more pronounced at corners)

Simulated physical quantities after optimization may be slightly above target values due to these differences.

Tip

For abnormally low optimized feed rates at corners, refer to Corner Feed Rate Optimization.


Tool Breakage Solutions

If the simulation shows yielding stress ratio, max spindle torque ratio, or max spindle power ratio above 100%, consider:

  1. Modify the toolpath to reduce cutting width/depth
  2. Use HiNC optimization to adjust feed rates, bringing these ratios below 100%

For thermal edge chipping, reduce the spindle speed to allow heat dissipation.


Complete Script Example

EnablePhysics = true;
LoadCuttingParaByFile("Material.mp");

OptEnableFeedrate = true;
OptEnableInterpolation = true;
OptRapidFeed_mmdmin = 4000;
OptMinFeedrate_mmdmin = 100;
OptMaxFeedrate_mmdmin = 4000;
OptMaxAcceleration_mmds2 = 10;
OptExtendedPreDistance_mm = 3;
OptExtendedPostDistance_mm = 2;
OptSpindlePowerSafetyFactor = 1.5;
OptSpindleTorqueSafetyFactor = 1.5;
OptThermalYieldSafetyFactor = 0;
OptPreferedForce_N = double.PositiveInfinity;

PlayNcFile("NC/file1.nc");

OptimizeToFiles("Cache/Opt-[NcName]");
WriteStepFiles("Output/[NcName].step.csv");

See Also