Resources Numerical accuracy Calculation policy

Cutting speeds, feeds and tool profiles

Works out spindle speed and feed rates for a tool in a material, and the shape of each tool's tip used by the simulation and 3D finishing.

How the precision is kept

The speed and feed relations are standard closed forms in 64-bit, but their inputs are a table of starting values that the file's header describes as taken toward the conservative end of published ranges and not tuned for any machine. The spindle speed is rounded to a whole number and feeds to one decimal before they are used and written.

Calculations under this policy

3 calculations in 1 source file. The code is read from the released app when this page loads. It is the calculation people run, not a copy kept for this page.

cam-tools.js PartCraft 0.8.1 64-bit 3 calculations Reviewed

Tests tools/partcraft-test/test-cam-library.mjs, tools/partcraft-test/test-cam.mjs

Spindle speed and feeds

64-bit

The spindle speed, cutting feed, plunge feed and ramp feed for a tool.

rpm = round(1000 vc ÷ (π d)), limited to the machine's range; feed = rpm × flutes × f_z; plunge = feed ÷ 3; ramp = feed ÷ 2

The speed is rounded to a whole rpm after clamping, and the feed is computed from that rounded speed, so the chip load is kept. Feeds are then rounded to 0.1 mm/min. The cutting speed returned is recomputed from the rounded rpm.

  • cam-tools.js
  • lines 115 to 133
  • PartCraft 0.8.1
/** Spindle speed and feeds for a tool in a material on a machine {maxRpm, minRpm}. */
export function speeds(tool, material = 'aluminum', machine = {}) {
  const M = MATERIALS[material] || MATERIALS.aluminum;
  const drill = tool.kind === 'drill';
  const hss = tool.material === 'hss' ? HSS_FACTOR : 1;
  // a chamfer or ball cuts at a smaller effective diameter; we use the nominal one (conservative for rpm)
  const vc = tool.vc ?? M.vc * hss * (drill ? M.drillVc : 1);
  const fz = tool.fz ?? (drill ? M.frk * tool.d : Math.min(M.fzMax, Math.max(M.fzMin, M.fzk * tool.d)));
  let rpm = tool.rpm ?? (1000 * vc) / (Math.PI * tool.d);
  const maxRpm = machine.maxRpm || 24000, minRpm = machine.minRpm || 0;
  let clamped = null;
  if (rpm > maxRpm) { rpm = maxRpm; clamped = 'max'; } else if (rpm < minRpm) { rpm = minRpm; clamped = 'min'; }
  rpm = Math.round(rpm);
  const feed = tool.feed ?? (drill ? rpm * fz : rpm * tool.flutes * fz);
  return {
    rpm, feed: round1(feed), plunge: round1(drill ? feed : feed / 3), ramp: round1(feed / 2),
    vc: (Math.PI * tool.d * rpm) / 1000, fz, clamped, source: speedsSource(),
  };
}

Rounding feeds to one decimal

64-bit

Rounds a feed rate to tenths.

round1(v) = round(v × 10) ÷ 10

The rounded feed is the value stored on every move and written to G-code.

  • cam-tools.js
  • line 134
  • PartCraft 0.8.1
const round1 = (v) => Math.round(v * 10) / 10;

Tool tip profile

64-bit

The height of the cutting surface above the tool's tip at a given distance from its axis.

ball: R − √(R² − ρ²); bull: r_c − √(r_c² − (ρ − a)²) beyond a = R − r_c; drill and chamfer: (ρ − r_t) ÷ tan(angle ÷ 2); flat: 0

For the ball and bull-nose forms the two terms are nearly equal close to the axis, so the height loses relative digits there while its absolute error stays at the rounding level of R. Square-root arguments are clamped at 0.

  • cam-tools.js
  • lines 136 to 158
  • PartCraft 0.8.1
/**
 * The tool's tip profile: h(ρ) = height of the cutting surface above the tip at radius ρ (∞ beyond the
 * cutting radius). Used by the stock simulation and the 3D drop cutter.
 */
export function profile(tool) {
  const R = tool.d / 2;
  switch (tool.kind) {
    case 'ball': return { R, h: (p) => (p > R ? Infinity : R - Math.sqrt(Math.max(0, R * R - p * p))) };
    case 'bull': {
      const rc = tool.cornerR, a = R - rc;
      return { R, h: (p) => (p > R ? Infinity : p <= a ? 0 : rc - Math.sqrt(Math.max(0, rc * rc - (p - a) * (p - a)))) };
    }
    case 'drill': {
      const k = 1 / Math.tan((tool.angle / 2) * Math.PI / 180);
      return { R, h: (p) => (p > R ? Infinity : p * k), tip: R * k };
    }
    case 'chamfer': {
      const rt = tool.tipD / 2, k = 1 / Math.tan((tool.angle / 2) * Math.PI / 180);
      return { R, h: (p) => (p > R ? Infinity : p <= rt ? 0 : (p - rt) * k) };
    }
    default: return { R, h: (p) => (p > R ? Infinity : 0) };
  }
}

In detail

Method
n = 1000 × vc ÷ (π × d); feed = n × flutes × chip load (drills: n × feed per revolution); plunge = feed ÷ 3; ramp = feed ÷ 2. The header cites Machinery's Handbook and tool makers' charts for the starting values.
Number types
64-bit numbers; a small table of constants per material.
Tolerances
Spindle speed rounded to 1 rpm; feeds rounded to 0.1 mm/min. High-speed steel tools use 0.35 × the cutting speed.
Limits
Default values are empirical starting points. Chamfer and ball tools are computed at their nominal diameter.

Approach: 64-bit, stated limit

The arithmetic is 64-bit, but the method or the data sets the accuracy: a solver tolerance, a mesh, a step size, a datum shift, a table. The limit is stated where the result is shown.

Every policy that takes this approach