お世話になります。
すいません。下記のプログラムにおいてお聞きしたいことがあります。(プログラムの記述の順は無視してください。)
void int_tim_b1(void)がタイマーによって10ms毎に呼ばれ、void control_pid(void)の
関数処理が始まり、float TBL_target(float sec, tbl_target *tbl)にテーブル値を引数として
渡すようなのですが、float TBL_target関数において府に落ちない点があります。
例えば、10ms経ち、引数secに0.01が入り、if(sec > tbl[i].time)の条件においてi = 0なので、
tbl[i].time == 0なので、次のif(0 > tbl[i].time)が判定されますが、これは「偽」ですので、
処理はされず、次のelse if(i == 1)もまだi == 0なので、実行されず、elseの中が処理されると
思うのですが、tbl[i-1].target、tbl[i-2].target等の処理は配列の要素の中身が負となってしまうと思うのですが、
違いますでしょうか?
又、else if(i == 1)の処理もtbl[i-1].target == 0となってしまい、次の割り算処理において
「0/0」の0割り処理となってしまう気がいたします。
自分の理解が間違っていると思うのですが、何分わからず、大変困っております。
何卒ご教授のほどよろしくお願いいたします。
typedef struct {
float time;
float target;
} tbl_target;
void control_pid(void);
float TBL_target(float sec, tbl_target *tbl);
const tbl_target tbl_target_angle[ ] = {
/*time[sec],target_angle[m/sec] */
0,0,
4.99f, 0,
5,PI/2,
10,PI/2,
15,0,
20,0,
-1,-1,
};
#pragma interrupt(INT_TimerB1)
void int_tim_b1(void)
{
IRR2.BIT.IRRTB1 = 0; /* 割り込み要求フラグクリア*/
if(c_start)
{
control_pid();c_time += 10;
}
}
void control_pid(void)
{
theta_ref = TBL_target((float)c_time / 1000, tbl_target_angle); /* 目標値*/
}
float TBL_target(float sec, tbl_target *tbl)
{
int i;
float a, b;
i = 0;
while(1){
if(sec > tbl[i].time){
if(0 > tbl[i].time){
/* -1:テーブル終端の場合 */
if(i == 0){
/* テーブルデータなし */
return 0;
}
else if(i == 1){
/* 初期値は0として直線補間 */
a = tbl[i-1].target / tbl[i-1].time;
b = 0;
return a * sec + b;
}
else{
/* 前2点で直線補間 */
a = (tbl[i-1].target - tbl[i-2].target) /
(tbl[i-1].time - tbl[i-2].time);
b = tbl[i-1].target - a * tbl[i-1].time;
return a * sec + b;
}
}
i++; /* 次のデータへ */
}
else if(sec == tbl[i].time){
/* テーブルデータと同じ場合 */
return tbl[i].target;
}
else{
if(i > 0){
/* 前1点で直線補間 */
a = (tbl[i].target - tbl[i-1].target) /
(tbl[i].time - tbl[i-1].time);
b = tbl[i].target - a * tbl[i].time;
return a * sec + b;
}
else{
/* 前1点は0として直線補間 */
a = tbl[i].target / tbl[i].time;
b = 0;
return a * sec + b;
}
}
}
}
A 回答 (3件)
- 最新から表示
- 回答順に表示
No.3
- 回答日時:
> ただ、else if(i == 1)の時の処理がいつかのタイミングでされると思うのですが、
> else if(i == 0)の処理が行われるタイミングがこない気がいたします。
たしかに、あまり綺麗なコードではないですが。
このプログラムがどんな原理でどんな処理をしようとしているのか、を考えるのがいいのではないでしょうか?
このプログラムの目的は、 tbl_target_angle のtimeで指定された時刻に target になるような出力を得ることです。
sec=tbl[i].timeのときはそのままtbl[i],targetを、
tbl[i-1].time<sec<tbl[i].timeのときは、線形補間します。
そこで、 戦略として、次のようにします。
(1)sec > tbl[i].time の場合:
tbl[i-1].time<tbl[i].time<sec の状態です。
一つ隣りの区間(tbl[i].time,tbl[i+1].time)に入っているかどうか調べるために、 i++して次のループへ行きます。
(2) sec=tbl[i].time なら そのまま tbl[i],target をreturnしてループ終了です。
(3) それ以外の場合
残るは、 sec < tbl[i].time しかありません。
また、ループしてここに来ているので、前の段階ではsec > tbl[i-1].time だとわかっています。
つまり、 tbl[i-1].time<sec<tbl[i].time ですので、補間してループ終了です。
ここで、問題になるのは、 secがtblの範囲外だった場合です。
そこで、tblの終端として、time=-1 となる項目が追加されています。
tblの最後まで来てしまったら、特別な処理をしてループを終了させます。
if (0>tbl[i].time)~ は、 tbl[i] が終端だった場合の処理をするためのものです。
となると
i==0 が真となるのは
tbl[]={{-1,-1}}
というデータが空の時だけです。
i==1 が真となるのは
tbl[]={
{2,4},
{-1,-1}
}
というデータが1つしか無い時だけです。
No.2
- 回答日時:
if ~ else ~ の関係を確実に掴むようにしてください。
整形ツールを使って、字下げをちゃんとつけるのもよいでしょう。
// ここの特性上、空白がまとめられてしまうので、非常にわかりづらくなってしまいます。
if (A) {
if(B) {
} else { /* ここ */
}
}
とあったら、
if(A) の後の { と、それに対応する } までが 真のときに実行されるthen節です。
if(A)に対するelseは、上記の } の後に記述されます。
/* ここ */ のelse は、 if(A)の{}の中にあるので、 if(A)に対するelseではありません。
> 例えば、10ms経ち、引数secに0.01が入り、if(sec > tbl[i].time)の条件においてi = 0なので、
> tbl[i].time == 0なので、次のif(0 > tbl[i].time)が判定されますが、これは「偽」ですので、
> 処理はされず
まではよいのですが、その後が間違いです
> 次のelse if(i == 1)
は
if(i == 0) {
/* テーブルデータなし */
} else if(i == 1) {
/* 初期値は0として直線補間 */
} else {
/* 前2点で直線補間 */
}
となっている i==0に対するelse です。
これらは
if(0 > tbl[i].time){
}
に対する then節の{}の中に書いてあるので、 偽の場合は実行されません。
この回答への補足
お忙しいところご回答いただき誠にありがとうございます。
回答して頂いた内容を拝見させて頂き、まだ完全ではないですが、理解できました。
ただ、else if(i == 1)の時の処理がいつかのタイミングでされると思うのですが、
a = tbl[i-1].target / tbl[i-1].time;において
tbl[i-1].target == 0、tbl[i-1].time == 0となってしまうのは間違いないと思うのですが
違いますでしょうか?
というよりも、else if(i == 0)の処理が行われるタイミングがこない気がいたします。
以上、何卒よろしくお願いいたします。
No.1
- 回答日時:
違います。
括弧対応を誤解していると思います。
47行目の if (0 > tbl[i].time) {に対応した}は64行目 (i++の直前) の}ですよね。
つまり、i == 0のとき、if (0 > tbl[i].time)がfalseとなるので、i++が実行され、その後にwhileループ内で実行されるべき文がないのでwhileループの先頭から、実行すると思います。
i == 1のとき、46行目 if (sec > tbl[i].time) {がfalseで、66行目 } else if (sec == tbl[i].time) {もfalseなので、69行目のelseが実行され、70行目if (i > 0) {がtrueなので、/* 前1点で直線補間 */のブロックを実行し、値をreturnしていると思います。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- JavaScript 追加ボタンを押した際に ok ボタンを押した場合のみ入力値が追記されるようにしたいです 6 2022/05/29 09:57
- Visual Basic(VBA) このマクロの説明文を教えてほしいです。 1 2023/01/12 09:17
- Visual Basic(VBA) ExcelのVBAコードについて教えてください。 2 2022/05/26 17:19
- Visual Basic(VBA) フォーム上のリストボックスに重複して表示しています 3 2022/10/19 11:55
- Visual Basic(VBA) VBAコードで質問があります 2 2022/10/20 15:27
- Visual Basic(VBA) VBAチェックボックスで有効無効切り替えできるように 5 2022/10/21 16:13
- Visual Basic(VBA) VBA チェックボックスの設定について 1 2022/10/24 10:27
- Visual Basic(VBA) ExcelのVBAコードについて教えてください。 2 2022/03/25 08:33
- Java 複数TBLのオブジェクトを1つの変数(オブジェクト)でまとめて管理したい 1 2022/12/17 00:12
- Visual Basic(VBA) ExcelのVBAコードについて教えてください。 4 2023/05/26 10:43
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
SELECTで1件のみ取得するには?
-
sqlplusの処理が途中でとまる
-
Date型にNULLをセットしたい V...
-
SQL>UPDATEと同時にその件数を...
-
oracleのinsert select性能
-
☆☆☆☆SQL Olacle 3つ以上の文字...
-
ORDER BY 半角カナ
-
Oracleでの文字列連結サイズの上限
-
GROUP BYを行った後に結合した...
-
access 自動採番 年が変わる...
-
Accessで別テーブルの値をフォ...
-
ADO VBA 実行時エラー3021
-
select句副問い合わせ 値の個...
-
Excelで、改行がある場合の条件...
-
select insertで複数テーブルか...
-
使うべきでない文字。
-
OracleのSQL*PLUSで、デー...
-
SELECTの結果で同一行を複数回...
-
SQL文で右から1文字だけ削除す...
-
JSPのNULLレコード表示について...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
SELECTで1件のみ取得するには?
-
Date型にNULLをセットしたい V...
-
SQL>UPDATEと同時にその件数を...
-
sqlplusの処理が途中でとまる
-
oracleのinsert select性能
-
ORDER BY 半角カナ
-
☆☆☆☆SQL Olacle 3つ以上の文字...
-
AccessVBAでリンクテーブルの参...
-
SELECTでの指定行からの指定行...
-
[Access]時間帯の重複チェック
-
PLSQLで変数に格納されたSQL文...
-
取得するデータの件数指定、MyS...
-
PostgreSQLで小数点以下を処理...
-
サブクエリ内のORとANDについて
-
異なるDB間でのJOINやVIEWについて
-
SELECTについて
-
表の結合について
-
ACCESSのSQLの書き方
-
ACCESSとORACLEで抽出結果が異なる
-
SQL文(最新データ且つ条件付)...
おすすめ情報