Skip to content

Commit

Permalink
bulk commit - sorry future self
Browse files Browse the repository at this point in the history
  • Loading branch information
askprash committed Sep 30, 2024
1 parent 871f381 commit ab51540
Show file tree
Hide file tree
Showing 4 changed files with 352 additions and 2 deletions.
276 changes: 276 additions & 0 deletions src/propsys/PMSM.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,276 @@
module ElectricMachine

abstract type AbstractElectricMachine end
abstract type AbstractMagnets end

const μ₀ = 1.25663706127e-6 #N⋅A⁻² https://physics.nist.gov/cgi-bin/cuu/Value?mu0

@kwdef mutable struct Motor
rotor::RotorGeometry = RotorGeometry()
stator::StatorGeometry = StatorGeometry()
teeth::Teeth = Teeth()
magnet::PermanentMagnet = PermanentMagnet()
windings::Windings = Windings()

"""Design shaft power [W]"""
P_design::Float64 = 1e6
"""Angular velocity [rad/s]"""
Ω::Float64 = 10e3
"""Slots per pole [-]"""
Nsp::Int = 3
"""Pole pairs [-]"""
N_pole_pairs::Int = 8
"""Max rotor tip speed [m/s]"""
U_max::Float64 = 200.0
"""Saturation Flux [Wb/m²]"""
B_sat::Float64 = 1.8
"""Maximum Current Density [A/m²]"""
J_max::Float64= 1e6
"""Max ratio to saturation"""
rB_sat::Float64 = 0.98
"""Stack length [m]"""
l::Float64 = 1.0
"""Thickness of air gap [m]"""
airgap_thickness::Float64 = 2e-3
"""Pole pairs [-]"""
p::Int = 8
"""Eddy current loss coefficient [W/lbm/Hz²/T²]"""
kₑ::Float64 = 32.183e-6 #https://arc.aiaa.org/doi/10.2514/6.2018-5026
"""Hysteresis loss coefficient [W/lbm/Hz]"""
kₕ::Float64 = 10.664e-3 #https://arc.aiaa.org/doi/10.2514/6.2018-5026

"""Mass of machine [kg]"""
mass::Float64 = 0.0
end

@kwdef struct PermanentMagnet <: AbstractMagnets
"""Magnet thickness [m]"""
thickness::Float64 = 20e-3
"""Magnet Density [kg/m⁻³]"""
density::Float64 = 7501.0 #Neodymium magnets
"""Magnetization constant [A/m]"""
M::Float64 = 8.604e5
"""Mass of magnets [kg]"""
mass::Float64 = 0.0
end

@kwdef struct Windings
"""Winding conductor material"""
conductor::Conductor
"""Winding insulator material"""
insulator::Insulator
"""Number of turns [-]"""
N_turns::Int = 1
"""Wire area [m²]"""
A_wire::Float64 = 0.518e-6 #20AWG
"""Winding temperature [K]"""
T::Float64 = 273.15 + 90
"""Packing factor [-]"""
kpf::Float64 = 0.35
"""Mass of windings [kg]"""
mass::Float64 = 0.0
end

@kwdef mutable struct Teeth
"""Tooth width [m]"""
width::Float64 = 0.005
"""Tooth thickness [m]"""
thickness::Float64 = 0.02
"""Inner radius [m]"""
Ri::Float64 = 0.01
"""Material"""
material::AbstractMaterial
"""Mass [kg]"""
mass::Float64 = 0.0
end

@kwdef mutable struct RotorGeometry
"""Rotor thickness [m]"""
thickness::Float64 = 0.01
"""Inner radius [m]"""
Ri::Float64 = 0.01
"""Outer radius [m]"""
Ro::Float64 = 0.02
"""Material"""
material::AbstractMaterial
"""Mass [kg]"""
mass::Float64 = 0.0
end

@kwdef mutable struct StatorGeometry
"""Stator thickness [m]"""
thickness::Float64 = 0.01
"""Inner radius [m]"""
Ri::Float64 = 0.01
"""Outer radius [m]"""
Ro::Float64 = 0.02
"""Material"""
material::AbstractMaterial
"""Mass [kg]"""
mass::Float64 = 0.0
end

