2012年 11月 21日

関連エントリー (画像)

レンズの解像度限界

センサーの高解像度化はどこまで可能なのか、実際今はどれぐらい限界に近付いているのかが気になった。

収差が全くないレンズであっても、回折によって解像度は低下してしまう。これは物理的にどうしようもない限界だ。Wikipedia のエアリーディスクの項を読むと比較的わかりやすい気がする。

ありがいたいことにカメラにおける分解能限界の式も求めてあるので、あてはめて JS で計算してみた。

/**
 * F値 `f`, 波長 `lambda` nm における分解能 (mm)
 */
function rayleighLimit (f, lambda) {
	return 1.22 * (lambda * 0.000001 * f);
}

// 500nm は緑
console.log('rayleighLimit F32', rayleighLimit(32, 500));
//=> rayleighLimit F32 0.01952
console.log('rayleighLimit F11', rayleighLimit(11, 500));
//=> rayleighLimit F11 0.00671
console.log('rayleighLimit F8', rayleighLimit(8, 500));
//=> rayleighLimit F8 0.00488
console.log('rayleighLimit F5.6', rayleighLimit(5.6, 500));
//=> rayleighLimit F5.6 0.0034159999999999998
console.log('rayleighLimit F2.8', rayleighLimit(2.8, 500));
//=> rayleighLimit F2.8 0.0017079999999999999

光の波長によって変わるらしいが (波長が長いほど分解能は低下する)、この例では人間の目が一番感じやすいらしい緑の波長に設定した。

Canon EOS 5D Mark II のピクセルサイズは 0.0064 mm ぐらいなので、F11 ぐらいになると1ピクセルを超えてしまうようだ。Nikon D800 だとピクセルサイズが 0.0049mm ぐらいで F8 ぐらいが物理的なぎりぎりになってしまう。

結論

  • 既に割と限界ぎりぎり
  • 開放すれば回折の影響は出なくなるけど、今度は収差がでる (どれぐらいでるかはわからない。物理的に無収差にできるのかもわからない)
    • さらにはボケてしまう (ピント面外の解像度が低下する)
  • F8 がだいたい最高解像度になるみたいな話は収差と回折のバランスをとった答えのようだ
  • さらなる解像度を求めるなら大判にするしかない

gerry++

2012年 11月 20日

関連エントリー (画像)

2012年 11月 19日

関連エントリー (画像)

2012年 11月 17日

関連エントリー (画像)

2012年 11月 16日

関連エントリー (画像)

家計簿のいいつけかたを知りたい。が、まず要件が自分でわかっていないようなので整理が必要。

知りたいこと・やりたいこと

  • 特定の日の実際使えるお金 (純資産)
    • 預金総額
    • クレジットカード利用額 (借金額)
      • 他に借金してないのでここだけ処理が面倒
  • 未来の予定している収入・支出を先に計上したい
    • 何年分? 最大でも15年程度で十分そう
  • 税金・保険料の可視化
  • 簡単に現金の決済結果を記録したい
  • PASMO で支払った分は自動化したい

当然できるだけ自動化しようと思うのだけれど、カード利用の明細はちゃんと残しつつ (つまり使った日に何に使ったかを含めて記載したい)、銀行からの引き落としも全部統一して扱いたいと思うと、複式で書くしかないような気がする。けど、複式だとぱっと見で何がどうなってるか理解できないので (どれが負債なのかとか)、なんとかしたい。

自動化しようと思うと、未来の予定の記述が邪魔になる (自動化されていると二重に記載されてしまう)。確定した時点で上書きするみたいな処理が必要。

十分に半自動化ぐらいまでできないとつける気が起きない。

gerry++

Google Apps Script はマジですごい。自分でサーバーを持たず、定期的に Gmail のメールを集計することができる

最近知ったがGoogle Apps Scriptはだいぶいろいろなことができてすごい。

ので、とりあえず楽天カード (今話題) の売上情報メールを集計して家計簿に記録していくみたいなスクリプト (Google Apps Script で使用する言語は JavaScript) を書いてみた。

