|
|
@@ -1,6 +1,6 @@ |
|
|
/** |
|
|
/** |
|
|
* @file plsr_accel_curve.c |
|
|
* @file plsr_accel_curve.c |
|
|
* @brief 脉冲域规划/取频:加速 f^2=start^2+2an;减速 f^2=end^2+2ak(k=N…1);S/正弦时间轴 |
|
|
|
|
|
|
|
|
* @brief 脉冲域规划/取频:直线邻项平均;S/正弦时间轴查表 |
|
|
* |
|
|
* |
|
|
* ============================================================================ |
|
|
* ============================================================================ |
|
|
* 【阅读指南 — 先看这个再往下翻 if/else】 |
|
|
* 【阅读指南 — 先看这个再往下翻 if/else】 |
|
|
@@ -20,8 +20,10 @@ |
|
|
* decel_rate_hz_per_s 减速斜率 Hz/s ≈ default_speed*1000/deceleration_time_ms |
|
|
* decel_rate_hz_per_s 减速斜率 Hz/s ≈ default_speed*1000/deceleration_time_ms |
|
|
* |
|
|
* |
|
|
* 二、三种曲线模式(curve_mode) |
|
|
* 二、三种曲线模式(curve_mode) |
|
|
* LINEAR 加速:f=sqrt(start^2+2a·n);减速:从终点往峰值加 |
|
|
|
|
|
* f=sqrt(end^2+2a·k),k=N…1(与加速对称,勿从峰值减计数) |
|
|
|
|
|
|
|
|
* LINEAR S_x=sqrt(f0^2+2a·x);第 k 拍命令频=(S_{k-1}+S_k)/2;末拍钉相终点 |
|
|
|
|
|
* N=floor(|ft^2-f0^2|/(2a))(非零斜坡且算得 0 → 1) |
|
|
|
|
|
* 减速以终点为 f0 往峰值建 S_N…S_0,首减拍 (S_N+S_{N-1})/2 |
|
|
|
|
|
* ARPE:冷启动须 Prime/NextFrequency 一次再 Start,避免首频写两遍 |
|
|
* S 时间域 jerk 梯形;规划/ISR 用离散 Δt=1/frequency_hz 仿真;ISR 查预建表 |
|
|
* S 时间域 jerk 梯形;规划/ISR 用离散 Δt=1/frequency_hz 仿真;ISR 查预建表 |
|
|
* SINE raised-cosine 时间剖面;同上,查预建表 |
|
|
* SINE raised-cosine 时间剖面;同上,查预建表 |
|
|
* |
|
|
* |
|
|
@@ -39,7 +41,7 @@ |
|
|
* |
|
|
* |
|
|
* 五、FreqAtPulse 的 completed_segment_pulses 含义(易混) |
|
|
* 五、FreqAtPulse 的 completed_segment_pulses 含义(易混) |
|
|
* completed_segment_pulses = 已完成脉冲数(不是「当前第几拍」) |
|
|
* completed_segment_pulses = 已完成脉冲数(不是「当前第几拍」) |
|
|
* done=0 → 第 1 拍频率 = start_frequency_hz;done=1 → 第 2 拍 ≈ sqrt(start_frequency_hz^2+2a) … |
|
|
|
|
|
|
|
|
* done=0 → 第 1 拍命令频 = (S_0+S_1)/2;done=k → 第 k+1 拍;末拍钉终点 |
|
|
* |
|
|
* |
|
|
* @details 模块职责 |
|
|
* @details 模块职责 |
|
|
* 实现 plsr_accel_curve.h 全部 API。核心路径: |
|
|
* 实现 plsr_accel_curve.h 全部 API。核心路径: |
|
|
@@ -74,25 +76,39 @@ static uint32_t PlsrAccelCurveAbsoluteDifference(uint32_t first_value, uint32_t |
|
|
(first_value - second_value) : (second_value - first_value); |
|
|
(first_value - second_value) : (second_value - first_value); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
/** 64 位整数平方根(牛顿法),支持 frequency_hz^2 + 2an */ |
|
|
|
|
|
|
|
|
/** 64 位整数平方根(牛顿法)。初值必须 ≥ 真根,否则一步上冲会误停。 */ |
|
|
static uint32_t PlsrAccelCurveIntegerSquareRoot(uint64_t squared_frequency) |
|
|
static uint32_t PlsrAccelCurveIntegerSquareRoot(uint64_t squared_frequency) |
|
|
{ |
|
|
{ |
|
|
uint64_t estimate; |
|
|
uint64_t estimate; |
|
|
uint64_t next_estimate; |
|
|
uint64_t next_estimate; |
|
|
|
|
|
uint32_t bit; |
|
|
uint32_t loop_index; |
|
|
uint32_t loop_index; |
|
|
|
|
|
|
|
|
if (squared_frequency <= 1ULL) |
|
|
if (squared_frequency <= 1ULL) |
|
|
{ |
|
|
{ |
|
|
return (uint32_t)squared_frequency; |
|
|
return (uint32_t)squared_frequency; |
|
|
} |
|
|
} |
|
|
estimate = squared_frequency; |
|
|
|
|
|
if (estimate > 100000ULL) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* 按最高位置初值:略大于 √x,保证从上方收敛(过低会一步上冲误停) */ |
|
|
|
|
|
bit = 0U; |
|
|
|
|
|
{ |
|
|
|
|
|
uint64_t temp = squared_frequency; |
|
|
|
|
|
|
|
|
|
|
|
while (temp > 1ULL) |
|
|
|
|
|
{ |
|
|
|
|
|
temp >>= 1; |
|
|
|
|
|
bit++; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
estimate = 1ULL << ((bit + 2U) / 2U); |
|
|
|
|
|
if (estimate < 1ULL) |
|
|
{ |
|
|
{ |
|
|
estimate = 100000ULL; |
|
|
|
|
|
|
|
|
estimate = 1ULL; |
|
|
} |
|
|
} |
|
|
for (loop_index = 0U; loop_index < 40U; loop_index++) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (loop_index = 0U; loop_index < 48U; loop_index++) |
|
|
{ |
|
|
{ |
|
|
next_estimate = (estimate + squared_frequency / estimate) / 2ULL; |
|
|
|
|
|
|
|
|
next_estimate = (estimate + (squared_frequency / estimate)) / 2ULL; |
|
|
if (next_estimate >= estimate) |
|
|
if (next_estimate >= estimate) |
|
|
{ |
|
|
{ |
|
|
break; |
|
|
break; |
|
|
@@ -116,7 +132,7 @@ static uint32_t PlsrAccelCurveRateFromDefaultSpeed(uint32_t default_speed_hz, ui |
|
|
{ |
|
|
{ |
|
|
return 0U; |
|
|
return 0U; |
|
|
} |
|
|
} |
|
|
return (default_speed_hz * 1000UL) / ramp_time_ms; |
|
|
|
|
|
|
|
|
return (uint32_t)(((uint64_t)default_speed_hz * 1000ULL) / (uint64_t)ramp_time_ms); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
/** 按默认速度计算变化率;默认速度未配置时用本段频差计算。 */ |
|
|
/** 按默认速度计算变化率;默认速度未配置时用本段频差计算。 */ |
|
|
@@ -166,14 +182,14 @@ static uint32_t PlsrAccelCurveCalculateJumpFrequency(uint32_t starting_frequency |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
/** |
|
|
/** |
|
|
* 解析配置起速/止速 → 本段实际入口或出口频率。 |
|
|
|
|
|
|
|
|
* 解析配置起速/止速 → 本段数学入口或出口频率 f0 / f_end。 |
|
|
* |
|
|
* |
|
|
* 三分支(按顺序判断,命中即 return): |
|
|
|
|
|
* ① configured_frequency_hz > target_frequency_hz → 直接用 configured_frequency_hz(例如起速 500、目标 200:先高位再减) |
|
|
|
|
|
* ② target_frequency_hz < jump_frequency_hz → 用 target_frequency_hz(目标比起跳还低,没必要从 jump_frequency_hz 起) |
|
|
|
|
|
* ③ 否则 → 用 jump_frequency_hz = sqrt(configured_frequency_hz^2 + 2a) |
|
|
|
|
|
|
|
|
* 直线邻项平均:S_x=√(f0²+2ax),首拍 (f0+S1)/2;起速=0 时 f0=0、S1=√(2a), |
|
|
|
|
|
* 不再把「起跳 √(f0²+2a)」当作段入口(否则首频变成 (S1+S2)/2≈170)。 |
|
|
* |
|
|
* |
|
|
* resolving_start=1 用 acceleration_time_ms 算 a;resolving_start=0 用 deceleration_time_ms(ResolveEndHz 止速侧)。 |
|
|
|
|
|
|
|
|
* ① configured > target → 用 configured(高位起再降) |
|
|
|
|
|
* ② a=0 且 configured=0 → 用 target(阶跃) |
|
|
|
|
|
* ③ 否则 → 用 configured(可为 0) |
|
|
*/ |
|
|
*/ |
|
|
static uint32_t PlsrAccelCurveResolveBoundaryFrequency(uint32_t configured_frequency_hz, |
|
|
static uint32_t PlsrAccelCurveResolveBoundaryFrequency(uint32_t configured_frequency_hz, |
|
|
uint32_t target_frequency_hz, |
|
|
uint32_t target_frequency_hz, |
|
|
@@ -184,7 +200,6 @@ static uint32_t PlsrAccelCurveResolveBoundaryFrequency(uint32_t configured_frequ |
|
|
{ |
|
|
{ |
|
|
uint32_t ramp_time_ms; |
|
|
uint32_t ramp_time_ms; |
|
|
uint32_t acceleration_hz_per_s; |
|
|
uint32_t acceleration_hz_per_s; |
|
|
uint32_t jump_frequency_hz; |
|
|
|
|
|
|
|
|
|
|
|
configured_frequency_hz = PlsrAccelCurveClampFrequencyHz(configured_frequency_hz); |
|
|
configured_frequency_hz = PlsrAccelCurveClampFrequencyHz(configured_frequency_hz); |
|
|
target_frequency_hz = PlsrAccelCurveClampFrequencyHz(target_frequency_hz); |
|
|
target_frequency_hz = PlsrAccelCurveClampFrequencyHz(target_frequency_hz); |
|
|
@@ -210,14 +225,7 @@ static uint32_t PlsrAccelCurveResolveBoundaryFrequency(uint32_t configured_frequ |
|
|
return (configured_frequency_hz >= 1U) ? configured_frequency_hz : target_frequency_hz; |
|
|
return (configured_frequency_hz >= 1U) ? configured_frequency_hz : target_frequency_hz; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
jump_frequency_hz = PlsrAccelCurveCalculateJumpFrequency(configured_frequency_hz, acceleration_hz_per_s); |
|
|
|
|
|
|
|
|
|
|
|
/* 目标 < 起跳 → 用目标;目标 >= 起跳 → 用起跳 */ |
|
|
|
|
|
if (target_frequency_hz < jump_frequency_hz) |
|
|
|
|
|
{ |
|
|
|
|
|
return target_frequency_hz; |
|
|
|
|
|
} |
|
|
|
|
|
return jump_frequency_hz; |
|
|
|
|
|
|
|
|
return configured_frequency_hz; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
uint32_t PlsrAccelCurveResolveStartHz(uint32_t configured_frequency_hz, |
|
|
uint32_t PlsrAccelCurveResolveStartHz(uint32_t configured_frequency_hz, |
|
|
@@ -297,8 +305,8 @@ static uint32_t PlsrAccelCurveInterpolate(uint32_t start_value, |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
/** |
|
|
/** |
|
|
* 脉冲闭合:N = ceil(|end_frequency_hz^2 - start_frequency_hz^2| / (2a))。 |
|
|
|
|
|
* a=0 且频差非 0 → 0(阶跃,无斜坡脉冲)。 |
|
|
|
|
|
|
|
|
* 脉冲闭合:N = floor(|end_frequency_hz^2 - start_frequency_hz^2| / (2a))。 |
|
|
|
|
|
* 非零斜坡且算得 0 → 1。a=0 且频差非 0 → 0(阶跃,无斜坡脉冲)。 |
|
|
*/ |
|
|
*/ |
|
|
static uint32_t PlsrAccelCurveCalculateLinearRampPulses(uint32_t start_frequency_hz, uint32_t end_frequency_hz, |
|
|
static uint32_t PlsrAccelCurveCalculateLinearRampPulses(uint32_t start_frequency_hz, uint32_t end_frequency_hz, |
|
|
uint32_t acceleration_hz_per_s) |
|
|
uint32_t acceleration_hz_per_s) |
|
|
@@ -320,9 +328,11 @@ static uint32_t PlsrAccelCurveCalculateLinearRampPulses(uint32_t start_frequency |
|
|
|
|
|
|
|
|
start_frequency_squared = (uint64_t)start_frequency_hz * (uint64_t)start_frequency_hz; |
|
|
start_frequency_squared = (uint64_t)start_frequency_hz * (uint64_t)start_frequency_hz; |
|
|
end_frequency_squared = (uint64_t)end_frequency_hz * (uint64_t)end_frequency_hz; |
|
|
end_frequency_squared = (uint64_t)end_frequency_hz * (uint64_t)end_frequency_hz; |
|
|
squared_frequency_difference = (end_frequency_squared > start_frequency_squared) ? (end_frequency_squared - start_frequency_squared) : (start_frequency_squared - end_frequency_squared); |
|
|
|
|
|
|
|
|
squared_frequency_difference = (end_frequency_squared > start_frequency_squared) ? |
|
|
|
|
|
(end_frequency_squared - start_frequency_squared) : |
|
|
|
|
|
(start_frequency_squared - end_frequency_squared); |
|
|
twice_acceleration = 2ULL * (uint64_t)acceleration_hz_per_s; |
|
|
twice_acceleration = 2ULL * (uint64_t)acceleration_hz_per_s; |
|
|
pulse_count = (squared_frequency_difference + twice_acceleration - 1ULL) / twice_acceleration; |
|
|
|
|
|
|
|
|
pulse_count = squared_frequency_difference / twice_acceleration; |
|
|
if (pulse_count == 0ULL) |
|
|
if (pulse_count == 0ULL) |
|
|
{ |
|
|
{ |
|
|
pulse_count = 1ULL; |
|
|
pulse_count = 1ULL; |
|
|
@@ -559,11 +569,11 @@ static uint32_t PlsrAccelCurveCalculateRampPulses(uint32_t start_frequency_hz, u |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
/** |
|
|
/** |
|
|
* 直线取频。 |
|
|
|
|
|
* 加速(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 |
|
|
|
|
|
|
|
|
* 直线邻项平均取频(任务侧预览)。 |
|
|
|
|
|
* pulse_count = 相内已完成脉冲数 → 返回第 (pulse_count+1) 拍命令频。 |
|
|
|
|
|
* rising:S_x=sqrt(start^2+2a·x),S_0=start;第 k 拍 (S_{k-1}+S_k)/2 |
|
|
|
|
|
* 末拍:S_N 取相终点 target_limit,(S_{N-1}+target_limit)/2(不钉死终点) |
|
|
|
|
|
* 减速:S_m=sqrt(end^2+2a·m);末拍 (S_1+end)/2 |
|
|
*/ |
|
|
*/ |
|
|
static uint32_t PlsrAccelCurveLinearFrequencyAtPulse(uint32_t start_frequency_hz, uint32_t acceleration_hz_per_s, |
|
|
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 pulse_count, uint8_t frequency_rising, |
|
|
@@ -571,8 +581,11 @@ static uint32_t PlsrAccelCurveLinearFrequencyAtPulse(uint32_t start_frequency_hz |
|
|
uint32_t phase_total_pulses) |
|
|
uint32_t phase_total_pulses) |
|
|
{ |
|
|
{ |
|
|
uint64_t squared_frequency; |
|
|
uint64_t squared_frequency; |
|
|
|
|
|
uint32_t s_prev; |
|
|
|
|
|
uint32_t s_next; |
|
|
uint32_t frequency_hz; |
|
|
uint32_t frequency_hz; |
|
|
uint32_t k_from_end; |
|
|
|
|
|
|
|
|
uint32_t k_hi; |
|
|
|
|
|
uint32_t k_lo; |
|
|
|
|
|
|
|
|
if (acceleration_hz_per_s == 0U) |
|
|
if (acceleration_hz_per_s == 0U) |
|
|
{ |
|
|
{ |
|
|
@@ -580,46 +593,86 @@ static uint32_t PlsrAccelCurveLinearFrequencyAtPulse(uint32_t start_frequency_hz |
|
|
return PlsrAccelCurveClampFrequencyHz((frequency_hz < 1U) ? 1U : frequency_hz); |
|
|
return PlsrAccelCurveClampFrequencyHz((frequency_hz < 1U) ? 1U : frequency_hz); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (phase_total_pulses < 1U) |
|
|
|
|
|
{ |
|
|
|
|
|
frequency_hz = target_limit_hz; |
|
|
|
|
|
if (frequency_hz < 1U) |
|
|
|
|
|
{ |
|
|
|
|
|
frequency_hz = 1U; |
|
|
|
|
|
} |
|
|
|
|
|
return PlsrAccelCurveClampFrequencyHz(frequency_hz); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
if (frequency_rising != 0U) |
|
|
if (frequency_rising != 0U) |
|
|
{ |
|
|
{ |
|
|
|
|
|
if (pulse_count + 1U >= phase_total_pulses) |
|
|
|
|
|
{ |
|
|
|
|
|
/* 升频末拍:直接相终点(进匀速后锁定,不再平均) */ |
|
|
|
|
|
frequency_hz = target_limit_hz; |
|
|
|
|
|
if (frequency_hz < 1U) |
|
|
|
|
|
{ |
|
|
|
|
|
frequency_hz = 1U; |
|
|
|
|
|
} |
|
|
|
|
|
return PlsrAccelCurveClampFrequencyHz(frequency_hz); |
|
|
|
|
|
} |
|
|
if (pulse_count == 0U) |
|
|
if (pulse_count == 0U) |
|
|
{ |
|
|
{ |
|
|
frequency_hz = start_frequency_hz; |
|
|
|
|
|
|
|
|
s_prev = start_frequency_hz; |
|
|
} |
|
|
} |
|
|
else |
|
|
else |
|
|
{ |
|
|
{ |
|
|
squared_frequency = (uint64_t)start_frequency_hz * (uint64_t)start_frequency_hz |
|
|
squared_frequency = (uint64_t)start_frequency_hz * (uint64_t)start_frequency_hz |
|
|
+ (2ULL * (uint64_t)acceleration_hz_per_s * (uint64_t)pulse_count); |
|
|
+ (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; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
s_prev = PlsrAccelCurveIntegerSquareRoot(squared_frequency); |
|
|
} |
|
|
} |
|
|
|
|
|
squared_frequency = (uint64_t)start_frequency_hz * (uint64_t)start_frequency_hz |
|
|
|
|
|
+ (2ULL * (uint64_t)acceleration_hz_per_s * (uint64_t)(pulse_count + 1U)); |
|
|
|
|
|
s_next = PlsrAccelCurveIntegerSquareRoot(squared_frequency); |
|
|
|
|
|
frequency_hz = (s_prev / 2U) + (s_next / 2U) + ((s_prev & 1U) + (s_next & 1U)) / 2U; |
|
|
} |
|
|
} |
|
|
else |
|
|
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) |
|
|
|
|
|
|
|
|
if (pulse_count + 1U >= phase_total_pulses) |
|
|
{ |
|
|
{ |
|
|
frequency_hz = target_limit_hz; |
|
|
|
|
|
|
|
|
/* 末拍:(S_1 + end)/2 */ |
|
|
|
|
|
squared_frequency = (uint64_t)target_limit_hz * (uint64_t)target_limit_hz |
|
|
|
|
|
+ (2ULL * (uint64_t)acceleration_hz_per_s); |
|
|
|
|
|
s_prev = PlsrAccelCurveIntegerSquareRoot(squared_frequency); |
|
|
|
|
|
if (s_prev > start_frequency_hz) |
|
|
|
|
|
{ |
|
|
|
|
|
s_prev = start_frequency_hz; |
|
|
|
|
|
} |
|
|
|
|
|
s_next = target_limit_hz; |
|
|
} |
|
|
} |
|
|
else |
|
|
else |
|
|
{ |
|
|
{ |
|
|
k_from_end = phase_total_pulses - pulse_count; |
|
|
|
|
|
|
|
|
k_hi = phase_total_pulses - pulse_count; |
|
|
|
|
|
k_lo = k_hi - 1U; |
|
|
squared_frequency = (uint64_t)target_limit_hz * (uint64_t)target_limit_hz |
|
|
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) |
|
|
|
|
|
|
|
|
+ (2ULL * (uint64_t)acceleration_hz_per_s * (uint64_t)k_hi); |
|
|
|
|
|
s_prev = PlsrAccelCurveIntegerSquareRoot(squared_frequency); |
|
|
|
|
|
if (s_prev > start_frequency_hz) |
|
|
|
|
|
{ |
|
|
|
|
|
s_prev = start_frequency_hz; |
|
|
|
|
|
} |
|
|
|
|
|
if (k_lo == 0U) |
|
|
|
|
|
{ |
|
|
|
|
|
s_next = target_limit_hz; |
|
|
|
|
|
} |
|
|
|
|
|
else |
|
|
{ |
|
|
{ |
|
|
frequency_hz = start_frequency_hz; |
|
|
|
|
|
|
|
|
squared_frequency = (uint64_t)target_limit_hz * (uint64_t)target_limit_hz |
|
|
|
|
|
+ (2ULL * (uint64_t)acceleration_hz_per_s * (uint64_t)k_lo); |
|
|
|
|
|
s_next = PlsrAccelCurveIntegerSquareRoot(squared_frequency); |
|
|
|
|
|
if (s_next > start_frequency_hz) |
|
|
|
|
|
{ |
|
|
|
|
|
s_next = start_frequency_hz; |
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
frequency_hz = (s_prev / 2U) + (s_next / 2U) + ((s_prev & 1U) + (s_next & 1U)) / 2U; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
if (frequency_hz < 1U) |
|
|
if (frequency_hz < 1U) |
|
|
{ |
|
|
{ |
|
|
frequency_hz = 1U; |
|
|
frequency_hz = 1U; |
|
|
@@ -824,17 +877,6 @@ void PlsrAccelCurvePlan(PlsrAccelPlan_t *plan, |
|
|
|
|
|
|
|
|
selected_mode = (curve_mode > PLSR_ACCEL_SINE) ? PLSR_ACCEL_LINEAR : curve_mode; |
|
|
selected_mode = (curve_mode > PLSR_ACCEL_SINE) ? PLSR_ACCEL_LINEAR : curve_mode; |
|
|
|
|
|
|
|
|
if (start_frequency_hz < 1U) |
|
|
|
|
|
{ |
|
|
|
|
|
start_frequency_hz = PlsrAccelCurveResolveStartHz(0U, target_frequency_hz, default_speed_hz, |
|
|
|
|
|
acceleration_time_ms, deceleration_time_ms); |
|
|
|
|
|
} |
|
|
|
|
|
if (end_frequency_hz < 1U) |
|
|
|
|
|
{ |
|
|
|
|
|
end_frequency_hz = PlsrAccelCurveResolveEndHz(0U, target_frequency_hz, default_speed_hz, |
|
|
|
|
|
acceleration_time_ms, deceleration_time_ms); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
accel_rate_hz_per_s = |
|
|
accel_rate_hz_per_s = |
|
|
PlsrAccelCurveCalculateRate(default_speed_hz, |
|
|
PlsrAccelCurveCalculateRate(default_speed_hz, |
|
|
start_frequency_hz, |
|
|
start_frequency_hz, |
|
|
@@ -846,6 +888,35 @@ void PlsrAccelCurvePlan(PlsrAccelPlan_t *plan, |
|
|
end_frequency_hz, |
|
|
end_frequency_hz, |
|
|
deceleration_time_ms); |
|
|
deceleration_time_ms); |
|
|
|
|
|
|
|
|
|
|
|
/* |
|
|
|
|
|
* 直线:允许 f0/f_end=0(邻项平均首末拍用)。 |
|
|
|
|
|
* S/正弦:时间仿真不能从 0 起,入口/出口 <1 时用起跳/落地 √(2a)。 |
|
|
|
|
|
*/ |
|
|
|
|
|
if (start_frequency_hz < 1U) |
|
|
|
|
|
{ |
|
|
|
|
|
if (selected_mode == PLSR_ACCEL_LINEAR) |
|
|
|
|
|
{ |
|
|
|
|
|
start_frequency_hz = 0U; |
|
|
|
|
|
} |
|
|
|
|
|
else |
|
|
|
|
|
{ |
|
|
|
|
|
start_frequency_hz = |
|
|
|
|
|
PlsrAccelCurveCalculateJumpFrequency(0U, accel_rate_hz_per_s); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
if (end_frequency_hz < 1U) |
|
|
|
|
|
{ |
|
|
|
|
|
if (selected_mode == PLSR_ACCEL_LINEAR) |
|
|
|
|
|
{ |
|
|
|
|
|
end_frequency_hz = 0U; |
|
|
|
|
|
} |
|
|
|
|
|
else |
|
|
|
|
|
{ |
|
|
|
|
|
end_frequency_hz = |
|
|
|
|
|
PlsrAccelCurveCalculateJumpFrequency(0U, decel_rate_hz_per_s); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
peak_frequency_hz = target_frequency_hz; |
|
|
peak_frequency_hz = target_frequency_hz; |
|
|
|
|
|
|
|
|
plan->start_frequency_hz = start_frequency_hz; |
|
|
plan->start_frequency_hz = start_frequency_hz; |
|
|
@@ -1006,7 +1077,8 @@ static uint32_t PlsrAccelCurveTimedFrequencyAtPulse( |
|
|
* completed_segment_pulses ∈ [accel_pulses+constant_pulses, …) → 减速相(target_frequency_hz → end_frequency_hz) |
|
|
* completed_segment_pulses ∈ [accel_pulses+constant_pulses, …) → 减速相(target_frequency_hz → end_frequency_hz) |
|
|
* |
|
|
* |
|
|
* 注意 completed_segment_pulses 是「已经发完的个数」: |
|
|
* 注意 completed_segment_pulses 是「已经发完的个数」: |
|
|
* Start 后第 1 拍进行中时 done 仍为 0,FreqAtPulse(0)=start_frequency_hz。 |
|
|
|
|
|
|
|
|
* Start 后第 1 拍进行中时 done 仍为 0,直线 FreqAtPulse(0)=(S0+S1)/2。 |
|
|
|
|
|
* ARPE 冷启动勿只靠本函数:须 Prime 把 runtime.completed 推到 1,否则 ISR 会再写一遍首频。 |
|
|
*/ |
|
|
*/ |
|
|
uint32_t PlsrAccelCurveFreqAtPulse(const PlsrAccelPlan_t *plan, |
|
|
uint32_t PlsrAccelCurveFreqAtPulse(const PlsrAccelPlan_t *plan, |
|
|
uint32_t completed_segment_pulses) |
|
|
uint32_t completed_segment_pulses) |
|
|
@@ -1148,6 +1220,9 @@ static void PlsrAccelRuntimeBeginRamp(PlsrAccelRuntime_t *runtime, |
|
|
uint32_t decel_rate_hz_per_s, |
|
|
uint32_t decel_rate_hz_per_s, |
|
|
PlsrAccelMode_e curve_mode) |
|
|
PlsrAccelMode_e curve_mode) |
|
|
{ |
|
|
{ |
|
|
|
|
|
uint64_t squared_frequency; |
|
|
|
|
|
uint32_t s_n; |
|
|
|
|
|
|
|
|
runtime->start_frequency_hz = start_frequency_hz; |
|
|
runtime->start_frequency_hz = start_frequency_hz; |
|
|
runtime->end_frequency_hz = end_frequency_hz; |
|
|
runtime->end_frequency_hz = end_frequency_hz; |
|
|
runtime->current_frequency_hz = start_frequency_hz; |
|
|
runtime->current_frequency_hz = start_frequency_hz; |
|
|
@@ -1164,6 +1239,26 @@ static void PlsrAccelRuntimeBeginRamp(PlsrAccelRuntime_t *runtime, |
|
|
runtime->frequency_table_id = 0U; |
|
|
runtime->frequency_table_id = 0U; |
|
|
runtime->table_length = 0U; |
|
|
runtime->table_length = 0U; |
|
|
runtime->table_stride = 1U; |
|
|
runtime->table_stride = 1U; |
|
|
|
|
|
/* 直线:升频 prev=S0=start;降频 prev=S_N(从终点往峰值建) */ |
|
|
|
|
|
runtime->linear_prev_s_hz = start_frequency_hz; |
|
|
|
|
|
if ((curve_mode == PLSR_ACCEL_LINEAR) && |
|
|
|
|
|
(runtime->frequency_rising == 0U) && |
|
|
|
|
|
(runtime->acceleration_hz_per_s > 0U) && |
|
|
|
|
|
(total_pulses > 0U)) |
|
|
|
|
|
{ |
|
|
|
|
|
squared_frequency = (uint64_t)end_frequency_hz * (uint64_t)end_frequency_hz |
|
|
|
|
|
+ (2ULL * (uint64_t)runtime->acceleration_hz_per_s * (uint64_t)total_pulses); |
|
|
|
|
|
s_n = PlsrAccelCurveIntegerSquareRoot(squared_frequency); |
|
|
|
|
|
if (s_n > start_frequency_hz) |
|
|
|
|
|
{ |
|
|
|
|
|
s_n = start_frequency_hz; |
|
|
|
|
|
} |
|
|
|
|
|
if (s_n < 1U) |
|
|
|
|
|
{ |
|
|
|
|
|
s_n = 1U; |
|
|
|
|
|
} |
|
|
|
|
|
runtime->linear_prev_s_hz = s_n; |
|
|
|
|
|
} |
|
|
PlsrAccelRuntimeCalculateTimes(runtime); |
|
|
PlsrAccelRuntimeCalculateTimes(runtime); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
@@ -1416,59 +1511,78 @@ void PlsrAccelBeginConstantSpeed(PlsrAccelRuntime_t *runtime, |
|
|
runtime->jerk_time_us = 0U; |
|
|
runtime->jerk_time_us = 0U; |
|
|
runtime->constant_accel_time_us = 0U; |
|
|
runtime->constant_accel_time_us = 0U; |
|
|
runtime->ramp_time_us = 0U; |
|
|
runtime->ramp_time_us = 0U; |
|
|
|
|
|
runtime->linear_prev_s_hz = 0U; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
/** |
|
|
/** |
|
|
* 直线 ISR 取频(开方,与规划公式一致)。 |
|
|
|
|
|
* 加速:f = sqrt(start^2 + 2·a·completed) |
|
|
|
|
|
* 减速:k = total-completed+1,f = sqrt(end^2 + 2·a·k)(从终点往峰值加) |
|
|
|
|
|
|
|
|
* 直线 ISR 取频:邻项平均。 |
|
|
|
|
|
* S_x=√(f0²+2a·x) 是瞬时速度,不是命令频率;命令频=(S_{k-1}+S_k)/2。 |
|
|
|
|
|
* linear_prev_s_hz 只存上一拍的 S(开方值),绝不能存输出频率。 |
|
|
|
|
|
* 升频末拍直接钉相终点(进匀速锁定);减速末拍仍 (S1+end)/2。 |
|
|
*/ |
|
|
*/ |
|
|
static uint32_t PlsrAccelNextFrequencyLinear(PlsrAccelRuntime_t *runtime) |
|
|
static uint32_t PlsrAccelNextFrequencyLinear(PlsrAccelRuntime_t *runtime) |
|
|
{ |
|
|
{ |
|
|
uint64_t target_frequency_squared; |
|
|
|
|
|
|
|
|
uint64_t squared_frequency; |
|
|
|
|
|
uint32_t s_new; |
|
|
uint32_t frequency_hz; |
|
|
uint32_t frequency_hz; |
|
|
uint32_t k_from_end; |
|
|
|
|
|
|
|
|
uint32_t k_lo; |
|
|
|
|
|
|
|
|
if (runtime->acceleration_hz_per_s == 0U) |
|
|
if (runtime->acceleration_hz_per_s == 0U) |
|
|
{ |
|
|
{ |
|
|
return PlsrAccelCurveClampFrequencyHz(runtime->end_frequency_hz); |
|
|
|
|
|
|
|
|
return PlsrAccelCurveClampFrequencyHz( |
|
|
|
|
|
(runtime->end_frequency_hz < 1U) ? 1U : runtime->end_frequency_hz); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/* 升频相结束:锁定峰值,不再开方/平均 */ |
|
|
|
|
|
if ((runtime->total_pulses > 0U) && |
|
|
|
|
|
(runtime->completed_pulses >= runtime->total_pulses) && |
|
|
|
|
|
(runtime->frequency_rising != 0U)) |
|
|
|
|
|
{ |
|
|
|
|
|
return PlsrAccelCurveClampFrequencyHz( |
|
|
|
|
|
(runtime->end_frequency_hz < 1U) ? 1U : runtime->end_frequency_hz); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
if (runtime->frequency_rising != 0U) |
|
|
|
|
|
|
|
|
if ((runtime->total_pulses > 0U) && |
|
|
|
|
|
(runtime->completed_pulses >= runtime->total_pulses)) |
|
|
|
|
|
{ |
|
|
|
|
|
/* 减速末拍:与相终点平均 */ |
|
|
|
|
|
s_new = runtime->end_frequency_hz; |
|
|
|
|
|
} |
|
|
|
|
|
else if (runtime->frequency_rising != 0U) |
|
|
{ |
|
|
{ |
|
|
target_frequency_squared = |
|
|
|
|
|
|
|
|
squared_frequency = |
|
|
(uint64_t)runtime->start_frequency_hz * (uint64_t)runtime->start_frequency_hz |
|
|
(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); |
|
|
+ (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) |
|
|
|
|
|
|
|
|
s_new = PlsrAccelCurveIntegerSquareRoot(squared_frequency); |
|
|
|
|
|
if (s_new > runtime->end_frequency_hz) |
|
|
{ |
|
|
{ |
|
|
frequency_hz = runtime->end_frequency_hz; |
|
|
|
|
|
|
|
|
s_new = runtime->end_frequency_hz; |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
else |
|
|
else |
|
|
{ |
|
|
{ |
|
|
if (runtime->total_pulses < 1U) |
|
|
|
|
|
|
|
|
k_lo = runtime->total_pulses - runtime->completed_pulses; |
|
|
|
|
|
if (k_lo == 0U) |
|
|
{ |
|
|
{ |
|
|
k_from_end = 1U; |
|
|
|
|
|
} |
|
|
|
|
|
else if (runtime->completed_pulses >= runtime->total_pulses) |
|
|
|
|
|
{ |
|
|
|
|
|
k_from_end = 1U; |
|
|
|
|
|
|
|
|
s_new = runtime->end_frequency_hz; |
|
|
} |
|
|
} |
|
|
else |
|
|
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; |
|
|
|
|
|
|
|
|
squared_frequency = |
|
|
|
|
|
(uint64_t)runtime->end_frequency_hz * (uint64_t)runtime->end_frequency_hz |
|
|
|
|
|
+ (2ULL * (uint64_t)runtime->acceleration_hz_per_s * (uint64_t)k_lo); |
|
|
|
|
|
s_new = PlsrAccelCurveIntegerSquareRoot(squared_frequency); |
|
|
|
|
|
if (s_new > runtime->start_frequency_hz) |
|
|
|
|
|
{ |
|
|
|
|
|
s_new = runtime->start_frequency_hz; |
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
frequency_hz = (runtime->linear_prev_s_hz / 2U) + (s_new / 2U) |
|
|
|
|
|
+ ((runtime->linear_prev_s_hz & 1U) + (s_new & 1U)) / 2U; |
|
|
|
|
|
runtime->linear_prev_s_hz = s_new; |
|
|
|
|
|
|
|
|
if (frequency_hz < 1U) |
|
|
if (frequency_hz < 1U) |
|
|
{ |
|
|
{ |
|
|
frequency_hz = 1U; |
|
|
frequency_hz = 1U; |
|
|
@@ -1476,6 +1590,50 @@ static uint32_t PlsrAccelNextFrequencyLinear(PlsrAccelRuntime_t *runtime) |
|
|
return PlsrAccelCurveClampFrequencyHz(frequency_hz); |
|
|
return PlsrAccelCurveClampFrequencyHz(frequency_hz); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
uint32_t PlsrAccelCurveLinearMinCommandHz(uint32_t boundary_frequency_hz, |
|
|
|
|
|
uint32_t rate_hz_per_s) |
|
|
|
|
|
{ |
|
|
|
|
|
uint32_t s1; |
|
|
|
|
|
uint32_t min_hz; |
|
|
|
|
|
|
|
|
|
|
|
if (boundary_frequency_hz >= 1U) |
|
|
|
|
|
{ |
|
|
|
|
|
return PlsrAccelCurveClampFrequencyHz(boundary_frequency_hz); |
|
|
|
|
|
} |
|
|
|
|
|
if (rate_hz_per_s < 1U) |
|
|
|
|
|
{ |
|
|
|
|
|
return 1U; |
|
|
|
|
|
} |
|
|
|
|
|
s1 = PlsrAccelCurveCalculateJumpFrequency(0U, rate_hz_per_s); |
|
|
|
|
|
min_hz = s1 / 2U; |
|
|
|
|
|
if (min_hz < 1U) |
|
|
|
|
|
{ |
|
|
|
|
|
min_hz = 1U; |
|
|
|
|
|
} |
|
|
|
|
|
return PlsrAccelCurveClampFrequencyHz(min_hz); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* 直线冷启动:推进一拍得到第 1 拍命令频(ARPE Start 用),runtime.completed=1。 |
|
|
|
|
|
*/ |
|
|
|
|
|
uint32_t PlsrAccelPrimeLinearStartFrequency(PlsrAccelRuntime_t *runtime) |
|
|
|
|
|
{ |
|
|
|
|
|
if (runtime == (PlsrAccelRuntime_t *)0) |
|
|
|
|
|
{ |
|
|
|
|
|
return 0U; |
|
|
|
|
|
} |
|
|
|
|
|
if (runtime->curve_mode != PLSR_ACCEL_LINEAR) |
|
|
|
|
|
{ |
|
|
|
|
|
return PlsrAccelCurveClampFrequencyHz(runtime->current_frequency_hz); |
|
|
|
|
|
} |
|
|
|
|
|
if (runtime->is_active == 0U) |
|
|
|
|
|
{ |
|
|
|
|
|
return PlsrAccelCurveClampFrequencyHz( |
|
|
|
|
|
(runtime->current_frequency_hz < 1U) ? 1U : runtime->current_frequency_hz); |
|
|
|
|
|
} |
|
|
|
|
|
return PlsrAccelNextFrequency(runtime); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
/** |
|
|
/** |
|
|
* S/正弦时间域步进:上一拍周期推进 t,再按剖面取下一拍频率。 |
|
|
* S/正弦时间域步进:上一拍周期推进 t,再按剖面取下一拍频率。 |
|
|
*/ |
|
|
*/ |
|
|
@@ -1569,11 +1727,12 @@ static uint32_t PlsrAccelCurveSimulateRampPulses(uint32_t start_frequency_hz, ui |
|
|
* 调用时机:每个 PWM UPDATE 中断里,在本段已发脉冲数加一之后。 |
|
|
* 调用时机:每个 PWM UPDATE 中断里,在本段已发脉冲数加一之后。 |
|
|
* |
|
|
* |
|
|
* 模式分支: |
|
|
* 模式分支: |
|
|
* LINEAR → SquareStep:用 frequency_hz±1 逼近 sqrt(start_frequency_hz^2±2an),不全量开方 |
|
|
|
|
|
|
|
|
* LINEAR → 邻项平均 (S_{k-1}+S_k)/2;prev 存 S 非输出频;末拍与相终点平均 |
|
|
* S/SINE+表 → 查 s_acceleration_frequency_table / s_deceleration_frequency_table(Prebuild 填好),table_index=(pulse_count-1)/table_stride |
|
|
* S/SINE+表 → 查 s_acceleration_frequency_table / s_deceleration_frequency_table(Prebuild 填好),table_index=(pulse_count-1)/table_stride |
|
|
* S/SINE无表 → 兜底 TimeStep(不应出现在正常路径) |
|
|
* S/SINE无表 → 兜底 TimeStep(不应出现在正常路径) |
|
|
* |
|
|
* |
|
|
* pulse_count 含义:本相已 Step 次数;BeginAcc 后第 1 次 Step 时 pulse_count 变为 1,对应「第 2 拍」频率。 |
|
|
|
|
|
|
|
|
* pulse_count 含义:本相已 Step 次数;Begin 后第 1 次 Step 时 pulse_count=1,对应第 1 拍命令频。 |
|
|
|
|
|
* ARPE 冷启动须先 Step/Prime 再 Start,使首 UPDATE 写第 2 拍。 |
|
|
*/ |
|
|
*/ |
|
|
uint32_t PlsrAccelNextFrequency(PlsrAccelRuntime_t *runtime) |
|
|
uint32_t PlsrAccelNextFrequency(PlsrAccelRuntime_t *runtime) |
|
|
{ |
|
|
{ |
|
|
@@ -1637,11 +1796,10 @@ uint32_t PlsrAccelNextFrequency(PlsrAccelRuntime_t *runtime) |
|
|
if ((runtime->total_pulses > 0U) && (runtime->completed_pulses >= runtime->total_pulses)) |
|
|
if ((runtime->total_pulses > 0U) && (runtime->completed_pulses >= runtime->total_pulses)) |
|
|
{ |
|
|
{ |
|
|
/* |
|
|
/* |
|
|
* 直线减速末步已是 sqrt(end^2+2a),不要再钉成 end(否则与「从终点往上加」不一致)。 |
|
|
|
|
|
* S/正弦 / 加速相:仍钉到相终点。 |
|
|
|
|
|
|
|
|
* 直线:末拍已是 (prev+end)/2,勿再钉 end。 |
|
|
|
|
|
* S/正弦:仍钉到相终点。 |
|
|
*/ |
|
|
*/ |
|
|
if (!((runtime->curve_mode == PLSR_ACCEL_LINEAR) && |
|
|
|
|
|
(runtime->frequency_rising == 0U))) |
|
|
|
|
|
|
|
|
if (runtime->curve_mode != PLSR_ACCEL_LINEAR) |
|
|
{ |
|
|
{ |
|
|
runtime->current_frequency_hz = runtime->end_frequency_hz; |
|
|
runtime->current_frequency_hz = runtime->end_frequency_hz; |
|
|
} |
|
|
} |
|
|
@@ -1654,19 +1812,23 @@ uint32_t PlsrAccelNextFrequency(PlsrAccelRuntime_t *runtime) |
|
|
runtime->current_frequency_hz = runtime->end_frequency_hz; |
|
|
runtime->current_frequency_hz = runtime->end_frequency_hz; |
|
|
runtime->is_active = 0U; |
|
|
runtime->is_active = 0U; |
|
|
} |
|
|
} |
|
|
else if (runtime->frequency_rising != 0U) |
|
|
|
|
|
|
|
|
else if (runtime->curve_mode != PLSR_ACCEL_LINEAR) |
|
|
{ |
|
|
{ |
|
|
if (runtime->current_frequency_hz >= runtime->end_frequency_hz) |
|
|
|
|
|
|
|
|
/* 时间剖面:到频即收;直线只靠 total_pulses 末拍钉终点 */ |
|
|
|
|
|
if (runtime->frequency_rising != 0U) |
|
|
|
|
|
{ |
|
|
|
|
|
if (runtime->current_frequency_hz >= runtime->end_frequency_hz) |
|
|
|
|
|
{ |
|
|
|
|
|
runtime->current_frequency_hz = runtime->end_frequency_hz; |
|
|
|
|
|
runtime->is_active = 0U; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
else if (runtime->current_frequency_hz <= runtime->end_frequency_hz) |
|
|
{ |
|
|
{ |
|
|
runtime->current_frequency_hz = runtime->end_frequency_hz; |
|
|
runtime->current_frequency_hz = runtime->end_frequency_hz; |
|
|
runtime->is_active = 0U; |
|
|
runtime->is_active = 0U; |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
else if (runtime->current_frequency_hz <= runtime->end_frequency_hz) |
|
|
|
|
|
{ |
|
|
|
|
|
runtime->current_frequency_hz = runtime->end_frequency_hz; |
|
|
|
|
|
runtime->is_active = 0U; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
} |
|
|
return PlsrAccelCurveClampFrequencyHz(runtime->current_frequency_hz); |
|
|
return PlsrAccelCurveClampFrequencyHz(runtime->current_frequency_hz); |
|
|
} |
|
|
} |