0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

MachiKaniaのSTRDIMクラスを潮位表データを使って試す

Posted at

はじめに

河口や干潟で野鳥を観察する時間帯を決めるために鹿児島湾の潮位表データをWebで参照していました。そこでその気象庁が公表している潮位表データをPicoCalc版MachiKaniaで取得してプログラムを実行した日付のデータを表示できないかを試しました。インターネット経由のデータ取得はうまくできなかったのでテキストデータをファイル化し、そこからデータを取得して表示できたのでそれをまとめました。

検証環境

以下の環境でプログラムの作成と検証を行ないました。

  • macOS : Tahoe 26.0
  • PicoCalc : Raspberry Pi Pico 2 Wに交換してある
    -MachiKania : Phyllosoma 1.6.0

潮位表データ

気象庁は各地方の潮位データをホームページで公開しています。地方と地点を選択すると開いた日から二週間分が表形式で表示されます。この表の元になっているデータがテキストデータとして公開されています。テキストデータのフォーマットも公開されていてテキストデータを取得できればプログラムから読み出しが可能です。
テキストデータは一年分のデータが格納されていて、一行が一日分で136バイトのデータです。

取り出すデータ

プログラムを実行した日付を取得し、その日のデータから次のデータを取り出します。

取り出すデータ カラム バイト数
日付 73〜78 6
満潮時刻と潮位 81〜108 $28=(4+3)\times 4$
干潮時刻と潮位 109〜136 $28=(4+3)\times 4$

満潮と干潮の潮位データは時刻4バイト、潮位3バイトが4件分がまとまっています。

プログラム

今回のプログラムはプログラム実行日時から一週間分の年月日、地点記号、満潮時刻・潮位、干潮時刻・潮位の文字列データをSDカードに保存された潮位表データファイルから読み取り、STRDIMクラスを使った作った文字列配列に格納して表示するようにしました。

データファイルからのデータ読み込み

潮位表データファイルは単純なテキストファイルなのでMachiKaniaのファイル操作関連命令を使用します。

文字列配列オブジェクトの生成

MachiKaniaで文字列配列を扱うクラスSTRDIMを使ってオブジェクトを生成します。
今回は一日分のデータの年月日、地点コード、満潮時刻・潮位(4個)、干潮時刻・潮位(4個)の18個のデータを一週間分を保存する二時限配列を用意します。

USECLASS STRDIM

X = NEW(STRDIM, 18, 7)

プログラム起動時がその年の何日目かを算出

潮位表データファイルには一年分のデータが格納されているのでプログラム起動時の日時から一週間分を取り出すためにRaspberry Pi Pico 2 WのRTCから日時を読み取り、その日が一年の何日目かを算出し、データを読み出す位置を移動する必要があります。

今回の検証環境ではNTPで時刻を同期しているのでMachiKaniaのRTC関連コマンドSTRFTIME$関数を使って、年月日を取得し、一年の何日目かを算出します。

配列Dに1月から12月までの各月の日数を格納し、取得して年から閏年かを判定し、二月の日数を調整します。
月、日からプログラムを起動した日が一年の何日目かを計算し、変数Sに日数を格納します。

DIM D(12) : REM 1月から12月までの各月の日数
D(1) = 31 : D(2) = 28 : D(3)  = 31 : D(4)  = 30
D(5) = 31 : D(6) = 30 : D(7)  = 31 : D(8)  = 30
D(9) = 30 : D(10)= 31 : D(11) = 30 : D(12) = 31

REM プログラム起動時の日時取得
Y=VAL(STRFTIME$("%Y"))
M=VAL(STRFTIME$("%m"))
E=VAL(STRFTIME$("%d"))

REM 閏年判定
IF (Y % 400) = 0 OR (Y % 4) = 0 OR (Y % 100) != 0 THEN D(2) = 29

REM プログラムを起動した日が何日目かを計算
S = 0
FOR I = 1 TO M - 1
  S = S + D(I)
NEXT
S = S + E

データの読み込み

データファイルをFOPEN命令で読み出しモードで開き、FSEEK命令で一日分のデータ量×(日数−1)分データの読み出し位置を移動します。

FOPEN "KG.TXT", "r"
FSEEK 137 * (S - 1)

読み出すデータは73バイト以降なので行ごとのデータを読み出す際にFINPUT$()命令で72バイト分を読み取りったのち、年月日のデータを2バイトとに読み取り、/で区切って読みやすい日付の形式にし、STRDIMクラスのメソッドSETSTRを使って文字列配列に格納します。続けて、地点コードを読み取り配列に補完します。

続けてFINPUT$()関数を使って4バイトの満潮時刻、3バイトの潮位、4バイトの干潮時刻、3バイトの潮位データをそれぞれ4つずつ読み取りSETSTRメソッドで配列に格納します。

