353 lines
15 KiB
C#
353 lines
15 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.Threading.Tasks;
|
|
using ClassicalCuttingForce;
|
|
using ToolPathParser;
|
|
|
|
namespace ClassicalCuttingForce
|
|
{
|
|
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 R_bull = toolParams.ArcRadius; // 环形圆弧半径(mm)
|
|
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 beta_rad = beta * PI / 180.0; // 螺旋角转换为弧度
|
|
double Rr = r - R_bull; // 径向偏移量(mm)
|
|
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) + 0.5 * PI;
|
|
|
|
double thetaEx = PI; // 切出角
|
|
|
|
// 计算切厚最大角
|
|
double thetaMax = CalculateThetaMax(R, r, a_e, dphi) + 0.5 * PI;
|
|
|
|
// 计算相对坐标和距离
|
|
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];
|
|
|
|
// 环形刀轴向几何参数数组
|
|
double[] r_z = new double[L]; // z处的刀具半径
|
|
double[] kappa_z = new double[L]; // z处的轴向浸入角(rad)
|
|
double[] psi_z = new double[L]; // z处的径向滞后角(rad)
|
|
double[] db_z = new double[L]; // z处的微元切削宽度(mm)
|
|
double[] ds_z = new double[L]; // z处的微元刃口长度(mm)
|
|
double[] tool_helixangel_z = new double[L];// z处的螺旋角(rad)
|
|
|
|
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_j = r1[n];
|
|
|
|
for (int j = 0; j < L; j++)
|
|
{
|
|
double z = (j + 1) * AxialIncrement;// 当前轴向高度(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] = r;
|
|
}
|
|
|
|
// 计算轴向浸入角、螺旋角、径向滞后角(分区)
|
|
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(beta_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] = beta_rad;
|
|
psi_z[j] = ( z * Math.Tan(beta_rad)) / r;
|
|
}
|
|
|
|
// 计算微元切削宽度db(z),避免除零
|
|
double sin_kap = Math.Sin(kappa_z[j]);
|
|
if (sin_kap < 1e-6)
|
|
sin_kap = 1e-6;
|
|
db_z[j] = AxialIncrement / sin_kap;
|
|
|
|
// 计算微元刃口长度ds(z)
|
|
ds_z[j] = AxialIncrement / (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;
|
|
|
|
|
|
if (phi_j_z >= thetaSt && phi_j_z <= thetaEx)
|
|
{
|
|
double chipThickness;
|
|
double phi = phi_j_z - 0.5 * PI;
|
|
|
|
if (phi_j_z <= 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 * 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++;
|
|
}
|
|
|
|
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];
|
|
}
|
|
}
|
|
|
|
|
|
|
|
}
|