C言語でのパルス幅の合計についての問題

このQ&Aのポイント
  • C言語におけるパルス幅の合計を計算する問題について質問します。
  • 現在のプログラムでは、Riseの値によって計算方法が異なり、一般化すると値が大きくなる問題があります。
  • 質問は、一般化したプログラムにおいてもべた書きのような分岐を回避する方法があるかどうかです。
回答を見る
  • ベストアンサー

C言語 値の合計について(PICマイコン上)

C言語、値の合計について(PICマイコンを使用) C言語のアルゴリズムについての質問です。 申し訳ございませんが、前提が長く、質問が後半にあります。 1.行いたいこと パルス幅を取り込んで、パルス幅を足しこんでいく。この値を面積とする。 2.仕様 ・500usでループを回しており、その都度、パルス幅を取得しています。 (パルス幅は1つであったり、複数であったりします。パルスの数を「Rise」という 変数で記憶しています。) ・そのパルス幅を取得し、一定ループ後に合計値を計算したい。 例) ___|¯¯|___|¯¯¯|___ Rise=1。中央のくぼみの幅を計算 ↓ ___|¯¯|_|¯¯|_|¯|____ Rise=2。中央2つのくぼみを計算 3.問題点 Riseの値でif分岐をした、べた書きしたプログラムと、より一般化したプログラムの 面積の値(SUM_Areaの値)が異なる。 一般化したものの方が値が大きくなる。 /*以下プログラム*/ // べた書き if(Rise==2){ Captime[1]=Captime_rise[2]-Captime_down[1]; //パルス幅の計算 Area[1] += Captime[1]; //面積計算 SUM_Area=Area[1]; //合計の面積 } // Rise==2 LOOP END else if(Rise==3){ Captime[1]=Captime_rise[2]-Captime_down[1]; Captime[2]=Captime_rise[3]-Captime_down[2]; Area[1] += Captime[1]; Area[2] += Captime[2]; SUM_Area=Area[1]+Area[2]; } // Rise==3 LOOP END else if(Rise==4){ Captime[1]=Captime_rise[2]-Captime_down[1]; Captime[2]=Captime_rise[3]-Captime_down[2]; Captime[3]=Captime_rise[4]-Captime_down[3]; Area[1] += Captime[1]; Area[2] += Captime[2]; Area[3] += Captime[3]; SUM_Area=Area[1]+Area[2]+Area[3]; } // 一般化したもの for(i=1;i<Rise;i++){ Captime[i]=Captime_rise[i+1]-Captime_down[i]; Area[i]+=Captime[i]; SUM_Area+=Area[i]; } 4.考察 一般化したプログラムの SUM_Area+=・・・・ の部分のみをifで場合分けすると、 (SUM_Area=Area[1]+Area[2]+Area[3]; の様にRiseの値で分岐) 値が一致したので この部分が悪さをしていると考えています。 5.質問 今回の場合はSUM_Areaの部分は、べた書き(Riseでの分岐)しか方法がないのでしょうか。 Riseが64個まであるので、プログラムが冗長になってしまいます。 宜しくお願いします

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

  • ベストアンサー
  • MSZ006
  • ベストアンサー率38% (390/1011)
回答No.3

#1です。何度もすみません。 修正プログラムには問題がありました。 例えばRize=4の次にRise=2がきてループが終了するような場合、SUM_AreaにはArea[1]と[2]しか足し込まれず、[3][4]が足し込まれないことになってしまいます。 なお、この問題は、お示しのべた書きプログラムでも同じことが言えると思います。 >一定ループ後に合計値を計算したい。 ということですので、ループ内ではSUM_Areaの計算はせずに、ループを抜ける際に、 Aera[1]~[64]の合計をSUM_Areaに格納するようにしたほうが良さそうです。

その他の回答 (2)

  • MSZ006
  • ベストアンサー率38% (390/1011)
回答No.2

#1です。修正後のプログラムに書き間違いがありました。 【誤】 for(i=1;i<=Rise;i++){ 【正】 for(i=1;i<Rise;i++){ です。Riseの前の = は不要です。

  • MSZ006
  • ベストアンサー率38% (390/1011)
回答No.1

