Language

Monday, March 3, 2014

漫談分貝(dB) 這一堆玩意兒

今天是 3 月 3 日, 恰好是發明電話的貝爾的生日, 所以今天我們來談以貝爾的姓氏命名的單位, Bel 以及 decibel(分貝或 dB)。剛開始接觸數位訊號處理或是通訊領域, 最常令人困惑的就是 dB 這個玩意兒, 它既不是一個單位, 也不怎麼直覺, 接下來就讓我們來看看這玩意兒吧。

分貝(dB, or decibel) 當初是拿來描述量測的電話線訊號衰減量, 在 1928 年貝爾系統公司(貝爾電報電話公司的相關企業)把原本使用的 Transmission Unit(TU) 改名為 decibel, 並且增加 Bel(1 Bel = 10 decibel), 用來紀念發明電話的貝爾(Alexander Graham Bell, March 3, 1847 – August 2, 1922),1 文章發布的今天剛好是他的生日。

分貝是拿來描述衰減量的, 只是一個相對單位而已, 就像一般講的數量級一樣, 一個數量級代表的是十倍, 而 1 Bel 就是 10 dB, 是由以 10 為基底的對數函數產生:

\begin{equation} L_{dB} = 10~\log_{10} \frac{P_1}{P_2} \end{equation}

要先記住上述衰減量是拿來描述功率衰減的, 我們也可以用 dB 描述振幅的衰減量, 而初學者很容易搞混計算功率以及振幅衰減的分貝公式。

功率:

\begin{equation} L_{dB} = 10~\log_{10} \frac{P_1}{P_2} \end{equation}

振幅(如電壓、電流、聲壓):

\begin{equation} L_{dB} = 20~\log_{10} \frac{A_1}{A_2} \end{equation}

只要先記得分貝都是計算功率的公式, 再利用電路的基本公式: \(P=IV=\frac{V^2}{R}\), P 為功率, I 為電流, V 為電壓, R 為電阻, 那麼:

\begin{equation} L_{dB} = 10~\log_{10} \frac{P_1}{P_2} = 10~\log_{10} \frac{V_1^2}{V_2^2} = 20~\log_{10} \frac{V_1}{V_2} \end{equation}

而大部分功率都是振幅的平方倍, 所以都可以得到上述的式子, 因此振幅計算公式前面的常數是 20。

當倍數轉換成分貝讓乘法轉換成加法, 除法轉換成減法, 使得運算更為簡單, 其數值也不容易超過能夠表示的範圍。例如接收機的情況, 從發射機一路到接收機的各級增益, 按照順序列表:

  • 發射機 \(P_{TX} = 1W = 10\log_{10} \frac{1W}{1mW} = 10\log_{10} 1000 = 30 dBm\)
  • 發射天線增益 \(G_{TXANT} = 10 dBi\), 或 10 倍
  • 空氣中衰減 \(ATT_{channel} = -60 dB\), 或 1/1000000 倍
  • 接收機天線增益 \(G_{RXANT} = 10 dBi\), 或 10 倍
  • 接收機 LNA 增益 \(G_{RX} = 20 dB\), 或 10 倍

計算各級增益, 以 dB 來計算,只要算

\begin{equation} RSSI_{dB} = P_{TX} + G_{TXANT} + ATT_{channel} + G_{RXANT} + G_{RX} = 30 + 10 - 60 + 10 + 20 = 10 dBm \end{equation}

而用倍數來計算則會是這樣:

\begin{equation} RSSI = 1 * 10 / 1000000 * 10 * 10 = 0.001 \end{equation}

可以看出用倍數算會出現動態範圍比較大的整數或小數, 而 dB 值只要加加減減就出來了, 這在浮點運算的時候看不出好處, 但在定點運算上可以看出來上述的例子, dB 的計算只要給有號整數部分 8 個位元即可表示, 而線性尺度(linear scale, 也就是上述所稱的倍數) 的計算則會做到超過 20 位元的除法。

除了運算上會變得動態範圍變小以外, dB 公式中的對數函數也有將比較小的數值變化放大並將比較大的數值變化縮小的功用。

Resp_linear.png

Figure 1: 線性尺度

Resp_dB.png

Figure 2: dB 尺度

可以看得出來 320kHz 以下的變化原本在線性尺度看不太出來, 但在 dB 尺度看出來上下變化範圍有 10 dB 的大小, 這對訊號來說已經算是不小的影響。而線性尺度看起來差異很大(一半)的 400kHz 到 900kHz 的範圍, 在 dB 尺度上只有 4 dB 左右, 320kHz 變化 10 dB 在這個例子中, 因為那不是我們要的訊號, 所以影響不大, 但若發生在我們想要的頻譜上, 線性尺度可能就會看不太出來, 這個是 dB 尺度的優點。

