using CaeKnowledge.Data; using System; using ToolPathParser; namespace CaeCuttingForce.FlatendCutter { internal class ConvexCurvesForce { private const double PI = Math.PI; private const double AngularIncrement = 0.006; // h1 private const double AxialIncrement = 0.006; // da public void CalculateCuttingForce(int direction, ToolPosition position, CuttingForceCoefficients coefficients, ToolParameters toolParams) { // 刀具参数 int N = toolParams.NumberOfTeeth; // 刀齿数 N double r = toolParams.ToolRadius; // 刀具半径 r double beta = toolParams.HelixAngle; // 刀具螺旋角 beta double a_p = position.AxialDepth; // 轴向切削深度 a_p double a_e = position.RadialDepth; // 径向切削深度 a_e double R = position.CurvatureRadius; // 目标曲率半径 R double nrot = position.SpindleSpeed; // 主轴转速 nrot double fd = position.FeedRate; // 进给速度 fd // 计算中间变量 double thetaPit = 2.0 * PI / N; // 齿间角 double kb = Math.Tan(beta * PI / 180.0) / r; // 刀具常数 double trot = 60.0 / nrot; // 主轴旋转周期 double c = fd / (nrot * N); // 每齿进给量 double e = R + r; // 注意:这里是 R+r,不是 R-r double H = 2.0 * PI * e; double nrev = fd / H; double trev = 60.0 / nrev; double krev = trev / trot * N; double dphi = 2.0 * PI / krev; // 计算切入角 double thetaSt = Math.Asin(-((Math.Pow(a_e, 2) + 2.0 * R * a_e - 2.0 * Math.Pow(r, 2) - 2.0 * R * r) / (2.0 * (R + r))) / r); double thetaEx = 0.5 * PI; // 切出角 // 计算切厚最大角 double x1 = (2.0 * Math.Pow(R, 2) * Math.Cos(2.0 * dphi) - 2.0 * R * r - 2.0 * R * a_e + Math.Pow(a_e, 2) * Math.Cos(2.0 * dphi) - 2.0 * Math.Pow(R, 2) - Math.Pow(a_e, 2) + Math.Sin(2.0 * dphi) * Math.Sqrt(-a_e * (2.0 * R + a_e) * (a_e - 2.0 * r) * (2.0 * R + a_e + 2.0 * r)) + 2.0 * R * a_e * Math.Cos(2.0 * dphi) + 2.0 * R * r * Math.Cos(2.0 * dphi)) / (4.0 * Math.Sin(dphi) * (R + r)); double thetaMax = Math.Acos(x1 / r); // 计算相对坐标和距离 double x_rel = position.X - position.Cx; // P_coords - O_coords double y_rel = position.Y - position.Cy; double d = Math.Sqrt(x_rel * x_rel + y_rel * y_rel); // 计算角向和轴向积分数目 int K = (int)Math.Floor(2.0 * PI / AngularIncrement); int L = (int)Math.Floor(a_p / AxialIncrement); // 初始化结果数组 double[] Fx = new double[K]; double[] Fy = new double[K]; double[] Fz = new double[K]; double[] Fx_global = new double[K]; double[] Fy_global = new double[K]; double[] Fz_global = new double[K]; int m = 0; int n = 0; int M = L * N * K; double[] h = new double[M]; double[] R1 = new double[N * K]; // 主计算循环 for (int i = 0; i < K; i++) { double R2 = i * AngularIncrement; // 螺旋槽底部切削刃的接触角 for (int k = 0; k < N; k++) { R1[n] = R2 + k * thetaPit; // 第k个齿当前角度的位置 double phi = R1[n]; for (int j = 0; j < L; j++) { double alph = (j + 1) * AxialIncrement; phi = R1[n] - kb * alph; // 角度规范化到 [0, 2π] while (phi > 2.0 * PI) phi -= 2.0 * PI; while (phi < 0) phi += 2.0 * PI; if (phi >= thetaSt && phi <= thetaEx) { double chipThickness; if (phi <= thetaMax) { // lp计算公式 double sqrt_term = 2.0 * R * a_e - 2.0 * R * r + Math.Pow(R, 2) * Math.Pow(Math.Sin(phi), 2) + Math.Pow(r, 2) * Math.Pow(Math.Sin(phi), 2) + Math.Pow(a_e, 2) - Math.Pow(r, 2) + 2.0 * R * r * Math.Pow(Math.Sin(phi), 2); double lp = R * Math.Sin(phi) - Math.Sqrt(sqrt_term) + r * Math.Sin(phi); chipThickness = r - lp; } else { // lQ计算公式 double lQ = CalculateLQ(R, r, a_e, dphi, phi); chipThickness = r - lQ; } h[m] = chipThickness; // 计算微分切削力 double dft = (coefficients.ktc * chipThickness + coefficients.kte) * AxialIncrement; double dfr = (coefficients.krc * chipThickness + coefficients.kre) * AxialIncrement; double dfu = (coefficients.kuc * chipThickness + coefficients.kue) * AxialIncrement; if (direction == 1) { // 坐标变换矩阵 double[,] T = { { Math.Sin(phi), -Math.Cos(phi), 0 }, { Math.Cos(phi), Math.Sin(phi), 0 }, { 0, 0, 1 } }; 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.Sin(phi), -Math.Cos(phi), 0 }, { Math.Cos(phi), Math.Sin(phi), 0 }, { 0, 0, -1 } }; 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++; } if (direction == 1) { // 坐标转换到工件坐标系 double Fx_from_Y1 = Fy[i] * (x_rel / d); double Fy_from_Y1 = Fy[i] * (y_rel / d); double Fx_from_X1 = Fx[i] * (y_rel / d); double Fy_from_X1 = Fx[i] * (-x_rel / d); Fx_global[i] = Fx_from_X1 + Fx_from_Y1; Fy_global[i] = Fy_from_X1 + Fy_from_Y1; Fz_global[i] = Fz[i]; } else if (direction == 2) { // 坐标转换到工件坐标系 double Fx_from_Y1 = Fy[i] * (x_rel / d); double Fy_from_Y1 = Fy[i] * (y_rel / d); double Fx_from_X1 = Fx[i] * (y_rel / d); double Fy_from_X1 = Fx[i] * (-x_rel / d); Fx_global[i] = Fx_from_X1 + Fx_from_Y1; Fy_global[i] = Fy_from_X1 + Fy_from_Y1; Fz_global[i] = -Fz[i]; } } // 计算并设置结果 SetResults(position, Fx_global, Fy_global, Fz_global, K); } // lQ计算公式 private double CalculateLQ(double R, double r, double a_e, double dphi, double phi) { double term1 = Math.Pow(R, 2) * Math.Cos(dphi + 2.0 * phi); double term2 = 2.0 * R * r; double term3 = Math.Pow(r, 2) * Math.Cos(dphi + 2.0 * phi); double term4 = Math.Pow(R, 2) * Math.Cos(2.0 * phi) / 2.0; double term5 = Math.Pow(r, 2) * Math.Cos(2.0 * phi) / 2.0; double term6 = Math.Pow(R, 2) * Math.Cos(2.0 * dphi + 2.0 * phi) / 2.0; double term7 = Math.Pow(r, 2) * Math.Cos(2.0 * dphi + 2.0 * phi) / 2.0; double term8 = Math.Pow(R, 2); double term9 = Math.Pow(R, 2) * Math.Cos(dphi); double term10 = Math.Pow(r, 2) * Math.Cos(dphi); double term11 = 2.0 * R * r * Math.Cos(dphi + 2.0 * phi); double term12 = R * r * Math.Cos(2.0 * phi); double term13 = R * r * Math.Cos(2.0 * dphi + 2.0 * phi); double term14 = 2.0 * R * r * Math.Cos(dphi); double sqrtContent = term1 - term2 + term3 - term4 - term5 - term6 - term7 - term8 + term9 + term10 + term11 - term12 - term13 + term14; double lQ = Math.Sqrt(sqrtContent) - R * Math.Sin(dphi + phi) - r * Math.Sin(dphi + phi) + R * Math.Sin(phi) + r * Math.Sin(phi); return lQ; } 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]; } position.AverageFx = sumFx / K; position.AverageFy = sumFy / K; position.AverageFz = sumFz / K; // 计算最大值 double maxAbsFx = 0, maxAbsFy = 0, maxAbsFz = 0; int idxFx = 0, idxFy = 0, idxFz = 0; for (int i = 0; i < K; i++) { if (Math.Abs(Fx_global[i]) > maxAbsFx) { maxAbsFx = Math.Abs(Fx_global[i]); idxFx = i; } if (Math.Abs(Fy_global[i]) > maxAbsFy) { maxAbsFy = Math.Abs(Fy_global[i]); idxFy = i; } if (Math.Abs(Fz_global[i]) > maxAbsFz) { maxAbsFz = Math.Abs(Fz_global[i]); idxFz = i; } } position.MaxFx = Fx_global[idxFx]; position.MaxFy = Fy_global[idxFy]; position.MaxFz = Fz_global[idxFz]; } } }