昨天的手寫字留下一句沒交代的話:速度–曲率冪次律裡的速度增益係數 VGF「畫的圈越大它越大」。今天把這句話補成可驗算的東西,方法是引進另一條與冪次律並列的規律,等時性(isochrony):字寫大,筆尖就跟著變快,書寫總時間只增加一點點。結論先給:在「圖形形狀相似、只改大小」的前提下,若速度隨大小的指數是 s,則 VGF 隨大小的指數是 s − 1/3;文獻報告的 s 約 0.75,於是字放大一倍,VGF 約變成 1.33 倍,總時間只多 19%。其中 s 的數字來自 2017 年一篇兒童手寫研究,是我今天讀到內容的來源;VGF 的推導是我自己做的。

昨天待辦的對帳如下。Lacquaniti、Terzuolo 與 Viviani 1983 年的原文我今天再試了一次(搜尋只回書目,ScienceDirect 全文回 403),仍然沒讀到,留在清單上。Raphaël 與 de Gennes 1999 年的原文今天沒碰,墨膜實驗的回填需要實際拍照,我做不了,也都維持待辦。這三項不影響今天的內容,因為今天的題目只用到速度與長度,不用到墨。

📖 學

一、等時性是什麼:兩個極端與一條恆等式

等時性的說法是:書寫(或繪圖)動作的執行速度與軌跡長度成正比,使得動作總時間大致與大小無關。設軌跡長度為 L,平均速度為 v,總時間為 T = L / v。把速度對大小寫成冪次 v ∝ L^s,就得到 T ∝ L^(1−s)。兩個極端:

指數 s意思字放大 2 倍字放大 5 倍速度放大 5 倍
0等速,完全沒有等時性時間 × 2.00時間 × 5.00× 1.00
0.5居中時間 × 1.41時間 × 2.24× 2.24
0.75文獻報告的量級時間 × 1.19時間 × 1.50× 3.34
1完全等時時間 × 1.00時間 × 1.00× 5.00

這些都是 2^(1−s) 與 5^(1−s) 的算術。另有一條在分析時很有用的恆等式:既然 log v = log L − log T,對 log L 做最小平方迴歸時,速度那條線的斜率恆等於 1 減去時間那條線的斜率。我用隨機資料驗過,兩個數字一致到小數點後 15 位(0.695248 與 0.695248),所以「測速度斜率」與「測時間斜率」是同一件事,不會有兩種答案。

二、文獻說了什麼,以及我讀到多少

等時性的源頭是 Viviani 與 Terzuolo 1982 年在《Neuroscience》的〈Trajectory determines movement dynamics〉,我只查到題名與二手轉述(速度與軌跡長度之間是冪函數關係、動作時間傾向與大小無關),沒讀到原文。

今天實際讀到內容的是 Pagliarini 等人 2017 年《Scientific Reports》的〈Children’s first handwriting productions show a rhythmic structure〉(PMC 開放全文)。我用的是抓取工具對該頁的整理結果,不是逐行自己讀,所以下面的數字請當作「該文所報告」並自行對照原文。研究對象是 298 位義大利語兒童,一到五年級,一年級平均 6 歲 8 個月;任務是寫義大利文單字 burle,有「自發」「寫大」「寫快」三種條件,印刷大寫與連筆兩種字體。用「字長(公分)」對「速度(公分每秒)」做取對數後的迴歸:大寫印刷體斜率 0.75(相關 0.64),連筆體斜率 0.72(相關 0.70),皆 p 小於 0.001,各年級相近。換句話說,s ≈ 0.72 到 0.75,既不是 1(完全等時),也不是 0。

把它代回上表:字放大一倍,時間約多 19%;放大五倍,時間約多 50%,速度卻變成 3.3 倍。這個結果的限制我先列出:受試者是兒童,一個單字,且我沒讀到他們是在每位受試者內部做迴歸,還是把所有人混在一起。成人、漢字、毛筆都不在這篇的範圍內,所以 0.75 只能當作要去檢驗的預期,不是你會量到的數字。

另一篇我只讀到摘要:Viviani 與 Flash 1995(《Journal of Experimental Psychology: Human Perception and Performance》21 卷 32–53 頁)用複雜二維軌跡的繪圖資料檢驗,冪次律與等時性是否都能由最小急動度(minimum-jerk)模型推出。摘要的結論是,速度與曲率的關係(冪次律)可以滿意地推出,但「整體等時性」無法由最優控制假設推出,只有動作次單元內的速度縮放可以。這給我一個提醒:冪次律與等時性是兩條各有來源的規律,不要因為昨天寫了前者,就預設後者自動成立。

三、和昨天接起來:VGF 為什麼隨大小增加

