2013年7月25日 星期四

Office-Word系列:3.善用交互參照


最近,實驗室的學長們都在寫論文。在譔寫論文時,常需要引入大量的圖片、表格、方程式等,在內文中還需要使用「shown in Fig. 3.10」、「eq 2.10」,這類插入物件與文字間的相互連結。
而當插入新的物件時,如果還需要一頁一頁手動修改內文的文字內容,在大文件上將是相當麻煩的事情,甚至是接近不可能的任務,秉持「work hard, after you know you are working smart」的精神,這種方法是絕對不能接受的。
這裡要介紹的交互參照,可以讓word自行進行文字-物件的連結,加速論文的修改過程。

--

如上所述,交互參照在管理文字與物件間的連結,點開word中的「插入」-「交互參照」或「參考資料」-「交互參照」,可看見可以連結的物件包括:編號項目、標題、書籤、註腳、附註、方程式、表格、圖片八項,以下以圖片進行交互參照使用說明,這個步驟適用於圖片、表格與方程式的參照上。

1.第一步當然是先插入圖片。
2.建立起圖片標號,在「參考資料」-「插入標號」為圖片建立一個標號,標號其實是指標籤與編號,包括下列幾個部分:「標籤.編號.內文」,例如
「Fig.1 Touhou is the best」
這個標籤是最重要的,交互參照認的就是這個標籤,如果你覺得Fig這個標籤不好,也可以在插入標號的選單內自行建立新的標籤。 

3.現在在你想要插入交互參照的地方,點選「交互參照」;參照類型會列出這份文件裡的所有標籤種類,我們上面的標籤是Fig就選Fig;在下面選擇你想要連結的圖片;「插入參照類型的」則視你要插入什麼文字,如果只要插入「Fig.1」就選「標籤與數字」,如果只要Fig那就是「標籤」。
確定之後就會看到文字出現「Fig 1」。

4.會自己加文字完全沒什麼,重要的是,現在我們可以在圖表一之前加入新的圖片,同樣加上圖表標號;此時只要全選文件,右鍵選「更新功能變數」,即可更新所有的交互參照。如下圖所示,內文會自動變成「fig 2」,圖片下方的標號也會自動更新。

有一點要注意的是,一但完成了交互參照,這張圖片便不能輕易刪除,否則參照的文字會變成「找不到參照來源」,這個目前小弟我也只會手動刪除……。

5.建立圖表目錄,針對圖片、表格、方程式,word可以自動生成圖表式目錄,跟製作一般目錄一樣簡單,只要選取「參考資料」->「建立圖表目錄」,下面的標籤選擇你想要製作的標籤即可。

結論:
使用交互參照進行物件與文字間的管理,也許平時寫文件時不太需要用到,但對付文件內容的修改時,善用交互參照就顯得相當有威力。

2013年7月21日 星期日

防止.bashrc輸出內容造成sftp無法使用

目前小弟我負責維護幾台工作站,之前幾台工作站的FTP都無法使用,一定要從另一台工作站傳送,反正利用網路硬碟的功能,其他的工作站還是能拿到檔案。
前幾天工作站因為不明原因死了,非得讓無法用FTP的工作站連FTP;debug才發現原因:

在.bashrc中,放入了許多通知用的訊息,echo內容會讓sftp的收到錯誤訊息直接中止傳輸。
.bashrc的第一行有一行判斷式:
if [ $prompt ]; then echo "blahblahblah" fi
前面if用來擋掉非互動的連線,不過這好像沒什麼用…查一下正確的方法是用:
if [ "$SSH_TTY" ]
這個可以確認使用者用ssh登入,而不是sftp連線。

修改這行判斷式後就可以正常使用sftp了。
--
其實到最後還是不知道原因是什麼:

本來唯一可以使用的工作站,它的ssh版本是
OpenSSH_5.5p1, OpenSSL 1.0.0a 1 Jun 2010
其他兩台不能用的則是:
OpenSSH_5.1p1 Debian-5, OpenSSL 0.9.8o 01 Jun 2010
OpenSSH_3.9p1, OpenSSL 0.9.7a Feb 19 2003
不知道是不是1.0允許echo輸出文字的關係?這部分目前未明。

