オイラー法での計算とエンコード

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら

トピックに返信する


答えを正確にご入力ください。答えられるかどうかでスパムボットか否かを判定します。

BBCode: ON
[img]: ON
[flash]: OFF
[url]: ON
スマイリー: OFF

トピックのレビュー
   

展開ビュー トピックのレビュー: オイラー法での計算とエンコード

Re: オイラー法での計算とエンコード

#6

by そら » 7年前

>>Mathさんありがとうございます。
そのような解き方もあるのですね…難しいです。

②については、なんとか自力で解けそうなので解決とします。

Re: オイラー法での計算とエンコード

#5

by Math » 7年前

① L-R-C 回路網の問題はわれわれ電気工学を習った者は”キルヒホッフの法則”
http://www.gxk.jp/elec/musen/1ama/H15/h ... 2A04_.html
を用いてときます。この場合はインディシャル応答とおもわれるのでラプラス変換を用いて厳密解が得られます。
http://www.ice.tohtech.ac.jp/~nakagawa/ ... ce7_c3.htm

自然対数の底を e = 2.71828 18284 59045 23536 02874 71352 …とする。

ラプラス変換を施せば ステップ入力 t = 0以前にはVin = 0 その後Vin = V を与えると、
Vin (s) = V * (1/s)
I(s)*(R + 1/Cs) = V * (1/s) であるから Vc(s)=V*(1/(1 + sRC))*( 1/s )
Vr(s)=V*(sRC/(1 + sRC))*( 1/s )となる。

部分分数分解 と 逆ラプラス変換より 
Vc(t)=V*(1-e^(-t/RC))
Vr(t)=V*e^(-t/RC) よってI(t)=Vr(t)/R

となる。

Vc(t)=Q(t)/C ゆえ dVc(t)/dt = dQ(t)/dt * ( 1/C) = I(t)/C であるから初期値0として
Δt=0.001のとき、0≤t≤1.0の範囲でVc(t) , I(t)  ( v(t),i(t)  )は オイラー法で求まり上記厳密解よりチェック出来る。

Re: オイラー法での計算とエンコード

#4

by そら » 7年前

>>かずまさん返信ありがとうございます。

丁寧なコードありがとうございます。
mainの中でeulerMethodの関数を実行するっていう認識でよろしいでしょうか?
しかし、なぜeulerMethodで初期値を設定してはいけないのかわかりません。
dvdtで各パラメータの設定は行って良いのに、なぜなんでしょうか?

>>Mathさん返信ありがとうございます。
プログラムへのアドバイスありがとうございます。
説明は、、、頑張ります!

②について、図で説明するのは難しいので、より詳細に説明します。
モータが回転すると、エンコーダがパルスをだします。一回転に何パルス出るかをエンコーダの分解能といいます。
このパルスを数えるのがカウンタボードです。
カウンタボードにも分解能があり、もし分解能が3ビットであれば、カウンタ値は000→001→010→011→100→101→110→111→000と上がっていきます。(正方向の回転の場合)
また、モータはギアで出力するものに接続されています。
そのギア比も与えられます。
今回は、カウンタの分解能が2バイトです。
一度に2バイト読み込むことはできないので、1バイトずつ読み取ります。

条件:
1バイトずつの時間を変数とする関数(16進数)を2つ与えられます。
エンコーダの分解能1000、ギア比100が与えられます。
これらから0秒から5秒まで、0.001秒ごとに出力角度を出せというものです。

考え方について助言をいただきたいです。
こちらの考えとしては、16進数で与えられる2つの関数を10進数に変換後、和を出す。
これをエンコーダの分解能とギア比で割る。これを0.001秒ずつ5000回ループする

というものです。
助言をいただいた後、自力でプログラムを作成し、再度わからない部分を質問するという形をとりたいと思います。
よろしくお願いします。

Re: オイラー法での計算とエンコード

#3

by Math » 7年前

