289 lines
12 KiB
C#
289 lines
12 KiB
C#
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];
|
||
}
|
||
|
||
}
|
||
}
|