|
|
|
@@ -1,6 +1,6 @@ |
|
|
|
/** |
|
|
|
* @file plsr_accel_curve.c |
|
|
|
* @brief 脉冲域规划/取频:直线 frequency_hz^2=start_frequency_hz^2±2an;S/正弦按时间轴剖面 |
|
|
|
* @brief 脉冲域规划/取频:加速 f^2=start^2+2an;减速 f^2=end^2+2ak(k=N…1);S/正弦时间轴 |
|
|
|
* |
|
|
|
* ============================================================================ |
|
|
|
* 【阅读指南 — 先看这个再往下翻 if/else】 |
|
|
|
@@ -20,7 +20,8 @@ |
|
|
|
* decel_rate_hz_per_s 减速斜率 Hz/s ≈ default_speed*1000/deceleration_time_ms |
|
|
|
* |
|
|
|
* 二、三种曲线模式(curve_mode) |
|
|
|
* LINEAR 直线:f_n = sqrt(start_frequency_hz^2 ± 2*a*pulse_count);ISR 里 SquareStep ±1Hz 逼近 |
|
|
|
* LINEAR 加速:f=sqrt(start^2+2a·n);减速:从终点往峰值加 |
|
|
|
* f=sqrt(end^2+2a·k),k=N…1(与加速对称,勿从峰值减计数) |
|
|
|
* S 时间域 jerk 梯形;规划/ISR 用离散 Δt=1/frequency_hz 仿真;ISR 查预建表 |
|
|
|
* SINE raised-cosine 时间剖面;同上,查预建表 |
|
|
|
* |
|
|
|
@@ -557,48 +558,65 @@ static uint32_t PlsrAccelCurveCalculateRampPulses(uint32_t start_frequency_hz, u |
|
|
|
return PlsrAccelCurveCalculateLinearRampPulses(start_frequency_hz, end_frequency_hz, acceleration_hz_per_s); |
|
|
|
} |
|
|
|
|
|
|
|
/** 直线:frequency_hz = sqrt(start_frequency_hz^2 + 2*a*pulse_count),升到/降到不超过 target_limit_hz 方向 */ |
|
|
|
/** |
|
|
|
* 直线取频。 |
|
|
|
* 加速(rising):f = sqrt(start^2 + 2·a·pulse_count),不超过 target_limit |
|
|
|
* 减速(!rising):从终点往峰值加 — pulse_count 为相内已完成步数(0…N-1)时 |
|
|
|
* k = N - pulse_count,f = sqrt(end_limit^2 + 2·a·k),不超过 start(峰值) |
|
|
|
* 例 N=5:第 1 个减速拍 k=5→end^2+10a;末拍 k=1→end^2+2a |
|
|
|
*/ |
|
|
|
static uint32_t PlsrAccelCurveLinearFrequencyAtPulse(uint32_t start_frequency_hz, uint32_t acceleration_hz_per_s, |
|
|
|
uint32_t pulse_count, uint8_t frequency_rising, |
|
|
|
uint32_t target_limit_hz) |
|
|
|
uint32_t target_limit_hz, |
|
|
|
uint32_t phase_total_pulses) |
|
|
|
{ |
|
|
|
uint64_t squared_frequency; |
|
|
|
uint32_t frequency_hz; |
|
|
|
uint32_t k_from_end; |
|
|
|
|
|
|
|
if (pulse_count == 0U) |
|
|
|
{ |
|
|
|
frequency_hz = start_frequency_hz; |
|
|
|
} |
|
|
|
else if (acceleration_hz_per_s == 0U) |
|
|
|
if (acceleration_hz_per_s == 0U) |
|
|
|
{ |
|
|
|
frequency_hz = target_limit_hz; |
|
|
|
frequency_hz = frequency_rising != 0U ? target_limit_hz : start_frequency_hz; |
|
|
|
return PlsrAccelCurveClampFrequencyHz((frequency_hz < 1U) ? 1U : frequency_hz); |
|
|
|
} |
|
|
|
else |
|
|
|
|
|
|
|
if (frequency_rising != 0U) |
|
|
|
{ |
|
|
|
squared_frequency = (uint64_t)start_frequency_hz * (uint64_t)start_frequency_hz; |
|
|
|
if (frequency_rising != 0U) |
|
|
|
if (pulse_count == 0U) |
|
|
|
{ |
|
|
|
frequency_hz = start_frequency_hz; |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
squared_frequency += 2ULL * (uint64_t)acceleration_hz_per_s * (uint64_t)pulse_count; |
|
|
|
squared_frequency = (uint64_t)start_frequency_hz * (uint64_t)start_frequency_hz |
|
|
|
+ (2ULL * (uint64_t)acceleration_hz_per_s * (uint64_t)pulse_count); |
|
|
|
frequency_hz = PlsrAccelCurveIntegerSquareRoot(squared_frequency); |
|
|
|
if (frequency_hz > target_limit_hz) |
|
|
|
{ |
|
|
|
frequency_hz = target_limit_hz; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
/* 减速:以终点 target_limit_hz 为 f0,k 从 N 倒数到 1 */ |
|
|
|
if (phase_total_pulses < 1U) |
|
|
|
{ |
|
|
|
frequency_hz = target_limit_hz; |
|
|
|
} |
|
|
|
else if (pulse_count >= phase_total_pulses) |
|
|
|
{ |
|
|
|
frequency_hz = target_limit_hz; |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
uint64_t frequency_drop = 2ULL * (uint64_t)acceleration_hz_per_s * (uint64_t)pulse_count; |
|
|
|
if (frequency_drop >= squared_frequency) |
|
|
|
k_from_end = phase_total_pulses - pulse_count; |
|
|
|
squared_frequency = (uint64_t)target_limit_hz * (uint64_t)target_limit_hz |
|
|
|
+ (2ULL * (uint64_t)acceleration_hz_per_s * (uint64_t)k_from_end); |
|
|
|
frequency_hz = PlsrAccelCurveIntegerSquareRoot(squared_frequency); |
|
|
|
if (frequency_hz > start_frequency_hz) |
|
|
|
{ |
|
|
|
frequency_hz = target_limit_hz; |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
frequency_hz = PlsrAccelCurveIntegerSquareRoot(squared_frequency - frequency_drop); |
|
|
|
if (frequency_hz < target_limit_hz) |
|
|
|
{ |
|
|
|
frequency_hz = target_limit_hz; |
|
|
|
} |
|
|
|
frequency_hz = start_frequency_hz; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
@@ -1015,7 +1033,8 @@ uint32_t PlsrAccelCurveFreqAtPulse(const PlsrAccelPlan_t *plan, |
|
|
|
uint32_t selected_rate_hz_per_s = (frequency_rising != 0U) ? plan->accel_rate_hz_per_s : plan->decel_rate_hz_per_s; |
|
|
|
|
|
|
|
frequency_hz = PlsrAccelCurveLinearFrequencyAtPulse(plan->start_frequency_hz, selected_rate_hz_per_s, |
|
|
|
completed_segment_pulses, frequency_rising, plan->target_frequency_hz); |
|
|
|
completed_segment_pulses, frequency_rising, plan->target_frequency_hz, |
|
|
|
plan->accel_pulses); |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
@@ -1059,7 +1078,8 @@ uint32_t PlsrAccelCurveFreqAtPulse(const PlsrAccelPlan_t *plan, |
|
|
|
uint32_t selected_rate_hz_per_s = (frequency_rising != 0U) ? plan->accel_rate_hz_per_s : plan->decel_rate_hz_per_s; |
|
|
|
|
|
|
|
frequency_hz = PlsrAccelCurveLinearFrequencyAtPulse(plan->target_frequency_hz, selected_rate_hz_per_s, |
|
|
|
pulse_count, frequency_rising, plan->end_frequency_hz); |
|
|
|
pulse_count, frequency_rising, plan->end_frequency_hz, |
|
|
|
plan->decel_pulses); |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
@@ -1234,18 +1254,34 @@ static uint32_t PlsrAccelRuntimeBuildFrequencyTable(PlsrAccelRuntime_t *runtime, |
|
|
|
} |
|
|
|
if (simulation.is_active == 0U) |
|
|
|
{ |
|
|
|
while ((loop_index + 1U) < runtime->total_pulses) |
|
|
|
/* 提前到终点:中间格保持最后仿真值,仅最后一格钉 end(勿 end±1 垫平台) */ |
|
|
|
{ |
|
|
|
loop_index++; |
|
|
|
table_index = loop_index / table_stride; |
|
|
|
if (table_index >= table_capacity) |
|
|
|
uint32_t hold_hz = simulation.current_frequency_hz; |
|
|
|
|
|
|
|
if (hold_hz < 1U) |
|
|
|
{ |
|
|
|
table_index = table_capacity - 1U; |
|
|
|
hold_hz = 1U; |
|
|
|
} |
|
|
|
frequency_table[table_index] = runtime->end_frequency_hz; |
|
|
|
if ((table_index + 1U) > table_length) |
|
|
|
while ((loop_index + 1U) < runtime->total_pulses) |
|
|
|
{ |
|
|
|
table_length = table_index + 1U; |
|
|
|
loop_index++; |
|
|
|
table_index = loop_index / table_stride; |
|
|
|
if (table_index >= table_capacity) |
|
|
|
{ |
|
|
|
table_index = table_capacity - 1U; |
|
|
|
} |
|
|
|
if ((loop_index + 1U) >= runtime->total_pulses) |
|
|
|
{ |
|
|
|
frequency_table[table_index] = runtime->end_frequency_hz; |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
frequency_table[table_index] = hold_hz; |
|
|
|
} |
|
|
|
if ((table_index + 1U) > table_length) |
|
|
|
{ |
|
|
|
table_length = table_index + 1U; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
break; |
|
|
|
@@ -1383,70 +1419,27 @@ void PlsrAccelBeginConstantSpeed(PlsrAccelRuntime_t *runtime, |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* 直线:用上一拍 frequency_hz ±1 逼近 target_frequency_squared,不全量开方。 |
|
|
|
* 低频 frequency_difference_hz/dn 大时循环次数多,但周期也长,ISR 仍可承受。 |
|
|
|
* 直线 ISR 取频(开方,与规划公式一致)。 |
|
|
|
* 加速:f = sqrt(start^2 + 2·a·completed) |
|
|
|
* 减速:k = total-completed+1,f = sqrt(end^2 + 2·a·k)(从终点往峰值加) |
|
|
|
*/ |
|
|
|
static uint32_t PlsrAccelNextFrequencyLinear(PlsrAccelRuntime_t *runtime) |
|
|
|
{ |
|
|
|
uint64_t target_frequency_squared; |
|
|
|
uint64_t current_frequency_squared; |
|
|
|
uint64_t start_frequency_squared; |
|
|
|
uint32_t frequency_hz; |
|
|
|
uint32_t iteration_guard; |
|
|
|
uint32_t k_from_end; |
|
|
|
|
|
|
|
start_frequency_squared = (uint64_t)runtime->start_frequency_hz * (uint64_t)runtime->start_frequency_hz; |
|
|
|
if (runtime->frequency_rising != 0U) |
|
|
|
if (runtime->acceleration_hz_per_s == 0U) |
|
|
|
{ |
|
|
|
target_frequency_squared = start_frequency_squared + (2ULL * (uint64_t)runtime->acceleration_hz_per_s * (uint64_t)runtime->completed_pulses); |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
uint64_t frequency_drop = 2ULL * (uint64_t)runtime->acceleration_hz_per_s * (uint64_t)runtime->completed_pulses; |
|
|
|
target_frequency_squared = (frequency_drop >= start_frequency_squared) ? 0ULL : (start_frequency_squared - frequency_drop); |
|
|
|
} |
|
|
|
|
|
|
|
frequency_hz = runtime->current_frequency_hz; |
|
|
|
if (frequency_hz < 1U) |
|
|
|
{ |
|
|
|
frequency_hz = 1U; |
|
|
|
} |
|
|
|
|
|
|
|
for (iteration_guard = 0U; iteration_guard < 2048U; iteration_guard++) |
|
|
|
{ |
|
|
|
current_frequency_squared = (uint64_t)frequency_hz * (uint64_t)frequency_hz; |
|
|
|
if (runtime->frequency_rising != 0U) |
|
|
|
{ |
|
|
|
if ((frequency_hz < runtime->end_frequency_hz) && (((uint64_t)(frequency_hz + 1U) * (uint64_t)(frequency_hz + 1U)) <= target_frequency_squared)) |
|
|
|
{ |
|
|
|
frequency_hz++; |
|
|
|
continue; |
|
|
|
} |
|
|
|
if ((frequency_hz > 1U) && (current_frequency_squared > target_frequency_squared)) |
|
|
|
{ |
|
|
|
frequency_hz--; |
|
|
|
continue; |
|
|
|
} |
|
|
|
break; |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
if ((frequency_hz > runtime->end_frequency_hz) && (current_frequency_squared > target_frequency_squared)) |
|
|
|
{ |
|
|
|
frequency_hz--; |
|
|
|
continue; |
|
|
|
} |
|
|
|
if ((frequency_hz < 100000U) && |
|
|
|
(((uint64_t)(frequency_hz + 1U) * (uint64_t)(frequency_hz + 1U)) < target_frequency_squared)) |
|
|
|
{ |
|
|
|
frequency_hz++; |
|
|
|
continue; |
|
|
|
} |
|
|
|
break; |
|
|
|
} |
|
|
|
return PlsrAccelCurveClampFrequencyHz(runtime->end_frequency_hz); |
|
|
|
} |
|
|
|
|
|
|
|
if (runtime->frequency_rising != 0U) |
|
|
|
{ |
|
|
|
target_frequency_squared = |
|
|
|
(uint64_t)runtime->start_frequency_hz * (uint64_t)runtime->start_frequency_hz |
|
|
|
+ (2ULL * (uint64_t)runtime->acceleration_hz_per_s * (uint64_t)runtime->completed_pulses); |
|
|
|
frequency_hz = PlsrAccelCurveIntegerSquareRoot(target_frequency_squared); |
|
|
|
if (frequency_hz > runtime->end_frequency_hz) |
|
|
|
{ |
|
|
|
frequency_hz = runtime->end_frequency_hz; |
|
|
|
@@ -1454,11 +1447,28 @@ static uint32_t PlsrAccelNextFrequencyLinear(PlsrAccelRuntime_t *runtime) |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
if (frequency_hz < runtime->end_frequency_hz) |
|
|
|
if (runtime->total_pulses < 1U) |
|
|
|
{ |
|
|
|
frequency_hz = runtime->end_frequency_hz; |
|
|
|
k_from_end = 1U; |
|
|
|
} |
|
|
|
else if (runtime->completed_pulses >= runtime->total_pulses) |
|
|
|
{ |
|
|
|
k_from_end = 1U; |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
k_from_end = runtime->total_pulses - runtime->completed_pulses + 1U; |
|
|
|
} |
|
|
|
target_frequency_squared = |
|
|
|
(uint64_t)runtime->end_frequency_hz * (uint64_t)runtime->end_frequency_hz |
|
|
|
+ (2ULL * (uint64_t)runtime->acceleration_hz_per_s * (uint64_t)k_from_end); |
|
|
|
frequency_hz = PlsrAccelCurveIntegerSquareRoot(target_frequency_squared); |
|
|
|
if (frequency_hz > runtime->start_frequency_hz) |
|
|
|
{ |
|
|
|
frequency_hz = runtime->start_frequency_hz; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if (frequency_hz < 1U) |
|
|
|
{ |
|
|
|
frequency_hz = 1U; |
|
|
|
@@ -1625,52 +1635,17 @@ uint32_t PlsrAccelNextFrequency(PlsrAccelRuntime_t *runtime) |
|
|
|
} |
|
|
|
|
|
|
|
if ((runtime->total_pulses > 0U) && (runtime->completed_pulses >= runtime->total_pulses)) |
|
|
|
{ |
|
|
|
runtime->current_frequency_hz = runtime->end_frequency_hz; |
|
|
|
runtime->is_active = 0U; |
|
|
|
} |
|
|
|
else if (runtime->curve_mode == PLSR_ACCEL_LINEAR) |
|
|
|
{ |
|
|
|
/* |
|
|
|
* 未到本相最后一拍:不要钳到 end。 |
|
|
|
* 否则减速在 n=N-1 就落到止速,ARPE 下会表现为末两拍同频。 |
|
|
|
* 直线减速末步已是 sqrt(end^2+2a),不要再钉成 end(否则与「从终点往上加」不一致)。 |
|
|
|
* S/正弦 / 加速相:仍钉到相终点。 |
|
|
|
*/ |
|
|
|
if (runtime->frequency_rising == 0U) |
|
|
|
if (!((runtime->curve_mode == PLSR_ACCEL_LINEAR) && |
|
|
|
(runtime->frequency_rising == 0U))) |
|
|
|
{ |
|
|
|
if ((runtime->current_frequency_hz <= runtime->end_frequency_hz) && |
|
|
|
(runtime->end_frequency_hz < 100000U)) |
|
|
|
{ |
|
|
|
runtime->current_frequency_hz = runtime->end_frequency_hz + 1U; |
|
|
|
} |
|
|
|
} |
|
|
|
else if ((runtime->current_frequency_hz >= runtime->end_frequency_hz) && |
|
|
|
(runtime->end_frequency_hz > 1U) && |
|
|
|
(runtime->total_pulses > 0U) && |
|
|
|
(runtime->completed_pulses < runtime->total_pulses)) |
|
|
|
{ |
|
|
|
runtime->current_frequency_hz = runtime->end_frequency_hz - 1U; |
|
|
|
} |
|
|
|
} |
|
|
|
else if (runtime->frequency_table_id != 0U) |
|
|
|
{ |
|
|
|
/* 查表:最后一拍之前若已是 end,同样让出 1Hz */ |
|
|
|
if ((runtime->total_pulses > 0U) && |
|
|
|
(runtime->completed_pulses < runtime->total_pulses)) |
|
|
|
{ |
|
|
|
if (runtime->frequency_rising == 0U) |
|
|
|
{ |
|
|
|
if ((runtime->current_frequency_hz <= runtime->end_frequency_hz) && |
|
|
|
(runtime->end_frequency_hz < 100000U)) |
|
|
|
{ |
|
|
|
runtime->current_frequency_hz = runtime->end_frequency_hz + 1U; |
|
|
|
} |
|
|
|
} |
|
|
|
else if ((runtime->current_frequency_hz >= runtime->end_frequency_hz) && |
|
|
|
(runtime->end_frequency_hz > 1U)) |
|
|
|
{ |
|
|
|
runtime->current_frequency_hz = runtime->end_frequency_hz - 1U; |
|
|
|
} |
|
|
|
runtime->current_frequency_hz = runtime->end_frequency_hz; |
|
|
|
} |
|
|
|
runtime->is_active = 0U; |
|
|
|
} |
|
|
|
else if (runtime->frequency_table_id == 0U) |
|
|
|
{ |
|
|
|
|