• 締切済み

C言語のファイル入力とif文

あるcsvファイルから波形を読み込み、それを配列に格納しています。 (これは先日質問したもので、以下URLにおけるNo.4様の回答を参考にしています。 http://okwave.jp/qa/q7521134.html) csvファイルの中身は左が時刻[ms]、右が電圧値[V]で、 0.001 0.14 0.002 0.32 0.003 0.46 ・ ・ 2.000 0.22 という風になっています。 このプログラムはシミュレーションを行っており、「計算上の時刻」と「csvファイルにおける時刻」が 一致したときの時刻の「csvファイルの電圧値」を計算でも使用したいと考えています。 例えば計算上で時刻0.003[ms]になったら0.32[V]、2[ms]になったら0.22[V]といった風に 値を取り出したいです。 どなたか詳しい方、回答・アドバイス等よろしくお願いいたします。

みんなの回答

  • jjk65536
  • ベストアンサー率59% (66/111)
回答No.2

popenで手抜きする方法もあります。 処理速度上は不利ですので、多少遅くても問題ない場合に限りますが さっさと動かしたい場合などに有用です。 たとえば時刻から電圧値を取得する関数を float getv(float time); というように作るとします。 内部実装をpopenでごまかす場合、例えば以下のように書けます。 #include <stdio.h> float getv(float time) {  float v;  char cmd[BUFSIZ];  sprintf(cmd, "grep '^%.3f' data.csv", time);  FILE *fd;  fd = popen(cmd, "r");  fscanf(fd, "%f %f", &time, &v);  close(fd);  return v; } int main(int argc, const char *argv[]) {  float v = getv(0.002);  printf("%f\n", v);  return 0; } 上記例はLinuxではそのまま動きますが、他のOSの場合はgrepなどを用意する必要があります。

回答No.1

時刻[ms]の値の性質がわからないので、方針が定まりませんが、自分だったら時刻の性質に応じてこのどれかを使いますね。 1. 時刻が必ず0.001[ms]刻みであることがわかっている場合 O(1) 0.001[ms]と配列の添え字が一対一対応する配列を作成し、そこにデータを入れる。 例えば、2.000[ms]が最大だったら、2001個の要素を持つ配列を作り、voltage[2001]; 0.012はvoltage[12]を参照する。 ここで、0.000[ms]がないのにvoltage[0]を作るのは時刻と配列が一対一対応したほうがわかりやすいと思ったからです。 2. 計算で使うときの時刻はきっかりその値を要求して、ブレがない場合 O(1) (動作しない可能性が高いので非推奨。しかしながら、うまくハマると3.よりは高速なはず) BerkeleyDBでDB_HASHなメモリーDBを作ってそこにデータを入れ、それを参照。 Keyとして時刻の値を、Valueとして電圧値の値をそれぞれバイト列だと思って入れます。 例えば、計算の時に0.002という値を確実に要求して、0.0021などは要求しない場合にのみ使えますが、浮動小数点値を入れるのでかなり不安ですね。 3. CSVファイルの時刻は0.001[ms]きざみであり、計算で使う時刻にブレがないか、計算で使う時の時刻が0.001[ms]以下のブレがある場合 O(log N) CSVファイルのデータを読み、時刻と電圧値をもった構造体の配列に入れます。それから、時刻順にソートして、電圧値を取るたびに二分探索します。 CではC90準拠の標準ライブラリーにqsortとbsearchはあるので、それを使えば簡単に作れるはずです。 qsortに与えるcomparは単純に大小で-1、1を返すようにして、 bsearchにcomparで与える関数は二値を引いた結果で-1、0、1を返すようにして、引いいた時の差が一定 (0.0005ms?) 以下なら0を返すようにしたほうが良いでしょう。 4. CSVファイルの時刻が0.001[ms]きざみでなく、値がなかったら前の値や後の値を使って欲しい場合 つまり、CSVファイルにある時刻では0.002と0.005の値しかない場合に0.003が来たら0.002の値を使いたいような場合。 O(log N) 上記3のcomparの条件では引いた時の差がその値に合致しないと発見できなかったことになるので、3の手順のところのbsearchの自作が必要です。 bsearchのソースコードはどこかのライブラリーのを使い、見つからなかった場合にNULLを返すところで比較に使っていた値を返すという工夫をすればよいでしょう。 例えば、FreeBSDのlibcにあるbsearchだと、pとその前後の値を見てNULLの代わりにほしいものを返すように書き換えるとよいでしょう。 http://www.freebsd.org/cgi/cvsweb.cgi/src/lib/libc/stdlib/bsearch.c?rev=1.4.10.1.8.1;content-type=text%2Fplain 5. それ以外の場合 (何らかの理由でソートできない場合も含む) O(N) CSVファイルのデータを読み、時刻と電圧値をもった構造体の配列に入れます。 配列の頭から順に条件に合う時刻がないか探します。 配列の要素をソートする必要もなく、一番簡単な実装です。 この場合でも、最近使われた時刻と電圧値のペアを覚えておくことで多少は性能が良くなるかもしれません。 1から5はおすすめの順に並べていますが、時刻の性質によって取れないアルゴリズムも多数ありますので。

関連するQ&A

  • C言語のファイル読み込み

    あるcsvファイルがあり、それは以下のように(規則性のない)波形のデータです。 0.001 0.14 0.002 0.32 0.003 0.46 ・ ・ 2.000 0.22 左側がx軸、右側がy軸で、データはそれぞれ2000個あります。 このデータ(波形)をC言語のプログラムに読み込ませるにはどうしたらいいのでしょうか? #include <stdio.h> int main(void) { double i,j; FILE *file; file = fopen("sample.csv","r"); fscanf(file,"%ls,%ls",&i,&j); fclose(file); printf("i = %d : j = %d\n",i,j); return 0; } とすれば最初の1行目だけは読めますが、それ以降がわかりません。 配列を使えばいいのでしょうか?

  • LTspiceでの充電波形

    お世話になります。 コンバータ回路をシミュレーションしたいです。 実際にシミュレーションしたいのは回路2の波形です。 突入抵抗:16Ω,平滑C:7500μFでは、時定数が120msとなります。 印加する電圧は3相AC528Vで、充電電圧はDC747Vとなります。 シミュレーションではなく、実機で確認するとAC電圧印加後120msでの充電電圧は約472Vと なりますが、シミュレーションでは389Vとなり、80Vもの誤差があります。 この誤差の原因は何でしょうか? ちなみに、シミュレーションの場合、回路1のようにDC472Vを印加すると実機と同等の 充電波形となります。 ご回答宜しくお願い致します。

  • C言語 csv 配列

    CSVファイルを2次元配列に格納したいのですが、書き方がわかりません。 csvファイルは1024×2048の0と1のみで構成されています。 fp=fopen(path,"r"); for(j=0; j<1024; j++) { for(i=0; i<2048; i++) { char c; do{c=(getc(fp));} while(c==','||c=='\n'||c=='\r'); map[j][i] = c-'0'; } } このように書きできたと思ったのですが、どうもうまくいっていないみたいです。 どこが悪いのか、どういう風に書けばいいのか教えていただげれば幸いです。

  • C++でのcsvファイル読み込みについて

    C++でのcsvファイル読み込みについて質問です. 読み込みcsvファイルの規模は300*1000として,その情報をdouble型の2次元配列に格納したいですが,ネットでいろいろ調べたり自分でコードを作ってみてもabort()has been calledなどいくつかエラーが表示されてしまい先に進めません. csvファイル名をa.csv,格納したい2次元配列をA[300][1000]などとしてサンプルコードを提供してくださいますと幸いです. 質問前に散々調べましたがプログラミング初心者でして今現在の力では対応できませんでした.申し訳ありませんが何卒ご教示お願いします.

  • C言語 strtok

    現在CSVファイルを読み込み多次元配列に格納しているのですが1行をstrtokで区切ってしまうと空白を無視してしまい、困っています。 例"xxx","","yyy","" のような文字列、空白、文字列があるとして空白は空白で読み込みたいです。 説明が下手ですいませんがなにかいい方法がありましたらご教授頂きたいです。 よろしくお願い致します。。

  • C++による ファイルの読み込み

    今、Visual C++2008 Express Editionを使用して、ファイルダイアログを使用して用意した配列にファイル内容を記憶させる簡単なプログラムを作成しています。 プログラムの流れは以下のとおりです。 1.ボタンをクリックする。 2.ファイルダイアログを表示する。 3.選択されたファイル名の内容を用意した配列に記憶する。 1,2はできたのですが、選択されたファイル(主にCSVファイル)の内容を配列に記憶させる方法がわかりません。 どうしたらよいのでしょうか。教えてください。 以下にボタンを押したときの動作を掲載しますのでお願いいたします。 ========================= private: System::Void button1_Click(System::Object^ sender, System::EventArgs^ e) { //ファイル内容を記憶させる配列 double x[1024], y[1024]; //ファイルを読み込むときのループインデックス                    int i=0;                   //ファイル名を格納する変数                    String^ fname;               ファイルを開くためのダイアログを用意 OpenFileDialog^ dlg = gcnew OpenFileDialog();                 //フィルターの内容を設定 dlg->Filter::set("CSVファイル(*.csv)|*.csv");              //ダイアログタイトルの設定 dlg->Title::set("開くファイルを選択してください。");              //ダイアログの表示 dlg->ShowDialog();             //ファイル名を取得して格納    fname=dlg->FileName;        /**********************************************           ここに上記の「fname」のファイルを読み込む処          理がくる              ********************************/ }

  • ファイルからの読み込み 配列

    座標データの数値のテキストファイルから配列の中に座標値を格納したいのですが、int型のデータを読み込んで配列に格納するのは、どのようにプログラムを組めばよろしいのでしょうか?下のようにxzahyou.csvというファイルから配列Z[i]に格納したくて組んでみたら、 br = new BufferedReader(new FileReader("xzahyou.csv")); for(int i=0;i<X.length;i++){ String line = br.readLine(); X[i]=line; X[i] = line;のところで互換性がないと出てきました。int型の場合どのようにすればよろしいのでしょうか?教えてください。お願いします。

  • この問題が解けません。

    ●横軸は時刻t[s]を表しており、右向き正、一目盛り20ms、太線は0s ●縦軸は電圧V(t)[V]を表しており、上向き正、一目盛り500mV、太線は0Vとする。 この波形に対して、時刻0s以降の波形は理論的には V(t)=a{1-e^(-t/T)} となる事が分かっているとする。グラフから必要な値を読み取ることによって、定数a,T(ともに二桁とする)を求めよ。単位もつけること。

  • オシロスコープ

    シンクロスコープの交流波形の観測という実験を行ったのですが、その時にシンクロスコープに交流電圧計、スライダックを接続し、スライダックで電圧計の読みを2.0Vにし、掃引時間を5ms、2ms、1msとして波形の観測をしました。その時の振幅から電圧計の読み(2V)を割ると、√2に近い値がでるはずなのですが、それはなぜですか? 教えてください。

  • Cで2次元配列にCSVファイルを格納するには?

    ~.csvというファイルがあって、ファイルの中身は256*256のある数字の2次元配列です。 このファイルを読み込んで、2次元配列に格納したいのですが、どのようなソースを書けばいいのでしょうか? プログラミングをちゃんと勉強してこなかったために苦戦しています。 #include <stdio.h> #include <stdlib.h> int main(int argc,char *argv[]){ FILE *fi; char I[256]; char J[256]; if((fi=fopen("ch.csv","r"))==NULL){//csvもこのような記述でよみこむことができるのか? printf("ファイルオープンエラー\n"); exit(1); } while(fgets(J,256,fi) != NULL) { これより先が全く書けていない状態です。 ここまでもこのソースで大丈夫でしょうか? かなり基本的なことだと思いますが、よろしくお願いします。

専門家に質問してみよう