Files
wg_cpso/CuttingForce2/LineForce.cs
2026-03-25 18:20:24 +08:00

255 lines
11 KiB
C#
Raw Permalink 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 System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using ClassicalCuttingForce;
using ToolPathParser;
namespace ClassicalCuttingForce
{
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;
}
}
}