分光器自作メモ の履歴(No.48)


分光器自作メモ(作成2025/03/11)(最終更新2025/08/16)

olivine-Raman-20250402.png
自作分光器と自作測定プログラム(python)で簡易ラマン測定(試料はオリビン結晶)

(以下SolExProメモの後半に書いていた部分を分光器利用に絞ってまとめています)

分光器を自作する

 SolExという「自作できる太陽分光望遠鏡」があって、それを2024年11月頃に作りました。その時に分光器部分は実験室での汎用の自作分光器としても使えそうだと思い、色々と試してみました。以下は分光器としての利用方法について書いてます。SolEx自体についてはSolExProメモをご覧ください。なお正確にはSolとExの間にアポストロフィが入るのですが、このwikiではアポストロフィがあるとエラーになるのでSolExと記載しています。

SolExの分光器部分を汎用分光器として使ってみる

 SolExの分光器は3Dプリンターで印刷できて、入射側コリメートレンズf=80 mm、2400 gr./mmの回折格子、検出側集光レンズf=125 mmの仕様となってます。ただ回折格子やレンズ等は交換可能です。レンズの焦点距離を変えるためには一部改造が必要となります。回折格子は自由に回転できるようになってます(上の写真の左側の丸いところ)。分光器部分だけだと光学系パーツが7万円程度で、それプラス3DPの印刷費用、さらにCMOSカメラが必要です。光学系パーツをAliExpressなどで調達するともっと安くなります。ラマンとして使う場合には、レーザー、対物レンズ、結像レンズ、フィルター類、高感度CMOSカメラなども必要ですので数十万円は必要になります。分光器部分のSolEx Proはキットで販売されています。自分で3Dプリンターで作ることもできますが、その場合はSolEx Ver.2となります。印刷用のファイルがダウンロードできます。作り方等も詳しい説明があります。光学部品もセットで売られてますが、個々のパーツを自分で買って集めることもできます。詳しくはSolEx本家やSolExProメモを見てください。以下は既に完成したSolEx ProまたはSolEx Ver.2があるとして進めます。

SolExPro-optical-fiber-input.png

 そのままでは汎用の分光器としては使いづらいので、まずは光ファイバーで分光器に光を入力できるようにしました。スリット部の端(四角い部分)はM42メスネジとなっているので、ソーラボ(米国の光学パーツメーカー)のM42オスネジ–SM1メスネジのアダプタ(TMA2)を使うと、ソーラボ標準のSM1使用の光学系に組み込むことができます。ネジのピッチは0.75で天文用アダプタでよく使われているものです(T-Mount)。光ファイバーのコネクタをSM1のパーツ(光ファイバーアダプタ、SM1外ネジ付き)を使って接続すれば光ファイバー入力の分光器としてすぐ使えます(スリットは外しておく)。右の写真はそうやって光ファイバーを接続した状態です(これはSMAタイプ)。これで光ファイバーから導入した光を分光して測定できるようになります。私は光ファイバーはSMA端のものを使っていますので、SMA905のアダプタを使ってます。
 ただよくあるNA0.22の光ファイバーを使うとして、コリメートレンズ80 mm焦点距離だとファイバーからの光はレンズ位置で35.2 mmまで広がるのですがレンズ直径は25 mmなので実際は半分くらいの光しかレンズを通らないことになります。50 mmくらいの焦点距離レンズを使えばいいのですが、そうすると拡大倍率が2.5倍になるので、それもちょっと困る気がします。まあそちら側のレンズの焦点距離も変えればいいのですが。太陽用には分散方向を縦(CMOSセンサーの短い方向)にしますが、分光器目的では分散方向は横にして横長なセンサーを有効利用します。
 ソーラボに組み込むもう1つの方法は後で出てきますが、M42メスネジがついている部分を30 mmケージ用の穴を開けたものを自作して交換することです。これは3Dプリンターで作ってます。これでもソーラボの光学系に組み込めます。