@kwdef mutable struct ShaftGeometry
"""Inner Radius [m]"""
Ri::Float64 = 0.01
"""Outer Radius [m]"""
Ro::Float64 = 0.01
"""Overhang fraction of shaft [-]"""
l_extra::Float64 = 1.2
"""Material"""
material::AbstractMaterial
"""Mass [kg]"""
mass::Float64 = 0.0
end
# Layout:
#
# +-------------------------------+ <----------------+
# | Stator back Iron | }ts |
# | +--+ +--+ +--+ +--+ | <------------+ |
# Teeth | | | | | | | | | wt| }tt | |
# *---* *---* *---* *---* *---* <--------+ | |
# air gap { | | |
# (g) +---------------+---------------+ ^ <----+ | | |
# | Magnets | | tm | | | |
# | | | v | | | |
# +---------------+---------------+ <-+ | | | |
# | | ^ | | | | |
# | Rotor back Iron | tr | | | | |
# | | v | | | | |
# +-------------------------------+ | | | | |
# ^ | | | | |
# | | | | | |
# + + + + + +
# Rri Rro Rg Rt Rsi Rso




"""
$TYPEDEF
Simplified permanent magnet synchronous machine (PMSM) sizing.
"""
function size_PMSM!(motor::Motor, shaft_speed::AbstractFloat, design_power::AbstractFloat)
rotor = motor.rotor
stator = motor.stator
magnet = motor.magnet
teeth = motor.teeth
windings = motor.windings
shaft = motor.shaft

Check warning on line 160 in src/propsys/PMSM.jl

View check run for this annotation

Codecov / codecov/patch

src/propsys/PMSM.jl#L154-L160

Added lines #L154 - L160 were not covered by tests

Ω = shaft_speed*(2*π/60)
f = motor.N_pole_pairs*shaft_speed/60

Check warning on line 163 in src/propsys/PMSM.jl

View check run for this annotation

Codecov / codecov/patch

src/propsys/PMSM.jl#L162-L163

Added lines #L162 - L163 were not covered by tests

#Outer radius of the magnet - subject to the highest rotational speeds
radius_gap = motor.U_max/Ω

Check warning on line 166 in src/propsys/PMSM.jl

View check run for this annotation

Codecov / codecov/patch

src/propsys/PMSM.jl#L166

Added line #L166 was not covered by tests

# Calculate maximum flux through the stator and rotor back iron
# Really, this needs to be a constraint Bsbi ≤ Bsat (at the top level) rather
# than a prescribed setting...
B_stator = motor.rB_sat * motor.B_sat
B_rotor = motor.rB_sat * motor.B_sat

Check warning on line 172 in src/propsys/PMSM.jl

View check run for this annotation

Codecov / codecov/patch

src/propsys/PMSM.jl#L171-L172

Added lines #L171 - L172 were not covered by tests

B_gap = airgap_flux(magnet.M, magnet.thickness, motor.airgap_thickness)

Check warning on line 174 in src/propsys/PMSM.jl

View check run for this annotation

Codecov / codecov/patch

src/propsys/PMSM.jl#L174

Added line #L174 was not covered by tests

rotor.thickness = B_gap/B_rotor * π * radius_gap / (2*motor.N_pole_pairs)
stator.thickness = B_gap/B_stator * π * radius_gap / (2*motor.N_pole_pairs)

Check warning on line 177 in src/propsys/PMSM.jl

View check run for this annotation

Codecov / codecov/patch

src/propsys/PMSM.jl#L176-L177

Added lines #L176 - L177 were not covered by tests

rotor.Ro = radius_gap - magnet.thickness
rotor.Ri = rotor.Ro - rotor.thickness

Check warning on line 180 in src/propsys/PMSM.jl

View check run for this annotation

Codecov / codecov/patch

src/propsys/PMSM.jl#L179-L180

Added lines #L179 - L180 were not covered by tests

teeth.Ri = radius_gap + motor.airgap_thickness

Check warning on line 182 in src/propsys/PMSM.jl

View check run for this annotation

Codecov / codecov/patch

src/propsys/PMSM.jl#L182

Added line #L182 was not covered by tests

stator.Ri = teeth.Ri + teeth.thickness
stator.Ro = stator.Ri + stator.thickness

Check warning on line 185 in src/propsys/PMSM.jl

View check run for this annotation

Codecov / codecov/patch

src/propsys/PMSM.jl#L184-L185

Added lines #L184 - L185 were not covered by tests

