techrmc’s blog

ICT大好きな中小企業診断士のブログです

Arduinoを用いた自作のパルスオキシメータ 〜技術でコロナを打倒しよう〜


コロナ禍真っ只中の時、パルスオキシメータがなかなか手に入らず、それなら自分で作ってしまおう、ということで製作したパルスオキシメータを紹介します。
マイコンArduino Uno R3を使用し、Arudinoシールド用ユニバーサル基板に血中酸素飽和度センサとLCDを搭載しました。

パルスオキシメータシールド回路図

パルスオキシメータシールドの回路図は下図の通りです。

パルスオキシメータシールド回路図

心拍・血中酸素飽和度のセンサは、心拍・酸素飽和度モニタモジュール MAXREFDES117#を利用しました。このモジュールのエンジンはMAX30102で、Arduino UnoからI2Cで制御します。また、このセンサは5Vで動作可能なため、Arduino Unoから供給される5V電源をそのまま直結しています。

LCDは、一般に広く用いられているSD1602HULBを利用しました。RV1はLCDコントラストを調整するための半固定抵抗、R2はLCDのバックライトを調整するための半固定抵抗です。

D1は動作状態を表示するためのLEDです。また、シールドをArduino Unoに載せるとArduino Unoのリセットボタンが押しづらくなってしまうため、シールド上にリセットボタンSW1を備えました。

Arudinoシールド用ユニバーサル基板に組み上げたパルスオキシメータシールドを下図に示します。

パルスオキシメータシールド

写真の中央部の水色枠に囲んだ部分がMAXREFDES117#で、ここに指を乗せて、心拍と血中酸素飽和度を測定します。

ソフトウェア

Arduino上のソフトウェアは、MAX30102のサンプルコードと、LCDへの文字表示プログラムを用いました。

測定の様子

Arduino Unoに搭載したパルスオキシメータシールドでの測定の様子を下図に示します。

測定の様子

HRが心拍数、SPO2が血中酸素飽和度です。

課題

心拍数はAppleWatchなど他の測定機器での測定結果とおおよそ同じ値を示しているかどうかで動作確認できました。しかし、血中酸素飽和度は他に測定機器がないため、キャリブレーションができず、表示されている値の正確さはわかりません。長い間息を止めると、若干、数値が下がるので、一応、動作はしているようですが、数値の精度は当てにならないというのが現在の課題です。機会があれば、医療機器として販売されているパルスオキシメータを入手して、キャリブレーションを試みたいと思います。

iCloud Drive不具合対応の記録 〜ありがとう、Appleサポート〜

いつの頃からか、極めて小さなサイズ(数バイト)のファイルであってもMacのFinderでiCloud Driveへファイルコピーできなかったり、Safariicloud.comにアクセスした際にiCloud Driveへアクセスできなかったり、iCloud Driveの不具合が発生しました。不具合が起き始めた時期や契機ははっきりしませんが、2023年1月に2代目のMacを購入し、1代目Macからファイルを移し替えた後に、不具合に気づきました。カレンダやリマインダーの端末間同期など、iCloud Drive以外のiCloud機能は正常に動作していて、iCloud Driveのみの不具合です。iPhoneiPadとのiCloud Driveの同期もうまく行かず、iCloud Driveのみが全ての端末でおかしくなりました。

ネット検索するとiCloud Driveの不具合に困っている人は多いようで、先達のノウハウを参考にしながら、iCloud Driveを止めてみたり、Apple IDからサインアウトしてみたり、色々と手を作りましたが、治りません。iCloud Driveの空きディスク容量が少ないためかと思い、iCloud Driveの契約容量を増やしてみましたが、一向に治りません。数日間トライ&エラーしてみた挙句、最終手段でAppleのサポートを頼りました。

以下は、このトラブルシューティングAppleサポートとのやり取りの記録です。

2月4日チャット相談

Appleサポートのホームページからテキストチャットで相談。もちろん日本語での相談です。サポートの方は名前や日本語のテキストの雰囲気から外国人のようですが、親切な対応でした。不具合の状況をお伝えしたりして、40分くらいチャットでやり取りしましたが、サポートの方も原因がわからず、電話で相談することになりました。

2月4日電話相談

