Wiki
velocity_smoother(速度限幅與加減速平滑)
本文由簡體中文內容確定性轉換,並受版本化術語表保護。
1.velocity_smoother(速度限幅與加減速平滑)
1.1.實車先看:平滑哪一路速度、反饋來自哪裏
當前velocity_smoother處理controller_server輸出的速度指令,逐軸限目標速度、限速度變化,再處理死區。OPEN_LOOP使用上一輪內部指令作當前速度,不用里程計實測速度;scale_velocities=False仍會限速和限加減速。 本節點處理Twist,不修改規劃路徑,也不查詢代價地圖判斷碰撞。
普通路径跟踪,两种navigation_launch分支相同:
controller_server/OmniPID
→ cmd_vel_controller
→ velocity_smoother
├─ 最新目标速度先夹到各轴min/max范围
├─ OPEN_LOOP:以内部last_cmd作为当前速度
├─ 按加/减速参数约束本轮变化
└─ 内部记录 → 应用死区 → 发布
→ cmd_vel_nav2_result
→ fake_vel_transform:换平移轴,再加cmd_spin
→ cmd_vel → 串口/执行端
恢复行为:
组件分支behavior_server → cmd_vel_nav2_result,绕过平滑器
独立分支behavior_server → namespace/cmd_vel,另有接线问题
當前launch把平滑器內部cmd_vel訂閲重映射為cmd_vel_controller,把cmd_vel_smoothed發佈重映射為cmd_vel_nav2_result;不是直接套用教程中的cmd_vel_nav→cmd_vel名稱。恢復與下游自旋的限速條件另見behavior_server和fake_vel_transform。
| 實車上看到的現象 | 先核對什麼 | 當前配置怎樣理解 |
|---|---|---|
| 認為False關閉了整個平滑功能 | scale_velocities控制的分支 | False只關閉統一比例的變化量縮放,各軸仍限幅與限加減速 |
| 以為min_velocity要求至少2.5 m/s才動 | 帶符號的速度範圍 | -2.5是負向下界,0和小的正/負速度都在允許範圍內 |
| 起步或轉向時方向暫時與目標不一致 | 各軸獨立約束及目標夾緊 | False各軸分別變化;True主要同比縮放Δ速度,也不能保證所有情況下保持原始目標方向 |
| 修改odom_duration後當前輸出沒變 | feedback是否仍為OPEN_LOOP | 正常初始化不建立反饋里程計訂閲,窗口不參與當前速度估計 |
| 收到零指令後還緩慢降速 | 零目標也經過減速約束 | 當前零指令不是直接透傳的急停信號 |
| 指令斷流滿1秒後沒有立刻歸零 | 超時先置零目標,再減速 | 1 s是開始超時處理的門檻,不是整個停車時間 |
| 設置非零死區後,小速度直接跳到某值 | 死區應用順序和內部last_cmd | 先記內部平滑值,再把小幅輸出置零;死區切換可造成發佈值跳變 |
| 平滑器角速度沒超過3,最終角速度卻更大 | 下游cmd_spin相加 | 3 rad/s約束本輸入目標,不約束相加後的最終總量 |
| 提高頻率,以為每秒加速度也必須提高 | 每輪步長和定時器節拍 | 每輪變化量按加速度/頻率計算;名義每秒限制保持相同,離散步長更小 |
本次安裝的nav2_velocity_smoother和nav2_util均為1.1.20。VelocitySmoother與OdomSmoother安裝頭文件匹配該版本,平滑器庫存在;本頁依據對應官方源碼及當前工程接線説明,不把後續版本的TwistStamped或其他參數直接套入。平滑器源碼、里程計窗口源碼
1.2.參數
下面原樣保留髮送的12項參數。源碼與安裝副本的reality段一致;simulation段只有use_sim_time=True不同。本次只寫文檔,未改工程配置或運行參數。
velocity_smoother:
ros__parameters:
use_sim_time: False
smoothing_frequency: 20.0
scale_velocities: False
feedback: "OPEN_LOOP"
max_velocity: [2.5, 2.5, 3.0]
min_velocity: [-2.5, -2.5, -3.0]
max_accel: [4.5, 4.5, 5.0]
max_decel: [-4.5, -4.5, -5.0]
odom_topic: "odometry"
odom_duration: 0.1
deadband_velocity: [0.0, 0.0, 0.0]
velocity_timeout: 1.0
所有三元素數組順序都是**[x,y,theta]**,對應Twist的linear.x、linear.y、angular.z。前兩項是平移,第三項是繞z軸的旋轉;theta這一項不是以rad為單位的目標角度。
1.2.1.ros__parameters(時鐘、頻率與反饋方式)
1.2.1.1.參數表
| 參數名 | 當前值 | 單位 | 實車處理建議 | 作用 | 調大效果 | 調小效果 | 生效條件/備註 |
|---|---|---|---|---|---|---|---|
use_sim_time |
False;仿真True |
不適用,布爾 | 上實物前必須核對並正確配置 | 選擇now()及輸入超時比較的ROS時間域 | 不適用 | 不適用 | launch重寫已有鍵;平滑定時器用wall timer,True不會把它變為仿真時鐘定時器 |
smoothing_frequency |
20.0;源碼默認20.0 |
Hz,平滑定時回調目標頻率 | 實物運行時重點觀察,有問題再針對性調整 | 決定輸出節拍及每輪加減速變化上限 | 名義每輪允許變化更小、回調更密、計算和發佈增加 | 名義每輪變化更大、命令更稀、離散過渡更粗 | 當前名義50 ms/輪,線速度步長0.225 m/s、角速度步長0.25 rad/s;用配置頻率而非實測dt;必須為有效正數 |
scale_velocities |
False;源碼默認False |
不適用,布爾 | 根據實際功能需求開啓或設置 | 是否先選統一eta同比縮放各軸目標變化量,再分別約束 | 不適用 | 不適用 | False仍逐軸平滑;True主要協調Δvx、Δvy、Δwz,不是始終保持最終速度方向;本版沒有動態更新該布爾成員的回調分支 |
feedback |
"OPEN_LOOP";源碼默認同值 |
不適用,模式名稱 | 通常保持當前值,不作為優先調試項 | 選擇當前速度來自內部last_cmd或里程計平均Twist | 不適用 | 不適用 | OPEN_LOOP使用死區前內部指令;CLOSED_LOOP使用OdomSmoother;改閉環前須核對速度對象、參考系、時間、頻率和數據新鮮度 |
1.2.1.2.參數詳解
1.2.1.2.1.smoothing_frequency(定時器、步長與上游控制頻率)
Active階段用wall timer觸發smootherTimer。當前1000/20=50 ms;定時器週期轉換為整數毫秒,其他頻率可能有截斷,例如33 Hz會創建30 ms週期,而變化上限仍按配置33計算。因此不能把任何設置值都視為精確實測頻率。定時器創建
每輪允許變化按參數除以smoothing_frequency計算,沒有根據上次實際回調時間測dt。負載導致週期延遲時,真實每秒的變化過程會受影響;這也是指令平滑約束,不代表實測機械加速度已被限制到同樣數值。
當前controller_server也為20 Hz,所以兩者名義頻率相同;提高平滑頻率可在兩條控制指令之間繼續生成過渡輸出,但不會提高規劃/路徑跟蹤本身的計算頻率。兩定時循環也沒有自動鎖定相位,不能保證每輪輸出都對應剛收到的一條新控制指令。控制器頻率
例如提高到100 Hz而保持加速度不變,名義線速度每輪上限從0.225降為0.045 m/s,角速度從0.25降為0.05 rad/s;理想每秒仍對應4.5 m/s²和5 rad/s²。這是參數計算,未改變當前頻率或測量輸出。
1.2.1.2.2.OPEN_LOOP(內部命令反饋,不等於機械人實測速度)
OPEN_LOOP把上一輪last_cmd作為本輪current速度,再向最新目標靠近。當前死區為0時,它等於上一輪發布的三個有效分量;若以後啓用非零死區,last_cmd記錄在死區置零之前,就不一定等於實際發佈值。反饋選擇與記錄順序
這種模式默認車輛能跟上此前指令,不能從中知道打滑、卡住、驅動限流或真實速度滯後,也不會因收到odometry自動切成實測閉環。當前啓動讀取odom_topic和odom_duration,但不創建OdomSmoother,不用它們參與current速度。
CLOSED_LOOP改用窗口內里程計Twist均值;這裏的“閉環”是平滑器以實測反饋為限變化的起點,並非額外建立一個車輪速度PID。反饋頻率低或一直為0時,每輪可能都從同一個反饋速度重新算,不能像開環那樣自然累計已發命令。
1.2.1.2.3.scale_velocities(縮放速度變化量,不是關閉限幅)
先把目標各軸夾到min/max範圍,再計算dv=目標−current。False令eta=1,各軸分別夾緊自己的dv;True從受約束軸中找更嚴格的統一比例eta,先縮放全部dv,再按各軸自己的約束夾緊。eta與逐軸約束
按當前頻率、從零起步、目標已在速度範圍內且死區為0,舉例:
| 請求目標[vx,vy,wz] | scale_velocities=False首輪 | scale_velocities=True首輪 |
|---|---|---|
| [1.0,0.1,1.0] | [0.225,0.1,0.25] | eta=0.225,得到[0.225,0.0225,0.225] |
前兩項單位m/s,第三項rad/s。False能讓小需求軸先達到目標,但首輪平移方向不按原請求的10∶1比例;True在此例協調變化比例,代價是其他軸也更慢接近。這是源碼公式示例,不是車輛軌跡測試。
current不為0時,同比的是從current到目標的變化向量,不是直接把整個目標速度乘同一個數。先行的各軸絕對速度夾緊、後續逐軸夾緊和死區也可能改變最終比例,不能把True理解為任何情況下都保證原始速度方向不變。
1.2.2.速度與加減速數組(每軸範圍、帶符號下界)
1.2.2.1.參數表
| 參數名 | 當前值 | 單位 | 實車處理建議 | 作用 | 調大效果 | 調小效果 | 生效條件/備註 |
|---|---|---|---|---|---|---|---|
max_velocity |
[2.5, 2.5, 3.0] |
[m/s,m/s,rad/s] | 上實物前必須核對並正確配置 | 設置各軸目標指令的上界 | 正上界提高時允許更大的正向目標 | 正上界減小時更早夾緊正向目標 | 獨立軸範圍,不是平移合速度2.5;只約束經過本節點的目標,不能限制恢復旁路或下游附加自旋 |
min_velocity |
[-2.5, -2.5, -3.0] |
[m/s,m/s,rad/s] | 上實物前必須核對並正確配置 | 設置各軸目標指令的帶符號下界 | 負值向0提高時,允許的反向幅值減小 | 負值更負時,允許的反向幅值增大 | 不是克服靜摩擦的最低非零速度;當前零、小幅正負都允許;須與每軸max保持min≤max |
max_accel |
[4.5, 4.5, 5.0] |
[m/s²,m/s²,rad/s²] | 實物運行時重點觀察,有問題再針對性調整 | 同號且目標幅值不小時,限制每輪速度變化 | 允許更快增速、過渡更短,驅動能力需匹配 | 起步/增速更緩,可能增加跟蹤滯後 | 各活動軸用非負值;當前每輪±[0.225,0.225,0.25];不是車輛jerk限制,也不是PID增益 |
max_decel |
[-4.5, -4.5, -5.0] |
[m/s²,m/s²,rad/s²],帶負號 | 實物運行時重點觀察,有問題再針對性調整 | 目標幅值減小或反向時,限制每輪速度變化 | 負值向0提高時,減速幅值變小、降速更慢 | 負值更負時,減速幅值變大、降速更快 | 本版要求非正;當前每輪幅值與加速相同;零目標和超時置零都經過它,不宜把數值更大理解為制動更強 |
1.2.2.2.參數詳解
1.2.2.2.1.max/min_velocity(x、y獨立夾緊,不是合速度上限)
當前目標限制為vx、vy各在[-2.5,2.5] m/s,wz在[-3,3] rad/s。例如目標(vx,vy)=(2.5,2.5)沒有超出任何一軸,平移模長卻為sqrt(2.5²+2.5²)≈3.54 m/s。僅本平滑器的這組數組不能推出模長≤2.5。目標夾緊
當前OmniPID另有標量平移速度範圍和計算過程;普通跟蹤實際能達到多少要看上游輸出。這裏的3.54只是本數組允許的目標組合,不是證明當前PID或實車已經輸出該速度。min_velocity中的-2.5允許負向運動,沒有把0.1 m/s之類的小速度抬到2.5 m/s。PID速度約束
速度範圍在平滑輸入的座標軸上施加。當前平移指令按gimbal_yaw_fake約定,fake_vel_transform後再換到實際gimbal_yaw;平面純旋轉換軸保持平移模長,但不能保證轉換後每個分量仍滿足同一軸上界。角速度又會加cmd_spin,最終值不由本數組統一夾緊。
源碼夾的是目標,沒有在加減速計算後再做一次最終速度夾緊。當前開環、固定邊界且內部初值在範圍內時,會逐步靠近範圍內目標;若改閉環且反饋本身超界,或運行中縮小邊界,過渡輸出仍可能暫時超出新界。例如current.vx=3、目標夾到2.5、20 Hz減速步長0.225時,本輪得2.775 m/s。此例説明實現順序,未運行閉環或改變限值。
1.2.2.2.2.max_accel與max_decel(符號、加速判據與反向)
每軸依據下麪條件選擇變化區間:
若 abs(v_target) >= abs(v_current),且 v_current × v_target >= 0:
使用加速:Δv ∈ [-max_accel/f,+max_accel/f]
否则:
使用减速:Δv ∈ [max_decel/f,-max_decel/f]
v_next = v_current + clamp(eta × (v_target-v_current),Δv下界,Δv上界)
f為配置的smoothing_frequency。負方向增速仍使用正max_accel來定義變化幅值;正方向減速則使用負max_decel,不是按“正vx用accel、負vx用decel”區分。跨零反向的這一輪先按減速區間處理,之後是否改用加速由下一輪current和目標重新判斷。逐軸公式
當前名義50 ms一輪:線速度最多變0.225 m/s,角速度最多變0.25 rad/s。從零到單軸2.5 m/s至少需要12次名義更新;從零到3 rad/s也需要12次,約0.6 s週期尺度。上游目標持續變化、其他軸統一縮放、定時器相位及實際驅動反饋會改變具體過程;這裏不是實測起步時間。
max_decel從-4.5改成-2,雖然數值提高,幅值卻減小,減速更慢;改成-6則幅值更大。應按車輛制動能力和任務響應調整,不能隨手去掉負號。當前OmniPID還按0.9 m/s²限制標量速度變化,它與本逐軸4.5 m/s²不是同一變量;最終命令受串聯過程共同影響,恢復旁路也不自動受到兩者的相同約束。
1.2.3.里程計反饋(當前OPEN_LOOP不參與估計)
1.2.3.1.參數表
| 參數名 | 當前值 | 單位 | 實車處理建議 | 作用 | 調大效果 | 調小效果 | 生效條件/備註 |
|---|---|---|---|---|---|---|---|
odom_topic |
"odometry";源碼默認odom |
不適用,反饋話題名稱 | 當前運行不使用這個參數,暫不調整 | CLOSED_LOOP時供OdomSmoother訂閲Odometry速度 | 不適用 | 不適用 | 當前開環啓動不建立該反饋訂閲;閉環直接讀twist,不差分pose、不做TF變換;動態改此鍵仍會重建一個OdomSmoother,但開環current分支不會改用它 |
odom_duration |
0.1;平滑器聲明默認0.1 |
s,反饋里程計歷史窗口 | 當前運行不使用這個參數,暫不調整 | CLOSED_LOOP按消息時間戳保留窗口並對速度做樣本均值 | 閉環通常平均更多樣本、減弱波動,但反饋延遲可能增大 | 閉環通常平均更少樣本、響應更快,噪聲影響可能更大 | 不是輸入超時或輸出延遲固定值;當前開環不參與current;具體樣本數由里程計頻率/時間戳決定 |
1.2.3.2.參數詳解
1.2.3.2.1.odom_duration(消息窗口中的樣本平均)
CLOSED_LOOP才在配置時創建OdomSmoother,直接累加Odometry.twist.twist,再除以保留的消息數。新消息到來時按“最新消息時間戳−最早消息時間戳>odom_duration”移除舊消息,因此窗口以消息stamp衡量,且邊界等於0.1 s時仍保留。不是連續時間積分平均,也不按協方差加權。窗口與均值
例如時間戳嚴格等間隔20 ms且穩定收包時,0.1 s窗口名義可保留6個樣本(含兩端);實際時間戳抖動會改變數量,不是固定五幀。odom_duration=0.1也不表示等待0.1 s收滿才允許輸出。
窗口只在收到新里程計時更新;getTwist返回緩存,沒有按now檢查其是否過期。里程計斷流不由velocity_timeout檢測,後者只檢測速度指令斷流;因此切換閉環前必須另行核對反饋新鮮度。當前開環不受這條里程計緩存分支影響。緩存讀取
1.2.3.2.2.當前odometry不能未經核對就直接作為閉環真值
當前發佈者sensor_scan_generation給出的是gimbal_yaw位姿及其差分Twist,平移差分在odom軸上計算,時間分母使用回調steady_clock,還存在首幀處理問題;它不等於已經驗證的底盤速度測量。平面條件下odom軸可能與gimbal_yaw_fake輸入軸近似一致,也不能因此跳過時間、原點和速度對象核對。上游速度實現與問題
尤其angular.z可能包含實際雲台獨立yaw運動,而平滑器的導航旋轉分量與下游附加底盤自旋又是不同來源。OdomSmoother不會根據child_frame_id自動換系或分離這些角運動;切成CLOSED_LOOP前,應明確反饋的是哪個實體、哪個參考點及哪一套軸下的速度。當前保持開環不意味着這些上游問題已經被修復。
1.2.4.死區與輸入超時(低速置零、超時後減速)
1.2.4.1.參數表
| 參數名 | 當前值 | 單位 | 實車處理建議 | 作用 | 調大效果 | 調小效果 | 生效條件/備註 |
|---|---|---|---|---|---|---|---|
deadband_velocity |
[0.0, 0.0, 0.0];源碼默認同值 |
[m/s,m/s,rad/s],速度幅值閾值 | 通常保持當前值,不作為優先調試項 | 將平滑結果中絕對值嚴格小於閾值的分量置零 | 更多低速分量被壓為0,可能減少微動,也可能丟失小幅指令 | 保留更多小幅輸出,低速噪聲/驅動能力需觀察 | 當前全0不剔除非零小速度;不是Δ速度噪聲門檻,也不會把小速度抬高到最小值;閾值按各軸幅值配置 |
velocity_timeout |
1.0;源碼默認1.0 |
s,從最後有效Twist接收起算的ROS時長 | 實物運行時重點觀察,有問題再針對性調整 | 當now−last_command_time嚴格超過此值時,把目標改為0並減速 | 可容忍更長指令間斷,也更久保留舊目標 | 更快觸發降速,也更易受正常抖動觸發 | 不是收到零指令後的等待時間;不檢測里程計/串口斷流;零目標仍經過max_decel,不保證1秒立刻停車 |
1.2.4.2.參數詳解
1.2.4.2.1.deadband_velocity(比較速度絕對值,不是相鄰消息差)
源碼先計算受加減速約束的結果並寫入last_cmd,再對發佈結果做abs(v)<deadband置零。當前全0時,不會因為“速度變化很小”而忽略消息,也不改變任意非零小速度;等於閾值的分量不被置零。死區處理順序
若以後把x死區設0.3 m/s,按當前開環步長、從零朝1 m/s起步:第一輪內部0.225而發佈0,第二輪內部0.45而發佈0.45。這會使發佈值從0直接跳到0.45,不能據內部0.225步長宣稱死區後的每輪輸出仍嚴格遵守同一變化上限。此為順序計算例,未改當前全0死區。
所以死區適合在確認驅動最低可執行速度、微動現象和到點需求後再設置;它不會增加定位精度,也不是控制器的min_x/min_y_velocity_threshold。控制器那些門檻處理輸入里程計,當前這個門檻處理平滑後的發佈速度。
1.2.4.2.2.velocity_timeout(先等待門檻,再把零當目標平滑)
收到有效Twist時保存目標並把last_command_time更新為接收時的now;NaN或Inf消息被拒絕,不刷新這個計時。Twist本身沒有時間戳,因此這裏測的是接收間隔,不是原始指令生成時刻或網絡總延遲。輸入回調
沒有收到過任何指令時,定時回調直接返回,不持續發佈零。收到指令後,即使暫時沒有新消息,也繼續按最新目標平滑;當ROS時間差嚴格>1 s,在某次回調把command改為零,再按當前減速參數生成輸出。顯式收到零指令則立即把它作為新目標,不先等待這1秒。超時分支
例如超時觸發時內部單軸速度為2.5 m/s,當前開環、死區0、20 Hz和減速幅值4.5下,需要12次名義減速更新才能歸零,約0.6 s週期尺度。加上前面的1 s門檻與定時相位,不能寫成“失去輸入1秒內必定停住”;物理停車還受執行端影響。本例是離散公式換算,不是斷流實測。
超時後內部last_cmd已精確為零或stopped=True時,函數直接返回,不再持續發佈零。當前開環能逐步到達精確零,隨後停止發佈;閉環或非零死區情形仍應結合內部狀態與真實反饋判斷,不能把停止發佈當作車已靜止的測量。
本超時使用ROS時鐘,平滑定時器卻使用牆鍾。use_sim_time=True且/clock暫停時,回調可能仍運行、按最新目標繼續生成指令,而1 s超時差不再增長。恢復旁路也不受這條輸入超時統一管理;平滑器發零後,fake_vel_transform仍可能加上保留的cmd_spin。
1.2.5.動態參數、配置邊界與驗證範圍
1.2.5.1.當前1.1.20哪些值會動態進入成員
本節點在activate安裝回調,deactivate移除;本版不能把“ROS參數設置成功”一律理解成所有內部設置已聯動更新。動態參數實現
| 參數組 | Active回調行為 | 本版需要注意 |
|---|---|---|
| smoothing_frequency | 更新double成員,取消舊timer並按新值創建wall timer | 與航點loop_rate不同,本節點確實重建節拍;仍有整數毫秒截斷 |
| velocity_timeout | 把double秒值轉為Duration更新 | 不清空已保存目標或重設最後接收時間 |
| max_velocity、min_velocity、max_accel、max_decel、deadband_velocity | 接受三元素double數組並更新成員 | 回調不完整複核min≤max;縮小範圍不重置last_cmd;應使用完整有效數組 |
| feedback | OPEN_LOOP重置OdomSmoother;CLOSED_LOOP創建新OdomSmoother | 模式切換會改變current來源,不等於已驗證反饋;新窗口需重新接收數據 |
| odom_topic、odom_duration | 更新對應成員並重建OdomSmoother | 即使當時OPEN_LOOP也可能建立訂閲,但current仍走開環分支;舊窗口不沿用 |
| scale_velocities | 沒有PARAMETER_BOOL更新分支 | ROS層值可能改變,成員仍為configure時值;需重新配置/重啓後核對 |
| use_sim_time | rclcpp時間源機制處理 | 不把wall timer改成ROS時鐘節拍;仍會影響超時比較 |
此外,max_accel/max_decel動態回調檢查符號後,即使判為失敗也仍有賦值成員的代碼,批量設置還可能先更新前面的成員再遇到後項失敗。不能依賴“設置失敗”證明內部完全未變;本次沒有運行這種非法設置實驗。符號檢查與賦值
啓動配置要保持三元素數組、加速非負、減速非正、各軸min≤max及有效頻率/時間;當前這些數值符合源碼的基本符號和數組要求,但是否匹配實際驅動能力仍需實物數據。平滑器沒有jerk約束,沒有統一的車體合速度限幅,也沒有代價地圖碰撞檢查;機械能力與碰撞處理不能只靠這組參數證明。
1.2.5.2.本次核對與實物觀察
- 已核對: nav2_velocity_smoother/nav2_util版本、兩份安裝頭文件與庫;reality/simulation參數及安裝副本;兩種navigation_launch的控制器和平滑器重映射、恢復旁路;上游odometry生成和下游速度換系/自旋。
- 源碼能確認: 十二項參數的使用條件、三軸順序與單位;目標夾緊→變化約束→內部記錄→死區發佈的順序;開環和閉環窗口區別;超時零目標降速、ROS與牆鐘差異;動態參數覆蓋及未覆蓋分支。
- 實物觀察時重點: 同時對照cmd_vel_controller、cmd_vel_nav2_result及最終cmd_vel,觀察起步、減速、橫移/方向切換和驅動實際響應;確認附加自旋、恢復旁路和控制指令斷流各自的處理結果。若保持開環,先不以odom_duration作為調試輸出平滑的入口。
- 本次範圍: 僅更新文檔和目錄,未改變運行參數或工程代碼,未發佈速度、未啓動導航/恢復、未進行運動或斷流測試;所有數值例子均為源碼公式計算。