2013年7月8日 星期一

使用python執行EM模擬及寄信通知

runem這個小程式,主要是因為,通常我RF的電磁模擬要花上很多的時間,丟上工作站的話都要跑很久,如果是在windows下透過putty連結工作站,要是putty突然當掉,導致跑到一半的模擬中止掉就頭大了。

面對這個狀況有幾個解決方案,例如使用專面負責離線工作的程式,像是screen;但因為幾台工作站的作業系統太過老舊,上面甚至連screen都沒有;另一個解決方案是用atd,也就是linux內建的服務,在某個時間進行某個指令,這個解決方式很好,只是at 的語法比較麻煩,強迫每個使用者去記也沒什麼道理,身為網管要提供使用者方便,決定把at包成一個shell,使用者只要使用這個指令即可。

--

其實這個只要用shell script寫幾行即可,不過考量到一些特別的功能,還是用python來寫。 核心功能其實就一個,透過python 的subprocess把em 的指令透過atd送進去(ref 3):
cmd = "echo 'em -v {0}'".format(filename) 
cmd2 = "at now +0 minutes" 
p1 = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE) 
p2 = subprocess.Popen(cmd2, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=p1.stdout)

監控程序:

啟動atd之後,必須要監控該執行程序,看看它是不是結束了,這裡我使用強者我同學AZ的python 解決方案: pnotify(ref 2)
當然,這個監控的程式也要用atd的方式來執行。

第一步是先找出atd呼叫出來的em -v的process,再來的function就是抄襲AZ的,簡單來說是先檢查/proc,看看該pid是否開啟,然後每隔一段時間就用kill 0的方式檢查該程序存在與否。
找出pid的部分,用的方法就笨一點,直接叫外部的ps,抓出有em的部分、濾出該使用者的資訊、排除grep自身,再用pid排個序,抓最大(最新)的pid即可,這個方法在pid用完一圈後會出錯,不過將就用一下,之後再看看有沒有更好的解,有的話麻煩強者們提示一下m(_ _)m:
pid_list = [] 
cmd = "sleep 1; ps -elf" 
p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE) 
stdout = p.stdout.read().decode("utf-8").split('\n') 
for line in stdout: 
    if ("em -v" in line) and (username in line) and ("grep" not in line): 
        pid_list.append(line.split()[3])

就可以抓出pid了。 再來再用atd開啟一個pnotify的監控工作即可。

email:

為了方便使用者,使用的是python + SMTP module,這部分的程式碼只能用明碼寫出帳號密碼,不過這在權限上設定為只有我能看即可;主要code如下:
 # open smtp session 
session = smtplib.SMTP('smtp.gmail.com', 587) 
session.ehlo 
session.starttls() 
session.ehlo 
session.login(account, password) 

# prepare the send message 
msg = MIMEText("Your EM simulation: {0} is over".format(filename)) 
msg['Subject'] = "the test title" 
msg['From'] = sender 
msg['To'] = receiver 


# send the message 
session.sendmail(sender, [receiver], msg.as_string()) 
session.quit()

透過google的smtp進行文件的轉送,其實這沒什麼,大部分都是抄的lol(ref 1)

成果:

現在工作站可以透過 runem file1.son 的方式執行一個超大em模擬,em模擬結束時候,可以透過電子郵件,通知進行模擬的使用者。
本程式透過python譔寫,相當快速,總開發時間約3-4天。
原始碼已上傳到github上:
https://github.com/lc85301/runem

附章:

趁著這次佈署runem的時候,順便佈署了另一個小script: clearcdslck
其實沒什麼,只是一個shell包含一行指令:
find . -name *.cdslck -exec rm -fv {} \;

方便使用者清除因不當結束產生的.cdslck檔。

參考資料:

1. about python mail using google SMTP
http://segfault.in/2010/12/sending-gmail-from-python/
2. about pnotify.py
http://blog.azhuang.me/2011/07/script-for-notifying-process.html#more
3. about python subprocess
http://docs.python.org/2/library/subprocess.html

致謝:

本文感謝AZ Huang同學的pnotify.py以及在SMTP使用上的指導,另外感謝同實驗室的曾奕恩大師幫忙測試本程式。