チャットでこちらの電話番号をお伝えしたところ、すぐにAppleサポートから電話がかかってきました。この日は、電話で不具合の状況をお伝えし、Macの画面をサポートの方と画面共有しながら設定など色々確認していただき、何枚か設定状態の画面キャプチャを撮って頂きました。これらの情報をエンジニアに送って検討してもらうとのことで、次回の電話相談のアポを取ったところでこの日は終了でした。電話相談のサポートの方は日本人のようです。言葉遣いなど非常に丁寧な対応でびっくりしました。さすがAppleと思った次第です。

2月11日電話相談

前回と同じAppleサポートの担当の方から、約束の時間に電話がかかってきました。エンジニアからの回答は「アカウントに問題がある」とのことで、それ以上の詳しいことはAppleサポートの担当の方もわからないとのこと。「詳しく調査してみる。ただし、調査結果を伝えられる時期は不明。」とのことでした。当方は普段は本業で忙しく、Appleサポートの方と話をしている時間がないため、次に電話をかけてもらう曜日だけ決めてこの日は終了でした。

3月18日電話相談

前回から1ヶ月経ったところで、前回と同じAppleアポートの担当の方から電話連絡がありました。「iCloud DriveをApple側でリセットする」とのことです。「iCloud Driveをリセットする際にiCloud Drive内のファイルが削除されても良いか」意向確認がありました。当方としては、とにかくiCloud Driveを直して欲しいので、もちろんファイル削除OKです。ただ、iCloud Drive以外のiCloud機能(カレンダやリマインダーなど)のデータが消えてしまうと不便この上ないので、iCloud Drive以外のデータには影響がないことは確認しました。この日は、3月21日までにiCloud Driveがリセットできたら3月21日に電話、3月21日までにはリセットできない時は4月1日に電話、という次回電話のアポで終了でした。

3月21日電話相談

前回と同じ担当者の方から「リセットはまだできていないが、事前にMacの設定変更が必要」という中間報告の電話です。iCloud Driveリセットの悪影響が出ないように、Macのシステム設定にあるicloudの設定項目のうち「Macストレージを最適化」をoffにするように、とのことでした。今回も、Appleサポートの方とMacの画面共有をしながら設定変更しました。

4月1日電話相談

今回も同じ担当者の方から電話です。「エンジニアがiCloud Driveを調整したので、今日は、問題が解消してされていることを確認する」とのことです。画面を共有しながら、icloud.comからiCoud Driveへアクセスしたり、Finderでicloud driveへファイルコピーしたり、iCloud Driveの不具合が解消されていることを、Appleと一緒に確認して一件落着でした。リセットで削除されると聞いていたファイルたちも削除されておらず、無事でした。(重要なファイルは他へ移しておいたので、削除されても困らないファイルたちではありますが。)

感想

iCloud Driveの不具合解消まで2ヶ月もかかってしまいましたが、無事に正常状態に戻って何よりです。電話対応してくれたフロントSEさんは、iCloud Driveサーバのログを調査したりシステム設定を触る権限は持っていないでしょうから、米国(?)にいるエンジニアの作業を待たざるを得ず、不具合解消に時間がかかるのは止むを得ません。兎にも角にも、今回対応してくれたフロントの担当者の方の丁寧な言葉遣いや真摯な対応は素晴らしいと思いました。Appleサポートの方、ありがとうございました!

 

【書評】現代病「集中できない」を知力に変える 読む力 最新スキル大全(著者:佐々木俊尚、東洋経済新報社)

「読むことで様々な知識・視点を身につけ、そこから概念を把握し、世界観を描いた上で、自分の血肉にする」ノウハウを整理した本です。

現代は大量の情報が溢れているので、まず読むべき本を選別することが重要です。インターネットの普及によって様々なメディアが出現しましたが、各メディアのタイプを意識して読まなければならないと説いています。主張に偏りのあるメディアは、特に注意が必要で、それを見抜くポイントを紹介しています。SNSのように特定のコミュニティに閉じたメディアでは主張の偏りが増幅しがちなので、発信者が信頼できる人物かどうかの見極めが肝心です。一般誌の新聞も、広く浅い知識を集めるには有用ですが、必ずしも公平とは限らないので要注意です。