昨天的式子是 v = VGF · κ^(−1/3)。若把整張圖形(含字)按比例放大 λ 倍,曲率 κ 變成 1/λ,而依等時性,速度變成 λ^s 倍。代入得 VGF = v · κ^(1/3),所以 VGF 變成 λ^(s − 1/3) 倍。這是我推的,前提是形狀嚴格相似。

兩個驗算。第一,諧振橢圓、完全等時(s = 1,同一週期):昨天的 60 毫米 × 30 毫米橢圓,每圈 1 秒,VGF = ω(ab)^(1/3) = 6.283 × 1800^(1/3) = 76.4;放大一倍成 120 × 60 毫米,同一週期,VGF = 6.283 × 7200^(1/3) = 121.3。比值 1.587,恰好是 2^(2/3) = 1.587,與 s − 1/3 = 2/3 吻合。第二,s = 0.75:指數 0.417,放大一倍 VGF 乘 1.335,放大五倍乘 5^0.417 = 1.96。

所以昨天綜述說「畫的圈越大,VGF 越大」,在等時性之下是必然的;若有人報告 VGF 與大小無關,代表 s 剛好等於 1/3(速度只隨大小多一點點)。這個預測我沒有在文獻裡對到,只是內部一致性檢查。

四、量測陷阱:路徑長度會被抖動灌水

等時性的量測看起來比昨天單純,只要總時間與路徑長度兩個數。但路徑長度是把取樣點間距加總,座標的雜訊每一步都貢獻一點額外長度,而且與字的大小無關,所以對小字的影響遠大於大字。我用 Python 模擬:一條形狀固定的曲線,路徑長為字高的 12 倍;速度 v = 8.46 · S^0.75(S 是字高,毫米),也就是 S = 10 毫米時約 50 毫米每秒、50 毫米時約 159 毫米每秒;100 Hz 取樣,逐次速度有 8% 的對數常態變異;真值 s = 0.75,字高 10、20、30、50 毫米各 5 次,共 20 次為一組實驗,重複 200 組取平均。座標雜訊的標準差是我假設的,我沒有量過任何實際裝置的抖動。

座標雜訊 SD路徑長度灌水(字高 10 毫米)路徑長度灌水(字高 50 毫米)直接加總的斜率先平滑再加總的斜率
0000.7550.759
0.1 毫米+4.6%+0.4%0.7420.753
0.3 毫米+44.6%+3.7%0.6780.752
1.0 毫米+283%+45.8%未跑斜率未跑斜率

小字的長度被灌水,於是小字的速度被高估,斜率被往下拉(0.3 毫米時從 0.75 變成 0.68)。先用 Savitzky–Golay 平滑(視窗 0.15 秒、三次多項式),或先降到 20 Hz 再加總(模擬中結果與平滑相同),可以把斜率拉回 0.75。昨天是「微分」被雜訊放大,今天是「加總」被雜訊放大,方向不同但病根一樣:低速、小尺度的段落最怕雜訊。

另一個要記的數字是不確定度:同樣設定下,斜率的標準差在每個大小只寫 3、5、10 次時分別是 0.037、0.028、0.021。每個大小寫 5 次的話,95% 區間約 ±0.06,不要用 0.05 的差距下結論。還有一個我沒有拆開模擬的因素:總時間若包含抬筆停頓,等於在每次時間上加了一個與大小無關的常數,會讓 T 對大小更不敏感,斜率偏高或偏低都有可能。我用合成資料(每次中間抬筆 0.3 秒)跑了一次腳本,真值 0.75 得到 0.736,區間 0.69 到 0.79,只是一次結果,不代表偏差方向。

五、一個我自己的假說:效應器換檔的轉折

寫 1 公分的字主要靠手指與手腕,寫 5 公分以上要動用前臂,這在 09-04 的四段槓桿帳裡已算過(腕約 10 公分、肘約 25 到 30 公分)。若不同效應器各有各的最大速度與慣性,log–log 圖上的點可能不是一條直線,而是在某個大小附近彎折。這是我的假說,沒有讀到任何支持或反對的文獻,所以實踐段只把它當作「看殘差」的附加檢查。

🧠 記

**一、等時性:v ∝ L^s,T ∝ L^(1−s)。**文獻(Pagliarini 等人 2017,兒童單字)報告 s ≈ 0.72 到 0.75:字放大一倍,時間 × 1.19、速度 × 1.68;放大五倍,時間 × 1.50、速度 × 3.34。s = 1 才是完全等時,s = 0 是等速。

**二、VGF ∝ L^(s − 1/3)(我推的,形狀相似為前提)。**橢圓放大一倍、週期不變,VGF 76.4 變 121.3,比值 2^(2/3) = 1.587;s = 0.75 時放大一倍為 1.335 倍。

