ただの時報
https://play-morse.lowreal.net/jiho.html
むかーーし作った時報のコードを発掘した。今なら Voicevox つけたらちゃんと喋る時報にできるぞと思ったのでガっとやった。正午だけ特殊なのでレアです。
短波JJYの再現
https://play-morse.lowreal.net/vhf-jjy.html
VHF JJYの再現スクリプトのほうも時報音声を入れるようにした。こっちは10分ごとにしか喋らないのでレアです。
https://play-morse.lowreal.net/jiho.html
むかーーし作った時報のコードを発掘した。今なら Voicevox つけたらちゃんと喋る時報にできるぞと思ったのでガっとやった。正午だけ特殊なのでレアです。
https://play-morse.lowreal.net/vhf-jjy.html
VHF JJYの再現スクリプトのほうも時報音声を入れるようにした。こっちは10分ごとにしか喋らないのでレアです。
Wikipedia の LDPC の項だけ読むとそんな難しくなさそうに見えるけど、実際に実装しようと思うと、むちゃくちゃ難しい。
LDPC符号の設計では、性能に優れたパリティ検査行列(H行列)を用意するのがまず難しい。ここにいろんな要素がある。
数学的素養がないと難しすぎる。そして自力で設計するのは考えたくない。
そんなH行列、例え1つ設計できたとしても、任意のデータ長・符号化率を持つH行列をいくつも作ろうと思うと何倍も大変になってしまう。
そこで Protograph (原始グラフ) という性質の良い原型となるような小さなグラフをまず設計し、それを何らかの方法で拡大して任意の大きさのH行列を得るという設計方法がある。
パンクチャリングは性質の良いH行列を使うために,多少の計算効率を犠牲にしつつ柔軟な送信ビット長/符号化率を得るための方法といえる
良い性質の Protograph を得られたとしても、それを拡大するプロセスには制約がある。整数倍の行列しか作れないとか。
そうなると求めるデータ長・符号化率ぴったりの行列というのは結局作れない。
これを解決するのがパンクチャリング。符号化率の低い(0.4など)のProtographを拡大し、欲しい符号化率 (0.5など)になるまでパリティビットの一部を送信しないことで、ちょうどいいサイズを作れる。
ぴったりよりも大きい行列を使うので計算コストは増えるが、高性能なH行列設計を流用できるという利点がある。
エンコードは既知の操作するだけやろ? という気持ちを打ち砕く。どっちも難しい。なんならデコードのほうが簡単かもしれない
performance.now() が monotonic (単調増加) なことを利用すると、システム時計の変化を比較的高精度に得られるなと思ったので、以下のようなClockMonitorクラスを作ってみた。
// ClockMonitor: システム時計の大幅な変更(NTP補正・手動変更等)を検知し、イベントを発行するクラス
// WebAudioやperformance.now()はmonotonicな経過時間だが、絶対時刻(Date.now())はシステム時計依存でジャンプすることがある
// そのため、performance.timeOrigin+performance.now()で絶対時刻を計算している場合、
// システム時計が変化しても自動で補正されない(ズレたままになる)
// このクラスは、定期的にDate.now()とperformance.timeOrigin+performance.now()の差分を監視し、
// 一定以上の差分が発生した場合に"clockchange"イベントを発行することで、
// 利用側がoffset等を補正できるようにする
class ClockMonitor extends EventTarget {
constructor({ threshold = 2000, interval = 1000 } = {}) {
super();
this.threshold = threshold; // 何ms以上の差分で検知するか
this.interval = interval; // 監視間隔(ms)
this.offset = performance.timeOrigin || 0; // performance.now()の起点(初期化時の絶対時刻)
this._timer = null;
}
start() {
if (this._timer) return;
this._timer = setInterval(() => {
const perfNow = performance.now();
const now = Date.now();
// 現在の絶対時刻の期待値(初期offset+経過時間)
const expected = this.offset + perfNow;
const diff = now - expected;
// threshold以上の差分が出たらシステム時計変更とみなす
if (Math.abs(diff) > this.threshold) {
// offsetを補正し、イベント発行
this.offset += diff;
this.dispatchEvent(new CustomEvent("clockchange", {
detail: { offset: this.offset, diff }
}));
}
}, this.interval);
}
stop() {
if (this._timer) {
clearInterval(this._timer);
this._timer = null;
}
}
} Date.now() を単に保持しておいて比較することでも、過去への遡りは検出できる。が、未来へ進むのは検出できない (ただのタイマーの遅れと区別できない)
問題点: performance.now() は monotonic ではあるがスリープで時間の連続性が失われることがある。
仕様上は連続することになっているが、一部の環境のブラウザだけ。