ネット上で情報を収集するツールとしては、著者はRSSリーダTwitterをお勧めしています。RSSリーダは正直なところ「今さら?」と思いましたが、あちらこちらのサイトから記事がプッシュされてくるので、多様なサイトから広く情報収集するには有用かもしれません。また、Twitterに関しては、信頼できる専門家を見出し、その専門家をTwitterでフォローする。それによって、意図的に流される怪情報に振り回されることなく、専門的にも妥当な深い情報を獲得できる。こうした偏りのない情報獲得を提案しています。

また現代人は時間に追われ、膨大な記事をじっくり読む時間がなかなか持てません。そうした記事洪水への対策として、著者はpocketの活用を提案しています。ネットで面白そうな記事を見つけたらpocketにしまっておき、移動中などスキマ時間にじっくり読むべき記事を選別し、場合によってはメモアプリに永久保存する。そうした著者のテクが紹介されています。刺激を受けて、私も早速pocketを使い始めたところです。

本に関しては、著者は電子書籍をお勧めしています。個人的には、電子書籍は自由な書き込みができず、紙の本に比べて深く読み解くことができないように感じています。電子版かリアル版か、書籍の好みは個人差がありそうですが、NHKの「100分de名著」の活用やビジネス書の読み方など、なるほどね、というノウハウは参考になりました。

読み方以外にも、現代人の「集中できない」生活スタイルについても、対策を提案しています。無理に長時間集中しようとせず、短時間集中のマルチタスキングがお勧めだそうです。本書は、読む力にとどまらず、現代人のワーキングスタイルについて著者のノウハウが詰まった本です。

 

ESP-WROOM-02を用いた自作のWiFiドアセンサ

自作のWiFiドアセンサを紹介します。ドアセンサと名付けていますが、郵便箱に取り付けて、郵便箱の扉の開閉検知に利用しています。元々は、新聞や郵便物が投函されたか、頻繁に見に行くのが面倒だと感じて作りました。郵便箱の開閉を外出中でも把握できるので、結構、便利です。郵便箱の扉の開閉以外に、ドアの開閉を検知したり、工具が定位置から持ち出されたことを検知したり、様々な用途に使えます。

郵便箱

全体概要

扉の開閉はリードスイッチと磁石で検知しています。リードスイッチを入れるケースは、100円ショップで購入した防犯センサのケースを流用しました。磁石も防犯センサの部品の流用です。リードスイッチは、扉が閉まっているときは磁石によって接点が閉じてクローズド状態となり、一方、扉が開くと接点が離れてオープン状態となります。

検知回路の心臓部はESP-WROOM-02というマイコンを利用しました。このマイコンは1個当たり数百円程度と安価で、WiFiを内蔵しているので、IoT用途にはもってこいです。もちろん技適マークも付いているので安心です。

リードスイッチがクローズド状態の間は、ESP-WROOM-02を低消費電力のディープスリープモードにしておきます。そして、リードスイッチがオープン状態になると、ESP-WROOM-02が眠りから覚めて起動し、建物内のWiFiアクセスポイント経由でインターネット上のIFTTTへメッセージを送り、IFTTTからメールが送られます。

郵便箱は屋外に設置してありそのままでは検知回路が雨ざらしとなってしまうため、検知回路をウォールボックスに格納することで防水性を高めています。また、検知回路からリードスィッチまでの配線も、金魚店で購入したチューブに通すことで、雨水や虫から保護しています。

ウォールボックスに格納した検知回路

検知回路

次に、検知回路について説明します。KiCADで描いた回路図を下記に示します。電源3.3Vは、単三乾電池3本(すなわち4.5V)から3端子レギュレータで降圧・安定化していますが、回路図からは省略しています。

回路図

リードスイッチSW1は、扉が閉まっている間は磁石によって通電状態となっています。それによって、トランジスタQ1のベース電位がゼロに近づくため、コレクタからエミッタへの電流は流れず、ENとIO5はそれぞれR1とR2でプルアップされたHigh状態となっています。