以上就是對於 dB 簡單的介紹, 那麼我們常常看到 dB 後面還加上一些字母, 那是什麼意思呢?我們來看一些常用的 dB 家族。

分貝後面如果加上了其他的字母, 代表分母的參考量, 就會從相對值變成絕對值。

  • dBm 代表分母是 1mW, 所以 \(dBm = 10~\log_{10} \frac{P}{1mW}\)
  • dBW 代表分母是 1W, 所以 \(dBW = 10~\log_{10} \frac{P}{1W}\)

如果是分貝後面加上其他字母, 但是該字母被括號刮起來, 是代表訊號的種類。

  • dB(A) 代表聲壓, 是一個絕對單位, 參考訊號位準是 \(20~\mu~Pa\),2 是人耳所能聽到的下限, 又因為聲音是振幅, 所以計算公式為:
\begin{equation} L_p = 20~\log_{10}\frac{P_{rms}}{P_{ref}}, P_{ref} = 20~\mu~Pa \end{equation}

聲音用 dB 來表示是因為耳朵對於壓力變化大小是對數級的, 至於頻率變化也有類似的關係, 因此對於噪音計算定義了 octave band filter, 每一個 octave band 的中心頻率是下一個 band 的 2 倍或 1/2。3

dBi 是用來描述天線增益, 定義是最大的波束相對於理想均勻球體輻射樣式(isotropic) 的增益。

dBm/Hz 則是拿來描述功率密度(power spectral density), 意思就是每 1 Hz 所含的功率, 如果你有功率密度 -30 dBm/Hz, 在 10 MHz 寬度上都是平坦的, 其他地方的數值都小到可以忽略, 那麼總發射功率就是 \(-30 + 10 \log_{10} {10 \times 10^6} = 40 dBm = 10W\)

我們描述 SNR(訊雜比) 的時候也常常用 dB 來描述, 大部分的接收機, 比如說 Wifi, Bluetooth, LTE, WCDMA 等等都會顯示 SNRdB, 而筆者常常看到有人引用這個 SNR 值的時候, 忘記加上 dB, 這樣會造成非常大的誤解與巨大的差異, 舉例來說, 如果 SNR 是 60 dB, 而引用的時候說 SNR 是 60, 那麼這個意思就是 \(\frac{P_{signal}}{P_{noise}} = 60\) 了, 而 \(60~dB = 10^{\frac{60}{10}} = 1000000\), 差距有 \(\frac{1000000}{60} = 16666.7\), 有上萬倍的差異啊!筆者知道分貝對初學者來說, 是個不容易搞懂的數量, 因此寫了這篇文章, 希望大家在接觸訊號與通訊領域的時候, 看到 dB4 能夠不再那麼陌生。

Author: Albert Huang

Created: 2014-03-03 Mon 21:47

Emacs 24.3.1 (Org mode 8.2.1)

Validate

Tuesday, February 18, 2014

談談 ARM Cortex-M4F 上的 DSP 功能

1 談談 ARM Cortex-M4F 上的 DSP 功能

1 前言

從 ARM2 在 1986 年問世以來, ARM 的處理器一向以省電性聞名, 之後到了智慧型手持裝置的時代, 省電性更是非常迫切的需求, 到了 2005 年, 有 98% 的手機上面至少有一顆 ARM 的處理器。1 專精於數位訊號處理的工程師, 除了傳統的數位訊號處理器以外, 勢必要了解一下這樣的趨勢, 以及如何在自己的專案中評估使用 ARM 處理器的可能性, 本文將會針對與中低階 DSP 較為類似的 ARM Cortex-M4F 上的 DSP 功能來討論。

2 ARM Cortex-M4F 功能簡介

ARM Cortex-M4F 是 ARM Cortex-M 系列的處理器裡面功能最為強大的一個, 而 Cortex-M 系列的 M 是指 microcontroller, 下表列舉了部分的 Cortex-M 系列處理器的比較, 可以看出 Cortex-M4F 在指令集上有硬體乘法、硬體除法、飽和運算、數位訊號處理延伸指令以及浮點運算。

ARM Cortex-M 系列指令集支援2