仕様がいまいちはっきりしないのですが、 (1)パルスを取得 こんなのや、 ___|¯¯|___|¯¯¯|___ こんなの ___|¯¯|_|¯¯|_|¯|____ が取得され、 ・パルス数がRiseという変数に格納される。 ・Captime_rise[n]とCaptime_down[n] に、パルスの立ち上がり/立ち下がりの時刻が格納される。(n は1からRiseまで) (2)プログラムが実行される  ・パルス間のくぼみの時間の長さがArea[n]に「加算」される。(今回のパルスのみではなく、今までのすべてのパルスの累計)  ・すべてのArea[n]の合計がSUM_Areaに格納される。 (3)500μsごとに(1)(2)を繰り返す。 といったことでしょうか。 一般化したプログラムを(2)の箇所で実行すると、 例えば2回ループを廻したとすると、 SUM_Area+= の箇所で、1回目のデータが2回重複して加算されてしまうことになります。 (2回目のループの際にArea[n]にはすでに1回目のデータが格納されている状態で、そこに2回目ループのデータを加算しています) 正しいプログラムは、 SUM_Area=0; for(i=1;i<=Rise;i++){ Captime[i]=Captime_rise[i+1]-Captime_down[i]; Area[i]+=Captime[i]; SUM_Area+=Area[i]; } とすればよいと思います。

Snoodam
質問者

お礼