2013年6月16日 星期日

硬體設計與軟體設計的不同思維

自己開始認真寫blog到現在約一年,總瀏覽人數大概6k,最多人看的,還是verilog的相關文章,顯然大家對這個莫名奇妙的語言都充滿了疑惑與不解。

最近正在寫一個verilog的作業,主要是要用verilog檢查8*8的candycrush有幾個步數是可以移動的,大概花了兩個小時,雖然寫出來的硬體很糟;但一方面發現自己verilog沒忘,另一方面也用這個例子,談談硬體設計與軟體設計差異之處。
這個問題,用軟體來寫實在滿簡單的,把陣列讀進來之後,只要用幾個for loop,把可能的狀況跑一次就是了,對一位有經驗的程式設計式來說,也許不用幾分鐘就能寫完。

但硬體設計來說,狀況就不一樣了。

--

我認為硬體設計的思維,必須從clock,前幾篇文所提到三大塊設計方式的角度下去想,這個模式和軟體有點差距,也造成很多從軟體轉到硬體設計人,有時就轉不過來,想不透為何硬體要這樣寫。
以這個candycrush為例,就我知道,有些人的判斷式是這樣寫的:
integer i;
...
case(state)
DOWN:begin
   for(i=0;i<40;i=i+1) begin
      count_num = ( (map[i]==map[i+1]&&map[i+3]==map[i] || map[i]==map[i+2]&&map[i+3]==map[i]) && i%8<6 )? count_num+1:count_num;
   end
end
簡單來說,在state為DOWN的時候,判斷 i這格糖果,和右邊一格、三格或是兩格、三格是否一樣(按:這個部分應該是原作者打錯,state應該是RIGHT),是的話就讓count_num加一。
看起來很合理,以軟體角度來說,不就是i=0,1...39,每次就檢查上面的判斷式?

這就是思維不同的地方,硬體設計你寫什麼,它都是同時進行的,combination circuit無時無刻把接到的資料進行邏輯運算並輸出;你如果希望某個行為和時間有關,希望它依序進行的東西,絕對都跟clock和sequencial circuit有關。
原作者可能是沒查過for loop在verilog內的意義為何,但for loop這個語法是combination circuit的一部分,實際上for loop在verilog內會被平行的展開,編譯器會自動把for loop內的code全部依for loop 變數展開,上面的寫法實際上大約等價於:

( (map[0]==map[1]&&map[3]==map[0] || map[0]==map[2]&&map[3]==map[0]) && 0%8<6 )? count_num+1:count_num; 
( (map[1]==map[2]&&map[4]==map[1] || map[1]==map[3]&&map[4]==map[1]) && 1%8<6 )? count_num+1:count_num;
下略38行。
於是當state進到DOWN時,count_num被平行輸入40個combination circuit中,每一個都有不同的判斷條件,有些加一,有些維持原值,然後要寫回到count_num裡,這下就天下大亂了(按,據說這個code最後無法合成到gate level)。
如果用我在三大塊中的例子:
Combinational circuit就像馬路,負責讓車(信號)流動,改變車道(運算)
Sequential circuit則像紅綠燈,負責管理信號什麼時候可以通行,到下一個combinational circuit。

這裡for loop的寫法,就像你要一位駕駛,每過一個紅綠燈就喝一種飲料,總共要喝40種;結果你把40支紅綠燈插在同一個路口,駕駛就得喝大雜燴了。

--

原作者的意思,應該是for loop展開的每一行,依序判斷,寫出結果到count_num中。
依序->和時間有關->請用sequential 電路和clock。
真正合理的寫法,是用另一個變數phase,在state DOWN從0加到39,這些動作才會依時間維度展開,而不是直接平行展開。
關鍵的幾行code大概是:
//count_num
if(state == DOWN) begin
( (map[phase]==map[phase+2]&&map[phase+3]==map[phase] || map[phase]==map[phase+1]&&map[phase+3]==map[phase]) && phase%8<6 )? count_num+1:count_num;
end
//phase
phase_next = (phase==39)? 0 : phase+1;
//state
state_next = (state==DOWN && phase==39): UP: DOWN;
隨隨便便打了這些,好像還是沒說到我想講的概念;簡單來說,硬體裡和時間有關的概念,一定都要歸到sequential的部分去;硬體設計是完全的一個口令一個動作,想像for loop裡的變數 i,在每一次clock來的時候加一,i不同時電路才有不同的行為,希望這樣的想法能對各位辛苦的電路人有幫助。

