Files
wg_cpso/CaeCuttingForce/FlatendCutter/ConcaveCurvesForce.cs

300 lines
12 KiB
C#
Raw Normal View History

2026-03-25 18:20:24 +08:00
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];
}
}
}