|
|
|
@@ -6,6 +6,7 @@ |
|
|
|
* 否则示波器上变成方波,三种模式完全无法区分)。 |
|
|
|
|
|
|
|
* @note:目前脉冲输出在低频时和高频时均有毛刺,需要优化 |
|
|
|
* 已解决,原因是逻辑分析仪采样率不够,导致采样点减少,波形有毛刺。 |
|
|
|
*/ |
|
|
|
#include "plsr_accel_curve.h" |
|
|
|
|
|
|
|
@@ -93,13 +94,94 @@ static uint32_t PlsrAccelCurveRampTimeMs(uint32_t f_from, |
|
|
|
return t; |
|
|
|
} |
|
|
|
|
|
|
|
/** 直线:进度千分比 → 形状千分比 */ |
|
|
|
static uint32_t PlsrAccelCurveShapeLinearPermille(uint32_t u) |
|
|
|
{ |
|
|
|
return (u > 1000U) ? 1000U : u; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
* 七段一侧 1:2:1:头尾更圆、中间更陡(相对直线可辨) |
|
|
|
* u∈[0,250]/[750,1000] 为抛物线圆角,中间线性陡段。 |
|
|
|
*/ |
|
|
|
static uint32_t PlsrAccelCurveShapeS7Permille(uint32_t u) |
|
|
|
{ |
|
|
|
uint32_t d; |
|
|
|
uint32_t p; |
|
|
|
|
|
|
|
if (u >= 1000U) |
|
|
|
{ |
|
|
|
return 1000U; |
|
|
|
} |
|
|
|
if (u <= 250UL) |
|
|
|
{ |
|
|
|
p = (8UL * u * u) / (3UL * 1000UL); |
|
|
|
} |
|
|
|
else if (u <= 750UL) |
|
|
|
{ |
|
|
|
p = 167UL + (666UL * (u - 250UL)) / 500UL; |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
d = 1000UL - u; |
|
|
|
p = 1000UL - (8UL * d * d) / (3UL * 1000UL); |
|
|
|
} |
|
|
|
return (p > 1000UL) ? 1000UL : p; |
|
|
|
} |
|
|
|
|
|
|
|
/** O(1):时间进度千分比 → 曲线形状千分比 */ |
|
|
|
static uint32_t PlsrAccelCurveShapePermille(uint32_t u, PlsrAccelMode_e mode) |
|
|
|
{ |
|
|
|
if (mode == PLSR_ACCEL_S) |
|
|
|
{ |
|
|
|
return PlsrAccelCurveShapeS7Permille(u); |
|
|
|
} |
|
|
|
if (mode == PLSR_ACCEL_SINE) |
|
|
|
{ |
|
|
|
//return PlsrAccelCurveShapeSinePermille(u); |
|
|
|
} |
|
|
|
return PlsrAccelCurveShapeLinearPermille(u); |
|
|
|
} |
|
|
|
|
|
|
|
static uint32_t PlsrAccelCurveShape(uint32_t t_ms, uint32_t T_ms, PlsrAccelMode_e mode) |
|
|
|
{ |
|
|
|
uint32_t u; |
|
|
|
|
|
|
|
if ((T_ms == 0U) || (t_ms >= T_ms)) |
|
|
|
{ |
|
|
|
return 1000U; |
|
|
|
} |
|
|
|
u = (t_ms * 1000UL) / T_ms; |
|
|
|
if (u > 1000U) |
|
|
|
{ |
|
|
|
u = 1000U; |
|
|
|
} |
|
|
|
return PlsrAccelCurveShapePermille(u, mode); |
|
|
|
} |
|
|
|
|
|
|
|
static uint32_t PlsrAccelCurveLerp(uint32_t a, uint32_t b, uint32_t ratio_permille) |
|
|
|
{ |
|
|
|
if (ratio_permille >= 1000U) |
|
|
|
{ |
|
|
|
return b; |
|
|
|
} |
|
|
|
if (b >= a) |
|
|
|
{ |
|
|
|
return a + ((b - a) * ratio_permille) / 1000UL; |
|
|
|
} |
|
|
|
return a - ((a - b) * ratio_permille) / 1000UL; |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* 与运行时相同:f(t)=f0+(f1-f0)*t/T(µs),t>=T 时为 f1。 |
|
|
|
* 与运行时相同:f = f0+(f1-f0)*shape(t/T),t>=T 时为 f1。 |
|
|
|
* shape 由 mode 决定;ISR 可用(O(1))。 |
|
|
|
*/ |
|
|
|
static uint32_t PlsrAccelCurveFreqOnRampUs(uint32_t f0, |
|
|
|
uint32_t f1, |
|
|
|
uint32_t t_us, |
|
|
|
uint32_t T_us) |
|
|
|
uint32_t PlsrAccelCurveFreqOnRampUs(uint32_t f0, |
|
|
|
uint32_t f1, |
|
|
|
uint32_t t_us, |
|
|
|
uint32_t T_us, |
|
|
|
PlsrAccelMode_e mode) |
|
|
|
{ |
|
|
|
uint32_t r; |
|
|
|
|
|
|
|
@@ -112,21 +194,18 @@ static uint32_t PlsrAccelCurveFreqOnRampUs(uint32_t f0, |
|
|
|
{ |
|
|
|
r = 1000U; |
|
|
|
} |
|
|
|
if (f1 >= f0) |
|
|
|
{ |
|
|
|
return f0 + ((f1 - f0) * r) / 1000UL; |
|
|
|
} |
|
|
|
return f0 - ((f0 - f1) * r) / 1000UL; |
|
|
|
r = PlsrAccelCurveShapePermille(r, mode); |
|
|
|
return PlsrAccelCurveLerp(f0, f1, r); |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* 直线加减速、脉冲起点锁频时的精确脉冲数(与 ISR 累加方式一致): |
|
|
|
* t=0 取 f0,周期 1/f,再取 f(t)……直到 t>=T。 |
|
|
|
* 不用平均/加权经验公式,改频率后仍与运行时一致。 |
|
|
|
* 脉冲起点锁频递推脉冲数(与 ISR 一致);f(t) 按 mode 形状。 |
|
|
|
* 仅任务/规划上下文;禁止进脉冲 ISR。 |
|
|
|
*/ |
|
|
|
static uint32_t PlsrAccelCurveEstimatePulses(uint32_t f_from, |
|
|
|
uint32_t f_to, |
|
|
|
uint32_t t_ms) |
|
|
|
uint32_t t_ms, |
|
|
|
PlsrAccelMode_e mode) |
|
|
|
{ |
|
|
|
uint32_t T_us; |
|
|
|
uint32_t elapsed_us; |
|
|
|
@@ -146,7 +225,7 @@ static uint32_t PlsrAccelCurveEstimatePulses(uint32_t f_from, |
|
|
|
|
|
|
|
while ((elapsed_us < T_us) && (guard < 2000000UL)) |
|
|
|
{ |
|
|
|
f = PlsrAccelCurveFreqOnRampUs(f_from, f_to, elapsed_us, T_us); |
|
|
|
f = PlsrAccelCurveFreqOnRampUs(f_from, f_to, elapsed_us, T_us, mode); |
|
|
|
if (f < 1U) |
|
|
|
{ |
|
|
|
f = 1U; |
|
|
|
@@ -160,14 +239,13 @@ static uint32_t PlsrAccelCurveEstimatePulses(uint32_t f_from, |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* 拟合斜坡时间 T:使离散直线模型下的脉冲数尽量等于 max_pulses。 |
|
|
|
* (旧逻辑取「Estimate<=max 的最大 T / 优先 t_prefer」,脉冲有余时会提前到终点再持平, |
|
|
|
* 减速末端出现一段平肩/弯曲。) |
|
|
|
* 拟合斜坡时间 T(任务上下文);使离散模型脉冲数尽量等于 max_pulses。 |
|
|
|
*/ |
|
|
|
uint32_t PlsrAccelCurveFitRampTimeMs(uint32_t f_from, |
|
|
|
uint32_t f_to, |
|
|
|
uint32_t max_pulses, |
|
|
|
uint32_t t_prefer_ms) |
|
|
|
uint32_t t_prefer_ms, |
|
|
|
PlsrAccelMode_e mode) |
|
|
|
{ |
|
|
|
uint32_t lo; |
|
|
|
uint32_t hi; |
|
|
|
@@ -188,10 +266,9 @@ uint32_t PlsrAccelCurveFitRampTimeMs(uint32_t f_from, |
|
|
|
return (t_prefer_ms > 0U) ? t_prefer_ms : 1U; |
|
|
|
} |
|
|
|
|
|
|
|
/* 放大上界直到脉冲数够到 max_pulses(或封顶) */ |
|
|
|
hi = (t_prefer_ms > 0U) ? t_prefer_ms : 1U; |
|
|
|
guard = 0U; |
|
|
|
n = PlsrAccelCurveEstimatePulses(f_from, f_to, hi); |
|
|
|
n = PlsrAccelCurveEstimatePulses(f_from, f_to, hi, mode); |
|
|
|
while ((n < max_pulses) && (hi < 120000U) && (guard < 24U)) |
|
|
|
{ |
|
|
|
if (hi > (120000U / 2U)) |
|
|
|
@@ -202,19 +279,19 @@ uint32_t PlsrAccelCurveFitRampTimeMs(uint32_t f_from, |
|
|
|
{ |
|
|
|
hi = hi * 2U; |
|
|
|
} |
|
|
|
n = PlsrAccelCurveEstimatePulses(f_from, f_to, hi); |
|
|
|
n = PlsrAccelCurveEstimatePulses(f_from, f_to, hi, mode); |
|
|
|
guard++; |
|
|
|
} |
|
|
|
|
|
|
|
lo = 1U; |
|
|
|
best = (t_prefer_ms > 0U) ? t_prefer_ms : hi; |
|
|
|
n = PlsrAccelCurveEstimatePulses(f_from, f_to, best); |
|
|
|
n = PlsrAccelCurveEstimatePulses(f_from, f_to, best, mode); |
|
|
|
best_err = (n > max_pulses) ? (n - max_pulses) : (max_pulses - n); |
|
|
|
|
|
|
|
while (lo <= hi) |
|
|
|
{ |
|
|
|
mid = lo + ((hi - lo) / 2UL); |
|
|
|
n = PlsrAccelCurveEstimatePulses(f_from, f_to, mid); |
|
|
|
n = PlsrAccelCurveEstimatePulses(f_from, f_to, mid, mode); |
|
|
|
err = (n > max_pulses) ? (n - max_pulses) : (max_pulses - n); |
|
|
|
if ((err < best_err) || |
|
|
|
((err == best_err) && (t_prefer_ms > 0U) && |
|
|
|
@@ -245,104 +322,6 @@ uint32_t PlsrAccelCurveFitRampTimeMs(uint32_t f_from, |
|
|
|
return best; |
|
|
|
} |
|
|
|
|
|
|
|
static uint32_t PlsrAccelCurveLerp(uint32_t a, uint32_t b, uint32_t ratio_permille) |
|
|
|
{ |
|
|
|
if (ratio_permille >= 1000U) |
|
|
|
{ |
|
|
|
return b; |
|
|
|
} |
|
|
|
if (b >= a) |
|
|
|
{ |
|
|
|
return a + ((b - a) * ratio_permille) / 1000UL; |
|
|
|
} |
|
|
|
return a - ((a - b) * ratio_permille) / 1000UL; |
|
|
|
} |
|
|
|
|
|
|
|
/** 直线:f 对时间线性 */ |
|
|
|
static uint32_t PlsrAccelCurveShapeLinear(uint32_t t_ms, uint32_t T_ms) |
|
|
|
{ |
|
|
|
if ((T_ms == 0U) || (t_ms >= T_ms)) |
|
|
|
{ |
|
|
|
return 1000U; |
|
|
|
} |
|
|
|
return (t_ms * 1000UL) / T_ms; |
|
|
|
} |
|
|
|
|
|
|
|
///** 正弦缓入缓出 */ |
|
|
|
//static uint32_t PlsrAccelCurveShapeSine(uint32_t t_ms, uint32_t T_ms) |
|
|
|
//{ |
|
|
|
// uint32_t x; |
|
|
|
// uint32_t y; |
|
|
|
// uint32_t d; |
|
|
|
// |
|
|
|
// if ((T_ms == 0U) || (t_ms >= T_ms)) |
|
|
|
// { |
|
|
|
// return 1000U; |
|
|
|
// } |
|
|
|
// x = (t_ms * 1000UL) / T_ms; |
|
|
|
// if (x <= 500UL) |
|
|
|
// { |
|
|
|
// y = (2UL * x * x) / 1000UL; |
|
|
|
// } |
|
|
|
// else |
|
|
|
// { |
|
|
|
// d = 1000UL - x; |
|
|
|
// y = 1000UL - (2UL * d * d) / 1000UL; |
|
|
|
// } |
|
|
|
// if (y > 1000UL) |
|
|
|
// { |
|
|
|
// y = 1000UL; |
|
|
|
// } |
|
|
|
// return y; |
|
|
|
//} |
|
|
|
// |
|
|
|
///** |
|
|
|
// * 七段一侧 1:2:1:相对直线,头尾更圆、中间更陡 |
|
|
|
// */ |
|
|
|
//static uint32_t PlsrAccelCurveShapeS7(uint32_t t_ms, uint32_t T_ms) |
|
|
|
//{ |
|
|
|
// uint32_t u; |
|
|
|
// uint32_t d; |
|
|
|
// uint32_t p; |
|
|
|
// |
|
|
|
// if ((T_ms == 0U) || (t_ms >= T_ms)) |
|
|
|
// { |
|
|
|
// return 1000U; |
|
|
|
// } |
|
|
|
// u = (t_ms * 1000UL) / T_ms; |
|
|
|
// if (u <= 250UL) |
|
|
|
// { |
|
|
|
// p = (8UL * u * u) / (3UL * 1000UL); |
|
|
|
// } |
|
|
|
// else if (u <= 750UL) |
|
|
|
// { |
|
|
|
// p = 167UL + (666UL * (u - 250UL)) / 500UL; |
|
|
|
// } |
|
|
|
// else |
|
|
|
// { |
|
|
|
// d = 1000UL - u; |
|
|
|
// p = 1000UL - (8UL * d * d) / (3UL * 1000UL); |
|
|
|
// } |
|
|
|
// if (p > 1000UL) |
|
|
|
// { |
|
|
|
// p = 1000UL; |
|
|
|
// } |
|
|
|
// return p; |
|
|
|
//} |
|
|
|
|
|
|
|
static uint32_t PlsrAccelCurveShape(uint32_t t_ms, uint32_t T_ms, PlsrAccelMode_e mode) |
|
|
|
{ |
|
|
|
// if (mode == PLSR_ACCEL_S) |
|
|
|
// { |
|
|
|
// return PlsrAccelCurveShapeS7(t_ms, T_ms); |
|
|
|
// } |
|
|
|
// if (mode == PLSR_ACCEL_SINE) |
|
|
|
// { |
|
|
|
// return PlsrAccelCurveShapeSine(t_ms, T_ms); |
|
|
|
// } |
|
|
|
return PlsrAccelCurveShapeLinear(t_ms, T_ms); |
|
|
|
} |
|
|
|
|
|
|
|
/** 在 f_cur→f_want 路径上按千分比取点 */ |
|
|
|
static uint32_t PlsrAccelCurveOnPath(uint32_t f_cur, uint32_t f_want, uint32_t permille) |
|
|
|
{ |
|
|
|
@@ -369,7 +348,8 @@ static uint32_t PlsrAccelCurveFitPeak(uint32_t total_pulses, |
|
|
|
uint32_t start_spd_ref, |
|
|
|
uint32_t end_spd_ref, |
|
|
|
uint32_t accel_ms, |
|
|
|
uint32_t decel_ms) |
|
|
|
uint32_t decel_ms, |
|
|
|
PlsrAccelMode_e mode) |
|
|
|
{ |
|
|
|
uint32_t lo = 0U; |
|
|
|
uint32_t hi = 1000U; |
|
|
|
@@ -392,8 +372,8 @@ static uint32_t PlsrAccelCurveFitPeak(uint32_t total_pulses, |
|
|
|
t_d = PlsrAccelCurveRampTimeMs(peak, f_end, default_spd, |
|
|
|
start_spd_ref, end_spd_ref, |
|
|
|
accel_ms, decel_ms); |
|
|
|
n_a = PlsrAccelCurveEstimatePulses(f_cur, peak, t_a); |
|
|
|
n_d = PlsrAccelCurveEstimatePulses(peak, f_end, t_d); |
|
|
|
n_a = PlsrAccelCurveEstimatePulses(f_cur, peak, t_a, mode); |
|
|
|
n_d = PlsrAccelCurveEstimatePulses(peak, f_end, t_d, mode); |
|
|
|
|
|
|
|
if ((n_a + n_d) <= total_pulses) |
|
|
|
{ |
|
|
|
@@ -434,6 +414,7 @@ void PlsrAccelCurvePlan(PlsrAccelPlan_t *plan, |
|
|
|
uint32_t acc_n; |
|
|
|
uint32_t dec_n; |
|
|
|
uint32_t f_peak; |
|
|
|
PlsrAccelMode_e m; |
|
|
|
|
|
|
|
if (plan == (PlsrAccelPlan_t *)0) |
|
|
|
{ |
|
|
|
@@ -444,9 +425,10 @@ void PlsrAccelCurvePlan(PlsrAccelPlan_t *plan, |
|
|
|
f_tgt = PlsrAccelCurveClampFreq(f_tgt); |
|
|
|
f_end = PlsrAccelCurveClampFreq(f_end); |
|
|
|
|
|
|
|
m = (mode > PLSR_ACCEL_SINE) ? PLSR_ACCEL_LINEAR : mode; |
|
|
|
plan->f_cur = f_cur; |
|
|
|
plan->f_end = f_end; |
|
|
|
plan->mode = (mode > PLSR_ACCEL_SINE) ? PLSR_ACCEL_LINEAR : mode; |
|
|
|
plan->mode = m; |
|
|
|
|
|
|
|
f_peak = f_tgt; |
|
|
|
t_acc = PlsrAccelCurveRampTimeMs(f_cur, f_peak, default_spd, |
|
|
|
@@ -455,8 +437,8 @@ void PlsrAccelCurvePlan(PlsrAccelPlan_t *plan, |
|
|
|
t_dec = PlsrAccelCurveRampTimeMs(f_peak, f_end, default_spd, |
|
|
|
start_spd_ref, end_spd_ref, |
|
|
|
accel_ms, decel_ms); |
|
|
|
acc_n = PlsrAccelCurveEstimatePulses(f_cur, f_peak, t_acc); |
|
|
|
dec_n = PlsrAccelCurveEstimatePulses(f_peak, f_end, t_dec); |
|
|
|
acc_n = PlsrAccelCurveEstimatePulses(f_cur, f_peak, t_acc, m); |
|
|
|
dec_n = PlsrAccelCurveEstimatePulses(f_peak, f_end, t_dec, m); |
|
|
|
|
|
|
|
if (total_pulses == 0U) |
|
|
|
{ |
|
|
|
@@ -498,15 +480,15 @@ void PlsrAccelCurvePlan(PlsrAccelPlan_t *plan, |
|
|
|
f_peak = PlsrAccelCurveFitPeak(total_pulses, |
|
|
|
f_cur, f_tgt, f_end, |
|
|
|
default_spd, start_spd_ref, end_spd_ref, |
|
|
|
accel_ms, decel_ms); |
|
|
|
accel_ms, decel_ms, m); |
|
|
|
t_acc = PlsrAccelCurveRampTimeMs(f_cur, f_peak, default_spd, |
|
|
|
start_spd_ref, end_spd_ref, |
|
|
|
accel_ms, decel_ms); |
|
|
|
t_dec = PlsrAccelCurveRampTimeMs(f_peak, f_end, default_spd, |
|
|
|
start_spd_ref, end_spd_ref, |
|
|
|
accel_ms, decel_ms); |
|
|
|
acc_n = PlsrAccelCurveEstimatePulses(f_cur, f_peak, t_acc); |
|
|
|
dec_n = PlsrAccelCurveEstimatePulses(f_peak, f_end, t_dec); |
|
|
|
acc_n = PlsrAccelCurveEstimatePulses(f_cur, f_peak, t_acc, m); |
|
|
|
dec_n = PlsrAccelCurveEstimatePulses(f_peak, f_end, t_dec, m); |
|
|
|
|
|
|
|
if ((acc_n + dec_n) > total_pulses) |
|
|
|
{ |
|
|
|
|