Arduino map関数をfloatに
map関数の処理は、
C:\Program Files\Arduino\hardware\arduino\avr\cores\arduino\WMath.cpp
ヘッダーファイルは、
C:\Program Files\Arduino\hardware\arduino\avr\cores\arduino\Arduino.h
ここで記述されています。
中味がこれ。
long map(long x, long in_min, long in_max, long out_min, long out_max) {
return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}
ちょっとわかりにくいので、図にします。
傾き「a」を出す計算が重要なわけです。
long値での割り算ですんで切り捨てで処理されます。
ですので、map関数が出した答えを使って四捨五入しても、
間に合いません。 ※<5>の処理
ということは、map関数自体をfloatにして、内部の割り算での
切り捨てをなくします。
/***** 線形補間 *****/
// floatで
float mapf(float x, float in_min, float in_max, float out_min, float out_max)
{
return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}
「long」を「float」に置き換えるだけ。
簡単なのも。
先日のA/D値を補正する例だと、
/***** A/D値補正 *****/
// in ad : 0~1023 A/D値(10bit)
// ch : ch1sitei
// 補正テーブルを使ってキャリブレーション
short adadj(word ad, byte ch)
{
float a;
long g;
a = mapf((float)ad, // floatにしたmap(線形補間)
(float)pgm_read_word(&adj_tbl[ch].x0), // in_min
(float)pgm_read_word(&adj_tbl[ch].x1), // in_max
(float)pgm_read_word(&adj_tbl[ch].y0), // out_min
(float)pgm_read_word(&adj_tbl[ch].y1)); // out_max
g = lround(a); // 四捨五入してlongに
// 必要ならshort範囲をチェック
return (short)g; // shortにしてリターン
}
浮動小数点の四捨五入には、関数「lround()」という便利なの
があります。
少数以下を四捨五入してlongの整数に変換してくれます。
+/-を判断してくれるので、
マイナス、右(数値が大)か左(数値が小)、どっちにそろえる
ねん? も問題なし。
こんな結果になります。
lround(+2.3) = 2 lround(+2.5) = 3 lround(+2.7) = 3
lround(-2.3) = -2 lround(-2.5) = -3 lround(-2.7) = -3
昔のCだと、lroundは標準関数には無いんですよね。
これで、「A/D値 → 電圧値」の変換が、実値(A/D値の読みと
テスターで測定した電圧)で可能になります。
変換テーブルは実値をwordにして2バイトで。
電圧だと「12345mV」などと5桁で表現できます。
ただ・・・floatを使ってmath.hをインクルードすると
1.5kバイトほどプログラムが大きくなっちゃいます。
※関連
・Arduino なんとかして誤用を正したい:A/Dの1/1023とmap関数
・Arduino 10bit A/D値をmap関数でスケーリングする例
・ミスが広まる 1/1023 vs 1/1024
・5chサーミスタ温度計のA/D入力、map関数を使って補正
| 固定リンク
「Arduino」カテゴリの記事
- パルスジェネレータをI2C液晶で動かす(2025.01.28)
- EEPROMを使ったシリアル受信バッファ 512kバイトに増設(2024.12.26)
- 1/nカウント方式とDDS方式の2相パルス発生回路(2024.10.13)
- おっと。map関数の計算桁に注意(2024.10.06)
- DDS方式の2相パルス発生回路、周波数スキャン機能を付ける(2024.10.05)
コメント
map関数を浮動小数点にすると・・・
y = map(x, 0, 1023, 0, 255);
この式でも、半値の x = 512 が
y = 127.6246 → 128
となり、四捨五入して整数にすると合っている
ように見えます。
しかし、2倍の 2048 をxに入れると
y = 510.4985 → 510
と、正しい 512 から離脱しているのがわかります。
3/4 の 768 でも、
y = 191.4369
となり、四捨五入しても、正しい 192.000 とは異なって
しまいます。
10bit → 8bit の1/4問題、浮動小数点にして四捨五入
だけでは解決できません。
y = map(x, 0, 1023, 0, 255);
そのものが、間違っているのです。
投稿: 居酒屋ガレージ店主(JH3DBO) | 2022年11月 8日 (火) 09時02分