SolExPro-w-table-and-plate.png

 SolExは望遠鏡に取り付けて使うことを想定しているため、平らな机の上では単体で安定しません。取り付けるカメラが大きいと机に当たります。私はAzur3dprintでKodak Turntableも購入しました。これはSolEx Proの下部に取り付けて、雲台に載せるためのアダプタです(3Dプリンターで作ることも可能です)。その下にさらに自作プレート1枚を置いて雲台用ネジを使って固定しました。これで机の上でも安定するようになりました。SolEx Ver.2でも同様なプレートをいくつか作ってます。1つは雲台ネジありで、これがあると三脚に固定できます。ソーラボのポストはメトリックだとネジがM4なので、M4ネジをつけておくと固定できますが、M4なのでポスト1本だとちょっと不安定な感じがあります。広めのベースで単に机の上で安定するだけのものも作ってます。

neon-2Dimage-fits.png

 光ファイバー入力にしたSolEx Proを少し使ってみました。右の図は光ファイバー(50ミクロン径)の波長分散されたイメージです。ネオンランプからの光を取り込んでいます。これはPlayer One Atronomyの非冷却CMOSカメラNeptune-CIIで撮ってます。SharpCapという天体撮影用のプログラムを使って撮影しました。範囲的には590 nm付近です。保存ファイル形式は天文分野でよく使うfitsを使いました。この画像を1次元スペクトルに変換するためにpythonでちょっとコードを作りました。fitsファイルを処理する場合にはastropyライブラリーがよく使われるので、astropyを使ってfitsファイルを読み込んで、縦方向にスポットがある辺りを縦に積算して1次元スペクトルに変換してみました。積算にはNumpyを使ってます。1行で(範囲を指定した)積算が処理できるので便利です。得られたスペクトルを下に示してます。左側が長波長側になります。そのままだとギザギザするので少し平滑化してます。これもNumpyの関数を使ってます。バックグラウンド処理なしでそのまま積算しているので、スペクトルのバックグラウンドが非常に大きな値になってます。

neon-SolExPro-590nm.png

 532 nmレーザーをルビーに照射して生じた蛍光(R1,R2)を見てみました。ルビー蛍光の2つのピークが690 nm付近に出ます。100ミクロン径光ファイバーを使ってます。ルビー蛍光法による圧力測定用途にも十分使えそうです。別ページで自作のLittrow型分光器について書いてますが、分解能はそれと同じかもっといいかもしれません。焦点距離が短い割に分解能がよくなっている理由は検出器のピクセルの大きさがSolExで使っているCMOSカメラの方がかなり小さいからです(約1/5)。もちろんファイバー径がそれよりは遥かに大きいので、分解能を十分生かしている訳ではありませんが、ルビー蛍光自体の線幅自体が広いのでファイバー径を小さくしても線幅はほぼ変わりません。それでも100ミクロン以下コア径を使った方がいいです。

SolExPro-ruby-100micron-fiber-image.png
SolExPro-ruby-100micron-fiber-spectrum.png

 比較的安く分光器を入手する方法の1つとしてSolExはいいかもしれせん。もう少しきちんとしたものが欲しい場合は、 OpenRaman や同じ人が作っている 分光器 がいいかもしれません。これらはソーラボのパーツを主に使ってます。このページの最後にPulsar Engineering設計の分光器とほぼ同じものを紹介してます。

ラマンスペクトルを撮ってみる

 ここまで来ると個人的にはSolEx Pro (またはSolEx Ver.2)でラマンスペクトルが測定できるのかどうかが気になります。簡単な顕微測定光学系を組んでみました(上のルビー蛍光もこれで測定)。これは上記の光ファーバーを使うものです。