2013年5月25日 星期六

使用差動雙投擲計時器應用於時鐘製作之研製

minecraft是一款我認為設計得相當好的遊戲,透過簡單方塊的堆積,讓你組出任何你想要的內容;而紅石又是其中最有變化的物件,可以模擬出許多數位電路的行為,老實說基本的邏輯設計課程應該可以用minecraft當作輔助教材(XD)。

minecraft升級到1.5之後,多了很多新的紅石元件,其中包括可以測定日光強度的日光sensor,讓我們有機會在minecraft當中,實現時鐘的功能。
之前已經有相當多相關的設計,包括直接用sensor輸出信號接在redstone lamp(1),及用長線分離出各時段的信號(2)等。
因為sensor輸出信號在白天呈現山形,第一種時鐘,共有上午和下午時會呈現相同的時間、計時非線性、晚上也只能顯示為晚上而非確切時間等問題;第二種則需要相當大的空間和電路,在一般server不用creative mode難以實現。
這裡我們就要設計的是,能夠線性計時,利用daylight sensor來校正,同時體積儘量小的設計。

最終設計的minecraft時鐘共有兩個主要部分,分別為:差動雙投擲計時器、雙比較器實現計數器(counter).本文將分為以下幾個部分:
1. minecraft 時間及sensor介紹:
2. 差動雙投擲計時器之設計:
3. 雙比較器實現計數器之設計:
4. 設計展示:
5. 相關設計:

1. minecraft 時間及sensor介紹:

minecraft一天有現實的20分鐘,共分為24000個基本時間單位ticks,ticks設為0時相當於每日早上6點。sensor的部分,固定每天22500ticks到13500ticks會發出信號,其他時間則不發射,信號強度依日光強度有所不同。
詳細資料請參考:(3)minecraft wiki daylight sensor。

2. 差動雙投擲計時器之設計:

過去minecraft上常難以實現長時間的delayer,可行的辦法包括用rail+detect rail、dispensor+蜘蛛網、鐵路+流水回收(4)等、活塞循環(5)等;但一般rail+detect rail需要相當大的面積來達成長delay,一般大小下delay只有約10-20秒,且重登入時不容易reset;dispensor+蜘蛛網、鐵路+流水回收則不夠精確,delay時間的可調長度與可調精度不佳;活塞循環相較之下較為可行,但拉到四角的紅石信號容易造成信號線相當複雜,一般體積也較大。 

本文提出之差動雙投擲計時器,除了能精確計時外,還具有容易reset、停止、可調長度相當廣及所佔體積相當小等好處,主要的參考來源為「SCAMP全自動造山機」(6)。 

雙投擲器將兩個投擲器相對,驅動一個投鄭器即會將內容物送至另一個投擲器內,透過1.5版新增的比較器,偵測投擲器是否內含物品,驅動比較器製成的振盪器(圖左),即可自動將一投擲器(下稱發射端)的物品送到另一側(下稱預備端),調整投擲器內的物品數量和振盪器的頻率,可以調整輸出變化的時間,由於comparator的delay不明,粗估送完的時間方式為,投擲器內的物品數量*(Osc. Delay),實測上兩個repeater調最長,17個物品送完的時間是30秒。
理論上可以在另一邊複製相同的振盪電路,將一側電路的輸出鎖住另一方向的repeater,達到來回振盪的功能,但如下圖,repeater要鎖住的方向不同,這樣的設計會讓電路變得相當大;同時兩邊都是相同的振盪頻率,實用上不容易做到校正的功能。


新架構加入另一套雙投擲計時器,兩計時器互鎖,當A方鎖住B方時(A方的Q值為1),A方輸出和B方預備端是否含物品的信號通過AND閘,驅動高速振盪器,將物品送回發射端。



