using CaeKnowledge.Data; using System; using ToolPathParser; namespace CaeCuttingForce.ToroidalCutter { public class LineForce { private const double PI = Math.PI; private const double h1 = 0.006; // h1 private const double da = 0.006; // da public void CalculateCuttingForce(int direction, ToolPosition position, CuttingForceCoefficients coefficients, ToolParameters toolParams) { // 刀具参数 int N = toolParams.NumberOfTeeth; // 刀齿数 N double D = toolParams.ToolRadius * 2; // 刀具直径 double i0 = toolParams.HelixAngle; // 刀具螺旋角 double R_bull = toolParams.ArcRadius; // 环形圆弧半径(mm) double Ap = position.AxialDepth; // 轴向切削深度 Ap double Ae = position.RadialDepth; // 径向切削深度 Ae double nrot = position.SpindleSpeed; // 主轴转速 n double fd = position.FeedRate; // 进给速度 fd // 计算中间变量 double Theta_pit = 2.0 * PI / N; // 齿间角(rad) double i0_rad = i0 * PI / 180.0; // 螺旋角转换为弧度 double Rr = D / 2.0 - R_bull; // 径向偏移量(mm) double stj = fd / (N * nrot); // 每齿进给量(mm/tooth) // 计算切入角和切出角 double Theta_st = Math.Acos(Ae / (D / 2.0) - 1.0); // 切入角(rad) double Theta_ex = PI; // 切出角 // 积分步数计算 int K_angle = (int)Math.Floor(2.0 * PI / h1); // 角向积分步数 int L_axial = (int)Math.Round(Ap / da); // 轴向积分步数(四舍五入) L_axial = Math.Max(L_axial, 1); // 初始化结果数组 double[] Fx = new double[K_angle]; double[] Fy = new double[K_angle]; double[] Fz = new double[K_angle]; double[] Fx_global = new double[K_angle]; double[] Fy_global = new double[K_angle]; double[] Fz_global = new double[K_angle]; // 环形刀轴向几何参数数组 double[] r_z = new double[L_axial]; // z处的刀具半径 double[] kappa_z = new double[L_axial]; // z处的轴向浸入角(rad) double[] psi_z = new double[L_axial]; // z处的径向滞后角(rad) double[] db_z = new double[L_axial]; // z处的微元切削宽度(mm) double[] ds_z = new double[L_axial]; // z处的微元刃口长度(mm) double[] tool_helixangel_z = new double[L_axial];// z处的螺旋角(rad) // 辅助数组 int M = L_axial * N * K_angle; double[] h = new double[M]; double[] Px = new double[M]; double[] Qx = new double[M]; double[] R1 = new double[N * K_angle]; int m = 0; int n_idx = 0; // 主计算循环 // 三重循环计算切削力(角向→刀齿→轴向) for (int i = 0; i < K_angle; i++) { double phi_i = i * h1; // 第i个角向位置的基础径向浸入角(rad) for (int k = 0; k < N; k++) { // 第k个刀齿的基础径向浸入角 R1[n_idx] = phi_i + k * Theta_pit; double phi_j = R1[n_idx]; for (int j = 0; j < L_axial; j++) { double z = (j + 1) * da; // 当前轴向高度(mm) // 计算z处的刀具半径r(z)(分区计算) if (z >= 0 && z < R_bull) // 环形圆弧区(MN区) { r_z[j] = Rr + Math.Sqrt(R_bull * R_bull - Math.Pow(R_bull - z, 2)); } else // 圆柱区(NS区) { r_z[j] = D / 2.0; } // 计算轴向浸入角、螺旋角、径向滞后角(分区) if (z >= 0 && z < R_bull) // 环形圆弧区 { kappa_z[j] = Math.Acos((R_bull - z) / R_bull); tool_helixangel_z[j] = Math.Atan((r_z[j] - Rr) * Math.Tan(i0_rad) / R_bull); psi_z[j] = z / R_bull * Math.Tan(tool_helixangel_z[j]); } else // 圆柱区 { kappa_z[j] = PI / 2.0; tool_helixangel_z[j] = i0_rad; psi_z[j] = 2 * z * Math.Tan(i0_rad) / D; } // 计算微元切削宽度db(z),避免除零 double sin_kap = Math.Sin(kappa_z[j]); if (sin_kap < 1e-6) sin_kap = 1e-6; db_z[j] = da / sin_kap; // 计算微元刃口长度ds(z) ds_z[j] = da / (Math.Cos(tool_helixangel_z[j]) * sin_kap); // 修正径向浸入角,角度归一化 double phi_j_z = phi_j - psi_z[j]; while (phi_j_z > 2 * PI) phi_j_z -= 2 * PI; while (phi_j_z < 0) phi_j_z += 2 * PI; // 计算Px、Qx、Ox Px[m] = (D / 2.0 - Ae) / Math.Tan(phi_j_z - PI / 2.0); double Ox = D / 2.0 * Math.Cos(Theta_st - PI / 2.0) - stj; Qx[m] = (D / 2.0 - stj * Math.Cos(phi_j_z - PI / 2.0)) * Math.Cos(phi_j_z - PI / 2.0); // 判断切削啮合区,计算未变形切屑厚度h if (phi_j_z >= Theta_st && phi_j_z <= Theta_ex) { if (Px[m] >= Ox) { h[m] = D / 2.0 - (D / 2.0 - Ae) / Math.Sin(phi_j_z - PI / 2.0); } else { h[m] = stj * Math.Sin(phi_j_z) * Math.Sin(kappa_z[j]); } // 计算微分切削力 double dft = coefficients.ktc * h[m] * db_z[j] + coefficients.kte * ds_z[j]; double dfr = coefficients.krc * h[m] * db_z[j] + coefficients.kre * ds_z[j]; double dfu = coefficients.kuc * h[m] * db_z[j] + coefficients.kue * ds_z[j]; if (direction == 1) { // 坐标变换矩阵 // 坐标系转换矩阵T double[,] T = { { -Math.Cos(phi_j_z), -Math.Sin(kappa_z[j]) * Math.Sin(phi_j_z), -Math.Cos(kappa_z[j]) * Math.Sin(phi_j_z) }, { Math.Sin(phi_j_z), -Math.Sin(kappa_z[j]) * Math.Cos(phi_j_z), -Math.Cos(kappa_z[j]) * Math.Cos(phi_j_z) }, { 0, Math.Cos(kappa_z[j]), -Math.Sin(kappa_z[j]) } }; // 矩阵乘法计算转换后的微元力 double fxComponent = T[0, 0] * dft + T[0, 1] * dfr + T[0, 2] * dfu; double fyComponent = T[1, 0] * dft + T[1, 1] * dfr + T[1, 2] * dfu; double fzComponent = T[2, 0] * dft + T[2, 1] * dfr + T[2, 2] * dfu; Fx[i] += fxComponent; Fy[i] += fyComponent; Fz[i] += fzComponent; } else if (direction == 2) { // 坐标变换矩阵 double[,] T = { { -Math.Cos(phi_j_z), -Math.Sin(kappa_z[j]) * Math.Sin(phi_j_z), -Math.Cos(kappa_z[j]) * Math.Sin(phi_j_z) }, { Math.Sin(phi_j_z), -Math.Sin(kappa_z[j]) * Math.Cos(phi_j_z), -Math.Cos(kappa_z[j]) * Math.Cos(phi_j_z) }, { 0, -Math.Cos(kappa_z[j]), Math.Sin(kappa_z[j]) } }; double fxComponent = T[0, 0] * dft + T[0, 1] * dfr + T[0, 2] * dfu; double fyComponent = T[1, 0] * dft + T[1, 1] * dfr + T[1, 2] * dfu; double fzComponent = T[2, 0] * dft + T[2, 1] * dfr + T[2, 2] * dfu; Fx[i] += fxComponent; Fy[i] += fyComponent; Fz[i] += fzComponent; } m++; } } n_idx++; } if (direction == 1) { // 坐标转换到工件坐标系 Fx_global[i] = Fy[i]; Fy_global[i] = -Fx[i]; Fz_global[i] = Fz[i]; } else if (direction == 2) { // 坐标转换到工件坐标系 Fx_global[i] = Fy[i]; Fy_global[i] = Fx[i]; Fz_global[i] = -Fz[i]; } } // 计算并设置结果 SetResults(position, Fx_global, Fy_global, Fz_global, K_angle); } private void SetResults(ToolPosition position, double[] Fx_global, double[] Fy_global, double[] Fz_global, int K) { // 计算平均值 double sumFx = 0, sumFy = 0, sumFz = 0; for (int i = 0; i < K; i++) { sumFx += Fx_global[i]; sumFy += Fy_global[i]; sumFz += Fz_global[i]; } double aFx = sumFx / K; double aFy = sumFy / K; double aFz = sumFz / K; // 设置结果到position对象 position.AverageFx = aFx; position.AverageFy = aFy; position.AverageFz = aFz; // 计算最大值 double maxFx = 0, maxFy = 0, maxFz = 0; for (int i = 0; i < K; i++) { if (Math.Abs(Fx_global[i]) > Math.Abs(maxFx)) maxFx = Fx_global[i]; if (Math.Abs(Fy_global[i]) > Math.Abs(maxFy)) maxFy = Fy_global[i]; if (Math.Abs(Fz_global[i]) > Math.Abs(maxFz)) maxFz = Fz_global[i]; } position.MaxFx = maxFx; position.MaxFy = maxFy; position.MaxFz = maxFz; } } }