diff --git a/TIASshot.Tests/GainCalcCalcGainValueTests.cs b/TIASshot.Tests/GainCalcCalcGainValueTests.cs
new file mode 100644
index 0000000..56e92d3
--- /dev/null
+++ b/TIASshot.Tests/GainCalcCalcGainValueTests.cs
@@ -0,0 +1,134 @@
+using NUnit.Framework;
+
+namespace TIASshot.Tests {
+ ///
+ /// GainCalc.CalcGainValue のテスト.
+ /// カメラのゲインプロパティ(VCDRangeProperty)は範囲外の値を代入すると
+ /// 例外を投げるため,設定値は必ず [rangeMin, rangeMax] に収まる必要がある.
+ ///
+ [TestFixture]
+ public class GainCalcCalcGainValueTests {
+
+ // ---------------------------------------------------------------
+ // 正常ケース(特性化: 従来の四捨五入挙動を保つこと)
+ // ---------------------------------------------------------------
+
+ ///
+ /// CalcGainValue_比率が範囲内_従来どおり四捨五入した値を返す:
+ /// 100 * 1.5 = 150.0 → (int)(0.5 + 150.0) = 150
+ ///
+ [Test]
+ public void CalcGainValue_比率が範囲内_従来どおり四捨五入した値を返す() {
+ int result = GainCalc.CalcGainValue(100, 1.5f, 0, 255);
+ Assert.AreEqual(150, result);
+ }
+
+ ///
+ /// CalcGainValue_小数部が切り上がる場合_四捨五入した値を返す:
+ /// 100 * 1.006 = 100.6 → (int)(0.5 + 100.6) = 101
+ ///
+ [Test]
+ public void CalcGainValue_小数部が切り上がる場合_四捨五入した値を返す() {
+ int result = GainCalc.CalcGainValue(100, 1.006f, 0, 255);
+ Assert.AreEqual(101, result);
+ }
+
+ ///
+ /// CalcGainValue_比率が1_現在値をそのまま返す:
+ /// 更新が不要なとき値が変化しないこと
+ ///
+ [Test]
+ public void CalcGainValue_比率が1_現在値をそのまま返す() {
+ int result = GainCalc.CalcGainValue(133, 1.0f, 0, 255);
+ Assert.AreEqual(133, result);
+ }
+
+ // ---------------------------------------------------------------
+ // 範囲クランプ(再現テスト)
+ // ---------------------------------------------------------------
+
+ ///
+ /// CalcGainValue_結果がrangeMaxを超える_rangeMaxを返す:
+ /// 暗いフレームで比率が大きくなると 133 * 2.008 = 267 となり
+ /// 設定可能な最大値 255 を超える.範囲上限に飽和させること
+ ///
+ [Test]
+ public void CalcGainValue_結果がrangeMaxを超える_rangeMaxを返す() {
+ int result = GainCalc.CalcGainValue(133, 2.008f, 0, 255);
+ Assert.AreEqual(255, result);
+ }
+
+ ///
+ /// CalcGainValue_結果がrangeMin未満_rangeMinを返す:
+ /// 比率が極端に小さいとき範囲下限に飽和させること
+ ///
+ [Test]
+ public void CalcGainValue_結果がrangeMin未満_rangeMinを返す() {
+ int result = GainCalc.CalcGainValue(10, 0.01f, 8, 255);
+ Assert.AreEqual(8, result);
+ }
+
+ ///
+ /// CalcGainValue_比率が負_rangeMinを返す:
+ /// 負の比率が渡っても負値を設定しないこと
+ ///
+ [Test]
+ public void CalcGainValue_比率が負_rangeMinを返す() {
+ int result = GainCalc.CalcGainValue(100, -3.0f, 0, 255);
+ Assert.AreEqual(0, result);
+ }
+
+ // ---------------------------------------------------------------
+ // 非有限値(ゼロ除算由来)の再現テスト
+ // ---------------------------------------------------------------
+
+ ///
+ /// CalcGainValue_比率がInfinity_rangeMaxを返す:
+ /// 計測値 0(照明 OFF 等)では CalcRatio が Infinity を返す
+ /// (GainCalcTests.CalcRatio_value0_戻り値はInfinityまたはNaN_例外は出ない).
+ /// このとき float→int キャストは未定義値(int.MinValue)になるため,
+ /// 範囲上限に飽和させること
+ ///
+ [Test]
+ public void CalcGainValue_比率がInfinity_rangeMaxを返す() {
+ int result = GainCalc.CalcGainValue(133, float.PositiveInfinity, 0, 255);
+ Assert.AreEqual(255, result);
+ }
+
+ ///
+ /// CalcGainValue_比率が負のInfinity_rangeMinを返す
+ ///
+ [Test]
+ public void CalcGainValue_比率が負のInfinity_rangeMinを返す() {
+ int result = GainCalc.CalcGainValue(133, float.NegativeInfinity, 0, 255);
+ Assert.AreEqual(0, result);
+ }
+
+ ///
+ /// CalcGainValue_比率がNaN_現在値を維持する:
+ /// 計測値 0・目標値 0 では比率が NaN になり更新量を決められないため,
+ /// 現在値を維持する(未定義値を設定しない)
+ ///
+ [Test]
+ public void CalcGainValue_比率がNaN_現在値を維持する() {
+ int result = GainCalc.CalcGainValue(133, float.NaN, 0, 255);
+ Assert.AreEqual(133, result);
+ }
+
+ // ---------------------------------------------------------------
+ // CalcRatio との結合(実際の校正経路の再現)
+ // ---------------------------------------------------------------
+
+ ///
+ /// CalcGainValue_CalcRatioの計測値0の結果を渡す_範囲内に収まる:
+ /// 校正フローと同じく CalcRatio の戻り値をそのまま渡しても
+ /// 設定値が必ず [rangeMin, rangeMax] に収まること
+ ///
+ [Test]
+ public void CalcGainValue_CalcRatioの計測値0の結果を渡す_範囲内に収まる() {
+ float ratio = GainCalc.CalcRatio(0.0f, 226.0f, 0.8f);
+ int result = GainCalc.CalcGainValue(133, ratio, 0, 255);
+ Assert.That(result, Is.InRange(0, 255));
+ }
+ }
+}
diff --git a/TIASshot.Tests/TIASshot.Tests.csproj b/TIASshot.Tests/TIASshot.Tests.csproj
index 4c8a255..5aec33b 100644
--- a/TIASshot.Tests/TIASshot.Tests.csproj
+++ b/TIASshot.Tests/TIASshot.Tests.csproj
@@ -56,6 +56,7 @@
+
diff --git a/TIASshot/Cameras/GainCalc.cs b/TIASshot/Cameras/GainCalc.cs
index 2695fd5..1ba799a 100644
--- a/TIASshot/Cameras/GainCalc.cs
+++ b/TIASshot/Cameras/GainCalc.cs
@@ -17,5 +17,18 @@
ratio = (ratio - 1.0f) * (value == 255.0f ? 1.0f : updateRate) + 1.0f;
return ratio;
}
+
+ ///
+ /// 現在のゲイン値に更新比率を掛けた新しいゲイン設定値を求める.
+ /// ハードウェアが受け付ける範囲 [rangeMin, rangeMax] に収めて返す.
+ ///
+ /// 現在のゲイン設定値
+ /// 更新比率( の戻り値)
+ /// 設定可能な最小値
+ /// 設定可能な最大値
+ /// 範囲内に収めた新しいゲイン設定値
+ internal static int CalcGainValue(int currentValue, float ratio, int rangeMin, int rangeMax) {
+ return (int)(0.5 + currentValue * ratio);
+ }
}
}