画像
もっとわかるように説明をしてください。
プログラムにはコメントをいれることと main 関数をかくことです。
http://www2.koyoen.birdview.co.jp/~abcxyz/た.jpg

②も図を書いて分かり易く!

Re: オイラー法での計算とエンコード

#2

by かずま » 7年前

main がないから実行できません。
初期条件などは main から引数で与えます。
eulerMethod の中に、初期値を書いてはいけません。
問題と同じ変数名を使ったほうが分かりやすいでしょう。

コード:

#include <stdio.h>
 
double dvdt(double v)
{
    double C = 0.00001;  // 10μF
    double R = 10000;    // 10 kΩ
    double V = 5;        //  5 V
    // i = (V - v) / R  --- (1)
    // dvdt = i / C     --- (2)
    return (V - v) / (R * C);
}
 
// オイラー法(初期条件 v0, 区間 [t0, tn], 分割数 n)
double eulerMethod(double v0, double t0, double tn, int n)
{
    double v = v0;
    double t = t0;
    double dt = (tn - t0) / n;
    int k;
    
    for (k = 1; k <= n ; k++) {
        v += dvdt(v) * dt;
        t = t0 + k * dt;
        printf("%.3f: %f\n", t, v);
    }
    return v;
}

int main(void)
{
    double v = eulerMethod(0, 0, 1, 1000);
    printf("時刻 1.0(秒)のコンデンサにかかる電圧 = %f\n", v);
    return 0;
}

オイラー法での計算とエンコード

#1

by そら » 7年前

初めまして。C言語を学びはじめて1週間ほどの大学生です。
今回、大学での課題で行き詰まったので2つほど質問させていただきます。
プログラミング以前に、数学の知識もまだまだな為、そういった点もアドバイスお願いします。

①直列のRC回路において、電源電圧Vと抵抗RとコンデンサCは決められています。
スイッチを入れると、抵抗には
i=(V-v)/R (1)
の電流が流れ(vはコンデンサにかかる電圧)、それによってコンデンサCが充電されます。
vはdv/dt=i/C (2)
の割合で上昇します。
これをオイラー法で
v(tk+1)=v(tk)+(1/C)i(tk)Δt (3)

Δt=0.001のとき、0≤t≤1.0の範囲でv(t),i(t)を求めろというものです。

コード:

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

double dxdt( double x)
{
    double c = 0.00001;
    double r = 10000;
    double e = 5;
    return (e-x)/(r*c);
}

// オイラー法(初期条件x0,  区間[t0, tn])
double eulerMethod(double x0, double t0, double tn, int n)
{
    int i;
    double x, t, h;
    x = x0=0;
    t = t0=0;
    h = 0.001;
    n=1000;
    
    // 漸化式を計算
    for ( i=1; i <= n ; i++){
        x += dxdt(x) * h;
        t = t0 + i*h;
        printf("%f\n", x);
    }
    return x;
}
 


のようなものになりそうなんですが、如何せんまだまだコードについての理解が乏しく、行き詰まっています。
解き方の考え方についてのアドバイスや、コードの書き方についてのアドバイスよろしくお願いします。

②2つの関数が示すカウンタ値をモータの角度に変換し、tによっての出力角度を出せというものです。
エンコーダの分解能を1000、ギア比を100、カウンタボードの分解能を2バイトとし、2つの関数は上位バイトと下位バイトを渡します。
サンプリングタイムを0.001秒とし、時刻範囲は0から5です。

こちらの解く方針としては、16進数で与えられる2つの関数を10進数に変換後、2つの関数(上位バイトと下位バイト)の和を出す。
これをエンコーダの分解能とギア比で割る。これを0.001秒ずつ5000回ループすればよいのでは、と考えました。
まだ、プログラミングは行っていませんが、考え方はあっているのでしょうか?
16進数の概念やカウンタボードの概念についての理解が全然です。
考え方を示していただければ、こちらでコードを作って提案しますのでよろしくお願いします。
また、問題に不備がありましたら画像にて説明いたしますのでよろしくお願いします。

ページトップ