**三、量測:長度用平滑後的路徑。**座標雜訊 0.3 毫米時,小字(10 毫米)的長度被灌水 44.6%,斜率從 0.75 掉到 0.68;平滑後回到 0.752。

**邊界:**Viviani 與 Terzuolo 1982、Viviani 與 Flash 1995 我只讀到題名與摘要;Pagliarini 2017 是抓取整理而非自己逐行讀,且受試者是兒童與義大利文;我的雜訊大小是假設值;換檔假說無文獻支持。

✍️ 實踐

用 40 分鐘量自己的等時性斜率,需要平板或有觸控筆的觸控裝置。

第一步,存成 iso.html 用瀏覽器開(這是昨天 trace.html 的改版,每次試寫標上大小標籤、記錄每一筆的結束;我只用 Node 檢查過語法,沒有在實機的觸控筆上跑,出問題先看 console)。

<canvas id="c" width="900" height="500" style="touch-action:none;border:1px solid"></canvas>
<p>大小標籤 <input id="lab" value="2cm" size="6">
<button onclick="nxt()">下一次(清畫布)</button> <button onclick="dl()">存檔</button> <span id="n">第 1 次</span></p>
<script>
const c=document.getElementById('c'), g=c.getContext('2d'); let rows=[], down=false, k=1;
function add(p,d){ rows.push([k,lab.value,p.timeStamp.toFixed(1),p.clientX,p.clientY,d].join(','));
  if(d) g.fillRect(p.clientX-c.getBoundingClientRect().left,p.clientY-c.getBoundingClientRect().top,2,2); }
c.onpointerdown=e=>{ down=true; c.setPointerCapture(e.pointerId); add(e,1); };
c.onpointermove=e=>{ if(!down) return; for(const p of (e.getCoalescedEvents?e.getCoalescedEvents():[e])) add(p,1); };
c.onpointerup=e=>{ down=false; add(e,0); };           // d=0 標記這一筆結束
function nxt(){ k++; g.clearRect(0,0,c.width,c.height); document.getElementById('n').textContent='第 '+k+' 次'; }
function dl(){ const a=document.createElement('a'); a.href=URL.createObjectURL(new Blob([rows.join('\n')])); a.download='iso.csv'; a.click(); }
</script>

第二步,存成 iso_fit.py(純 numpy;我用一份合成資料測過,每次兩筆、中間抬筆 0.3 秒、座標雜訊 0.3 毫米,真值 0.75,算出 0.736):

import numpy as np, math, sys, csv
from collections import defaultdict
def sg(x, w, p, dt):                         # Savitzky-Golay 平滑(0 階),僅 numpy
    h = w // 2
    C = np.linalg.pinv(np.vander(np.arange(-h, h + 1), p + 1, increasing=True))[0]
    return np.convolve(np.pad(x, h, mode="edge"), C[::-1], mode="valid")
trials = defaultdict(list)
for row in csv.reader(open(sys.argv[1])):
    k, lab, t, x, y, d = row; trials[(k, lab)].append((float(t), float(x), float(y), int(d)))
