5

最大電圧値を取得するために、信号の位相を0から360に段階的に変更しています。信号の位相を変更すると、電圧も変化するためです。最大値を見つけるための休憩コードがあります。

void Maxphase(float *max, unsigned int *index) 
{
*max = 0.0;
float value;
unsigned int i, data;
for (i=0;i<=360;i++) 
{              
    phaseset(i); 
    delay_ms(100);
    data = readvalue(); 
    value = voltage(mux1);    
    if(value > *max)   //find max value 
    { 
        *max = value;    //max voltage 
        *index = i;   
    }  
}                           
}

上記のコードから、38秒(360 * 100)後に最大値(電圧)を取得しています。これは、読み取り操作ごとにデバイスに100msの遅延が必要なためです。これは大きすぎてハードウェアを変更できないので、ソフトウェアを最適化して2〜3秒以内に最大値を取得したいと思います。それから私は休閑コードで試しました。

void Maxphase(float *max1, unsigned int *index1) 
{
  max = 0.0;
  float value;
  unsigned int i,j,data;
  for (i=0;i<=360;i+=10) 
   {              
    phaseset(i); 
    delay_ms(100);
    data = readvalue(); 
    value = voltage(mux1);    
    if(value > max)   //find max value 
    { 
        max = value;    //max voltage 
        index = i;   
    }  
   }    
   *max1=max;
   *index1=index;
   for (i=*index1-9;i<=*index1+9;i+=1) 
     {       
     j=i;       
    phaseset(j); 
    delay_ms(100);
    data = readvalue(); 
    value = voltage(mux1);    
    if(value > *max1)   //find max value 
    { 
        *max1 = value;    //max voltage 
        *index1 = i;   
    }  
    }                         
}

時間を45秒から7秒に短縮しました。反復回数を360から54(54 * 100)に減らしました。7秒から2秒に短縮したい。

誰かが2秒で(0から360)までの最大値を取得できるより良いアルゴリズムで私を助けることができますか?

スコープを使って相を変えて電圧値を測定しました。相によって電圧がどのように変化するかを以下に書きました。

Phase (degree)     voltage(max)
  0             0.9mv

 45             9.5mv

 90             9.0mv

135             0.9mv

180             292mv

225             601mv

270             555mv

315             230mv

360             0.9mv

私はCプログラミングに不慣れです。誰でも最高のアルゴリズムのサンプルコードを提供できますか?

4

4 に答える 4

2

ゴールデン セクション検索は、おそらくあなたが求めているものです。効果的ですが、それでもかなり単純です。

さらに高速で洗練されたものが必要な場合は、ブレントの方法を使用できます。

于 2012-11-07T14:25:43.273 に答える
1

360 度の最高点が 1 つだけであると確信できる場合は、再帰的な分割統治を行うことができます。

たとえば、0、180、270 から始めます。答えが 180 + 270 の合計が最高値であることがわかったとしましょう。210 を調べることから始めるよりも.... どちら側が高いですか? 等々 ...

于 2012-11-07T14:22:40.763 に答える
0

更新: 2012 年 11 月 10 日。

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

#define FAKE_TARGET 89
unsigned fake_target = FAKE_TARGET;

float probe_one(unsigned int phase);
void Maxphase(float *max, unsigned int *index);