ここで扉が開くとSW1がオープン状態となってQ1のベースがHighになり、コレクタからエミッタへ電流が流れ始めます。すると、IO5がLowになるとともに、同電位になっているコンデンサC1の両足がLowに落ち、それに伴い、R1でプルアップされていたENがHighからLowに落ちます。そして、C1がR1経由で蓄電されるにつれ、ENの電位はLowから徐々にHighに戻っていきます。ESP-WROOM-02は、ENがHighの時にアクティブとなるため、ENがHighとなるタイミングでディープスリープから復帰します。ディープスリープから復帰した後のプログラムの動作は、後ほどプログラムのパートで説明します。

再び扉が閉まると、SW1が閉じてコレクタからエミッタへの電流が停止し、R2でプルアップされたコレクタの電位がHighになります。この時C1は蓄電状態になっているためC1の両足には電位差があり、このままではEN側の電位が3.3V以上となってESP-WROOM-02の耐電圧を超えてしまいます。そこでダイオードD1によってC1に溜まった電荷を逃し、ENに3.3V以上の電圧がかかることを防ぎます。

ディープスリープからの復帰の肝となるのは、C1です。C1の容量が小さすぎると、ENが十分にLowに下がり切らないために復帰しません。実験したところ、0.1μFでは容量不足で、1μFで動作しました。

また、SW1が閉じている間、R3には常に電流が流れ続けるので、乾電池を長持ちさせるためにはできるだけ抵抗値を大きくして電流を絞りたいところです。R3の抵抗値を変えながら実験した結果、1MΩ以上では動作しなかったため、R3を470kΩとしました。計算上、470kΩとした場合、R3での消費電流は7μAとなります。ディープスリープ中のESP-WROOM-02の消費電流は20μAであるため、合計27μAが常に消費される計算です。実機で長時間運転していますが、単三アルカリ乾電池3本でざっくり1年程度は連続運用できています。

回路図のその他の部品についても説明します。

SW2は回路動作をプログラムで切り替えるためのスイッチです。プログラムのモード切り替えに使っています。

SW3はESP-WROOM-02をリセットするスイッチで、スイッチを入れてRESETをLOWに落とすと、ESP-WROOM-02がリセットされます。

D2は動作状態を可視化するためのLEDで、プログラムで点灯制御します。

回路図には描いていませんが、電源3.3Vは、3端子レギュレータによって単三乾電池3本から作り出しています。ESP-WROOM-02は、WiFi接続の際に200mA近くの電流を消費するため、3端子レギュレータの選定も重要です。ここでは、出力電流150mAのXC6202P332THを使いましたが、現在はディスコンとなっているので、今後は他の3端子レギュレータを探す必要があります。

ユニバーサル基板への実装結果は下記の写真の通りです。

SW2は手持ちの4連DIP-SWを使いましたが、4つのSWのうち1つのみ結線しています。

また、右側中ほどの2連ターミナルブロックにはリードスイッチまでのシールド線を接続します。

ユニバーサル基板に実装した検知回路

プログラム

ESP-WROOM-02に書き込むプログラムを説明します。ソフトウェア開発環境は、使い慣れているArduinoを用いました。

#include <ESP8266WiFi.h>                    // ESP8266用ライブラリ
extern "C" {
#include "user_interface.h"                 // ESP8266用の拡張IFライブラリ
}
#define PIN_SW 5                            // connect a reed SW to IO5
#define PIN_LED 4                           // connect an LED to IO4
#define PIN_TEST 12                         // connect a test SW to IO12, LOW at test-mode
#define SLEEP_P 0                           // sleep forever 
#define REED_ON 1                           // door closed
#define REED_OFF 0                          // door opened

// WiFi config
const char ssid[] = "xxxxxxxx";             // xxxxxxxxはWiFiアクセスポイントのSSIDに差し替え
const char pass[] = "xxxxxxxx";             // xxxxxxxxはWiFiアクセスポイントのパスワードに差し替え

// IFTTT
const char* host = "maker.ifttt.com";
const int httpPort = 80;
String url_message = "/trigger/xxxxxxxx/with/key/xxxxxxxx"; // xxxxxxxxは各自のイベント名及びアクセスキーに差し替え

// Use WiFiClient class to create TCP connections
WiFiClient client;