res = []
for (k, lab), pts in trials.items():
    t, x, y, d = map(np.array, zip(*pts))
    T = (t[-1] - t[0]) / 1000.0              # 第一次落筆到最後一次離筆(含抬筆時間)
    L = 0.0; start = 0                       # 只算「筆在紙上」的墨跡長度,每一筆各自平滑
    for i in range(1, len(d) + 1):
        if i == len(d) or (d[i - 1] == 0):   # d=0 的點是一筆的最後一點
            xs, ys = x[start:i], y[start:i]
            if len(xs) >= 9:
                w = min(len(xs) // 2 * 2 - 1, 9)
                xs, ys = sg(xs, w, 3, 0), sg(ys, w, 3, 0)
            L += np.hypot(np.diff(xs), np.diff(ys)).sum(); start = i
    if T > 0 and L > 0: res.append((lab, L, T, L / T))
res.sort()
for r in res: print("%-6s L=%7.1f px  T=%5.2f s  v=%6.1f px/s" % r)
lL = np.log([r[1] for r in res]); lv = np.log([r[3] for r in res]); lT = np.log([r[2] for r in res])
s, b = np.polyfit(lL, lv, 1); rng = np.random.default_rng(0); n = len(res); bs = []
for _ in range(2000):
    i = rng.integers(0, n, n)
    if np.ptp(lL[i]) > 0: bs.append(np.polyfit(lL[i], lv[i], 1)[0])
lo, hi = np.percentile(bs, [2.5, 97.5])
print(f"n = {n}   slope(log v ~ log L) = {s:.3f}   95% bootstrap CI [{lo:.2f}, {hi:.2f}]")
print(f"duration exponent 1-s = {1 - s:.3f}  (T ~ L^(1-s));  2x size -> T x{2 ** (1 - s):.2f}")

第三步,寫字。固定一個兩字詞(例如「春風」),字高約 1、2、3、5 公分四種,每種寫 5 次,共 20 次;順序打散(例如 2、5、1、3、3、1、5、2、…),不要由小到大一路寫下去,以免疲勞或熱身與大小混在一起。指示只有一句:「用你平常寫字的速度寫」,不要刻意放慢或加快。每次寫完按「下一次」,換大小時先改標籤。字高用畫布上的格子目測,不必精準,因為斜率用的是量到的路徑長度,標籤只是分組名。全部寫完按「存檔」,執行 python3 iso_fit.py iso.csv。

第四步,判讀。輸出的斜率就是 s。以我的算術與模擬為基準,s 約 0.9 以上接近完全等時,0.6 到 0.9 屬部分等時(文獻量級在這裡),0.3 以下接近等速;這些分界是我訂的,不是文獻值。看區間寬度:每個大小 5 次時,區間寬約 ±0.06 是預期,若遠大於此,先檢查有沒有幾次寫到一半停下來想事情。接著算 VGF 的預測:s 代入 s − 1/3,放大一倍乘 2^(s−1/3)。選做:把殘差(每次的 log v 減去直線)按大小排,看最小與最大兩組是否系統性偏離直線,對照第五節的換檔假說。

沒有觸控裝置的紙筆版:寫同一個兩字詞,字高 2 公分與 6 公分(放大 3 倍),各 5 次,用手機碼錶量從落筆到收筆的時間(碼錶誤差約 0.2 秒,在 3 秒左右的總時間上約 7%,所以要多寫幾次取平均)。時間比 = 3^(1−s):s = 0 時 3.00,s = 0.5 時 1.73,s = 0.75 時 1.32,s = 1 時 1.00。用平均時間比反推 s = 1 − ln(比值)/ln 3。這個版本不需要量長度,但假設兩種大小的字形相似。

限制:一個人、一種裝置、螢幕上寫字的摩擦與紙上不同;兩個字的詞筆畫數少,總時間短;文獻的 0.75 來自兒童,你的數字高低都有可能。若你量到的 s 與 0.75 差很遠,這本身就是有資訊的結果,把四個大小的平均時間與斜率一起記下來。

🔗 延伸學習


💬 問 AI

我在做手寫的等時性(isochrony)量測,請逐項回答,並嚴格區分三類:(一)原文明確寫了的、(二)你能查證或憑訓練資料確定的、(三)純屬推論的,每項標明把握程度(高/中/低);查不到或不確定就直說,不要編造文獻、數字或公式。這是學習與實驗設計。
 
【A 組:定律與文獻】
1. 我用 v ∝ L^s、T ∝ L^(1−s) 描述等時性,並推出 log v 對 log L 的最小平方斜率恆等於 1 減去 log T 對 log L 的斜率。請檢查這兩個說法。
2. Viviani & Terzuolo 1982(Neuroscience)原文實際報告的指數是多少?他們用的是成人嗎?Pagliarini 等人 2017(Scientific Reports,298 位義大利兒童,斜率 0.75 與 0.72)是在每位受試者內部做迴歸,還是混合所有人?
3. 成人書寫、漢字、毛筆有沒有報告過等時性指數?數值大概在哪裡?
 
【B 組:與冪次律的關係】
4. 我推:形狀相似放大 λ 倍,速度放大 λ^s,曲率變 1/λ,所以 VGF 放大 λ^(s−1/3)。請檢查;並說明 Viviani & Flash 1995 摘要說「整體等時性無法由最小急動度推出」在這個推導裡的含意。
5. 如果文獻報告 VGF 與大小的關係,指數有沒有和 s − 1/3 對上?
 
【C 組:量測】
6. 我模擬:座標雜訊 0.3 毫米、100 Hz,字高 10 毫米時路徑長度被灌水 44.6%,斜率從真值 0.75 掉到 0.68;先用 Savitzky–Golay(視窗 0.15 秒)平滑回到 0.752。這個結果合理嗎?實際的觸控筆或平板座標雜訊大概是多少毫米?
7. 總時間包含抬筆停頓,對斜率的影響方向怎麼判斷?應該只用筆在紙上的時間,還是包含抬筆?各有什麼代價?
8. 小字用手指與手腕、大字用前臂,log–log 圖上有沒有報告過斜率轉折?
 
【D 組】
9. 把所有存疑項目分成三堆:(一)憑訓練資料就能判斷的、(二)必須查一手文獻的(請列出先查哪幾篇)、(三)必須用實際書寫資料才能回答的。