N_teeth = motor.Nsp * 2 * motor.N_pole_pairs

Check warning on line 187 in src/propsys/PMSM.jl

View check run for this annotation

Codecov / codecov/patch

src/propsys/PMSM.jl#L187

Added line #L187 was not covered by tests

A_teeth = N_teeth * teeth.thickness * teeth.width
A_slots = π*(teeth.Ri + stator.Ri)*teeth.thickness - A_teeth
A_slot = A_slots/N_teeth
λ = A_slots/(A_slots + A_teeth)
l_end_turns = π/(2*motor.N_pole_pairs) * teeth.Ri */sqrt(1 - λ^2))

Check warning on line 193 in src/propsys/PMSM.jl

View check run for this annotation

Codecov / codecov/patch

src/propsys/PMSM.jl#L189-L193

Added lines #L189 - L193 were not covered by tests

#Armature reaction
B_windings = μ₀ * motor.J_max * teeth.thickness

Check warning on line 196 in src/propsys/PMSM.jl

View check run for this annotation

Codecov / codecov/patch

src/propsys/PMSM.jl#L196

Added line #L196 was not covered by tests

B_teeth = sqrt((B_gap/λ)^2 + B_windings^2)
if B_teeth > motor.B_sat
@warn "Flux density in teeth exceeds saturation flux density"

Check warning on line 200 in src/propsys/PMSM.jl

View check run for this annotation

Codecov / codecov/patch

src/propsys/PMSM.jl#L198-L200

Added lines #L198 - L200 were not covered by tests
end

torque = design_power/Ω
slot_current = J_max * windings.kpf*A_slot #Update to be peak current
windings.N_turns = floor(windings.kpf * A_slot/windings.A_wire)

Check warning on line 205 in src/propsys/PMSM.jl

View check run for this annotation

Codecov / codecov/patch

src/propsys/PMSM.jl#L203-L205

Added lines #L203 - L205 were not covered by tests

#Assume 2/3 phases excited at any given time, implicitly assumes 3 phase machine
force_length = (2/3 * motor.Nsp * 2*motor.N_pole_pairs) * B_gap * slot_current
motor.l = torque /(force_length * radius_gap)

Check warning on line 209 in src/propsys/PMSM.jl

View check run for this annotation

Codecov / codecov/patch

src/propsys/PMSM.jl#L208-L209

Added lines #L208 - L209 were not covered by tests

#Size shaft
shaft.Ro = rotor.Ri
if shaft.Ro^4 > torque/shaft.material.τmax * 2 * shaft.Ro/π
shaft.Ri = (shaft.Ro^4 - torque/shaft.material.τmax * 2 * shaft.Ro/π)^0.25

Check warning on line 214 in src/propsys/PMSM.jl

View check run for this annotation

Codecov / codecov/patch

src/propsys/PMSM.jl#L212-L214

Added lines #L212 - L214 were not covered by tests
else
# shaft can be solid as well
shaft.Ri = 0.0

Check warning on line 217 in src/propsys/PMSM.jl

View check run for this annotation

Codecov / codecov/patch

src/propsys/PMSM.jl#L217

Added line #L217 was not covered by tests
end

#Masses
rotor.mass = cross_sectional_area(rotor) * motor.l * rotor.material.density
stator.mass = cross_sectional_area(stator) * motor.l * stator.material.density
magnet.mass = cross_sectional_area(radius_gap, rotor.Ro)* motor.l * magnet.material.density
teeth.mass = A_teeth * motor.l * teeth.material.density

Check warning on line 224 in src/propsys/PMSM.jl

View check run for this annotation

Codecov / codecov/patch

src/propsys/PMSM.jl#L221-L224

Added lines #L221 - L224 were not covered by tests

total_winding_volume = A_slots * (motor.l + 2*l_end_turns)
windings.mass = windings.kpf * total_winding_volume * windings.conductor.material.density +

Check warning on line 227 in src/propsys/PMSM.jl

View check run for this annotation

Codecov / codecov/patch

src/propsys/PMSM.jl#L226-L227

Added lines #L226 - L227 were not covered by tests
(1 - windings.kpf)* total_winding_volume * windings.insulator.material.density

shaft.mass = cross_sectional_area(shaft) * (motor.l * shaft.l_extra)* shaft.material.density