ARM Cortex-M Thumb Thumb-2 硬體乘法器 硬體除法器 飽和運算 DSP 延伸功能 浮點 ARM 架構 核心架構
Cortex-M3 完整 完整 單一時脈 ARMv7-M Harvard
Cortex-M4 完整 完整 單一時脈 選項 ARMv7E-M Harvard

另外, Cortex-M4F 還有以下特點是數位訊號處理器程式設計師會注意的:

  • 沒有快取記憶體
  • 沒有記憶體管理單元(MMU)
  • 記憶體保護單元(MPU) 是選項功能
  • 中斷處理延遲最長 12 個時脈

在擁有 DSP 能力的處理器中, 有幾個分類:

  1. 數位訊號處理器(Digital Signal Processor)
  2. 數位訊號控制器(Digital Signal Controller)

第一種就是一般印象中的數位訊號處理器, 其特點就是架構完全針對數位訊號處理而優化, 是真正能夠持續的以單一時脈執行乘積累加運算, 亦即乘積累加所需的運算元會在下一個時脈就已經載入並執行運算, 而不用等待運算元從記憶體載入的時間, 發揮極致的運算能力, 但是設計複雜度比較高, 一般來說省電性不如微處理器或微控制器。這種有 TI TMS320C67x 定點與浮點 DSP 系列與很早期的 Motorola(現為 Freescale) DSP56300(這是 Steve Jobs 出走 Apple 時創立的 NeXT 公司在他們的工作站使用的 DSP56001 的下一代產品線, 是特殊的 24-bit DSP)。大部分的 DSP 只支援定點運算, 因為同樣的面積與功耗, 定點運算能夠提供更高的運算能力, 而且以訊號處理的應用而言, 不需要浮點數這麼高的動態範圍。當然, 浮點 DSP 還是有其優勢, 尤其是在一些必須縮短開發時間的應用上, 浮點數能力使得程式設計師不需要耗費太多精神與時間處理定點數運算。

第二種就是把微控制器整合數位訊號處理能力而成, 以傳統的微控制器為主, 擁有豐富的周邊支援與輸出入腳位。ARM Cortex-M4F 屬於這一個分類, 並且因為 ARM 架構被廣泛的支援, 使得 ARM Cortex-M4F 擁有豐富的工具可以應用。以 STMicroelectronics 公司的 STM32F 系列來說, 其 10ku 報價在 2 至 10 美元之間, 往下與 16-bit MCU 重疊, 往上與入門級 DSP 重疊。

3 DSP 運算的核心: 乘積累加(Multiply-and-Accumulate)

我們常常看到支援數位訊號處理能力的處理器都會強調其乘積累加(MAC, or Multiply-and-ACcumulate) 的能力, 這是因為在數位訊號處理演算法上, 大量的使用 MAC 運算。

不管是有限響應濾波器:

\begin{equation} y[n] = \sum_{k=0}^{N-1} h[k]x[n-k] \end{equation}

或是無限響應濾波器:

\begin{equation} y[n] = b_0 x[n] + b_1 x[n-1] + b_2 x[n-2] + a_1 y[n-1] + a_2 y[n-2] \end{equation}

還是快速傅利葉轉換中很重要的 butterfly 運算:

\begin{eqnarray} Y[k_1] & = & X[k_1] + X[k_2] \\ Y[k_2] & = & (X[k_1] - X[k_2])e^{-j\omega} \end{eqnarray}

這些都非常仰賴乘積累加的運算。

ARM Cortex-M4F 與乘法或乘積累加有關的指令集如下表2:

