Forum: Mikrocontroller und Digitale Elektronik Vektorregelung ohne Strommessung


von Bert S. (kautschuck)


Lesenswert?

Hi,

Ich habe eine Vektorregelung (FOC) für einen brüstenlosen Motor 
implementiert und festgestellt, dass wenn ich die Phasenströme für den 
FOC Algorithmus einfach auf einen konstanten Wert setzte, es trotzdem 
hervorragend funktioniert, wenn nicht sogar noch besser (weniger torque 
ripple) als wenn ich die gemessenen Phasenströme in die Rechnung mit 
einbeziehe. Wenn ich ja das magnetische Feld kenne, dann kann ich ja 
mein Stator Feld immer 90° voraus haben, ohne dass ich die Amplitude 
wissen muss, solange ich nicht genau den Strom bestimmen will und somit 
genau das Drehmoment, oder? Hat eine FOC ohne Strommessung weitere 
Nachteile als nur die Unbestimmtheit des Drehmomentes und Strom?

von THOR (Gast)


Lesenswert?

Du kennst den Lastwinkel deiner SyM nicht, daher kann die Durchrutschen.

von Bert S. (kautschuck)


Lesenswert?

Wie meinst du das? Ich habe einen Encoder im System, somit kenne ich die 
absolute Position des Stators zum Rotor zu jeder Zeit und ein 
Durchrutschen sollte nicht möglich sein.

von Jonas B. (jibi)


Lesenswert?

Moin,

wenn du es ganz genau wissen willst:

https://www.youtube.com/watch?v=fpTvZlnrsP0

Gruß J

von Pandur S. (jetztnicht)


Lesenswert?

Mit Encoder ist es in der Tat viel einfacher. Die hohe Schule arbeitet 
aber aus Kostengruenden ohne Encoder, weiss also die Position nicht.

von Bert S. (kautschuck)


Lesenswert?

Ich hab hier mal den FOC Code welchen ich verwende. Das ganze habe ich 
mehr oder weniger von hier:

http://www.st.com/content/ccc/resource/technical/document/application_note/06/30/4a/f2/c8/e3/48/e5/CD00116774.pdf/files/CD00116774.pdf/jcr:content/translations/en.CD00116774.pdf

