femagtools 1.8.16__py3-none-any.whl → 1.8.18__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- femagtools/__init__.py +1 -1
- femagtools/airgap.py +5 -1
- femagtools/dxfsl/area.py +52 -23
- femagtools/dxfsl/areabuilder.py +69 -46
- femagtools/dxfsl/converter.py +25 -5
- femagtools/dxfsl/fslrenderer.py +2 -2
- femagtools/dxfsl/geom.py +264 -68
- femagtools/dxfsl/machine.py +38 -8
- femagtools/dxfsl/symmetry.py +20 -5
- femagtools/femag.py +27 -16
- femagtools/machine/__init__.py +2 -0
- femagtools/machine/effloss.py +10 -4
- femagtools/machine/pm.py +72 -68
- femagtools/machine/sm.py +15 -15
- femagtools/plot/bch.py +3 -1
- femagtools/plot/char.py +5 -16
- femagtools/plot/nc.py +67 -34
- femagtools/shortcircuit.py +10 -3
- femagtools/utils.py +5 -4
- {femagtools-1.8.16.dist-info → femagtools-1.8.18.dist-info}/METADATA +2 -2
- {femagtools-1.8.16.dist-info → femagtools-1.8.18.dist-info}/RECORD +26 -26
- tests/test_machine.py +1 -2
- {femagtools-1.8.16.dist-info → femagtools-1.8.18.dist-info}/WHEEL +0 -0
- {femagtools-1.8.16.dist-info → femagtools-1.8.18.dist-info}/entry_points.txt +0 -0
- {femagtools-1.8.16.dist-info → femagtools-1.8.18.dist-info}/licenses/LICENSE +0 -0
- {femagtools-1.8.16.dist-info → femagtools-1.8.18.dist-info}/top_level.txt +0 -0
femagtools/femag.py
CHANGED
@@ -79,6 +79,7 @@ def set_magnet_properties(model, simulation, magnets):
|
|
79
79
|
magn_temp = simulation.magn_temp
|
80
80
|
if 'material' not in model.magnet:
|
81
81
|
return
|
82
|
+
|
82
83
|
try:
|
83
84
|
material = model.magnet['material']
|
84
85
|
magnetMat = magnets.find(material)
|
@@ -95,19 +96,24 @@ def set_magnet_properties(model, simulation, magnets):
|
|
95
96
|
tempcoefmuer = (tempcoefbr-tempcoefhc)/(1+tempcoefhc*(magn_temp-20))
|
96
97
|
if 'temcoefmuer' in magnetMat:
|
97
98
|
tempcoefmuer = magnetMat['temcoefmuer']
|
98
|
-
|
99
|
-
|
100
|
-
|
99
|
+
if not hasattr(model, 'hc_min'):
|
100
|
+
for k in 'Hk', 'HcJ':
|
101
|
+
if k in magnetMat:
|
102
|
+
hcmin = magnetMat.get(k)
|
103
|
+
model.hc_min = hcmin * (1+tempcoefhc*(magn_temp-20))
|
104
|
+
break
|
105
|
+
if hasattr(model, 'hc_min'):
|
106
|
+
logger.info("hc_min %f", model.hc_min)
|
101
107
|
model.magnet['temp_prop']['relperm'] = \
|
102
108
|
(1+tempcoefmuer*(magn_temp-20))*relperm
|
103
109
|
if tempcoefbr:
|
104
110
|
model.magnet['temp_prop']['temcoefbr'] = tempcoefbr
|
105
111
|
if tempcoefhc:
|
106
112
|
model.magnet['temp_prop']['temcoefhc'] = tempcoefhc
|
107
|
-
|
108
113
|
except AttributeError:
|
109
114
|
pass
|
110
115
|
|
116
|
+
|
111
117
|
class BaseFemag(object):
|
112
118
|
def __init__(self, workdir, cmd, magnetizingCurves, magnets, condMat,
|
113
119
|
templatedirs=[]):
|
@@ -415,7 +421,8 @@ class BaseFemag(object):
|
|
415
421
|
except FileNotFoundError:
|
416
422
|
pass
|
417
423
|
|
418
|
-
return
|
424
|
+
return sorted(pathlib.Path(self.workdir).glob('*.PROT'),
|
425
|
+
key=lambda x: x.stat().st_mtime, reverse=True)[0].stem
|
419
426
|
|
420
427
|
def readResult(self, machine, simulation, bch=None):
|
421
428
|
if simulation:
|
@@ -460,14 +467,6 @@ class BaseFemag(object):
|
|
460
467
|
|
461
468
|
if not bch:
|
462
469
|
bch = self.read_bch(self.modelname)
|
463
|
-
if simulation['calculationMode'] == 'pm_sym_fast' or \
|
464
|
-
simulation['calculationMode'] == 'torq_calc':
|
465
|
-
if simulation.get('shortCircuit', False):
|
466
|
-
from .shortcircuit import shortcircuit
|
467
|
-
set_magnet_properties(self.model, simulation, self.magnets)
|
468
|
-
bch.scData = shortcircuit(self, machine, bch, simulation)
|
469
|
-
#bch.torque += bchsc.torque
|
470
|
-
#bch.demag += bchsc.demag
|
471
470
|
|
472
471
|
if 'airgap_induc' in simulation:
|
473
472
|
try:
|
@@ -477,6 +476,19 @@ class BaseFemag(object):
|
|
477
476
|
bch.airgap = ag.read(os.path.join(self.workdir, 'bag.dat'),
|
478
477
|
pmod=pmod)
|
479
478
|
|
479
|
+
if simulation['calculationMode'] == 'pm_sym_fast' or \
|
480
|
+
simulation['calculationMode'] == 'torq_calc':
|
481
|
+
if simulation.get('shortCircuit', False):
|
482
|
+
from .shortcircuit import shortcircuit
|
483
|
+
set_magnet_properties(self.model, simulation, self.magnets)
|
484
|
+
bch.scData = shortcircuit(self,
|
485
|
+
{'name': self.model.name,
|
486
|
+
'poles': self.model.poles,
|
487
|
+
'hc_min': self.model.get('hc_min', 0)},
|
488
|
+
bch, simulation)
|
489
|
+
#bch.torque += bchsc.torque
|
490
|
+
#bch.demag += bchsc.demag
|
491
|
+
|
480
492
|
if simulation.get('magnet_loss', False):
|
481
493
|
logger.info('Evaluating magnet losses...')
|
482
494
|
ops = range(len(bch.torque))
|
@@ -490,7 +502,7 @@ class BaseFemag(object):
|
|
490
502
|
|
491
503
|
if len(ops) != len(bch.losses):
|
492
504
|
magn_losses.insert(0, magn_losses[0])
|
493
|
-
|
505
|
+
|
494
506
|
magn_losses = [float(i) for i in magn_losses]
|
495
507
|
try:
|
496
508
|
for i in range(len(bch.losses)):
|
@@ -600,10 +612,9 @@ class Femag(BaseFemag):
|
|
600
612
|
os.remove(f)
|
601
613
|
|
602
614
|
def __call__(self, machine, simulation={},
|
603
|
-
options=['-b'], fsl_args=[]):
|
615
|
+
options=['-b'], fsl_args=[], fslfile='femag.fsl'):
|
604
616
|
"""setup fsl file, run calculation and return
|
605
617
|
BCH, ASM, TS or LOS results if any."""
|
606
|
-
fslfile = 'femag.fsl'
|
607
618
|
with open(os.path.join(self.workdir, fslfile), 'w') as f:
|
608
619
|
f.write('\n'.join(self.create_fsl(machine,
|
609
620
|
simulation)))
|
femagtools/machine/__init__.py
CHANGED
@@ -51,6 +51,8 @@ def create_from_eecpars(temp, eecpars, lfe=1, wdg=1):
|
|
51
51
|
smpars = copy.deepcopy(eecpars)
|
52
52
|
smpars['tcu1'] = temp[0]
|
53
53
|
smpars['tcu2'] = temp[1]
|
54
|
+
# external inductances
|
55
|
+
opts["ls"] = eecpars.get('ls1', 0)*rwdg**2
|
54
56
|
if 'ldq' in smpars:
|
55
57
|
machine = SynchronousMachineLdq(smpars, lfe=rlfe, wdg=rwdg, **opts)
|
56
58
|
else:
|
femagtools/machine/effloss.py
CHANGED
@@ -252,6 +252,8 @@ def efficiency_losses_map(eecpars, u1, T, temp, n, npoints=(60, 40),
|
|
252
252
|
rb['n'] = None
|
253
253
|
rb['T'] = None
|
254
254
|
if 'n' not in rb:
|
255
|
+
if kwargs.get('i1max', 0):
|
256
|
+
kwargs['i1max'] = -kwargs['i1max']
|
255
257
|
rb = m.characteristics(-T, max(r['n']), u1, nsamples=nsamples,
|
256
258
|
with_mtpv=with_mtpv, with_mtpa=with_mtpa,
|
257
259
|
with_pmconst=with_pmconst, with_tmech=with_tmech,
|
@@ -267,13 +269,17 @@ def efficiency_losses_map(eecpars, u1, T, temp, n, npoints=(60, 40),
|
|
267
269
|
if isinstance(m, (SynchronousMachineLdq, SynchronousMachinePsidq)):
|
268
270
|
iq, id, iex = m.iqd_torque(T[-1])
|
269
271
|
i1max = betai1(iq, id)[1]
|
272
|
+
if kwargs.get("i1max", 0):
|
273
|
+
i1max = kwargs["i1max"]
|
270
274
|
w1type, tmax = m.w1_imax_umax(i1max, u1)
|
271
275
|
pmax = tmax*w1type/m.p
|
272
276
|
else:
|
273
277
|
iq, id = m.iqd_torque(T[-1])
|
274
|
-
|
278
|
+
i1max = betai1(iq, id)[1]
|
279
|
+
if kwargs.get("i1max", 0):
|
280
|
+
i1max = kwargs["i1max"]
|
281
|
+
w1type, tmax = m.w1_imax_umax(i1max, u1)
|
275
282
|
|
276
|
-
i1max = betai1(iq, id)[1]
|
277
283
|
logger.info("%s %s", n, T)
|
278
284
|
for nx in n:
|
279
285
|
w1 = 2*np.pi*nx*m.p
|
@@ -431,7 +437,7 @@ def efficiency_losses_map(eecpars, u1, T, temp, n, npoints=(60, 40),
|
|
431
437
|
e = pm / p1
|
432
438
|
else:
|
433
439
|
e = p1 / pm
|
434
|
-
eta.append(e)
|
440
|
+
eta.append(float(e))
|
435
441
|
|
436
442
|
return dict(
|
437
443
|
iq=iqd[0].tolist(),
|
@@ -450,4 +456,4 @@ def efficiency_losses_map(eecpars, u1, T, temp, n, npoints=(60, 40),
|
|
450
456
|
plfric=plfric.tolist(),
|
451
457
|
losses=ploss.tolist(),
|
452
458
|
plcu1_dc=plcu1_dc,
|
453
|
-
plcu1_ac=plcu1_ac)
|
459
|
+
plcu1_ac=plcu1_ac)
|
femagtools/machine/pm.py
CHANGED
@@ -182,6 +182,8 @@ class PmRelMachine(object):
|
|
182
182
|
return (0, 0)
|
183
183
|
if np.isscalar(iqd0):
|
184
184
|
i0 = self.io
|
185
|
+
if torque<0:
|
186
|
+
i0[0] = -i0[0]
|
185
187
|
else:
|
186
188
|
i0 = iqd0
|
187
189
|
if with_mtpa:
|
@@ -193,10 +195,14 @@ class PmRelMachine(object):
|
|
193
195
|
if res.success:
|
194
196
|
#raise ValueError(f'Torque {torque}, io {i0}: {res.message}')
|
195
197
|
return res.x
|
198
|
+
# should not happen
|
196
199
|
def func(i1):
|
197
200
|
return torque - self.mtpa(i1)[2]
|
201
|
+
# with warnings.catch_warnings():
|
202
|
+
# warnings.simplefilter("error")
|
198
203
|
i1 = so.fsolve(func, res.x[0])[0]
|
199
204
|
return self.mtpa(i1)[:2]
|
205
|
+
|
200
206
|
def func(iq):
|
201
207
|
return torque - self.torque_iqd(iq, 0)
|
202
208
|
return so.fsolve(func, 0)[0]
|
@@ -220,7 +226,7 @@ class PmRelMachine(object):
|
|
220
226
|
else:
|
221
227
|
i0 = (iq0, 0)
|
222
228
|
logger.debug("initial guess i0 %f -> %s tx %f torque %f",
|
223
|
-
|
229
|
+
self.io[0], i0, tx, torque)
|
224
230
|
else:
|
225
231
|
i0 = iqd0
|
226
232
|
|
@@ -237,7 +243,7 @@ class PmRelMachine(object):
|
|
237
243
|
# make new initial guess:
|
238
244
|
tx = self.tmech_iqd(*i0, n)
|
239
245
|
logger.debug("k %d new guess i0 %s tx %f torque %f",
|
240
|
-
|
246
|
+
k, i0, tx, torque)
|
241
247
|
i0=(min(0.9*self.i1range[1]/np.sqrt(2), torque/tx*i0[0]), 0)
|
242
248
|
k += 1
|
243
249
|
raise ValueError(
|
@@ -247,39 +253,6 @@ class PmRelMachine(object):
|
|
247
253
|
iq = so.fsolve(tqiq, (i0[0],))[0]
|
248
254
|
return iq, 0, self.tmech_iqd(iq, 0, n)
|
249
255
|
|
250
|
-
def iqd_tmech0(self, torque, n, iqd0=0, with_mtpa=True):
|
251
|
-
"""return minimum d-q-current for shaft torque"""
|
252
|
-
if np.abs(torque) < 1e-2:
|
253
|
-
return (0, 0)
|
254
|
-
if np.isscalar(iqd0):
|
255
|
-
i0 = self.io
|
256
|
-
else:
|
257
|
-
i0 = iqd0
|
258
|
-
|
259
|
-
if with_mtpa:
|
260
|
-
res = so.minimize(
|
261
|
-
lambda iqd: la.norm(iqd), i0, method='SLSQP',
|
262
|
-
constraints=({'type': 'eq',
|
263
|
-
'fun': lambda iqd:
|
264
|
-
self.tmech_iqd(*iqd, n) - torque}))
|
265
|
-
if res.success:
|
266
|
-
return res.x
|
267
|
-
|
268
|
-
#logger.warning("n: %s, torque %s: %s %s",
|
269
|
-
# 60*n, torque, res.message, i0)
|
270
|
-
# try a different approach:
|
271
|
-
#raise ValueError(
|
272
|
-
# f'Torque {torque:.1f} speed {60*n:.1f} {res.message}')
|
273
|
-
def func(i1):
|
274
|
-
return torque - self.mtpa_tmech(i1, n)[2]
|
275
|
-
i1 = so.fsolve(func, res.x[0])[0]
|
276
|
-
return self.mtpa_tmech(i1, n)[:2]
|
277
|
-
|
278
|
-
def tqiq(iq):
|
279
|
-
return torque - self.tmech_iqd(float(iq), 0, n)
|
280
|
-
iq = so.fsolve(tqiq, (i0[0],))[0]
|
281
|
-
return iq, 0, self.tmech_iqd(iq, 0, n)
|
282
|
-
|
283
256
|
def tloss_iqd(self, iq, id, n):
|
284
257
|
"""return loss torque of d-q current, iron loss correction factor
|
285
258
|
and friction windage losses"""
|
@@ -350,12 +323,12 @@ class PmRelMachine(object):
|
|
350
323
|
sign = -1 if i1max > 0 else 1
|
351
324
|
res = so.minimize(
|
352
325
|
lambda n: sign*self.tmech_iqd(iq, id, n),
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
326
|
+
n0,
|
327
|
+
constraints={
|
328
|
+
'type': 'eq',
|
329
|
+
'fun': lambda n:
|
330
|
+
np.sqrt(2)*u1max - np.linalg.norm(
|
331
|
+
self.uqd(2*np.pi*n*self.p, iq, id))})
|
359
332
|
return 2*np.pi*res.x[0]*self.p, self.tmech_iqd(iq, id, res.x[0])
|
360
333
|
|
361
334
|
return so.fsolve(lambda x: np.linalg.norm(
|
@@ -453,22 +426,26 @@ class PmRelMachine(object):
|
|
453
426
|
i1 = self.i1_tmech(torque, 0, n)
|
454
427
|
i0 = iqd(0, i1)
|
455
428
|
|
429
|
+
logger.debug("i0 %s", i0)
|
456
430
|
if np.linalg.norm(self.uqd(w1, *i0))/np.sqrt(2) > u1max:
|
457
431
|
beta, i1 = betai1(*i0)
|
458
432
|
with warnings.catch_warnings():
|
459
433
|
warnings.simplefilter("ignore")
|
460
|
-
|
461
|
-
self.uqd(w1, *iqd(b, i1)))/np.sqrt(2),
|
462
|
-
|
434
|
+
bx, _, ier, msg = so.fsolve(lambda b: u1max - np.linalg.norm(
|
435
|
+
self.uqd(w1, *iqd(b, i1)))/np.sqrt(2), beta,
|
436
|
+
full_output=True)
|
437
|
+
i0 = iqd(bx[0], i1)
|
438
|
+
logger.debug("i0 %s ier %d %s", i0, ier, msg)
|
463
439
|
|
464
|
-
res = so.minimize(
|
465
|
-
|
466
|
-
|
467
|
-
|
468
|
-
|
469
|
-
|
470
|
-
|
471
|
-
|
440
|
+
res = so.minimize(
|
441
|
+
lambda iqd: np.linalg.norm(iqd), i0, method='SLSQP',
|
442
|
+
constraints=(
|
443
|
+
{'type': 'eq',
|
444
|
+
'fun': lambda iqd:
|
445
|
+
self.tmech_iqd(*iqd, n) - torque},
|
446
|
+
{'type': 'ineq',
|
447
|
+
'fun': lambda iqd:
|
448
|
+
np.sqrt(2)*u1max - la.norm(self.uqd(w1, *iqd))}))
|
472
449
|
iq, id = res.x
|
473
450
|
else:
|
474
451
|
iq, id = i0
|
@@ -587,18 +564,19 @@ class PmRelMachine(object):
|
|
587
564
|
log((iq, id, tq))
|
588
565
|
return iq, id, tq
|
589
566
|
|
590
|
-
def iqd_imax_umax(self, i1max, w1, u1max, torque, with_mtpv=True,
|
567
|
+
def iqd_imax_umax(self, i1max, w1, u1max, torque, with_mtpv=True,
|
568
|
+
with_tmech=True, with_mtpa=True):
|
591
569
|
"""return d-q current and shaft torque at stator frequency and max voltage
|
592
570
|
and max current (for motor operation if maxtorque else generator operation)"""
|
593
571
|
if torque > 0:
|
594
|
-
sign
|
572
|
+
sign = -1
|
595
573
|
# -pi/2 --> 0
|
596
574
|
b0, b1 = max(-np.pi/2, self.betarange[0]), 0
|
597
575
|
if max(self.betarange) < b1:
|
598
576
|
raise ValueError(
|
599
577
|
f"invalid betarange for maxtorque>0: {self.betarange}")
|
600
578
|
else:
|
601
|
-
sign=1
|
579
|
+
sign = 1
|
602
580
|
# -pi/2 --> -pi
|
603
581
|
b0, b1 = -np.pi/2, max(-np.pi, self.betarange[0])
|
604
582
|
if min(self.betarange) > b0:
|
@@ -608,6 +586,7 @@ class PmRelMachine(object):
|
|
608
586
|
iq, id, _ = self.mtpa(i1max)
|
609
587
|
else:
|
610
588
|
iq, id = iqd(0, i1max)
|
589
|
+
|
611
590
|
deps = 1e-6
|
612
591
|
kmax = 100
|
613
592
|
|
@@ -622,8 +601,10 @@ class PmRelMachine(object):
|
|
622
601
|
else:
|
623
602
|
iq, id, tq = self.iqd_torque_umax(torque, w1, u1max)
|
624
603
|
if not with_mtpv:
|
604
|
+
logging.debug("not mtpv iq %f id %f tq %f",
|
605
|
+
iq, id, tq)
|
625
606
|
return iq, id, tq
|
626
|
-
beta, i1 = betai1(iq, id)
|
607
|
+
#beta, i1 = betai1(iq, id)
|
627
608
|
else:
|
628
609
|
for k in range(kmax):
|
629
610
|
bx = b0 + (b1-b0)/2
|
@@ -642,9 +623,9 @@ class PmRelMachine(object):
|
|
642
623
|
if abs(du) > 0.1:
|
643
624
|
logger.debug('oops? iqd_imax_umax one more torque reduction')
|
644
625
|
if with_tmech:
|
645
|
-
iq, id = self.iqd_tmech_umax(torque, w1, u1max)
|
626
|
+
iq, id, tq = self.iqd_tmech_umax(torque, w1, u1max)
|
646
627
|
else:
|
647
|
-
iq, id = self.iqd_torque_umax(torque, w1, u1max)
|
628
|
+
iq, id, tq = self.iqd_torque_umax(torque, w1, u1max)
|
648
629
|
if with_mtpv:
|
649
630
|
try:
|
650
631
|
if with_tmech:
|
@@ -656,9 +637,26 @@ class PmRelMachine(object):
|
|
656
637
|
iq, id, tq = self.mtpv(w1, u1max, iqd0=(iq, id),
|
657
638
|
maxtorque=torque>0,
|
658
639
|
i1max=i1max)
|
640
|
+
logging.debug("mtpv iq %f id %f tq %f",
|
641
|
+
iq, id, tq)
|
659
642
|
return iq, id, tq
|
660
643
|
except ValueError as e:
|
661
|
-
|
644
|
+
n = w1/2/np.pi/self.p
|
645
|
+
logger.debug(" i1max %f iq %f id %f", i1max, iq, id)
|
646
|
+
#
|
647
|
+
res = so.minimize(
|
648
|
+
lambda iqd: sign*self.tmech_iqd(*iqd, n),
|
649
|
+
(iq, id),
|
650
|
+
constraints=[{
|
651
|
+
'type': 'eq',
|
652
|
+
'fun': lambda iqd:
|
653
|
+
np.sqrt(2)*u1max - np.linalg.norm(
|
654
|
+
self.uqd(w1, *iqd))}])
|
655
|
+
logger.debug(" n %f i1max %f %f iq %f id %f tq %f",
|
656
|
+
60*n, i1max, np.linalg.norm(res.x)/np.sqrt(2),
|
657
|
+
iq, id, sign*res.fun)
|
658
|
+
if res['success'] and abs(i1max*np.sqrt(2)) >= np.linalg.norm(res.x):
|
659
|
+
return *res.x, sign*res.fun
|
662
660
|
|
663
661
|
if with_tmech:
|
664
662
|
tq = self.tmech_iqd(iq, id, w1/2/np.pi/self.p)
|
@@ -723,6 +721,8 @@ class PmRelMachine(object):
|
|
723
721
|
else:
|
724
722
|
i0 = iqd0
|
725
723
|
n = w1/2/np.pi/self.p
|
724
|
+
logger.debug("w1 %f u1 %f iqd0 %s maxtorque %s %f",
|
725
|
+
w1, u1, iqd0, maxtorque, i1max)
|
726
726
|
constraints=[{'type': 'eq',
|
727
727
|
'fun': lambda iqd:
|
728
728
|
np.sqrt(2)*u1 - la.norm(
|
@@ -734,6 +734,7 @@ class PmRelMachine(object):
|
|
734
734
|
res = so.minimize(lambda iqd: sign*self.tmech_iqd(*iqd, n), i0,
|
735
735
|
method='SLSQP',
|
736
736
|
constraints=constraints)
|
737
|
+
logger.debug("iq %f id %f w1 %f success %s", res.x[0], res.x[1], w1, res['success'])
|
737
738
|
if res['success']:
|
738
739
|
return res.x[0], res.x[1], sign*res.fun
|
739
740
|
#logger.warning("w1=%.1f u1=%.1f maxtorque=%s %s: %s", w1, u1, maxtorque, res.x, res.message)
|
@@ -814,7 +815,7 @@ class PmRelMachine(object):
|
|
814
815
|
if (abs(i1max) >= i1
|
815
816
|
and round(u1max, 1) >= round(np.linalg.norm(
|
816
817
|
self.uqd(w1max, iq, id)/np.sqrt(2)), 1)):
|
817
|
-
return [w1type/2/np.pi/self.p, speedmax]
|
818
|
+
return [float(w1type/2/np.pi/self.p), float(speedmax)]
|
818
819
|
wl, wu = [w1type, min(4*w1type, w1max)]
|
819
820
|
if with_mtpv:
|
820
821
|
kmax = 6
|
@@ -835,6 +836,7 @@ class PmRelMachine(object):
|
|
835
836
|
T, with_mtpa=with_mtpa,
|
836
837
|
with_mtpv=False)[:2]
|
837
838
|
i1 = betai1(iq, id)[1]
|
839
|
+
logger.debug("iq %f id %f i1 %f", iq, id, i1)
|
838
840
|
try:
|
839
841
|
if with_tmech:
|
840
842
|
def voltw1(wx):
|
@@ -851,7 +853,7 @@ class PmRelMachine(object):
|
|
851
853
|
if ier == 1: #in (1, 4, 5):
|
852
854
|
if abs(w[0]) <= wx:
|
853
855
|
self.check_extrapolation = True
|
854
|
-
return [w/2/np.pi/self.p
|
856
|
+
return [float(w/2/np.pi/self.p)
|
855
857
|
for w in (w1type, w[0], w1max)] # ['MTPA', 'MTPV']
|
856
858
|
if w[0] > wu:
|
857
859
|
wl += (wu-wl)/4
|
@@ -873,7 +875,7 @@ class PmRelMachine(object):
|
|
873
875
|
self.check_extrapolation = True
|
874
876
|
w1max = min(w1max, np.floor(self.w1_umax(
|
875
877
|
u1max, *iqd(-np.pi/2, abs(i1max)))))
|
876
|
-
return [w/2/np.pi/self.p for w in (w1type, w1max)] # ['MTPA']
|
878
|
+
return [float(w/2/np.pi/self.p) for w in (w1type, w1max)] # ['MTPA']
|
877
879
|
|
878
880
|
|
879
881
|
def operating_point(self, T, n, u1max, with_mtpa=True):
|
@@ -990,8 +992,8 @@ class PmRelMachine(object):
|
|
990
992
|
if kwargs.get('i1max', 0):
|
991
993
|
i1max = kwargs['i1max']
|
992
994
|
w1, Tf = self.w1_imax_umax(i1max, u1max,
|
993
|
-
|
994
|
-
|
995
|
+
with_mtpa=with_mtpa,
|
996
|
+
with_tmech=with_tmech)
|
995
997
|
if with_mtpa:
|
996
998
|
iq, id, T = self.mtpa(i1max)
|
997
999
|
else:
|
@@ -1026,7 +1028,8 @@ class PmRelMachine(object):
|
|
1026
1028
|
iq, id = iqd(0, i1max)
|
1027
1029
|
|
1028
1030
|
if with_tmech:
|
1029
|
-
w1, Tf = self.w1_imax_umax(i1max, u1max,
|
1031
|
+
w1, Tf = self.w1_imax_umax(i1max, u1max,
|
1032
|
+
with_mtpa=with_mtpa,
|
1030
1033
|
with_tmech=with_tmech)
|
1031
1034
|
else:
|
1032
1035
|
iq, id = self.iqd_torque(T)
|
@@ -1100,14 +1103,15 @@ class PmRelMachine(object):
|
|
1100
1103
|
iq, id, tq = self.iqd_imax_umax(
|
1101
1104
|
i1max, w1, u1max,
|
1102
1105
|
tq, with_tmech=with_tmech,
|
1103
|
-
with_mtpv=with_mtpv,
|
1104
1106
|
with_mtpa=with_mtpa)
|
1105
1107
|
else:
|
1106
1108
|
if with_tmech:
|
1107
1109
|
iq, id, tq = self.mtpv_tmech(w1, u1max,
|
1110
|
+
iqd0=(iq, id),
|
1108
1111
|
maxtorque=T > 0)
|
1109
1112
|
else:
|
1110
1113
|
iq, id, tq = self.mtpv(w1, u1max,
|
1114
|
+
iqd0=(iq, id),
|
1111
1115
|
maxtorque=T > 0)
|
1112
1116
|
if (T > 0 and tq > 0) or (T < 0 and tq < 0):
|
1113
1117
|
r['id'].append(id)
|
@@ -1115,8 +1119,8 @@ class PmRelMachine(object):
|
|
1115
1119
|
r['n'].append(nn)
|
1116
1120
|
r['T'].append(tq)
|
1117
1121
|
else:
|
1118
|
-
logger.
|
1119
|
-
|
1122
|
+
logger.debug("fieldweakening: n %g T %g tq %g i1max %g w1 %g u1 %g",
|
1123
|
+
nn*60, T, tq, i1max, w1, u1max)
|
1120
1124
|
except ValueError as e:
|
1121
1125
|
nmax = r['n'][-1]
|
1122
1126
|
logger.warning("%s: adjusted nmax %f T %f", e, nmax, r['T'][-1])
|
femagtools/machine/sm.py
CHANGED
@@ -126,7 +126,7 @@ def parident(workdir, engine, machine,
|
|
126
126
|
period_frac=kwargs.get('period_frac', 6),
|
127
127
|
speed=kwargs.get('speed', 50))
|
128
128
|
|
129
|
-
if kwargs.get("feloss", 0):
|
129
|
+
if kwargs.get("feloss", 0):
|
130
130
|
simulation["feloss"] = kwargs["feloss"]
|
131
131
|
machine["calc_fe_loss"] = loss_models[kwargs["feloss"].lower()]
|
132
132
|
###self.cleanup() # remove previously created files in workdir
|
@@ -413,8 +413,8 @@ class SynchronousMachine(object):
|
|
413
413
|
def uqd(self, w1, iq, id, iex):
|
414
414
|
"""return uq, ud of frequency w1 and d-q current"""
|
415
415
|
psid, psiq = self.psi(iq, id, iex)
|
416
|
-
r1 = self.rstat(w1)
|
417
|
-
return r1*iq + w1*psid, r1*id - w1*psiq
|
416
|
+
# r1 = self.rstat(w1)
|
417
|
+
return self.r1*iq + w1*(self.ls*id + psid), self.r1*id - w1*(self.ls*iq + psiq)
|
418
418
|
|
419
419
|
def plcu1(self, iqde, w1):
|
420
420
|
r1 = self.rstat(w1)
|
@@ -458,9 +458,9 @@ class SynchronousMachine(object):
|
|
458
458
|
#options={'disp': disp, 'maxiter': maxiter})
|
459
459
|
if res['success']:
|
460
460
|
return res.x
|
461
|
-
else:
|
461
|
+
else:
|
462
462
|
res = so.minimize(
|
463
|
-
lambda cur: (self.tmech_iqd(*cur, n) - torque)**2, res.x, method='SLSQP',
|
463
|
+
lambda cur: (self.tmech_iqd(*cur, n) - torque)**2, res.x, method='SLSQP',
|
464
464
|
bounds=self.bounds,
|
465
465
|
)
|
466
466
|
if res['success']:
|
@@ -548,10 +548,10 @@ class SynchronousMachine(object):
|
|
548
548
|
log(res.x)
|
549
549
|
if res["success"]:
|
550
550
|
return *res.x, self.tmech_iqd(*res.x, n)
|
551
|
-
else:
|
551
|
+
else:
|
552
552
|
# didn't converge, fullfill voltage and torque demand
|
553
553
|
res = so.minimize(
|
554
|
-
lambda cur: (self.tmech_iqd(*cur, n) - torque)**2, io, method='SLSQP',
|
554
|
+
lambda cur: (self.tmech_iqd(*cur, n) - torque)**2, io, method='SLSQP',
|
555
555
|
bounds=self.bounds,
|
556
556
|
constraints=[
|
557
557
|
{'type': 'eq',
|
@@ -562,8 +562,8 @@ class SynchronousMachine(object):
|
|
562
562
|
return *res.x, self.tmech_iqd(*res.x, n)
|
563
563
|
else:
|
564
564
|
res = so.minimize(
|
565
|
-
lambda cur: (self.tmech_iqd(*cur, n) - torque)**2 +
|
566
|
-
(np.linalg.norm(self.uqd(w1, *cur)) - u1max*np.sqrt(2))**2, io, method='SLSQP',
|
565
|
+
lambda cur: (self.tmech_iqd(*cur, n) - torque)**2 +
|
566
|
+
(np.linalg.norm(self.uqd(w1, *cur)) - u1max*np.sqrt(2))**2, io, method='SLSQP',
|
567
567
|
bounds=self.bounds,
|
568
568
|
)
|
569
569
|
return *res.x, self.tmech_iqd(*res.x, n)
|
@@ -680,7 +680,7 @@ class SynchronousMachine(object):
|
|
680
680
|
Tf = T
|
681
681
|
w1type = self.w1_umax(u1max, iq, id, iex)
|
682
682
|
logger.debug("w1type %f", w1type)
|
683
|
-
wmType = w1type/self.p
|
683
|
+
wmType = float(w1type/self.p)
|
684
684
|
pmax = Tf*wmType
|
685
685
|
|
686
686
|
def tload(wm):
|
@@ -723,7 +723,7 @@ class SynchronousMachine(object):
|
|
723
723
|
iq, id, iex, tqx = self.iqd_torque_umax(
|
724
724
|
tq, w1, u1max)
|
725
725
|
tqx -= self.tfric
|
726
|
-
else:
|
726
|
+
else:
|
727
727
|
tqx = Tf
|
728
728
|
|
729
729
|
uq, ud = self.uqd(w1, iq, id, iex)
|
@@ -857,9 +857,9 @@ class SynchronousMachinePsidq(SynchronousMachine):
|
|
857
857
|
'rotor_hyst', 'rotor_eddy')}
|
858
858
|
|
859
859
|
def set_max_iex(self, iexc):
|
860
|
-
self.bounds[-1] = (self.bounds[-1][0], iexc)
|
860
|
+
self.bounds[-1] = (self.bounds[-1][0], iexc)
|
861
861
|
self.exc_max = iexc
|
862
|
-
|
862
|
+
|
863
863
|
def psi(self, iq, id, iex):
|
864
864
|
"""return psid, psiq of currents iq, id"""
|
865
865
|
try:
|
@@ -980,9 +980,9 @@ class SynchronousMachineLdq(SynchronousMachine):
|
|
980
980
|
'styoke_eddy', 'stteeth_eddy',
|
981
981
|
'rotor_hyst', 'rotor_eddy')}
|
982
982
|
pass
|
983
|
-
|
983
|
+
|
984
984
|
def set_max_iex(self, iexc):
|
985
|
-
self.bounds[-1] = (self.bounds[-1][0], iexc)
|
985
|
+
self.bounds[-1] = (self.bounds[-1][0], iexc)
|
986
986
|
self.exc_max = iexc
|
987
987
|
|
988
988
|
def psi(self, iq, id, iex):
|
femagtools/plot/bch.py
CHANGED
@@ -515,10 +515,12 @@ def cogging(bch, title=''):
|
|
515
515
|
fig.subplots_adjust(top=0.92)
|
516
516
|
|
517
517
|
|
518
|
-
def demagnetization(demag, ax=0):
|
518
|
+
def demagnetization(demag, title='', ax=0):
|
519
519
|
"""plot rel. remanence vs. current"""
|
520
520
|
if ax == 0:
|
521
521
|
ax = plt.gca()
|
522
|
+
if title:
|
523
|
+
ax.set_title(title)
|
522
524
|
scale = 1
|
523
525
|
unit = 'A'
|
524
526
|
if np.max(demag['i1']) > 25e3:
|
femagtools/plot/char.py
CHANGED
@@ -304,23 +304,12 @@ def _plot_contour(speed, torque, z, ax, title='', levels=[],
|
|
304
304
|
y, yscale = _normalize10(y, **kwargs)
|
305
305
|
|
306
306
|
if not levels:
|
307
|
+
levels = [0.5, 0.7, 0.8]
|
307
308
|
if max(z) <= 1:
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
levels = np.round(levels, 2)
|
313
|
-
levels = list(levels)
|
314
|
-
|
315
|
-
else:
|
316
|
-
#levels = [0.25, 0.5, 0.75, 0.8, 0.84,
|
317
|
-
#0.88, 0.9, 0.92, 0.94, 0.96]
|
318
|
-
levels = np.linspace(min(z),max(z),9)
|
319
|
-
levels = np.round(levels, 2)
|
320
|
-
levels = list(levels)
|
321
|
-
|
322
|
-
if max(z) > levels[-1]:
|
323
|
-
levels.append(np.ceil(max(z)*100)/100)
|
309
|
+
a = np.array(z)
|
310
|
+
zmax = np.ceil(100*np.max(z))/100
|
311
|
+
levels += [zmax - x for x in
|
312
|
+
[0.07, 0.05, 0.03, 0.02, 0.01, 0]]
|
324
313
|
else:
|
325
314
|
levels = 14
|
326
315
|
#
|