運算 指令意義 指令列表
16 * 16 = 32 Signed Multiply (SMUL) SMULBB, SMULBT, SMULTB, SMULTT
16 * 16 + 32 = 32 Signed Multiply and Accumulate (SMLA) SMLABB, SMLABT, SMLATB, SMLATT
16 * 16 + 64 = 64 16-bit Signed Multiply with 64-bit Accumulate (SMLAL) SMLALBB, SMLALBT, SMLALTB, SLMALTT
16 * 32 = 32 16-bit by 32-bit signed multiply returning 32 MSB, i.e. word (SMULW) SMULWB, SMULWT
(16*32) + 32 = 32 Q setting 16-bit by 32-bit signed multiply with 32-bit accumulate (SMLAW) SMLAWB, SMLAWT
(16*16) + (16*16) = 32 Q setting sum of dual 16-bit signed multiply (SMU-AD) SMUAD, SMUADX
(16*16) - (16*16) = 32 Dual 16-bit signed multiply returning difference (SMU-SD) SMUSD, SMUSDX
(16*16) + (16*16) + 32 = 32 Q setting dual 16-bit signed multiply with single 32-bit accumulator (SMLAD) SMLAD, SMLADX
(16*16) - (16*16) + 32 = 32 Q setting dual 16-bit signed multiply subtract with 32-bit accumulate (SMLSD) SMLSD, SMLSDX
(16*16) + (16*16) + 64 = 64 Dual 16-bit signed multiply with single 64-bit accumulator (SMLALD) SMLALD, SMLALDX
(16*16) - (16*16) + 64 = 64 Q setting dual 16-bit signed multiply subtract with 64-bit accumulate (SMLSLD) SMLSLD, SMLSLDX
32 * 32 = 32 Multiply MUL
32 + (32 * 32) = 32 Multiply accumulate MLA
32 - (32 * 32) = 32 Multiply subtract MLS
32 * 32 = 64 Long signed/unsigned multiply SMULL, UMULL
(32 * 32) + 64 = 64 Long signed/unsgiend accumulate SMLAL, UMLAL
(32 * 32) + 32 + 32 = 64 32-bit unsigned multiply with double 32-bit accumulation yielding 64-bit result UMAAL
32 + (32 * 32) = 32 MSB 32-bit multiply with 32-most-significant-bit accumulate SMMLA, SMMLAR
32 - (32 * 32) = 32 MSB 32-bit multiply with 32-most-significant-bit subtract SMMLS, SMMLSR
(32 * 32) = 32 MSB 32-bit multiply returning 32-most-significant-bits SMMUL, SMMULR

以上都是定點運算3, 並且每一個指令都能夠在一個時脈執行完畢, 或許你會問:「我只想寫 C 語言, 而且已經有函式庫, 為什麼還需要了解指令集呢?」如果你不碰數位訊號處理應用, 或許可以不用了解這一顆處理器的指令集, 但就像作業系統的程式設計師必須要了解處理器關於作業系統的指令集一樣, 數位訊號處理工程師必須在了解所有 DSP 指令集後, 想盡辦法像國稅局一樣榨乾這顆處理器, 一滴都不能剩。尤其是函式庫提供的定點運算都只有 Q31 與 Q15 的選擇, 如果你有其他特殊的需求, 就得自己寫數位訊號處理程式碼。在 C 語言的優化過程中, 使用指令集的 intrisincs 是不可避免的。

ARM Cortex-M4F 也有符合 IEEE-754 規範的浮點運算單元, 而單精確浮點數在訊號處理演算法上扮演很重要的角色, 下表列舉了單精確浮點數的運算與時脈數:

單精度浮點運算 指令 執行時脈
加/減 VADD.F32, VSUB.F32 1
乘法 VMUL.F32 3
乘積累加 VMLA.F32, VMLS.F32, VNMLA.F32, VNMLS.F32 3
Fused MAC VFMA.F32, VFMS.F32, VFNMA.F32, VFNMS.F32 3
平方根 VSQRT.F32 14
除法 VDIV.F32 14

可以看出浮點數的乘法比較花時間, ARM Cortex-M4F 有提供 fused MAC 指令以增加精確度。

接下來, 我們來看實際上拿 ARM Cortex-M4F 寫數位訊號處理程式的時候的效能, 以下是一般標準的 FIR 濾波器的程式碼:

void fir(q31_t *in, q31_t *out, q31_t *coeffs, 
         int *state, int numTaps, int blkSize)
{
    int sample;
    int k;
    q63_t sum;                  /* Q2.62 in 64-bit acccumulator */
    int idx = *state;

    for (sample=0; sample<blkSize; sample++)
    {
        state[idx++] = in[sample];
        sum = 0;
        for (k = 0; k < numTaps; k++)
        {
            sum += (q63_t) coeffs[k] * state[idx]; /* 1. Fetch coefficient and sample. 2. Perform MAC */
            idx--;                         /* Pointer update for circular addressing */
            if (idx < 0)
            {
                idx = numTaps - 1; 
            }
        }
        out[sample] = (q31_t) (sum >> 31u); // Convert Q2.62 to Q1.31
    }
    *state = idx;
}

參考更早之前的 FIR 濾波器運算式:4

\begin{equation} y[n] = \sum_{k=0}^{N-1} h[k]x[n-k] \end{equation}

h[k] 就是 coeffs[k], x[n-k] 就是 state[idx], numTaps 就是 N, out[sample] 則是 y[n].

在最內側的迴圈中包含了:

  • 載入係數與輸入取樣
  • 執行乘積累加運算
  • 循環定址的指標更新