Google SpreadSheet を開き、ツール → スクリプトエディタ で開かれるエディタに以下をコピペして、run 関数を実行すると、Gmail のメール直近1ヶ月のうち、楽天カードの売上メールから決済情報を抜きだし、シートに転記することができる。手動で実行してもいいが、定期的に実行することもできるみたいだ。

また、ウェブアプリも作ることができて、CSVのインポート画面を作ることもできそうなので作ってみてる。銀行のサイトでブックマークレットを実行すると CSV をつくってインポート画面を開く、みたいなことができそうだ。現金記録用のアプリだけ何か良さそうなのを見つければ、あとはほぼ自動で家計簿的なものを作れそうだと思う。

Google Apps Script はカレンダーの予定とかもいじれるようなので、例えば旅行の予定を入れておけば、自動でそれらも纏めて家計簿の備考欄に追記できると思う。大変夢が広がる。

ただしいくつか欠点もありそうだと思う。

  • ウェブアプリは大変遅い
  • スクリプト実行6分の時間制限
  • Google に完全にロックインされる (もはや抜けようがない)
function run () {
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var sheet = ss.getSheets()[0];
  
  var exists = {};
  var values = sheet.getDataRange().getValues();
  for (var i = 0, row; row = values[i]; i++) {
    exists[ [ row[0], row[1], row[4] ].join(':') ] = true;
  }
  
  var rakuten = getRakutenCardData(new Date(new Date().getTime() - (1000 * 60 * 60 * 24 * 30)));
  for (var i = 0, it; it = rakuten[i]; i++) {
    var debit = guessTitle(it.place);
    var credit = "クレジット (楽天)";
    var row = [it.date, it.place, debit, credit, it.amount, "支払い予定日: " + [it.pay_date.getYear(), it.pay_date.getMonth() + 1, it.pay_date.getDate()].join('/') ];
    if (exists[ [ row[0], row[1], row[4] ].join(':') ]) continue;
    sheet.appendRow(row);
  }
  
  sheet.sort(1);
  
  function guessTitle (name) {
    if (/ガス|ガス|スイドウ|スイドウ|水道|デンキ|電力/.test(name)) {
      return "光熱費";
    } else
    if (/ユニクロ/.test(name)) {
      return "衣服費";
    } else
    if (/スーパー/.test(name)) {
      return "食費";
    } else
    if (/KDDI/.test(name)) {
      return "通信費";
    } else
    if (/SONY ONLINE SERVICES|デイ-エムエム/.test(name)) {
      return "娯楽費";  
    } else {
      return "";
    }
  }
}

var regexp = new RegExp('<tr><td align="center" bgcolor="#ffff00"><font size="-1"><input type="checkbox" name="uriage\\[\\]" value="[0-9]+"></font></td><td align="center"><font size="-1">([0-9]+)/([0-9]+)/([0-9]+)</font></td><td align="left"><font size="-1">([^<]+)</font></td><td align="center"><font size="-1">[^<]+</font></td><td align="right"><font size="-1">([0-9,]+) 円</font></td><td align="center"><font size="-1">([0-9]+)/([0-9]+)</font></td><td align="right"><font size="-1">[0-9]+ ポイント</font></td><td align="right"><font size="-1">[0-9]+/[0-9]+</font></td></tr>', 'g');
function getRakutenCardData (fromDate) {
  var result = [];
  
  var newer = [fromDate.getYear(), fromDate.getMonth() + 1, fromDate.getDate()].join('/');
  var threads = GmailApp.search('subject:"【売上情報】カード利用お知らせメール" newer:' + newer, 0, 50);
  for (var i = 0, it; it = threads[i]; i++) {
    var messages = it.getMessages();
    for (var j = 0, message; message = messages[j]; j++) {
      var matched = [];
      message.getBody().replace(regexp, function (_, year, month, date, place, amount, pay_year, pay_month) {
        Logger.log([ year, month, date, place, amount ]);
        matched.push({
          date : new Date(+year, +month - 1, +date),
          pay_date : new Date(+pay_year, +pay_month - 1, 27),
          place : place,
          amount : +(amount.replace(/,/g, ''))
        });
      });
      
      if (matched.length) {
        result = result.concat(matched);
      } else {
        Logger.log("unmatched: %s (%s)", message.getId(), message.getSubject());
      }
    }
  }
  
  Logger.log(result);
  return result;
}