FOPEN "KG.TXT", "r" : REM データファイルを読み取りモードで開く
FSEEK 137 * (S - 1) : REM ファイル読み出し位置を移動

FOR L = 1 TO 7
  T$ = FINPUT$(72)  : REM 73バイト目から読み取るように移動
  T$ = FINPUT$(2) + "/" + FINPUT$(2) + "/" + FINPUT$(2)

  X.SETSTR(T$, 1, L) : REM 日付の格納
  X.SETSTR(FINPUT$(2), 2, L) : REM 地点コードの格納
 
 REM 満潮時刻・潮位、干潮時刻・潮位の格納
  FOR I = 3 TO 18
    IF I % 2 = 1 THEN
      X.SETSTR(FINPUT$(4), I, L)
    ELSE
      X.SETSTR(FINPUT$(3), I, L)
    ENDIF
  NEXT
  FGETC() :REM 改行コードの読み込み
NEXT
FCLOSE

データの表示

文字列配列に格納されたデータをGETSTR$()メソッドを使って取り出し、表示します。
満潮時刻・潮位、干潮時刻・潮位がすべて9の場合は満潮および干潮データがないことを示しているのでSTRNCMP関数を使って999の3文字が含まれている場合には表示しないようにCONTINUE命令でFORループNEXT文まで飛ばしています。
また、時刻が一桁の場合には10の位が空白文字で桁が欠けて見えるのでSTRINGクラスのREPLC$メソッドを使って数字の0に置き換えています。さらに時:分表示となるように調整しています。

USECLASS STRING

FOR L = 1 TO 7
  COLOR 7
  PRINT X.GETSTR$(1, L)

  FOR I = 3 TO 18
    IF I < 11 THEN COLOR 3
    IF I = 11 THEN COLOR 5 : PRINT
    REM 潮位データがないところを表示しない
    IF STRNCMP(X.GETSTR$(I,L), "999", 3) = 0 THEN CONTINUE
    IF I % 2 = 1 THEN
      M$ = X.GETSTR$(I, L)
      REM 空白文字を0に置換
      S = NEW(STRING, M$)
      M$ = S.REPLC$(" ", "0")
      PRINT M$(0,2);":";M$(2,2);" ";
    ELSE
      PRINT X.GETSTR$(I,L);"cm ";
    ENDIF
  NEXT
  PRINT
NEXT

全体

プログラム全体を下記に示します。

CHOUI.BAS
USECLASS STRDIM, STRING

X = NEW(STRDIM, 18, 7)

DIM D(12)
D(1) = 31 : D(2) = 28 : D(3)  = 31 : D(4)  = 30
D(5) = 31 : D(6) = 30 : D(7)  = 31 : D(8)  = 30
D(9) = 30 : D(10)= 31 : D(11) = 30 : D(12) = 31

Y=VAL(STRFTIME$("%Y"))
M=VAL(STRFTIME$("%m"))
E=VAL(STRFTIME$("%d"))
IF (Y % 400) = 0 OR (Y % 4) = 0 OR (Y % 100) != 0 THEN D(2) = 29

S = 0
FOR I = 1 TO M - 1
  S = S + D(I)
NEXT
S = S + E

FOPEN "KG.TXT", "r"
FSEEK 137 * (S - 1)

FOR L = 1 TO 7
  T$ = FINPUT$(72)
  T$ = FINPUT$(2) + "/" + FINPUT$(2) + "/" + FINPUT$(2)

  X.SETSTR(T$, 1, L)
  X.SETSTR(FINPUT$(2), 2, L)
 
  FOR I = 3 TO 18
    IF I % 2 = 1 THEN
      X.SETSTR(FINPUT$(4), I, L)
    ELSE
      X.SETSTR(FINPUT$(3), I, L)
    ENDIF
  NEXT
  FGETC()
NEXT
FCLOSE

FOR L = 1 TO 7
  COLOR 7
  PRINT X.GETSTR$(1, L)

  FOR I = 3 TO 18
    IF I < 11 THEN COLOR 3
    IF I = 11 THEN COLOR 5 : PRINT
    IF STRNCMP(X.GETSTR$(I,L), "999", 3) = 0 THEN CONTINUE
    IF I % 2 = 1 THEN
      M$ = X.GETSTR$(I, L)
      S = NEW(STRING, M$)
      M$ = S.REPLC$(" ", "0")
      PRINT M$(0,2);":";M$(2,2);" ";
    ELSE
      PRINT X.GETSTR$(I,L);"cm ";
    ENDIF
  NEXT
  PRINT
NEXT

END

実行結果

上記のプログラムを実行した結果は次のとおりです。

IMG_2301.jpeg

さいごに

潮位表データをWGETクラスを使って取得しようとしましたがうまくできませんでした。
今回のプログラムは文字列配列を使わなくてもデータファイルから文字列データを読み出すごとに数値データに変換して配列に格納する方法で実現できます。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?