在現代 DSP5 中, 上述運算可以在一個或兩個時脈內執行完畢, 如:

    do          x0,FirLoop
     mac    x1,y1,a     x:(r0)+,x1  y:(r4)+,y1
FirLoop

這個迴圈指令是 zero overhead loop, 而且只需一個時脈指令就能完成上述三項最內側迴圈需要完成的事項。這是數位訊號處理器的能力, 而且也需要使用組合語言來優化, 那我們來看 ARM Cortex-M4F 用 C 語言能夠達到的速度:

動作 時脈數
載入 coeffs[k] 2
載入 state[idx] 1
乘積累加 1
idx-- 1
循環定址 4
迴圈 overhead 3
總共 12

從上述表格中可以看出, 即便 ARM Cortex-M4F 這類數位訊號控制器擁有一個時脈就可以完成的乘積累加指令, 加上其他額外的執行成本, 就增加到 12 個時脈才能完成一個乘積累加。有一些 C 語言優化的方式:

  • Circular addressing alternatives
  • Loop unrolling
  • Caching of intermediate variables
  • Extensive use of SIMD and intrinsincs(還是用上指令集)

如果用上這些, 並且輸入以及係數是 16-bit 的情況下, 是可以達到平均每個乘積累加 1.625 個時脈的程度。6如果需要的精確度是 32-bit 的情況下, 可能會需要更多時脈, 但已經與數位訊號處理器差距不算遠了, 當然若與同樣擁有 SIMD 能力的數位訊號處理器並且優化相比, 還是差上一大截, 但是搭配 ARM 廣泛的周邊與軟體資源, 這樣的效能已經很吸引人。

在數位訊號處理程式上, ARM 提供了 CMSIS(Cortex Microcontroller Software Interface Standard) DSP 函式庫, 在實際開發時只需要呼叫這些函數即可, 但要善用這個函式庫, 還是需要對於數位訊號處理基本概念有認識才行。

另外, 在使用 ARM Cortex-M4F 的累加器的時候, 需要注意的是, 累加器不會自動作飽和動作, 因此做定點運算的時候, 必需自行預留累加的空間, 或是先將數值預先縮小以避免溢位。

4 結語

從 ARM7 問世開始, ARM 這間公司展現的企圖就是除了 32-bit microprocessor 以外, 還要開始蠶食 8-bit/16-bit MCU 的市場, 經過了一陣子的努力之後, 繼續推出了 ARM Cortex-M 系列展現強烈的企圖心, 如今採用的公司漸漸增多, 侵蝕了部分 16-bit MCU 的市場, MCU 程式設計師必須要看清這個趨勢, 學習 ARM 系列架構來接受這個潮流變化。Cortex-M 系列最高接的 Cortex-M4F 提供了數位訊號處理能力, 成為數位訊號控制器, 在省電性主導的地方, 與 16-bit DSP 相比互有優劣, 但 Cortex-M4F 提供了 32-bit 浮點運算, 讓開發時間能夠縮短, 千萬不可小看 ARM 在數位訊號控制器上的未來性。本文只討論了 ARM Cortex-M4F 的 DSP 能力以及在新的 DSP 專案中使用 ARM Cortex-M4F 的可能性, 筆者將在後續的文章中陸陸續續介紹如何使用 Cortex-M4F 來做實際的數位訊號處理應用。

Footnotes:

2

ARM® Cortex™-M4 Processor Technical Reference Manual Revision r0p1, http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0439d/index.html

3

有關於定點數 Q format 可以參考我之前寫的「定點數表示法」, http://alberthuang314.blogspot.tw/2012/08/blog-post.html

4

有關於 FIR 有限響應濾波器的概念可以參考我之前寫的「淺談動平均濾波器」, http://alberthuang314.blogspot.tw/2012/08/blog-post_24.html

5

這還是 Motorola DSP56300 的組合語言, 是將近二十年前的產品。

6

Kishore Dasari, Designing with the Cortex-M4, http://www.arm.com/files/pdf/dspconceptsm4presentation.pdf

Author: Albert Huang

Created: 2014-02-18 Tue 22:05

Emacs 24.3.1 (Org mode 8.2.1)

Validate

Saturday, February 2, 2013

如何在 GNU Emacs 減少按鍵次數並提升工作效率


GNU Emacs 是一個非常 powerful 的編輯器, 這個就不需要我多作介紹, 但是與 vim 相比, GNU Emacs 有一個比較大的缺點就是按鍵多。只要是採用 modeless 的方式編輯, 又要功能多, 按鍵數很難減少, 但是還是有一些方法, 可以讓我們整體的按鍵數量變少的, 可以減少手的傷害。至於那些買了青軸機械式鍵盤之後, 想辦法多打字讓別人聽按鍵聲音的, 就不在本文的討論範圍內。

