ダイナミックマイクアンプの制作
概要
リモート会議等が増えたことでマイクをパソコンに入力することが増えた。話者聴者双方の快適性のため、家にあるダイナミックマイクを通話で使用することにした。その際電圧をラインレベルまで引き上げるためのアンプを制作した。
回路のユニバーサル基板への実装と筐体への実装、加えて簡単な正弦波発生器によるテストまで完了しているが、実験中にマイク本体が故障してしまい実用テストが完了していない。現在別製品を注文中。
目標
昔使っていたカラオケ機能付きレコードプレイヤーに付属していたダイナミックマイクが残っていた。オーディオテクニカのAT-X11という型番。この出力信号をラインレベルまで引き上げ、PCへ入力、通話で使用できるようにすることを目標とした。
設計 (回路)
opアンプで非反転増幅回路を実装した。 図1に回路図を示す。電源回路はUSB microBによる5Vを使いたかったので (以前microBソケットを大量に購入し、余っているため)、opアンプは両電源用を片電源で使うことにした。
入力信号はバイアスしてopアンプに入力される。増幅回路は2段にして80dBほどの利得が得られるように設計した。設計上は、40 + 43.2 = 83.2dB。
直流成分が増幅されないように、-入力にデカップリングキャパシタを挿入し、直流成分にとってはボルテージフォロワになるように設計してある。これはマルツの レールツーレールオペアンプLMC6482使用レポート―簡易集音装置の製作実験 を参考にした。
入力段のカップリングキャパシタは、後ろの (小信号等価回路における) インピーダンスが十分高いことから、もっと小さい値でも良いはずだが (RC ハイパスフィルタを構成する)、適当に手元にあった 100μF のものを採用した。実際に計算してみると、カットオフ周波数 0.031 程度になり、こんなにいらない。むしろ、電源投入時のポップノイズが大きくマイクにかかることの方を考慮するべきだった。もしかすると、前述のマイクの故障はこれが原因かもしれない。
電源は昔使用していたモバイルルータに付属したACアダプタ (USB micro B 出力) を使用することにした。安物っぽく、スイッチングノイズが懸念されることからRLCローパスフィルタをかけた。
これをユニバーサル基板へ実装した。配線図を図2に示す。引き回しにはノイズ対策のための考慮事項があるはずだが、とりあえずアースループができないようにだけした。C6はopアンプの直前につけたほうが良かったかもしれない。
設計 (筐体)
筐体の役割として、信号入力、信号出力用3.5mm フォーンプラグ、電源スイッチ、電源用 USB micro B ソケットからなるインターフェースを実装することと、シャーシアースをしてノイズを防ぐことがある。これを実現するために最低限のことはやった。外形を図3に示す (この画像には電源コネクタが実装されていないが、このあと四角孔部分にL字に曲げたアルミの治具とともに接着剤で (!) 固定された)。
まず、アルミ板をホームセンターで買ってきて、曲げてコの字型にした。インターフェース用の穴は、ドリルで小さい穴を開けた後リーマで大きくし、ヤスリですこし磨いた。手垢と傷がすごいので、脱脂や塗装などをしたほうがいいのだろうが、経験も知識もないので今後の課題とした。ゴム足も着いていないが、今後の課題。
基板取り付け用にM3スペーサがほしかったが、近所のホームセンターではM4からしか取り扱っていなかった。幸い手持ちに2個あったので、対角をスペーサで、残りをナットでかさ増ししてとりあえず固定した。インターネットを見ていたら、おもちゃ屋さんにあるかもしれないということで、今後の課題として物色に行くことにする。
現在下の台座部分のみできており、ふたは今後の課題。
電源用のソケットを逆向きにすればもう少し配線が楽できれいかもしれなかった。
検証
ゲインの実測をするため、正弦波発生器を実装し、それを入力した。発生器を図4に示す。
部品が少ない簡単な発振回路2選 を参考に、出力段にバイアスとエミッタフォロワを付加した。バイアスし直しているのは、Q2の V_BE によって波形下部がクリップされてしまうため。
この発生器によって、1.6mVP-P の正弦波が得られるので、これを当アンプに入力した。結果、1.16VP-P が得られた。この記事 によれば、ダイナミックマイクの出力電圧 (入力感度) は
1.0 ~ 3.16 [mV/Pa]
とのことなので、ラインレベルを目標とすれば要求を満たすゲインだと思われる (民生品としては大きすぎるのかもしれないが (参考: 0.31V、マザーボードに入力して壊れなかったのでよいことにする。音量を下げる分についてはソフトウェアで行えばよい)。
ちなみに、1.16VP-P / 1.6mVP-P = 725 = 57.2dB。
図5 に実験の様子を示す。左側が正弦波発生器。正弦は発生機には図? の回路に加えて、分圧抵抗による降圧をしてある。
図6 に観測された波形を示す。Ch.1 がアンプの出力で Ch. 2 が正弦波発生器による入力 (エミッタフォロワ・分圧のあと)。 目視する上では大きな歪は無いように見える。歪率は解析していない。もとの入力波形が (簡単な回路のためか) かなり歪んでいるため。
続き
実際にマイクを通してパソコンに入力してみた結果はマイクが届き実験が完了し次第記載する。
AWS SDK for GO API Reference がもっさりするのでダウンロードして閲覧する
AWS SDK for GO API Reference (例えばEC2のリファレンスなら ec2 - Amazon Web Services - Go SDK) はかなりもっさりしている。特に、ページ内リンクを新しいタブで開くときは新たにダウンロード・ページ遷移を両方するのでしんどい思いをする。
Google Chrome によってページが再現できるようにダウンロードすることができるが、HTMLファイル内のリンクは絶対パスなので新しいタブを開くと結局もう一度ダウンロードが発生してしまう。
以下のsedスクリプトで、html内のリンクを相対パスに変えて、新しいタブで開いてもダウンロード済みのファイルが読み込まれるようになる。
sed -ie 's$https://docs.aws.amazon.com/sdk-for-go/api/service/ec2/$./ec2 - Amazon Web Services - Go SDK.html$g' ec2\ -\ Amazon\ Web\ Services\ -\ Go\ SDK.html ec2\ -\ Amazon\ Web\ Services\ -\ Go\ SDK_files/*
その他
- htmlソースを見ると、ページ内リンクは
#hogehoge
だが、ダウンロードしたファイルであっても新しいタブで開くと新たなロードが発生する (https://docs.aws.amazon.com/ にリクエストが飛ぶ)。現在のurlにページ内識別子を追記する仕様ではなく、metaタグかなにかを見るのかもしれない。
vimでgolang (あるいは他の言語) のquickfix errorformat を利用する (Debian)
Vimは、組み込みでいくつかの言語のコンパイル設定ファイルを持っている。 Debian, Vim 8.1なら、/usr/share/vim/vim81/compiler
の下に ${言語名}.vim
というファイルが置いてある。golangなら /usr/share/vim/vim81/compiler/go.vim
。このPATHは runtimepath
か packpath
を見ればみつかる。
これを読み込むことで (拡張子で自動で読んでくれるわけではないらしい?) quickfix errorformatが適用される。
:compiler! go.vim
必要があれば autcmd
などで拡張子毎の設定をしておくと良さそう。
その他
:help compiler
によると
What the command actually does is the following: - Delete the "current_compiler" and "b:current_compiler" variables. - Define the "CompilerSet" user command. With "!" it does ":set", without "!" it does ":setlocal". - Execute ":runtime! compiler/{name}.vim". The plugins are expected to set options with "CompilerSet" and set the "current_compiler" variable to the name of the compiler. - Delete the "CompilerSet" user command. - Set "b:current_compiler" to the value of "current_compiler". - Without "!" the old value of "current_compiler" is restored.
compiler/{name}.vim
を読んでみると、makeprg
(:make
が発効されたときのコマンド)とerrorformat
が設定されているようだ。 errorformatを自分で書くときののexampleとしても役立つ。
参考
:help runtime
:help compiler
:help current_compiler
:help makeprg
gitでコミット時にコードをフォーマットしてからコミットする
上記事によると
for FILE in `git diff --staged --name-only | grep .php`; do # ここで言語に応じたなんらかのフォーマット処理 git add $FILE done
が提案されているが、ステージングエリアにdeletedがあると formatter の引数にに存在しないファイルが渡されて、 formatterによってはnon-zero exit codeが帰ってきてしまいcommitが行えない (例えば、pythonのフォーマッタ yapf はエラーコードを返す)。
deletedはフォーマットする必要はないので、diffコマンドにフィルタ --diff-filter
を追加し、Deletedは削ぎ落とす。その他Unknownも落としておいた。 git-diffのオンラインマニュアルを参照してほしい。
最終的に、yapfでフォーマットする場合は以下のスクリプトを実行権限付きで .git/hooks/pre-commit
に書けばよい。
for FILE in `git diff --staged --name-only --diff-filter=ACMRTUB | grep .py`; do yapf -i $FILE git add $FILE done
pytestでpytest-profilingを使っているときにでる ValueError: Plugin already registered
概要
$ make pytest if [ -z 1588034257 ] || [ 1587982138 -ge 1588034257 ]; then \ docker build . -t test; \ else \ echo "Docker container image is ready up to date."; \ fi Docker container image is ready up to date. docker run --rm -it test pytest --color=no tests/ Traceback (most recent call last): File "/usr/local/lib/python3.8/site-packages/_pytest/config/__init__.py", line 495, in _importconftest return self._conftestpath2mod[key] KeyError: PosixPath('/test/conftest.py') During handling of the above exception, another exception occurred: Traceback (most recent call last): File "/usr/local/bin/pytest", line 8, in <module> sys.exit(main()) File "/usr/local/lib/python3.8/site-packages/_pytest/config/__init__.py", line 105, in main config = _prepareconfig(args, plugins) File "/usr/local/lib/python3.8/site-packages/_pytest/config/__init__.py", line 257, in _prepareconfig return pluginmanager.hook.pytest_cmdline_parse( File "/usr/local/lib/python3.8/site-packages/pluggy/hooks.py", line 286, in __call__ return self._hookexec(self, self.get_hookimpls(), kwargs) File "/usr/local/lib/python3.8/site-packages/pluggy/manager.py", line 93, in _hookexec return self._inner_hookexec(hook, methods, kwargs) File "/usr/local/lib/python3.8/site-packages/pluggy/manager.py", line 84, in <lambda> self._inner_hookexec = lambda hook, methods, kwargs: hook.multicall( File "/usr/local/lib/python3.8/site-packages/pluggy/callers.py", line 203, in _multicall gen.send(outcome) File "/usr/local/lib/python3.8/site-packages/_pytest/helpconfig.py", line 90, in pytest_cmdline_parse config = outcome.get_result() File "/usr/local/lib/python3.8/site-packages/pluggy/callers.py", line 80, in get_result raise ex[1].with_traceback(ex[2]) File "/usr/local/lib/python3.8/site-packages/pluggy/callers.py", line 187, in _multicall res = hook_impl.function(*args) File "/usr/local/lib/python3.8/site-packages/_pytest/config/__init__.py", line 836, in pytest_cmdline_parse self.parse(args) File "/usr/local/lib/python3.8/site-packages/_pytest/config/__init__.py", line 1044, in parse self._preparse(args, addopts=addopts) File "/usr/local/lib/python3.8/site-packages/_pytest/config/__init__.py", line 1001, in _preparse self.hook.pytest_load_initial_conftests( File "/usr/local/lib/python3.8/site-packages/pluggy/hooks.py", line 286, in __call__ return self._hookexec(self, self.get_hookimpls(), kwargs) File "/usr/local/lib/python3.8/site-packages/pluggy/manager.py", line 93, in _hookexec return self._inner_hookexec(hook, methods, kwargs) File "/usr/local/lib/python3.8/site-packages/pluggy/manager.py", line 84, in <lambda> self._inner_hookexec = lambda hook, methods, kwargs: hook.multicall( File "/usr/local/lib/python3.8/site-packages/pluggy/callers.py", line 208, in _multicall return outcome.get_result() File "/usr/local/lib/python3.8/site-packages/pluggy/callers.py", line 80, in get_result raise ex[1].with_traceback(ex[2]) File "/usr/local/lib/python3.8/site-packages/pluggy/callers.py", line 187, in _multicall res = hook_impl.function(*args) File "/usr/local/lib/python3.8/site-packages/_pytest/config/__init__.py", line 899, in pytest_load_initial_conftests self.pluginmanager._set_initial_conftests(early_config.known_args_namespace) File "/usr/local/lib/python3.8/site-packages/_pytest/config/__init__.py", line 441, in _set_initial_conftests self._try_load_conftest(anchor) File "/usr/local/lib/python3.8/site-packages/_pytest/config/__init__.py", line 447, in _try_load_conftest self._getconftestmodules(anchor) File "/usr/local/lib/python3.8/site-packages/_pytest/config/__init__.py", line 473, in _getconftestmodules mod = self._importconftest(conftestpath) File "/usr/local/lib/python3.8/site-packages/_pytest/config/__init__.py", line 520, in _importconftest self.consider_conftest(mod) File "/usr/local/lib/python3.8/site-packages/_pytest/config/__init__.py", line 575, in consider_conftest self.register(conftestmodule, name=conftestmodule.__file__) File "/usr/local/lib/python3.8/site-packages/_pytest/config/__init__.py", line 386, in register self.consider_module(plugin) File "/usr/local/lib/python3.8/site-packages/_pytest/config/__init__.py", line 581, in consider_module self._import_plugin_specs(getattr(mod, "pytest_plugins", [])) File "/usr/local/lib/python3.8/site-packages/_pytest/config/__init__.py", line 586, in _import_plugin_specs self.import_plugin(import_spec) File "/usr/local/lib/python3.8/site-packages/_pytest/config/__init__.py", line 629, in import_plugin self.register(mod, modname) File "/usr/local/lib/python3.8/site-packages/_pytest/config/__init__.py", line 379, in register ret = super().register(plugin, name) File "/usr/local/lib/python3.8/site-packages/pluggy/manager.py", line 104, in register raise ValueError( ValueError: Plugin already registered: pytest_profiling=<module 'pytest_profiling' from '/usr/local/lib/python3.8/site-packages/pytest_profiling.py'> {'140074314182224': <_pytest.config.PytestPluginManager object at 0x7f6597bd2e50>, 'pytestconfig': <_pytest.config.Config object at 0x7f6597170220>, 'mark': <module '_pytest.mark' from '/usr/local/lib/python3.8/site-packages/_pytest/mark/__init__.py'>, 'main': <module '_pytest.main' from '/usr/local/lib/python3.8/site-packages/_pytest/main.py'>, 'runner': <module '_pytest.runner' from '/usr/local/lib/python3.8/site-packages/_pytest/runner.py'>, 'fixtures': <module '_pytest.fixtures' from '/usr/local/lib/python3.8/site-packages/_pytest/fixtures.py'>, 'helpconfig': <module '_pytest.helpconfig' from '/usr/local/lib/python3.8/site-packages/_pytest/helpconfig.py'>, 'python': <module '_pytest.python' from '/usr/local/lib/python3.8/site-packages/_pytest/python.py'>, 'terminal': <module '_pytest.terminal' from '/usr/local/lib/python3.8/site-packages/_pytest/terminal.py'>, 'debugging': <module '_pytest.debugging' from '/usr/local/lib/python3.8/site-packages/_pytest/debugging.py'>, 'unittest': <module '_pytest.unittest' from '/usr/local/lib/python3.8/site-packages/_pytest/unittest.py'>, 'capture': <module '_pytest.capture' from '/usr/local/lib/python3.8/site-packages/_pytest/capture.py'>, 'skipping': <module '_pytest.skipping' from '/usr/local/lib/python3.8/site-packages/_pytest/skipping.py'>, 'tmpdir': <module '_pytest.tmpdir' from '/usr/local/lib/python3.8/site-packages/_pytest/tmpdir.py'>, 'monkeypatch': <module '_pytest.monkeypatch' from '/usr/local/lib/python3.8/site-packages/_pytest/monkeypatch.py'>, 'recwarn': <module '_pytest.recwarn' from '/usr/local/lib/python3.8/site-packages/_pytest/recwarn.py'>, 'pastebin': <module '_pytest.pastebin' from '/usr/local/lib/python3.8/site-packages/_pytest/pastebin.py'>, 'nose': <module '_pytest.nose' from '/usr/local/lib/python3.8/site-packages/_pytest/nose.py'>, 'assertion': <module '_pytest.assertion' from '/usr/local/lib/python3.8/site-packages/_pytest/assertion/__init__.py'>, 'junitxml': <module '_pytest.junitxml' from '/usr/local/lib/python3.8/site-packages/_pytest/junitxml.py'>, 'resultlog': <module '_pytest.resultlog' from '/usr/local/lib/python3.8/site-packages/_pytest/resultlog.py'>, 'doctest': <module '_pytest.doctest' from '/usr/local/lib/python3.8/site-packages/_pytest/doctest.py'>, 'cacheprovider': <module '_pytest.cacheprovider' from '/usr/local/lib/python3.8/site-packages/_pytest/cacheprovider.py'>, 'freeze_support': <module '_pytest.freeze_support' from '/usr/local/lib/python3.8/site-packages/_pytest/freeze_support.py'>, 'setuponly': <module '_pytest.setuponly' from '/usr/local/lib/python3.8/site-packages/_pytest/setuponly.py'>, 'setupplan': <module '_pytest.setupplan' from '/usr/local/lib/python3.8/site-packages/_pytest/setupplan.py'>, 'stepwise': <module '_pytest.stepwise' from '/usr/local/lib/python3.8/site-packages/_pytest/stepwise.py'>, 'warnings': <module '_pytest.warnings' from '/usr/local/lib/python3.8/site-packages/_pytest/warnings.py'>, 'logging': <module '_pytest.logging' from '/usr/local/lib/python3.8/site-packages/_pytest/logging.py'>, 'reports': <module '_pytest.reports' from '/usr/local/lib/python3.8/site-packages/_pytest/reports.py'>, 'faulthandler': <module '_pytest.faulthandler' from '/usr/local/lib/python3.8/site-packages/_pytest/faulthandler.py'>, 'profiling': <module 'pytest_profiling' from '/usr/local/lib/python3.8/site-packages/pytest_profiling.py'>, 'capturemanager': <CaptureManager _method='fd' _global_capturing=<MultiCapture out=<FDCapture 1 oldfd=5 _state='started' tmpfile=<_pytest.capture.EncodedFile object at 0x7f6596ed0220>> err=<FDCapture 2 oldfd=6 _state='started' tmpfile=<_pytest.capture.EncodedFile object at 0x7f6596ed02b0>> in_=<FDCapture 0 oldfd=3 _state='started' tmpfile=<_io.TextIOWrapper name='/dev/null' mode='r' encoding='UTF-8'>> _state='started' _in_suspended=False> _capture_fixture=None>, '/test/conftest.py': <module 'conftest' from '/test/conftest.py'>} make: *** [Makefile:26: pytest] Error 1/conftest.py'>} make: *** [Makefile:26: pytest] Error 1
とりあえずpytest-profilingを無効にして、testを行えるようにしようと思ったが、conftest.pyを消してdockerイメージをビルドしても直らなかった。
.pyc
をすべて消す方法は効かなかった
https://github.com/pytest-dev/pytest/issues/3112#issuecomment-404979798
Docker imageを消してから作り直してみても効かなかった
dangling image を消して再度pytestを動かしたら治った
$ docker image prune
疑問
docker rmi
では解決せず、docker image prune
では解決したことから、原因は中間イメージレイヤの変更であると考えられるdocker rmi
では中間イメージレイヤは削除されないと仮定するとこういう演繹ができる
しかし、中間レイヤは読み込み専用のはず
- ファイルを変更するたびに毎回イメージをビルドし直す方法をとっていたが、Dockerfileの
COPY
コマンド以降にはENV
コマンドしかないのでファイルシステムに変更はないはず - なぜ中間イメージレイヤが変更されたのか?
- 再度conftest.pyを配置してイメージをビルドしても同じエラーが出た。以前は使用可能だった。
2020-04-28 13:40 追記
- conftest.pyを消去してもprofileは動作したので、
If a plugin is installed, pytest automatically finds and integrates it, there is no need to activate it.
や
Requiring plugins using a pytest_plugins variable in non-root conftest.py files is deprecated. See full explanation in the Writing plugins section.
が関係しそう。conftest.pyはrootに配置しているはずではあるが。
Linux CLIでWi-Fiをする関係のまとめ
Prerequisites
- Raspbian
- wpa_supplicant
- dhcpcd
困ったら
sudo systemctl restart dhcpcd
primitiveにやる
- wpa_cli
$ wpa_cli interface $ wpa_cli interface [ifname] $ add_network 0 set_network 0 ssid "SSID" set_network 0 psk "passphrase" enable_network 0
dhcpcd ${interface}
またはdhclient
アクセスポイントへの接続状況を見る
- iw dev ${devname} link
VNCでOpenGL APplicationsを飛ばす on Ubuntu16.04 with Nvidia GPU
VNCでOpenGL APplicationsを飛ばす on Ubuntu16.04 with Nvidia GPU
考え方
手順概要
初期設定手順
$ sudo apt install -y turbovnc virtualgl $ vi ${HOME}/.vnc/xstartup.turbovnc # xfceが立ち上がるように書いたが、おそらくなんでもよい $ cat ${HOME}/.vnc/xstartup.turbovnc # WMを探すコードを取り除き、xfceを起動する行を追加。Gnomeのなにかがあり、これは関係なさそうだがとりあえず残しておいた #!/bin/sh unset SESSION_MANAGER unset DBUS_SESSION_BUS_ADDRESS XDG_SESSION_TYPE=x11; export XDG_SESSION_TYPE # This works around pointer disappearance issues under GNOME 3 if [ -x /usr/bin/dconf ]; then dconf write /org/gnome/settings-daemon/plugins/cursor/active false fi OS=`uname -s` if [ $OS = 'Linux' ]; then case "$WINDOWMANAGER" in *gnome*) if [ -e /etc/SuSE-release ]; then PATH=$PATH:/opt/gnome/bin export PATH fi ;; esac fi startxfce4 $ sudo nvidia-xconfig $ /opt/VirtualGL/bin/vglserver_config # ウィザードに従って設定をする $ systemctl restart lightdm # このへんで適当にDMを再起動。意味があるのかは不明。
つかいかた
- リモートマシンにログインし、vncserverコマンドを実行する
- Xorgが起動しているかを確認する (ある環境の場合、lightdmが正しく起動しているか確認する)
/opt/TurboVNC/bin/vncserver :2 # :2の部分は適当に変更する。lightdmが何故か:1で起動するようになってしまい、ちょっときもちわるい。
- クライアントマシンからVNC Client App でリモートマシンに接続
- URI: ${remote machine IP address}:${Display Number (e.g. :2)}
- いくつかのアプリではポート番号はポート番号を指定しないといけないかも。デフォルトだと5900 + (display number)
- リモートデスクトップ上でターミナルを開き、vglrunを通してコマンドを実行
vglrun ${application}
感想
- Gazeboをremoteで動かしてrender結果を(リアルタイムに)localに持ってきたかった
- Gazeboはそれ自体がサーバー・クライアント分離に対応しているが、サーバのGazeboとクライアントのGazeboのバージョンが完全に一致していないといけない。Debianの公式リポジトリとUbuntuの公式リポジトリのバージョンが合うことは(ほぼ)無いので、しんどい。
- Gazeboのサーバ・クライアントが通信するにはhttps://wiki.ros.org/ROS/NetworkSetupが必要っぽいので、remote serverでdockerコンテナを動かす方法は簡 単には行かない(ソースはROSの話だがGazeboも一緒だろう)。
- VNCで持ってこようとするとOpenGLが使えなくてなんとかと言われるので、VirtualGLを入れるなどしていろいろやるが、"Xlib: extension "GLX" missing on display ":1""と言われてGazeboが一瞬起動して死ぬ
- (こちらのローカルなミスで) xorg.confが消えていた(正確に言うとバックアップしか残っていなかった)ので、GLとWindowの連携が不可能だったと思われる。
- nvidia-xconfigコマンドでxorg.confを再生成して解決。