using CaeKnowledge.Data; using System; using ToolPathParser; namespace CaeCuttingForce.FlatendCutter { 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 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 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); double thetaEx = 0.5 * PI; // 切出角 // 计算切厚最大角 double thetaMax = CalculateThetaMax(R, r, a_e, dphi); // 计算相对坐标和距离 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]; 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 = r1[n]; for (int j = 0; j < L; j++) { double z = (j + 1) * AxialIncrement; phi = r1[n] - kb * z; // 角度规范化到 [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 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 * 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 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]; } } }