« DDS方式の2相パルス発生回路、周波数スキャン機能を付ける | トップページ | 東芝インパルス TNH-3LE 950mAh 充放電実験 »

2024年10月 6日 (日)

おっと。map関数の計算桁に注意

Arduinoのmap関数に関して恨みを持っている
がごとくウダウダ言っております。
 ・2020年5月17日:Arduino なんとかして誤用を正したい:A/Dの1/1023とmap関数

トラ技にも載りました。
 ・トランジスタ技術2024年3月号『実はワナだらけ…確実に動かすArduino Uno R3

で、今回の
 ・2024年10月5日:DDS方式の2相パルス発生回路、周波数スキャン機能を付ける

ここで、「おっと危ない」だったのが「map」関数の数値範囲。

周波数sweepでは、
  周波数の値は0.01Hz単位で9999.99Hzが最大。
  BCDで8桁。999999=0xF423F 20bit

  経過時間が10ms単位で600.00秒が最大。
  BCDで5桁。60000=0xEA60 16bit

sweep処理では、こんな値を使います。
  Lo側周波数 1~9999Hz   f1
  Hi側周波数 1~9999Hz   f2
  Rise,fall時間 0.0~600.0秒 t1

sweep周波数の設定は1Hz単位ですが、内部では0.01Hz
単位に直します。
sweep時間も0.1秒を0.01秒にして60000が最大。

そして、「map関数」はこのように定義されています。

long map(long x,         入力
  long in_min, long in_max,  X1,X2 変換元
  long out_min, long out_max) Y1,Y2 変換先
{
 return (x - in_min) * (out_max - out_min) ★1
   /  (in_max - in_min)
   + out_min;
}

sweep処理で経過時間tmからsweep周波数fmを計算するとき、
map関数をこのように使いました。

  fm = map (tm , 0, t1, f1, f2);

このとき、周波数と経過時間が設定の最大値に近づくと、
★1の乗算に失敗するのです。

周波数(20bit)と時間(16bit)を掛け算すると、
値によっては「36bit」の数字が出てきます。

map関数の入力と出力、単独で見るとそれぞれは
32bitの数値範囲に入っていますが、内部計算を考えると
32bitではアウトなのです。

内部は「int64_t」で計算しなくちゃなりません。

 return ((int64_t)(x - in_min) *
     (int64_t)(out_max - out_min))
     / ((int64_t)(in_max - in_min))
     + out_min;

乗算部、除算部をint64_tにキャストして64bitで
計算するようにしました。

LOG sweepではfloatにしたmapも使っています。

float mapf(float x,
  float in_min, float in_max,
  float out_min, float out_max)

2022年11月6日:Arduino map関数をfloatに

もうひとつ。
t1がゼロだとゼロ除算してしまうので、mapに
食わす前に判定して除外しておかなくちゃなりません。
t1がゼロなら fm=f1でリターンてな処理です。

|

« DDS方式の2相パルス発生回路、周波数スキャン機能を付ける | トップページ | 東芝インパルス TNH-3LE 950mAh 充放電実験 »

Arduino」カテゴリの記事

重箱の隅」カテゴリの記事

1023 vs 1024」カテゴリの記事

コメント

コメントを書く



(ウェブ上には掲載しません)




« DDS方式の2相パルス発生回路、周波数スキャン機能を付ける | トップページ | 東芝インパルス TNH-3LE 950mAh 充放電実験 »