無課金おじさんの試験勉強DX（第一級海上特殊無線技士）

## はじめに
まず自己紹介です。専攻は機械工学で、職歴は国内外での火力発電や再エネ発電に携わった後、今は継続雇用で海外火力発電案件の技術監理をしています。仕事柄英語に不自由はありません。若い頃からの資格コレクターで、強電やエネルギー関連を一通り制覇し、最近は弱電・気象・データサイエンスなど関連分野…と言うか興味の赴くまま手を出しています。実務経験や認定講習などではなく試験での正面突破がポリシーです。
定番の参考書や問題集を何周もコツコツこなすのが、従来からの資格試験の勉強法でしたが、今回受験した第一級海上特殊無線技士では、準備期間が約1か月と**短期集中**だったこともあり、、学習用**アプリ**や**生成AI**による音声合成などのICTを積極的に活用した効率化、名付けて**試験勉強DX**を実践しました。以下に概要を紹介します。
## 無線従事者免許
**無線従事者免許**とは.無線工学や電波法に関する知識や無線設備の操作・運用の技能を有する者に対し、**電波法**に基づき総務大臣から与えられる**国家資格**です。陸海空といった場所、運用可能な出力や周波数、通信の相手方や目的などにより23種類に区分されており、歴史的な変遷もあって体系はかなり複雑です[^1]。
[^1]:[23種類もある無線従事者資格と、それぞれの操作範囲との相互関係はどうなっていますか。｜公益財団法人 日本無線協会](https://www.nichimu.or.jp/denpa/faq/index.html#vcb00000144-26-18-BasicParts-3-1-01)
### 第一級海上特殊無線技士（一海特）とは
**海上特殊無線技士**は船舶など海上で無線設備の通信操作を行うための資格です。許可される内容により4つの種別がありますが、海上特殊無線技士のうち**国際通信**のための通信操作（制限あり）が認められているのは、今回受験した**第一級特殊無線技士**（略称**一海特**）だけです[^2]。
[^2]: [総務省｜東海総合通信局｜無線従事者の資格と操作範囲](https://www.soumu.go.jp/soutsu/tokai/musen/juujisha/shikaku.html)
## 一海特の試験科目と内容
一海特の試験は**無線工学**、**法規**、**英語**、**通信術**の4科目で、このうち**英語**と**通信術**は、海上特殊無線技士の中では**一海特だけ**に課されます[^3]。
[^3]: [［表１］資格別・科目別試験問題数と試験時間｜公益財団法人 日本無線協会](https://www.nichimu.or.jp/vc-files/denpa/pdf/h01.pdf)
### 法規・無線工学
法規・無線工学それぞれ四択式12問が出題され、計24問を1時間以内で解く必要があります。それぞれ60点が満点。
### 英語（英会話）
音声による通信文を聴取り、問題用紙に印刷された4つの選択肢から応答として最も適切な文を選ぶ形式です。音声は3回読上げられ、始めの2回はややゆっくり、最後の1回は少し速くなります。満点は100点。
### 通信術
アルファベット100文字を**欧文通話表**に従って受話・送話する試験です。欧文通信表とは、アルファベットの各文字に特定の単語を対応させる規則（例えば**A**,**B**,**C**には、それぞれ**A**lpha, **B**ravo, **C**harlieが対応）を定めたもので、通信状況が悪かったり送信者の発音に癖があったりしても正確に伝達できるよう定められています。日本では**無線局運用規則**により欧文と和文の通話表が定められており、**一海特**の試験で用いられるのは欧文通話表[^4]（のうちアルファベットのみ）で、いわゆる**NATO Phonetic Code**と同じものです。
標準的な速さは**2分（120秒）あたり100文字**ですが、息継ぎなどのため5文字ごとにポーズを置くのが慣例となっており、受話・送話とも**毎秒約1文字**のペースになります。
[^4]: [無線局運用規則別表第五号第2項「欧文通話表」](https://www.tele.soumu.go.jp/horei/law_honbun/72393000.html#e000008348)
#### 受話
**ランダムな**アルファベット**100文字**が欧文通話表に従って読上げられる**音声**を聴き、**アルファベット**（単語ではない）を答案用紙に書取るものです。単純そうな作業ですが、通話表をしっかり覚えて音声を聴いたら反射的に手が動くまで習熟する必要があります。速度は意外と速く、迷ったり間違いを訂正したりする余裕はありません。また、あまりにも字が汚くて**判読困難だと減点**されます。100点が満点。
#### 送話
試験官から渡される紙に**ランダムな**アルファベット100文字が印刷されており、これを欧文通話表に従って2分で読上げます。受話と違って自分のペースでできますが、適切なテンポを身体で覚えるまで習熟しないと**制限時間オーバーで減点**されます。100点満点。
## 傾向と対策
### 過去問を大量に入手
どんな試験であれ一番参考になるのは**過去問**でしょう。出題形式や頻出分野を分析すれば対策の方向が見えてきます。
無線従事者試験を実施している**日本無線協会**は**最近の問題・解答**を公開[^5]していますが、更にネットを探すと**約20年分もの問題・解答**を公開しているサイト[^6]が見つかり、ありがたくダウンロードしました。これだけあれば充分です。
[^5]: [試験問題と解答 | 公益財団法人 日本無線協会](https://www.nichimu.or.jp/kshiken/siken/index.html#vcb00000365-3-117-default3-01)
[^6]: [無線従事者国家試験過去問ダウンロード | kema's Homepage](https://kemanai.jp/2018/01/01/%E7%84%A1%E7%B7%9A%E5%BE%93%E4%BA%8B%E8%80%85%E5%9B%BD%E5%AE%B6%E8%A9%A6%E9%A8%93%E9%81%8E%E5%8E%BB%E5%95%8F%E3%83%80%E3%82%A6%E3%83%B3%E3%83%AD%E3%83%BC%E3%83%89/)
### 法規・無線工学
法規・無線工学とも平易で、殆どが既出問題の再出題なので、**過去問をマスター**（暗記）すれば合格ライン（60%）は楽にクリアできそうです。ネット情報に基づき学習範囲を**最近3年分程**に絞り、過去問を**暗記用アプリのAnki**[^7]にインプットして主にスマートフォンで勉強しました。特に目新しい事はありません。
[^7]: [Anki - powerful, intelligent flashcards](https://apps.ankiweb.net/)
### 英語
過去問を眺めると、英語としては平易な義務教育レベルですが、問題文（読上げられる通信文）の場面設定は**海上での通信を想定**したもので、例えば**遭難**した船からの**救援要請**、**港湾管理者**や**検疫所**の指示、**水産庁の立入検査**や**水先案内人**派遣会社との連絡、**船舶相互**の気象情報の共有や単なる雑談などです。従って、状況設定を理解し正解を選び出すには、**海事特有の用語や慣用表現**をキチンと理解しておく必要があります。聴き取れた**キーワード**っぽい単語を拾って同じ単語がある選択肢を選ぶ**安易な解法**[^8]だと**出題者の罠**にハマります。また、法規や無線工学のように同じ問題の繰返しではなく**新作問題**が出題されているようです。
英語には自信のある私ですが、**最も手強く感じた**科目でした。
何れにしても**数多くの事例**に当たって**海事英語に慣れる**ことが最良の試験対策であり、大量の過去問を入手できたことを大変心強く感じました。しかし、ひとつ困った事がありました。**印刷した問題文**を読んで答案練習をしても**リスニング対策にならない**事です。
[^8]:このような読解法を新井紀子氏は「AI読み」と指摘しているが、一海特の英語の過去問のテキストをコピペしてChatGPTに解かせてみたところ、意外にも出題者の罠にハマる事は少なく概ね正解を選び出せていた（サンプル数は少ないが合格基準の60%は軽くクリアした印象）。
#### Anki×Text To Speech=リスニング教材
法規・無線工学の学習に使った**Anki**は**マルチメディア**に対応しており、問題に音声ファイルを使った**語学のリスニング対策**での活用例もあります。また、ありがたい事に、最近は生成AIによる**音声合成**（Text To Speech）APIがPCから容易に利用できます。そこで、これらを活用して過去問の問題文を音声化した教材を自作しました。
##### 問題文と選択肢の抽出
次のPythonコードは、所定の**フォルダ**内に**過去問pdf**を入れて実行すると、元ファイルの**問題文と選択肢**を抽出した**テキストファイル**が作成されます（目印として元ファイルのbasenameも挿入される）。
```python
#
# 過去問pdfから問題文と選択肢のテキストを抽出
#
from pdfminer.high_level import extract_text
from pathlib import Path
import re
import os
import glob
from unicodedata import normalize

# 各回の問題文テキストリスト（text）を引数に与えると整形した問題リスト（qlist）を返す
# 選択肢番号などの表記ゆれを整理する
def text_to_list(text):
    buffer = ''
    qlist = []
    for line in text:
        # 問題番号に混在している全角を半角に
        line = normalize('NFKC', line)
        # QUESTIONの後にスペースが無い場合があるので追加（ダブったら次行で消せる）
        line = re.sub('^QUESTION', 'QUESTION ', line)
        # 複数の空白を1つに、正解選択肢のマークを削除、左の余分な空白を削除
        line = (re.sub(' +', ' ', line.replace('#', ''))).lstrip()
        # 複数の選択肢番号フォーマットに対応
        if ((line.startswith('QUESTION')) or (re.search('^\([1234]\)', line)) or (re.search('^[1234]', line))):
            if (buffer != ''):
                qlist.append(buffer.rstrip())
            buffer = line
        elif (line != ''):
            if ('(RE' not in line):
                if (buffer != ''):
                    buffer += line
    if (buffer != ''):
        qlist.append(buffer.rstrip())
    return qlist

# qa_folderに集めた過去問pdfを調べて
# 同じフォルダにファイル名'eigo_qt_fn'の問題文・選択肢集約ファイルを作成する
qa_folder = r'./1kaitoku'
# 英語の過去問のファイル名パターン
eigo_q_fn = '1kaitoku-20??([HR]??)-??-eikaiwa.pdf'
# 問題文・選択肢集約ファイル
eigo_qt_fn = 'eigo_q_text.txt'
eigo_q_path = os.path.join(qa_folder, eigo_q_fn)
ql = sorted(glob.glob(eigo_q_path))
eigo_qt_path = os.path.join(qa_folder, eigo_qt_fn)

with open (eigo_qt_path, "w") as qt:
    for qf in ql:
        # 各回の問題・選択肢ブロックの前にファイル名（basename）を出力
        print(os.path.splitext(os.path.basename(qf))[0][9:13]+os.path.splitext(os.path.basename(qf))[0][18:21], file=qt)
        text = extract_text(qf)
        text = text.split('\n')
        qlist = text_to_list(text)
        for q in qlist:
            print(q.rstrip(), file=qt)
```
##### 問題文読上げ音声ファイルの作成
次は、上記のコードで作成した**問題文・選択肢集約ファイル**から、問題ごとの読上げ音声ファイルを作成するコードです。音声化APIはMicrosoft社が公開している**Edge-TTS**[^9]を、サンプルコード[^10]などを参考に作成しました。
[^9]:[GitHub - rany2/edge-tts: Use Microsoft Edge's online text-to-speech service from Python WITHOUT needing Microsoft Edge or Windows or an API key](https://github.com/rany2/edge-tts?tab=readme-ov-file)
[^10]:[Pythonで音声合成 ～edge-ttsを利用して英語の音声ファイルを作成～ | 東陽テクニカ | “はかる”技術で未来を創る | 情報通信](https://www.toyo.co.jp/ict/casestudy/detail/id=42440)

```python
#
# 一海特：英会話音声追加作成ツール
#
import csv
import subprocess
import asyncio
import edge_tts
import os
import random

# US英語のAndrewをメインに他の話者も時折混ぜる
voices, vweights = zip(*(
    ('en-US-AndrewNeural', 50),
    ('en-US-JennyNeural', 2),
    ('en-GB-ThomasNeural', 20),
    ('en-GB-LibbyNeural', 2),
    ('en-AU-WilliamNeural', 10),
    ('en-SG-WayneNeural', 5)
))

# 読上げの速さに変化をもたせる
# 最初の2回はゆっくり
speed1s, s1weights = zip(*(
    ('-12%', 10),
    ('-11%', 20),
    ('-10%', 100),
    ('-9%', 20),
    ('-8%', 10),
))
# 3回目は少し速く
speed2s, s2weights = zip(*(
    ('-2%', 10),
    ('-1%', 20),
    ('+0%', 100),
    ('+1%', 20),
    ('+2%', 10),
))

async def save_voice(text, voice, rate, fname) -> None:
    communicate = edge_tts.Communicate(text, voice, rate=rate)
    await communicate.save(fname)

async def make_vfile(question, fname, voice, speed1, speed2) -> None:
    temp_files = []
    dummy_file = 'dummy.mp3'

    await save_voice(question[0:10]+'.', voice, speed1, dummy_file)
    add_pause = f'ffmpeg -i {dummy_file} -af "apad=pad_dur=1" q_head.mp3'
    subprocess.run(add_pause, shell=True)

    for i in range(3):
        temp_file = f"temp_part_{i}.mp3"
        if (i != 2):
            await save_voice(question[11:], voice, speed1, dummy_file)
            add_pause = f'ffmpeg -i {dummy_file} -af "apad=pad_dur=2" {temp_file}'
            subprocess.run(add_pause, shell=True)
        else:
            OUTPUT_FILE = temp_file
            await save_voice(question[11:], voice, speed2, temp_file)
        temp_files.append(temp_file)

    concat_command = f"ffmpeg -y -i \"concat:q_head.mp3|{'|'.join(temp_files)}\" -acodec copy {fname}"
    subprocess.run(concat_command, shell=True)
    os.remove(dummy_file)
    os.remove('q_head.mp3')
    for temp_file in temp_files:
        os.remove(temp_file)

# ForAnki.txtファイルは過去問から集めた問題文のテキスト
with open('./ForAnki.txt') as f:
    for s_line in f:
        # voice, speed1, speed2をランダム設定
        voice = random.choices(voices, vweights)[0]
        speed1 = random.choices(speed1s, s1weights)[0]
        speed2 = random.choices(speed2s, s2weights)[0]
        s = ''.join(s_line.splitlines())
        if s.startswith('20'):
            basename = s[0:7]
        elif s.startswith('QUESTION'):
            fname = basename + '_Q' + s[9] + '.mp3'
            print(f'making {fname}')
            await make_vfile(s, fname, voice, speed1, speed2)
```
Edge-TTSでは**多様な話者**を設定できるため、せっかくなので米英のネイティブだけでなく**非ネイティブの話者**も含めて音声合成しました。実際、国際航路では**非ネイティブの乗組員**も多く、最近のTOEICのリスニングでは米英以外にカナダ・オーストラリア・ニュージーランドの話者による音声も出題されるなど英語の多様化も進んでいます。これは実際の試験で直接役立つものではありませんでしたが、練習の段階での**汎化能力**向上には寄与したかもしれません（個人の感想です）。
こうやって準備した問題文の音声ファイルを、過去問pdfから別途抽出した選択肢や正解とリンクさせて**Anki**にインポートして自習教材としました。
Ankiは**スマートフォンアプリ**もあるので、仕事の行き返りや休み時間などの**すき間時間**を貪欲に活用して学習しました。これはAnkiに入れた法規・無線工学も同じです。
##### 音声合成のメリット
リスニングテストでは、問題文の文字を読んで勉強しても所詮**畳の上の水練**です。かと言って、自分で問題文を読んで録音しても内容が記憶に残って練習の効果が薄れます。しかし、今回は内容を殆ど見ずに音声化を行ったため、言わば**初耳状態**での聴取り練習になりました。勿論Ankiで繰返し練習していれば同じ問題に何度も当たる訳ですが、**文字に頼らず耳から入る英語**の練習はしっかりできたと思います。
### 通信術
#### 受話
ネットで見つけた受話練習用アプリ[^11]を使いました。**航空特殊無線技士**等と銘打っていますが、欧文通話表は共通なので**一海特**にも転用可能です。なお、このソフトは音声データの差替えが可能なので、先述の**Edge-TTS**を使い、複数の発話者による音声データを作り、マンネリ化を防ぎました。
[^11]: [電気通信術 電話 練習用ソフトウェア](https://tosjb.web.fc2.com/PHTRY/index.html)
#### 送話
レコーダーに録音し、所要時間を計測したり自分で聴いたりして完成度を高めました。ランダムなアルファベットの生成用に簡単なプログラムを作った程度で、特にDXと言えるようなことはしていません。
#### 試験勉強DXによる間接的メリット
本番に即した通信術の練習には、**受話**では音声を聴いて答案用紙に**手書き**、**送話**では問題文を読みながら**発声**、といったことが必要です。この科目でも**試験勉強DX**として、例えばOCRによる手書き文字の評価、音声認識による発話の評価、といった方法を考えたものの導入には至りませんでした。
なお、他の科目（法規・無線工学・英語）の学習にAnkiを導入してすき間時間を活用したことで、自宅学習の大部分を通信術に割振ることができました。これも広い意味では**試験勉強DX**の効用と言えるかもしれません。
## 試験
試験日は2024年6月11日。試験地は熊本で朝9:30開始なので福岡から前泊で入りました。
### 法規・無線工学
全問自信を持って解答できました。時間にかなり余裕がありましたが、途中退出しても持て余すので自席でマークシートや計算などを見直しつつゆったり過ごしました。
### 通信術（受話）
音声がいわゆるジャパニーズ・イングリッシュだったこともあり全く迷わずに解答できました。
### 英語
迷った問題が1問ありましたが他の4問は問題無し。合格ラインは突破できている筈です。
### 通信術（送話）
落着いて読上げることができました。解答している間は紙の上の文字だけに集中できている不思議な感覚です。いわゆる**フロー状態**のようなものかもしれません。
## 結果
2024年6月27日の朝、日本無線協会から試験結果のメールが届きました。結果は⋯⋯やはり**合格**でした。あのバーニーおじさんも祝っています[^12]。
![IMG_2562.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/772615/8d2a6138-10f4-3e9b-3073-00877da2d7d9.jpeg)
[^12]: [【妄想】G検定の勉強で知った「バーニーおじさん」の勝手なイメージ | コヨイ](https://koyoy.com/g-ken/)
### 得点開示請求
無線従事者試験では、日本無線協会の支部に問い合わせると得点を教えてくれます。もしや……と思って開示請求した結果、全科目満点でした。
![得点.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/772615/992e3818-ba96-0921-f92b-c488611cdcf8.jpeg)
## まとめ&おまけ
参考書や問題集を使わず、過去問を素材に公開アプリやAPIを活用した**無課金**での学習で合格。しかも全科目パーフェクトという嬉しいおまけがつきました。
これに気を良くして11月には**第一種陸上特殊無線技士**を受験しました。こちらの科目は法規と無線工学だけ。最近の過去問をAnkiにインプット。今度も**無課金**の学習で合格。
無課金おじさんの怪進撃はまだまだ続きます。