先定義最小刻度與整數範圍
讀回253而實際溫度是25.3°C,通常可以用整數加比例解釋,不必直接把位元當浮點數。本篇教你把固定小數點的儲存、運算與顯示分開,避免先除後乘截斷精度,或把負數的捨入方向弄錯。
本例定義raw是有號整數,scale=100表示每一工程單位有一百個最小刻度,工程值E=raw/100,offset明確設為零。這裡scale是除數,有些設備文件卻把倍率寫成0.01;兩者數學等價,但欄位命名必須附公式,不能只抄一個倍率數字。
raw=1234代表12.34,raw=−1234代表−12.34;若scale改10,同一raw就變123.4與−123.4。顯示小數位數只決定畫面格式,不會自動修改通訊契約。來源scale改版時,接收端公式和資料版本都需要同步處理。
假設儲存採十六位元二補數且沒有保留碼,raw範圍−32768到32767,scale100對應−327.68到327.67。若產品保留某些碼表示故障,有效量測範圍會縮小,必須先排除保留碼,不能把型別可表示範圍直接當成設備允許量程。
把原始整數、scale、offset、單位、有效性和公式版本保留下來。本文提供數學演算與測試向量,不指定通用PLC轉型函式。目標平台的整數除法、溢位與轉換指令,需要另外依所用CPU和語言確認。
練習時先用紙筆寫下儲存單位,例如每一raw代表百分之一攝氏度。接著反算工程值零、十二點三四及負十二點三四各應送出哪個整數。正算和反算能對上,才繼續測捨入與超界;這能先排除把乘倍率和除倍率寫反的初級錯誤。
先算中間結果再決定何時取整
假設要把raw=1234由每單位一百刻度轉成每單位十刻度。新整數理想值是1234×10/100=123.4,再依輸出規則取整。若先做1234整數除100得到12,再乘10只剩120,結果變12.0,原本0.34的資訊提早遺失。
反過來先乘雖能保留分數,也可能溢位。raw最大32767乘100得到3276700,已超過有號十六位元上限32767;本例用有號三十二位元可容納這個乘積,但仍要檢查整個公式,而不是只把目的變數宣告成較寬型別。
中間運算必須在乘法發生前提升寬度。若窄型別乘法已溢位,事後存入寬變數不能還原正確結果。把每一步的允許最大絕對值列出來,包含乘積、加上offset與最後的縮小位寬;有任何一步無法證明範圍,就不能交付該實作。
同scale的兩筆raw可以先加總再除,例如1234加1235等於2469,平均工程值2469/200=12.345。若兩筆先各顯示成一位小數再平均,會把顯示捨入誤差帶進內部運算。內部保留足夠精度,到輸出契約邊界才做一次必要取整。
不同scale不能直接加raw。12.34使用raw1234/100,另一筆2.5使用raw25/10;先統一成百分之一單位,第二筆變250,總raw1484代表14.84。倍率轉換也要做中間範圍檢查,並確認兩筆單位和物理意義可以相加。
把負數捨入寫成可驗收規則
假設要把25.35輸出到一位小數,先計算十分之一單位的理想raw=253.5。向零取整得到253,回轉25.3;取最近且正好一半時遠離零,得到254,回轉25.4。只寫四捨五入或轉INT,還不足以讓跨平台結果一致。
對−25.35,理想raw=−253.5。向零取整得到−253,回轉−25.3;向負無窷取整得到−254;取最近且一半遠離零也得到−254,回轉−25.4。負數案例可以立刻區分向零與向下,不能只測正數253.5。
再測25.25與−25.25:理想raw是252.5與−252.5。一半遠離零分別得到253與−253;最近偶數規則則得到252與−252。這一組用來區分兩種都可能被口頭稱為四捨五入的政策,本篇輸出示例明確選一半遠離零。
使用十進位測試數據時,要注意二進位浮點可能不能精確表示25.35。若來源本來就是百分之一單位整數,優先從2535轉到十分之一單位,以整數商和餘數判斷是否剛好一半;不要先轉浮點再期待每個臨界點都沒有表示誤差。
例如正2535除10,商253、餘5,半數遠離零結果254;負值可先在足夠寬型別中處理絕對量,再恢復符號。最小有號整數的絕對值可能超出原型別,這一步也要檢查。上述是演算法設計,不暗示某個PLC除法的餘數符號。
驗收精度與超界處理
完成後至少保存raw1234→12.34、raw−1234→−12.34、32767→327.67,以及正負25.35、25.25的輸出結果。表格應列原始整數、中間乘積或餘數、取整政策、輸出整數與反算工程值,讓每一個差異都能定位。
本例輸出一位小數並採最近捨入,未超界且數學計算精確時,量化誤差絕對值不超過0.05工程單位。這是輸出解析度造成的誤差,不是感測器準確度保證;實際量測還可能有校正、雜訊與輸入量化誤差,不能全部算在捨入上。
若輸出raw超出目的型別,先依規格拒絕或夾限並標示。夾限會遺失資訊,不能再要求反算回原始工程值。scale為零、scale未知、資料無效與單位不符,也都應在除法前攔下,不能用預設倍率一來讓流程勉強產生數字。
失敗時先按現象查:固定十倍或百倍差異查scale;負數變大正數查有號性;只在半刻度附近差一查捨入政策;大數才錯查中間溢位;每次運算逐步失真查是否拿顯示值反覆回算。每個問題都保留一筆raw案例再修公式。
精確整數到固定刻度的轉換也有平台限制。三十二位元乘積夠不夠、轉浮點是否損失整數精度、最後轉型會拒絕或回捲,都要查實際指令。本文以數值計算說明。
若同一raw要同時供畫面和歷史資料使用,讓兩者共用同一份原始值與公式版本,但各自產生需要的顯示格式。不要讓歷史紀錄只剩格式化字串;日後更正倍率時,保留的原始整數才能重算,並區分原始紀錄與修正後結果。
常見問題
問:raw253一定是25.3嗎?答:只有除數scale為10且offset為零時成立;scale100則是2.53。
問:先乘再除一定安全嗎?答:能避免提早截斷,但必須先證明乘法中間值不溢位。
問:負25.35保留一位一定是負25.4嗎?答:本篇最近且一半遠離零規則如此;向零取整會是負25.3。
問:畫面顯示兩位小數就有百分之一精度嗎?答:格式不會增加原始資料的解析度或量測準確度。
參考:Python decimal官方文件,Rounding modes;僅對照捨入定義,不代表PLC API。
參考:Modbus Application Protocol V1.1b3,第4.2節;比例與單位由產品契約定義。