運作包含五個相位:
1. A方發射端將物品送入預備端,B方預備端高速送物品回發射端。
2. B方預備端送完,高頻振盪器停止。
3. A方發射端送完,B方發射端解鎖,使A方輸出鎖住,並啟動A方預備端高頻振盪器。
4. A方預備端送完,高頻振盪器停止。
5. B方發射端送完,A方發射端解鎖,使B方輸出鎖住,並啟動B方預備端高頻振盪器,回到相位一。

最後則是控制信號的部分,可以透過強制將A/B方鎖住信號設在1來達成開關計時器的功能;但要注意的是,repeater的鎖住是鎖在 0或1,如果鎖在1的話,會使雙投擲器進入來回投擲的不穩定狀態;因此我們要在控制信號的輸入處,加入一個由輸出控制的鎖,以避免上述狀況的發生,詳細如下圖所示。
完成之雙投擲計時器所佔面積為10*8*3,相當compact,理論上的最長delay時間估計為2032秒左右




3. 雙比較器實現計數器之設計:

由於上述差動雙投擲計時器的輸出端,只能隨時間輸出長週期的1/0信號,因此輸出端先接入一個上升/下降緣檢測電路(edge detector),產生短脈衝;再接入計數器計算短脈衝的數量,以達成隨不同時間輸出不同信號的能力。

這裡狀態機的設定參考(7)的設計,功能考量,我們只取其中的down counter跟重設的能力,同樣由雙比較器維持信號強度,每一個脈衝進來,經比較器產生強度一的信號,使狀態強度減小一,達到狀態記錄。
實作上計數器記錄的是計時器發出多少次信號;在這裡我們用來記錄經過多少時間,在日間感測器開始運作之後,到日落的時間為15000ticks=12.5分,晚上感測器則是9000ticks=7.5分,分別需要記錄12, 7個狀態。

為了reset計數器,我們需要特定強度的信號,當然也可以用強度15的信號reset,但這樣會加大計數器的體積;這部分使用箱子+comparator產生,並利用另一個信號為15的信號相減,來產生所需的強度。
以日間計數器需設到強度12的信號,箱子要放345-460個物品。
以日間計數器需設到強度7的信號,箱子要放921-1036個物品。(雞蛋的話請除4)
這個用骨粉來放最容易了。



4. 設計展示:

最終時鐘設計如下圖所示:

中央的日光偵測器為核心,左右各為一套雙投擲計時器,分別在日、夜時工作(左日右夜,不想看到紅石電路請自己拉到地底=w=);計時器Q+輸出經edge detector進到計數器-1端,Q-經edge detector到對方計數器reset端;上方為夜間計數器,七個狀態;下方為日間計數器,12個狀態;有一些些調整是在鎖住sensor信號跟接到計數器的部分,都是為了讓體積更小。

稍微提一下,因為在雙投擲計時器,鎖住控制信號的那一方(Q-),在計時器被鎖住時,其輸出為0,如圖中左邊上半的狀態,因此在停止工作的瞬間,會有一個negative edge pulse,利用negative edge detector偵側這個信號幫另一方重設。
開始計時的時候,Q-端會先變1,然後30秒後換Q+端變1,再30秒Q+變0;因此從Q+端接到計數器減一端的detector同樣是negative edge detector。

這大概是整體時鐘的設計了,每個一紅石燈的信號可以自行拉線到想顯示的方式上;就我所知,這是目前能線性計時,同時體積最小的設計。

5. 參考資料:

(1)Basic Minecraft Clock Using 13w01a "Daylight Sensors"
http://www.youtube.com/watch?v=2x-l0owQGF0
(2)WORKING 12-HOUR CLOCK IN MINECRAFT
http://www.youtube.com/watch?v=1-ylYISMAck
(3)daylight sensor
www.minecraftwiki.net/wiki/Daylight_Sensor
(4)Minecraft clocks (6min)
http://www.youtube.com/watch?v=Rz1Qxbh3_XI
(5)Minecraft : Piston clock for long delay
http://www.youtube.com/watch?v=M19UQ5Y_wzQ
(6)The SCAMP: How it Works, and How to Use It
http://www.youtube.com/watch?v=vBpPKVwIwP4
(7)Decimal Counter with Comparators [Tutorial] Minecraft 1.5
http://www.youtube.com/watch?v=J7mRNZXshCQ