• ベストアンサー

指数関数?duty制御

カテゴリー違いかもしれませんが、とりあえずこちらでご相談させていただきます。 picマイコンを使って、自動的に電球の明るさをフェードイン、 フェードアウトさせる照明を制作したいと考えています。 私はマイコンのプログラム部分だけの担当です。 電圧と、光の強さの関係がイコールでないため、 添付したような、グラフの関係になるのかと思うのですが これを数式で表すと、どのような式になるのかがわかりません。 (フェードイン、フェードアウトまでの時間をmsecとしています) ledの制御などでも、指数関数を用いたフェードインの仕方は よくやられているようなのですが。。 数学がほとんどわからず、またC言語、picに対しても 初心者です。 よろしければ、ご教授いただけると幸いです。

質問者が選んだベストアンサー

  • ベストアンサー
  • Interest
  • ベストアンサー率31% (207/659)
回答No.4

結論を先に書きます。 次のテーブルを使って、10ms毎にテーブルのインデックスを一つずつ上げていけば、指数関数のカーブに沿って200ms後にdutyが255になります。 /* 10ms毎に変化させるdutyのテーブル */ const unsigned char dutyTable[20] = { 2 , 2 , 3 , 4 , 5 , 7 , 9 , 12 , 16 , 21 , 27 , 36 , 48 , 63 , 83 , 109 , 144 , 190 , 250 , 255 }; (参考) t=200ms後にduty=255になる指数関数は、   255 = a^200 (^は累乗の意味です) を a について解くと(計算過程を省略しますが)   a = 1.028 であるから、   duty = 1.028^t と求まる。 以上が > 添付したような、グラフの関係になるのかと思うのですが > これを数式で表すと、どのような式になるのかがわかりません。 に対する回答です。そうなんですが、PICの中で浮動小数点の計算をしたくないので、10ms毎にdutyを変化させた場合のテーブルを用意しておき、プログラム中ではこのテーブルを参照するだけにします。そのテーブルが、最初に書いた dutyTable です。

kassel
質問者

お礼

お礼、大変おそくなってしまい、申し訳ございません! 仕事の合間にやっていたもので、なかなか試してみることができず、、 再度のご回答、本当にありがとうございます。 テーブルでの処理、初心者の私でもわかりやすく とても参考になりました。 数値を変えて、テーブルを作ってみたところ、理想に近い数値の変化に なり、感謝しております。 未だ、picでの実装はできていないのですが、、できると思います。 がんばります。

その他の回答 (3)

回答No.3