SolEx Ver.2を使った分光器

 上記はSolEx Proを使っていたのですが、そちらは本来の太陽分光望遠鏡に戻して、分光器として使う目的でSolEx Ver.2を印刷して作りました。こちらは太陽には使わない予定なのでPLA+黒をフィラメントに印刷しました。Anker MakeのM5Cで印刷して特に問題は生じませんでした(M42外ネジのあるカメラ側のレンズ筒はネジの具合が悪く、印刷し直しましたが)。印刷後はM4とM3のインサートネジを埋め込む必要があります。
 SolEx Proは回折格子のアオリ角を調整しやすくする工夫がされているのですが、Ver.2にはありません。そこで回折格子ホルダーを取り付けるホルダーの底とハンドルの間にカマボコ形の薄い棒を挟んである程度調整できるようにしています。ハンドルを固定する2つのネジの締め加減で角度を調整できます。
 私の目的(実験室での分光)ではレンズを80 mmから100 mmに取り替えて、別のスリットやピンホールをSolExの外側で使いますので、SolExに用意されているスリットは使いません。コリメーターボックス外側にソーラボの30 mmケージと接続するアダプタを3DPで印刷しました。SolEx ProとVer.2ではコリメーターボックスの形状が異なるので共用できず、作り直しました。これでソーラボのケージを使った光学系に組み込めます。さらに本体底に15 mm厚のプレートも3DPで印刷して取り付けて、それにカメラネジのインサートナットを埋め込んでソーラボのポストで本体を支えるようにしてます(このためにはM4/カメラネジ変換が必要)。本当は1点だけの支持ではバランスが悪いのですが、ケージで別途繋がっているので、とりあえずはこれでもOKでしょう。光学パーツ(アクロマートレンズ2個と回折格子)はソーラボで買ったものを使ってます。回折格子は観察できる波長領域を広げるために1200 g/mmを使います。ただカメラ側のレンズは焦点距離f=100 mmだとちょっとうまく手持ちのCMOSカメラでフォーカスが合わないことが分かりました。そこでSolEx Proのf=125のレンズと交換しています。SolEx Proの方はf=100でも問題ありません。これは延長筒である程度調整できるためですが、それがVer.2ではできません(その後レンズ筒部分を自作してf=100でも使えるようにしました)。
 なお回折格子は6 mm厚のものだと交換可能です。厚さが異なるとホルダー部分をカスタマイズする必要があります。私の持っている回折格子は6 mm厚が多いのですが、9.5 mmのものもありました。9.5 mmはちょっと取り付け難しいと思います。
 下の写真は光ファイバーからの光を分光する場合のSolEx Ver.2の構成で、入射部分にファイバーを接続する端子をつけています。前述のようにProで同様のことを行ないました。アダプタでソーラボの30 mmケージが付くようにして、ロッドにケージプレートを固定、ケージプレートにファイバーコネクタを固定してます。ケージプレートは移動できるので、0次反射で光ファイバーのコア像を見ながらフォーカスを合わせます。ルビー蛍光やラマンも測定できます。波長は光ファイバーで繋いだネオンランプや低圧水銀ランプで校正できます。

SolExV2-fiber-spectrometer-20250305.png

 以前B&W OEMの中古装置(実質的にラマン分光装置だった)から外されて再構成してe-bayで販売されていたミニ分光器を、さらに私が改造してLittrow分光器にしてルビー蛍光で使っていたのですが、最近は上記のSolEx Ver.2分光器と入れ替えているところです。Littrow分光器で特に問題なかったのですが、1つだけ不便だったのはスペクトル測定は販売会社のソフトで、ルビー蛍光の処理を自作のソフトで後から行う必要がありました。今はネオンランプによる波長校正から、ルビー蛍光測定から圧力計算まで全部自作pythonコードで1つでできるようになりました。TkinterでGUI化してます。校正時のネオン輝線およびルビーR1,R2ピークのフィットはpseudo Voigt関数を使って自動で行います。これはscipy.optimizeのcurve_fitを使ってます。ピーク検出はscipy.signalのfind_peaks、バックグラウンドは5次多項式で、こちらはnumpyのpolyfitを使ってます。

POA-ruby-spectrum-demo2.png

(光ファイバーではなく)直接接続

 その後、3Dプリンターでソーラボの30 mmケージに接続できるようにするアダプタ(望遠鏡と繋ぐアダプタと入れ替える)を作成しました。下の写真で、30 mmケージ用の4本の6 mmロッドが固定できるようになってます(テプラシール貼っているところ)。これでソーラボの光学系と直接組み合わせて分光器として使うことができます。下の写真はVer.2の場合で、手前には可変スリットが付いてます(ミツトヨのマイクロメータがついているもの)。

