spresense LTE Cat-M1で省電力通信で試したこと

# はじめに
LTE-M通信では省電力のためPSMとeDRXという機能があるということで実際に調べてみました
まず送信や受信をしないときにモデムの電源を切れば良いのではと思いますが以下のような理由により推奨されていません

> **LTEは、IoT通信モジュールの電源を頻繁にオン・オフするようには設計されていません。モジュールの観点からは、オンとオフの切り替えプロセスは非常に迅速に行われますが、ネットワークの観点からは、信号メッセージが大幅に増加し、セルラーネットワークに大きな負担がかかります。** 
　-ソラコム デバイス実装ガイドライン より引用
https://soracom.jp/files/device_guideline.pdf

そこで　**eDRX**（Extended Discontinuous Reception）や　**PSM**（Power Saving Mode）といった省電力ネットワーク機能が用意されています

> **eDRX は、基地局を探索する時間間隔を延ばす機能です。また、PSM は、基地局の探索を一定時間停止する機能です。**
[ソラコムユーザードキュメント](https://users.soracom.io/ja-jp/docs/air/subscriptions/#lte-catm1-%e3%81%ae%e6%8e%a5%e7%b6%9a%e5%8f%af%e5%90%a6%e3%81%ab%e3%81%a4%e3%81%84%e3%81%a6:~:text=eDRX%20%E3%81%AF%E3%80%81%E5%9F%BA%E5%9C%B0%E5%B1%80%E3%82%92%E6%8E%A2%E7%B4%A2%E3%81%99%E3%82%8B%E6%99%82%E9%96%93%E9%96%93%E9%9A%94%E3%82%92%E5%BB%B6%E3%81%B0%E3%81%99%E6%A9%9F%E8%83%BD%E3%81%A7%E3%81%99%E3%80%82%E3%81%BE%E3%81%9F%E3%80%81PSM%20%E3%81%AF%E3%80%81%E5%9F%BA%E5%9C%B0%E5%B1%80%E3%81%AE%E6%8E%A2%E7%B4%A2%E3%82%92%E4%B8%80%E5%AE%9A%E6%99%82%E9%96%93%E5%81%9C%E6%AD%A2%E3%81%99%E3%82%8B%E6%A9%9F%E8%83%BD%E3%81%A7%E3%81%99%E3%80%82) より

>[eDRX / PSM に向いているユースケースについて](https://users.soracom.io/ja-jp/docs/air/subscriptions/#lte-catm1-%e3%81%ae%e6%8e%a5%e7%b6%9a%e5%8f%af%e5%90%a6%e3%81%ab%e3%81%a4%e3%81%84%e3%81%a6:~:text=eDRX%20/%20PSM%20%E3%81%AB%E5%90%91%E3%81%84%E3%81%A6%E3%81%84%E3%82%8B%E3%83%A6%E3%83%BC%E3%82%B9%E3%82%B1%E3%83%BC%E3%82%B9%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6)
eDRX のみ	サーバーからデバイスに向かう通信を、大きな遅延なく受信する。
PSM のみ	サーバーからデバイスに向かう通信は存在しない。

センサーデータをアップロードするならPSM、デバイスを外部から
操作したいならeDRXが向いているということらしい




[spresen sedevelopment-guides](https://developer.sony.com/spresense/development-guides/sdk_developer_guide_ja.html#_%E3%83%A2%E3%83%87%E3%83%A0%E3%82%92%E7%9C%81%E9%9B%BB%E5%8A%9B%E8%A8%AD%E5%AE%9A%E3%81%AB%E3%81%99%E3%82%8B)の波形をみるとイメージしやすい
ピークになっている時のみ受信可能でそれ以外の待機時は消費電流を抑えている



# 実験
## 使用機材
・Spresense メインボード
・Spresense LTE 拡張ボード（オンボードアンテナモデルCXD5602PWBLM1）
https://developer.sony.com/ja/spresense/specifications
・soracom sim(plan-D ドコモ）
・Power Profiler Kit II (PPK2) 電流計測用
https://www.nordicsemi.jp/tools/ppk2/
PPK2のVOUTをLTE 拡張ボードのMAINPOWERピンに繋いで５V入力

## 送信仕様
・CPUClockをデフォルトは156MHzのところを8Mhzまで下げる
・soracomの Unified Endpoint にUDPで送信
・soracomにはバイナリーパーサーを使ってバイト数を減らせる方法もありますが、
　今回はjson形式の文字列をそのまま送ります
・送信し終わったらudp.stop()して300秒（5分）待機し
　電源投入から3回目の送信が終わるまで(3回送信）の消費電力と待機中の平均消費電流を計測


## スケッチ
参考記事
https://qiita.com/nara256/items/7cd69918f583245e3b5a

```cpp:spresenseLowpowerSend.ino
#include <LTE.h>
#include <LowPower.h>
#include <EEPROM.h>
#include <lte/lte_api.h>  
#define APP_LTE_APN   "soracom.io"      // replace your APN
#define APP_LTE_USER_NAME "sora"     // replace with your username
#define APP_LTE_PASSWORD  "sora" // replace with your password
#define APP_LTE_IP_TYPE (LTE_NET_IPTYPE_V4V6) // IP : IPv4v6
#define APP_LTE_AUTH_TYPE (LTE_NET_AUTHTYPE_CHAP) // Authentication : CHAP
#define APP_LTE_RAT (LTE_NET_RAT_CATM) // RAT : LTE-M (LTE Cat-M1)


// Soracom  の接続先情報
const char* server = "uni.soracom.io"; // Soracomのエンドポイント
const int port = 23080;                // Soracom のポート番号
char count ;
// LTEオブジェクト
LTE lteAccess;
LTE lte;
LTEUDP udp;


int setup_edrx() {
  //eDRXの設定を記述する
  //設定値は https://developer.sony.com/spresense/spresense-api-references-sdk/structlte__edrx__setting.html を参照。
  lte_edrx_setting  edrx_setting;
  edrx_setting.enable = false;              // eDRXを有効にする
  edrx_setting.act_type = LTE_EDRX_ACTTYPE_WBS1; // LTE-Mを使用する場合は LTE_EDRX_ACTTYPE_WBS1 を設定しておく
  edrx_setting.edrx_cycle = LTE_EDRX_CYC_6144;  // eDRXサイクルを 61.44 sec に設定する
  edrx_setting.ptw_val = LTE_EDRX_PTW_256 ;       // PTWを 2.56sec に設定する

  int ret = lte_set_edrx_sync(&edrx_setting);    // eDRX を設定する
  Serial.print("lte_set_edrx_sync result=");  Serial.println(ret);
  return ret;
}

int get_edrx() {
  lte_edrx_setting edrx_setting;
  int ret= lte_get_current_edrx_sync(&edrx_setting);
  Serial.print("lte_get_edrx_sync result=");  Serial.println(ret);
  printf("eDRX Active Type: %d\n", edrx_setting.act_type);
  printf("eDRX Enabled: %s\n", edrx_setting.enable ? "Yes" : "No");

  if (edrx_setting.enable && edrx_setting.act_type != LTE_EDRX_ACTTYPE_NOTUSE) {
      printf("eDRX Cycle: %d\n", edrx_setting.edrx_cycle);
      printf("Paging Time Window: %d\n", edrx_setting.ptw_val);
  } else {
      printf("eDRX is not active or not used.\n");
  }
  return ret;
}

int setup_psm() {
  //psmの設定を記述する
  //設定値は https://developer.sony.com/spresense/spresense-api-references-sdk/structlte__psm__timeval.html を参照。
  lte_psm_setting psm_setting;
  lte_psm_timeval req_active_time;
  lte_psm_timeval ext_periodic_tau_time;
  psm_setting.enable = false;
  psm_setting.req_active_time.unit = LTE_PSM_T3324_UNIT_2SEC;  // 2s
  psm_setting.req_active_time.time_val = 1;                   // 2*1=2s
  psm_setting.ext_periodic_tau_time.unit = LTE_PSM_T3412_UNIT_30SEC; // 30s
  psm_setting.ext_periodic_tau_time.time_val = 2;                  // 30*2=60s
  int ret = lte_set_psm_sync(&psm_setting);    // psm を設定する
  Serial.print("lte_set_psm_sync result=");  Serial.println(ret);
  return ret;
}

int get_psm() {
  lte_psm_setting psm_setting;
  lte_psm_timeval req_active_time;
  lte_psm_timeval ext_periodic_tau_time;
  int ret= lte_get_current_psm_sync(&psm_setting);
  Serial.print("lte_get_psm_sync result=");  Serial.println(ret);
  printf("PSM Enabled: %s\n", psm_setting.enable ? "Yes" : "No");
  printf("Requested Active Time(T3324):\n");
  printf("  Unit: %d\n", psm_setting.req_active_time.unit);
  printf("  Time Value: %d\n", psm_setting.req_active_time.time_val);
  printf("Extended Periodic TAU Time(T3412):\n");
  printf("  Unit: %d\n", psm_setting.ext_periodic_tau_time.unit);
  printf("  Time Value: %d\n", psm_setting.ext_periodic_tau_time.time_val);
  return ret;
}

void setup() {
  char apn[LTE_NET_APN_MAXLEN] = APP_LTE_APN;
  LTENetworkAuthType authtype = APP_LTE_AUTH_TYPE;
  char user_name[LTE_NET_USER_MAXLEN] = APP_LTE_USER_NAME;
  char password[LTE_NET_PASSWORD_MAXLEN] = APP_LTE_PASSWORD;

  Serial.begin(115200);
  LowPower.begin();
  //Clockを下げる　https://developer.sony.com/spresense/spresense-api-references-arduino/group__lowpower.html#gaadd892046ae072f2a4024f2fe9bbc601
  LowPower.clockMode(CLOCK_MODE_8MHz);

  Serial.println("Starting Soracom UDP JSON example...");
    // LTE接続の初期化
      while (true) {
        /* Power on the modem and Enable the radio function. */
        if (lteAccess.begin() != LTE_SEARCHING) {
          Serial.println("Could not transition to LTE_SEARCHING.");
          Serial.println("Please check the status of the LTE board.");
          for (;;) {
            sleep(1);
          }
        }
        //セッションの無通信監視タイマーの設定
        setup_edrx(); 
        setup_psm();

        if (lteAccess.attach(APP_LTE_RAT,
                            apn,
                            user_name,
                            password,
                            authtype,
                            APP_LTE_IP_TYPE) == LTE_READY) {
          Serial.println("attach succeeded.");
          // タイマーの設定の確認
          get_psm();
          get_edrx();
          break;
        }

        Serial.println("An error has occurred. Shutdown and retry the network attach process after 1 second.");
        lteAccess.shutdown();
        sleep(1);
      }
  
}

void loop() {
  // UDP通信の準備
  if (!udp.begin(port)) { 
    Serial.println("Failed to start UDP client!");
    delay(1000);
    return;
  }

  // uptime を計算 (秒単位)
  unsigned long uptime = millis() / 1000;
  count = EEPROM.read(0);
  // JSON形式のメッセージを作成
  char jsonMessage[128];
  snprintf(jsonMessage, sizeof(jsonMessage), "{ \"uptime\": %lu, \"count\": %d }", uptime, count);

  // Soracom  UDPでデータを送信
  udp.beginPacket(server, port);
  udp.write(jsonMessage, strlen(jsonMessage));
  if (udp.endPacket()) {
    Serial.printf("JSON message sent: %s\n", jsonMessage);
  } else {
    Serial.println("Failed to send JSON message.");
  }
  udp.stop();
  count++;
  EEPROM.write(0, count);
  // 次回送信まで待機

  delay(300*1000);
  // LowPower.sleep(300);

}

```

## delay　対　Lowpower.sleep　でどちらが省電力か？
・delay
![delay_nomal1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261581/1c9a3b0b-d71c-2079-873a-0458392348b5.png)
・Lowpower.sleep
![sleep_nomal1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261581/a2fb4051-c590-ffc0-be56-623a65e10e5b.png)

Lowpower.sleepの方が下がると予想していたが意外に差はなく
待機時平均電流は共に15～20mAの間だった
10分電気量計は10～12C（クーロン＝アンペア・秒）
以降のテストはdelayを使用

## PSMを設定
```
  psm_setting.enable = true;
  psm_setting.req_active_time.unit = LTE_PSM_T3324_UNIT_2SEC;  // 2s
  psm_setting.req_active_time.time_val = 1;                   // 2*1=2s
  psm_setting.ext_periodic_tau_time.unit = LTE_PSM_T3412_UNIT_30SEC; // 30s
  psm_setting.ext_periodic_tau_time.time_val = 2;                  // 30*2=60s
```


![delay_PSM1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261581/97ab814f-23c7-7540-ca07-226d5a271a96.png)

2秒のピークと60秒の待機がくりかえされている
平均の待機時電流は4.3mA 
10分電気量計は4.6C

## eDRXを設定
```
  edrx_setting.enable = true;              // eDRXを有効にする
  edrx_setting.act_type = LTE_EDRX_ACTTYPE_WBS1; // LTE-Mを使用する場合は LTE_EDRX_ACTTYPE_WBS1 を設定しておく
  edrx_setting.edrx_cycle = LTE_EDRX_CYC_6144;  // eDRXサイクルを 61.44 sec に設定する
  edrx_setting.ptw_val = LTE_EDRX_PTW_254 ;       // PTWを 2.54sec に設定する
```
![delay_eDrx1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261581/dec1716a-ae00-309f-c26c-0bbd0c3b8883.png)
61.44ｓ毎にピークが現れるはずですがはっきりとは分からず
平均の待機時電流は8.1mA 
10分電気量計は6.7C

## PSMとeDRXを両方設定
今回はなぜか同時設定するとPSMのみ有効になりeDRXは無効になりました
理由はわかりません

# 結果
PSMを使うことで約50%の省電力になった
ただし平均待機時電流4.3mAではバッテリー駆動のIoTデバイスまだまだ物足りないのでさらなる低消費電力化が必要
例えば[WioBG770A](https://soracom.jp/store/30926/)の場合PSMを使用すれば[待機時平均75μA](https://seeedjp.github.io/Wiki/Wio_BG770A/power-consumption.html)まで下げられるとのこと