
接続済み SSH セッションからファイルをダウンロードする というエントリを2012年ぐらいに書いて、その中で uutransfer という、screen ウィンドウを通じて uuencode したファイルを転送して書きだすツールを紹介しました。
便利に使っていたんですが、最近 tmux に移行した ので、このツールが動かなくなって困りました。ということで書きなおして独立したレポジトリに移動しました。

接続済み SSH セッションからファイルをダウンロードする というエントリを2012年ぐらいに書いて、その中で uutransfer という、screen ウィンドウを通じて uuencode したファイルを転送して書きだすツールを紹介しました。
便利に使っていたんですが、最近 tmux に移行した ので、このツールが動かなくなって困りました。ということで書きなおして独立したレポジトリに移動しました。
ITU-T G.227 にあるフィルタを実装して、無線機の特性試験の試験方法に登場する「疑似音声信号発生器」を WebAudio で作ってみる。
Conventional Telephone Signal という名前の勧告。伝達関数が書いてある。600Hz ぐらいにピークのあるフィルタになっている。
ホワイトノイズをこのフィルタに通すことによって疑似音声となる。なので、この周波数特性を持つフィルタを設計する。
フィルタの知識がないので、試行錯誤しながら以下のようにすすめていった。
結論からいえば、今回の場合はアナログフィルタの伝達関数が示されているので、そこからデジタル IIR フィルタに変換するのが一番良かった (と思う)
求めるのは Jupyter Notebook 上で行なった。
FIR フィルタは周波数特性がわかっていれば IFFT で作ることができる。ほぼ何も考えずに作れる。
最初は対称をつくらず IFFT して、最後に実数だけとるのを作った。
フィルタを左右対称にすればほぼ実数フィルタになるはずだが、低域の減衰が急峻すぎるせいかこれでも虚数が出てきてしまう。しかたないのでこのまま虚数を捨てて実数フィルタとして評価した。
まぁまぁうまくいくけど、かなり重くなってしまう。そして、それなりに G.227 の特性から誤差が発生して気持ちがわるい。FIR なので次数を増やせばそれだけ近似はできるが、どんどん重くなっていく。
なお FIR フィルタを WebAudio で使いたい場合は、ConvolverNode を使えば良い。
↑補正なし↓補正
アナログフィルタ(周波数連続という意味)からデジタルフィルタ(離散という意味)をつくる方法の一つに双一次変換がある。scipy で簡単にできるので、これを試す。
今回の場合、アナログの伝達関数はわかっているので、この規格に書いてある伝達関数を双一次変換してIIRフィルタの係数を得る。つまり以下を変換してデジタルフィルタを得たい。
なぜ微妙に括弧がついてるのかわからないが、結局これは次数ごとに書きなおすと見なれた以下の形になる。ほぼ scipy.signal.freqs などが受けとる形になっている。4次。
ただ、p が なので、これを角周波数 をとる関数に変えたい。
python で上記通り係数計算して、signal.bilinear() に渡してあげると、デジタルフィルタの係数になる。ただ、双一次変換は周波数歪みが起こるので、完全にアナログフィルタの特性と一致するわけではない。
こういう場合どうするのかよくわからなかったが、次数の少ない FIR で容易に補正できそうだったため、アナログフィルタの周波数特性との差分をとって補正する FIR フィルタを追加で設計する。
IIR フィルタを WebAudio で使う場合は IIRFilterNode を使えば良い。feedForward に分子 feedBack に分母の係数を渡せば動いてくれる。
ということでできたのが冒頭にリンクしたレポジトリとなる。https://github.com/cho45/pseudo-audio-signal
裏面に WeAct と書いてあった。
何もせずそのまま USB に繋ぐとシリアルポートとして認識される。
Bus 020 Device 025: ID 0483:5740 STMicroelectronics STM32 Virtual ComPort
00:01:10,04012019 VrefintAdc: 1.2133V TempSensorAdc: 24.75C FlashID:0 ERROR!
こういう出力がずっと流れている。
この MCU は System Memory という領域を持っており、ブートローダーが最初から書きこまれている。詳細は AN2606
USB 経由で DFU するには、基板上の BOOT0 を押しながら、NRST を押せば良い。
Bus 020 Device 008: ID 0483:df11 STMicroelectronics STM32 BOOTLOADER Serial
として認識される。
https://docs.platformio.org/en/latest/boards/ststm32/blackpill_f401cc.html
blackpill_f401cc というのがある。たぶんこれなので、一旦これで試す。
platformio init --board=blackpill_f401cc
残念ながら mbed framework が使えないみたいなので、一旦 arduino でいく src/main.cpp
#include "Arduino.h"
#ifndef LED_BUILTIN
#define LED_BUILTIN 13
#endif
void setup() {
pinMode(LED_BUILTIN, OUTPUT);
}
void loop() {
digitalWrite(LED_BUILTIN, HIGH);
delay(500);
digitalWrite(LED_BUILTIN, LOW);
delay(500);
} pio run
.pio/build/blackpill_f401cc/firmware.bin ができるので、BOOT0 を押しながら NRST を押し、USB DFU モードにする。この状態で dfu-util で書きこめる。
dfu-util -d 0483:df11 -a 0 -s 0x08000000:leave -D .pio/build/blackpill_f401cc/firmware.bin
とりあえず mbed のほうが好みなので mbed を使えるようにしてみる。こういうことするとハマりやすいのであまりよくないが…
403 Forbidden に従いながらカスタムボードを定義する。
platformi.ini
[env:f401cc] platform = ststm32 board = f401cc framework = mbed build_flags = -I$PROJECTSRC_DIR/TARGET_F401CC
boards/f401cc.json
# https://github.com/platformio/platform-ststm32/blob/develop/boards/blackpill_f401cc.json をコピペ
custom_targets.json https://github.com/ARMmbed/mbed-os/blob/e1c3de649dd9c16d9548f73b4bbb71858af904f7/targets/targets.json#L4834 から抜き出してコピペ
{
"F401CC": {
"inherits": ["FAMILY_STM32"],
"core": "Cortex-M4F",
"default_toolchain": "GCC_ARM",
"extra_labels_add": [
"STM32F4",
"STM32F401",
"STM32F401xC",
"STM32F401VC"
],
"supported_toolchains": ["GCC_ARM"],
"device_has_add": ["MPU"],
"device_name": "STM32F401CC"
}
} cp -r ~/.platformio/packages/framework-mbed/targets/TARGET_STM/TARGET_STM32F4/TARGET_STM32F401xC/TARGET_DISCO_F401VC src/TARGET_F401CC
#include "mbed.h"
DigitalOut led(PC_13);
int main() {
for (;;) {
led = 1;
wait(0.2);
led = 0;
wait(0.2);
}
} これで pio run が走って .pio/build/f401cc/firmware.bin ができるはず。
time dfu-util -d 0483:df11 -a 0 -s 0x08000000:leave -D .pio/build/f401cc/firmware.bin
で書きこみ。
別表第35とかに出てくる「標準符号化試験信号」の生成について調べた。
擬似信号発生器は、標準符号化試験信号(ITU-T勧告O.150による9段PN符号)を発
と書いてある。
生させる。
ITU-T O.150 は n 段(stage)のシフトレジスタで構成されるテスト用の疑似乱数列について定義している。n段の符号はnビットのシフトレジスタに対応する。
具体的な生成方法は wikipedia の LFSR を読むのがわかりやすい。
「4.1 511-bit pseudo-random test pattern」となっているところが9段のもの。
「The pattern may be generated in a nine-stage shift register whose 5th and 9th stage outputs are added in a modulo-two addition stage, and the result is fed back to the input of the first stage. The pattern begins with the first ONE of 9 consecutive ONEs.」と文章で書いてある。
5th and 9th と書いてあるところが帰還多項式に対応しており、この場合
以下のような任意のビット数(ただし32ビット以下)の LFSR のコードを書いた。全ビットが0でない限りは最大周期で全ての状態が出現する。
/**
* Linear-feedback shift register
*
* reg: n bits register state
* n: Bits(n) (up to 32bits)
* taps: feedback polynomial (eg. x^16 + x^14 + x^13 + x^11 + 1 => [16, 14, 13, 11])
* ref. https://en.wikipedia.org/wiki/Linear-feedback_shift_register
*/
function LFSR(reg, n, taps) {
const mask = n === 32 ? (-1>>>0) : (1 << n) - 1;
reg &= mask;
const bit = taps.
map( (tap) => reg >> (n - tap) ).
reduce( (r, i) => r ^ i ) & 1;
return ( (reg >>> 1) | ( bit << (n-1) ) ) & mask;
}
const start = 511;
let lfsr = start;
let period = 0;
do {
lfsr = LFSR(lfsr, 9, [9, 5]);
console.log('output:', lfsr>>(9-1), 'internal:', (lfsr | (1<<9)).toString(2).slice(1));
period++;
} while(lfsr !== start);
console.log('this feedback polynomial period:', period); ちょっと困ったことが起きており、一昨日からワンオ… | Fri, Oct 11. 2019 - 氾濫原 書いてからワンオペしてたがとりあえず終わった。
入院する前、調子を崩して家にいる状態だと、保育園から毎日毎日「何の病気なのか」と聞かれ続け、知らねーよ判ったら苦労しねーよと内心苛立っていたが、とりあえずそれがなくなってストレスは一つ減った。
生活品を届けにいったとき先生から説明をうける。ハッキリ原因がわからないので、安全な治療からはじめて、それがいつまでにうまくいかなかったら次はこうする、という方針を聞く。洒落ためがねをしていて頭が良さそう(医者なんだからもちろんそうなのだが、その上で)とぼーっと考えていた。
運悪く、保育園の弁当を持ってこいイベントが発生間近であり、まぁ冷凍食品のからあげを詰めたり、梨を剥いて詰めたりしてしのいだ。からあげは大変好評であった。
その間に台風19号があって避難したりして、なかなか面倒に。一人親の苦労ってのは責任が単一にかかるってのもあるよなあとか、大人が一人だけだと満足にトイレもいけないなとかいろいろ考えさせられる。子どもが5歳で良かったとか、近くに (妻方の) 親戚がいたので助かったとか思った。
台風後に子どもが発熱。幸い機嫌は良く、一日経ったら解熱して問題なかった。
病院は12歳以下の面会はお断りなので、あまり子どもをつれてお見舞いにいくという感じではない。そういえばと思ったのでテレビ電話で通話。子どもは喜んでたみたい。テクノロジー。
洗濯物は仕舞うのが面倒なので山積みにして (山になるほどではないが)、宝探しだぞと子どもに探させた。割と楽しくて一石二鳥
週があけて入院診療計画書が渡された。事前に主治医から聞いた内容が文書になった感じ。週単位の入院計画でなかなか暗い気持ちにはなる。
と思ったら翌日に、経過がよければ次の週末に退院の予定となる。一回説明するから来てくださいと言われたので (必要なの?とは思いつつ) 早退して聞きにいった。部屋で座って説明されることになって、重病なのか?と不安になったがそういうわけではなく、ものすごく丁寧な先生というだけだった。紙に図解付きで明確に説明されるので、資料作りながらプレゼンしてる感じですごいな〜と考えてた。
Android で外部キーボード使用時の日本語入力を快適にする (SKK) | tech - 氾濫原 というのを書いたが、設定できない部分で自分にあわない挙動があったので、fork して変更した。
以下の点だけ
GitHub Actions で自動ビルドするようにしてある。
Android では、アプリのサイズをできるだけ減らしたりするために、リリース前にアプリ全体のコードの最適化 (いわゆるツリーシェイキング) が推奨されている。動作としては、実行されるコードを解析で割り出しで、不要なコードを全て削除、というものになる。
基本的には minifyEnabled true を build.gradle に書けばよくて、簡単なアプリケーションなら、マニフェストから起動される Activity を解析してそこから呼ばれるクラスやメソッドは削除されないようになるので、これだけですむ。
が、リフレクションや JNI、または capacitor のように JavaScript のエンジンを一度経由して呼ばれるクラスなどは、この解析パスで到達できない。結果として、性質上、実行時にエラーが起こることになる。
capacitor の場合、JavaScript 経由で呼ばれるものには全て keep しておく必要がある。
-keep public class com.getcapacitor.plugin.App {
static *;
public *;
}
-keep public class com.getcapacitor.plugin.Device {
static *;
public *;
}
-keep public class com.getcapacitor.plugin.Filesystem {
static *;
public *;
}
-keep public class org.apache.cordova.CordovaPlugin
-keep public class fr.drangies.cordova.serial.**
-keepclasseswithmembers class com.hoho.android.usbserial.driver.** {
static *;
public *;
}
-printconfiguration /tmp/full-r8-config.txt
-printusage /tmp/usage.txt `-keep public class com.getcapacitor.plugin.Filesystem` だけだと名前が変わってしまう。ProGuard の指定方法がややこしつてよくわからなかったが、上記のようにしたらうまくいった。
cordovarduino という Cordova のプラグインを利用しているので、それ系の設定もある。
`-printusage` で指定したファイルには「削除された」クラスやメソッド名が出力される。必要なメソッドが意図せず削除されているかも?と思ったらこのファイルを見てみる。
手元にある Elecraft KX3 の測定をしてみる。
(ちなみに当局の KX3 は「平成17年12月以降にアマチュア局の保証を受けて免許を受けた無線機」に該当するのでスプリアス確認保証は不要、のはず)
以下を根拠に測定する
測定結果を提出データとして使うためには測定器(スペアナ)が1年以内に校正されていなければならないので、現実的に個人でこれを行うのは難しい。
しかしアマチュアであれば JARD に対してスペアナ(校正済みでなくてもよい) の測定結果をもって保証してもらうという手がある。
アマチュアの場合広い帯域を一括で免許をうけるので、どの周波数を使うのかと思うが、割り当て帯域幅によって異なり、帯域幅が1MHz以下なら指定周波数 (免許状に書いてある、周波数帯域の中央) で測定をすれば良いらしい。別表第35
ただし電波形式は免許を受けるすべての形式で行う必要がある。
スプリアス領域における不要発射等の測定方法の陸上関係無線設備(一般)にしたがう。
スペアナの設定のうちRBW, VBW, 検波モードが必ず指定された通りになっていることを確認すること。
探索したピークに周波数をあわせて振幅をはかる
面倒なので 40m (7100kHz) の CW だけでやる。変調をかけ最大送信電力にするということになっている。できるだけ厳しい条件でやるという意図だと思われるので、短点連続(帯域が最大)でやってみる。技適の手順だと25ボーとか、外部変調装置がある場合その最高速度みたいな手順みたいだが…
10W 7100kHz の場合、帯域外領域のスプリアス発射強度の許容値は 50mW (17dBm) 以下かつ、基本周波数の平均電力より40dB低い値。スプリアス領域での不要発射の強度の許容値は 50μW (-13dBm)以下。
必要周波数帯 (BN) は基本的に占有周波数帯幅の許容値と同値になるので CW の場合は 0.5kHz。スプリアス領域 は 2.5BN 離れた領域なため、7100±1.25kHz の外側がスプリアス領域。
7MHz の場合、基本波が9kHz〜100MHzのケースのためなのでスプリアスの測定範囲は 9kHz〜1GHz。ただし10倍高調波まで見る。
帯域外領域の測定を勘違いしていました。別表第一 スプリアス発射又は不要発射の強度の測定方法 によると帯域外領域は無変調で行うようです。
ということで撮りなおしました。(Ref Offset を40dBいれているので、直読できるようになってます)
以下の画像はキーイング状態なので正確な測定ではないです。
一旦必要周波数帯と帯域外発射を見る。帯域外発射の範囲は 7100±1.25kHz なので、7100kHz を CENTER にして 2.5kHz SPAN で見てみる。
「帯域外領域のスプリアス発射強度の許容値は 50mW 以下かつ、基本周波数の平均電力より40dB低い値。」基本周波数の平均電力より -64dB 低いので後者の条件は達成、10W は 40dBm なので、帯域外領域の発射強度は -24dBm。50mW は約17dBmなので達成している。
上下にあるので、下から見ていく。
下側 RBW=1kHz の範囲
なにもなさそう。
下側 RBW=10kHz の範囲
なにもなさそう。
上側 RBW=10kHz の範囲
高調波が出てる。40dBm -62 なので -22dBm。50μW (13dBm) 以下なので合格
RBW=100kHz の範囲
見つからず。
「ITU-R 勧告SM.329-10における指針」に従って、基本周波数の10倍高調波まで見れば良いことにはなっている。つまり 7MHz なら 70MHz まで見れば十分なはず。
スプリアス強度が許容値を超えていた場合はどのぐらい超えたかを確定させるため、スプリアス振幅測定を行う必要がある。
今回は超えていないがこれもやってみる。14.2MHz を CENTER にして、ゼロスパンにする。
1Fに住んでいて、ハザードマップでは最悪2mの浸水、ということは事前に調べてあった。土曜日10時ごろには既に、浸水地域に対してエリアメールで警戒レベル4が出た。実際まだ上陸まで時間がだいぶあるのに多摩川の水位が非常に上がっていた。子どももいるので暴風域に入ってから移動はしたくないし、万が一のときマンションの階段をかけのぼるのもあまりやりたくない。とかいろいろ考えた結果避難を決断。11時ごろに傘がさせる程度の雨の中避難所に (かっぱは着てたが)。
避難したことがなかったので、ちゃんと避難所が開設されているのか不安だったが一応開いていた。一旦かなり狭い部屋に案内されたあと、人が増えてきたので体育館が解放された。
そこで近くに住む妻方の親戚も避難してきて合流。食料や貴重品に不安があったので、子どもを親戚にあずけて一旦帰宅。短時間にだいぶ風雨が強くなっており、往復だけでずぶぬれに。
ところで避難所も浸水地域のため、体育館も安全ではなく、加えてさらに避難者が増えていたので、全体的に体育館は使わず、校舎内の一定階数以上を使うようにと再三の変更があった。
小学校側の担当者と市の担当者がいるみたいで、若干せめぎあいがあるみたいだった。小学校側としては児童のものがあり授業の円滑な継続のためには教室などは解放したくないようだった。当初は特別教室しか解放されていなかったが、増え続ける避難者に対して足りなくなり解放されていた。
21時ぐらいに台風が最接近して、急激に納まっていった。風雨の状況が全くわからない場所にいたので、そのへんの恐怖感は全くなかった。22時ぐらいから帰りはじめる避難者もいた。24時ぐらいにはほぼ完全に風雨がおさまっていたが、子どもが寝ていたし自宅の状況もわからないし、水位も下がりきっているわけではないので、そのまま明るくなるのを待った。
結局何事もなく、停電も断水も浸水もなかった。影響ある地点は越水まで1m程度でなんとか決壊しなかった。治水事業に感謝。
避難は結果的には辛いだけで無駄だったが、判断自体は間違いではなかったと思いたい。ただ避難先はもっと先に考えといたほうがよかった。漠然と公設避難所と思っていたが、これはかなり厳しいなと思った。ホテルとかに避難できればたぶんベストだと思った。
ちょっと困ったことが起きており、一昨日からワンオペ。
普段ルーチンに入っていないので、一番面倒なのが食事。平日は朝食だけ用意すれば良い。もともと延長保育にしてもらっているので昼食・夕食は保育園で出してくれる。休日はまだ考えてない。
洗濯ものは自分と子供だけなら洗ったものを着るという単純ローテできるので、実用上は別に仕舞う必要がなく、洗って乾燥したのを出しておくだけでなんとかなる。もともと洗濯・乾燥まではルーチンに入っているので困ったことは起きない。
掃除はもともと気になったときにしかやってないので負荷は増えない。床面はルンバがある程度綺麗に保ってくれる。あとはコードレス掃除機でさっとやるぐらい。
子どもは習いごと、勉強を見るのがそこそこ時間をとる。
まぁもう5歳になると結構聞きわけある年齢だし、やることやったら何やっててもいいルールにしていると、一人でゲームやったりして、その間は手があけられるのはありがたい。事情を話せばある程度はわかってくれるし、なんなら洗濯物とかを手伝ってくれてありがたい。
前回 に引き続き NiZ のキーマップをごにょごにょする。
とりあえず表題の通り、キーマップの書きかえまではできた。
#!/usr/bin/env ruby
require "./niz.rb"
require 'progress_bar'
override_mapping = lambda do |mapping|
# mapping[level][key_id] = hwcode
# level:
# 0: normal
# 1: Right Fn
# 2: Left Fn
# key_id: 1-66
# hwcode: See ./niz.rb HWCODE constant
mapping[0][61] = 68 # Set key_id 61 (right side of space) = 68 (super)
mapping[0][62] = 71
mapping[0][63] = 74
end
#################################################################
niz = NiZ.new
Timeout.timeout(1) do
begin
niz.open
rescue => e
$stderr.puts "#{e.inspect} retrying open device..."
retry
end
end
puts "Version: #{niz.version}"
puts "#{niz.keycount} keys"
puts "Reading key mapping..."
progress = ProgressBar.new(niz.keycount * 3)
read_all = niz.read_all do |count, keymap|
progress.increment!
end
mapping = NiZ.mapping_from_array(read_all)
override_mapping[mapping]
puts "Writing key mapping..."
progress = ProgressBar.new(niz.keycount * 3)
niz.write_all(mapping) do |count|
progress.increment!
end
キーマップの書きかえコマンドを送ると、まず既存のキーマップが全てリセットされるみたい。つまり、プロトコル的には一部のキーだけを書きかえということはできない。常に全部のキーマップを送信する必要がある。
なので、一部の書きかえを実現したいのであれば、
という手順になる。
NiZ は内部的にキーに対応する数値を HWCODE という名前で持っている。このコードは USB HID の scan code や、multi media キーや、その他いろいろな機能キーを一意に特定するものになっている。HWCODE は ASCII や Usage とまったく別の規則で割り当てられているようで、マッピングは気合で作るしかない。
気合で作るしかないので、おおむね作った。https://github.com/cho45/niz-tools-ruby/blob/master/niz.rb#L13 ということで、ここを読んでいる良い子のみんなは気合を入れる必要がなくなった。
自分で使わないのでまったく調べてない。マクロ登録用のコマンドがあるっぽい。
CorvusSKK にしてみた。Ctrl-SPC で IME のオン・オフをしたいので、設定する。
「キー0」タブが IME の ON/OFF 用のキーを設定する画面になっている。スペースキーは 0x20 なので、0x20 と入力して修飾キーとして CTRL を選択し、ON と OFF それぞれについてキーを追加する。
順番にどういう意味があるかわかってないけど、一応一番上にしておいた。こういう感じに。
https://play.google.com/store/apps/details?id=jp.kcm.thumbctrl.en.layout これを入れて、レイアウトから Caps Lock -> Ctrl 置き換えする。いろいろレイアウトが追加されるけど、とりあえずこれで良い。
http://ray-mizuki.la.coocan.jp/software/skk_jp.html SKK for Android を apk から入れて、設定する
これでほぼ違和感なく入力できる。ただ、SKK for Android には RET したとき改行しない設定がないので、ちょっと気をつけて入力する必要がある。
JRE込みのPyCharmで日本語入力がおかしい · Issue #24 · codefirst/aquaskk · GitHub この問題と同じだと思う。
どうも JDK のバージョンによって変な挙動になるらしい。ので、Android Studio の bundled JDK を使うのをやめる。
Selecting the JDK version the IDE will run under – IDEs Support (IntelliJ Platform) | JetBrains この手順に従う
Shift 連打とかで Choose Runtime... のダイアログを出す。
適当に 1.8.0 の JDK を選んで Install ボタンを押すと勝手に再起動する。
これでおわり。
なんとなく AdoptOpenJDK 11 を入れて指定したら、起動しなくなってしまった。起動しないので Choose Runtime も使えない。
macOS の場合 ~/Library/Preferences/AndroidStudio3.5 以下に設定ファイルがある。~/Library/Preferences/AndroidStudio3.5/studio.jdk というファイルがあるので、これを消せばデフォルトの JDK に戻すことができる。