miniRaman-variable-slit.png

 それを使って上のファイバー光学系の時のラマン光学系をほぼそのまま使ってミニ顕微ラマン分光器を組んでみました。全部載せるために300x300のブレッドボードを斜めに使ってます(適当なボードがないので)。小さいXYZステージをポストに付けてます。ここでは幅が変えられるスリットをラマン散乱を結像レンズで集光する所に置いています(前のファイバー位置)。コリメート側のレンズは焦点距離を100 mmと変えてます。回折格子も1200 g/mmへ変更してます。検出側のレンズも120から100 mmに変えて対称的にしたいのですが、これはVer.2では(この時点では)ちょっと難しく120 mmのままです。下の写真が光学系の全体像です。

miniRaman-whole-view-20250308.png

 可変スリットのいいところは幅を広げておいて、さらに0次反射になるように回折格子を回転させると、試料像が観察できることです(ミラーとして働くので)。そこで試料像にフォーカスを合わせて、レーザースポットがスリット中央に来るようにダイクロイックビームスプリッターの回転とアオリ角を微調整します(キネマティックマウントで)。その状態でスリットを50~100 micron程度に絞って、回折格子を560 nmくらいに移動するとダイヤモンドのラマンピークが観察されました。こちらの方が調整しやすいので、可変スリットのこの利用方法は結構いいなと思ってます(ただ回折格子を回転させるので定性的な測定にしか使えませんが)。スリットを使ってますが、ビーム自体はスポット状なので、ラマン散乱(スペクトル)は実際にはCMOS画面の上下かなり狭い範囲に出ることになります。SharpCapだと2712x200という観察領域が選べたので(Neptune-CIIの場合)、それを使うと撮像が速くなります。
 下は2秒露光のCMOS画面。中央から少し左の明るい2点がオリビンの2つの強いピークに対応してます。右端の縦長の部分がレーザー(0 cm-1)によるもので、その付近が暗いのはラマンエッジフィルターによる減光のため。2つのピークの分離が前より悪いのは回折格子を変えているためで倍の波数領域が見えてます。Windows上のSharpCapで画像を取得してます。SharpCapにはMac版がないのですが、AstroDMx CaptureにはMac版もあって、これを使うとMacからもラマンピークを見ることができました。今回はフィルター類は本格的なもの(Semrockの532 nm用ラマンエッジフィルター、ダイクロイックフィルター)を使ってます。

olivine-2Dimage-miniRaman-20250307.png

 最初は2D画像をSharpCapかAstroDMx Captureで取得してfitsファイルで保存して、それをpythonのコードで縦方向に積算して1次元スペクトルに直していました。よりよいスペクトルを得るにはStackingが必要です。SharpCapではLive Stackingが可能なのですが、試してみたところうまくいきません。星雲写真のように基準となる星に対応するものがないためのようです。普通に繰り返し測定は可能なのですが、fitsファイルが多量に出来るので、それを別途stackingしないといけないので、pythonでstacking用のプログラムを作りました。それでオリビンの2秒露光データファイル100個を処理したのが下のスペクトルです。上の2Dの図とは横軸を反転させてます。積算で波形がスムーズになりました。ただ、スリットが100ミクロンだったこと、レーザー自体が幅広いことなどからピークはSolEx Proでの測定例と比べてブロードになっています。
(以下に書いているように現在はpythonでPlayer One AstronomyのCMOSカメラを制御して、画像を取り込んで、1次元スペクトルへ変換することができるようになってます。)

olivine-miniRaman-spectrum-20250308.png

 カメラ側のレンズ筒部分を作り直しました。オリジナルだとレンズの焦点距離が125 mmかそれ以上でないとフォーカスできなかったため。新しいものはスリット側と同じくソーラボのケージが使えるようなアダプタがレンズ筒の端に付いてます。ヘリコイドフォーカサは使いません(その分安くなります)。ケージプレートをずらしてフォーカスを調整します、これで100 mmの焦点距離が使えるようになり、現在コリメート側も100 mmにしているので対称的な配置になりました。

SolExV2_new_camera_adaptor-20250311.png

 さらにもう1台SolEx Ver.2を印刷しました。今回はコリメートボックス部分を止めて、カメラ側と同じレンズ筒を使うように改造しました。最初からソーラボケージに組み込む目的です。これはNIRでの分光に使ってみる予定。これで本当に対称的になりました。また回折格子の回転ハンドルと止めネジをカラフルにしてみました。