void setup(){
    int reed;                                       // status of the reed switch. REED_ON or REED_OFF
    int test;                                       // status of the test switch. LOW at test-mode
    int waiting=0;                                  // アクセスポイント接続待ち用カウンタ
    int i;
    pinMode(PIN_SW,INPUT);                          // INPUT_PULLUP did not work. Should be INPUT. 
    pinMode(PIN_TEST,INPUT_PULLUP);
    pinMode(PIN_LED,OUTPUT);
    delay(250);
    reed=digitalRead(PIN_SW);
    test=digitalRead(PIN_TEST);
    delay(250);

    if (test==LOW) {                                // test mode
        if (reed == REED_OFF) {                     // REED_OFF
            WiFi.mode(WIFI_STA);                    // STA mode
            WiFi.begin(ssid, pass);                 
            while(WiFi.status() != WL_CONNECTED){   // wait until WiFi connected
                delay(100);                         // wait 100msec
                waiting++;                          // counter increment
                if(waiting > 300) {                 // max waiting counter. approx.300*100 msec= 30sec
                    digitalWrite(PIN_LED,LOW);
                    for(i=0;i<5;i++) longLight();   // long alarm in case of WiFi connection error
                    sleep();
                }
                digitalWrite(PIN_LED,waiting%2);    // short interval lightning during connection
            }
            digitalWrite(PIN_LED,LOW);
            send2IFTTT();
        } else {                                    // REED_ON
            longLight();
        } 
        sleep();
    } else {                                        // not test mode
        if (reed == REED_OFF) {                     // REED_OFF
            WiFi.mode(WIFI_STA);                    // STA mode
            WiFi.begin(ssid, pass);                 
            while(WiFi.status() != WL_CONNECTED){   // wait until WiFi connected
                delay(100);                         // wait 100msec
                waiting++;                          // counter increment
                if(waiting > 300) {                 // max waiting counter. approx.300*100 msec= 30sec
                    sleep();
                }
            }
            send2IFTTT();
        }
        sleep();
    }  
}

void loop(){  // dummy
    sleep();
}

void longLight(){
    digitalWrite(PIN_LED,HIGH);
    delay(1000);  // light on for 1 sec
    digitalWrite(PIN_LED,LOW);
    delay(100);  // light off for 100 msec
}

void send2IFTTT(){  
    if (!client.connect(host, httpPort)) {
        return;
    }
    
    // This will send the request to the server
    client.print(String("GET ") + url_message 
                   + "?value1=postbox&value2=sense&value3=opened"
                   + " HTTP/1.1\r\n" 
                   + "Host: " + host + "\r\n" 
                   + "Connection: close\r\n\r\n");    
    unsigned long timeout = millis();
    while (client.available() == 0) {
        if (millis() - timeout > 5000) {
            client.stop();
            return;
        }
    }
  
    // Read all the lines of the reply from server
    while(client.available()){
        String line = client.readStringUntil('\r');
    }
}

void sleep(){
    ESP.deepSleep(SLEEP_P,WAKE_RF_DEFAULT);  // スリープモードへ移行する
    delay(1000);                             // スリープモードに入るのに時間を要すためダミーのdelayを入れる
}

動作モードはSW2で切り替えます。SW2を閉じてIO12をLowにするとテストモードになり、SW2を解放すると低消費電力モードになります。テストモードではLEDによって動作状況をモニタできます。一方、低消費電力モードではLEDを点灯させずに消費電力を抑えます。

扉が開いてリードスイッチSW1がオープン状態になると、検知回路で説明したように、ENが一旦HighからLowに落ち、C1の働きでENがLowからHighに戻る際にESP-WROOM-02がアクティブ状態になります。アクティブ状態になると、まずsetup()が走ります。setup()の冒頭はESP-WROOM-02の初期設定です。その後は、テストモードと低消費電力モードに分岐しますが、LED点灯制御が異なる以外は基本的に次の流れで処理が進みます。

  1. reedに読み取ったIO5(PIN_SW)をチェック。reed=1(すなわちIO5=High)の場合は、扉が開いていないのにノイズ等の影響でディープスリープから復帰した誤作動、あるいは扉が閉まった状態でリセットボタンSW3が押されたと判定して再度ディープスリープ。reed=0(すなわちIO5=Low)の場合は、扉が開いていることを示すので、2へ進む。
  2. WiFiアクセスポイントへ接続確立。
  3. 接続に成功したらsend2IFTTT()を呼ぶ。接続に失敗した場合はsleep()を呼んでディープスリープ。
  4. send2IFTTT()がIFTTTのサーバへHTTPのGETでメッセージを送信。
  5. sleep()を呼んでディープスリープ。

