using CaeKnowledge.Data; using System; using ToolPathParser; namespace CaeCuttingForce.ToroidalCutter { public class ConcaveCurvesForce { 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; // 刀齿数 double r = toolParams.ToolRadius; // 刀具半径 double beta = toolParams.HelixAngle; // 刀具螺旋角 double R_bull = toolParams.ArcRadius; // 环形圆弧半径(mm) double a_e = position.RadialDepth; // 径向切削深度 double a_p = position.AxialDepth; // 径向切削深度 double R = position.CurvatureRadius; // 目标曲率半径 double nrot = position.SpindleSpeed; // 主轴转速 double fd = position.FeedRate; // 进给速度 double thetaPit = 2.0 * PI / N; // 齿间角 double beta_rad = beta * PI / 180.0; // 螺旋角转换为弧度 double Rr = r - R_bull; // 径向偏移量(mm) double kb = Math.Tan(beta * PI / 180.0) / r; // 刀具常数 double trot = 60.0 / nrot; // 主轴旋转周期 double c = fd / (nrot * N); // 每齿进给量 double e = 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 - 2.0 * r)) / r) + 0.5 * PI; double thetaEx = PI; // 切出角 // 计算切厚最大角 double thetaMax = CalculateThetaMax(R, r, a_e, dphi) + 0.5 * PI; // 计算相对坐标和距离 double xRel = position.Cx - position.X; double yRel = position.Cy - position.Y; double distance = Math.Sqrt(xRel * xRel + yRel * yRel); // 计算角向和轴向积分数目 int K = (int)(2.0 * PI / AngularIncrement); int L = (int)(a_p / AxialIncrement); // 初始化结果数组 double[] fx = new double[K]; double[] fy = new double[K]; double[] fz = new double[K]; double[] fxGlobal = new double[K]; double[] fyGlobal = new double[K]; double[] fzGlobal = new double[K]; // 环形刀轴向几何参数数组 double[] r_z = new double[L]; // z处的刀具半径 double[] kappa_z = new double[L]; // z处的轴向浸入角(rad) double[] psi_z = new double[L]; // z处的径向滞后角(rad) double[] db_z = new double[L]; // z处的微元切削宽度(mm) double[] ds_z = new double[L]; // z处的微元刃口长度(mm) double[] tool_helixangel_z = new double[L];// z处的螺旋角(rad) int m = 0; int n = 0; int totalSteps = L * N * K; double[] h = new double[totalSteps]; 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_j = r1[n]; for (int j = 0; j < L; j++) { double z = (j + 1) * AxialIncrement;// 当前轴向高度(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] = r; } // 计算轴向浸入角、螺旋角、径向滞后角(分区) 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(beta_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] = beta_rad; psi_z[j] = z * Math.Tan(beta_rad) / r; } // 计算微元切削宽度db(z),避免除零 double sin_kap = Math.Sin(kappa_z[j]); if (sin_kap < 1e-6) sin_kap = 1e-6; db_z[j] = AxialIncrement / sin_kap; // 计算微元刃口长度ds(z) ds_z[j] = AxialIncrement / (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; if (phi_j_z >= thetaSt && phi_j_z <= thetaEx) { double chipThickness; double phi = phi_j_z - 0.5 * PI; if (phi_j_z <= thetaMax) { // lp计算公式 double lp = Math.Sqrt( 2.0 * R * r - 2.0 * R * a_e + 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)) - R * Math.Sin(phi) + 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 * 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++; } if (direction == 1) { // 坐标转换到工件坐标系 double fxFromY1 = fy[i] * (xRel / distance); double fyFromY1 = fy[i] * (yRel / distance); double fxFromX1 = fx[i] * (yRel / distance); double fyFromX1 = fx[i] * (-xRel / distance); fxGlobal[i] = fxFromX1 + fxFromY1; fyGlobal[i] = fyFromX1 + fyFromY1; fzGlobal[i] = fz[i]; } else if (direction == 2) { // 坐标转换到工件坐标系 double fxFromY1 = fy[i] * (xRel / distance); double fyFromY1 = fy[i] * (yRel / distance); double fxFromX1 = fx[i] * (-yRel / distance); double fyFromX1 = fx[i] * (xRel / distance); fxGlobal[i] = fxFromX1 + fxFromY1; fyGlobal[i] = fyFromX1 + fyFromY1; fzGlobal[i] = -fz[i]; } } // 计算并设置结果 SetResults(position, fxGlobal, fyGlobal, fzGlobal, K); } private double CalculateThetaMax(double R, double r, double a_e, double dphi) { double numerator = 2.0 * R * a_e + 2.0 * R * r + 2.0 * Math.Pow(R, 2) * Math.Cos(2.0 * dphi) + Math.Pow(a_e, 2) * Math.Cos(2.0 * dphi) + Math.Sin(2.0 * dphi) * Math.Sqrt( a_e * (a_e - 2.0 * r) * (2.0 * R - a_e) * (a_e - 2.0 * R + 2.0 * r)) - 2.0 * Math.Pow(R, 2) - Math.Pow(a_e, 2) - 2.0 * R * a_e * Math.Cos(2.0 * dphi) - 2.0 * R * r * Math.Cos(2.0 * dphi); double denominator = 4.0 * Math.Sin(dphi) * (R - r); return Math.Acos(numerator / denominator) / r; } 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(phi) + r * Math.Sin(phi) - R * Math.Sin(dphi - phi) + r * Math.Sin(dphi - phi); return lQ; } private void SetResults(ToolPosition position, double[] fxGlobal, double[] fyGlobal, double[] fzGlobal, int K) { // 计算平均值 double sumFx = 0, sumFy = 0, sumFz = 0; for (int i = 0; i < K; i++) { sumFx += fxGlobal[i]; sumFy += fyGlobal[i]; sumFz += fzGlobal[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(fxGlobal[i]) > maxAbsFx) { maxAbsFx = Math.Abs(fxGlobal[i]); idxFx = i; } if (Math.Abs(fyGlobal[i]) > maxAbsFy) { maxAbsFy = Math.Abs(fyGlobal[i]); idxFy = i; } if (Math.Abs(fzGlobal[i]) > maxAbsFz) { maxAbsFz = Math.Abs(fzGlobal[i]); idxFz = i; } } position.MaxFx = fxGlobal[idxFx]; position.MaxFy = fyGlobal[idxFy]; position.MaxFz = fzGlobal[idxFz]; } } }