SolExV2-custermized-20250321.png

Player One Astronomyのカメラ画像を直接スペクトルへ

 これまで2D画像をSharpCapかAstroDMxで取得してfitsファイルで保存して、それをpythonのコードで縦方向に積算して1次元スペクトルに直していましたが、すぐにスペクトルを見れなくて不便でした。また調整の時に2D画像からはピーク強度の変化が分かりづらいことも問題になってました。直接スペクトルを表示できるソフトが必要で、自分で作るしかないようです。Player One Astronomyのカメラを使うことが多いので、まずはPlayer One Astronomyカメラから始めました。Player One AstronomyはSDKを配布しているので、それに入っているPythonテストプログラムを動かすことから始めました。以下Macを使ってますが、Windowsでもほぼ同じでできるはずです(LinuxやLinuxベースのラズパイでも使えます)。
 Macの場合はreadmeにlibusbをインストールする必要があると書いてありました(Windowsは不要ですが、カメラドライバーインストールが必要)。brewをインストールしているので、brew install libusbでインストールできました(実際は古いlibusbがあったが、更新した)。
 私はminicondaでインストールしたpythonを使っています。テストプログラムではOpenCVライブラリーを使っているので、ライブラリーをインストールしました(Numpyも必要ですが既にインストールしてました)。minicondaの場合はconda install opencvで出来ます。ただ私の場合はエラーが出て、classicでやれとなったので、先にconda config --set solver classicを実行して、それからconda install opencvを実行すると今回はエラーなく出来ました。なお、このテストプログラムではOpenCVが必要ですが、自作プログラムで画像表示にMatPlotLibを使う場合には不要です。
 SDKにあるpythonコードはPOA_Camera_test.pyとpyPOACamera.pyで、test.pyの方が実行する方です。まずは実行ファイルになってなかったので、chmod 755 *.pyで実行可能ファイルに直しました。readmeに従ってpythonプログラムがあるディレクトリーにPlayerOneCamera.hとlibPlayerONeCamera.3.8.0.dylibをコピーします(header fileはいらないと思いますが)。そしてpyPOACamera.py中のdllの名前がWindows用のようなので、dll = cdll.LoadLibrary("./libPlayerOneCamera.3.8.0.dylib")と直しました。ディレクトリさえ正しく指定すればlibPlayerOneCamera.3.8.0.dylib自体はどこに置いてもいいはずです。これはユニバーサルバイナリなので古いIntel MacBookAirでも動作しました。
 これでPlayer One Astronomyカメラを繋いで、POA_Camera_test.pyをターミナルから実行すると、カメラ情報を出力し、さらに画像を表示しました。最初明るすぎてよく見えないのですが、これは露光時間の設定がなぜか長いためです。また左右逆転設定になってました。終了するにはqキーを押します。一応カメラを制御できることは確認できました。
 これをベースにちょっと直してみました。イメージはNumpyの配列(3次元になっている)に入るので、Numpyを使って処理します。画像を縦に積算して、1次元スペクトルへの変換ができました。
 現在はTKinterでGUI化した測定プログラムを作ってます。スペクトルや画像の表示にはMatPlotLibを使ってます(OpenCVは使ってません)。連続的な表示やスタックもできるようになってます。これで自作分光器が使いやすくなるはずです。動かしている動画を置いておきます。これはネオンランプのスペクトルを測定しているところです。外部ライブラリーとしては、numpy, pillows, MatPlotLib, tkinterを使ってます。非冷却カメラしか持ってないので、温度やファン制御などはやってません。非冷却カメラでも画像センサー温度は取得できますが。
POA-spectrum.pyのデモ動画 これはネオンランプのスペクトルです。
 上記の簡易ラマン分光装置で自作プログラムを使ってみました。同様に532 nmレーザーで4.5 mW出力。下はオリビン結晶を測定したもので、1秒露光で60回積算。スタッキング機能を使ってます。この試料はいつもバックグラウンドが高くなります…

olivine-Raman-1sx60.png

 次は水晶を測定したもので、1秒露光で20回積算。どちらもスリットは50ミクロンくらいで、binningは40ピクセルで約120ミクロンの領域に対応します。こちらはバックグラウンドは低いです。

