はじめに
調光カーブとは?(理論編)では、
実際のDMX値のフェードと、
人間の目で見たときに感じる調光との
ギャップについて解説しました。
今回は、Pythonでガンマテーブルを生成し、
PIC16F1938へ実装する方法について解説します。
PIC16Fでガンマ計算をさせる?
受信したDMX値に対して、
毎回ガンマ補正を計算することもできます。
しかし、ガンマ補正には指数関数の計算が必要です。
PIC16Fのような8bitマイコンでは、
このような浮動小数点演算は処理負荷が高くなります。
そこで今回は、あらかじめPythonで、
DMX値0~255に対応する256個のガンマ値を計算し、
PICのFlashへテーブルとして保存しておく方法を採用します。
実行時は計算ではなく配列を参照するだけなので、高速にガンマ補正を行えます。
Pythonで256段階の出力値を計算
⇩
C言語形式の gammaTable[256]を生成
⇩
PICのプログラムに貼り付けてへ書き込み
⇩
DMX値を配列の添字として参照
この流れで処理を行うようにしていきます。
Pythonでガンマテーブルを生成
まずは、第一ステップの
”Pythonで256個の値からなるガンマテーブルを作成”
です。
今回はVS CodeでPythonを実行し、
PICへ貼り付けるためのガンマテーブルを自動生成します。
python
# ガンマ値
gamma = 2.2
print("const unsigned char gammaTable[256] = {")
for i in range(256):
value = round(pow(i / 255.0, gamma) * 255)
end = "," if i != 255 else ""
print(f"{value}{end}")
print("};")
round()で計算結果を0~255の整数に丸め、
PICへ貼り付けられるC言語の配列形式で
出力しています。
出力
c
const unsigned char gammaTable[256] = {
0, 0, 0, 1, 1, 2,
/*中略*/
253, 254, 255
};
PICへ貼り付け
生成された配列をPIC側のCソースへ
貼り付け、つぎの流れで使用します。
c
/***********ガンマテーブルの宣言************/
const unsigned char gammaTable[256] = {
...
};
⇓
例えばDMX値が100なら、
gammaTable[100]に格納されている補正後の値が
PWMに代入されます。
c
/*********変数定義*************/
unsigned char pwm;
pwm = gammaTable[dmx];
⇓
c
/******PWMの出力*****/
pwm_apply(0,pwm); //1ch目にガンマ計算されたPWMが出力される
ガンマ補正はこのような形で、
難しい指数計算を毎回せず、
ガンマテーブルを1回参照するだけで、
補正後のPWM値を出力させることができます。
このコード一式を
「PIC16F1938で4ch DMX受信からオフセットをかけた4ch PWM出力」
に入れ込んでテストしました。
今回は1・2chに下限オフセット処理とガンマ補正を適用し、
3・4chはDMX値をそのままPWMへ出力して比較しました。
実際のコードと結果
下限オフセット処理で得られた0~255の値から、
ガンマテーブルを参照します。
unsigned char Apply_offset(unsigned char data_vol, unsigned char offset) {
unsigned int span;
unsigned int value;
if (data_vol <= 2) return 0;
if (data_vol >= 255) return 255;
span = 255 - offset;
value = offset + (((unsigned int) (data_vol - 2) * span) >> 8);
if (value > 255) value = 255;
return (unsigned char) gammaTable[value];
}
valueそのものを返す代わりに、
gammaTable[value]を返すことで、
下限オフセット処理ごの値にガンマ補正を
適応しています。
その結果を、2chずつに分けて
出力します
unsigned char stored_offset[4];
unsigned char write_val[4];
for (char i = 0; i < 4; i++) {
stored_offset[i] = EEPROM_Read(i);
}
while (1) {
for (unsigned char i = 0; i < 4; i++) {
if(i < 2){
write_val[i] = Apply_offset(dimmer[i], stored_offset[i]);
} else{
write_val[i] = dimmer[i];
}
pwm_apply(i, write_val[i]);
}
}
これを実装したのが次の動画です。
左側のLED(オシロスコープの黄色波形)がガンマ補正ありの動きで、
右側のLED(オシロスコープの青色波形)がガンマ補正なしの動きとなります。
4chすべてを点灯すると動画では違いが分かりにくかったため、
今回は1ch目と4ch目のみを比較しています。
操作は、1ch目と4ch目のチャンネルフェーダをフルまで上げて、
マスターフェーダで操作しています。
ご覧のとおり、
ガンマ補正されている左のLEDは、
補正されていない右のLEDに比べて、
立上りがかなり緩やかになっているのが分かります。
また、補正されていない右のLEDは、
フェーダ操作の最初に一気に明るくなり、
後半から明るさの変化量が小さく感じます。
一方、左のLEDは、
フェーダの操作中ずっとLEDの明るさが
変化しているように感じます。
これがガンマ補正の効果です。
次回予告
次回は、DMX受信、下限オフセット、ガンマ補正など、これまで実装してきた処理を組み合わせ、調光アルゴリズムとしてまとめていきます。

コメント