femagtools 1.8.6__py3-none-any.whl → 1.8.8__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 +2 -2
- femagtools/amela.py +18 -286
- femagtools/bch.py +11 -7
- femagtools/ecloss.py +121 -105
- femagtools/femag.py +13 -73
- femagtools/fsl.py +11 -8
- femagtools/isa7.py +174 -10
- femagtools/leakinduc.py +63 -0
- femagtools/losscoeffs.py +29 -3
- femagtools/machine/afpm.py +138 -60
- femagtools/machine/effloss.py +13 -1
- femagtools/mcv.py +173 -9
- femagtools/nc.py +16 -14
- femagtools/parstudy.py +3 -1
- femagtools/plot/bch.py +126 -44
- femagtools/plot/nc.py +13 -0
- femagtools/shortcircuit.py +378 -0
- femagtools/templates/psi-torq-rem-rot.mako +127 -0
- femagtools/templates/psi-torq-rot.mako +98 -0
- femagtools/tks.py +1 -1
- femagtools/windings.py +65 -0
- {femagtools-1.8.6.dist-info → femagtools-1.8.8.dist-info}/METADATA +1 -1
- {femagtools-1.8.6.dist-info → femagtools-1.8.8.dist-info}/RECORD +31 -27
- {femagtools-1.8.6.dist-info → femagtools-1.8.8.dist-info}/WHEEL +1 -1
- tests/test_afpm.py +2 -2
- tests/test_amela.py +1 -3
- tests/test_fsl.py +4 -4
- tests/test_nc.py +10 -0
- {femagtools-1.8.6.dist-info → femagtools-1.8.8.dist-info}/LICENSE +0 -0
- {femagtools-1.8.6.dist-info → femagtools-1.8.8.dist-info}/entry_points.txt +0 -0
- {femagtools-1.8.6.dist-info → femagtools-1.8.8.dist-info}/top_level.txt +0 -0
femagtools/mcv.py
CHANGED
@@ -99,7 +99,8 @@ def norm_pfe(B, pfe):
|
|
99
99
|
b = list(b)
|
100
100
|
b[-1] = Bv[n]
|
101
101
|
n += 1
|
102
|
-
|
102
|
+
k = 3 if len(pfe[i]) > 3 else 2
|
103
|
+
pfunc = make_interp_spline(b, pfe[i], k=k)
|
103
104
|
m.append([float(pfunc(x))
|
104
105
|
for x in Bv[:n]] + [None]*(len(Bv)-n))
|
105
106
|
return Bv.tolist(), m
|
@@ -298,6 +299,8 @@ class Mcv(object):
|
|
298
299
|
# {'ch': 0, 'cw': 0, 'ch_freq':0, 'cw_freq':0}
|
299
300
|
self.bertotti = {}
|
300
301
|
# {'ch': 0, 'cw': 0, 'ce':0, 'ch_freq':0, 'cw_freq':0}
|
302
|
+
self.steinmetz_modified = {}
|
303
|
+
# {'ch': 0, 'cw': 0, 'ch_freq': 1, 'b_beta_coeff': 0, 'cw_freq': 2, 'b_coeff': 2}
|
301
304
|
self.MC1_FE_SPEZ_WEIGTH = 7.65
|
302
305
|
self.MC1_FE_SAT_MAGNETIZATION = 2.15
|
303
306
|
|
@@ -359,7 +362,7 @@ class Mcv(object):
|
|
359
362
|
for k in wtrans:
|
360
363
|
if wtrans[k] in data.keys():
|
361
364
|
self.__setattr__(k, data[wtrans[k]])
|
362
|
-
for k in ('bertotti', 'jordan', 'steinmetz'):
|
365
|
+
for k in ('bertotti', 'jordan', 'steinmetz', 'steinmetz_modified'):
|
363
366
|
if k in data:
|
364
367
|
self.__setattr__(k, data[k])
|
365
368
|
self.curve = data['curve']
|
@@ -374,6 +377,13 @@ class Mcv(object):
|
|
374
377
|
# assume jordan iron loss parameters
|
375
378
|
for k in self.jordan:
|
376
379
|
self.jordan[k] = getattr(self, transl[k])
|
380
|
+
# set loss coeffs when existing
|
381
|
+
try:
|
382
|
+
for k in ('bertotti', 'jordan', 'steinmetz', 'steinmetz_modified'):
|
383
|
+
if k in data:
|
384
|
+
self.__setattr__(k, data[k])
|
385
|
+
except:
|
386
|
+
pass
|
377
387
|
return
|
378
388
|
|
379
389
|
def rtrimValueList(self, vlist):
|
@@ -489,14 +499,24 @@ class Writer(Mcv):
|
|
489
499
|
feloss: (str) iron loss method (bertotti, jordan)
|
490
500
|
"""
|
491
501
|
curve = self._prepare(fillfac, recsin)
|
502
|
+
write_losses = True
|
492
503
|
try:
|
493
504
|
if feloss.lower() == 'bertotti':
|
494
505
|
for k in self.bertotti:
|
495
506
|
setattr(self, transl[k], self.bertotti[k])
|
496
|
-
|
497
|
-
|
507
|
+
write_losses = False
|
508
|
+
elif feloss.lower() == 'jordan':
|
498
509
|
for k in self.jordan:
|
499
510
|
setattr(self, transl[k], self.jordan[k])
|
511
|
+
write_losses = False
|
512
|
+
elif feloss.lower() == 'steinmetz':
|
513
|
+
for k in self.steinmetz:
|
514
|
+
setattr(self, transl[k], self.steinmetz[k])
|
515
|
+
write_losses = False
|
516
|
+
elif feloss.lower() == 'modified steinmetz':
|
517
|
+
for k in self.steinmetz_modified:
|
518
|
+
setattr(self, transl[k], self.steinmetz_modified[k])
|
519
|
+
write_losses = False
|
500
520
|
except AttributeError as e:
|
501
521
|
logger.warning("%s", e)
|
502
522
|
pass
|
@@ -578,7 +598,8 @@ class Writer(Mcv):
|
|
578
598
|
self.writeBlock([self.mc1_angle[K], self.mc1_db2[K]])
|
579
599
|
|
580
600
|
try:
|
581
|
-
if not (self.mc1_ch_factor or self.mc1_cw_factor)
|
601
|
+
if (not (self.mc1_ch_factor or self.mc1_cw_factor)
|
602
|
+
and self.losses and write_losses):
|
582
603
|
# fit loss parameters
|
583
604
|
pfe = self.losses['pfe']
|
584
605
|
f = self.losses['f']
|
@@ -611,12 +632,25 @@ class Writer(Mcv):
|
|
611
632
|
float(self.mc1_fe_spez_weigth),
|
612
633
|
float(self.mc1_fe_sat_magnetization)])
|
613
634
|
|
635
|
+
logger.info("MCV coeffs %s",
|
636
|
+
{"fo": float(self.mc1_base_frequency),
|
637
|
+
"Bo": float(self.mc1_base_induction),
|
638
|
+
"ch": float(self.mc1_ch_factor),
|
639
|
+
"cw": float(self.mc1_cw_factor),
|
640
|
+
"ch_freq": float(self.mc1_ch_freq_factor),
|
641
|
+
"cw_freq": float(self.mc1_cw_freq_factor),
|
642
|
+
"b_coeff": float(self.mc1_induction_factor),
|
643
|
+
"fr_spez_weight": float(self.mc1_fe_spez_weigth),
|
644
|
+
"fe_sat_magnetization": float(self.mc1_fe_sat_magnetization)})
|
645
|
+
|
614
646
|
if not hasattr(self, 'losses') or not self.losses:
|
615
647
|
# new variables: ce factor for bertotti losses
|
616
648
|
# b_beta_coeff for modified steinmetz
|
617
649
|
try:
|
618
650
|
self.writeBlock([float(self.mc1_ce_factor),
|
619
651
|
float(self.mc1_induction_beta_factor)])
|
652
|
+
#logger.info(f"ce = {float(self.mc1_ce_factor)}")
|
653
|
+
#logger.info(f"b_beta_coeff = {float(self.mc1_induction_beta_factor)}")
|
620
654
|
except:
|
621
655
|
pass
|
622
656
|
return
|
@@ -677,13 +711,24 @@ class Writer(Mcv):
|
|
677
711
|
[0.0]*(M_LOSS_INDUCT - len(pl)))
|
678
712
|
self.writeBlock(float(f))
|
679
713
|
nrec += 1
|
680
|
-
|
681
|
-
|
682
|
-
|
714
|
+
|
715
|
+
if write_losses:
|
716
|
+
logger.info("Append empty blocks %d x %d",
|
717
|
+
M_LOSS_FREQ - nrec, M_LOSS_INDUCT)
|
718
|
+
for m in range(M_LOSS_FREQ - nrec):
|
719
|
+
self.writeBlock([0.0]*M_LOSS_INDUCT)
|
720
|
+
self.writeBlock(0.0)
|
683
721
|
|
684
722
|
self.writeBlock([self.losses['cw'], self.losses['cw_freq'],
|
685
723
|
self.losses['b_coeff'], self.losses['fo'],
|
686
724
|
self.losses['Bo']])
|
725
|
+
logger.info("loss coeff %s",
|
726
|
+
{"cw": float(self.losses['cw']),
|
727
|
+
"cw_freq": float(self.losses['cw_freq']),
|
728
|
+
"b_coeff": float(self.losses['b_coeff']),
|
729
|
+
"fo": float(self.losses['fo']),
|
730
|
+
"Bo": float(self.losses['Bo'])})
|
731
|
+
|
687
732
|
self.writeBlock([1])
|
688
733
|
logger.info('Losses n freq %d n ind %d', nfreq, nind)
|
689
734
|
except Exception as e:
|
@@ -1113,7 +1158,7 @@ class MagnetizingCurve(object):
|
|
1113
1158
|
repls.items(), name)
|
1114
1159
|
|
1115
1160
|
def writefile(self, name, directory='.',
|
1116
|
-
fillfac=None, recsin='', feloss='
|
1161
|
+
fillfac=None, recsin='', feloss=''):
|
1117
1162
|
"""find magnetic curve by name or id and write binary file
|
1118
1163
|
Arguments:
|
1119
1164
|
name: key of mcv dict (name or id)
|
@@ -1175,6 +1220,125 @@ class MagnetizingCurve(object):
|
|
1175
1220
|
losses['fo'] = self.mcv[m]['fo']
|
1176
1221
|
|
1177
1222
|
|
1223
|
+
class MCVconvert:
|
1224
|
+
def __init__(self, bhdata):
|
1225
|
+
self.steinmetz = dict(cw=0, cw_freq=0, b_coeff=0)
|
1226
|
+
self.jordan = dict(ch=0, ch_freq=0, cw=0, cw_freq=0, b_coeff=0)
|
1227
|
+
self.bertotti = dict(ch=0, cw=0, ce=0)
|
1228
|
+
self.steinmetz_modified = dict(ch=0, cw=0, ch_freq=1, b_beta_coeff=0, cw_freq=2, b_coeff=2)
|
1229
|
+
self.losscalc = None
|
1230
|
+
|
1231
|
+
B = []
|
1232
|
+
f = [50.0, 100.0, 200.0, 400.0, 1000.0, 2000.0]
|
1233
|
+
pfe = []
|
1234
|
+
jordan = False
|
1235
|
+
bertotti = False
|
1236
|
+
modified_steinmetz = False
|
1237
|
+
flag = False
|
1238
|
+
|
1239
|
+
if "losses" in bhdata:
|
1240
|
+
# test if any nan in data
|
1241
|
+
for i in ("B", "f"):
|
1242
|
+
if np.any(np.isnan(bhdata["losses"][i])) or \
|
1243
|
+
np.any(np.isnan(bhdata["losses"][i])):
|
1244
|
+
flag = True
|
1245
|
+
for i in bhdata["losses"]['pfe']:
|
1246
|
+
if np.any(np.isnan(i)):
|
1247
|
+
flag = True
|
1248
|
+
|
1249
|
+
if 'losses' not in bhdata or flag:
|
1250
|
+
# check steinmetz or jordan
|
1251
|
+
bhdata.update({"losses": {"pfe": [], "f":[], "B": []}})
|
1252
|
+
B = bhdata["curve"][-1]["bi"]
|
1253
|
+
if "ch" in bhdata:
|
1254
|
+
|
1255
|
+
if "ce" in bhdata:
|
1256
|
+
if bhdata['ce'] > 1e-15:
|
1257
|
+
bertotti = True
|
1258
|
+
|
1259
|
+
if bhdata["ch"] > 1e-15 and bhdata['ce'] < 1e-15:
|
1260
|
+
jordan = True
|
1261
|
+
|
1262
|
+
else:
|
1263
|
+
jordan = True
|
1264
|
+
|
1265
|
+
#if (conditions for modified steinmetz):
|
1266
|
+
# modified_steinmetz = True
|
1267
|
+
|
1268
|
+
if jordan:
|
1269
|
+
self.losscalc = 'jordan'
|
1270
|
+
logger.info("calculating based on jordan...")
|
1271
|
+
for i in f:
|
1272
|
+
pfe.append(lc.pfe_jordan(i, np.array(B), bhdata['ch'], bhdata['ch_freq'], bhdata['cw'],
|
1273
|
+
bhdata['cw_freq'], bhdata['b_coeff'], 50, 1.5))
|
1274
|
+
|
1275
|
+
elif bertotti:
|
1276
|
+
self.losscalc = 'bertotti'
|
1277
|
+
logger.info("calculating based on bertotti")
|
1278
|
+
for i in f:
|
1279
|
+
pfe.append(lc.wbert(i, np.array(B), bhdata['ch'], bhdata['cw'], bhdata['ce']))
|
1280
|
+
|
1281
|
+
elif modified_steinmetz:
|
1282
|
+
self.losscalc = 'modified steinmetz'
|
1283
|
+
logger.info("calculating based on modified steinmetz...")
|
1284
|
+
for i in f:
|
1285
|
+
pfe.append(lc.pfe_modified_steinmetz(i, np.array(B), bhdata['ch'], bhdata['cw'], bhdata['b_coeff'], bhdata['b_beta_coeff'], 1, 1))
|
1286
|
+
|
1287
|
+
else: # steinmetz
|
1288
|
+
self.losscalc = 'steinmetz'
|
1289
|
+
logger.info("calculating based on steinmetz...")
|
1290
|
+
for i in f:
|
1291
|
+
pfe.append(lc.pfe_steinmetz(i, np.array(B), bhdata['cw'],
|
1292
|
+
bhdata['cw_freq'], bhdata['b_coeff'], 50, 1.5))
|
1293
|
+
bhdata['losses']['pfe'] = pfe
|
1294
|
+
bhdata['losses']['B'] = B
|
1295
|
+
bhdata['losses']['f'] = f
|
1296
|
+
|
1297
|
+
idx = 0
|
1298
|
+
for i, j in enumerate(bhdata['losses']['f']):
|
1299
|
+
if j == 0:
|
1300
|
+
idx = i
|
1301
|
+
break
|
1302
|
+
idx = idx - 1
|
1303
|
+
z = lc.fitsteinmetz(bhdata['losses']['f'][0:idx],
|
1304
|
+
bhdata['losses']['B'],
|
1305
|
+
bhdata['losses']['pfe'][0:idx],
|
1306
|
+
1.5,
|
1307
|
+
50)
|
1308
|
+
|
1309
|
+
for i, j in enumerate(self.steinmetz):
|
1310
|
+
self.steinmetz[j] = z[i]
|
1311
|
+
self.steinmetz.update({"Bo": 1.5, "fo": 50})
|
1312
|
+
|
1313
|
+
z = lc.fitjordan(bhdata['losses']['f'][0:idx],
|
1314
|
+
bhdata['losses']['B'],
|
1315
|
+
bhdata['losses']['pfe'][0:idx],
|
1316
|
+
1.5,
|
1317
|
+
50)
|
1318
|
+
|
1319
|
+
for i, j in enumerate(self.jordan):
|
1320
|
+
self.jordan[j] = z[i]
|
1321
|
+
self.jordan.update({"Bo": 1.5, "fo": 50})
|
1322
|
+
|
1323
|
+
z = lc.fit_bertotti(bhdata['losses']['f'][0:idx],
|
1324
|
+
bhdata['losses']['B'],
|
1325
|
+
bhdata['losses']['pfe'][0:idx])
|
1326
|
+
|
1327
|
+
for i, j in enumerate(self.bertotti):
|
1328
|
+
self.bertotti[j] = z[i]
|
1329
|
+
self.bertotti.update({"Bo": 1, "fo": 1, "alpha": 2.0, "ch_freq": 1.0, "cw_freq": 2.0, "b_coeff": 2.0})
|
1330
|
+
|
1331
|
+
z = lc.fit_modified_steinmetz(bhdata['losses']['f'][0:idx],
|
1332
|
+
bhdata['losses']['B'],
|
1333
|
+
bhdata['losses']['pfe'][0:idx], 1, 1)
|
1334
|
+
|
1335
|
+
for i,j in enumerate(self.steinmetz_modified):
|
1336
|
+
self.steinmetz_modified[j] = z[i]
|
1337
|
+
self.steinmetz_modified.update({"Bo": 1, "fo": 1})
|
1338
|
+
|
1339
|
+
bhdata['losses']['pfe'] = np.transpose(bhdata['losses']['pfe']).tolist() #len(B) rows and len(f) columns
|
1340
|
+
|
1341
|
+
|
1178
1342
|
def read(filename):
|
1179
1343
|
"""read MC/MCV file and return mc dict"""
|
1180
1344
|
mcv = Reader()
|
femagtools/nc.py
CHANGED
@@ -192,21 +192,23 @@ class Reader(object):
|
|
192
192
|
for k in ('sr_key', 'nxt_sr_pntr')]
|
193
193
|
except:
|
194
194
|
pass
|
195
|
-
|
196
|
-
|
195
|
+
|
196
|
+
grp = ds.groups['machine']
|
197
|
+
if 'speed' in grp.variables:
|
197
198
|
self.speed = float(grp.variables['speed'].getValue().data)
|
199
|
+
if 'fc_radius' in grp.variables:
|
198
200
|
self.FC_RADIUS = float(grp.variables['fc_radius'].getValue().data)
|
199
|
-
|
201
|
+
self.delta_node_angle = float( # rad
|
202
|
+
grp.variables['delta_node_angle'].getValue().data)
|
203
|
+
self.arm_length = float(grp.variables['arm_length'].getValue().data)
|
204
|
+
for attr in ('pole_pairs', 'poles_sim', 'coil_span',
|
205
|
+
'state_of_problem', 'move_action'):
|
206
|
+
if attr in grp.variables:
|
207
|
+
setattr(self, attr, int(grp.variables[attr].getValue().data))
|
208
|
+
if 'num_layers' in grp.variables:
|
200
209
|
self.layers = int(grp.variables['num_layers'].getValue().data)
|
201
|
-
|
202
|
-
self.delta_node_angle = float( # rad
|
203
|
-
grp.variables['delta_node_angle'].getValue().data)
|
204
|
-
self.poles_sim = int(grp.variables['poles_sim'].getValue().data)
|
210
|
+
if 'num_slots' in grp.variables:
|
205
211
|
self.slots = int(grp.variables['num_slots'].getValue().data)
|
206
|
-
self.arm_length = float(grp.variables['arm_length'].getValue().data)
|
207
|
-
self.state_of_problem = int(grp.variables['state_of_problem'].getValue().data)
|
208
|
-
except:
|
209
|
-
pass
|
210
212
|
|
211
213
|
if hasattr(self, 'state_of_problem'):
|
212
214
|
if self.state_of_problem == 5:
|
@@ -236,18 +238,18 @@ class Reader(object):
|
|
236
238
|
except KeyError:
|
237
239
|
pass
|
238
240
|
|
239
|
-
|
241
|
+
if 'el_induction' in ds.groups:
|
240
242
|
grp = ds.groups['el_induction']
|
241
243
|
(self.pos_el_fe_induction,
|
242
244
|
self.el_fe_induction_1,
|
243
245
|
self.el_fe_induction_2,
|
244
|
-
self.eddy_cu_vpot) = [grp.variables[k][:]
|
246
|
+
self.eddy_cu_vpot) = [grp.variables[k][:] if k in grp.variables else []
|
245
247
|
for k in ('position',
|
246
248
|
'fe_induction_1',
|
247
249
|
'fe_induction_2',
|
248
250
|
'eddy_cu_vpot')]
|
249
251
|
logger.debug('el_fe_induction %d', len(self.pos_el_fe_induction))
|
250
|
-
|
252
|
+
else:
|
251
253
|
self.pos_el_fe_induction = []
|
252
254
|
self.el_fe_induction_1 = []
|
253
255
|
self.el_fe_induction_2 = []
|
femagtools/parstudy.py
CHANGED
@@ -6,6 +6,7 @@ import scipy as sc
|
|
6
6
|
import logging
|
7
7
|
import glob
|
8
8
|
import os
|
9
|
+
import re
|
9
10
|
import time
|
10
11
|
import shutil
|
11
12
|
import functools
|
@@ -172,7 +173,8 @@ class ParameterStudy(object):
|
|
172
173
|
else:
|
173
174
|
workdir = pathlib.Path(self.femag.workdir)
|
174
175
|
for d in workdir.glob('[0-9]*'):
|
175
|
-
|
176
|
+
if re.search(r'^\d+$', d.name):
|
177
|
+
shutil.rmtree(d)
|
176
178
|
|
177
179
|
extra_result_files = []
|
178
180
|
if simulation.get('airgap_induc', False):
|
femagtools/plot/bch.py
CHANGED
@@ -515,80 +515,151 @@ def cogging(bch, title=''):
|
|
515
515
|
fig.subplots_adjust(top=0.92)
|
516
516
|
|
517
517
|
|
518
|
-
def
|
519
|
-
"""
|
520
|
-
|
521
|
-
|
522
|
-
|
523
|
-
|
524
|
-
|
525
|
-
|
526
|
-
|
527
|
-
|
528
|
-
|
529
|
-
|
530
|
-
|
518
|
+
def demagnetization(demag, ax=0):
|
519
|
+
"""plot rel. remanence vs. current"""
|
520
|
+
if ax == 0:
|
521
|
+
ax = plt.gca()
|
522
|
+
scale = 1
|
523
|
+
unit = 'A'
|
524
|
+
if np.max(demag['i1']) > 25e3:
|
525
|
+
scale = 1e-3
|
526
|
+
unit = 'kA'
|
527
|
+
i1 = [scale*x for x in demag['i1']]
|
528
|
+
ax.plot(i1, demag['rr'], 'o', color='C0')
|
529
|
+
ax.plot(i1, demag['rr'], color='C0')
|
530
|
+
rrmin = 0.6
|
531
|
+
if demag.get('i1c', 0):
|
532
|
+
Icrit = scale*demag['i1c']
|
533
|
+
Hk = demag['Hk']
|
534
|
+
Tmag = demag['Tmag']
|
535
|
+
di = 0.05*np.max(i1)
|
536
|
+
rrmin = min(0.6, np.min(demag['rr']))
|
537
|
+
ax.plot([Icrit, Icrit], [rrmin, 1], 'k--')
|
538
|
+
ax.annotate(
|
539
|
+
f'Icrit = {Icrit:.1f}{unit}\nHk = {Hk:.1f} kA/m\nTmag={Tmag:.1f} °C',
|
540
|
+
xy=(Icrit, rrmin),
|
541
|
+
xytext=(Icrit-di, rrmin+0.1*(1-rrmin)), ha='right',
|
542
|
+
bbox={'facecolor': 'white',
|
543
|
+
'edgecolor': 'white'})
|
544
|
+
ax.set_ylim([rrmin, 1.01])
|
545
|
+
ax.set_ylabel('Rel. Remanence')
|
546
|
+
ax.set_xlabel(f'Phase Current / {unit}')
|
547
|
+
ax.grid()
|
548
|
+
|
549
|
+
|
550
|
+
def transientsc_currents(scData, ax=0, title='', set_xlabel=True):
|
551
|
+
"""plot transient shortcircuit currents vs time"""
|
552
|
+
if ax == 0:
|
553
|
+
ax = plt.gca()
|
531
554
|
ax.grid(True)
|
532
|
-
|
555
|
+
if title:
|
556
|
+
ax.set_title(title)
|
557
|
+
istat = np.array([scData[i]
|
533
558
|
for i in ('ia', 'ib', 'ic')])
|
534
559
|
pv = [find_peaks_and_valleys(
|
535
|
-
np.array(
|
560
|
+
np.array(scData['time']), i1)
|
536
561
|
for i1 in istat]
|
537
562
|
try:
|
538
563
|
ipvmax = np.argmax(
|
539
564
|
[y['yp'] if np.abs(y['yp']) > np.abs(y['yv']) else y['yv']
|
540
|
-
for y in pv])
|
565
|
+
for y in pv if y['yp']])
|
541
566
|
imax = pv[ipvmax]['yp'] if np.abs(pv[ipvmax]['yp']) > np.abs(pv[ipvmax]['yv']) else pv[ipvmax]['yv']
|
567
|
+
iac = [pv[ipvmax]['tpeaks'][-1], pv[ipvmax]['peaks'][-1]]
|
542
568
|
except KeyError:
|
543
569
|
pass
|
544
570
|
if np.max(istat) > 4000:
|
545
571
|
istat *= 1e-3
|
546
|
-
|
547
|
-
|
572
|
+
try:
|
573
|
+
imax *= 1e-3
|
574
|
+
iac[1] *= 1e-3
|
575
|
+
except NameError:
|
576
|
+
pass
|
577
|
+
ax.set_ylabel('Currents / kA')
|
548
578
|
else:
|
549
|
-
ax.
|
579
|
+
ax.set_ylabel('Currents / A')
|
550
580
|
|
551
581
|
for i, iph in zip(('ia', 'ib', 'ic'), istat):
|
552
|
-
ax.plot(
|
582
|
+
ax.plot(scData['time'], iph, label=i)
|
553
583
|
try:
|
554
584
|
ax.plot([pv[ipvmax]['tp']], [imax], '.')
|
585
|
+
ax.plot([iac[0]], [iac[1]], '.')
|
586
|
+
dtx = (scData['time'][-1]-scData['time'][0])/75
|
587
|
+
dy = imax/25
|
555
588
|
ax.annotate(f'Imax = {imax:.1f}',
|
556
589
|
xy=(pv[ipvmax]['tp'], imax),
|
557
|
-
xytext=(pv[ipvmax]['tp']+
|
590
|
+
xytext=(pv[ipvmax]['tp']+dtx, imax-dy))
|
591
|
+
dy = iac[1]/25
|
592
|
+
ax.annotate(f'I = {iac[1]:.1f}',
|
593
|
+
xy=iac,
|
594
|
+
xytext=(iac[0]+dtx, iac[1]-dy))
|
558
595
|
except NameError:
|
559
596
|
pass
|
560
|
-
|
597
|
+
if set_xlabel:
|
598
|
+
ax.set_xlabel('Time / s')
|
561
599
|
ax.legend()
|
562
600
|
|
563
|
-
|
564
|
-
|
565
|
-
|
601
|
+
|
602
|
+
def transientsc_torque(scData, ax=0, title='', set_xlabel=True):
|
603
|
+
"""plot transient shortcircuit torque vs time"""
|
604
|
+
if ax == 0:
|
605
|
+
ax = plt.gca()
|
606
|
+
if title:
|
607
|
+
ax.set_title(title)
|
566
608
|
pv = find_peaks_and_valleys(
|
567
|
-
np.array(
|
609
|
+
np.array(scData['time']), np.array(scData['torque']))
|
568
610
|
try:
|
569
611
|
tqmax = pv['yp'] if np.abs(pv['yp']) > np.abs(pv['yv']) else pv['yv']
|
570
612
|
tp = pv['tp'] if np.abs(pv['yp']) > np.abs(pv['yv']) else pv['tv']
|
571
|
-
|
613
|
+
tc = [pv['tpeaks'][-1], pv['peaks'][-1]]
|
614
|
+
except (KeyError, ValueError):
|
572
615
|
pass
|
573
|
-
torque = np.array(
|
616
|
+
torque = np.array(scData['torque'])
|
574
617
|
if np.max(torque) > 4000:
|
575
618
|
torque *= 1e-3
|
576
|
-
|
577
|
-
|
619
|
+
try:
|
620
|
+
tqmax *= 1e-3
|
621
|
+
tc[1] *= 1e-3
|
622
|
+
except NameError:
|
623
|
+
pass
|
624
|
+
ax.set_ylabel('Torque / kNm')
|
578
625
|
else:
|
579
|
-
ax.
|
626
|
+
ax.set_ylabel('Torque / Nm')
|
580
627
|
|
581
628
|
ax.grid(True)
|
582
|
-
ax.plot(
|
629
|
+
ax.plot(scData['time'], torque)
|
583
630
|
try:
|
584
631
|
ax.plot([tp], [tqmax], '.')
|
632
|
+
ax.plot([tc[0]], [tc[1]], '.')
|
633
|
+
dtx = (scData['time'][-1]-scData['time'][0])/75
|
634
|
+
dy = tqmax/25
|
585
635
|
ax.annotate(f'Tmax = {tqmax:.1f}',
|
586
636
|
xy=(tp, tqmax),
|
587
|
-
xytext=(tp+
|
637
|
+
xytext=(tp+dtx, tqmax-dy))
|
638
|
+
dy = tc[1]/25
|
639
|
+
ax.annotate(f'T = {tc[1]:.1f}',
|
640
|
+
xy=tc,
|
641
|
+
xytext=(tc[0]+dtx, tc[1]))
|
588
642
|
except NameError:
|
589
643
|
pass
|
590
|
-
|
644
|
+
if set_xlabel:
|
645
|
+
ax.set_xlabel('Time / s')
|
646
|
+
|
647
|
+
def transientsc(bch, title=''):
|
648
|
+
"""creates a transient short circuit plot"""
|
649
|
+
try:
|
650
|
+
scData = bch.scData
|
651
|
+
except AttributeError:
|
652
|
+
scData = bch
|
653
|
+
cols = 1
|
654
|
+
rows = 2
|
655
|
+
htitle = 1.5 if title else 0
|
656
|
+
fig, axs = plt.subplots(nrows=rows, ncols=cols, sharex=True,
|
657
|
+
figsize=(10, 3*rows + htitle))
|
658
|
+
if title:
|
659
|
+
fig.suptitle(title, fontsize=16)
|
591
660
|
|
661
|
+
transientsc_currents(scData, axs[0], set_xlabel=False)
|
662
|
+
transientsc_torque(scData, axs[1])
|
592
663
|
fig.tight_layout(h_pad=2)
|
593
664
|
if title:
|
594
665
|
fig.subplots_adjust(top=0.92)
|
@@ -602,24 +673,35 @@ def transientsc_demag(demag, magnet=0, title='', ax=0):
|
|
602
673
|
"""
|
603
674
|
if ax == 0:
|
604
675
|
ax = plt.gca()
|
605
|
-
|
606
|
-
|
607
|
-
|
608
|
-
|
609
|
-
|
676
|
+
if type(d) == list:
|
677
|
+
pos = [d['displ'] for d in demag if 'displ' in d]
|
678
|
+
hmax = [-d['H_max'] for d in demag if 'H_max' in d]
|
679
|
+
havg = [-d['H_av'] for d in demag if 'H_av' in d]
|
680
|
+
hclim = [-d['lim_hc'] for d in demag if 'lim_hc' in d][0]
|
681
|
+
else:
|
682
|
+
pos = demag['displ']
|
683
|
+
hmax = demag['H_max']
|
684
|
+
havg = demag['H_av']
|
685
|
+
hclim = demag['Hk']
|
610
686
|
ax.set_title('Transient Short Circuit Demagnetization [kA/m]')
|
611
687
|
ax.plot(pos, hmax,
|
612
688
|
label='H Max {:4.2f} kA/m'.format(max(hmax)))
|
613
689
|
ax.plot(pos, havg,
|
614
690
|
label='H Avg {:4.2f} kA/m'.format(max(havg)))
|
615
691
|
if len(hclim) > 1:
|
616
|
-
ax.plot([pos[0], pos[-1]], hclim, color='C3',
|
617
|
-
|
618
|
-
|
692
|
+
ax.plot([pos[0], pos[-1]], [hclim,hclim], color='C3',
|
693
|
+
linestyle='dashed',
|
694
|
+
label='Hc {:4.2f} kA/m'.format(hclim))
|
695
|
+
if 'Tmag' in demag:
|
696
|
+
Tmag = demag['Tmag']
|
697
|
+
elif magnet:
|
698
|
+
Tmag = magnet['Tmag']
|
699
|
+
else:
|
700
|
+
Tmag = ''
|
619
701
|
ax.set_xlabel('Rotor Position / °')
|
620
702
|
ax.grid(True)
|
621
|
-
if
|
622
|
-
ax.legend(title=f"Magnet Temperature {
|
703
|
+
if Tmag:
|
704
|
+
ax.legend(title=f"Magnet Temperature {Tmag}°C")
|
623
705
|
else:
|
624
706
|
ax.legend()
|
625
707
|
|
femagtools/plot/nc.py
CHANGED
@@ -130,6 +130,19 @@ def demag(isa, cmap=DEFAULT_CMAP, ax=0):
|
|
130
130
|
logger.info("Max demagnetization %f", np.max(demag))
|
131
131
|
|
132
132
|
|
133
|
+
def remanence(isa, cmap=DEFAULT_CMAP, ax=0):
|
134
|
+
"""plot remanence of NC/I7/ISA7 model
|
135
|
+
Args:
|
136
|
+
isa: Isa7/NC object
|
137
|
+
"""
|
138
|
+
emag = [e for e in isa.elements if e.is_magnet()]
|
139
|
+
rem = np.linalg.norm([e.remanence(isa.MAGN_TEMPERATURE)
|
140
|
+
for e in emag], axis=1)
|
141
|
+
_contour(ax, f'Remanence at {isa.MAGN_TEMPERATURE} °C (min {np.min(rem):.1f} T)',
|
142
|
+
emag, rem, 'T', cmap, isa)
|
143
|
+
logger.info("Min remanence %f", np.min(rem))
|
144
|
+
|
145
|
+
|
133
146
|
def demag_pos(isa, pos=-1, icur=-1, ibeta=-1, cmap=DEFAULT_CMAP, ax=0):
|
134
147
|
"""plot demag of NC/I7/ISA7 model at rotor position
|
135
148
|
Args:
|