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?
Du kennst den Lastwinkel deiner SyM nicht, daher kann die Durchrutschen.
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.
Mit Encoder ist es in der Tat viel einfacher. Die hohe Schule arbeitet aber aus Kostengruenden ohne Encoder, weiss also die Position nicht.
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
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.:-)
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.