femagtools 1.8.13__py3-none-any.whl → 1.8.15__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/bch.py +36 -9
- femagtools/femag.py +8 -1
- femagtools/fsl.py +31 -37
- femagtools/isa7.py +16 -0
- femagtools/job.py +9 -0
- femagtools/machine/__init__.py +7 -38
- femagtools/machine/afpm.py +12 -2
- femagtools/machine/effloss.py +7 -8
- femagtools/machine/im.py +57 -26
- femagtools/machine/pm.py +2 -1
- femagtools/machine/sizing.py +92 -7
- femagtools/machine/sm.py +5 -1
- femagtools/machine/utils.py +37 -14
- femagtools/multiproc.py +6 -0
- femagtools/parstudy.py +1 -1
- femagtools/plot/wdg.py +26 -5
- femagtools/templates/FE-losses.mako +0 -3
- femagtools/templates/ec-rotorbar.mako +1 -2
- femagtools/templates/ld_lq_fast.mako +1 -1
- femagtools/templates/mesh-airgap.mako +0 -1
- femagtools/templates/noloadflux-rot.mako +5 -32
- femagtools/templates/statorRing.mako +1 -1
- femagtools/utils.py +5 -1
- femagtools/windings.py +32 -14
- {femagtools-1.8.13.dist-info → femagtools-1.8.15.dist-info}/METADATA +31 -2
- {femagtools-1.8.13.dist-info → femagtools-1.8.15.dist-info}/RECORD +34 -35
- {femagtools-1.8.13.dist-info → femagtools-1.8.15.dist-info}/WHEEL +1 -1
- femagtools-1.8.15.dist-info/licenses/LICENSE +26 -0
- tests/test_femag.py +1 -1
- tests/test_fsl.py +5 -5
- tests/test_windings.py +11 -0
- femagtools/templates/rotor_winding_ks2.mako +0 -44
- femagtools/templates/rotor_winding_ks2_ecSimulation.mako +0 -44
- {femagtools-1.8.13.dist-info → femagtools-1.8.15.dist-info}/entry_points.txt +0 -0
- {femagtools-1.8.13.dist-info → femagtools-1.8.15.dist-info}/top_level.txt +0 -0
femagtools/machine/im.py
CHANGED
@@ -119,7 +119,6 @@ class InductionMachine(Component):
|
|
119
119
|
if 'u1type' in parameters:
|
120
120
|
self.u1ref = self.u1type
|
121
121
|
if hasattr(self, 'f1ref'):
|
122
|
-
#self.wref = 2*np.pi*self.f1ref[0]
|
123
122
|
self.wref = 2*np.pi*self.f1ref
|
124
123
|
if hasattr(self, 'u1ref'):
|
125
124
|
self.psiref = self.u1ref/self.wref
|
@@ -522,9 +521,10 @@ class InductionMachine(Component):
|
|
522
521
|
wmrange = sorted([0, wmType, wmPullout, wmMax])
|
523
522
|
elif wmMax < wmType:
|
524
523
|
wmrange = sorted([0, wmMax])
|
524
|
+
elif wmType<0 or wmPullout<0 or wmMax<0:
|
525
|
+
wmrange = sorted([1, abs(min(wmMax,wmType, wmPullout)), abs(max(wmMax,wmType, wmPullout))])
|
525
526
|
else:
|
526
527
|
wmrange = sorted([0, wmType, wmMax])
|
527
|
-
|
528
528
|
logger.info("Speed range %s", wmrange)
|
529
529
|
wmlin = []
|
530
530
|
dw = 0
|
@@ -604,6 +604,7 @@ class InductionMachine(Component):
|
|
604
604
|
r['eta'] += (pmech[i:]/(p1[i:])).tolist()
|
605
605
|
else:
|
606
606
|
r['eta'] += (p1[i:]/pmech[i:]).tolist()
|
607
|
+
|
607
608
|
return r
|
608
609
|
|
609
610
|
|
@@ -660,7 +661,7 @@ def parident(workdir, engine, f1, u1, wdgcon,
|
|
660
661
|
num_steps)]
|
661
662
|
else:
|
662
663
|
i1tab = np.linspace(i1min, i1max, num_steps).tolist()
|
663
|
-
|
664
|
+
|
664
665
|
m = copy.deepcopy(machine)
|
665
666
|
Q2 = m['rotor']['num_slots']
|
666
667
|
noloadsim = dict(
|
@@ -668,7 +669,7 @@ def parident(workdir, engine, f1, u1, wdgcon,
|
|
668
669
|
curvec=i1tab,
|
669
670
|
num_par_wdgs=machine[wdgk].get('num_par_wdgs', 1),
|
670
671
|
Q2=Q2)
|
671
|
-
|
672
|
+
|
672
673
|
da1 = m['bore_diam']
|
673
674
|
ag = m['airgap']
|
674
675
|
# do not create airgap nodechains automatically
|
@@ -679,11 +680,11 @@ def parident(workdir, engine, f1, u1, wdgcon,
|
|
679
680
|
m[wdgk].pop('resistance')
|
680
681
|
except KeyError:
|
681
682
|
pass
|
682
|
-
|
683
|
+
|
683
684
|
parstudy = femagtools.parstudy.ParameterStudy(
|
684
685
|
workdir, condMat=condMat,
|
685
686
|
magnetizingCurves=magnetizingCurves, cmd=cmd)
|
686
|
-
|
687
|
+
|
687
688
|
builder = femagtools.fsl.Builder(kwargs.get('templatedirs', []))
|
688
689
|
model = femagtools.model.MachineModel(m)
|
689
690
|
# modelfiles = parstudy.setup_model(builder, model)
|
@@ -722,7 +723,7 @@ def parident(workdir, engine, f1, u1, wdgcon,
|
|
722
723
|
rotorbar['rotor'][k]['num_slots_gen'] = 1
|
723
724
|
rotorbar['rotor'][k]['zeroangle'] = 90-180/Q2
|
724
725
|
break
|
725
|
-
|
726
|
+
|
726
727
|
loadsim = dict( # not used
|
727
728
|
calculationMode="asyn_motor",
|
728
729
|
bar_len=bar_len,
|
@@ -740,7 +741,7 @@ def parident(workdir, engine, f1, u1, wdgcon,
|
|
740
741
|
task = job.add_task(_eval_noloadrot(pmod), extra_result_files)
|
741
742
|
logger.debug("Task %s noload workdir %s result files %s",
|
742
743
|
task.id, task.directory, task.extra_result_files)
|
743
|
-
# create model
|
744
|
+
# create model
|
744
745
|
for mc in parstudy.femag.copy_magnetizing_curves(
|
745
746
|
model,
|
746
747
|
dir=task.directory):
|
@@ -754,11 +755,10 @@ def parident(workdir, engine, f1, u1, wdgcon,
|
|
754
755
|
|
755
756
|
# ec simulation
|
756
757
|
barmodel = femagtools.model.MachineModel(rotorbar)
|
757
|
-
barmodel_new = barmodel
|
758
|
-
barmodel_new['stator']['ecSimulation']=1
|
759
758
|
extra_result_files = ['bar.dat']
|
760
759
|
r = (da1-ag)/2
|
761
|
-
task = job.add_task(_eval_ecsim())
|
760
|
+
#task = job.add_task(_eval_ecsim())
|
761
|
+
task = job.add_task(_eval_ecsim(), extra_result_files)
|
762
762
|
logger.debug("Task %s rotobar workdir %s result files %s",
|
763
763
|
task.id, task.directory, task.extra_result_files)
|
764
764
|
task.set_stateofproblem('mag_dynamic')
|
@@ -769,7 +769,7 @@ def parident(workdir, engine, f1, u1, wdgcon,
|
|
769
769
|
task.add_file(mc)
|
770
770
|
task.add_file(
|
771
771
|
'femag.fsl',
|
772
|
-
builder.create_model(
|
772
|
+
builder.create_model(barmodel,
|
773
773
|
condMat=parstudy.femag.condMat) +
|
774
774
|
builder.create_analysis(ecsim) +
|
775
775
|
['save_model("close")'])
|
@@ -795,10 +795,9 @@ def parident(workdir, engine, f1, u1, wdgcon,
|
|
795
795
|
logger.info('Started %s', status)
|
796
796
|
status = engine.join()
|
797
797
|
tend = time.time()
|
798
|
-
logger.info("
|
798
|
+
logger.info("Elapssed time %d s Status %s",
|
799
799
|
(tend-tstart), status)
|
800
800
|
if any([x != 'C' for x in status]):
|
801
|
-
logger.error("AC simulation failed with statuses: %s", status)
|
802
801
|
raise ValueError("AC simulation failed")
|
803
802
|
# collect results
|
804
803
|
results = [t.get_results() for t in job.tasks]
|
@@ -821,16 +820,17 @@ def parident(workdir, engine, f1, u1, wdgcon,
|
|
821
820
|
u1ref = u1ph
|
822
821
|
psiref = u1ref/w1
|
823
822
|
|
824
|
-
|
825
|
-
|
826
|
-
|
827
|
-
|
828
|
-
|
829
|
-
|
830
|
-
|
831
|
-
|
832
|
-
|
833
|
-
|
823
|
+
# def inoload(x, iml, ims, mexp):
|
824
|
+
# """return noload current"""
|
825
|
+
# return iml*x/psiref + ims*(x/psiref)**mexp
|
826
|
+
# fitp, cov = so.curve_fit(inoload, psihtab, i10tab, (1, 1, 1))
|
827
|
+
# iml, ims, mexp = fitp
|
828
|
+
# logger.info("iml, ims, mexp %g, %g, %g",
|
829
|
+
# iml, ims, mexp)
|
830
|
+
# i1tab.insert(0, 0)
|
831
|
+
# psi1_0.insert(0, 0)
|
832
|
+
# i1_0.insert(0, 0)
|
833
|
+
|
834
834
|
logger.info("psi1_0 %s", np.mean(psi1_0, axis=1))
|
835
835
|
logger.info("psih %s", psih)
|
836
836
|
logger.debug("psi1_0-psih %s", np.mean(psi1_0, axis=1)-psih)
|
@@ -851,7 +851,7 @@ def parident(workdir, engine, f1, u1, wdgcon,
|
|
851
851
|
hs = machine['stator'][slotmodel].get('slot_height',
|
852
852
|
0.33*(machine['outer_diam']-da1))
|
853
853
|
n = machine[wdgk]['num_wires']
|
854
|
-
if 'dia_wire' in machine[wdgk]:
|
854
|
+
if 'dia_wire' in machine[wdgk] and machine[wdgk].get('dia_wire', 1e-3) !=0:
|
855
855
|
aw = np.pi*machine[wdgk].get('dia_wire', 1e-3)**2/4
|
856
856
|
else: # wire diameter from slot area
|
857
857
|
aw = 0.75 * \
|
@@ -878,6 +878,7 @@ def parident(workdir, engine, f1, u1, wdgcon,
|
|
878
878
|
# kind='quadratic')(imref))
|
879
879
|
psihref = float(log_interp1d(i1tab, psih)(imref))
|
880
880
|
psi1ref = float(psi1(imref))
|
881
|
+
|
881
882
|
|
882
883
|
lh = psihref/imref
|
883
884
|
L1 = psi1ref/imref
|
@@ -908,8 +909,37 @@ def parident(workdir, engine, f1, u1, wdgcon,
|
|
908
909
|
# r2 = results[1]['r2']
|
909
910
|
# ls2 = results[1]['ls2']
|
910
911
|
pfe = results[2]['pfe1'][0]
|
912
|
+
|
913
|
+
end_ring_section = machine['rotor']['Aring']
|
914
|
+
bore_diam = machine['bore_diam']
|
915
|
+
for key, value in machine['rotor'].items():
|
916
|
+
if isinstance(value, dict) and 'slot_height' in value:
|
917
|
+
slot_height_rotor = value['slot_height']
|
918
|
+
break
|
919
|
+
if slot_height_rotor is not None:
|
920
|
+
rayon = (bore_diam / 2) - slot_height_rotor/2
|
921
|
+
end_ring_length = 2 * np.pi * rayon
|
922
|
+
else:
|
923
|
+
end_ring_length = 0
|
924
|
+
|
925
|
+
end_ring_volume = end_ring_section*end_ring_length
|
926
|
+
|
927
|
+
for material_info in condMat:
|
928
|
+
if material_info.get('name') == machine.get('rotor', {}).get('material'):
|
929
|
+
spmaweight_rotor = material_info.get('spmaweight')
|
930
|
+
break
|
931
|
+
else:
|
932
|
+
spmaweight_rotor = 0
|
933
|
+
end_ring_mass = end_ring_volume * spmaweight_rotor*1e3
|
934
|
+
|
911
935
|
rotor_mass = sum([results[2].get('conweight', 0),
|
912
936
|
results[2].get('lamweight', 0)])
|
937
|
+
logger.info('Conductor mass in rotor = %s',results[2].get('conweight', 0))
|
938
|
+
logger.info('Lamination mass in rotor = %s',results[2].get('lamweight', 0))
|
939
|
+
logger.info('Rotor mass without end-ring = %s',rotor_mass)
|
940
|
+
rotor_mass += 2*end_ring_mass
|
941
|
+
logger.info('One end-ring mass = %s',end_ring_mass)
|
942
|
+
logger.info('Total rotor mass = %s',rotor_mass)
|
913
943
|
|
914
944
|
n = machine[wdgk]['num_wires']
|
915
945
|
g = loadsim['num_par_wdgs']
|
@@ -977,12 +1007,13 @@ class _eval_noloadrot():
|
|
977
1007
|
i0 = np.linalg.norm(
|
978
1008
|
femagtools.machine.T(0).dot(ire.T),
|
979
1009
|
axis=0)/np.sqrt(2)
|
1010
|
+
|
980
1011
|
|
981
1012
|
psi0 = np.array([np.linalg.norm(
|
982
1013
|
femagtools.machine.T(0).dot(psire[:, k, :].T),
|
983
1014
|
axis=0)/np.sqrt(2)
|
984
1015
|
for k in range(ncurs)])
|
985
|
-
|
1016
|
+
|
986
1017
|
# matrix (i x j x k) of curr, rotor pos, angle
|
987
1018
|
Bamp = [[femagtools.airgap.fft(bags[:, 0], b, self.pmod)['Bamp']
|
988
1019
|
for b in bags.T[1:]]
|
femagtools/machine/pm.py
CHANGED
femagtools/machine/sizing.py
CHANGED
@@ -381,7 +381,7 @@ def get_stator_dimensions(par, slots=[]):
|
|
381
381
|
Da2 = Da1-2*airgap
|
382
382
|
r = dict(
|
383
383
|
lfe=round(lfe, 3),
|
384
|
-
Dy1=round(Dy1, 3),
|
384
|
+
Dy1=round(Dy1, 3),
|
385
385
|
Da1=round(Da1, 4),
|
386
386
|
Da2=round(Da2, 4),
|
387
387
|
ans=round(ans, 6),
|
@@ -546,9 +546,10 @@ def get_interior_magnet_dimensions(I1, N, kw, psi1, lfe, Da2, par):
|
|
546
546
|
iron_shape=Da2/2))
|
547
547
|
|
548
548
|
|
549
|
-
def get_im_rotor_dimensions(A, Da2, psi1, lfe, par, rtype='
|
549
|
+
def get_im_rotor_dimensions(A, Da2, psi1, lfe, par, rtype='statorRotor3'):
|
550
550
|
r = dict()
|
551
551
|
r['Da2'] = Da2
|
552
|
+
r['rotorfilfact']=0.95
|
552
553
|
if 'Q2' not in par:
|
553
554
|
r['num_slots'] = _rotor_slots(par['Q1'], par['p'])[0]
|
554
555
|
else:
|
@@ -568,15 +569,42 @@ def get_im_rotor_dimensions(A, Da2, psi1, lfe, par, rtype='rotorKs2'):
|
|
568
569
|
taup = np.pi * Da2/(2*par['p'])
|
569
570
|
hyr = psi1/2/lfe*par['By']
|
570
571
|
r['Dy2'] = round(Da2 - 2*hr - 2*hyr, 4)
|
571
|
-
logger.info("Dy2 %f Da2 %f hys %f hr %f",
|
572
|
-
r['Dy2']*1e3, Da2*1e3, hyr*1e3, hr*1e3)
|
573
572
|
slotwidth = 1e-3
|
574
573
|
Q2 = r['num_slots']
|
575
574
|
r1 = wr/2-slotwidth
|
576
575
|
r2 = (Da2/2-hr-hs1)*np.tan(alfar)
|
576
|
+
|
577
577
|
logger.info("Dy2 %f Da2 %f hys %f hr %f",
|
578
578
|
r['Dy2']*1e3, Da2*1e3, hyr*1e3, hr*1e3)
|
579
|
-
|
579
|
+
|
580
|
+
# End-ring calculation
|
581
|
+
Ir_total_estimated = A * np.pi * Da2 / (2 * par['p'])
|
582
|
+
Ibar_eff = Ir_total_estimated / r['num_slots']
|
583
|
+
|
584
|
+
if r['num_slots'] > 0:
|
585
|
+
sin_term = np.sin(np.pi / r['num_slots'])
|
586
|
+
if sin_term != 0:
|
587
|
+
Iring_max_eff = Ibar_eff / (2 * sin_term)
|
588
|
+
else:
|
589
|
+
Iring_max_eff = 0
|
590
|
+
else:
|
591
|
+
Iring_max_eff = 0
|
592
|
+
if 'Jring' not in par:
|
593
|
+
par['Jring'] = par.get('J', 4e6)
|
594
|
+
|
595
|
+
Jring = par['Jring']
|
596
|
+
|
597
|
+
if 'kfilling_ring' not in par:
|
598
|
+
par['kfilling_ring'] = 1.0
|
599
|
+
|
600
|
+
kfilling_ring = par['kfilling_ring']
|
601
|
+
|
602
|
+
if Jring * kfilling_ring > 0:
|
603
|
+
Aring = Iring_max_eff / (Jring * kfilling_ring)
|
604
|
+
else:
|
605
|
+
Aring = 0
|
606
|
+
|
607
|
+
"""if rtype == 'statorRotor3':
|
580
608
|
r['statorRotor3'] = dict(
|
581
609
|
slot_width=slotwidth,
|
582
610
|
tooth_width=round(wt, 4),
|
@@ -589,6 +617,18 @@ def get_im_rotor_dimensions(A, Da2, psi1, lfe, par, rtype='rotorKs2'):
|
|
589
617
|
wedge_width1=0,
|
590
618
|
wedge_width2=0,
|
591
619
|
middle_line=0)
|
620
|
+
r['statorRotor3'] = dict(
|
621
|
+
slot_width=1e-3,
|
622
|
+
tooth_width=0,
|
623
|
+
slot_height=0.0157,
|
624
|
+
slot_top_sh=0,
|
625
|
+
slot_h1=0.5e-3,
|
626
|
+
slot_h2=2.2e-3,
|
627
|
+
slot_r1=2.2e-3,
|
628
|
+
slot_r2=1e-3,
|
629
|
+
wedge_width1=1e-3,
|
630
|
+
wedge_width2=0,
|
631
|
+
middle_line=0)
|
592
632
|
elif rtype == 'rotorAsyn':
|
593
633
|
r['rotorAsyn'] = dict(
|
594
634
|
slot_bs2=0.1e-3,
|
@@ -612,8 +652,52 @@ def get_im_rotor_dimensions(A, Da2, psi1, lfe, par, rtype='rotorKs2'):
|
|
612
652
|
slot_h2=0,
|
613
653
|
slot_r1=1e-3, # r1,
|
614
654
|
slot_r2=1e-3, # r2,
|
655
|
+
middle_line=0)"""
|
656
|
+
|
657
|
+
all_rotor_types = {}
|
658
|
+
|
659
|
+
all_rotor_types['statorRotor3'] = dict(
|
660
|
+
slot_width=slotwidth,
|
661
|
+
tooth_width=round(wt, 4),
|
662
|
+
slot_height=round(hr+r2, 4),
|
663
|
+
slot_top_sh=1.0,
|
664
|
+
slot_h1=round(hs1, 4),
|
665
|
+
slot_h2=round(hs1+r1, 4),
|
666
|
+
slot_r1=round(r1, 4),
|
667
|
+
slot_r2=round(r2),
|
668
|
+
wedge_width1=0,
|
669
|
+
wedge_width2=0,
|
615
670
|
middle_line=0)
|
616
671
|
|
672
|
+
all_rotor_types['rotorAsyn'] = dict(
|
673
|
+
slot_bs2=0.1e-3,
|
674
|
+
slot_hs2=0.5e-3,
|
675
|
+
slot_b32=0.0,
|
676
|
+
slot_h32=0.0,
|
677
|
+
slot_b42=0.0,
|
678
|
+
slot_h42=0.0,
|
679
|
+
slot_b52=round(wr, 4),
|
680
|
+
slot_b62=3e-3,
|
681
|
+
slot_h52=2.5e-3,
|
682
|
+
slot_h62=round(hr, 4),
|
683
|
+
slot_h72=2e-3
|
684
|
+
)
|
685
|
+
|
686
|
+
all_rotor_types['rotorKs2'] = dict(
|
687
|
+
slot_angle=round(2 * alfar * 180 / np.pi, 2),
|
688
|
+
slot_height=round(hr + r1 + r2, 4),
|
689
|
+
slot_topwidth=round(wr, 4),
|
690
|
+
slot_width=slotwidth,
|
691
|
+
slot_h1=hs1,
|
692
|
+
slot_h2=0,
|
693
|
+
slot_r1=1e-3, # r1,
|
694
|
+
slot_r2=1e-3, # r2,
|
695
|
+
middle_line=0
|
696
|
+
)
|
697
|
+
|
698
|
+
|
699
|
+
r.update(all_rotor_types)
|
700
|
+
r['Aring'] = Aring
|
617
701
|
return r
|
618
702
|
|
619
703
|
|
@@ -949,7 +1033,7 @@ def im(pnom: float, speed: float, p: int, **kwargs) -> dict:
|
|
949
1033
|
slots = []
|
950
1034
|
r = get_stator_dimensions(par, slots=slots)
|
951
1035
|
# rotor parameters
|
952
|
-
rtype = kwargs.get('rtype', '
|
1036
|
+
rtype = kwargs.get('rtype', 'statorRotor3')
|
953
1037
|
r['rotor'] = get_im_rotor_dimensions(
|
954
1038
|
par['cos_phi']*r['A'], r['Da2'], r['psi1'], r['lfe'],
|
955
1039
|
par, rtype=rtype)
|
@@ -987,12 +1071,13 @@ def eesm(pnom: float, speed: float, p: int, **kwargs) -> dict:
|
|
987
1071
|
r['name'] = f"EESM-{r['poles']}"
|
988
1072
|
return r
|
989
1073
|
|
1074
|
+
|
990
1075
|
if __name__ == "__main__":
|
991
1076
|
# sizing example with SPM
|
992
1077
|
pnom = 10e3 # shaft power in W
|
993
1078
|
speed = 4400/60 # speed in 1/s
|
994
1079
|
p = 4 # number of pole pairs
|
995
|
-
udc = 600 # DC voltage in V
|
1080
|
+
udc = 600 # DC voltage in V
|
996
1081
|
|
997
1082
|
r = spm(pnom, speed, p, udc=udc)
|
998
1083
|
|
femagtools/machine/sm.py
CHANGED
@@ -7,7 +7,7 @@ import pathlib
|
|
7
7
|
import numpy as np
|
8
8
|
import scipy.optimize as so
|
9
9
|
import scipy.interpolate as ip
|
10
|
-
from .utils import skin_resistance, wdg_resistance, betai1, iqd, KTH, create_wdg
|
10
|
+
from .utils import skin_resistance, wdg_resistance, betai1, iqd, KTH, create_wdg, loss_models
|
11
11
|
from .. import parstudy, windings
|
12
12
|
import femagtools.bch
|
13
13
|
|
@@ -50,6 +50,7 @@ def parident(workdir, engine, machine,
|
|
50
50
|
beta_max: maximal current angle (default 0°)
|
51
51
|
num_move_steps: number of move steps
|
52
52
|
cmd: femag command (default None, platform executable)
|
53
|
+
feloss: jordan, steinmetz, modified steinmetz, bertotti
|
53
54
|
"""
|
54
55
|
cmd = kwargs.get('cmd', None)
|
55
56
|
|
@@ -125,6 +126,9 @@ def parident(workdir, engine, machine,
|
|
125
126
|
period_frac=kwargs.get('period_frac', 6),
|
126
127
|
speed=kwargs.get('speed', 50))
|
127
128
|
|
129
|
+
if kwargs.get("feloss", 0):
|
130
|
+
simulation["feloss"] = kwargs["feloss"]
|
131
|
+
machine["calc_fe_loss"] = loss_models[kwargs["feloss"].lower()]
|
128
132
|
###self.cleanup() # remove previously created files in workdir
|
129
133
|
results = parvar(parvardef, machine, simulation, engine)
|
130
134
|
b = results['f'][-1]
|
femagtools/machine/utils.py
CHANGED
@@ -8,9 +8,16 @@ import numpy.linalg as la
|
|
8
8
|
import scipy.interpolate as ip
|
9
9
|
import logging
|
10
10
|
from .. import parstudy, windings
|
11
|
+
from ..model import MachineModel
|
11
12
|
|
12
13
|
logger = logging.getLogger(__name__)
|
13
14
|
|
15
|
+
loss_models = {
|
16
|
+
"modified steinmetz": 10,
|
17
|
+
"bertotti": 11,
|
18
|
+
"jordan": 1,
|
19
|
+
"steinmetz": 1
|
20
|
+
}
|
14
21
|
|
15
22
|
def K(d):
|
16
23
|
"""space phasor transformation matrix
|
@@ -369,6 +376,7 @@ def dqparident(workdir, engine, temp, machine,
|
|
369
376
|
period_frac: (int) fraction of rotating angle (default 6)
|
370
377
|
dqtype: (str) type of identification: 'ldq' (default), 'psidq'
|
371
378
|
cmd: femag executable
|
379
|
+
feloss: jordan, steinmetz, modified steinmetz, bertotti
|
372
380
|
"""
|
373
381
|
import pathlib
|
374
382
|
|
@@ -390,21 +398,25 @@ def dqparident(workdir, engine, temp, machine,
|
|
390
398
|
else:
|
391
399
|
fcu = 0.42
|
392
400
|
|
393
|
-
try:
|
394
|
-
from ..model import MachineModel
|
401
|
+
try:
|
395
402
|
wdg = create_wdg(machine)
|
396
|
-
Q1 = wdg.Q
|
397
|
-
model = MachineModel(machine)
|
398
|
-
Jmax = 30e6 # max current density in A/m2
|
399
|
-
Acu = fcu*model.slot_area() # approx. copper area of one slot
|
400
|
-
i1_max = round(g*Acu/wdg.l/N*Jmax/10)*10
|
401
403
|
except KeyError:
|
402
|
-
|
403
|
-
|
404
|
+
pass
|
405
|
+
model = MachineModel(machine)
|
406
|
+
if kwargs.get('i1_max', 0):
|
404
407
|
i1_max = kwargs['i1_max']
|
408
|
+
else:
|
409
|
+
try: # calc basic dimensions if not fsl or dxf model
|
410
|
+
Jmax = 30e6 # max current density in A/m2
|
411
|
+
Acu = fcu*model.slot_area() # approx. copper area of one slot
|
412
|
+
i1_max = round(g*Acu/wdg.l/N*Jmax/10)*10
|
413
|
+
except KeyError:
|
414
|
+
raise ValueError('i1_max missing')
|
405
415
|
|
406
416
|
# winding resistance
|
407
417
|
try:
|
418
|
+
da1 = machine['bore_diam']
|
419
|
+
hs = model.slot_height()
|
408
420
|
if 'wire_gauge' in machine[wdgk]:
|
409
421
|
aw = machine[wdgk]['wire_gauge']
|
410
422
|
elif 'dia_wire' in machine[wdgk]:
|
@@ -412,10 +424,10 @@ def dqparident(workdir, engine, temp, machine,
|
|
412
424
|
elif ('wire_width' in machine[wdgk]) and ('wire_height' in machine[wdgk]):
|
413
425
|
aw = machine[wdgk]['wire_width']*machine[wdgk]['wire_height']
|
414
426
|
else: # wire diameter from slot area
|
415
|
-
|
427
|
+
Q1 = wdg.Q
|
416
428
|
aw = 0.75 * fcu * np.pi*da1*hs/Q1/wdg.l/N
|
417
|
-
r1 = wdg_resistance(wdg, N, g, aw, da1, hs, lfe)
|
418
|
-
except (NameError, KeyError):
|
429
|
+
r1 = float(wdg_resistance(wdg, N, g, aw, da1, hs, lfe))
|
430
|
+
except (NameError, KeyError) as ex:
|
419
431
|
r1 = 0 # cannot calc winding resistance
|
420
432
|
|
421
433
|
n = len(temp)
|
@@ -483,6 +495,10 @@ def dqparident(workdir, engine, temp, machine,
|
|
483
495
|
speed=kwargs.get('speed', defspeed),
|
484
496
|
period_frac=period_frac)
|
485
497
|
|
498
|
+
if kwargs.get("feloss", 0):
|
499
|
+
simulation["feloss"] = kwargs["feloss"]
|
500
|
+
machine["calc_fe_loss"] = loss_models[kwargs["feloss"].lower()]
|
501
|
+
|
486
502
|
# TODO: cleanup() # remove previously created files in workdir
|
487
503
|
# start calculation
|
488
504
|
results = parvar(parvardef, machine, simulation, engine)
|
@@ -490,7 +506,6 @@ def dqparident(workdir, engine, temp, machine,
|
|
490
506
|
if 'poles' not in machine: # dxf model?
|
491
507
|
machine['poles'] = 2*results['f'][0]['machine']['p']
|
492
508
|
da1 = 2*results['f'][0]['machine']['fc_radius']
|
493
|
-
wdg = create_wdg(machine)
|
494
509
|
if 'bore_diam' in machine:
|
495
510
|
da1 = machine['bore_diam']
|
496
511
|
ls1 = 0
|
@@ -506,6 +521,14 @@ def dqparident(workdir, engine, temp, machine,
|
|
506
521
|
except KeyError:
|
507
522
|
rotor_mass = 0 # need femag classic > rel-9.3.x-48-gca42bbd0
|
508
523
|
|
524
|
+
if rotor_mass == 0:
|
525
|
+
try:
|
526
|
+
nc = parvar.femag.read_nc()
|
527
|
+
rotor_mass = float(sum(nc.get_mass()[1].values()))
|
528
|
+
logger.info("rotor mass from nc-file: %.1f kg", rotor_mass)
|
529
|
+
except StopIteration:
|
530
|
+
logger.warning("Could not read nc-file. Setting rotor_mass = 0!")
|
531
|
+
|
509
532
|
dq = []
|
510
533
|
if dqtype == 'ldq':
|
511
534
|
for i in range(0, len(results['f']), 2):
|
@@ -585,7 +608,7 @@ def dqparident(workdir, engine, temp, machine,
|
|
585
608
|
# diameter of wires
|
586
609
|
aw = fcu*asl/Q1/nlayers/N
|
587
610
|
hs = asl/(np.pi*da1/3)
|
588
|
-
dqpars['r1'] = wdg_resistance(wdg, N, g, aw, da1, hs, lfe)
|
611
|
+
dqpars['r1'] = float(wdg_resistance(wdg, N, g, aw, da1, hs, lfe))
|
589
612
|
|
590
613
|
if 'current_angles' in results['f'][0]:
|
591
614
|
dqpars['current_angles'] = results['f'][0]['current_angles']
|
femagtools/multiproc.py
CHANGED
@@ -235,6 +235,12 @@ class Engine:
|
|
235
235
|
self.pool = None # garbage collector deletes threads
|
236
236
|
return status
|
237
237
|
|
238
|
+
def read_nc(self):
|
239
|
+
"""return a generator object of nc list"""
|
240
|
+
for t in self.job.tasks:
|
241
|
+
yield t.read_nc()
|
242
|
+
return None
|
243
|
+
|
238
244
|
def stopThreads(self):
|
239
245
|
""" stop all running treads
|
240
246
|
"""
|
femagtools/parstudy.py
CHANGED
@@ -310,7 +310,7 @@ class ParameterStudy(object):
|
|
310
310
|
set_magnet_properties(model, fea, self.femag.magnets)
|
311
311
|
task.add_file(
|
312
312
|
'femag.fsl',
|
313
|
-
builder.create_model(model, self.femag.magnets) if not data_model_created else [] +
|
313
|
+
(builder.create_model(model, self.femag.magnets) if not data_model_created else []) +
|
314
314
|
builder.create_analysis(fea) +
|
315
315
|
['save_model("close")'],
|
316
316
|
append=data_model_created # model already created, append fsl
|
femagtools/plot/wdg.py
CHANGED
@@ -7,6 +7,7 @@
|
|
7
7
|
"""
|
8
8
|
import numpy as np
|
9
9
|
import matplotlib.pyplot as plt
|
10
|
+
import logging
|
10
11
|
|
11
12
|
|
12
13
|
def currdist(wdg, title='', k='all', phi=0, ax=0):
|
@@ -81,13 +82,13 @@ def mmf_fft(f, title='', mmfmin=1e-2, ax=0):
|
|
81
82
|
pass
|
82
83
|
|
83
84
|
|
84
|
-
def zoneplan(wdg, write_title=True,
|
85
|
+
def zoneplan(wdg, write_title=True, ax=0, max_slots=0):
|
85
86
|
"""plot zone plan of winding wdg"""
|
86
87
|
from matplotlib.patches import Rectangle
|
87
88
|
upper, lower = wdg.zoneplan()
|
88
89
|
Qb = len([n for l in upper for n in l])
|
89
90
|
if max_slots:
|
90
|
-
Qb = max_slots
|
91
|
+
Qb = min(max_slots, Qb)
|
91
92
|
from femagtools.windings import coil_color
|
92
93
|
h = 0.5
|
93
94
|
w = 1
|
@@ -171,7 +172,7 @@ def winding_factors(wdg, n=8, ax=0):
|
|
171
172
|
pass
|
172
173
|
|
173
174
|
|
174
|
-
def winding(wdg, ax=0):
|
175
|
+
def winding(wdg, ax=0, max_slots=0):
|
175
176
|
"""plot coils of windings wdg"""
|
176
177
|
from matplotlib.patches import Rectangle
|
177
178
|
from matplotlib.lines import Line2D
|
@@ -186,12 +187,16 @@ def winding(wdg, ax=0):
|
|
186
187
|
if ax == 0:
|
187
188
|
ax = plt.gca()
|
188
189
|
z = wdg.zoneplan()
|
190
|
+
z0 = z[0] if len(z[0]) >= len(z[1]) else z[1]
|
191
|
+
Qb = sum([len(l) for l in z0])
|
192
|
+
if max_slots:
|
193
|
+
Qb = min(max_slots, Qb)
|
189
194
|
xoff = 0
|
190
195
|
if z[-1]:
|
191
196
|
xoff = 0.75
|
192
197
|
yd = dslot*wdg.yd
|
193
198
|
mh = 2*coil_height/yd
|
194
|
-
slots = sorted([abs(n) for m in z[0] for n in m])
|
199
|
+
slots = sorted([abs(n) for m in z[0] for n in m])[:Qb]
|
195
200
|
smax = slots[-1]*dslot
|
196
201
|
for n in slots: # draw slots and lamination
|
197
202
|
x = n*dslot
|
@@ -204,6 +209,15 @@ def winding(wdg, ax=0):
|
|
204
209
|
backgroundcolor="white",
|
205
210
|
bbox=dict(boxstyle='circle,pad=0', fc="white", lw=0))
|
206
211
|
|
212
|
+
# colors in slots
|
213
|
+
csl = [['']*(Qb+1), ['']*(Qb+1)]
|
214
|
+
for i, layer in enumerate(z):
|
215
|
+
for m, mslots in enumerate(layer):
|
216
|
+
for k in mslots:
|
217
|
+
if abs(k) > Qb:
|
218
|
+
continue
|
219
|
+
csl[i][abs(k)-1] = coil_color[m]
|
220
|
+
|
207
221
|
nl = 2 if z[1] else 1
|
208
222
|
line_thickness = [0.6, 1.2]
|
209
223
|
for i, layer in enumerate(z):
|
@@ -213,8 +227,9 @@ def winding(wdg, ax=0):
|
|
213
227
|
d = 1
|
214
228
|
for m, mslots in enumerate(layer):
|
215
229
|
for k in mslots:
|
230
|
+
if abs(k) > Qb:
|
231
|
+
continue
|
216
232
|
x = abs(k) * dslot + b
|
217
|
-
kcoil = (abs(k)-1)//wdg.yd
|
218
233
|
xpoints = []
|
219
234
|
ypoints = []
|
220
235
|
if nl == 2:
|
@@ -224,6 +239,12 @@ def winding(wdg, ax=0):
|
|
224
239
|
d = 1 if i == 1 else 0
|
225
240
|
else:
|
226
241
|
d = 0 if k > 0 else 1
|
242
|
+
if abs(k) > 1:
|
243
|
+
if csl[0][abs(k)-2] == coil_color[m]:
|
244
|
+
d = 1
|
245
|
+
csl[0][abs(k)-1] = ''
|
246
|
+
else:
|
247
|
+
d = 0
|
227
248
|
|
228
249
|
if direction[d] == 'right':
|
229
250
|
# first layer, positive dir or neg. dir and 2-layers:
|
@@ -6,8 +6,7 @@ muer = 1
|
|
6
6
|
rel = 100
|
7
7
|
cur = {1, 0}
|
8
8
|
sigma1, sigma2 = get_dev_data( "cond_conduct" )
|
9
|
-
|
10
|
-
rotorbar = def_new_bar(xcoil,ycoil, "green", "U", cur[1],cur[2], "wi", -- xcoil and ycoil defined in rotor_winding_ks2.mako
|
9
|
+
rotorbar = def_new_bar(xb,yb, "green", "U", cur[1],cur[2], "wi",
|
11
10
|
sigma2, muer, rel, "polar", 0, 0)
|
12
11
|
Abar = get_sreg_data("area",rotorbar)
|
13
12
|
|
@@ -19,7 +19,6 @@ if not airgap_created then
|
|
19
19
|
end
|
20
20
|
x1, y1 = pr2c(r1, alfa)
|
21
21
|
n = math.floor(m.fc_radius*alfa/agndst + 1.5)
|
22
|
-
n = n/10 -- Otherwise stacking mesh error TODO find a better formula
|
23
22
|
nc_circle_m(r1, 0, x1, y1, 0.0, 0.0, n)
|
24
23
|
if(m.npols_gen == m.num_poles) then
|
25
24
|
nc_circle_m(x1, y1, r1, 0, 0.0, 0.0, n)
|