Check warning on line 230 in src/propsys/PMSM.jl

View check run for this annotation

Codecov / codecov/patch

src/propsys/PMSM.jl#L230

Added line #L230 was not covered by tests

motor.mass = rotor.mass + stator.mass + magnet.mass + teeth.mass + windings.mass + shaft.mass

Check warning on line 232 in src/propsys/PMSM.jl

View check run for this annotation

Codecov / codecov/patch

src/propsys/PMSM.jl#L232

Added line #L232 was not covered by tests
#size_rotor!(rotor, R_gap)
#size_stator!()
#size_windings!()

## Calculate losses


end # function size_PMSM!

"""
"""
function cross_sectional_area(Ro, Ri)
return π*(Ro^2 - Ri^2)

Check warning on line 245 in src/propsys/PMSM.jl

View check run for this annotation

Codecov / codecov/patch

src/propsys/PMSM.jl#L244-L245

Added lines #L244 - L245 were not covered by tests
end # function cross_section

# Might not need to define each of this and just let anything go
# cross_sectional_area(X) = cross_sectional_area(X.Ro, X.Ri)
# if it doesn't have the right fields it'll throw an error.
cross_sectional_area(R::RotorGeometry) = cross_sectional_area(R.Ro, R.Ri)
cross_sectional_area(R::StatorGeometry) = cross_sectional_area(R.Ro, R.Ri)
cross_sectional_area(R::ShaftGeometry) = cross_sectional_area(R.Ro, R.Ri)

Check warning on line 253 in src/propsys/PMSM.jl

View check run for this annotation

Codecov / codecov/patch

src/propsys/PMSM.jl#L251-L253

Added lines #L251 - L253 were not covered by tests


"""
"""
function size_rotor!(rotor::RotorGeometry, R_gap::AbstractFloat)
Ro = R_gap - magnet.thickness
rotor.thickness = (B_gap/B_rotor) * π * R_gap/(2p)
rotor.Ri = Ro

Check warning on line 261 in src/propsys/PMSM.jl

View check run for this annotation

Codecov / codecov/patch

src/propsys/PMSM.jl#L258-L261

Added lines #L258 - L261 were not covered by tests

end # function size_rotor!

"""
Given the magnetization constant (M), thickness of the magnet, and the
air gap thickness, returns the flux density in the air gap.
Simplified expression from a magnetic circuit analysis. Assumes no MMF drop
across the steel.
"""
function airgap_flux(M, thickness, airgap)
B_gap = μ₀ * M * thickness/ (thickness + airgap)

Check warning on line 273 in src/propsys/PMSM.jl

View check run for this annotation

Codecov / codecov/patch

src/propsys/PMSM.jl#L272-L273

Added lines #L272 - L273 were not covered by tests
end # function airgap_flux

