METPV-11の解析

諸般の事情で,太陽電池の実発電量を試算するはめになったので,とりあえずNEDOが公開しているデータベースであるMETPV-11を利用して計算することに。ちょっと複雑な事をしようとすると,付属のソフトじゃ足りないので,公開されているテキスト形式のデータ(METPV-11データファイル.zipを解凍)を直接読み込む必要があるのだけど,わかりやすい形式が公開されていないので,解析した結果をまとめてみた*1

METPV11データファイルの各テキストファイルは1行のヘッダーと3285行(=365*9)のデータ行からなっている。それぞれの形式は以下のとおり。データ形式は固定長なので,各要素の説明の末尾の括弧内に想定される長さを記載。

ヘッダー

43056 KUMAGAYA               36  9.0  139 22.8    30.0
地点コード(5)	地点名(22)	緯度-度(4)	緯度-分以下(6)	経度-度(4)	経度-分以下(6)	標高m(6)

データ行

00001  428  6.5   02   02   02   02   06   96  446 1566 2186 2666 2986 3116 3056 2806 2376 1796 1116  346   16   02   02   02   02   02  311 8888 2449 8888  118
要素番号(6)	月(2)	日(2)	風速計高さm(5)	毎時データ(5)*24	日最大値(5)	日最小値(5)	日積算値(5)	日平均値(5)	日付番号(5)

各要素番号にどんなデータがどんな単位で格納されているかは以下のとおり。各毎時データは整数だけかとおもいきや,平気で小数も来るので,プログラムを書くときには注意が必要。

  1. 水平面全天日射量(0.001MJ/m^2)
  2. 水平面直達日射量(0.001MJ/m^2)
  3. 水平面天空散乱日射量(0.001MJ/m^2)
  4. 日射時間(1000秒/30=1/108時間 = 0.009259時間)
  5. 気温(0.01℃)
  6. 風向き(度)
  7. 風速(0.01m/s)
  8. 降水量(0.01mm)
  9. 積雪深(mm)

これだけだとわかりづらいので,以下は,rubyで書いたMETPV11の形式のテキストファイルを読み込むサンプルスクリプト

使い方は

metpv = METPV.new("ファイル名")
puts metpv.place_name; # TOKYOとかの地名が出力
puts metpv.get(Date.today,1); # 今日の水平面全天日射量が24個の要素を持つ配列で出力
puts metpv.get_single(DateTime.now, 1); # 今の時刻の水平面全天日射量を出力
class METPV
  attr_reader :place_name, :latitude, :longitude, :height, :height_of_anemometer

  def initialize(filename)
    @data = Array.new
    open(filename).each do |line|
      line = line.chomp
      if (line.length == 54)
        # header
        a = line.unpack("A6A22A4A6A4A6A6")
        @place_code = a[0].to_i
        @place_name = a[1]
        @latitude  = a[2].to_f+a[3].to_f/60.0 # [degree]
        @longitude = a[4].to_f+a[5].to_f/60.0 # [degree]
        @height = a[6].to_f # height[m]
      elsif (line.length == 160)
        # data
        format = 29.times.map{|x| "A5"}
        a = line.unpack("A6A2A2A5#{format}")
        data_type = a[0].to_i
        month = a[1].to_i
        day = a[2].to_i
        @height_of_anemometer = a[3].to_f # height of anemometer[m]
        yday = a[32].to_i-1
        @data[yday] = Array.new if @data[yday]==nil
        
        case data_type
          when 1..3
            # irradiance values [MJ/m^2/hour]
            @data[yday][data_type-1] = a[4..27].map{|x| x.to_f*0.001}
          when 4
            # sunshine duration [hour]
            @data[yday][data_type-1] = a[4..27].map{|x| x.to_f/108.0}
          when 5
            # temperature [deg C]
            @data[yday][data_type-1] = a[4..27].map{|x| x.to_f*0.01}
          when 6
            # angle of wind [deg]
            @data[yday][data_type-1] = a[4..27].map{|x| x.to_f}
          when 7
            # speed of wind [m/s]
            @data[yday][data_type-1] = a[4..27].map{|x| x.to_f*0.01}
          when 8
            # rain fall [mm]
            @data[yday][data_type-1] = a[4..27].map{|x| x.to_f*0.01}
          when 9
            # snow height [mm]
            @data[yday][data_type-1] = a[4..27].map{|x| x.to_f}
        end
      end
    end
  end

  def get(a_date, index) 
    # assume a_date is not leap year
    @data[a_date.yday-1][index-1] if !a_date.leap?
  end

  def get_single(a_datetime, index)
    # assume a_datetime is not leap year
    a = @data[a_datetime.yday-1][index-1]
    a[a_datetime.hour]
  end
end

*1http://www.ide.titech.ac.jp/~kandalab/ja/manual/metpv/METPVManual.html がかなり参考になるけど,今の形式と少し合ってない。