Files
wg_cpso/CaeCuttingForce/FlatendCutter/ConvexCurvesForce.cs
2026-03-25 18:20:24 +08:00

289 lines
12 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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];
}
}
}