GNU Emacs 有兩種方式減少打字數目, 筆者認為值得推薦, 一種是用巨集(macro), 另一種是用 skeleton 套件。當然還有第三種是編寫 Emacs Lisp, 寫點函數, 這個難度比較高, 不太適合初學者。今天筆者介紹的這兩個方式都很適合初學者使用。

Table of Contents


巨集

首先, 我們來看看巨集。要知道 EMACS 這個名字是由 Editing MACroS 來的, 巨集可是 Emacs 的核心價值啊!只要你發現你在做重複性的工作, 就可以把那些一連串的按鍵動作變成巨集。
定義巨集很簡單, 在你的一連串按鍵動作開始之前, 先輸入 C-x (, 然後就開始按照平常的動作按按鍵, 按完所有按鍵之後, 鍵入 C-x ) 就完成巨集的定義了。
要執行剛剛定義完的巨集, 就按 C-x e, 也可以配合 Emacs 的數字前置指令來執行多次的巨集。比如說你想要執行這個巨集四次, 就鍵入 M-4 C-x e 就會執行這個巨集四次。
The quick brown fox jumps over the lazy dog

比方說, 你想要把上面這個檔案改成一個英文單字一行, 可以用巨集來做, 方法如下:
按鍵動作
C-x (開始錄製巨集
M-f把游標往前移一個單字
C-d刪除一個字元
[ENTER]插入換行字元
C-x )結束巨集的錄製

上述的巨集可以讓一個單字單獨存在於一行, 把剩下的文字換到下一行去, 如果要把所有英文單字都單獨存在於一行, 就需要重複作這個巨集。可以先用 M-x count-words-region 來計算這一行的單字數, 九個。所以要處理完所有的單字, 就輸入按鍵 M-9 C-x e, 不過通常我們錄製巨集的時候已經先做完一遍了, 那這時候你只需要執行 8 次就好。執行完結果就會如下所示:
The
quick
brown
fox
jumps
over
the
lazy
dog



Skeleton




如果你的重複性工作, 是經常性的使用到, 比方說寫函數時的註解, 常常需要寫函數名稱、作者、建立的時間等等資訊, 有些是每次都寫一樣的資訊(如作者), 有些則可以由函數執行結果得來(如日期), 有些需要打兩次一樣的字串(如函數名稱), 那麼 skeleton 就是一個不錯的工具, 讓你減少打字數目。


使用 skeleton 的方法如下:

(define-skeleton your-skeleton-name
  "String to describe this skeleton."
  "String that will be inserted when you call your-skeleton")



然後你就可以用 Emacs Lisp 函數一樣的呼叫方式來呼叫:
M-x your-skeleton-name 這函數就會自動從游標位置插入預先定義好的字串。
高階一點的用法就會牽扯到

  • 使用者輸入字串

    • 使用 (skeleton-read)

  • 重複使用者輸入的字串

    • 使用 v1, v2 變數

  • 游標最後所處位置

    • 使用 "_" 來標示

  • 呼叫 Emacs Lisp 函數來插入字串

    • 直接呼叫


筆者就用我自己用的一個例子來說明 skeleton:
; Skeleton for assembly subroutine header
(define-skeleton insert-asm-header
  "Prompt for subroutine name and insert assembly subroutine header"
  "" ?\n
  ";******************************************************************************" ?\n
  "; Name:\t\t" (setq v1 (skeleton-read "Subroutine name: "))?\n
  "; Purpose:" ?\n
  ";   " (skeleton-read "Purpose: ") ?\n
  "; Method:\t" ?\n
  ";   " ?\n
  "; Parameters:\t\t" (skeleton-read "Parameters: ") ?\n
  "; Affected regs:\t" ?\n
  "; Author:\tAlbert Chun-Chieh Huang, " (insert-current-date) ?\n
  ";******************************************************************************" ?\n
  v1 \n
  "" _ \n
  "rts" \n
  )



定義完之後, 我們就可以用 M-x insert-asm-header 來呼叫這個 skeleton, 呼叫之後, 在 mode line 會出現
Subroutine name: 



