おっと。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でリターンてな処理です。
| 固定リンク
「Arduino」カテゴリの記事
- Arduino、analogWriteは捨てちゃえ。ちゃんとしたPWMの例(2025.03.22)
- パルスジェネレータをI2C液晶で動かす(2025.01.28)
- EEPROMを使ったシリアル受信バッファ 512kバイトに増設(2024.12.26)
- 1/nカウント方式とDDS方式の2相パルス発生回路(2024.10.13)
- おっと。map関数の計算桁に注意(2024.10.06)
「重箱の隅」カテゴリの記事
- 1/1023監視団 活動中!(2025.03.10)
- DIPのLMC6482えらい高くなった(2025.03.07)
- 因縁のボリューム記号 トランジスタ技術2025年3月号(2025.02.17)
- ボリューム記号のボヤキ、トラ技2025年3月号の別冊付録に再掲載(2025.02.10)
- NECは3段タイプの発振回路をすすめてる(2025.01.31)
「1023 vs 1024」カテゴリの記事
- Arduino、analogWriteは捨てちゃえ。ちゃんとしたPWMの例(2025.03.22)
- 1023 vs 1024:AVRマイコンとPICマイコンのデータシートより(2025.03.19)
- 1/1023監視団 活動中!(2025.03.10)
- おっと。map関数の計算桁に注意(2024.10.06)
- サーミスタでの温度測定、「inf」の出現に耐えられるか?(2024.05.13)
コメント