面白さのために、そしてそれが実行できることを証明するために、sin(x)の結果を計算して1ビットのエラーで24ビット(3バイト)になるAVRアセンブリルーチンを終了しました。入力角度は、小数点以下1桁の度数で、最初の象限のみ000から900(0〜90.0)までです。それは210未満のAVR命令を使用し、平均211マイクロ秒で実行され、211us(角度= 001)から213us(角度= 899)まで変化します。
AVRマイクロコントローラーを考慮して、計算に最適なアルゴリズムを検討するだけで10日(自由時間)以上かかり、浮動小数点はなく、すべての可能な除算が排除されました。さらに時間がかかったのは、整数に適切なステップアップ値を作成することでした。精度を高めるには、1e-8の値を2の整数2 ^ 28以上にステップアップする必要があります。精度と切り上げのすべてのエラーの原因が見つかったら、計算の分解能を2 ^ 8または2 ^ 16増やして、最良の結果が得られました。最初に、すべての値をInt(x)またはRound(x、0)としてAVRコア処理を正確に表すようにして、Excelですべての計算をシミュレートしました。
たとえば、アルゴリズムでは、角度はラジアンでなければならず、ユーザーが入力しやすいように入力は度単位です。度をラジアンに変換するための自明な式はrad = degrees * PI / 180ですが、見栄えがよく簡単ですが、そうではありません。PIは無限数です。使用する桁数が少ない場合、出力でエラーが発生し、180で割ると、 AVRビット操作には除算命令がないため、整数1をはるかに下回る数値が含まれるため、結果は浮動小数点数を必要とします。たとえば、ラジアン1°(度)は0.017453293です。PIと180は定数なので、単純な乗算のためにこれを逆にしないのはなぜですか?PI / 180 = 0.017453293、2 ^ 32を掛けると、結果は定数74961320(0x0477D1A8)になり、この数値に角度(度単位)を掛けます。90°に対して900と言い、4ビット右(÷16)にシフトして4216574250(0xFB53D12A)を取得します。これは、2 ^ 28の拡張による90°のラジアンであり、単一の除算なしで4バイトに収まります(4ビットシフト右)。ある意味では、そのようなトリックに含まれるエラーは2 ^ -27よりも小さいです。
したがって、以降のすべての計算では2 ^ 28高いことを覚えておく必要があります。外出先での結果を16、256、または65536で割り、解決に役立たない不要な増大するハンガーバイトを使用しないようにする必要があります。それは骨の折れる仕事であり、各計算結果のビットの最小量を見つけ、結果の精度を24ビット前後に保ちました。Excelフローで上位または下位のビット数を使用してtry / errorで実行されるいくつかの計算のそれぞれ、結果のエラービットの全体的な量を、コードを900回実行するマクロで0-90°を示すグラフで監視します。 10分の1度に1回。この「ビジュアル」Excelアプローチは私が作成したツールであり、コードのすべての部分に最適なソリューションを見つけるのに大いに役立ちました。
たとえば、この特定の計算結果13248737.51を13248738に切り上げるか、「0.51」の小数を失うだけで、900のすべての入力角度(00.1〜90.0)テストの最終結果の精度にどのくらい影響しますか?
動物をすべての計算で32ビット(4バイト)以内に収めることができ、結果として23ビット以内の精度を得るという魔法に終わりました。結果の3バイト全体をチェックする場合、エラーは±1 LSBであり、未解決です。
ユーザーは、独自の精度要件のために、結果から1バイト、2バイト、または3バイトを取得できます。もちろん、1バイトで十分な場合は、単一の256バイトのsinテーブルを使用し、それを取得するためにAVR 'LPM'命令を使用することをお勧めします。
Excelシーケンスをスムーズかつきちんと実行すると、ExcelからAVRアセンブリへの最終的な変換に2時間もかかりませんでした。
その時、私はさらに圧迫し、レジスターの使用を減らすことができました。実際の(最終ではない)コードは約205命令(約410バイト)を使用し、sin(x)計算を平均212us、16MHzのクロックで実行します。その速度では、1秒あたり4700以上のsin(x)を計算できます。重要ではありませんが、ルックアップテーブルを使用しなくても、23ビットの精度と解像度で最大4700Hzの正確な正弦波を実行できます。
基本アルゴリズムはsin(x)のテイラー級数に基づいていますが、AVRマイクロコントローラーと精度を念頭に置いて私の意図に合うように大幅に変更されました。
2700バイトのテーブル(900エントリ* 3バイト)を使用すると速度が魅力的になりますが、その面白さや学習経験は何ですか?もちろん、CORDICアプローチも検討されましたが、おそらく後で、ここでのポイントは、テイラーをAVRコアに押し込み、乾いた岩から水を取り出すことです。
Arduinoの「sin(78.9°)」は、212us未満で23ビットの精度で処理(C ++)を実行でき、必要なコードは205命令未満で実行できるのでしょうか。C ++がCORDICを使用している可能性があります。Arduinoスケッチはアセンブリコードをインポートできます。
ここにコードを投稿しても意味がありません。後でこの投稿を編集して、おそらくこのURLの私のブログにWebリンクを含めます。ブログはほとんどがポルトガル語です。
この趣味のお金なしのベンチャーは興味深いもので、除算命令なしで、8x8ビットでの乗算のみで、16MHzでほぼ16MIPSのAVRエンジンの限界を押し上げました。sin(x)、cos(x)[= sin(900-x)]およびtan(x)[= sin(x)/ sin(900-x)]を計算できます。
とりわけ、これは私の63歳の脳を磨き、油を塗っておくのに役立ちました。10代の若者が「古い人々」はテクノロジーについて何も知らないと言ったとき、私は「もう一度考えてみてください。今日あなたが楽しむすべての基礎を作ったのは誰だと思いますか?」と答えます。
乾杯