現在、シンボル時間回復ブロックを実装しています。アイデアは、さまざまな TED (Gardner、ゼロクロッシング、Early-Late、Maximum-likelihood など) を選択できるようにすることです。M&M リカバリのようなブロックでは、ループのゲイン パラメータが明示的に表現され (gain_omega と gain_mu)、正しく設定するのが難しい場合があります。ただし、contro_loop クラスの方が便利です (ループ特性は「ループ帯域幅」と「ダンピング ファクター」(ゼータ) で指定できます)。そのため、私の最初のテストは、制御ループを使用して MM クロック リカバリを再実装することから始まりました。このブロックの仕事関数を以下に示します (コメントは私のものです)
clock_recovery_mm_ff_impl::general_work(int noutput_items,
gr_vector_int &ninput_items,
gr_vector_const_void_star &input_items,
gr_vector_void_star &output_items)
{
const float *in = (const float *)input_items[0];
float *out = (float *)output_items[0];
int ii = 0; // input index
int oo = 0; // output index
int ni = ninput_items[0] - d_interp->ntaps(); // don't use more input than this
float mm_val;
while(oo < noutput_items && ii < ni ) {
// produce output sample
out[oo] = d_interp->interpolate(&in[ii], d_mu); //Interpolation
mm_val = slice(d_last_sample) * out[oo] - slice(out[oo]) * d_last_sample; // Error calculation
d_last_sample = out[oo];
//Loop filtering
d_omega = d_omega + d_gain_omega * mm_val; //Frequency
d_omega = d_omega_mid + gr::branchless_clip(d_omega-d_omega_mid, d_omega_lim); //Bound the frequency
d_mu = d_mu + d_omega + d_gain_mu * mm_val; //Phase
ii += (int)floor(d_mu); // Basepoint index
d_mu = d_mu - floor(d_mu); // Fractional interval
oo++;
}
consume_each(ii);
return oo;
}
これが私のコードです。まず、制御ループがコンストラクターで初期化されます
loop(new gr::blocks::control_loop(0.02,(1 + d_omega_relative_limit)*omega,
(1 - d_omega_relative_limit)*omega))
まず最初に、シンボル タイミングの回復、特に位相と周波数の範囲 (ラッピングに使用される) における pll (上記の control_loop) に関するいくつかの疑問を解消したいと思います。Costas ループから類推すると、キャリア位相は -2pi と +2pi の間でラップされ、周波数オフセットは -1 と +1 の間で追跡されます。その理由は簡単にわかります。残念ながら、シンボル復元における位相と周波数の追跡について理解できません。m&m ブロックから、周波数は (1+omega_relative_limit) と (1 - omega_relative_limit)*omega の間で追跡されます。ここで、omega は単にシンボルあたりのサンプル数です。位相は 0 とオメガの間で追跡されます。これがなぜそうなのか、なぜ m&m ブロックがそれをラップしないのか理解できません。ここでのアイデアは大歓迎です。そして、ここに私の仕事関数があります
debug_time_recovery_pam_test_1_impl::general_work (int noutput_items,
gr_vector_int &ninput_items,
gr_vector_const_void_star &input_items,
gr_vector_void_star &output_items)
{
// Tell runtime system how many output items we produced.
const float *in = (const float *)input_items[0];
float *out = (float *)output_items[0];
int ii = 0; // input index
int oo = 0; // output index
int ni = ninput_items[0] - d_interp->ntaps(); // don't use more input than this
float mm_val;
while(oo < noutput_items && ii < ni ) {
// produce output sample
out[oo] = d_interp->interpolate(&in[ii], d_mu);
//Calculating error
mm_val = slice(d_last_sample) * out[oo] - slice(out[oo]) * d_last_sample;
d_last_sample = out[oo];
//Loop filtering
loop->advance_loop(mm_val); // Filter the error
loop->frequency_limit(); //Stop frequency from wandering too far
//Loop phase and frequency
d_omega = loop->get_frequency();
d_mu = loop->get_phase();
//d_omega = d_omega + d_gain_omega * mm_val;
//d_omega = d_omega_mid + gr::branchless_clip(d_omega-d_omega_mid, d_omega_lim);
//d_mu = d_mu + d_omega + d_gain_mu * mm_val;
ii += (int)floor(d_mu); // Basepoint index
d_mu = d_mu - floor(d_mu);//Fractional interval
oo++;
}
consume_each(ii);
return oo;
}
GFSK 復調器でブロックを使用しようとしましたが、このエラーが発生しました
python: /build/gnuradio-bJXzXK/gnuradio-3.7.9.1/gnuradio-runtime/include/gnuradio/buffer.h:177: unsigned int gr::buffer::index_add(unsigned int, unsigned int): Assertion `s < d_bufsize' failed.
このエラーに関する最初の Google 検索は、このエラーが API の下のどこかに発生するため、何らかの形でスケジューラを「悪用」していることを示唆しています。制御ループからの d_omega と d_mu の計算は少し単純だと思いますが、残念ながら他の方法は知りません。もう 1 つの方法は、モジュロ 1 カウンター (インクリメントまたはデクリメント) を使用することですが、最初にこのオプションを検討したいと思います。