要求使用者輸入副程式名稱, 除了馬上把這名稱字串放到 "Name:" 之後, 並且存在 v1 這個變數裡。 接下來會要求使用者輸入 Purpose: 說明這個副程式的用途, 並把副程式用途就插入 (skeleton-read "Purpose: ") 的位置上。接下來的 Parameters: 也一樣。到了 Author 的地方就呼叫 Emacs Lisp 函數 (insert-current-date) 把日期填上。
在倒數第四行的 v1 就是把剛剛存在 v1 這個變數的副程式名稱取代 v1 填上去。
倒數第三行的 "_" 就是指示 skeleton 插入完這些字串之後, 游標要回到這個位置來。
所有被雙引號包起來的都是字串, 不會有特殊意義。在雙引號以外的, 就是 Emacs Lisp 函數、變數、或是特殊字元。=\n= 是換行並且依照所處的 mode 縮排, 而 ?\n 則只有單純的換行字元而已。


下面的例子就是執行完後的結果, 游標會停在倒數第二行, 與 rts 同樣的縮排位置上, 方便我打第一個 instruction.
;******************************************************************************
; Name:         Test
; Purpose:
;   Test
; Method:       
;   
; Parameters:           a1
; Affected regs:        
; Author:       Albert Chun-Chieh Huang, 02 February 2013
;******************************************************************************
Test
        
        rts


如果對於 skeleton 想要有更深入的了解, 可以按 C-h f skeleton-insert, 裡面有關於 define-skeleton 的字串該怎麼寫的詳盡說明。






結語




要提升工作效率, 第一要件就是先找出重複的工作, 並且用快速有效率的方法執行這個工作。當你找出重複性的部份之後, 可以把重複不變的部份抽出來變成巨集, 如果有經常性的重複編輯工作, 就可以考慮用 skeleton 來定義, 如果有每一次呼叫變動的部份, 就考慮把這些變動用呼叫函數或是輸入參數的方式來引入, 如此就可以有效的減少按鍵次數, 並且提升工作效率。



--
Albert Huang
Chun-Chieh Huang(黃俊傑)

Tuesday, December 18, 2012

GNU Radio Talk: A Glimpse into Developing Software-Defined Radio by Python

這是我十二月十七日在 PyHUG(一個新竹的 Python 社群, 由陳永昱(Yung-Yu Chen) 博士與我在 2011 年所組織發起的)講的講題, 內容簡介了軟體無線電的概念, 軟體無線電的硬體以及開源的專案 GNU Radio, 以及使用 GNU Radio 來開發軟體無線電的三種不同路徑的簡介。這是 GNU Radio 系列講題的第一個, 接下來的講題目前未定, 可能會從數位訊號處理的概念以及如何使用 GNU Radio 來作濾波器先切入, 然後再看聽眾反應決定接下來的主題。有任何建議都歡迎提出來!

PyHUG 目前的聚會模式是每個月的第一與第三個星期一晚上, 通常都會有一個或一個以上的二十分鐘短講, 地點在交大計中一樓訓練教室, 所有訊息都是透過 meetup 這個網頁來公告, 你可以到這裡看相關訊息。

The slides were given to PyHUG in December 17, 2012 in PyHUG, which is Python Hsinchu User Group initiated by Dr. Yung-Yu Chen and I in 2011. In this talk, I introduced the concept of software-defined radio, the free & open source software-defined radio project - GNU Radio, RF front-end hardware that can be used with GNU Radio provided by Ettus Research and Realtek, and illustrated three ways to develop software-defined radio by GNU Radio. This is the first of GNU Radio series talk, the topics for the subsequent talks are to be done, and I'll probably start from using filters in GNU Radio as well as concepts of digital signal processing. And then I'll try to decide topics depending upon feedback of attendees. Any idea or suggestions are welcome!

Currently we have regular meetings on the first and the third Monday nights every month at the training classroom in the building of computer center in National Chaio-Tung University. Normally there will be one or two 20-minute talks. All messages related to PyHUG meetings or events are distributed via meetup website, and you can find information here.

Download/view slides of "A Glimpse into Developing Software-Defined Radio by Python"

Saturday, December 15, 2012

工程訓練與人文素養


工程訓練與人文素養, 一個是左腦, 一個是右腦, 一個需要理性, 一個需要感性, 看似非常衝突的兩個面向, 但我覺得是一個工程師必須同時要具備的兩個面向。