void Maxphase(float *max, unsigned int *index)
{

unsigned int aim, idx, victim;

struct best {
    unsigned pos;
    float val;
    } samples[4] = {{0, 0.0}, };

    for (aim = 0;aim < 360;aim += 90) {
        idx=aim/90;
        samples[idx].pos = aim;
        samples[idx].val = probe_one(samples[idx].pos);
        if (!idx || samples[idx].val < samples[victim].val ) victim = idx;
        }

        /* eliminate the weakist postion, and rotate the rest,
        ** such that:
        ** samples[0] := lower boundary.
        ** samples[1] := our best guess
        ** samples[2] := upper boundary
        ** samples[3] := scratch/probe element
        */
    fprintf(stderr, "Victim=%u\n", victim );
    switch(victim) {
    case 0: samples[0] = samples[1]; samples[1] = samples[2]; samples[2] = samples[3]; break;
    case 1: samples[1] = samples[3]; samples[3] = samples[0]; samples[0] = samples[2]; samples[2] = samples[3]; break;
    case 2: samples[2] = samples[1]; samples[1] = samples[0]; samples[0] = samples[3]; break;
    case 3: break;
    }


        /* Calculation is easier if the positions are increasing.
        ** (We can always perform the modulo 360 if needed)
        */
    if (samples[0].pos > samples[1].pos ) samples[1].pos  += 360;
    if (samples[1].pos > samples[2].pos ) samples[2].pos  += 360;

    while( 1) {
        int step;

        step = samples[2].pos - samples[0].pos;
        if (step < 3) break;

        do    {
            fprintf(stderr, "\n[%u %u %u] Diff=%d\n"
            , samples[0].pos , samples[1].pos , samples[2].pos , step);
            if (step > 0) step++; else step--;
            step /= 2;
            aim = (samples[0].pos + step ) ;
                /* avoid hitting the middle cell twice */
            if (aim %360 != samples[1].pos %360) break;
            step += 1;
            aim = (samples[0].pos + step ) ;
            if (aim %360 != samples[1].pos %360) break;
            step -= 2;
            aim = (samples[0].pos + step ) ;
            break;
            } while(0);

        fprintf(stderr, "Step=%d Aim=%u, Idx=%u\n",step, aim,idx );

        samples[3].pos = aim;
        samples[3].val = probe_one( samples[3].pos );

        victim= (samples[3].pos > samples[1].pos ) ? 2 : 0;
        if (samples[3].val > samples[1].val) idx= 1; else idx = victim;

        fprintf(stderr, "Victim=%u, TargetIdx=%u\n", victim, idx );
                /* This should not happen */
        if (samples[3].val < samples[victim].val) break;
        if (idx != victim) samples[2-victim] = samples[idx];
        samples[idx] = samples[3];
        }

    *max = samples[1].val;
    *index = samples[1].pos % 360;
}
float probe_one(unsigned int phase)
{
    float value;

#ifdef FAKE_TARGET
    int dif;
        dif = fake_target-phase;
    if (dif < -180) dif = 360+dif;
    else if (dif > 180) dif = 360-dif;
        /* value = 1.0 / (1 + pow(phase-231, 2)); */
        value = 1.0 / (1 + pow(dif, 2));
        fprintf(stderr, "Target = %d: Probe(%d:%d) := %f\n", fake_target, phase, dif, value );
        sleep (1);
#else
    unsigned int data;
    phase %= 360;
    phaseset(phase);
    delay_ms(100);
    data = readvalue();  // what is this ?
    value = voltage(mux1);
#endif

return value;
}

int main(int argc, char **argv)
{
float value;
unsigned int index;

if (argv[1]) sscanf (argv[1], "%u", &fake_target);
fake_target %= 360;

Maxphase(&value, &index) ;
printf("Phase=%u Max=%f\n", index, value );
return 0;
}
于 2012-11-07T23:02:13.663 に答える
0

ここにあるさまざまなコメントや提案を利用して、この未テストのコードを提示します。これがまったく機能するのか、既存のソースよりも改善されているのかはわかりませんが、とにかく試してみるのは楽しかったです:

extern void phaseset(int);
extern void delay_ms(int);
extern float readvalue();
extern float voltage(int);
extern int mux1;

float probe(int phase)
{
    float data;
    phaseset(phase);
    delay_ms(100);
    data = readvalue(); /* data is ignored? */
    return voltage(mux1); /* mux1? */
}

/* helper routine, find the max in a given range [phase1, phase2] */
void maxphase_aux(int phase1, float vol1, int phase2, float vol2, int *phaseret, float *volret)
{
    float xvol1 = 0, xvol2 = 0;
    int xphase1 = -1, xphase2 = -1;

    /* test the voltage in the middle */
    int phasem = abs(phase2 - phase1) / 2;
    float volm = probe(phasem);

    if (volm > vol1 && volm > vol2) {
        /* middle point is the highest so far,
         * search left and right for maximum */
        *volret = volm;
        *phaseret = phasem;

        maxphase_aux(phase1, vol1, phasem, volm, &xphase1, &xvol1);
        maxphase_aux(phase2, vol2, phasem, volm, &xphase2, &xvol2);
    } else if (volm < vol1 && volm > vol2) {
        /* vol1 is the highest so far,
         * search between volm and vol1 for maximum */
        maxphase_aux(phase1, vol1, phasem, volm, &xphase1, &xvol1);
    } else if (volm > vol1 && volm < vol2) {
        /* vol2 is the highest so far,
         * search between volm and vol2 for maximum */
        maxphase_aux(phase2, vol2, phasem, volm, &xphase2, &xvol2);
    } else {
        /* not possible? */
        return;
    }

    if (xvol1 > volm) {
        *volret = xvol1;
        *phaseret = xphase1;
    }

    if (xvol2 > volm) {
        *volret = xvol2;
        *phaseret = xphase2;
    }
}

void maxphase(int *phaseret, float *volret)
{
    float v0 = probe(0);
    float v360 = probe(360);
    maxphase_aux(0, v0, 360, v360, phaseret, volret);
}
于 2012-11-07T15:40:26.190 に答える