Open jucky154 opened 1 year ago
https://github.com/nextzlog/cw4i/blob/5dae69de1cc035755d3241c8c3db3a123de44e0a/core/decoder.go#L63-L82
をみると、next.Code == prev.Code
という前と今が同じ「Code」ならばmissが増える。
つまり、Scan関数が文字間の空白が最後に来ることが許されるのであれば
最後の文字が解読される
↓
文字間の空白が出るのでmissは増えない
↓
文字間の空白でそのままなのでmissが増える
↓
解読終了
という流れになっているはずなので、上のコードでいいはず(多分)
実際に実装すると
panic: runtime error: slice bounds out of range [:-1]
というエラーが出たlen(code)
の長さを考える必要があった
上のコードではよくなかったので、下のように修正
func CodeToText(code string) (result string) {
for _, s := range strings.Split(code, " ") {
if val, ok := reverse[s]; ok {
result += string(val)
} else {
result += "?"
}
}
if len(code) > 0 {
if code[len(code)-1:] != " " {
result = result[:len(result)-1]
}
}
return
}
実際の実働の動画が以下 https://github.com/nextzlog/todo/assets/58735989/36185382-b5ed-4055-a127-c894b3f79e93 確かに、ころころ変わるのは無くなったが、最後の文字が消えただけの状態
最後の文字が解読される
↓
文字間の空白が出るのでmissは増えない
↓
文字間の空白でそのままなのでmissが増える
↓
解読終了
という自分の仮定が誤りで、最後に空白がやってくると言うことがあり得ないと言うことだと思われるので、別の対処が求められる。
基本的には、現在の解析手法では最後の文字が正しいかどうかがわからない
Miss==0
の時には、前回と比較するとcode
が変わっている(最後の文字が変化したか、新しい文字が増えたかはわからないが、どちらにしろ最後の文字が正しくない)
Miss > 0
のときには、前回と比較するとcode
が同じであり、文字列として確定していると考えられる。
それを実装したのが以下のcode
func (d *Decoder) Read(signal []float64) (result []Message) {
for _, next := range d.Next(signal) {
for _, prev := range d.History {
if prev.Freq == next.Freq {
next = d.Scanner.Scan(prev.Merge(next))
if next.Code == prev.Code {
next.Miss = prev.Miss + 1
}
}
}
if d.Program != nil {
next = d.Program(next)
}
if next.Miss == 0 {
next.Text = next.Text[:len(next.Text)-1]
}
if next.Miss <= d.MaxMiss {
result = append(result, next)
}
}
d.History = result
return
}
https://github.com/nextzlog/todo/assets/58735989/5d403141-9a29-4ce7-9a63-d957538aea85
ただし、この手法だと無音から1周期必須であるので、最悪0.4秒遅れてしまう。
そのため、「文字間の空白」を正しく検知する方が正しい実装な気もする。
https://github.com/nextzlog/cw4i/blob/5dae69de1cc035755d3241c8c3db3a123de44e0a/core/segment.go#L17 の
for until, value := range m.X {
if class := m.Class(value); first != class {
result = append(result, Segment{
Class: first == 1,
Since: since,
Until: until,
Width: float64(until - since),
Level: med64(m.X[since:until]),
})
since = until
first = class
}
}
となっていることから、最後のところが空白にならないので
func CodeToText(code string) (result string) {
for _, s := range strings.Split(code, " ") {
if val, ok := reverse[s]; ok {
result += string(val)
} else {
result += "?"
}
}
if len(code) > 0 {
if code[len(code)-1:] != " " {
result = result[:len(result)-1]
}
}
return
}
では正しく表示されなかった。 現状のコードの良さは今聴いている音が短音なのか長音を区別してから解析されるので、新語調法的な流れで表示がすすむ。 しかし、最後の文字を消すのであれば関係ないので、
for until, value := range m.X {
if class := m.Class(value); first != class {
result = append(result, Segment{
Class: first == 1,
Since: since,
Until: until,
Width: float64(until - since),
Level: med64(m.X[since:until]),
})
since = until
first = class
}
}
result = append(result, Segment{
Class: first == 1,
Since: since,
Until: until,
Width: float64(until - since),
Level: med64(m.X[since:until]),
})
と最後につけておいて、最後の空白が出るようにする?
func (m *Classes) Segments(first int) (result []Segment) {
since := 0
for until, value := range m.X {
if class := m.Class(value); first != class {
result = append(result, Segment{
Class: first == 1,
Since: since,
Until: until,
Width: float64(until - since),
Level: med64(m.X[since:until]),
})
since = until
first = class
}
class := m.Class(value)
if until == len(m.X) -1 && since != until && class == 0{
result = append(result, Segment{
Class: first == 1,
Since: since,
Until: until,
Width: float64(until - since),
Level: med64(m.X[since:until]),
})
}
}
if len(result) > 2 {
return result[1:]
} else {
return nil
}
}
とすると、うまくいっているように見えるが、最後の文字が?になってしまう…
たぶん、最後の文字が?になってしまうのは、
for _, s := range strings.Split(code, " ") {
if val, ok := reverse[s]; ok {
result += string(val)
} else {
result += "?"
}
}
のところで、最後の文字が""か" "になっていることが原因だと思われる。
for key, value := range forward {
reverse[value] = key
}
に
for key, value := range forward {
reverse[value] = key
}
reverse[" "] = ""
reverse[""] = ""
を追加すれば解決すると思われる
最新の実装でPRを出しておきました
素晴らしいです。ただ、CodeToText
関数は素直にモールス符号を文字列に変換する想定なので、今回のPRではテストが落ちます。何点か修正があるので、待ってください。
問題意識
OBの方から、確定していない文字の表示に関して、「出てくる文字が確定していないところはコロコロ変わる。それも無線家の頭の中に浮かぶ文字ではないものが表示される。よって、混乱を招くので確定していない文字、つまりは文字間の空白が来る前の文字は表示しないようにするべき」という要望が出た。 (現状、コロコロ変わる文字はhttps://blog.goo.ne.jp/ykimata/e/b5dee1229c784c05b39ae74456260010 のように聞き取れた部分までの分岐点の場所で、結構混乱するかもしれない)
確定していない文字を表示しない手法が求められる
解決方法
以前の確定していない文字を表示しない手法は前回と同じ文字のみ表示するというものだった (https://github.com/jucky154/cwListener/blob/b24f4925e8132212f0b2920dec0917762bb08aa8/cwListener.go#L218 ) がかなりコードが複雑化しているので、あまり採用するべき手法ではないと考えられる。
よって、OBの言うとおり、「文字間の空白が来る前の文字は表示しない」という対応が良いと思われる。 対応としては https://github.com/nextzlog/cw4i/blob/5dae69de1cc035755d3241c8c3db3a123de44e0a/core/symbols.go#L27C1-L36C2 の部分に関して、
のように対処すれば最後の部分が文字間の空白であれば確定なので表示し、そうでないならば最後の文字は確定していないので表示しないといった対応が可能であると考えられる。