工程師, 尤其是電子電機工程師, 在現代的社會及媒體上, 有著許多不同的稱號, 比如說: 科技宅男、竹科新貴,中國大陸還有張江男之類的稱號, 其實都帶有些許戲謔的成分在。但回首過往, 被譽為中國鐵路之父的詹天佑(1861-1919), 不就是一名工程師嗎?他幼年就留學美國, 後來回近代中國修築了中國第一條鐵路, 並且修築了難度頗高的京張鐵路, 不僅帶給當代中國交通上的便利, 更因修築了外國人認為中國人不可能辦到的鐵路而激勵了當時的華人世界。更現代一些, 我們都在國中小學課本裡面讀過的作者, 陳之藩先生(1925-2012), 寫了不少膾炙人口的文章, 被收錄在「旅美小簡」、「在春風裡」、「劍河倒影」、「一星如月」等等, 我想在台灣應該是幾乎每一個人都讀過陳之藩先生的文章, 而他是學電機的, 也是工程師出身。


工程訓練的目的是訓練一個人, 在既有的流程或基礎上, 運用自己所學的知識與理論, 事先籌劃改善的方法, 並預測改善後的成效, 然後著手實踐這個改善方法。因此, 大學的工程相關科系有著非常多的理論與實驗課程, 這些都在養成工程師基礎的知識, 與動手做的能力, 兩者缺一不可, 卻也相輔相成。沒有基礎知識, 不知道實驗結果的真正原因為何; 沒有動手做, 就不知道自己缺乏哪些知識與理論, 也不知道為什麼要學那些理論。


人文素養對一名工程師來說, 乍看之下似乎沒有必要, 畢竟工程師不需要人文素養就能夠成為一名工程師。但是若從工程的本質來看的話, 人文素養又變成不可或缺的一部分。我來給工程下個定義, 把上一段的工程訓練目的稍微擴展一下, 「工程是為了改善人類的生活, 而在既有的基礎上, 運用自己所學的知識, 事先規劃改善方法, 預測改善後的成效, 並且著手實踐它。」既然是為了改善人類的生活, 人文素養能說不重要嗎?工程師做成的產品大部分時候是要給人使用的, 如果工程師在設計的時候, 脫離了「人」來思考, 設計出來的東西不是難以使用, 就是曲高和寡。工程師如果對於人性有所了解, 懂得人, 那麼就能夠很輕易的從日常生活中, 找到改善生活的方法, 讓人類的生活更便利。市面上有一種拖把, 有個桶子, 上面有個轉盤, 在洗好拖把之後可以用腳踩使轉盤轉動, 利用離心力的原理可以輕易的把水甩乾, 就不需要用手擰乾拖把而把手弄髒, 這個產品的問世帶給所有需要打掃的人, 包括家庭主婦與幫理家務的好男人, 非常便利的生活。這個就是因為發明人, 在幫忙老婆打掃家務的時候, 對於整個流程有敏銳與細膩的觀察, 從中找到改善的方法, 並且實踐這個改善的方法。我認為這就是帶有人文素養的工程思維表現。


如果科學家的熱情是來自於研究宇宙的真理, 哲學家的熱情是來自於思考人類的問題, 那麼我覺得工程師的熱情就來自於改善人類的生活。我無法想像工程師只以賺錢為唯一的目的, 也不能是主要目的, 那會讓工程的樂趣整個消失不見, 只剩下金錢遊戲。你能想像廚師只愛賺錢, 而不以做好料理讓客人吃得愉快為熱情嗎?我並不是說賺錢不好, 相反的, 我覺得賺錢很好, 但是以賺錢為目的與熱情的, 有別的職業, 比方說學習巴菲特在股票證券市場上賺錢, 巴菲特就說過他對於賺錢有極大的熱情, 股票與金融市場的即時回報就是金錢, 你把這件事做得愈好, 賺的錢遇多, 如果你的熱情就來自於賺錢, 那麼在證券市場上的即時回報也會讓你的熱情不斷加增。而工程師的即時回報, 是把一個東西改善而變得更好, 而我們心裡知道這些小小的改善累積起來, 就會讓人類的生活變得更好更便利, 但是比較大筆的金錢也許是一年一次的回報, 如果工程師的熱情來自於金錢, 那麼在工程師生涯裡面, 你只有千分之二點七左右(1/365)的時間是有回報來增強你的熱情的, 絕大多數的時間, 你要做你不覺得有趣的事情, 我說這也太痛苦了吧!工程師生涯看似枯燥乏味, 但如果你的熱情來自於改善人類的生活, 那麼這些枯燥乏味的事情, 就會頓時變得很有趣!當你習慣於觀察周遭生活, 找出改善方法, 並且著手實踐它, 誰說下一個改善人類生活的發明家不會是你呢?


--
Albert Huang
Chun-Chieh Huang(黃俊傑)