quartz-Raman-1sx20.png

 使っていて1つ気付いたのはカラーカメラだと隣合うピクセルで強度が大きく異なることです。カラーCMOSピクセル特有の問題だとは思いますが、スペクトルでピークがギザギザに見えることやピークが二重に見えることがあります(拡大すると分かりやすい)。モノクロカメラではこの問題は出ません。現在はカラーカメラだと自動的に平滑化機能がONになるようにしてます。平滑化を使うとカラーCMOSカメラを使った時のギザギザが消えます。ただこの辺りは取得するデータのフォーマットで異なる気がします。私はRAW16で取得しています。


SolExではないミニ分光器

 ついでにSolExではない自作分光器(最近作った)も紹介します(下の写真)。これはPULSER Engneeringさん設計の400~800 nm分光器とほぼ同じもので、ソーラボのパーツで組んであり、カメラはFLIRのBlackFlyを使ってます(もちろんPlayer One Astronomyカメラでも使えます)。PULSER Engneeringさんの見積もりでは必要な予算は1400ユーロくらいになります。台はPULSER Engneeringさんは使わない方がいいと言っている積層式3Dプリンターで作りました。PULSER Engneeringさんは粉末をレーザーで固めるタイプの3Dプリンターで作ることを推奨してます(またはアルミ板を加工)。この分光器は50 mmのレンズを両側に使っていて、300 gr./mmの回折格子を使って、一度に400 nmくらいの範囲を測定できるような仕様になってます。理想的には使う光ファイバーは10 micronがいいのですが、持ってないので50 micronでテストしました。ネオンランプや蛍光灯のスペクトルがよく見えましたが、ネオンランプでは本来ピークが出ない位置にピークがあり(一部はネオンランプに含まれるアルゴンによるもの)、高次回折のピークが紛れこんでいるようでした。ショートパスやロングパスフィルターで必要ない波長をカットした方がいいようです。
 現在これを温度測定用に使う予定です。BlackFlyもPythonのデモプログラムが付いているのですが、今のところうまく動かせてません。なので検出器はPlayer One AstronomyのスティックタイプのCMOSカメラ(Ceres-M)と交換しています。Ceres-Mはセンサーサイズが小さいので300 nm弱の領域が測定できます。同じ形状のSedna-Mだとセンサーサイズが1.5倍くらいあるので、400+ nm範囲が測定できます。しかしSedna-Mを入手して試してみたところ、どうも干渉によると思われるウネウネが見られたためこの用途には使わないことにしました。他のカメラでもウネウネが見られるものがありました。
 その後、3Dプリンターでケースを設計して作りました(上下が分離していて長いネジで固定する)。印刷にはPLA+黒を使ってます。スペクトルがCMOSセンサーの中央に来るように調子しておいたのですが、上側ケースをネジで締めたらスポットの位置が下にずれました。多少ケースが変形するようです。ケースを閉めると調整できないので、予め上にワザとずらせておいて対応しました(実際的には中央にきちんと合わせる必要はありません)。CMOSセンサーのピクセルが小さいので、50ミクロン光ファイバーを使ってもネオンランプなどスペクトルがブロードに見えます。その後10ミクロンと25ミクロンの光ファイバーを入手して使ってます(PULSER Engneeringさんは10ミクロンを使っている)。

visible-spectrometer-case-printed.png

 波長の校正はHg-Ar校正用ランプを持っているので、それで校正しています。温度測定では強度も補正する必要があります。強度についても校正用光源を持っているのでそれで校正を行います。現在温度測定プログラムができたところでテスト中です。下はタングステンハロゲン光源を測定した例で、右側スペクトルの赤い線が強度補正された観測スペクトルで青い線がWien式でfitした結果です。温度は2600 Kくらいになりました。光源のマニュアルには色温度で2800 Kと書いてあったのでちょっと測定結果は低く出ているようです。Pythonなのでそれほど早くはないので現状1測定毎秒くらいの測定速度になってます。
 その後、Wien式のフィッティングを線形化して計算し、プロットも省くバージョンを作ったら5回/秒くらいに測定速度は上がりました。現在はWien式やPlanck式でフィットする時は温度初期値に線形化Wien式で得られた温度を使ってます。
 さらにその後、二点の温度を測定したいとの要望があったので、光ファイバーで片側はコアが2つ隣接していて、他端は2分岐している光ファイバーを使って、CMOSセンサー上で2つのスペクトルを上下に分離して(binningする領域を分けることで)同時に測定するようにしてます。

