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)后得到最大值(电压),因为对于每次读取操作,我的设备都需要 100 毫秒的延迟。这太大了,我无法更改硬件,因此我想通过优化软件在 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

黄金分割搜索可能是您所追求的。它很有效,但仍然很简单。

如果你想要更快更复杂的东西,你可以使用Brent 的方法

于 2012-11-07T14:25:43.273 回答
1

如果您可以确定 360 度上只有一个最高点,您可以进行递归分而治之。

您首先查看例如 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 回答