end
2 changes: 1 addition & 1 deletion src/propsys/cable.jl
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ end
(c::cable)(P::Float64, V::Float64, lcable::Float64)
Sizes the cable given a power, voltage, and length of the cable and returns
the efficiency function for the sized cable.
the *efficiency function* for the sized cable.
"""
function (c::cable)(P::Float64, V::Float64, lcable::Float64)
cond = c.cond
Expand Down
72 changes: 72 additions & 0 deletions src/propsys/inverter.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
"""
$TYPEDEF
Simplified model of an inverter.
$TYPEDFIELDS
"""
@kwdef mutable struct inverter
"""Design power [W]"""
P::AbstractFloat = 1e3
"""Number of pole-pairs"""
N_poles::Integer = 2
"""Design Rotational speed [RPM]"""
N::AbstractFloat

end

"""
inverter(P::Float64, N::Float64, parte::Array{Float64, 1})
Simple inverter model that calculates the efficiency and mass of an inverter or rectifier.
Default specific power is 19 kW/kg per [GE and Uni Illinois using SiC and GaN switches respectively.](https://arc.aiaa.org/doi/pdf/10.2514/6.2017-4701)
"""
function inverter(P::Float64, N::Float64, parte::Array{Float64, 1})
kcf = 20.
SPinv = 19.0e3 #W/kg

Check warning on line 27 in src/propsys/inverter.jl

View check run for this annotation

Codecov / codecov/patch

src/propsys/inverter.jl#L25-L27

Added lines #L25 - L27 were not covered by tests

p = parte[ite_p]

Check warning on line 29 in src/propsys/inverter.jl

View check run for this annotation

Codecov / codecov/patch

src/propsys/inverter.jl#L29

Added line #L29 was not covered by tests

f = p * N
fSwitch = f*kcf
η100 = -2.5e-7*fSwitch + 0.995
η20 = η100 - 0.0017
η10 = η100 - 0.0097

Check warning on line 35 in src/propsys/inverter.jl

View check run for this annotation

Codecov / codecov/patch

src/propsys/inverter.jl#L31-L35

Added lines #L31 - L35 were not covered by tests

M = [1.0 0.1 10.0

Check warning on line 37 in src/propsys/inverter.jl

View check run for this annotation

Codecov / codecov/patch

src/propsys/inverter.jl#L37

Added line #L37 was not covered by tests
1.0 0.2 5.0
1.0 1.0 1.0]

k1, k2, k3 = M\[η10; η20; η100]

Check warning on line 41 in src/propsys/inverter.jl

View check run for this annotation

Codecov / codecov/patch

src/propsys/inverter.jl#L41

Added line #L41 was not covered by tests

# η = k1 + k2*(P/Pmax) + k3*(P/Pmax)^-1 but here P = Pmax at design
η = k1 + k2*1 + k3/1

Check warning on line 44 in src/propsys/inverter.jl

View check run for this annotation

Codecov / codecov/patch

src/propsys/inverter.jl#L44

Added line #L44 was not covered by tests

parte[ite_k1] = k1
parte[ite_k2] = k2
parte[ite_k3] = k3

Check warning on line 48 in src/propsys/inverter.jl

View check run for this annotation

Codecov / codecov/patch

src/propsys/inverter.jl#L46-L48

Added lines #L46 - L48 were not covered by tests

parte[ite_Pinvdes] = P

Check warning on line 50 in src/propsys/inverter.jl

View check run for this annotation

Codecov / codecov/patch

src/propsys/inverter.jl#L50

Added line #L50 was not covered by tests

Winverter = P/SPinv * gee # Weight in [N]

Check warning on line 52 in src/propsys/inverter.jl

View check run for this annotation

Codecov / codecov/patch

src/propsys/inverter.jl#L52

Added line #L52 was not covered by tests

return η, Winverter, SPinv

Check warning on line 54 in src/propsys/inverter.jl

View check run for this annotation

Codecov / codecov/patch

src/propsys/inverter.jl#L54

Added line #L54 was not covered by tests

end
"""
Off design method for inverter
"""
function inverter(P::Float64, parte::Array{Float64, 1})

Check warning on line 60 in src/propsys/inverter.jl

View check run for this annotation

Codecov / codecov/patch

src/propsys/inverter.jl#L60

Added line #L60 was not covered by tests

k1 = parte[ite_k1]
k2 = parte[ite_k2]
k3 = parte[ite_k3]

Check warning on line 64 in src/propsys/inverter.jl

View check run for this annotation

Codecov / codecov/patch

src/propsys/inverter.jl#L62-L64

Added lines #L62 - L64 were not covered by tests

Pdes = parte[ite_Pinvdes]

Check warning on line 66 in src/propsys/inverter.jl

View check run for this annotation

Codecov / codecov/patch

src/propsys/inverter.jl#L66

Added line #L66 was not covered by tests

η = k1 + k2*(P/Pdes) + k3*(P/Pdes)^-1

Check warning on line 68 in src/propsys/inverter.jl

View check run for this annotation

Codecov / codecov/patch

src/propsys/inverter.jl#L68

Added line #L68 was not covered by tests

return η

Check warning on line 70 in src/propsys/inverter.jl

View check run for this annotation

Codecov / codecov/patch

src/propsys/inverter.jl#L70

Added line #L70 was not covered by tests

end
4 changes: 3 additions & 1 deletion src/propsys/propsys.jl
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
"""
Module containing all propulsion system related code.
Will cover alternate engine models - NPSS vs Drela's orig. model vs pyCycle
This includes alternate propulsion systems such as turbo-electric architectures.
Will eventually cover alternate engine models - NPSS vs Drela's orig. model vs pyCycle,
replacing the turbofan code such as `tfoper`, `tfsize`etc.
"""
module propsys

Expand Down

0 comments on commit ab51540

Please sign in to comment.