temperature-measurement-demo.png

 2025年6月後半に2台目のミニ分光器を作りました(下の写真の右側)。1台目は別の研究室で使ってもらう用途なので、自分のところで使うために2台目を作りました。ストックパーツでほとんど間に合いました。1台目とほぼ同じなのですが、光学部分をケース下側からネジで固定するように変更しています。この方が調整しやすいので。1台目にも同じ改良を行いました。

2nd-minispectroscopy-20250621.png

 2台目で測定したHg-Ar校正光源のスペクトル。25ミクロンの光ファイバーを使用。

2nd-miniSpectrometer-HgAr-lamp.png

ラズパイ5を測定に使う

 上記はMac上でソフトを作ってきましたが、Windowsでも少し手直しすれば動きます。Player One AstronomyのSDKはラズパイOSにも対応していたので(現在はLinux版に統合されています)、ラズパイ5や4Bで使ってみました。ラズパイOS(Bookworm)にはPython等は元々入っているので、SDKだけコピーしました。ただMatPlotLibが入ってなかったので、インストールしました($ sudo apt install python3-matplotlib) 。わずかの手直し(Readmeファイルに書いてある通りにライブラリを移動する)、それからpyPOACamera.pyのライブラリの指定がWindows用になっているのでコメントアウトして、Linuxに変えることでPlayer One AstronomyのCMOSカメラを制御することができました。なお実行した時はlibusbの実行権限がないと怒られたので、sudoで実行する必要がありました。また、ラズパイ400(ラズパイ4がキーボードに内蔵されているもの)でも問題なく動きました。さらにラズパイ4Bでも動くことを確認しました。
 sudoで実行しなくてもよい方法を見つけました。SDKにudevというディレクトリがあって、その中に99-player_one_astronomy.rulesという名前のファイルがあります。これは/etc/udev/rules.dディレクトリにコピーします($ sudo cp 99-player_one_astronomy.rules /etc/udev/rules.d/)。それでOSをリブートするとsudoなしで使えるはずです。
 その後、ラズパイ用のTouch Display2を入手しました。Touch Display2を使っても上記プログラムは問題なく動きました。ピークが幅広なのは使っている光ファイバー径が大きいから。

RaspPi-spectrometer.png

 天文目的の画像取得ソフトのAstroDMx Captureにはラズパイ版もあります。ラズパイ5にインストールしてみました。解凍して、スーパーユーザー権限でinstall.shを実行するだけです。メニューの中にAstroDMx Captureが追加されています。HayearのカメラとPlayer One AstronomyのカメラはUSBで接続して画像を見ることができました。分光測定用にもラズパイは結構使えるかも。実際、太陽用分光器のSunScanではラズパイが使われています。

ラズパイHQカメラを使う

RaspPi5-HQcamera-set.png

 SunScanではラズパイボードに直接接続するHQカメラが使われています。HQカメラなどのラズパイ用カメラはpythonのopencvライブラリをインストールすることで簡単に使えます。雑誌インターフェースの2024年5月号のラズパイ5特集にカメラのことも詳しく載ってます。また単純にrpicam-hello -t 0をターミナルから実行するとカメラプレビュー画像を示してくれます。HQカメラはSonyのIMX477Rを使ってます。分光用にも使えるかも。ただHQカメラはケーブルがリボンケーブルで長くすることも難しいので分光器とラズパイを合体させる必要がありそうです。SunScanはそうなってます。その後、HQカメラとラズパイボードを3Dプリンターで作ったアダプタで合体したものを作りました(上の写真)。これは顕微鏡などCマウントがあるものに接続して使えます。MacやWindowsからVNCでラズパイに接続してリモートで使うと便利です。
 なおHQカメラには赤外フィルターが内蔵されています。近赤外領域まで見たい場合はそのフィルターを外す必要があります。私は外しましたが、フィルターを貼っているガラスを割ってしまいました…破らなくても復元はほぼ無理なので、覚悟して行う必要があります。
 最近上記のSolExではない分光器にHQカメラを繋いでみました。下がその状態です(実際に使う場合にはラズパイ5にケーブルが色々とつながります)。HQカメラはCマウントなので、SM1メスーCマウントオスのアダプタ(これもソーラボ)でソーラボの光学パーツと接続できます。ケーブルの点からはケーブルを上に出すようにカメラを接続せざるを得ませんが、そうすると右側が長波長側になります。