sleep()の中でESP.deepSleep()を呼んでいますが、この第一引数をゼロとすることで、永続的にディープスリープ状態に入ります。なお、通常のArduinoのプログラムでは、初期化時にsetup()が呼ばれた後、loop()が無限に呼ばれますが、上記のプログラムでは、setup()の中でディープスリープに入るため、loop()が呼ばれることはありません。
次に、検知回路からHTTPのGETメソッドで送られてくるメッセージを処理するIFTTTアプレットを説明します。

IFTTTアプレット

IFTTTのアプレットは、WebHookとe-mailで構成されます。検知回路がHTTP GETメソッドでWebHookをキックすると、e-mailが発火して自分のメールアドレスにメールが送られてくるという流れです。IFTTTの設定は、IFTTTにログインした状態で、IFTTTのサイト上で作業します。

IFTTTアプレットの構成

WebHookのイベント名(Event Name)には、プログラムの文字列定数url_messageに、アクセスキーとともに埋め込んだ文字列を設定します。(下記の設定画面ではイベント名は伏せています。)

WebHookの設定画面

e-mailでは、発火した時に自分宛に送付するメールのsubjectとメール本文を設定します。下記の設定画面では、メールのsubjectは「”イベント名”通知」と設定しています。また、メール本文は、イベント名、発火時刻、3つの文字列パラメータ(Value1、Value2、Value3、いずれもプログラムのsend2IFTTT()で指定しています)を埋める設定としています。

e-mailの設定画面

下記は、扉が開いた時に、自分のメールアドレスへ送られてきた実際のメール画面です。イベント名や、Vaue1, Value2, Value3には、プログラムの中で設定した文字列が埋め込まれています。

実際のメール画面

【書評】デジタル人材がいない中小企業のためのDX入門(著者:長尾一洋、KADOKAWA)

中小企業のDXについて、筆者の考え方を紹介しています。文中に特定の製品名が目につくと、その製品を売り込むための宣伝目的の書籍かと警戒してしまうのですが、中立的に筆者の考えが述べられていて、安心して読むことができました。

筆者によると、デジタルの本質は限界費用のゼロ化とのこと。本書の主張はこの点に集約されます。この特徴を活かせば、例えば営業を効率的に行うことが可能になります。ホームページ・SNS・動画配信・メルマガなどデジタル技術をうまく活用すれば、飛び込み営業やテレアポのようなアナログ的な営業手法に比べて見込み客との接点を広げることができるはずです。とは言え、玉石混淆のネットでは自社の情報発信が埋没しがちなのも事実です。デジタル技術で引き寄せた見込み客に対して、アナログ的な手法で背中を押す、デジタルとアナログのハイブリット的な営業が効果的でしょう。

このようにDXは従来の業務プロセスを変革し、生産性を飛躍的に向上させる可能性を秘めています。しかし一方で、中小企業にはDX推進人材の不足という問題があります。この点に関しては、大企業のようにDX人材を育成したり外部から確保するのではなく、社内の普通の社員がノーコードツールを使ってDXを実践すべきというのが筆者の主張です。ノーコードツールならプログラミングのスキルがなくとも業務システムや業務アプリを作成できるので、業務改善に意欲を持った当事者意識の高い人材に任せれば、業務プロセスのアジャイル的な改善につながります。

また、DXにはデータ入力が不可欠です。電帳法対応のためにも、効率的なデータ入力が必要な時代となりました。この点に関して筆者は、一人一人の社員が各自でデータを入力するような業務プロセスへの変革を勧めています。確かに、特定の社員だけにDX化の負荷が集中するようでは、DX化に反発されることもあるでしょうし、草の根的に全員がワンチームでDX推進した方が分散処理による高速化が図れます。

