這是 2017 年的最後一周了, 人生就是一串數字, 串起各種回憶, 但遺忘的多, 記得的總是比較少. 時間就像我房外不遠處小圳中川流不息的水, 它不斷地流逝, 在桌前靜靜讀書的時候就可以聽到那潺潺的水流聲, 看似平淡, 但那就是生命之流啊!
姊姊週五 12/29 晚上坐自強號回到高雄, 聽她頻頻咳嗽, 原來聖誕節第二天感冒請假沒去上課, 拖到回高雄才要去看醫生, 結果楊醫師卻休診四天. 週六回到鄉下採了一些魚腥草燉麥芽糖酸梅湯給她喝, 但似乎效果不顯著. 冬天的魚腥草不像夏天時那麼茂密, 品質可能也不甚好.
元旦連假雖說休三天, 但週六我要上課, 周一中午姊姊又要搭車回台北, 所以也是如往常只休一天而已. 元旦過後就準備迎接舊曆年了, 一整年大部分的時間都在忙, 這時除了要來個大掃除, 大整理外, 應該放慢腳步來回顧一下做了甚麼, 想做又沒做的有哪些, 也要來個大盤點.
2018年1月3日 星期三
2018年1月2日 星期二
Arduino + LoRa 模組測試
這篇是去年 10 月底對 LoRa 模組進行初步測試的紀錄, 後來忙著幫二哥準備 APCS 而暫停下來. 昨天有網友問我空曠處實測距離多少, 才想起這篇還沒完成的草稿, 稍作整理如下備查. 在傳送距離方面, 網友與我的實測距離都約 200~250 米而已, 據說使用 IPEX 天線似乎沒有好到哪裡去, 實在殘念! 我還抱著一絲希望的說.
會接觸 LoRa 是因為去年十月初有另一位網友詢問我有無用過 LoRa, 當時我連買了放在零件箱好久的 nRF24L01 模組都還沒動哩! 為此我除了找出 nRF24L01 先測試一番以產生比較資料外, 還上網對此新興無線射頻技術做了初步研究, 整理了一篇知識摘要, 參見 :
# 長距離低功耗無線通訊技術 LoRa
接著在露天購買了一對最便宜的 LoRa 模組來測試 (跟 nRF24L01 一樣要成對地買, 一個傳送, 一個接收, 或者互相傳送接收), 此板用的是 SX1278 晶片 (433 MHz) :
# [史塔克實驗室][Arduino/RPi]每個180元2個一組販售SX1278 Lora module 模組433MHz $180
由於這是 2.0mm 腳距的裸板, 所以特地跑去禾樺買了 2.0 mm 的排針與排母, 在焊接前試試看到底要用排針或排母比較適合, 結果發現排針根本不能用, 因為 2.0mm 的排針比較細, 杜邦線母頭插上去鬆鬆的會接觸不良, 應該要用排母才對, 因為 2.0mm 的排母上的洞與一般 2.54mm 者一樣, 插杜邦線沒問題.
我買的這組 LoRa 模組每邊 8 隻腳, 其腳位布局如下 :
由於 ANT 腳要焊彈簧天線, 因此左邊的排母只要 7 隻腳, 而右邊的則需 8 隻腳, 使用小型電鑽前面裝上鑽石圓盤分別切出 7 支與 8 支腳的排母各一對, 然後用三秒膠少許加以固定後進行焊接. 注意, 三秒膠不可用太多, 否則萬一滲入排母內會讓排針插不下去.
Lora 板子焊好後就可以進行測試了, 我使用 Arduino 當作 MCU 主控, 首先是到下列 GitHub 網站下載 Arduino 的 Lora 函式庫 :
# https://github.com/sandeepmistry/arduino-LoRa
按右邊的 "Clone or download" 鈕, 選 "Download ZIP" 下載壓縮檔 arduino-LoRa-master.zip, 將其複製到 Arduino IDE 安裝目錄的 libraries 下解開即可. 重新開啟 IDE 就可存取到此函式庫了. 此函式庫的 API 說明如下 :
# https://github.com/sandeepmistry/arduino-LoRa/blob/master/API.md
此函式庫使用 SPI 協定與 LoRa 模組通訊, 預設傳輸速率是 10 MHz. 接下來是硬體接線, 此 LoRa 模組採用 SPI 介面 (也有用 Serial 介面的), Arduino 有特定的 SPI 接腳, 與 LoRa 的預設對應如下 :
不過其中 NSS, RESET, 與 DIO0 這三隻腳不一定要對應到 D10, D9, 與 D2 這三支 Arduino 腳, 可以連接到除 D13, D12, D11 以外的任何 DIO 腳位, 但在程式中要用 LoRa.setPins(NSS, RESET, DIO0) 指令指定.
測試 1 :
傳送端程式 :
#include <SPI.h>
#include <LoRa.h>
int counter=0; //傳送次數計數器
void setup() {
Serial.begin(9600);
while (!Serial); //等待序列埠起始完畢
Serial.println("LoRa Sender");
if (!LoRa.begin(433E6)) { //起始 433MHz LoRa
Serial.println("Starting LoRa failed!");
while (1);
}
}
void loop() {
Serial.print("Sending packet: ");
Serial.println(counter);
LoRa.beginPacket(); //封包傳送開始
LoRa.print("hello "); //封包內容
LoRa.print(counter); //封包內容
LoRa.endPacket(); //封包傳送結束
counter++; //計數器增量 1
delay(5000);
}
接收端程式 :
#include <SPI.h>
#include <LoRa.h>
void setup() {
Serial.begin(9600);
while (!Serial); //等待序列埠起始完畢
Serial.println("LoRa Receiver");
if (!LoRa.begin(433E6)) { //起始 LoRa
Serial.println("Starting LoRa failed!");
while (1);
}
}
void loop() {
int packetSize=LoRa.parsePacket(); //讀取剖析 LoRa 封包大小
if (packetSize) { //若有封包進來
Serial.print("Received packet '");
while (LoRa.available()) { //若接收緩衝器有內容
Serial.print((char)LoRa.read()); //讀取緩衝器內容並輸出階收到的封包
}
Serial.print("' with RSSI="); //輸出接收封包之 RSSI
Serial.print(LoRa.packetRssi()); //顯示接收信號強度
Serial.print(" and SNR="); //輸出接收封包之 SNR (信噪比)
Serial.println(LoRa.packetSnr()); //顯示接收信號信噪比
}
}
序列埠監控視窗輸出結果如下, 收到訊號時會顯示 "Received packet ... RSSI= .... SNR=...." :
2018-01-12 補充 :
參考 :
# 物聯網技術標準 NB-IOT 和 LoRa 到底是什麼?
# 120 LoRa on batteries: How long does it last?
2018-05-14 補充 :
LoRa 也有 UART 介面的模組, 目前最便宜大約 450 元, 參考 :
# 【ACSip LoRa實作2】快速開發LoRa通訊功能-UART介面篇
# REYAX RYLR896 SX1276 UART 介面 帶天線 AT command lora module 模組 $450
會接觸 LoRa 是因為去年十月初有另一位網友詢問我有無用過 LoRa, 當時我連買了放在零件箱好久的 nRF24L01 模組都還沒動哩! 為此我除了找出 nRF24L01 先測試一番以產生比較資料外, 還上網對此新興無線射頻技術做了初步研究, 整理了一篇知識摘要, 參見 :
# 長距離低功耗無線通訊技術 LoRa
接著在露天購買了一對最便宜的 LoRa 模組來測試 (跟 nRF24L01 一樣要成對地買, 一個傳送, 一個接收, 或者互相傳送接收), 此板用的是 SX1278 晶片 (433 MHz) :
# [史塔克實驗室][Arduino/RPi]每個180元2個一組販售SX1278 Lora module 模組433MHz $180
由於這是 2.0mm 腳距的裸板, 所以特地跑去禾樺買了 2.0 mm 的排針與排母, 在焊接前試試看到底要用排針或排母比較適合, 結果發現排針根本不能用, 因為 2.0mm 的排針比較細, 杜邦線母頭插上去鬆鬆的會接觸不良, 應該要用排母才對, 因為 2.0mm 的排母上的洞與一般 2.54mm 者一樣, 插杜邦線沒問題.
我買的這組 LoRa 模組每邊 8 隻腳, 其腳位布局如下 :
| DIO2 | GND |
| DIO1 | MISO |
| DIO0 | MOSI |
| 3.3V | SCK |
| DIO4 | NSS |
| DIO3 | RESET |
| GND | DIO5 |
| ANT | GND |
由於 ANT 腳要焊彈簧天線, 因此左邊的排母只要 7 隻腳, 而右邊的則需 8 隻腳, 使用小型電鑽前面裝上鑽石圓盤分別切出 7 支與 8 支腳的排母各一對, 然後用三秒膠少許加以固定後進行焊接. 注意, 三秒膠不可用太多, 否則萬一滲入排母內會讓排針插不下去.
Lora 板子焊好後就可以進行測試了, 我使用 Arduino 當作 MCU 主控, 首先是到下列 GitHub 網站下載 Arduino 的 Lora 函式庫 :
按右邊的 "Clone or download" 鈕, 選 "Download ZIP" 下載壓縮檔 arduino-LoRa-master.zip, 將其複製到 Arduino IDE 安裝目錄的 libraries 下解開即可. 重新開啟 IDE 就可存取到此函式庫了. 此函式庫的 API 說明如下 :
# https://github.com/sandeepmistry/arduino-LoRa/blob/master/API.md
此函式庫使用 SPI 協定與 LoRa 模組通訊, 預設傳輸速率是 10 MHz. 接下來是硬體接線, 此 LoRa 模組採用 SPI 介面 (也有用 Serial 介面的), Arduino 有特定的 SPI 接腳, 與 LoRa 的預設對應如下 :
不過其中 NSS, RESET, 與 DIO0 這三隻腳不一定要對應到 D10, D9, 與 D2 這三支 Arduino 腳, 可以連接到除 D13, D12, D11 以外的任何 DIO 腳位, 但在程式中要用 LoRa.setPins(NSS, RESET, DIO0) 指令指定.
測試 1 :
傳送端程式 :
#include <SPI.h>
#include <LoRa.h>
int counter=0; //傳送次數計數器
void setup() {
Serial.begin(9600);
while (!Serial); //等待序列埠起始完畢
Serial.println("LoRa Sender");
if (!LoRa.begin(433E6)) { //起始 433MHz LoRa
Serial.println("Starting LoRa failed!");
while (1);
}
}
void loop() {
Serial.print("Sending packet: ");
Serial.println(counter);
LoRa.beginPacket(); //封包傳送開始
LoRa.print("hello "); //封包內容
LoRa.print(counter); //封包內容
LoRa.endPacket(); //封包傳送結束
counter++; //計數器增量 1
delay(5000);
}
接收端程式 :
#include <SPI.h>
#include <LoRa.h>
void setup() {
Serial.begin(9600);
while (!Serial); //等待序列埠起始完畢
Serial.println("LoRa Receiver");
if (!LoRa.begin(433E6)) { //起始 LoRa
Serial.println("Starting LoRa failed!");
while (1);
}
}
void loop() {
int packetSize=LoRa.parsePacket(); //讀取剖析 LoRa 封包大小
if (packetSize) { //若有封包進來
Serial.print("Received packet '");
while (LoRa.available()) { //若接收緩衝器有內容
Serial.print((char)LoRa.read()); //讀取緩衝器內容並輸出階收到的封包
}
Serial.print("' with RSSI="); //輸出接收封包之 RSSI
Serial.print(LoRa.packetRssi()); //顯示接收信號強度
Serial.print(" and SNR="); //輸出接收封包之 SNR (信噪比)
Serial.println(LoRa.packetSnr()); //顯示接收信號信噪比
}
}
序列埠監控視窗輸出結果如下, 收到訊號時會顯示 "Received packet ... RSSI= .... SNR=...." :
.....
irqFlags 0
irqFlags 10
irqFlags 40
Received packet 'hello 29' with RSSI=-39 and SNR=16.00
irqFlags 0
irqFlags 0
irqFlags 0
irqFlags 0
irqFlags 0
irqFlags 0
irqFlags 0
irqFlags 0
irqFlags 0
irqFlags 0
irqFlags 80
irqFlags 0
irqFlags 0
irqFlags 0
irqFlags 0
irqFlags 0
irqFlags 0
irqFlags 0
irqFlags 0
irqFlags 80
irqFlags 0
其中 RSSI (Received Signal Strength Indicator) : 接收信號强度指示.
用彈簧天線於空曠地區實測距離約 250 公尺, 似乎只比 nRF24L01 的 100 公尺長兩倍多而已, 與產品說明中所說的 1 公里相差達 4 倍. 不過信號穿透力可達 2~3 層樓, 在電梯中亦可收到信號, 這就比 nRF24L01 出色多了, nRF24L01 只要 5 公尺外轉個牆角就 GG 了, 參考 :
# Arduino 無線傳輸模組 NRF24L01 測試
測試距離方面, 有空我還是會買支 IPEX 或其他廠家的 LoRa 模組來驗證看看.
# Arduino Arduino module communication by Lora Sx1278
# https://github.com/matthijskooijman/arduino-lmic
# 【Acsip LoRa實作1】快速開發LoRa通訊功能-SPI介面篇
# An Arduino library for sending and receiving data using LoRa radiosirqFlags 0
irqFlags 10
irqFlags 40
Received packet 'hello 29' with RSSI=-39 and SNR=16.00
irqFlags 0
irqFlags 0
irqFlags 0
irqFlags 0
irqFlags 0
irqFlags 0
irqFlags 0
irqFlags 0
irqFlags 0
irqFlags 0
irqFlags 80
irqFlags 0
irqFlags 0
irqFlags 0
irqFlags 0
irqFlags 0
irqFlags 0
irqFlags 0
irqFlags 0
irqFlags 80
irqFlags 0
.....
irqFlags 10
irqFlags 40
Received packet 'hello 30' with RSSI=-51 and SNR=15.75
irqFlags 0
irqFlags 0
irqFlags 0
irqFlags 0
irqFlags 0
irqFlags 0
irqFlags 0
irqFlags 0
irqFlags 0
irqFlags 0
irqFlags 80
irqFlags 0
.....
其中 RSSI (Received Signal Strength Indicator) : 接收信號强度指示.
用彈簧天線於空曠地區實測距離約 250 公尺, 似乎只比 nRF24L01 的 100 公尺長兩倍多而已, 與產品說明中所說的 1 公里相差達 4 倍. 不過信號穿透力可達 2~3 層樓, 在電梯中亦可收到信號, 這就比 nRF24L01 出色多了, nRF24L01 只要 5 公尺外轉個牆角就 GG 了, 參考 :
# Arduino 無線傳輸模組 NRF24L01 測試
測試距離方面, 有空我還是會買支 IPEX 或其他廠家的 LoRa 模組來驗證看看.
參考 :
# Arduino Arduino module communication by Lora Sx1278
# https://github.com/matthijskooijman/arduino-lmic
# 【Acsip LoRa實作1】快速開發LoRa通訊功能-SPI介面篇
# LoRa 的 Arduino 函式庫
# 【Acsip LoRa實作1】快速開發LoRa通訊功能-SPI介面篇
# WLK01S78-TH 無線模組 LORA模組 SX1278數傳模組 w7 056 [5059647] $260
# LoRa 測試資料下載 (測試地圖快照) (測試地形圖)
# <微控制器科技> Pycom LoPy IoT 三合一開發板 (LoRa+BLE+WiFi) $1350
# Pycom LoPy - LoRa+WiFi+Bluetooth MicroPython IoT Platform £32.5
# https://github.com/a3rd/lora-inair4
# SX1278 LoRa擴頻無線模組 433Mhz $220
# 大陸模組資料下載
# https://drive.google.com/drive/folders/0BywdxdAWyMLcWXpFNF9QVWhHZHc
# SX1278 LOra擴頻 電力抄表模組 5km無線收發模組SX1276模組 $200
# iFrogLab iL-LORA1272 超遠端15公里LoRa資料傳遞和接收模組 for Arduino 和 樹梅派 $850
# iFrogLab iL-LORA1272-A LoRa 資料傳遞和接收模組 韌體全面更新為1.1版 $850
# 98 Mailbag #8: LoRa, ESP8285, ESP32 in a WiPy Python board, A6C with camera
# LoRa 範例程式下載
# Setting Up the Modtronix InAir4 with Arduino
2018-01-03 補充 :
下面這部影片測試 LoRa 的耗電情形 :
#120 LoRa on batteries: How long does it last?
# 【Acsip LoRa實作1】快速開發LoRa通訊功能-SPI介面篇
# WLK01S78-TH 無線模組 LORA模組 SX1278數傳模組 w7 056 [5059647] $260
# LoRa 測試資料下載 (測試地圖快照) (測試地形圖)
# <微控制器科技> Pycom LoPy IoT 三合一開發板 (LoRa+BLE+WiFi) $1350
# Pycom LoPy - LoRa+WiFi+Bluetooth MicroPython IoT Platform £32.5
# https://github.com/a3rd/lora-inair4
# SX1278 LoRa擴頻無線模組 433Mhz $220
# 大陸模組資料下載
# https://drive.google.com/drive/folders/0BywdxdAWyMLcWXpFNF9QVWhHZHc
# SX1278 LOra擴頻 電力抄表模組 5km無線收發模組SX1276模組 $200
# iFrogLab iL-LORA1272 超遠端15公里LoRa資料傳遞和接收模組 for Arduino 和 樹梅派 $850
# iFrogLab iL-LORA1272-A LoRa 資料傳遞和接收模組 韌體全面更新為1.1版 $850
# 98 Mailbag #8: LoRa, ESP8285, ESP32 in a WiPy Python board, A6C with camera
# LoRa 範例程式下載
# Setting Up the Modtronix InAir4 with Arduino
2018-01-03 補充 :
下面這部影片測試 LoRa 的耗電情形 :
#120 LoRa on batteries: How long does it last?
2018-01-12 補充 :
參考 :
# 物聯網技術標準 NB-IOT 和 LoRa 到底是什麼?
# 120 LoRa on batteries: How long does it last?
2018-05-14 補充 :
LoRa 也有 UART 介面的模組, 目前最便宜大約 450 元, 參考 :
# 【ACSip LoRa實作2】快速開發LoRa通訊功能-UART介面篇
# REYAX RYLR896 SX1276 UART 介面 帶天線 AT command lora module 模組 $450
2018年1月1日 星期一
城邦購書四本
城邦網路書店每年會員生日有 65 折優惠 (我是 VIP 會員), 加上累積紅利已 411 點 (2018-08-03 到期), 因此上網挑了下面四本書 :
原總價 1520 元, 65 折優惠價 988, 扣除紅利換書 300 點 (用情感運算革命這本兌換最划算, 只損失 1 點紅利), 應付 689 元, 實際折扣 689/1520 約 45 折, 紅利換書實在很優惠.
網路訂單須注意 :
如您的網路訂單有使用折價券優惠,線上取消訂單後,該折價券優惠將無法再使用!
完成訂單交易贈送的折價券,請務必於訂單日期後三個月內索取,否則將自動失效!
如您的網路訂單有使用紅利點數兌換書籍,線上取消訂單後,該筆訂單使用的紅利點數會立即加回。
- 情感運算革命:下一波人工智慧狂潮,操縱你的情緒、販售你的想法,將是威脅還是機會?
- 從人到人工智慧,破解AI革命的68個核心概念
- 台灣股神教你看懂贏家選股必賺的財報祕技
- 把60萬變3億!不買主流股,我賺500倍
原總價 1520 元, 65 折優惠價 988, 扣除紅利換書 300 點 (用情感運算革命這本兌換最划算, 只損失 1 點紅利), 應付 689 元, 實際折扣 689/1520 約 45 折, 紅利換書實在很優惠.
網路訂單須注意 :
樹莓派自動偵測網路斷線時重開機的方法
這兩周因為在學 R 語言, 無暇玩樹莓派. 不過最近有注意到, 奇怪, 為何都沒收到鄉下樹莓派主機傳送的 IP Changed 的郵件? 難道這個禮拜 ADSL 的浮動 IP 都沒變? 不太可能啊! 周六晚上回到鄉下檢查樹莓派才知是沒有連上無線基地台, 我猜是信舟這台 AP 有時會卡住, 我叫爸遇到 WiFi 無法上網時就去重開 AP 電源, 但 AP 重啟後樹莓派不是應該會自動再連線嗎? 有待細究. 總之, 我將樹莓派重開機後就正常連線了, 馬上就收到 IP Changed 郵件通知.
看來只有自動偵測 IP 變化是不夠的, 還得偵測網路連線是否正常. 如果因為 AP 重啟, 而樹莓派又沒有自動去連線, 就抓不到外網 IP, 當然也送不出郵件來. 經爬文找到下面這篇文章, 剛好就是我遇到的問題及解決辦法, 呵呵, 得來實在不費工夫, 感謝原作之分享 :
# Rebooting the Raspberry Pi when it loses wireless connection
作者的解決辦法其實很簡單, 就是寫一個如下的 shell 程式放在 /usr/local/bin 底下, 賦予可執行權限, 然後在 crontab 中加一條定時工作週期性執行此程式來檢查網路連線, 如果發現連線有問題就重啟樹莓派 :
ping -c4 192.168.2.2 > /dev/null
if [ $? != 0 ]
then
sudo reboot
fi
程式第一行是用來 ping 無線網路上的某個主機, 通常是無線基地台的 IP, 這也是程式中唯一要改的地方. 此 ping 指令若網路連線正常將無回應值, 使得 $? 為 0 而不會去執行 then 的 reboot; 反之當連線異常時就會有回應值, $? 即不為 0 導致 reboot 指令被執行.
首先用 nano 編輯 checkwifi.sh 程式, 輸入上述程式後按 Ctrl+O 與 Ctrl+X 存檔 :
"I have met the same problem. And the problem is the format of the file is "dos", but in linux shell requires "unix", so I install the "dos2unix""
原來即使用 nano 編輯的 shell 程式還是 DOS 格式, 須安裝 dos2unix 來將其改為 Unix 格式 :
接下來就是修改 crontab, 設定每小時執行一次 checkwifi.sh, 若連線異常就重啟樹莓派 :
看來只有自動偵測 IP 變化是不夠的, 還得偵測網路連線是否正常. 如果因為 AP 重啟, 而樹莓派又沒有自動去連線, 就抓不到外網 IP, 當然也送不出郵件來. 經爬文找到下面這篇文章, 剛好就是我遇到的問題及解決辦法, 呵呵, 得來實在不費工夫, 感謝原作之分享 :
# Rebooting the Raspberry Pi when it loses wireless connection
作者的解決辦法其實很簡單, 就是寫一個如下的 shell 程式放在 /usr/local/bin 底下, 賦予可執行權限, 然後在 crontab 中加一條定時工作週期性執行此程式來檢查網路連線, 如果發現連線有問題就重啟樹莓派 :
ping -c4 192.168.2.2 > /dev/null
if [ $? != 0 ]
then
sudo reboot
fi
程式第一行是用來 ping 無線網路上的某個主機, 通常是無線基地台的 IP, 這也是程式中唯一要改的地方. 此 ping 指令若網路連線正常將無回應值, 使得 $? 為 0 而不會去執行 then 的 reboot; 反之當連線異常時就會有回應值, $? 即不為 0 導致 reboot 指令被執行.
首先用 nano 編輯 checkwifi.sh 程式, 輸入上述程式後按 Ctrl+O 與 Ctrl+X 存檔 :
pi@raspberrypi:~ $ nano checkwifi.sh
然後將此指令複製到 /usr/local/bin 下, 並賦予可執行權限 :
然後將此指令複製到 /usr/local/bin 下, 並賦予可執行權限 :
pi@raspberrypi:~ $ sudo cp checkwifi.sh /usr/local/bin/checkwifi.sh
pi@raspberrypi:~ $ sudo chmod 775 /usr/local/bin/checkwifi.sh
但是執行此程式卻出現語法錯誤 :
但是執行此程式卻出現語法錯誤 :
pi@raspberrypi:~ $ sudo /usr/local/bin/checkwifi.sh
/usr/local/bin/checkwifi.sh: 6: /usr/local/bin/checkwifi.sh: Syntax error: end of file unexpected (expecting "then")
查詢 shell script 語法確認程式語法正確, 怎會如此呢? 以錯誤訊息查詢發現 stackoverflow 已有人遇到過此問題並提出解答, 參考 :
"I have met the same problem. And the problem is the format of the file is "dos", but in linux shell requires "unix", so I install the "dos2unix""
原來即使用 nano 編輯的 shell 程式還是 DOS 格式, 須安裝 dos2unix 來將其改為 Unix 格式 :
pi@raspberrypi:~ $ sudo apt-get install dos2unix
Reading package lists... Done
Building dependency tree
Reading state information... Done
The following NEW packages will be installed:
dos2unix
0 upgraded, 1 newly installed, 0 to remove and 198 not upgraded.
Need to get 75.9 kB of archives.
After this operation, 204 kB of additional disk space will be used.
Get:1 http://mirrordirector.raspbian.org/raspbian/ jessie/main dos2unix armhf 6.0.4-1 [75.9 kB]
Fetched 75.9 kB in 6s (12.0 kB/s)
Selecting previously unselected package dos2unix.
(Reading database ... 123331 files and directories currently installed.)
Preparing to unpack .../dos2unix_6.0.4-1_armhf.deb ...
Unpacking dos2unix (6.0.4-1) ...
Processing triggers for man-db (2.7.0.2-5) ...
Setting up dos2unix (6.0.4-1) ...
安裝完畢後用 dos2unix 將 checkwifi.sh 改成 Unix 格式即可正常執行了 :
安裝完畢後用 dos2unix 將 checkwifi.sh 改成 Unix 格式即可正常執行了 :
pi@raspberrypi:~ $ dos2unix checkwifi.sh
dos2unix: converting file checkwifi.sh to Unix format ...
pi@raspberrypi:~ $ sudo cp checkwifi.sh /usr/local/bin/checkwifi.sh
pi@raspberrypi:~ $ sudo chmod 775 /usr/local/bin/checkwifi.sh
pi@raspberrypi:~ $ sudo /usr/local/bin/checkwifi.sh
pi@raspberrypi:~ $
接下來就是修改 crontab, 設定每小時執行一次 checkwifi.sh, 若連線異常就重啟樹莓派 :
pi@raspberrypi:~ $ crontab -e
GNU nano 2.2.6 File: /tmp/crontab.HDz47N/crontab
# daemon's notion of time and timezones.
#
# Output of the crontab jobs (including errors) is sent through
# email to the user the crontab file belongs to (unless redirected).
#
# For example, you can run a backup of all your user accounts
# at 5 a.m every week with:
# 0 5 * * 1 tar -zcf /var/backups/home.tgz /home/
#
# For more information see the manual pages of crontab(5) and cron(8)
#
# m h dom mon dow command
*/10 * * * * /usr/bin/python2 /home/pi/reportip2.py
0 * * * * sudo /usr/local/checkwifi.sh
這樣應該就萬無一失了. 查看 crontab 日誌表可知 checkwifi.sh 在整點時有正常執行 :
pi@raspberrypi:~ $ sudo cat /var/log/cron.log
.....
Jan 1 13:00:01 raspberrypi CRON[23684]: (pi) CMD (sudo /usr/local/checkwifi.sh)
Jan 1 13:00:01 raspberrypi CRON[23674]: (pi) MAIL (mailed 49 bytes of output bu t got status 0x0001 from MTA#012)
Jan 1 13:00:02 raspberrypi CRON[23675]: (pi) MAIL (mailed 101 bytes of output b ut got status 0x0001 from MTA#012)
Jan 1 13:09:01 raspberrypi CRON[23708]: (root) CMD ( [ -x /usr/lib/php5/sessio nclean ] && /usr/lib/php5/sessionclean)
Jan 1 13:10:01 raspberrypi CRON[23751]: (pi) CMD (/usr/bin/python2 /home/pi/rep ortip2.py)
Jan 1 13:10:02 raspberrypi CRON[23747]: (pi) MAIL (mailed 101 bytes of output b ut got status 0x0001 from MTA#012)
Jan 1 13:17:01 raspberrypi CRON[23837]: (root) CMD ( cd / && run-parts --repo rt /etc/cron.hourly)
Jan 1 13:20:01 raspberrypi CRON[23855]: (pi) CMD (/usr/bin/python2 /home/pi/rep ortip2.py)
Jan 1 13:20:02 raspberrypi CRON[23851]: (pi) MAIL (mailed 101 bytes of output b ut got status 0x0001 from MTA#012)
Jan 1 13:30:01 raspberrypi CRON[23897]: (pi) CMD (/usr/bin/python2 /home/pi/rep ortip2.py)
Jan 1 13:30:02 raspberrypi CRON[23893]: (pi) MAIL (mailed 101 bytes of output b ut got status 0x0001 from MTA#012)
Jan 1 13:39:01 raspberrypi CRON[23920]: (root) CMD ( [ -x /usr/lib/php5/sessio nclean ] && /usr/lib/php5/sessionclean)
Jan 1 13:40:01 raspberrypi CRON[23965]: (pi) CMD (/usr/bin/python2 /home/pi/rep ortip2.py)
Jan 1 13:40:02 raspberrypi CRON[23961]: (pi) MAIL (mailed 101 bytes of output b ut got status 0x0001 from MTA#012)
關於 crontab 日誌紀錄開啟方式參考 :
# 從外網以 SSH 存取樹莓派的方法
2018-01-02 補充 :
早上 07:00 手機收 mail 就收到樹莓派傳來的最新 IP 為 114.27.99.134 :
這兩天觀察 IP 變換頻率不定, 昨天一天一次, 今天則已變換兩次. 每當我要連線操控鄉下的 Pi 3 時就在手機信箱中找最近一次的 [RPI] IP CHANGED 標題的郵件, 再開啟手機 App JuiceSSH 1編輯連線 IP 即可, 不須開啟電腦也能透過 Internet 控制 Pi 3, 操作如下 :
首先按 JuiceSSH 最上方的連線 (管理您的連線) :
按住所要編輯的連線 (此處為中間的 Raspberry Pi 3) :
選編輯 :
更改主機欄為最新的 IP, 然後務必按右上角的勾勾才會儲存進去 :
按左上角的 <- 更新連線回到 JuiceSSH 首頁, 點 "常用" 中剛剛編輯好新 IP 的連線 (此處為 Raspberry Pi 3) 就會建立連線了 :
有 JuiceSSH 真好用.
2018-01-08 補充 :
觀察本周收到的 IP_CHANGED 郵件如下 :
有時候一天變化多次 (1 月 3 日就三次), 有時好幾天都不變, 例如 1/4~1/5 都沒變. 或許 1/3 的多次變化是因為自動重開機, 但上面的 Shell script 沒有紀錄重開機事件, 因此無法印證. 有空要修改程式, 在 reboot 前把時間紀錄到一個文字檔中.
pi@raspberrypi:~ $ sudo cat /var/log/cron.log
.....
Jan 1 12:50:02 raspberrypi CRON[23625]: (pi) MAIL (mailed 101 bytes of output b ut got status 0x0001 from MTA#012)
Jan 1 13:00:01 raspberrypi CRON[23682]: (pi) CMD (/usr/bin/python2 /home/pi/rep ortip2.py)Jan 1 13:00:01 raspberrypi CRON[23684]: (pi) CMD (sudo /usr/local/checkwifi.sh)
Jan 1 13:00:01 raspberrypi CRON[23674]: (pi) MAIL (mailed 49 bytes of output bu t got status 0x0001 from MTA#012)
Jan 1 13:00:02 raspberrypi CRON[23675]: (pi) MAIL (mailed 101 bytes of output b ut got status 0x0001 from MTA#012)
Jan 1 13:09:01 raspberrypi CRON[23708]: (root) CMD ( [ -x /usr/lib/php5/sessio nclean ] && /usr/lib/php5/sessionclean)
Jan 1 13:10:01 raspberrypi CRON[23751]: (pi) CMD (/usr/bin/python2 /home/pi/rep ortip2.py)
Jan 1 13:10:02 raspberrypi CRON[23747]: (pi) MAIL (mailed 101 bytes of output b ut got status 0x0001 from MTA#012)
Jan 1 13:17:01 raspberrypi CRON[23837]: (root) CMD ( cd / && run-parts --repo rt /etc/cron.hourly)
Jan 1 13:20:01 raspberrypi CRON[23855]: (pi) CMD (/usr/bin/python2 /home/pi/rep ortip2.py)
Jan 1 13:20:02 raspberrypi CRON[23851]: (pi) MAIL (mailed 101 bytes of output b ut got status 0x0001 from MTA#012)
Jan 1 13:30:01 raspberrypi CRON[23897]: (pi) CMD (/usr/bin/python2 /home/pi/rep ortip2.py)
Jan 1 13:30:02 raspberrypi CRON[23893]: (pi) MAIL (mailed 101 bytes of output b ut got status 0x0001 from MTA#012)
Jan 1 13:39:01 raspberrypi CRON[23920]: (root) CMD ( [ -x /usr/lib/php5/sessio nclean ] && /usr/lib/php5/sessionclean)
Jan 1 13:40:01 raspberrypi CRON[23965]: (pi) CMD (/usr/bin/python2 /home/pi/rep ortip2.py)
Jan 1 13:40:02 raspberrypi CRON[23961]: (pi) MAIL (mailed 101 bytes of output b ut got status 0x0001 from MTA#012)
關於 crontab 日誌紀錄開啟方式參考 :
# 從外網以 SSH 存取樹莓派的方法
2018-01-02 補充 :
早上 07:00 手機收 mail 就收到樹莓派傳來的最新 IP 為 114.27.99.134 :
這兩天觀察 IP 變換頻率不定, 昨天一天一次, 今天則已變換兩次. 每當我要連線操控鄉下的 Pi 3 時就在手機信箱中找最近一次的 [RPI] IP CHANGED 標題的郵件, 再開啟手機 App JuiceSSH 1編輯連線 IP 即可, 不須開啟電腦也能透過 Internet 控制 Pi 3, 操作如下 :
首先按 JuiceSSH 最上方的連線 (管理您的連線) :
按住所要編輯的連線 (此處為中間的 Raspberry Pi 3) :
選編輯 :
更改主機欄為最新的 IP, 然後務必按右上角的勾勾才會儲存進去 :
按左上角的 <- 更新連線回到 JuiceSSH 首頁, 點 "常用" 中剛剛編輯好新 IP 的連線 (此處為 Raspberry Pi 3) 就會建立連線了 :
有 JuiceSSH 真好用.
2018-01-08 補充 :
觀察本周收到的 IP_CHANGED 郵件如下 :
有時候一天變化多次 (1 月 3 日就三次), 有時好幾天都不變, 例如 1/4~1/5 都沒變. 或許 1/3 的多次變化是因為自動重開機, 但上面的 Shell script 沒有紀錄重開機事件, 因此無法印證. 有空要修改程式, 在 reboot 前把時間紀錄到一個文字檔中.
標籤:
網路
,
樹莓派
,
Raspberry Pi
2017年12月31日 星期日
如何更新樹莓派的 Node.js
因為週五在明儀買的 "實戰聊天機器人Bot開發-使用Node.js" 使用 Node.js, 這個我兩年前才學一點點就沒時間學的 Javascript 聖品又重回我的眼簾, 參考 :
# 關於 Node.js
早上去市場時經過圖書館把 "不一樣的 Node.js" 這本書借回來, 這本書寫得不錯, 非常適合初學者, 已經出第二版了 (2015) :
檢查我的 Raspbian Pixel 發現已經安裝 Node.js :
pi@raspberrypi:~ $ node -v
v0.10.29
但官網可下載的 Windows 版本卻是 9.3.0 版 :
# https://nodejs.org/en/
會不會差太多啊! 我參考下面這篇試圖去更新 Node.js :
# Upgrading to more recent versions of Node.js on the Raspberry Pi
首先是更新套件清單 :
pi@raspberrypi:~ $ sudo apt update
Get:1 http://mirrordirector.raspbian.org jessie InRelease [14.9 kB]
Get:2 http://archive.raspberrypi.org jessie InRelease [22.9 kB]
Get:3 http://mirrordirector.raspbian.org jessie/main armhf Packages [9,536 kB]
Get:4 http://archive.raspberrypi.org jessie/main armhf Packages [171 kB]
Get:5 http://archive.raspberrypi.org jessie/ui armhf Packages [58.9 kB]
Get:6 http://archive.raspberrypi.org jessie/ui armhf Packages [58.9 kB]
Ign http://archive.raspberrypi.org jessie/main Translation-en_US
Ign http://archive.raspberrypi.org jessie/main Translation-en
Ign http://archive.raspberrypi.org jessie/ui Translation-en_US
Ign http://archive.raspberrypi.org jessie/ui Translation-en
Get:7 http://mirrordirector.raspbian.org jessie/contrib armhf Packages [43.3 kB]
Get:8 http://mirrordirector.raspbian.org jessie/non-free armhf Packages [84.2 kB]
Get:9 http://mirrordirector.raspbian.org jessie/rpi armhf Packages [1,356 B]
Ign http://mirrordirector.raspbian.org jessie/contrib Translation-en_US
Ign http://mirrordirector.raspbian.org jessie/contrib Translation-en
Ign http://mirrordirector.raspbian.org jessie/main Translation-en_US
Ign http://mirrordirector.raspbian.org jessie/main Translation-en
Ign http://mirrordirector.raspbian.org jessie/non-free Translation-en_US
Ign http://mirrordirector.raspbian.org jessie/non-free Translation-en
Ign http://mirrordirector.raspbian.org jessie/rpi Translation-en_US
Ign http://mirrordirector.raspbian.org jessie/rpi Translation-en
Fetched 9,916 kB in 2min 41s (61.5 kB/s)
Reading package lists... Done
Building dependency tree
Reading state information... Done
198 packages can be upgraded. Run 'apt list --upgradable' to see them.
然後檢查套件清單中最新的 Node.js 版本 :
pi@raspberrypi:~ $ apt list nodejs
Listing... Done
nodejs/oldstable,now 0.10.29~dfsg-2 armhf [installed,automatic]
咦? 跟我已安裝的一樣都是 0.10.29? 不管它, 直接下 install 指令去更新 Node.js (已安裝的話就是更新) :
pi@raspberrypi:~ $ sudo apt install nodejs
Reading package lists... Done
Building dependency tree
Reading state information... Done
nodejs is already the newest version.
nodejs set to manually installed.
0 upgraded, 0 newly installed, 0 to remove and 198 not upgraded.
pi@raspberrypi:~ $
$ sudo apt install nodejs
# 關於 Node.js
早上去市場時經過圖書館把 "不一樣的 Node.js" 這本書借回來, 這本書寫得不錯, 非常適合初學者, 已經出第二版了 (2015) :
Source : Taaze
檢查我的 Raspbian Pixel 發現已經安裝 Node.js :
pi@raspberrypi:~ $ node -v
v0.10.29
但官網可下載的 Windows 版本卻是 9.3.0 版 :
# https://nodejs.org/en/
會不會差太多啊! 我參考下面這篇試圖去更新 Node.js :
# Upgrading to more recent versions of Node.js on the Raspberry Pi
首先是更新套件清單 :
pi@raspberrypi:~ $ sudo apt update
Get:1 http://mirrordirector.raspbian.org jessie InRelease [14.9 kB]
Get:2 http://archive.raspberrypi.org jessie InRelease [22.9 kB]
Get:3 http://mirrordirector.raspbian.org jessie/main armhf Packages [9,536 kB]
Get:4 http://archive.raspberrypi.org jessie/main armhf Packages [171 kB]
Get:5 http://archive.raspberrypi.org jessie/ui armhf Packages [58.9 kB]
Get:6 http://archive.raspberrypi.org jessie/ui armhf Packages [58.9 kB]
Ign http://archive.raspberrypi.org jessie/main Translation-en_US
Ign http://archive.raspberrypi.org jessie/main Translation-en
Ign http://archive.raspberrypi.org jessie/ui Translation-en_US
Ign http://archive.raspberrypi.org jessie/ui Translation-en
Get:7 http://mirrordirector.raspbian.org jessie/contrib armhf Packages [43.3 kB]
Get:8 http://mirrordirector.raspbian.org jessie/non-free armhf Packages [84.2 kB]
Get:9 http://mirrordirector.raspbian.org jessie/rpi armhf Packages [1,356 B]
Ign http://mirrordirector.raspbian.org jessie/contrib Translation-en_US
Ign http://mirrordirector.raspbian.org jessie/contrib Translation-en
Ign http://mirrordirector.raspbian.org jessie/main Translation-en_US
Ign http://mirrordirector.raspbian.org jessie/main Translation-en
Ign http://mirrordirector.raspbian.org jessie/non-free Translation-en_US
Ign http://mirrordirector.raspbian.org jessie/non-free Translation-en
Ign http://mirrordirector.raspbian.org jessie/rpi Translation-en_US
Ign http://mirrordirector.raspbian.org jessie/rpi Translation-en
Fetched 9,916 kB in 2min 41s (61.5 kB/s)
Reading package lists... Done
Building dependency tree
Reading state information... Done
198 packages can be upgraded. Run 'apt list --upgradable' to see them.
然後檢查套件清單中最新的 Node.js 版本 :
pi@raspberrypi:~ $ apt list nodejs
Listing... Done
nodejs/oldstable,now 0.10.29~dfsg-2 armhf [installed,automatic]
咦? 跟我已安裝的一樣都是 0.10.29? 不管它, 直接下 install 指令去更新 Node.js (已安裝的話就是更新) :
pi@raspberrypi:~ $ sudo apt install nodejs
Reading package lists... Done
Building dependency tree
Reading state information... Done
nodejs is already the newest version.
nodejs set to manually installed.
0 upgraded, 0 newly installed, 0 to remove and 198 not upgraded.
pi@raspberrypi:~ $
還真的已經是最新版, 原來樹莓派最新的套件清單還是 0.10.29 版啊! 如果要更新到 9.3.0 版可能要用該文後面那個 curl 指令去下載官網最新版本 :
$ curl -sL https://deb.nodesource.com/setup_9.x | sudo -E bash -
然後再安裝 9.3.0 版了 :
不過我決定暫時不升版, 目前這樣夠用就好, 以後有需要再升.
參考 :
# Installing newer version of NodeJS on Pi 3
2018-01-02 補充 :
今天我用高雄家裡的 RPI B 執行了上面 curl 指令失敗, 結果如下 :
pi@raspberrypi:~ $ curl -sL https://deb.nodesource.com/setup_9.x | sudo -E bash -
## Installing the NodeSource Node.js v9.x repo...
## You appear to be running on ARMv6 hardware. Unfortunately this is not currently supported by the NodeSource Linux distributions. Please use the 'linux-armv6l' binary tarballs available directly from nodejs.org for Node.js v4 and later.
意思好像是 Node.js v9 還未支援 ARMv6 核心.
2018-01-05 補充 :
今日有熱心的 Node.js 先進留言指教, 原來上面我找到的方法不管用, 網友提供的更新方法我複製整理如下 :
1. 下載
wget https://nodejs.org/dist/latest-v9.x/node-v9.3.0-linux-armv6l.tar.gz
2. 解壓縮
tar -xvf node-v9.3.0-linux-armv6l.tar.gz
3. 切換至資料夾
cd node-v9.3.0-linux-armv6l
4. 移動至/usr/local/
sudo cp -R * /usr/local/
5. 設定NODE_PATH變數(.bashrc)
export NODE_PATH=/usr/local/lib/node_modules
6. 檢查版本
node -v
npm -v
我依此步驟進行, 果真將 Node.js 升版至 v9.3.0, 實在太感謝這位匿名的朋友啦!
升版過程節錄如下 :
pi@raspberrypi:~ $ wget https://nodejs.org/dist/latest-v9.x/node-v9.3.0-linux-ar
mv6l.tar.gz
--2018-01-05 19:21:38-- https://nodejs.org/dist/latest-v9.x/node-v9.3.0-linux-armv6l.tar.gz
Resolving nodejs.org (nodejs.org)... 104.20.22.46, 104.20.23.46, 2400:cb00:2048:1::6814:172e, ...
Connecting to nodejs.org (nodejs.org)|104.20.22.46|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 16930799 (16M) [application/gzip]
Saving to: node-v9.3.0-linux-armv6l.tar.gz
pi@raspberrypi:~/node-v9.3.0-linux-armv6l $ sudo cp -R * /usr/local/
pi@raspberrypi:~/node-v9.3.0-linux-armv6l $ export NODE_PATH=/usr/local/lib/node_modules
pi@raspberrypi:~/node-v9.3.0-linux-armv6l $ node -v
v9.3.0
pi@raspberrypi:~/node-v9.3.0-linux-armv6l $ npm -v
5.5.1
pi@raspberrypi:~/node-v9.3.0-linux-armv6l $ cd ..
pi@raspberrypi:~ $ node
> console.log("Hello World");
Hello World
undefined (為啥會有這個東東?Windows 上沒有)
參考 :
# Installing newer version of NodeJS on Pi 3
2018-01-02 補充 :
今天我用高雄家裡的 RPI B 執行了上面 curl 指令失敗, 結果如下 :
pi@raspberrypi:~ $ curl -sL https://deb.nodesource.com/setup_9.x | sudo -E bash -
## Installing the NodeSource Node.js v9.x repo...
## You appear to be running on ARMv6 hardware. Unfortunately this is not currently supported by the NodeSource Linux distributions. Please use the 'linux-armv6l' binary tarballs available directly from nodejs.org for Node.js v4 and later.
意思好像是 Node.js v9 還未支援 ARMv6 核心.
2018-01-05 補充 :
今日有熱心的 Node.js 先進留言指教, 原來上面我找到的方法不管用, 網友提供的更新方法我複製整理如下 :
1. 下載
wget https://nodejs.org/dist/latest-v9.x/node-v9.3.0-linux-armv6l.tar.gz
2. 解壓縮
tar -xvf node-v9.3.0-linux-armv6l.tar.gz
3. 切換至資料夾
cd node-v9.3.0-linux-armv6l
4. 移動至/usr/local/
sudo cp -R * /usr/local/
5. 設定NODE_PATH變數(.bashrc)
export NODE_PATH=/usr/local/lib/node_modules
6. 檢查版本
node -v
npm -v
我依此步驟進行, 果真將 Node.js 升版至 v9.3.0, 實在太感謝這位匿名的朋友啦!
升版過程節錄如下 :
pi@raspberrypi:~ $ wget https://nodejs.org/dist/latest-v9.x/node-v9.3.0-linux-ar
mv6l.tar.gz
--2018-01-05 19:21:38-- https://nodejs.org/dist/latest-v9.x/node-v9.3.0-linux-armv6l.tar.gz
Resolving nodejs.org (nodejs.org)... 104.20.22.46, 104.20.23.46, 2400:cb00:2048:1::6814:172e, ...
Connecting to nodejs.org (nodejs.org)|104.20.22.46|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 16930799 (16M) [application/gzip]
Saving to: node-v9.3.0-linux-armv6l.tar.gz
(略)
pi@raspberrypi:~ $ tar -xvf node-v9.3.0-linux-armv6l.tar.gz
(略)
pi@raspberrypi:~ $ cd node-v9.3.0-linux-armv6lpi@raspberrypi:~/node-v9.3.0-linux-armv6l $ sudo cp -R * /usr/local/
pi@raspberrypi:~/node-v9.3.0-linux-armv6l $ export NODE_PATH=/usr/local/lib/node_modules
pi@raspberrypi:~/node-v9.3.0-linux-armv6l $ node -v
v9.3.0
pi@raspberrypi:~/node-v9.3.0-linux-armv6l $ npm -v
5.5.1
pi@raspberrypi:~/node-v9.3.0-linux-armv6l $ cd ..
pi@raspberrypi:~ $ node
> console.log("Hello World");
Hello World
undefined (為啥會有這個東東?
標籤:
樹莓派
,
Node.js
,
Raspberry Pi
2017年12月30日 星期六
買 R 語言深入淺出財經計量等三本書
昨天明儀通知我所訂 "R 語言深入淺出財經計量" 已到貨, 晚上去市圖還書後順路去取書, 回來稍微翻閱了一下, 嗯, 這也是我今年所買的書裡最棒的一本之一.
買好後逛了一下, 又找到兩本不錯的書 :
# 實戰物聯網開發-使用ESP8266
# 實戰聊天機器人Bot開發-使用Node.js
但買回來才知金石堂竟然打七折!
參考 :
# Raspberry Pi 入門與機器人實作應用
# Python資料科學學習手冊
# 玩轉社群:文字大數據實作
# Google Cloud雲端平台實作手冊:Google雲端功能一點就通
# Data Science from Scratch中文版:用Python學資料科學
# AI及機器學習的經脈:演算法新解
買好後逛了一下, 又找到兩本不錯的書 :
# 實戰物聯網開發-使用ESP8266
# 實戰聊天機器人Bot開發-使用Node.js
但買回來才知金石堂竟然打七折!
參考 :
# Raspberry Pi 入門與機器人實作應用
# Python資料科學學習手冊
# 玩轉社群:文字大數據實作
# Google Cloud雲端平台實作手冊:Google雲端功能一點就通
# Data Science from Scratch中文版:用Python學資料科學
# AI及機器學習的經脈:演算法新解
太陽光電設置班第四課
今天載二哥去上 APCS 後順路到正修上課, 8:15 出發大約 8:45 分就到了. 今天早上是室內課, 老師花了點時間複習上禮拜的併聯型配線圖, 然後講解獨立型配線圖. 獨立型比較複雜, 比並聯型多了充電控制器與電池, 電表也多了一個, 分流器多兩個, 但少了瓦時計與比流器, 因為不用跟台電並聯. 在檢定方面考量考試時間, 獨立型不考日照計與溫度計量測.
下午則是上頂樓實做, 主要是檢定第一站的直流接線箱配線練習, 以及第一站到第二站的拉線. 其實第一站配線是最簡單的, 複雜的第二站, 特別是獨立型. 邊做邊聊才知道, 今天跟我一組的兩位同學是遠從台北與苗栗搭高鐵下來上課的, 原來台東還不是最遠, 真是佩服. 他們倆位都有參加回訓班 (上課時間 3/3, 3/4, 3/21, 3/22 週六日, 學費 12000), 也報名明年乙級技術士檢定 (1/2~1/12 報名, 3 月學科考試, 6/5, 6/6 術科考試).
我雖然前天在全家也買了報名表, 但今天聽黃老師說檢定主要是考熟練度, 我們這班上課內容雖然主要是檢定為主, 但練習時間不夠達到熟練程度, 考量明年菁菁要參加會考, 我也沒時間準備檢定, 所以決定不報名檢定, 也不參加回訓, 就是純粹學習而已. 上黃宏欣老師的課收穫頗多, 今天老師強調 "觀念比技術重要" 很有道理, 因為技術只要練習就會進步, 但觀念錯思考方式就有問題, 要進步就很難.
以下整理獨立型配線, 其單線圖如下 :
注意, 虛線表示要使用 5.5mm 電力線, 而實線使用 3.5mm 電力線.
首先是第一站的直流接線箱 (左邊第一個紅框). 與並聯型不同的是, 獨立型模組是三串兩並, 因為獨立型之交流負載為 110V, 所以只要三個串聯即可達到所需電壓, Voc=38.85*3=116.55v, 乘以 1.25 倍 : 116.55*1.25=145.7v.
其元件配置圖與配線如下 :
電力線因為模組是三串兩並, 故有 4 條 4mm 的耐候線 (紅黑紅黑) 從模組進來, 先到兩組 Fuse 後進 DCS, 再出箱體到第二站的獨立型配線箱. 注意, 獨立型因電流比並聯型大, 接線箱配線都使用 5mm 的電力線. 另外, 兩組 Fuse 底下各用一條較短的電力線並接.
接下來是第二站的配電箱, 獨立型配電箱元件配置圖如下 :
左半部是組列側配電箱, 主要是充電控制器 (將 116v 穩壓至 24v/48v), 兩個直流電表, 以及偵測直流電流的兩個分流器, 與 NFB, DCS 開關等. 主角是充電控制器, 用來將來自三串兩並模組的 100 多伏特直流電壓降壓成 24V 的穩定電壓, 以便向額定 24V 蓄電池充電. 左上角的直流電表 1 搭配左下角分流器測得之電流用來測量模組側功率 (充控輸入端); 右方的直流電表 2 則搭配右下角分流器測得之電流用來測量電池側的功率 (充控輸出端).
充電控制器端點 :
PV+, PV- : 模組電壓輸入
BAT+, BAT- : 蓄電池輸出
G : 接地
直流電表端點 :
DCS24V+, DCS24V- : 電表電源
DC+, DC- : 電壓取樣
A+, A- : 電流取樣
RS-485+, RS485- : 通訊
組列側的配線圖如下 :
注意, 單線圖中虛線部分必須使用 5.5mm 電力線, 實線部分用 3.5mm 電力線. 這是因為 260W 模組短路電路 Isc=9A, 兩組並聯為 18A, 乘以 1.25 為 22.5A, 超過 3.5mm PV 線的耐流 (導線槽 20A), 須改用 5.5mm 才行.
配線時先接電力線, 次接電表線, 再接 RS-485 通訊線與接地線. 從直流接線箱跨站而來的 5.5mm 耐候線先到 NFB 一次側, 然後進充電控制器的 PV+, 充控的 PV- 則先接分流器上端 (比較近), 然後接 NFB 的負端形成迴路. 由於電流是從分流器上方流入, 因此上方為正電壓, 要接電表的 A+; 下方為負電壓, 要接電錶 A-. 電壓取樣部分則從 NFB 下方取電, 接到電錶的 DC+ 與 DC-. 這樣充控輸入側就接好了.
然後是充控的輸出側, BAT+ 接到 DCS 上端下接電池; BAT- 接分流器上端 (較近), 分流器下端則回到 DCS 上方的負端形成迴路. 由於充電時電流表要顯示正, 電流是從分流器下方往上流, 因此充電時分流器下方為正, 要接到輸出側電錶的 A+, 分流器上方為負接 A-. 電壓取樣則從共接點 BAT+ 與 BAT- 接到 DC+ 與 DC-, 同時分接到兩個直流電表的電源 DC24+ 與 DC24-, 亦即兩顆直流電表都是吃電池的電. BAT+ 與 BAT- 是組列側 (A), 電池側 (B), 與負載側 (C) 的共接點, 所以要分岐下自行配管的 PVC 管路到隔壁的負載側. 三方的功率有如下關係 :
A(組列)=B(電池)+C(負載)
如果組列供電 2000W, 負載吃 1500W, 則可向電池充電 500W (電表 2 電流為正); 若組列供電降至 1000W, 則 B=-500W, 亦即電池要放電 500W (電表 2 電流為負).
最後是接充控接電點到接地板, 接地線也要隨電力線下 PVC 管. 而兩個電表的 RS-485 通訊線共接後下備妥之可撓金屬管路到隔壁的負載側.
配電箱右半部是負載側配電箱, 主要是變流器與搭配分流器的直流電表 (量負載端功率). 負載側配線圖如下 :
組列側的電力線紅線先到 NFB 上方, 下方直接到變流器的 RED (+), 黑線則接分流器下方 (較近), 分流器上方黑線接變流器 BLACK(-) 形成迴路. 跟組列側一樣, 因為分流器接在變流器後面, 所以電流是從分流器上方 (即變流器之 BLACK) 流下來, 故上方為正要接到電錶電流取樣的 A+; 下方接 A-. 電表電源從 NFB 下方分歧接到 DC24+ 與 DC24-, 同時分岐到 DC+ 與 DC- 做電壓取樣. 亦即三個電表之電源都是吃 BAT+ 與 BAT-, 只是負載側的電表被 NFB 隔離而已.
接著是輸出至負載端, 直流電源從變流器輸入端的 RED 與 BLACK 分岐到直流負載 NFB3, 交流電源則從變流器之 L (紅) 與 N (黑) RU, 接到 NFB4. 最後接上共接的 RS-485 通訊線即可.
完整的獨立型配電箱配線圖如下 :
配線看起來很複雜, 其實從單線圖看, 電路非常簡單. 比較難理解的是分流器接法, 因為單線圖顯示 NFB 或充控紅線一出來就是接分流器, 實際配線分流器卻是接在迴路後端, 只要循著電流方向辨別正負, 就知道哪一端要接 A+ 了. 但要注意, 電池側的分流器要以充電方向來思考.
下午則是上頂樓實做, 主要是檢定第一站的直流接線箱配線練習, 以及第一站到第二站的拉線. 其實第一站配線是最簡單的, 複雜的第二站, 特別是獨立型. 邊做邊聊才知道, 今天跟我一組的兩位同學是遠從台北與苗栗搭高鐵下來上課的, 原來台東還不是最遠, 真是佩服. 他們倆位都有參加回訓班 (上課時間 3/3, 3/4, 3/21, 3/22 週六日, 學費 12000), 也報名明年乙級技術士檢定 (1/2~1/12 報名, 3 月學科考試, 6/5, 6/6 術科考試).
我雖然前天在全家也買了報名表, 但今天聽黃老師說檢定主要是考熟練度, 我們這班上課內容雖然主要是檢定為主, 但練習時間不夠達到熟練程度, 考量明年菁菁要參加會考, 我也沒時間準備檢定, 所以決定不報名檢定, 也不參加回訓, 就是純粹學習而已. 上黃宏欣老師的課收穫頗多, 今天老師強調 "觀念比技術重要" 很有道理, 因為技術只要練習就會進步, 但觀念錯思考方式就有問題, 要進步就很難.
以下整理獨立型配線, 其單線圖如下 :
注意, 虛線表示要使用 5.5mm 電力線, 而實線使用 3.5mm 電力線.
首先是第一站的直流接線箱 (左邊第一個紅框). 與並聯型不同的是, 獨立型模組是三串兩並, 因為獨立型之交流負載為 110V, 所以只要三個串聯即可達到所需電壓, Voc=38.85*3=116.55v, 乘以 1.25 倍 : 116.55*1.25=145.7v.
其元件配置圖與配線如下 :
電力線因為模組是三串兩並, 故有 4 條 4mm 的耐候線 (紅黑紅黑) 從模組進來, 先到兩組 Fuse 後進 DCS, 再出箱體到第二站的獨立型配線箱. 注意, 獨立型因電流比並聯型大, 接線箱配線都使用 5mm 的電力線. 另外, 兩組 Fuse 底下各用一條較短的電力線並接.
接下來是第二站的配電箱, 獨立型配電箱元件配置圖如下 :
左半部是組列側配電箱, 主要是充電控制器 (將 116v 穩壓至 24v/48v), 兩個直流電表, 以及偵測直流電流的兩個分流器, 與 NFB, DCS 開關等. 主角是充電控制器, 用來將來自三串兩並模組的 100 多伏特直流電壓降壓成 24V 的穩定電壓, 以便向額定 24V 蓄電池充電. 左上角的直流電表 1 搭配左下角分流器測得之電流用來測量模組側功率 (充控輸入端); 右方的直流電表 2 則搭配右下角分流器測得之電流用來測量電池側的功率 (充控輸出端).
充電控制器端點 :
PV+, PV- : 模組電壓輸入
BAT+, BAT- : 蓄電池輸出
G : 接地
直流電表端點 :
DCS24V+, DCS24V- : 電表電源
DC+, DC- : 電壓取樣
A+, A- : 電流取樣
RS-485+, RS485- : 通訊
組列側的配線圖如下 :
注意, 單線圖中虛線部分必須使用 5.5mm 電力線, 實線部分用 3.5mm 電力線. 這是因為 260W 模組短路電路 Isc=9A, 兩組並聯為 18A, 乘以 1.25 為 22.5A, 超過 3.5mm PV 線的耐流 (導線槽 20A), 須改用 5.5mm 才行.
配線時先接電力線, 次接電表線, 再接 RS-485 通訊線與接地線. 從直流接線箱跨站而來的 5.5mm 耐候線先到 NFB 一次側, 然後進充電控制器的 PV+, 充控的 PV- 則先接分流器上端 (比較近), 然後接 NFB 的負端形成迴路. 由於電流是從分流器上方流入, 因此上方為正電壓, 要接電表的 A+; 下方為負電壓, 要接電錶 A-. 電壓取樣部分則從 NFB 下方取電, 接到電錶的 DC+ 與 DC-. 這樣充控輸入側就接好了.
然後是充控的輸出側, BAT+ 接到 DCS 上端下接電池; BAT- 接分流器上端 (較近), 分流器下端則回到 DCS 上方的負端形成迴路. 由於充電時電流表要顯示正, 電流是從分流器下方往上流, 因此充電時分流器下方為正, 要接到輸出側電錶的 A+, 分流器上方為負接 A-. 電壓取樣則從共接點 BAT+ 與 BAT- 接到 DC+ 與 DC-, 同時分接到兩個直流電表的電源 DC24+ 與 DC24-, 亦即兩顆直流電表都是吃電池的電. BAT+ 與 BAT- 是組列側 (A), 電池側 (B), 與負載側 (C) 的共接點, 所以要分岐下自行配管的 PVC 管路到隔壁的負載側. 三方的功率有如下關係 :
A(組列)=B(電池)+C(負載)
如果組列供電 2000W, 負載吃 1500W, 則可向電池充電 500W (電表 2 電流為正); 若組列供電降至 1000W, 則 B=-500W, 亦即電池要放電 500W (電表 2 電流為負).
最後是接充控接電點到接地板, 接地線也要隨電力線下 PVC 管. 而兩個電表的 RS-485 通訊線共接後下備妥之可撓金屬管路到隔壁的負載側.
配電箱右半部是負載側配電箱, 主要是變流器與搭配分流器的直流電表 (量負載端功率). 負載側配線圖如下 :
組列側的電力線紅線先到 NFB 上方, 下方直接到變流器的 RED (+), 黑線則接分流器下方 (較近), 分流器上方黑線接變流器 BLACK(-) 形成迴路. 跟組列側一樣, 因為分流器接在變流器後面, 所以電流是從分流器上方 (即變流器之 BLACK) 流下來, 故上方為正要接到電錶電流取樣的 A+; 下方接 A-. 電表電源從 NFB 下方分歧接到 DC24+ 與 DC24-, 同時分岐到 DC+ 與 DC- 做電壓取樣. 亦即三個電表之電源都是吃 BAT+ 與 BAT-, 只是負載側的電表被 NFB 隔離而已.
接著是輸出至負載端, 直流電源從變流器輸入端的 RED 與 BLACK 分岐到直流負載 NFB3, 交流電源則從變流器之 L (紅) 與 N (黑) RU, 接到 NFB4. 最後接上共接的 RS-485 通訊線即可.
完整的獨立型配電箱配線圖如下 :
配線看起來很複雜, 其實從單線圖看, 電路非常簡單. 比較難理解的是分流器接法, 因為單線圖顯示 NFB 或充控紅線一出來就是接分流器, 實際配線分流器卻是接在迴路後端, 只要循著電流方向辨別正負, 就知道哪一端要接 A+ 了. 但要注意, 電池側的分流器要以充電方向來思考.
2017年12月28日 星期四
R 語言學習筆記 (三) : 陣列
測完矩陣接著測試陣列, 此前的測試紀錄如下 :
# R 語言安裝
# 在樹莓派上安裝 R 語言
# R 語言學習筆記 (一) : 基本語法與向量
# R 語言學習筆記 (二) : 矩陣
R 語言的陣列是矩陣的維度擴展 (矩陣是陣列的一個特例, 它是二維的陣列), 因此其元素一樣也都是同質的 (即資料類型必須相同). 陣列也可視為多維度的向量 (注意, R 語言中向量並無維度), 使用多個索引如 A[i, j, k, ...] 來存取元素, 其中索引 i, j, k, ... 代表各維之位置. 最常用的是三維陣列, 在一些時間序列的應用中甚至會用到高維陣列.
與幾何類比, 向量相當於線; 矩陣相當於面; 而陣列則相當於多維空間. 不管是向量, 矩陣或陣列, 它們的元素都必須同質, 即由相同類型的資料組成.
一. 建立陣列的方法 :
1. 呼叫 array() 函數 :
函數 array() API 如下 :
array(data=NA, dim=length(data), dimnames=NULL)
data : 向量或串列 (用來填滿陣列), 向量以外的資料會自動被 as.vector() 強制轉型.
dim : 整數向量, 用來依序定義各維度之長度.
dimnames : 字串列表 (list) 用來賦予各維度因次名稱 (例如列名, 行名, 表名)
三維陣列的第一列相當於矩陣之列, 第二維相當於行, 第三維通常稱為表 (table). 例如以下的三維陣列用 1:24 的向量來填滿 3*4*2 個元素位置, 會逐行 (by column) 填入元素, 即先填滿第一行, 再填第二行 :
> A <- array(1:24, c(3,4,2)) #建立一,二,三維長度各為 3,4,2 之陣列
> A
, , 1 #顯示第三維第一個資料結構 (相當於 table 1)
[,1] [,2] [,3] [,4]
[1,] 1 4 7 10
[2,] 2 5 8 11
[3,] 3 6 9 12
, , 2 #顯示第三維第二個資料結構 (相當於 table 2)
[,1] [,2] [,3] [,4]
[1,] 13 16 19 22
[2,] 14 17 20 23
[3,] 15 18 21 24
接著來看看陣列的資料結構是用甚麼組成的 :
> class(A) #檢查資料結構是 array
[1] "array"
> is.array(A)
[1] TRUE
> is.vector(A) #不是向量結構
[1] FALSE
> is.matrix(A) #不是矩陣結構
[1] FALSE
> is.array(A[, 1 ,]) # A[ , 1, ] 是二維陣列 (降維)
[1] TRUE
> is.matrix(A[, 1, ]) # A[, 1, ] 也是矩陣 (降維)
[1] TRUE
> class(A[,1,]) # A[, 1, ] 的真實結構是矩陣
[1] "matrix"
> A[,1,]
[,1] [,2]
[1,] 1 13
[2,] 2 14
[3,] 3 15
> A[1,1,]
[1] 1 13
> is.matrix(A[1,1,]) #A[1, 1, ] 則降維成向量
[1] FALSE
上面降維後的 A[ , 1, ] 用 is.array() 與 is.matrix() 檢查, 結果它似乎既是陣列 (二維) 也是矩陣, 用 class() 去檢驗即知事實上 A[ , 1, ] 結構是矩陣而非陣列, 可見陣列確實是用矩陣堆起來的, 而矩陣又是用向量堆起來的.
其實 R 語言中的二維陣列就是矩陣, 例如用 array() 建立一個二維陣列, 用 is.array() 與 is.matrix() 都回應 TRUE, 表示它既是陣列也是矩陣, 但用 class() 去檢查其結構類型卻歸類為是矩陣 :
> A <- array(1:12, c(4,3)) #建立一個二維陣列
> A
[,1] [,2] [,3]
[1,] 1 5 9
[2,] 2 6 10
[3,] 3 7 11
[4,] 4 8 12
> is.array(A) #用 array() 建立當然是陣列
[1] TRUE
> is.matrix(A) #也是矩陣
[1] TRUE
> class(A) #結構上歸類為矩陣
[1] "matrix"
如果建立一個矩陣之後用 as.array() 強制轉成陣列會怎樣呢?
> A <- matrix(1:12, nrow=4) #建立一個矩陣
> A
[,1] [,2] [,3]
[1,] 1 5 9
[2,] 2 6 10
[3,] 3 7 11
[4,] 4 8 12
> is.matrix(A) #用 matrix() 建立當然是矩陣
[1] TRUE
> is.array(A) #嘿! A 竟然也是陣列
[1] TRUE
> class(A) #結構是矩陣
[1] "matrix"
> B <- as.array(A) #用 as.array() 將 A 強制轉型為陣列 B
> B
[,1] [,2] [,3]
[1,] 1 5 9
[2,] 2 6 10
[3,] 3 7 11
[4,] 4 8 12
> is.matrix(B) #還是矩陣
[1] TRUE
> is.array(B) #當然是陣列
[1] TRUE
> class(B) #結構仍歸類為矩陣
[1] "matrix"
我們可以用 identical() 函數來檢驗用 matrix() 與 array() 建立的二維物件是否雷同 :
> A <- matrix(1:12, nrow=4) #建立一個矩陣 A
> A
[,1] [,2] [,3]
[1,] 1 5 9
[2,] 2 6 10
[3,] 3 7 11
[4,] 4 8 12
> B <- array(1:12, c(4,3)) #建立一個二維陣列 B, 內容與 A 矩陣相同
> B
[,1] [,2] [,3]
[1,] 1 5 9
[2,] 2 6 10
[3,] 3 7 11
[4,] 4 8 12
> class(A) #矩陣 A 結構為 matrix
[1] "matrix"
> class(B) #陣列 B 結構亦為 matrix
[1] "matrix"
> identical(A, B) #呼叫 identical() 顯示兩者是同樣物件
[1] TRUE
總之, 在 R 語言中, 大於二維的資料結構是陣列, 二維陣列就被歸類為矩陣.
如果傳入的向量不夠填滿陣列, 則會套用循環規則從頭抓資料, 例如 :
> array(1:17, c(3,4,2))
, , 1
[,1] [,2] [,3] [,4]
[1,] 1 4 7 10
[2,] 2 5 8 11
[3,] 3 6 9 12
, , 2
[,1] [,2] [,3] [,4]
[1,] 13 16 2 5
[2,] 14 17 3 6
[3,] 15 1 4 7
下面是用這 24 個元素來建立一個四維陣列 :
> A <- array(1:24, c(3,2,2,2))
> A
, , 1, 1
[,1] [,2]
[1,] 1 4
[2,] 2 5
[3,] 3 6
, , 2, 1
[,1] [,2]
[1,] 7 10
[2,] 8 11
[3,] 9 12
, , 1, 2
[,1] [,2]
[1,] 13 16
[2,] 14 17
[3,] 15 18
, , 2, 2
[,1] [,2]
[1,] 19 22
[2,] 20 23
[3,] 21 24
五維陣列範例如下 :
> A <- array(1:32, c(2,2,2,2,2))
> A
, , 1, 1, 1
[,1] [,2]
[1,] 1 3
[2,] 2 4
, , 2, 1, 1
[,1] [,2]
[1,] 5 7
[2,] 6 8
, , 1, 2, 1
[,1] [,2]
[1,] 9 11
[2,] 10 12
, , 2, 2, 1
[,1] [,2]
[1,] 13 15
[2,] 14 16
, , 1, 1, 2
[,1] [,2]
[1,] 17 19
[2,] 18 20
, , 2, 1, 2
[,1] [,2]
[1,] 21 23
[2,] 22 24
, , 1, 2, 2
[,1] [,2]
[1,] 25 27
[2,] 26 28
, , 2, 2, 2
[,1] [,2]
[1,] 29 31
[2,] 30 32
可見 R 語言在顯示高維陣列內容時, 是把它拆解到矩陣 (就是第一與第二維組成的二維陣列) 當作最小的單位, 然後從第三維起依序顯示 "每一張表".
2. 呼叫 dim() 函數設定維度將向量或列表變成陣列 :
R 語言中向量 (vector) 是一群有序資料, 看起來像是一維, 但在 R 裡面是沒有維度的資料結構, 用 dim() 檢查會得到 NULL. 與建立矩陣一樣, 若呼叫 dim() 為向量指定大於 2 的維度, 則此無維度的向量將變成有維度的陣列結構, 例如 :
> v <- 1:24 #建立 24 個元素的向量
> dim(v) #向量是無維度的資料結構 (NULL)
NULL
> dim(v) <- c(4,3,2) #指定維度給向量會使其變成矩陣 (2 維) 或向量 (大於 2 維)
> v
, , 1
[,1] [,2] [,3]
[1,] 1 5 9
[2,] 2 6 10
[3,] 3 7 11
[4,] 4 8 12
, , 2
[,1] [,2] [,3]
[1,] 13 17 21
[2,] 14 18 22
[3,] 15 19 23
[4,] 16 20 24
> class(v) #變成陣列了
[1] "array"
> dim(v) #查詢陣列維度是 4*3*2
[1] 4 3 2
二. 存取陣列元素 :
存取陣列元素的方式與矩陣一樣, 也是用索引, 只是索引比較多而已.
> A <- array(1:24, c(4,3,2))
> A
, , 1
[,1] [,2] [,3]
[1,] 1 5 9
[2,] 2 6 10
[3,] 3 7 11
[4,] 4 8 12
, , 2
[,1] [,2] [,3]
[1,] 13 17 21
[2,] 14 18 22
[3,] 15 19 23
[4,] 16 20 24
> A[1,1,1]
[1] 1
> A[1,3,1]
[1] 9
> A[1,3,2]
[1] 21
> A[1,1,]
[1] 1 13
> A[1,,]
[,1] [,2]
[1,] 1 13
[2,] 5 17
[3,] 9 21
> A[,1,]
[,1] [,2]
[1,] 1 13
[2,] 2 14
[3,] 3 15
[4,] 4 16
> A[,,1]
[,1] [,2] [,3]
[1,] 1 5 9
[2,] 2 6 10
[3,] 3 7 11
[4,] 4 8 12
注意, 這些取出來的物件都降階變成了二維的矩陣了, 可用 class() 檢驗. 如果取出來的元件想保留 array 架構, 不要降階成矩陣, 可以在索引最後面加上 drop=FALSE (預設是 TRUE), 例如 :
> A <- array(1:24, c(4,3,2))
> A[1,,] #只取第一維
[,1] [,2]
[1,] 1 13
[2,] 5 17
[3,] 9 21
> class(A[1,,]) #降階為 matrix
[1] "matrix"
> A[1,,,drop=FALSE] #不降階 (保留陣列結構)
, , 1
[,1] [,2] [,3]
[1,] 1 5 9
, , 2
[,1] [,2] [,3]
[1,] 13 17 21
> class(A[1,,,drop=FALSE]) #仍為 array 結構
[1] "array"
> identical(A[1,,], A[1,,,drop=FALSE]) #兩個是不同物件 (內容相同, 但結構不同)
[1] FALSE
上面是存取三維陣列內容時的降維情形, 如果取得的內容是二維, 則降階為矩陣; 若小於二維則為向量. 從多維陣列取得的內容如果大於二維, 則仍然是陣列結構, 例如 :
> A <- array(1:32, c(2,2,2,2,2))
> A
, , 1, 1, 1
[,1] [,2]
[1,] 1 3
[2,] 2 4
, , 2, 1, 1
[,1] [,2]
[1,] 5 7
[2,] 6 8
, , 1, 2, 1
[,1] [,2]
[1,] 9 11
[2,] 10 12
, , 2, 2, 1
[,1] [,2]
[1,] 13 15
[2,] 14 16
, , 1, 1, 2
[,1] [,2]
[1,] 17 19
[2,] 18 20
, , 2, 1, 2
[,1] [,2]
[1,] 21 23
[2,] 22 24
, , 1, 2, 2
[,1] [,2]
[1,] 25 27
[2,] 26 28
, , 2, 2, 2
[,1] [,2]
[1,] 29 31
[2,] 30 32
> A[,,,1,1] #取得子陣列
, , 1
[,1] [,2]
[1,] 1 3
[2,] 2 4
, , 2
[,1] [,2]
[1,] 5 7
[2,] 6 8
> class(A[,,,1,1]) #結構是陣列 (因為是三維)
[1] "array"
取得陣列內容時也可以使用負索引來排除不要的部分, 例如 :
> A <- array(1:24, c(4,3,2))
> A
, , 1
[,1] [,2] [,3]
[1,] 1 5 9
[2,] 2 6 10
[3,] 3 7 11
[4,] 4 8 12
, , 2
[,1] [,2] [,3]
[1,] 13 17 21
[2,] 14 18 22
[3,] 15 19 23
[4,] 16 20 24
> A[-3, c(1,3), 2] #第一維不要第三列, 第二維取第一與第三行, 第三維取第二張
[,1] [,2]
[1,] 13 21
[2,] 14 22
[3,] 16 24
修改陣列的內容只要直接將向量或矩陣指派給陣列的指定部分即可, 例如 :
> A <- array(1:24, c(4,3,2)) #建立陣列
> A
, , 1
[,1] [,2] [,3]
[1,] 1 5 9
[2,] 2 6 10
[3,] 3 7 11
[4,] 4 8 12
, , 2
[,1] [,2] [,3]
[1,] 13 17 21
[2,] 14 18 22
[3,] 15 19 23
[4,] 16 20 24
> A[3:4,c(1,3),1] #第一維之 3~4 列, 第二維的 1 與 3 行, 第三維的第一張表
[,1] [,2]
[1,] 3 11
[2,] 4 12
> A[3:4,c(1,3),1] <- matrix(NA, nrow=2, ncol=2) #將矩陣指派給陣列局部
> A
, , 1
[,1] [,2] [,3]
[1,] 1 5 9
[2,] 2 6 10
[3,] NA 7 NA
[4,] NA 8 NA
, , 2
[,1] [,2] [,3]
[1,] 13 17 21
[2,] 14 18 22
[3,] 15 19 23
[4,] 16 20 24
三. 陣列常用函數 :
# R 語言安裝
# 在樹莓派上安裝 R 語言
# R 語言學習筆記 (一) : 基本語法與向量
# R 語言學習筆記 (二) : 矩陣
R 語言的陣列是矩陣的維度擴展 (矩陣是陣列的一個特例, 它是二維的陣列), 因此其元素一樣也都是同質的 (即資料類型必須相同). 陣列也可視為多維度的向量 (注意, R 語言中向量並無維度), 使用多個索引如 A[i, j, k, ...] 來存取元素, 其中索引 i, j, k, ... 代表各維之位置. 最常用的是三維陣列, 在一些時間序列的應用中甚至會用到高維陣列.
與幾何類比, 向量相當於線; 矩陣相當於面; 而陣列則相當於多維空間. 不管是向量, 矩陣或陣列, 它們的元素都必須同質, 即由相同類型的資料組成.
一. 建立陣列的方法 :
1. 呼叫 array() 函數 :
函數 array() API 如下 :
array(data=NA, dim=length(data), dimnames=NULL)
data : 向量或串列 (用來填滿陣列), 向量以外的資料會自動被 as.vector() 強制轉型.
dim : 整數向量, 用來依序定義各維度之長度.
dimnames : 字串列表 (list) 用來賦予各維度因次名稱 (例如列名, 行名, 表名)
三維陣列的第一列相當於矩陣之列, 第二維相當於行, 第三維通常稱為表 (table). 例如以下的三維陣列用 1:24 的向量來填滿 3*4*2 個元素位置, 會逐行 (by column) 填入元素, 即先填滿第一行, 再填第二行 :
> A <- array(1:24, c(3,4,2)) #建立一,二,三維長度各為 3,4,2 之陣列
> A
, , 1 #顯示第三維第一個資料結構 (相當於 table 1)
[,1] [,2] [,3] [,4]
[1,] 1 4 7 10
[2,] 2 5 8 11
[3,] 3 6 9 12
, , 2 #顯示第三維第二個資料結構 (相當於 table 2)
[,1] [,2] [,3] [,4]
[1,] 13 16 19 22
[2,] 14 17 20 23
[3,] 15 18 21 24
接著來看看陣列的資料結構是用甚麼組成的 :
> class(A) #檢查資料結構是 array
[1] "array"
> is.array(A)
[1] TRUE
> is.vector(A) #不是向量結構
[1] FALSE
> is.matrix(A) #不是矩陣結構
[1] FALSE
> is.array(A[, 1 ,]) # A[ , 1, ] 是二維陣列 (降維)
[1] TRUE
> is.matrix(A[, 1, ]) # A[, 1, ] 也是矩陣 (降維)
[1] TRUE
> class(A[,1,]) # A[, 1, ] 的真實結構是矩陣
[1] "matrix"
> A[,1,]
[,1] [,2]
[1,] 1 13
[2,] 2 14
[3,] 3 15
> A[1,1,]
[1] 1 13
> is.matrix(A[1,1,]) #A[1, 1, ] 則降維成向量
[1] FALSE
> is.vector(A[1,1,])
[1] TRUE
上面降維後的 A[ , 1, ] 用 is.array() 與 is.matrix() 檢查, 結果它似乎既是陣列 (二維) 也是矩陣, 用 class() 去檢驗即知事實上 A[ , 1, ] 結構是矩陣而非陣列, 可見陣列確實是用矩陣堆起來的, 而矩陣又是用向量堆起來的.
其實 R 語言中的二維陣列就是矩陣, 例如用 array() 建立一個二維陣列, 用 is.array() 與 is.matrix() 都回應 TRUE, 表示它既是陣列也是矩陣, 但用 class() 去檢查其結構類型卻歸類為是矩陣 :
> A <- array(1:12, c(4,3)) #建立一個二維陣列
> A
[,1] [,2] [,3]
[1,] 1 5 9
[2,] 2 6 10
[3,] 3 7 11
[4,] 4 8 12
> is.array(A) #用 array() 建立當然是陣列
[1] TRUE
> is.matrix(A) #也是矩陣
[1] TRUE
> class(A) #結構上歸類為矩陣
[1] "matrix"
> A <- matrix(1:12, nrow=4) #建立一個矩陣
> A
[,1] [,2] [,3]
[1,] 1 5 9
[2,] 2 6 10
[3,] 3 7 11
[4,] 4 8 12
> is.matrix(A) #用 matrix() 建立當然是矩陣
[1] TRUE
> is.array(A) #嘿! A 竟然也是陣列
[1] TRUE
> class(A) #結構是矩陣
[1] "matrix"
> B <- as.array(A) #用 as.array() 將 A 強制轉型為陣列 B
> B
[,1] [,2] [,3]
[1,] 1 5 9
[2,] 2 6 10
[3,] 3 7 11
[4,] 4 8 12
> is.matrix(B) #還是矩陣
[1] TRUE
> is.array(B) #當然是陣列
[1] TRUE
> class(B) #結構仍歸類為矩陣
[1] "matrix"
我們可以用 identical() 函數來檢驗用 matrix() 與 array() 建立的二維物件是否雷同 :
> A <- matrix(1:12, nrow=4) #建立一個矩陣 A
> A
[,1] [,2] [,3]
[1,] 1 5 9
[2,] 2 6 10
[3,] 3 7 11
[4,] 4 8 12
> B <- array(1:12, c(4,3)) #建立一個二維陣列 B, 內容與 A 矩陣相同
> B
[,1] [,2] [,3]
[1,] 1 5 9
[2,] 2 6 10
[3,] 3 7 11
[4,] 4 8 12
> class(A) #矩陣 A 結構為 matrix
[1] "matrix"
> class(B) #陣列 B 結構亦為 matrix
[1] "matrix"
> identical(A, B) #呼叫 identical() 顯示兩者是同樣物件
[1] TRUE
總之, 在 R 語言中, 大於二維的資料結構是陣列, 二維陣列就被歸類為矩陣.
如果傳入的向量不夠填滿陣列, 則會套用循環規則從頭抓資料, 例如 :
> array(1:17, c(3,4,2))
, , 1
[,1] [,2] [,3] [,4]
[1,] 1 4 7 10
[2,] 2 5 8 11
[3,] 3 6 9 12
, , 2
[,1] [,2] [,3] [,4]
[1,] 13 16 2 5
[2,] 14 17 3 6
[3,] 15 1 4 7
> A <- array(1:24, c(3,2,2,2))
> A
, , 1, 1
[,1] [,2]
[1,] 1 4
[2,] 2 5
[3,] 3 6
, , 2, 1
[,1] [,2]
[1,] 7 10
[2,] 8 11
[3,] 9 12
, , 1, 2
[,1] [,2]
[1,] 13 16
[2,] 14 17
[3,] 15 18
, , 2, 2
[,1] [,2]
[1,] 19 22
[2,] 20 23
[3,] 21 24
五維陣列範例如下 :
> A <- array(1:32, c(2,2,2,2,2))
> A
, , 1, 1, 1
[,1] [,2]
[1,] 1 3
[2,] 2 4
, , 2, 1, 1
[,1] [,2]
[1,] 5 7
[2,] 6 8
, , 1, 2, 1
[,1] [,2]
[1,] 9 11
[2,] 10 12
, , 2, 2, 1
[,1] [,2]
[1,] 13 15
[2,] 14 16
, , 1, 1, 2
[,1] [,2]
[1,] 17 19
[2,] 18 20
, , 2, 1, 2
[,1] [,2]
[1,] 21 23
[2,] 22 24
, , 1, 2, 2
[,1] [,2]
[1,] 25 27
[2,] 26 28
, , 2, 2, 2
[,1] [,2]
[1,] 29 31
[2,] 30 32
可見 R 語言在顯示高維陣列內容時, 是把它拆解到矩陣 (就是第一與第二維組成的二維陣列) 當作最小的單位, 然後從第三維起依序顯示 "每一張表".
2. 呼叫 dim() 函數設定維度將向量或列表變成陣列 :
R 語言中向量 (vector) 是一群有序資料, 看起來像是一維, 但在 R 裡面是沒有維度的資料結構, 用 dim() 檢查會得到 NULL. 與建立矩陣一樣, 若呼叫 dim() 為向量指定大於 2 的維度, 則此無維度的向量將變成有維度的陣列結構, 例如 :
> v <- 1:24 #建立 24 個元素的向量
> dim(v) #向量是無維度的資料結構 (NULL)
NULL
> dim(v) <- c(4,3,2) #指定維度給向量會使其變成矩陣 (2 維) 或向量 (大於 2 維)
> v
, , 1
[,1] [,2] [,3]
[1,] 1 5 9
[2,] 2 6 10
[3,] 3 7 11
[4,] 4 8 12
, , 2
[,1] [,2] [,3]
[1,] 13 17 21
[2,] 14 18 22
[3,] 15 19 23
[4,] 16 20 24
> class(v) #變成陣列了
[1] "array"
> dim(v) #查詢陣列維度是 4*3*2
[1] 4 3 2
二. 存取陣列元素 :
存取陣列元素的方式與矩陣一樣, 也是用索引, 只是索引比較多而已.
> A <- array(1:24, c(4,3,2))
> A
, , 1
[,1] [,2] [,3]
[1,] 1 5 9
[2,] 2 6 10
[3,] 3 7 11
[4,] 4 8 12
, , 2
[,1] [,2] [,3]
[1,] 13 17 21
[2,] 14 18 22
[3,] 15 19 23
[4,] 16 20 24
> A[1,1,1]
[1] 1
> A[1,3,1]
[1] 9
> A[1,3,2]
[1] 21
> A[1,1,]
[1] 1 13
> A[1,,]
[,1] [,2]
[1,] 1 13
[2,] 5 17
[3,] 9 21
> A[,1,]
[,1] [,2]
[1,] 1 13
[2,] 2 14
[3,] 3 15
[4,] 4 16
> A[,,1]
[,1] [,2] [,3]
[1,] 1 5 9
[2,] 2 6 10
[3,] 3 7 11
[4,] 4 8 12
注意, 這些取出來的物件都降階變成了二維的矩陣了, 可用 class() 檢驗. 如果取出來的元件想保留 array 架構, 不要降階成矩陣, 可以在索引最後面加上 drop=FALSE (預設是 TRUE), 例如 :
> A <- array(1:24, c(4,3,2))
> A[1,,] #只取第一維
[,1] [,2]
[1,] 1 13
[2,] 5 17
[3,] 9 21
> class(A[1,,]) #降階為 matrix
[1] "matrix"
> A[1,,,drop=FALSE] #不降階 (保留陣列結構)
, , 1
[,1] [,2] [,3]
[1,] 1 5 9
, , 2
[,1] [,2] [,3]
[1,] 13 17 21
> class(A[1,,,drop=FALSE]) #仍為 array 結構
[1] "array"
> identical(A[1,,], A[1,,,drop=FALSE]) #兩個是不同物件 (內容相同, 但結構不同)
[1] FALSE
上面是存取三維陣列內容時的降維情形, 如果取得的內容是二維, 則降階為矩陣; 若小於二維則為向量. 從多維陣列取得的內容如果大於二維, 則仍然是陣列結構, 例如 :
> A <- array(1:32, c(2,2,2,2,2))
> A
, , 1, 1, 1
[,1] [,2]
[1,] 1 3
[2,] 2 4
, , 2, 1, 1
[,1] [,2]
[1,] 5 7
[2,] 6 8
, , 1, 2, 1
[,1] [,2]
[1,] 9 11
[2,] 10 12
, , 2, 2, 1
[,1] [,2]
[1,] 13 15
[2,] 14 16
, , 1, 1, 2
[,1] [,2]
[1,] 17 19
[2,] 18 20
, , 2, 1, 2
[,1] [,2]
[1,] 21 23
[2,] 22 24
, , 1, 2, 2
[,1] [,2]
[1,] 25 27
[2,] 26 28
, , 2, 2, 2
[,1] [,2]
[1,] 29 31
[2,] 30 32
> A[,,,1,1] #取得子陣列
, , 1
[,1] [,2]
[1,] 1 3
[2,] 2 4
, , 2
[,1] [,2]
[1,] 5 7
[2,] 6 8
> class(A[,,,1,1]) #結構是陣列 (因為是三維)
[1] "array"
取得陣列內容時也可以使用負索引來排除不要的部分, 例如 :
> A <- array(1:24, c(4,3,2))
> A
, , 1
[,1] [,2] [,3]
[1,] 1 5 9
[2,] 2 6 10
[3,] 3 7 11
[4,] 4 8 12
, , 2
[,1] [,2] [,3]
[1,] 13 17 21
[2,] 14 18 22
[3,] 15 19 23
[4,] 16 20 24
> A[-3, c(1,3), 2] #第一維不要第三列, 第二維取第一與第三行, 第三維取第二張
[,1] [,2]
[1,] 13 21
[2,] 14 22
[3,] 16 24
修改陣列的內容只要直接將向量或矩陣指派給陣列的指定部分即可, 例如 :
> A <- array(1:24, c(4,3,2)) #建立陣列
> A
, , 1
[,1] [,2] [,3]
[1,] 1 5 9
[2,] 2 6 10
[3,] 3 7 11
[4,] 4 8 12
, , 2
[,1] [,2] [,3]
[1,] 13 17 21
[2,] 14 18 22
[3,] 15 19 23
[4,] 16 20 24
[,1] [,2]
[1,] 3 11
[2,] 4 12
> A[3:4,c(1,3),1] <- matrix(NA, nrow=2, ncol=2) #將矩陣指派給陣列局部
> A
, , 1
[,1] [,2] [,3]
[1,] 1 5 9
[2,] 2 6 10
[3,] NA 7 NA
[4,] NA 8 NA
, , 2
[,1] [,2] [,3]
[1,] 13 17 21
[2,] 14 18 22
[3,] 15 19 23
[4,] 16 20 24
三. 陣列常用函數 :
| 函數 | 說明 |
| array(data, dim, dimnames) | 建立維度為 dim 向量之陣列 |
| str(x) | 顯示物件結構與內容 |
| length(x) | 顯示陣列元素個數 |
| dim(x) | 顯示物件 (矩陣, 陣列, 資料框) 維度 |
| is.array(x) | 檢查是否為鎮ㄌㄧ類型 |
| as.array(x) | 將物件強制轉型為陣列陣類型 |
| identical(x, y) | 檢查兩個物件 x, y 是否為相同物件 |
2017年12月27日 星期三
糞金龜與聖甲蟲
今天跟同事談到以前我們鄉下常見的糞金龜, 通常都躲在牛糞堆裡努力做糞球, 他們都市孩子根本沒見過. 我去維基查了一下, 原來牠竟然就是埃及人崇拜的聖甲蟲哩! 因為糞金龜會製作圓滾滾的糞球, 就好像他們信仰的太陽神會做出圓圓的太陽, 糞金龜因此被神化, 參考 :
# https://zh.wikipedia.org/wiki/蜣螂
令我驚訝的是, 糞金龜是自然界最大力的生物, 牠們可以舉起自己體重 1141 倍的糞球! 而且他們是利用月光太陽光的偏振來導航, 將糞球推回家. 甚麼叫偏振呢? 參考 :
# https://zh.wikipedia.org/wiki/偏振
總之, 縱波 (例如聲波與地震波) 沒有偏振, 橫波 (例如電磁波) 才會有偏振現象. 電磁波中電場與磁場與波前進方向垂直, 而兩者又互相垂直 (正交). 如果電磁場都像下面這樣不偏不倚以正交方式前進的話就沒有偏振 :
如果電場與磁場會旋轉或轉向就叫做有偏振, 偏振的形式有多種, 有線偏振, 圓偏振, 或橢圓偏振, 端看旋轉方式在前進方向平面的投影形狀而定 :
我在 Youtube 找到兩部很有意思的糞金龜影片 :
# 糞金龜的真實面貌
# 聖甲蟲傳奇 【下課花路米 286】
原來雄的糞金龜有角 (三支), 而雌的沒有角. 而且製作與滾糞球的是雄糞金龜, 糞球做得大就容易求偶, 難怪牠們這麼努力!
參考 :
# 大自然的清道夫-糞金龜
# https://zh.wikipedia.org/wiki/蜣螂
令我驚訝的是, 糞金龜是自然界最大力的生物, 牠們可以舉起自己體重 1141 倍的糞球! 而且他們是利用月光太陽光的偏振來導航, 將糞球推回家. 甚麼叫偏振呢? 參考 :
# https://zh.wikipedia.org/wiki/偏振
總之, 縱波 (例如聲波與地震波) 沒有偏振, 橫波 (例如電磁波) 才會有偏振現象. 電磁波中電場與磁場與波前進方向垂直, 而兩者又互相垂直 (正交). 如果電磁場都像下面這樣不偏不倚以正交方式前進的話就沒有偏振 :
如果電場與磁場會旋轉或轉向就叫做有偏振, 偏振的形式有多種, 有線偏振, 圓偏振, 或橢圓偏振, 端看旋轉方式在前進方向平面的投影形狀而定 :
我在 Youtube 找到兩部很有意思的糞金龜影片 :
# 糞金龜的真實面貌
# 聖甲蟲傳奇 【下課花路米 286】
原來雄的糞金龜有角 (三支), 而雌的沒有角. 而且製作與滾糞球的是雄糞金龜, 糞球做得大就容易求偶, 難怪牠們這麼努力!
參考 :
# 大自然的清道夫-糞金龜
關於入聲調標註問題
老張寄來一份關於入聲調標註的文件, 要我評估可行與否, 因最近較忙無暇細看, 故先將其中網上資料部分記錄如下 :
# 【煨番薯】彭瑞珠原作
# 關於入聲字表的說明
# 入声字自动标注工具
另有一篇應該是湘雲的作品 "石牯情緣" docx 檔, 須以客語發音才能了解.
還有一篇中央大學客家語文研究所徐翠真的碩士論文 "四縣客家話入聲字研究", 有 200 頁之多, 要花一點時間來看.
語言學與網頁設計都好久沒摸了, 坦白說有點吃力.
對岸這個入聲字自動標註工具好用, 我把 "石牯情緣" 前三段貼上去 :
"時間過還遽,埋頭佇研究室打電腦,無感覺到,一日又會過忒咧。 探頭看向窗門外背,日頭偏西,王椰 樹搖啊搖,像同捱揲手,喊捱毋好恁拼,好放下手頭任做都做毋忒个事情,出去外背行行啊仔。乜好,恁久無運動咧,這幾日都落水,落到人、鳥仔摎蟲仔通棚都囥嶐孔樣少行出來,趕今晡日下晝天時恁好,來出去曬一下日頭,行行看看仔乜好 。
學校後山有一條路做得直直蹶到八卦山山頂,一路係上崎,一路係梯碫,爬到山崠頂,没汗流脈落, 也乜氣賒激激。毋過來到崗頂,鼻到花香草香,看到山下一大片恁闊 个風景,先先个腳軟身痶也無算麼介咧。
來到飛機公園,一台老飛行機像雞嫲孵卵 樣跍佇草坪頂,仰頭看 向天頂,堵好兩台訓練用个現代飛行機飛等過,這隻「老雞嫲」也像緬懷當年樣仔,還想做過一飆沖天,飛到高高个雲頂看遍世界,毋過這下煞分大索綯核核鎖到地泥頂,樣般想飛也飛毋起來咧。"
按第一個按鈕 (標準模式) 下方就出現標註結果, 入聲字底下會有紅色底線 :
現在問題是入聲字雖然標出來了, 但卻無法連結發音, 紅色的底線如果能加上超連結就完美了. 老張要我評估能否將標註的結果加工一下, 可連結到萌典去聽發音, 如【煨番薯】所示.
觀察此標註工具網頁原始碼, 輸入框是一個 id 為 mf_ipt 的 textarea 元件 :
<textarea name=mf_ipt id=mf_ipt cols=50 rows=10></textarea>
底下有三個按鈕, 按下去會分別呼叫 Javascript 函數 MarkWords(0), MarkWords(1), 以及 ResetWords() :
<div class="rsz_btn"><button onclick="MarkWords(0);">查询入声字(标准检查模式)</button></div>
<div class="rsz_btn"><button onclick="MarkWords(1);">查询入声字(使用平水韵检查模式)</button></div>
<div class="rsz_btn"><button onclick="ResetWords();">清除</button></div>
底下則是 id 為 rsz_output 的輸出區塊 :
<div class="rsz_opt"><div id="rsz_output"></div>
呼叫 MarkWords(0) 時此函數會讀取輸入框 mf_ipt 之內容, 如果有輸入內容就呼叫 CheckRSZ() 函數, 它會依據傳入的第一參數 pi_iType 是 0 (標準) 或 1 (平水韻) 去搜尋存放在變數 g_strRSZ (標準) 或 g_strPS (平水韻) 中的入聲字表來辨認是否為入聲字, 如果是入聲字就給這個字加上底線與紅色樣式, 加工後的字串放在變數 t_strOpt 裡 :
然後再用 innerHTML 將此標註結果字串 t_strOpt 寫入輸出區塊 rsz_output 內 :
初步研究我覺得應該可行.
至於第二個按鈕的平水韻, 我查了維基, 原來是宋代之後的詩韻系統 :
# https://zh.wikipedia.org/wiki/平水韻
平水之名據說源自金朝聲韻家劉淵所作 "壬子新刊禮部韻略", 劉淵為山西平水人因而得名; 又有一說為出自金國人王文鬱所作 "新刊韻略", 尚無定論.
2018-08-17 補充 :
老張邀我今晚登門一敘, 討論如何將入聲調標註後連結萌典, 因 9 月初要用, 近日集中時間解決此問題.
2018-08-20 補充 :
這個功能其實很簡單, 只要將 MarkWords() 中的變數 t_strOpt 改成如下即可 :
t_strOpt += "<a href='https://www.moedict.tw/:" + t_strChar +
"' target='checked_tone'>" + t_strChar + "</a>";
修改後的網頁暫時放在下列免費伺服器測試 :
# https://tony1966.000webhostapp.com/test/checked_tone.htm
# 【煨番薯】彭瑞珠原作
# 關於入聲字表的說明
# 入声字自动标注工具
另有一篇應該是湘雲的作品 "石牯情緣" docx 檔, 須以客語發音才能了解.
還有一篇中央大學客家語文研究所徐翠真的碩士論文 "四縣客家話入聲字研究", 有 200 頁之多, 要花一點時間來看.
語言學與網頁設計都好久沒摸了, 坦白說有點吃力.
對岸這個入聲字自動標註工具好用, 我把 "石牯情緣" 前三段貼上去 :
"時間過還遽,埋頭佇研究室打電腦,無感覺到,一日又會過忒咧。 探頭看向窗門外背,日頭偏西,王椰 樹搖啊搖,像同捱揲手,喊捱毋好恁拼,好放下手頭任做都做毋忒个事情,出去外背行行啊仔。乜好,恁久無運動咧,這幾日都落水,落到人、鳥仔摎蟲仔通棚都囥嶐孔樣少行出來,趕今晡日下晝天時恁好,來出去曬一下日頭,行行看看仔乜好 。
學校後山有一條路做得直直蹶到八卦山山頂,一路係上崎,一路係梯碫,爬到山崠頂,没汗流脈落, 也乜氣賒激激。毋過來到崗頂,鼻到花香草香,看到山下一大片恁闊 个風景,先先个腳軟身痶也無算麼介咧。
來到飛機公園,一台老飛行機像雞嫲孵卵 樣跍佇草坪頂,仰頭看 向天頂,堵好兩台訓練用个現代飛行機飛等過,這隻「老雞嫲」也像緬懷當年樣仔,還想做過一飆沖天,飛到高高个雲頂看遍世界,毋過這下煞分大索綯核核鎖到地泥頂,樣般想飛也飛毋起來咧。"
按第一個按鈕 (標準模式) 下方就出現標註結果, 入聲字底下會有紅色底線 :
入声字自动标注 输出结果:
時間過還遽,埋頭佇研究室打電腦,無感覺到,一日又會過忒咧。 探頭看向窗門外背,日頭偏西,王椰 樹搖啊搖,像同捱揲手,喊捱毋好恁拼,好放下手頭任做都做毋忒个事情,出去外背行行啊仔。乜好,恁久無運動咧,這幾日都落水,落到人、鳥仔摎蟲仔通棚都囥嶐孔樣少行出來,趕今晡日下晝天時恁好,來出去曬一下日頭,行行看看仔乜好 。
學校後山有一條路做得直直蹶到八卦山山頂,一路係上崎,一路係梯碫,爬到山崠頂,没汗流脈落, 也乜氣賒激激。毋過來到崗頂,鼻到花香草香,看到山下一大片恁闊 个風景,先先个腳軟身痶也無算麼介咧。
來到飛機公園,一台老飛行機像雞嫲孵卵 樣跍佇草坪頂,仰頭看 向天頂,堵好兩台訓練用个現代飛行機飛等過,這隻「老雞嫲」也像緬懷當年樣仔,還想做過一飆沖天,飛到高高个雲頂看遍世界,毋過這下煞分大索綯核核鎖到地泥頂,樣般想飛也飛毋起來咧。
學校後山有一條路做得直直蹶到八卦山山頂,一路係上崎,一路係梯碫,爬到山崠頂,没汗流脈落, 也乜氣賒激激。毋過來到崗頂,鼻到花香草香,看到山下一大片恁闊 个風景,先先个腳軟身痶也無算麼介咧。
來到飛機公園,一台老飛行機像雞嫲孵卵 樣跍佇草坪頂,仰頭看 向天頂,堵好兩台訓練用个現代飛行機飛等過,這隻「老雞嫲」也像緬懷當年樣仔,還想做過一飆沖天,飛到高高个雲頂看遍世界,毋過這下煞分大索綯核核鎖到地泥頂,樣般想飛也飛毋起來咧。
現在問題是入聲字雖然標出來了, 但卻無法連結發音, 紅色的底線如果能加上超連結就完美了. 老張要我評估能否將標註的結果加工一下, 可連結到萌典去聽發音, 如【煨番薯】所示.
觀察此標註工具網頁原始碼, 輸入框是一個 id 為 mf_ipt 的 textarea 元件 :
<textarea name=mf_ipt id=mf_ipt cols=50 rows=10></textarea>
底下有三個按鈕, 按下去會分別呼叫 Javascript 函數 MarkWords(0), MarkWords(1), 以及 ResetWords() :
<div class="rsz_btn"><button onclick="MarkWords(0);">查询入声字(标准检查模式)</button></div>
<div class="rsz_btn"><button onclick="MarkWords(1);">查询入声字(使用平水韵检查模式)</button></div>
<div class="rsz_btn"><button onclick="ResetWords();">清除</button></div>
底下則是 id 為 rsz_output 的輸出區塊 :
<div class="rsz_opt"><div id="rsz_output"></div>
呼叫 MarkWords(0) 時此函數會讀取輸入框 mf_ipt 之內容, 如果有輸入內容就呼叫 CheckRSZ() 函數, 它會依據傳入的第一參數 pi_iType 是 0 (標準) 或 1 (平水韻) 去搜尋存放在變數 g_strRSZ (標準) 或 g_strPS (平水韻) 中的入聲字表來辨認是否為入聲字, 如果是入聲字就給這個字加上底線與紅色樣式, 加工後的字串放在變數 t_strOpt 裡 :
<div class=result>"+t_strOpt+"</div>
document.getElementById("rsz_output").innerHTML = "<div class=output><div class=tips><strong>入声字自动标注 输出结果:</strong></div><div class=result>"+t_strOpt+"</div><div class=for_print>入声字自动标注工具: <span class=b>https://www.xiaohui.com/rsz</span></div></div><div class=print><a href='#' onclick='OnPrint();'>打印标注结果</a></div>";
至於第二個按鈕的平水韻, 我查了維基, 原來是宋代之後的詩韻系統 :
# https://zh.wikipedia.org/wiki/平水韻
平水之名據說源自金朝聲韻家劉淵所作 "壬子新刊禮部韻略", 劉淵為山西平水人因而得名; 又有一說為出自金國人王文鬱所作 "新刊韻略", 尚無定論.
2018-08-17 補充 :
老張邀我今晚登門一敘, 討論如何將入聲調標註後連結萌典, 因 9 月初要用, 近日集中時間解決此問題.
2018-08-20 補充 :
這個功能其實很簡單, 只要將 MarkWords() 中的變數 t_strOpt 改成如下即可 :
t_strOpt += "<a href='https://www.moedict.tw/:" + t_strChar +
"' target='checked_tone'>" + t_strChar + "</a>";
修改後的網頁暫時放在下列免費伺服器測試 :
# https://tony1966.000webhostapp.com/test/checked_tone.htm
訂閱:
文章
(
Atom
)



