>数学がほとんどわからず、またC言語、picに対しても初心者です。 まず1つ。 「picマイコンでは、数学的な解法はご法度」です。 「数学的な解法」に頼ると、どうしても「浮動小数点数を扱う関数を使う」と言う事になります。 で「picマイコンで、SQRTなどの浮動小数点数を扱う関数を使うと、プログラムが肥大化し、ROMの容量を圧迫する」ので、絶対にやっちゃいけません。 グラフを見ると、縦軸は「下が0、上が255」で、横軸は「左が0、右が200msec」のようですね(サイト掲載時に縮小されてしまい、字が潰れて読めないですが) 多分「200msecのうち、0なら点灯時間が0msec(全消灯)、255なら200msec(全点灯)」って事だと思います(違うなら指摘して下さい) さて、このグラフを良く見ると「部分的に、殆ど直線の部分がある」と言うのが判ります。 それでは、このグラフを「直線の部分」ごとに「分断」して見ます(添付画像) 横に引いた青い直線は、下から順に、横軸の「64」「128」「192」「224」の所に引いてあります。 「0~64の間」は「0msec~90msec」までの「ほぼ直線」です。ここは「直線」にしちゃいましょう。 「64~128の間」も「90msec~160msec」までの「ほぼ直線」です。ここも「直線」にしちゃいましょう。 「128~192の間」も「160msec~192msec」までの「ほぼ直線」です。ここも「直線」にしちゃいましょう。 「192~224の間」も「192msec~198msec」までの「ほぼ直線」です。ここも「直線」にしちゃいましょう。 「224~255の間」も「198msec~200msec」までの「ほぼ直線」です。ここも「直線」にしちゃいましょう。 さて「224~255」だと「32段階」です。この32段階を「198~200」の間で直線的に変化させないといけませんから、 224=198msec 225=198.1msec 226=198.2msec (中略) 253=199.8msec 254=199.9msec 255=200msec にしないといけません。 つまり「精度は0.1msecくらいあれば良い」と言う事です。 言いかえれば「1を引数に渡すと0.1msec待ち、2000を引数に渡すと、200msec待つ関数があれば良い」と言う事です。 すると「0~255で、対応する0~2000までの数値を返す関数」があれば良い事になります。 この関数は 0~64は0~900を返す 64~128は900~1600を返す 128~192は1600~1920を返す 192~224は1920~1980を返す 244~255は1980~2000を返す って事です。 以下のようになるでしょう。 int GetDuty(int inp) {  if (imp < 64) return ((imp * 9000 / 64) + 5) / 10;  if (imp < 128) return (((imp - 64) * 7000 / 64) + 5) / 10 + 900;  if (imp < 192) return (((imp - 128) * 3200 / 64) + 5) / 10 + 1600;  if (imp < 224) return (((imp - 192) * 600 / 32) + 5) / 10 + 1920;  return (((imp - 224) * 200 / 31) + 5) / 10 + 1980; } この関数は0~255を与えると0~2000を返します。 照度調整では int Duty; int InpVal; for(;;) {  InpVal = PortInput(); // I/Oポートから0~255の値を取得  Duty = GetDuty(InpVal);  if(duty){   OnLight(); // 点灯   if(duty!=2000) mSecWait(Duty); // Duty×0.1msec待つ  }  if(duty!=2000){   OffLight(); // 消灯   if(duty) mSecWait(2000 - Duty); // (2000-Duty)×0.1msec待つ  } } と言うようなループを組む事になります。 なお、上記のルーチンは「待ってる間は何もしないので、適切ではない」です。 本来であれば、点灯と消灯の間の「待ち時間中」にも、I/Oポートの監視を行い、照度ツマミが回されたのを「常時監視」すべきです。 この例では「待ってる間、ツマミが回されても反応しない」ので、ツマミを早く回すと追従しません。 但し、照明器具によっては「変化が急激だと、電球などの発光部分の消耗が激しくなる」などの理由で「あえて、反応をにぶくする」と言う事も行われます。

kassel
質問者

お礼

御礼遅くなりました! ありがとうございます。 >picマイコンでは、数学的な解法はご法度 知りませんでした。。。 >縦軸は「下が0、上が255」で、横軸は「左が0、右が200msec」のようですね すみません、y軸は255 ですが、x軸は 2500 (msec)でした。 言葉足らずでした。お詫び申し上げます。 直線で考えるということですね。なるほどです! 情報の少ない中、ここまで考えてくださって感謝です。 参考になりました。ありがとうございました。

  • pyonmae
  • ベストアンサー率64% (40/62)
回答No.2

こんにちは。 私も数学は苦手ですが、個人的にも興味ありましたので、考えてみました。 グラフの形からして放物線を横にしたものっぽいので、平方根のグラフだと決め付けてやってみます。 平方根のグラフは、お示しのグラフをちょうど180°回転したような形ですので、これを式にしますと、以下のようになるかと思います。 エクセルでグラフにしてみると、若干形が違うような気もしますが、近いっちゃ近いのではないでしょうか・・・。 今回設定する輝度:L 輝度に応じたタイマの設定値:T タイマのカウントアップ値:Tmax 輝度階調数:Lmax  T = (1 - SQRT((Lmax - L) / Lmax)) * Tmax 実際にマイコンに組み込む際にはmsへの換算とか整数演算にするとかテーブルにするとかもう一工夫が必要かと思いますが、がんばって下さい。

kassel
質問者

お礼

お礼遅くなってしまい、申し訳ありません! なるほど、このような式になるのですね。。 picには使わないかもしれないのですが 大変参考になります。 ありがとうございました!

  • Interest
  • ベストアンサー率31% (207/659)
回答No.1

何を教えてほしいのか良くわかりませんが、とにかく > picマイコンを使って、自動的に電球の明るさをフェードイン、 > フェードアウトさせる照明を制作したい というのだけは了解しました。kasselさんはPICのプログラム担当とのことですが、回路を設計された方はどういう制御方式にするつもりで回路設計されたのでしょうか。相談してみましたか? > 電圧と、光の強さの関係がイコールでないため、 > 添付したような、グラフの関係になるのかと思うのですが そこは、どうしたいのか、ですよね。PWM方式で電球に流れる電流を高速でON/OFFして、ON/OFF時間の比率(=duty)を変えることで明るさを連続的に変化させたいのかなぁ、とご質問のタイトルから推測しました。が、その変化の仕方は別に指数関数的じゃなくてもいいと思うのですが、だめですか?  直線的な変化でも指数関数的な変化でも、どちらでもほとんど同じ方法で対応できますので、まずは直線的に dutyを変化させる方法で設計してみてはいかがでしょうか。具体的な実装方法は、回路がどうなっているか、PICがほかにやらなきゃいけないことがあるか、コンパイラは何を使っているかに依存しますので、補足があればまた回答いたします。

kassel
質問者

お礼

あ、添付できませんでした。。すみません。 http://www.picfun.com/document/powerunit/triac07.gif これにほぼ近いものです。 picの種類がちがうこと(16F84Aを使用します。) LCDを使わないこと pcとの通信は行わないこと が違います。 なので、この図では16番ピン出力にあたる部分でしょうか。 いろいろと、投げてしまい、申し訳ございません。。

kassel
質問者

補足

ご回答ありがとうございます。 言葉が足りませんでした。補足させていただきますね >そこは、どうしたいのか、ですよね。PWM方式で電球に流れる電流を高速でON/OFFして、ON/OFF時間の比率(=duty)を変えることで明るさを連続的に変化させたいのかなぁ、とご質問のタイトルから推測しました。 そのとおりです! >が、その変化の仕方は別に指数関数的じゃなくてもいいと思うのですが、だめですか?  この表に近い電圧の変化をしてくれと頼まれておりまして。。 直線だと、望み通りの結果にならないそうです。 pic16f84A の10-13番ピンをlow にすることで スイッチングし、duty制御したいと考えています。 回路図も、添付いたします。 このサイトのプログラムを参考にしています。 http://www.picfun.com/equipj61.html コンパイラは、ccs社のPCMです。

関連するQ&A