251 lines
11 KiB
C#
251 lines
11 KiB
C#
|
|
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;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
|
|||
|
|
|