Files
wg_cpso/CaeCuttingForce/ToroidalCutter/LineForce.cs

251 lines
11 KiB
C#
Raw Normal View History

2026-03-25 18:20:24 +08:00
using CaeKnowledge.Data;
using System;
using ToolPathParser;
namespace CaeCuttingForce.ToroidalCutter
{
public class LineForce
{
private const double PI = Math.PI;
private const double h1 = 0.006; // h1
private const double da = 0.006; // da
public void CalculateCuttingForce(int direction, ToolPosition position, CuttingForceCoefficients coefficients, ToolParameters toolParams)
{
// 刀具参数
int N = toolParams.NumberOfTeeth; // 刀齿数 N
double D = toolParams.ToolRadius * 2; // 刀具直径
double i0 = toolParams.HelixAngle; // 刀具螺旋角
double R_bull = toolParams.ArcRadius; // 环形圆弧半径(mm)
double Ap = position.AxialDepth; // 轴向切削深度 Ap
double Ae = position.RadialDepth; // 径向切削深度 Ae
double nrot = position.SpindleSpeed; // 主轴转速 n
double fd = position.FeedRate; // 进给速度 fd
// 计算中间变量
double Theta_pit = 2.0 * PI / N; // 齿间角(rad)
double i0_rad = i0 * PI / 180.0; // 螺旋角转换为弧度
double Rr = D / 2.0 - R_bull; // 径向偏移量(mm)
double stj = fd / (N * nrot); // 每齿进给量(mm/tooth)
// 计算切入角和切出角
double Theta_st = Math.Acos(Ae / (D / 2.0) - 1.0); // 切入角(rad)
double Theta_ex = PI; // 切出角
// 积分步数计算
int K_angle = (int)Math.Floor(2.0 * PI / h1); // 角向积分步数
int L_axial = (int)Math.Round(Ap / da); // 轴向积分步数(四舍五入)
L_axial = Math.Max(L_axial, 1);
// 初始化结果数组
double[] Fx = new double[K_angle];
double[] Fy = new double[K_angle];
double[] Fz = new double[K_angle];
double[] Fx_global = new double[K_angle];
double[] Fy_global = new double[K_angle];
double[] Fz_global = new double[K_angle];
// 环形刀轴向几何参数数组
double[] r_z = new double[L_axial]; // z处的刀具半径
double[] kappa_z = new double[L_axial]; // z处的轴向浸入角(rad)
double[] psi_z = new double[L_axial]; // z处的径向滞后角(rad)
double[] db_z = new double[L_axial]; // z处的微元切削宽度(mm)
double[] ds_z = new double[L_axial]; // z处的微元刃口长度(mm)
double[] tool_helixangel_z = new double[L_axial];// z处的螺旋角(rad)
// 辅助数组
int M = L_axial * N * K_angle;
double[] h = new double[M];
double[] Px = new double[M];
double[] Qx = new double[M];
double[] R1 = new double[N * K_angle];
int m = 0;
int n_idx = 0;
// 主计算循环
// 三重循环计算切削力(角向→刀齿→轴向)
for (int i = 0; i < K_angle; i++)
{
double phi_i = i * h1; // 第i个角向位置的基础径向浸入角(rad)
for (int k = 0; k < N; k++)
{
// 第k个刀齿的基础径向浸入角
R1[n_idx] = phi_i + k * Theta_pit;
double phi_j = R1[n_idx];
for (int j = 0; j < L_axial; j++)
{
double z = (j + 1) * da; // 当前轴向高度(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] = D / 2.0;
}
// 计算轴向浸入角、螺旋角、径向滞后角(分区)
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(i0_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] = i0_rad;
psi_z[j] = 2 * z * Math.Tan(i0_rad) / D;
}
// 计算微元切削宽度db(z),避免除零
double sin_kap = Math.Sin(kappa_z[j]);
if (sin_kap < 1e-6)
sin_kap = 1e-6;
db_z[j] = da / sin_kap;
// 计算微元刃口长度ds(z)
ds_z[j] = da / (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;
// 计算Px、Qx、Ox
Px[m] = (D / 2.0 - Ae) / Math.Tan(phi_j_z - PI / 2.0);
double Ox = D / 2.0 * Math.Cos(Theta_st - PI / 2.0) - stj;
Qx[m] = (D / 2.0 - stj * Math.Cos(phi_j_z - PI / 2.0)) * Math.Cos(phi_j_z - PI / 2.0);
// 判断切削啮合区计算未变形切屑厚度h
if (phi_j_z >= Theta_st && phi_j_z <= Theta_ex)
{
if (Px[m] >= Ox)
{
h[m] = D / 2.0 - (D / 2.0 - Ae) / Math.Sin(phi_j_z - PI / 2.0);
}
else
{
h[m] = stj * Math.Sin(phi_j_z) * Math.Sin(kappa_z[j]);
}
// 计算微分切削力
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_idx++;
}
if (direction == 1)
{
// 坐标转换到工件坐标系
Fx_global[i] = Fy[i];
Fy_global[i] = -Fx[i];
Fz_global[i] = Fz[i];
}
else if (direction == 2)
{
// 坐标转换到工件坐标系
Fx_global[i] = Fy[i];
Fy_global[i] = Fx[i];
Fz_global[i] = -Fz[i];
}
}
// 计算并设置结果
SetResults(position, Fx_global, Fy_global, Fz_global, K_angle);
}
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];
}
double aFx = sumFx / K;
double aFy = sumFy / K;
double aFz = sumFz / K;
// 设置结果到position对象
position.AverageFx = aFx;
position.AverageFy = aFy;
position.AverageFz = aFz;
// 计算最大值
double maxFx = 0, maxFy = 0, maxFz = 0;
for (int i = 0; i < K; i++)
{
if (Math.Abs(Fx_global[i]) > Math.Abs(maxFx)) maxFx = Fx_global[i];
if (Math.Abs(Fy_global[i]) > Math.Abs(maxFy)) maxFy = Fy_global[i];
if (Math.Abs(Fz_global[i]) > Math.Abs(maxFz)) maxFz = Fz_global[i];
}
position.MaxFx = maxFx;
position.MaxFy = maxFy;
position.MaxFz = maxFz;
}
}
}