Das ganze funktioniert ziemlich gut, aber eben bei höheren Strömen wird 
der torque ripple gross, aber nur wenn ich 
v_d_ref=k_p_foc*(i_d+i_d_ref*B) + k_i_foc*sum_i_d; und nicht v_d_ref=0 
setze.
1
void startFOC(float ia, float ib, float ic, float pos, float out , float v) {
2
  v_dc=v_dc_val;
3
4
  i_a=ia;
5
  i_b=ib;
6
  i_c=ic;
7
8
9
  /*i_a=0;//ia;
10
  i_b=0;//ib;
11
  i_c=0;//ic;*/
12
13
14
  theta=(pos*(float)MY_PI)/180.0f;
15
16
  i_q_ref=-out;
17
  i_d_ref=0;
18
  clarkTransformation();
19
  parkTransformation();
20
  currentControl();
21
  inverseParkTransformation();
22
  inverseClarkTransformation();
23
  calcCommutationDuration();
24
  sectorDetermination();
25
  setPeriods();
26
}
27
28
void calcCommutationDuration() {
29
  //PU- System to scale v_beta, v_alpha
30
  v_alpha=v_alpha/440;
31
  v_beta=v_beta/440;
32
33
  x_dur=v_dc*v_beta*SQRT_3;
34
  y_dur=(v_dc*v_beta*SQRT_3 + 3*v_dc*v_alpha)/2;
35
  z_dur=(v_dc*v_beta*SQRT_3- 3*v_dc*v_alpha)/2;
36
}
37
38
void inverseClarkTransformation() {
39
  v_a=v_beta;
40
  v_b=(SQRT_3*v_alpha - v_beta)/2;
41
  v_c=-(v_beta + SQRT_3*v_alpha)/2;
42
}
43
44
void clarkTransformation() {
45
  i_alpha=i_a;
46
  i_beta=(i_a + 2*i_b)/SQRT_3;
47
}
48
49
void inverseParkTransformation() {
50
  v_alpha= v_d_ref*cosf(theta) - v_q_ref*sinf(theta);
51
  v_beta= v_q_ref*cosf(theta) + v_d_ref*sinf(theta);
52
}
53
54
void parkTransformation() {
55
  i_d = i_alpha*cosf(theta) + i_beta*sinf(theta);
56
  i_q = -i_alpha*sinf(theta) + i_beta*cosf(theta);
57
}
58
59
void currentControl() {
60
  v_d_ref=k_p_foc*(i_d+i_d_ref*B) + k_i_foc*sum_i_d;
61
  v_q_ref=k_p_foc*(i_q+i_q_ref*B) + k_i_foc*sum_i_q;
62
63
  sum_i_d+=(i_d+i_d_ref)/SUM_W;
64
  sum_i_q+=(i_q+i_q_ref)/SUM_W;
65
66
  if(sum_i_d>integral_windup) {
67
    sum_i_d=integral_windup;
68
  } else if(sum_i_d<-integral_windup) {
69
    sum_i_d=-integral_windup;
70
  }
71
72
  if(sum_i_q>integral_windup) {
73
    sum_i_q=integral_windup;
74
  } else if(sum_i_q<-integral_windup) {
75
    sum_i_q=-integral_windup;
76
  }
77
78
}
79
80
void sectorDetermination() {
81
  if(v_a>0) {
82
    sector[0]=1;
83
  } else {
84
    sector[0]=0;
85
  }
86
87
  if(v_b>0) {
88
    sector[1]=1;
89
  } else {
90
    sector[1]=0;
91
  }
92
93
  if(v_c>0) {
94
    sector[2]=1;
95
  } else {
96
    sector[2]=0;
97
  }
98
99
  sector_is= sector[0]+2*sector[1]+4*sector[2];
100
101
  switch(sector_is) {
102
    case 1:
103
      period_t1=z_dur;
104
      period_t2=y_dur;
105
      break;
106
    case 2:
107
      period_t1=y_dur;
108
      period_t2=-x_dur;
109
      break;
110
    case 3:
111
      period_t1=-z_dur;
112
      period_t2=x_dur;
113
      break;
114
    case 4:
115
      period_t1=-x_dur;
116
      period_t2=z_dur;
117
      break;
118
    case 5:
119
      period_t1=x_dur;
120
      period_t2=-y_dur;
121
      break;
122
    case 6:
123
      period_t1=-y_dur;
124
      period_t2=-z_dur;
125
      break;
126
    default:
127
      break;
128
  }
129
130
  if((period_t1+period_t2) > period_t) {
131
    period_t1_sat=period_t1*(period_t)/(period_t1+period_t2);
132
    period_t2_sat=period_t2*(period_t)/(period_t1+period_t2);
133
  }
134
135
  if(period_t1_sat>0 && period_t1>period_t1_sat)
136
    period_t1=period_t1_sat;
137
  if(period_t1_sat<0 && period_t1<period_t1_sat)
138
    period_t1=period_t1_sat;
139
  if(period_t2_sat>0 && period_t2>period_t2_sat)
140
    period_t2=period_t2_sat;
141
  if(period_t2_sat<0 && period_t2<period_t2_sat)
142
    period_t2=period_t2_sat;
143
144
    period_a=(period_t+1 - period_t1 - period_t2)/2;
145
    period_b=period_a + period_t1;
146
    period_c=period_b + period_t2;
147
}
148
149
void setPeriods(void) {
150
  switch(sector_is) {
151
    case 1:
152
      TIM2->CCR1 = period_b;
153
      TIM2->CCR2 = period_a;
154
      TIM2->CCR3 = period_c;
155
      break;
156
    case 2:
157
      TIM2->CCR1 = period_a;
158
      TIM2->CCR2 = period_c;
159
      TIM2->CCR3 = period_b;
160
      break;
161
    case 3:
162
      TIM2->CCR1 = period_a;
163
      TIM2->CCR2 = period_b;
164
      TIM2->CCR3 = period_c;
165
      break;
166
    case 4:
167
      TIM2->CCR1 = period_c;
168
      TIM2->CCR2 = period_b;
169
      TIM2->CCR3 = period_a;
170
      break;
171
    case 5:
172
      TIM2->CCR1 = period_c;
173
      TIM2->CCR2 = period_a;
174
      TIM2->CCR3 = period_b;
175
      break;
176
    case 6:
177
      TIM2->CCR1 = period_b;
178
      TIM2->CCR2 = period_c;
179
      TIM2->CCR3 = period_a;
180
      break;
181
    default:
182
      break;
183
  }
184
}

: Bearbeitet durch User
von WS (Gast)


Lesenswert?

Sapperlot W. schrieb:
> Mit Encoder ist es in der Tat viel einfacher. Die hohe Schule arbeitet
> aber aus Kostengruenden ohne Encoder, weiss also die Position nicht

Die ganz "hohe Schule" arbeitet auch ohne Decoder, wertet aber den 
Motorstrom aus und kennt damit dessen Position dennoch.:-)

von Bert S. (kautschuck)


Lesenswert?

Es scheint mir so, als würde ich I_d irgendwie nicht wirklich ganz zu 
Null regeln, denn wenn ich einfach I_d=0 und I_d_ref=0 setzte, ist das 
Resultat viel besser. Aber ich kann mir nicht erklären, was genau die 
Ursache ist. Die Strommessung müsste eigentlich sehr exakt sein, da ich 
zwei AD8418 verwende.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.