本書では、テレワークを成功させるための秘訣や、テレワークによって可能となった外部人材の活用についても解説しており、人材不足に悩む中小企業に役立つ内容となっています。

【書評】Pythonによるあたらしいデータ分析の教科書第2版(著者:寺田学ほか、翔泳社)

Pythonでのデータ分析の仕方を解説した初学者向けの解説書です。Pythonの実行環境は、venv仮想環境上のJupyterLabを用いています。データ分析の裏にある理論はごく簡単に触れる程度にとどめられ、実施例が豊富に説明されています。データ分析の理論を学びたい人にはもの足らないかもしれませんが、難解な理論より具体的な実施例を学びたい人には最適です。

利用している主なツール類は、

  • Numpy
  • pandas
  • Matplotlib
  • scikit-learn
  • Requests
  • Beautiful Soup 4
  • MeCab

です。

データ分析の基本として、分類、回帰、クラスタリングなど、主だったデータ分析手法が紹介されています。

応用例としては、Webページからのデータ収集(スクレイピング)、TF-IDFやポジ・ネガ判定といった自然言語処理機械学習による画像分類も解説されています。

iPhone・iPadなどIOSデバイスのバックアップをMac内蔵ディスクから外付けディスクへ移動

iPhoneiPadなどのIOSバイスMacでバックアップすると、結構大きなサイズでMacのディスク容量を消費します。内蔵ディスクが一杯になってきたときに、Windowsマシンのように大容量の内蔵ディスクに換装できれば良いのですが、Macの内蔵ディスクは換装することができません。

そこで、IOSバイスのバックアップファイルを外付けHDDに移して、内蔵ディスクの空き容量を増やしてみました。IOSバイスのバックアップの際に、外付けHDDを必ず接続しなければならなくなりますが、内蔵ディスクの空きが増えて、快適になりました。

バックアップファイルの置き場所

IOSバイスのバックアップファイルは、デフォルト状態では、次の場所にあります。

/Users/ユーザ名/Library/Application Support/MobileSync/Backup

通常のFinder操作では上記フォルダは隠されているので、Finderメニューの”移動”から”フォルダへ移動”を選択し、/Users/ユーザ名/Library/Application Support/MobileSync/Backupを入力します。ユーザ名の部分は、Macのログイン名に差し替えてください。

すると、内蔵ディスクに格納されているIOSバイスのバックアップファイルが表示されます。

バックアップファイルの新しい置き場所

外付けHDDを接続し、新しい置き場所となるBackupフォルダを作成します。ここからは、外付けHDDのトップ直下にBackupフォルダを作成したとして説明します。

バックアップファイルを新しい置き場所へコピー

/Users/ユーザ名/Library/Application Support/MobileSync/Backupの中身を、外付けHDDのBackupフォルダへ丸ごとコピーします。

安全のため古いバックアップファイルを適当な場所へ移動

作業ミスでバックアップファイルを壊してしまった場合の復旧用に、古いBackupフォルダ(つまり/Users/ユーザ名/Library/Application Support/MobileSync/Backup)を適当な場所(デスクトップ等)へ移動しておきます。この時点で/Users/ユーザ名/Library/Application Support/MobileSyncは、Backupフォルダが削除された状態になります。

新しい置き場所へシンボリックリンクを張る

ターミナルで/Users/ユーザ名/Library/Application Support/MobileSyncへ移動し、MobileSyncフォルダの中にBackupという名前で、新しい置き場所へのシンボリックリンクを張ります。

ln -s /Volumes/ディスク名/Backup ./Backup

ディスク名の部分は、外付けHDDの名前に置き換えてください。

シンボリックリンクを張る際に、”permissionがない”というようなエラーが表示される場合は、”システム設定”→”プライバシーとセキュリティ”→”フルディスクアクセス”を開いて、”ターミナル”のフルディスクアクセスが許可されているか(トグルスイッチがONになっているか)確認してください。

ターミナルのフルディスクアクセスが許可されているかを確認

動作確認

IOSバイスを接続して、Finderで外付けHDDにバックアップが正常にできるか、確認します。

問題なくバックアップが動作していれば、適当な場所へ退避させておいた旧バックアップファイルを削除します。

 

以上で作業完了です。