miniSpectrometer-Raspi5-HQcamera.png

 さらにPlayer One AstronomyのCMOSカメラ用に作ったプログラムをHQカメラ用に直すこともできました。下はそのコードで撮ったHg-Arランプのスペクトル。

HQcamera-HgAr-lamp-spectrum.png

 HQカメラで必要なライブラリやアプリなどはラズパイOSに最初から入っているので、すぐ使えるようになってます。特にいくつかterminalから実行できるコマンドがあって、とりあえずHQカメラをチェックするためには便利です。以下に示すのは画像を5秒だけ表示するだけのコマンド。2つ目はオプション付けてずっと表示する方法。

$ rpicam-hello
$ rpicam-hello -t 0

 次は撮影してjpegで保存するコマンド。

$ rpicam-jpeg --output test.jpg

 次は動画を保存するコマンド。

$ rpicam-vid -t 10s -o test.h264

 他にもいくつかありますし、オプションも色々あります。https://www.raspberrypi.com/documentation/computers/camera_software.html に詳しい説明があります。
 それでpythonから制御する場合は、以下でpicamera2ライブラリを使う必要があります。

from picamera2 import Picamera2, Preview

 単に撮影して、matplotlibを使って表示するには以下の簡単なプログラムで出来ます。

import time
import matplotlib.pyplot as plt
from picamera2 import Picamera2, Preview
picam2 = Picamera2()
picam2.start_preview(Preview.NULL)
capture_config = picam2.create_still_configuration()
picam2.configure(capture_config)
picam2.start()
time.sleep(0.1)
img = picam2.capture_array()
plt.imshow(img)
plt.show()

 次は撮影して、np配列に入れて、それを上下にbinningしてスペクトルに変換、それをmatplotlibで表示するプログラムです。この場合transformで左右逆転してます。今の場合、設定はpicam2.start()の前に行ってますが、ExposureTimeとAnalogueGainはpicam2.start()後に変えても問題ありません。ただすぐには反映されず数フレーム後に変わります。Transform(hflip=True)はpicam2.start()後で変えるとエラーになります。一度picam2.stop()でストップして、設定を変えて、再度picam2.start()を実行する必要があります。

import time
import numpy as np
import matplotlib.pyplot as plt
from picamera2 import Picamera2, Preview
from libcamera import Transform

picam2 = Picamera2()
picam2.start_preview(Preview.NULL)
controls = {"ExposureTime":100000,"AnalogueGain":300.0}
capture_config = picam2.create_still_configuration(controls=controls,transform=Transform(hflip=True))
picam2.configure(capture_config)
picam2.start()
time.sleep(0.1)
img = picam2.capture_array() # put data into array
data = img[:,:,0] # 3D to 2D
h = data.shape[0]
w = data.shape[1]
x = np.arange(w)
y = np.sum(data[1450:1550],axis=0) # vertical binning from 1450 to 1550
plt.plot(x,y,color="r")
plt.show()

 
 ただよく見ると560 nm以下があまり見えてないようです。理由はこの場合、dataにはRGBのRだけ入っているようです。カラーで見るには1つ前と同じでplt.imshow(img)を使えば見られます。グレースケールに変えるには、img[:,:,0]にR、img[:,:,1]にG、img[:,:,2]にBが入っているらしいので、data = のところを

 data = 0.299*img[:,:,0] + 0.587*img[:,:,1] + 0.114*img[:,:,2]

とすればいいようです。これはグレースケール変換で一般的に使われている式です。ただ今の方法だと8 bitになるので困ります。rawファイルで扱えばいいのかもしれませんが結構面倒そうです。