[DIARY] Digital APFの実験
![]()
おはようございます。昨日は無線もせずに、朝5時に家をでて6時から釣りをやっていたのですが、10時を回ると気温は30℃を越えだし、熱中症になりそうだったので早々に帰宅しました。やはり最近の暑さは異常ですね。
釣りから帰宅後は、エアコンの効いた部屋で先日から手を付け始めたDigital APFの実験を始めました。
数日前までには、リグのPhone端子から得た信号を入力とし、ADCからPCM変換でリグのPhone端子で聞く音質と同じようになるまで実験は進みました。
昨日は実際のAPF機能の作り込みです。APFは一般的に、OPアンプの帰還を利用して特定周波数で同調させるような感じで、特定周波数のみを強調して聞こえるようにします。
この強調はOPアンプの帰還率からQの大きさで選択度(ピーク度)が決まりますが、これをデジタル処理しようと言うのが今回の実験です。
更には、FPGAとかDSPとか言う高価でかつ高度な知識を要するモノでは無く、Raspberry Pi pico2を使用して内蔵しているCPUとADCで処理を掛けようというものです。
当然ながら、当局はそんな知識も持ち合わせておりませんので、今までと同じくパートナーのGemini君に活躍して貰いました。
当局は細かな仕様設定をし、後はデバッグを行いながらGemini君にフィードバックしていくだけです。
入出力がちゃんと出来るようになったことを受けて、ADCで得た信号をCPUでピーク処理をし、外付けのVRで選定周波数が変わるようにします。
更には、選択度を変えるQもロータリーエンコーダで可変することでQの大きさを変えて、選択度を変化させると言う所まで実験しました。
最終的に、VRで度の周波数を選定しているのか?Qは幾つでどのくらいの選択度となっているのか?を視覚化するように、OLEDに表示をさせるようにしました。
最終的にOLEDで表示もでき、とりあえず目標としていた実験までは完了しました。
センター周波数700Hzに対して、選択度Qは15帯域は一番狭い状態となっております。ロータリエンコーダを回すと、Qの値が小さくなると同時に下部にあるバンド幅が広がっていきます。最低のQ:2に設定すると、最大通過幅になります。
また、APF用VRを回すと中心周波数が変化していきます。
40mで実際の信号を聞いてみると、ズレて呼ぶ局に対してだいぶ減衰して聞こえない状態ですが、VRを回して周波数を合わせると信号が浮いてきます。
OPアンプのAPFと違い、キンキンしたような音質ではなくトランシーバーにヘッドフォンを付けて聞いている音で、帯域が狭くなったりして信号が浮き上がる感じです。
切れは有るが音はキンキンせずに普通の音質で聞こえる、これがDigital APFの特徴なんでしょうね。
トランシーバーについているAPFとフィルタの帯域変更だけでは取り切れない混信を、オーディオスペクトル的に切り落としてしまうDigital APFはなかなかのモノです。
思ったよりは使えるかなって思えてきました。未だ完成ではないですが、先が楽しみです。
コードの一部はこんな感じです
#include <I2S.h>#include <math.h>#include "hardware/sync.h"// OLED用ライブラリ#include <U8g2lib.h>#include <Wire.h>// ★標準のハードウェアI2C(Wire=I2C0)を使用するコンストラクタに戻しますU8G2_SH1106_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);// GPIOピン定義const int I2S_BCK = 18;const int I2S_LRCK = 19;const int I2S_DOUT = 22;const int AUDIO_IN_PIN = 26;const int FREQ_VR_PIN = 27; const int ENCODER_A_PIN = 10;const int ENCODER_B_PIN = 11;const int SAMPLE_RATE = 16000;I2S i2sOutput(OUTPUT);repeating_timer_t timer;// リングバッファconst int BUFFER_SIZE = 1024;volatile int16_t adc_buffer[BUFFER_SIZE];volatile int head = 0;volatile int tail = 0;float dc_estimate = 2048.0;// フィルター係数volatile float b0 = 0, b1 = 0, b2 = 0;volatile float a1 = 0, a2 = 0;// フィルターの過去データバッファfloat v_x1 = 0, v_x2 = 0;float v_y1 = 0, v_y2 = 0;float current_freq = 700.0;float current_q = 15.0; float target_freq = 700.0; int last_vr_value = -999; bool is_moving = false; // 画面更新フラグbool oled_needs_update = true;// APF係数計算関数void calc_apf_coefficients(float target_freq, float q_value) { float omega = 2.0 * M_PI * target_freq / (float)SAMPLE_RATE; float alpha = sin(omega) / (2.0 * q_value);
開発言語を十分理解していなくても、プログラムが出来てしまうなんて、すごい世の中になりましたね。もっとも、ポイントは仕様書をどこまで細かく掛けるかにかかっていますが。
にほんブログ村 ↑ブログランキング参加中。クリックでランキングが上がりますので、ご支援をお願いします。

関連記事:
- [DIARY] 開けても短時間でQSOできず おはようございます。昨日は1日寒かったですね。日中も風花が舞う天気で、日が出ていても気温が上昇しません。土曜日に取りこぼした6mのDXを期待してまた作業をしながらのながらワッチ。 PCB設計をしながらだと、つい夢中になっ...
- [DIARY] 最終確認の実施で完了 今日はほぼ1日、強い雨が断続的に降っていた1日でした。これから週末に掛けて回復していくと言う予報ですがどうでしょうね。 さて、帰宅後に頼んでおいた部品が届きましたので、アンテナ切替器の最終確認を実施していきました。 とり...
- [DIARY] 新たな工作の準備開始 おはようございます。昨日も蒸し暑く暑い1日になりました。陽射しは強いが、それ以上に湿度が高く梅雨の中休み的な感じでした。本格的な梅雨は来週からのようですが、特に週明けは大雨になる予報になっていますね。今日も...