MSZ006様: アドバイスありがとうございます。 仰る通り、ループ外でSUM_Areaを計算するようにしたところ 上手く行きました。 Area[i]の計算まではforで回して計算しています。 また、私の稚拙な文章から仕様を読み取って頂きありがとうございます。 上手く言葉では言えないのですが、Riseは都度0に初期化されます。 (ラインカメラの仕様上) for(i=1;i<Rise;i++){ Captime[i]=Captime_rise[i+1]-Captime_down[i]; Area[i] += Captime[i]; //面積計算 -> Area = Area+ Captime[1] } Calc_area(); void Calc_area(void){ if(Rise==2) SUM_Area=Area[1]; else if(Rise==3) SUM_Area=Area[1]+Area[2]; /*以下 Rise==64まで分岐*/ } 一応ここに全文があります。 (決して「見て頂きたい」という厚かましいお願いではございません。) http://anasys.blog.fc2.com/blog-entry-15.html

Snoodam
質問者

補足

関係の無いことなのですが、MSZ006様はガンダムがお好きなのでしょうか。ファーストのご世代なのでしょうか。(Zの形式番号な為そう推測しました。)

関連するQ&A

  • C言語でのif文分岐について(PICで使用)

    お世話になります。 現在PICマイコンでC言語を用いて、プログラムを組んでいますが、煮詰まったので皆様のアドバイスを頂戴したく、質問させて頂きます。 問題点概要: if文の分岐がうまく行かない。 パルス幅を計測し、その幅に応じて個数を判別し、累積カウントをするプログラムです。 しかし、パルス幅での個数の判別がうまく行きません。 例)パルス幅100以上で「2つ」とカウントしたいところが、「1つ」とカウントする。 プログラム仕様: 1.パルスの幅を計測するプログラム 2.計測したパルス幅に応じて、個数を判別する。 3.個数を累積する。 4.表示する 1から3を2[ms]周期で実行しています。 ※カメラの前を物体が横切ると、カメラ出力がLになるので、そのエッジを見ています。 したがって、 カメラの前にずっと物体があると、出力がLのままなので、累積カウントがアップし続けます。 その時は、累積カウントをしないプログラムにしています。  → 一回目の検知時のみ累積カウントをアップさせる。 そのために、「PP」という変数を定義しています。 添付資料に、詳しく書いています。 見て頂けると幸いです。 カメラ出力の取り込みについて: 立ち上りエッジをCaptime_rise[Rise]; Riseは検知するたびに、インクリメントされます。(1から++) Downも同様です。 カメラは、物体を検知しないときは ______|‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾|________________ なので、Rise==Down==1です。 物体を検知すると ______|‾‾‾‾‾‾|_____|‾‾‾‾‾‾|______________ となります。 上述の通り、「カメラの前に物体がずっとある場合の、累積カウントアップ防止」の為に PP==1  // PPは前のRiseの値 の時のみ、累積を加算するようにしています。 PP==1の状態とは、物体を検知していない場合なので、この考えで大丈夫ではないかと思っています。 //プログラム抜粋 // 個数の計算 /* Captime[i] → 計測パルス Captime_rise[i] → 立上パルス Captime_down[i] → 立下パルス KOSU → 個数 KOSU_SUM → 累積個数 PP → 1つ前のサイクルのRiseの値 STD_width → 個数判別の基準値 */ if(Rise==1){ KOSU=0; Captime[1]=0; } else if(Rise==2){ // パルス幅の計算 Captime[0]=Captime_down[1]-Captime_rise[1]; // Captime[1]=Captime_rise[2]-Captime_down[1]; // 1つ目の検知 if(PP==1){ if(Captime[1]>STD_width) { KOSU=2; KOSU_SUM=KOSU_SUM+2; } else { KOSU=1; KOSU_SUM++; } } } else{ KOSU=9; } PP=Rise; アルゴリズムの考え方等が我流なので、皆様のアドバイスを頂けると幸いです。

  • C言語でのif文分岐について(PICで使用) 2

    http://oshiete1.watch.impress.co.jp/qa9017378.html で質問をさせて頂き、アドバイスを基に以下のアルゴリズムを追加しました。 (以前の質問では、間違って質問を締め切ってしまいました。 アドバイスを頂いた方に大変失礼なことをしてしまいました。申し訳ございません。) 1.パルス幅の最大値を保持する。 2.物体の通過後に累積個数を加算する。この時に、保持した最大値を用いる 従来はRise==2,PP==1の時に、累積加算+パルス幅の判別を行っていました。 このタイミングは、「物体の先端を検知した時」になります。 それを変更し、Rise==1,PP==2の時に、判別するようにしました。 このタイミングは「物体の通過後」になります。 質問: 「1」の「最大値の保持」のプログラムが意図した通りに動きません。 1ループ前のパルス幅を P_Captime[1]=Captime[1]; として保持し、 現在のループの計測値を比較を行い、現在の値の方が大きければ Max_Captime[1]=Captime[1]; とし、最大値を保持しています。 私の意図している動き: LCDに ・現在のパルス幅(Captime[1]) ・最大値 (Max_Captime[1]) を表示しています。 この時、LCDの表示が ・1ループ目 現在のパルス幅が50 →最大値も50 ・2ループ目 現在のパルス幅が20 →最大値は50のまま としたいのですが、 ずっと現在のパルス幅=最大値となり、 最後のパルス幅(物体が通過した最後のループ)がLCDに保持されたままになります。 例)上記の後、最後のループのパルス幅が30の場合、最大値は50でなく、30と表示される。 以下ソース抜粋 /* パルス有無の検知 Rise による識別*/ if(Rise==1){ KOSU=0; Captime[1]=0; } else if(Rise==2){ // パルス幅の計算 Captime[1]=Captime_rise[2]-Captime_down[1]; if(Captime[1]>P_Captime[1]){ // 最大パルスの取得・保持 Max_Captime[1]=Captime[1]; } } P_Captime[1]=Captime[1]; PP=Rise; /*抜粋終わり*/ ドツボに嵌っています。 あえて昨日は何も考えずに、もう一度ソースコードでなく、アルゴリズム図から見直してみましたが、うまくいきません。 /*****************************/ 冗長な文章でしたので、要約すると 1.パルス幅の最大値を保持する。 2.物体の通過後に累積個数を加算する。この時に、保持した最大値を用いる の「1.パルス幅の最大値を保持する」がうまくいかないので、「2」に進めずに 困っています。 となります。 アドバイスを頂けたら幸いです。 (もちろん自分自身でも、並行して考え直しています)

  • 16ビットPICのインプットキャプチャについて

    dsPICやPIC24の16ビットPICのインプットキャプチャについて お世話になります。16ビットPICのインプットキャプチャは、8ビットのPIC(特に16F1ファミリ)のCCPモジュールと使用方法がどこか違うのでしょうか。 16ビットPICはバッファを4つ持っており、値を4つまで保持できるはずですが、パルス幅計測がうまくできません。 現在dsPIC33Eを使っています。 皆様のアドバイスを頂けると幸いです。 問題点: 以下のパルスを計測すると、値がおかしくなる。 ㅤAㅤㅤ Bㅤㅤ CㅤㅤD ___|¯¯¯¯|_________|¯¯¯¯¯|______ ・B-Aでは正常 ・D-Cでも正常 ・しかし、C-Bをすると値が狂う。 値の確認方法: LCDにて表示。 タイマ1をキャプチャ用タイマとしている。(分解能は0.1336us) オシロでの計測値が120usの時、LCDの表示は「896」なので 896*0.1336=119.705us なので、正常と判断しています。(B-AやD-Cでパルス幅を計算時) プログラム仕様: メインループ内で、キャプチャを行う。 IC1で立下りエッジを検出 Captime_down[0]=IC1BUF;ㅤㅤ上図のDエッジ Captime_down[1]=IC1BUF;ㅤㅤ上図のBエッジ IC2で立ち上がりエッジ検出 Captime_rise[0]=IC2BUF;ㅤㅤ上図のCエッジ Captime_rise[1]=IC2BUF;ㅤㅤ上図のAエッジ 2msでタイマ3割込みが入り、値を計算し、表示 Captime[0]=Captime_down[0]-Captime_rise[0];ㅤㅤD-C Captime[1]=Captime_down[1]-Captime_rise[1];ㅤㅤB-A この時にC-B Captime_rise[0]-Captime_down[1] を行うと値が理論値をはるかに超えた19000等の値になります。 考察: インプットキャプチャに使用のタイマ1のオーバーフローも疑いましたが オーバフローしている形跡はありません。以下を試しました。 (1)タイマ1は0.1336usでカウントUP。 FFFFまで8755us=8.7ms必要。今回は2msで回し、値もクリアしている。 (TMR1=0) (2)タイマ1がオーバーフローすると、別ピンがON →ONしていないのでオーバーフローしない バッファの使い方?がおかしいのか? Captime_rise[0]-Captime_down[1] と配列の要素が違う計算(バッファの位置とでも言うのでしょうか、 キャプチャしたタイミングの違う値→[0]でのエッジ検出と[1]で タイマ1の値が変わる?) リファレンスマニュアルや書籍も読んだのですがわかりません。 アドバイスを頂けると幸いです。

  • 配列に値が入らない【c言語】

    下のプログラムで配列(DivBdInfo[i].StgSizeAvg)に値が入らず困っています。 やっていることは平均を求めているだけです。 DivBdInfo[i].StgSizeAvgの変数iを3や5に変えるとこちらは値が入ります。 デバッグ時にSumとcntに値が入っているのは確認しました。 DIVBD_INFO DivBdInfo[DIVBOARD_NUM];はグローバルです。 回答よろしくお願いします。 #define DIVBOARD_NUM 9 typedef struct _DIVBD_INFO { double StrgSizeAvg; double LinkNumAvg; double GrpSizeAvg; }DIVBD_INFO; DIVBD_INFO DivBdInfo[DIVBOARD_NUM]; void StrgSizeAvg(STRING *stringlist) { int x,y,i,id; int rfx,rfy; int Sum; int cnt; for(i=0;i<DIVBOARD_NUM;i++) { GetDivideRfXY(i,&rfx,&rfy); for(i=0;i<movenum;i++){stringlist[i].chk=FALSE;} Sum= cnt= 0; for(y=0;y<DIVIDE_SIZE;y++) { for(x=0;x<DIVIDE_SIZE;x++) { if(gostridboard[rfy+y][rfx+x]>SPACE){ id= gostridboard[rfy+y][rfx+x]-1; if(stringlist[id].chk==FALSE){ Sum+= stringlist[id].size; stringlist[id].chk=TRUE; cnt++; } } } } DivBdInfo[i].StrgSizeAvg=(double)Sum/cnt; //DivBdInfo[5].StrgSizeAvg=Sum/cnt; } }

  • C言語 繰り返しの問題

    C言語の初心者です。 キーボードから値を入力して、1から入力された値までの奇数の和を求めて出力するプログラムを作成します。以下のように組んでみましたが、全然うまくいきません。誰か教えていただけませんか? #include<stdio.h> int main(void) { int i,n,sum; sum=0; printf("入力値:",n); scanf("%d",&n); if(n<=0) { printf("\n合計値:0\n"); } else { printf("入力値:\n",n); for(i= 1; i<= n; i=i+2) { if(n%2=1) { sum=sum+i; } } } printf("\n合計値\n",sum); }

  • c言語で大きな値の階数を求めたいのですが

    c言語で関数を用いてn!を求めるプログラムを作ったのですが、 nの値が大きくなると0という値になってしまって正しい値が出てきません。 プログラムをどの様に修正したらきちんとnの値が大きくなっても 正しく値が表示されるでしょうか? ソースはこちらです。 #include <stdio.h> int func(int i); int func(int i){ if(i == 0) return 1; else return (i*func(i-1)); } void main(){ printf("%d",func(90)); /*90!を求める*/ } よろしくお願いします。

  • C言語!プログラム書いたのですがエラーです!

    課題内容 キーボードから数字を入力してその値までの合計を表示する。 さらに入力した値が偶数なら0から入力した値までのすべての偶数の和を 入力した値が奇数なら1から入力した値までのすべての奇数の和を表示するプログラム。 #include<stdio.h> int main(void) { int i, n, sum; sum=0; scanf("%d",&n); printf("入力値:%d\n", n); if(n%2 = 0) { for(i=0;i<=n;i+=2) { sum=sum+i; } printf("合計値:%d\n",sum); } else { for(i=1;i<=n;i+=2) { sum=sum+i; } printf("合計値:%d\n",sum); } return(0); } これでコンパイルすると10行目に左辺値が必要とでます。 どうすればよいでしょうか? 教えてください。よろしくお願いします。

  • C言語 入力した数値の平均値の近似値

    n個の数値を入力して、その平均値にもっとも近い値を求めよ。(double型の配列を用いること) nは実数データの前に最初に入力するものとする。 必要ならばnは100以下と仮定せよ。 答えは指数なしの表現で、欄の最小幅は8とし、精度は3とする。 という問題なのですが、作ってみたプログラムでは正しく動作できませんでした。 どこが違うのか教えてください。 以下が私の作ったプログラムです。 _____________________________________________________________________________________________________________________ #include <stdio.h> int main (void) { int i,n; double c[100],sum,avg,num1,num2,ans; sum=0.0; scanf("%d",&n); for(i=0;i<n;i=i+1) { scanf("%lf",&c[i]); sum=sum+c[i]; } avg=sum/n; num1=avg-c[0]; if(num1<0){ num1=num1*(-1); } for(i=1;i<n;i=i+1){ num2=avg-c[i]; if(num2<0){ num2=num2*(-1); } if(num1>num2); num1=num2; } printf("%8.3f",num1); return(0); } _____________________________________________________________________________________________________________________ ちなみに「3 3.0 5.0 11.0」と入力すれば「5.000」となるはずなのですが、 私のでは「4.667」と表示されてしまいます。 よろしくお願いします。

  • C言語でわからないところががあります。

    入力された年月日で曜日を求める問題で このサイトでも似たような質問がいくつかあり(他のサイトでも) 参考になりました、閏年とか日数とか特に助かりました。 (参考と言うよりパクった感じですが #include<stdio.h> int main() { int ,months,day,year,sum,i;  //「変数 月 日 年 sum iを宣言」 int m_array[12] = {31,28,31,30,31,30,31,31,30,31,30,31};//「その月の最後の日 char*cweek[7] = {"日","月","火","水","木","金","土"};//曜日(1週間) sum =0;// 「sumを0で初期化」 printf ("input (e.g. ****/**/**)\n>>");//ここで入力 scanf ("%d/%d/%d",&year,&months,&day);//「年 月 日を10進数で出力」 for(i=1;i<year;i++){//「1からユーザーが入力した年までループ」 sum++; if((i%4==0)&&((i%100!=0))||(i%400==0)){//「閏年かどうか判定し、閏年なら1(29日)を足す」 sum++; } } for (i =0; i < months-1; i++) { sum += m_array[i]; } if((i%4==0)&&((i%100!=0))||(i%400==0))//「年が閏年で月が3月以降なら閏年分の1を足す」 if(months>=3){ sum++; } } sum=sum+day-1; printf("%s曜日",cweek[sum%7]);//曜日の計算と出力// return 0;   } このソースの意味で質問なんですけど このソースでいう前年度の総日数は最初の方に出ているループでだされてますよね?あと最後に出ているfor分、これは前月?までの総日数を求めてる・・・と思います。あと最後のsum=sum+day-1;なんですがこれはdayがその月の日数って事なんですよね?sumは前月で。 ちょっとわかりにくり質問で申し訳ないです。

  • PIC 割り込み

     PIC16f873のRB0ピンにパルス波形が常に送られてきているとして、そのHighのときのパルス幅(時間)をタイマー1で測り、その値を常にグローバル変数のHWidthに代入し更新している処理Aがあるとします。  そして、メインの処理Bを走らせている途中で、Widthの値を使いたいというときは、どのような方法を用いればいいのでしょうか? 素人質問で申し訳ありませんが、よろしくお願いします。できたら、サンプルプログラム的なものをあげていただくとありがたいです。

専門家に質問してみよう