DUPA
This commit is contained in:
parent
60d09632a9
commit
7c020fc1f3
33
apc_perf.py
33
apc_perf.py
|
|
@ -1,11 +1,13 @@
|
|||
from dataclasses import dataclass
|
||||
from functools import cache, cached_property
|
||||
import math
|
||||
import re
|
||||
from typing import Collection, Mapping, Self, Sequence
|
||||
|
||||
from utils import lin_fun_interpolate, with_ops_scalar, with_ops_unary, with_ops_vector
|
||||
from utils import inrange, lin_fun_interpolate, with_ops_scalar, with_ops_unary, with_ops_vector
|
||||
|
||||
MPH = 0.44704
|
||||
RPM = 2 * math.pi / 60
|
||||
|
||||
@with_ops_unary('neg')
|
||||
@with_ops_vector('sub', 'add')
|
||||
|
|
@ -17,6 +19,10 @@ class PropOppoint:
|
|||
torque: float
|
||||
rpm: float
|
||||
|
||||
@cached_property
|
||||
def rot_speed(self) -> float:
|
||||
return self.rpm * RPM
|
||||
|
||||
def __neg__(self) -> Self: ...
|
||||
|
||||
def __truediv__(self, other: float) -> Self: ...
|
||||
|
|
@ -30,8 +36,19 @@ class ApcPerfdata:
|
|||
oppoints: Collection[PropOppoint]
|
||||
|
||||
@cached_property
|
||||
def rpms(self) -> Collection[float]:
|
||||
return { op.rpm for op in self.oppoints }
|
||||
def rpms(self) -> Sequence[float]:
|
||||
return sorted({ op.rpm for op in self.oppoints })
|
||||
|
||||
def speed_range_at_rpm(self, rpm: float) -> tuple[float, float]:
|
||||
speeds = [op.speed for op in self.rpm_series[rpm]]
|
||||
return min(speeds), max(speeds)
|
||||
|
||||
def rpms_at_speed(self, speed: float):
|
||||
return [rpm for rpm in self.rpms if inrange(speed, *self.speed_range_at_rpm(rpm))]
|
||||
|
||||
def rpm_range_at_speed(self, speed: float) -> tuple[float, float]:
|
||||
rpms = self.rpms_at_speed(speed)
|
||||
return min(rpms), max(rpms)
|
||||
|
||||
def _rpm_serie(self, rpm: float) -> Sequence[PropOppoint]:
|
||||
return sorted([op for op in self.oppoints if op.rpm == rpm], key=lambda op: op.speed)
|
||||
|
|
@ -46,6 +63,12 @@ class ApcPerfdata:
|
|||
return lambda: op
|
||||
return lin_fun_interpolate([op.speed for op in s], [mk_op(op) for op in s], speed)
|
||||
|
||||
def get_op_interp(self, rpm: float, speed: float) -> PropOppoint:
|
||||
loc_rpms = self.rpms_at_speed(speed)
|
||||
def mk_op(_rpm):
|
||||
return lambda: self.get_op_interpspeed(_rpm, speed)
|
||||
return lin_fun_interpolate(loc_rpms, [mk_op(_rpm) for _rpm in loc_rpms], rpm)
|
||||
|
||||
|
||||
@classmethod
|
||||
def from_file(cls, path: str):
|
||||
|
|
@ -72,8 +95,8 @@ def parse_apc_data(raw_data: str) -> Collection[PropOppoint]:
|
|||
continue
|
||||
|
||||
speed = vals[0] * MPH
|
||||
thrust = vals[9]
|
||||
torque = vals[10]
|
||||
torque = vals[9]
|
||||
thrust = vals[10]
|
||||
data_points.append(PropOppoint(speed, thrust, torque, current_rpm))
|
||||
|
||||
return data_points
|
||||
|
|
|
|||
|
|
@ -0,0 +1,84 @@
|
|||
from dataclasses import dataclass
|
||||
from functools import cached_property
|
||||
import math
|
||||
from scipy import optimize
|
||||
|
||||
from apc_perf import RPM, ApcPerfdata
|
||||
|
||||
VOLT_DUTY_MAX = 0.97
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class MotorOppoint:
|
||||
voltage: float
|
||||
current: float
|
||||
rpm: float
|
||||
torque: float
|
||||
|
||||
@cached_property
|
||||
def rot_speed(self) -> float:
|
||||
return self.rpm * RPM
|
||||
|
||||
@property
|
||||
def power_in(self) -> float:
|
||||
return self.voltage * self.current
|
||||
|
||||
@property
|
||||
def power_out(self) -> float:
|
||||
return self.torque * self.rot_speed
|
||||
|
||||
@property
|
||||
def efficiency(self) -> float:
|
||||
return self.power_out/self.power_in
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class MotorData:
|
||||
mot_kv: float
|
||||
mot_ir: float
|
||||
mot_idle_i: float
|
||||
|
||||
@cached_property
|
||||
def mot_kv_si(self) -> float:
|
||||
return self.mot_kv * RPM
|
||||
|
||||
@property
|
||||
def effective_ir(self) -> float:
|
||||
return self.mot_ir*1.5
|
||||
return self.mot_ir
|
||||
|
||||
def mot_full_pizda(self, rpm: float, voltage: float) -> MotorOppoint:
|
||||
rotspd = rpm * RPM
|
||||
voltage = VOLT_DUTY_MAX * voltage
|
||||
u_active = (rotspd / self.mot_kv_si)
|
||||
u_heat = voltage - u_active
|
||||
current = u_heat / self.effective_ir
|
||||
torq = (current-self.mot_idle_i) / self.mot_kv_si
|
||||
|
||||
return MotorOppoint(
|
||||
voltage = voltage,
|
||||
current = current,
|
||||
rpm = rpm,
|
||||
torque = torq,
|
||||
)
|
||||
|
||||
|
||||
|
||||
def op_full_pizda(mot: MotorData, prop: ApcPerfdata, speed: float, volt: float):
|
||||
|
||||
def f(rpm):
|
||||
return prop.get_op_interp(rpm, speed).torque - mot.mot_full_pizda(rpm, volt).torque
|
||||
|
||||
opt = optimize.root_scalar(f, bracket = prop.rpm_range_at_speed(speed))
|
||||
# print(opt)
|
||||
|
||||
rpm = opt.root
|
||||
|
||||
p_op = prop.get_op_interp(rpm, speed)
|
||||
m_op = mot.mot_full_pizda(rpm, volt)
|
||||
# print(p_op)
|
||||
# print(m_op)
|
||||
|
||||
return p_op, m_op
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
from apc_perf import ApcPerfdata
|
||||
from mot import MotorData, op_full_pizda
|
||||
|
||||
|
||||
at2826_900 = MotorData(
|
||||
mot_kv = 900,
|
||||
mot_ir = 0.035,
|
||||
mot_idle_i =2.5
|
||||
)
|
||||
|
||||
at2826_1100 = MotorData(
|
||||
mot_kv = 900,
|
||||
mot_ir = 0.11,
|
||||
mot_idle_i = 2.5
|
||||
)
|
||||
|
||||
rcf = MotorData(
|
||||
mot_kv = 1100,
|
||||
mot_ir = 0.02,
|
||||
mot_idle_i = 5
|
||||
)
|
||||
m_at100c = MotorData(
|
||||
mot_kv = 90,
|
||||
mot_ir = 0.02,
|
||||
mot_idle_i=4,
|
||||
)
|
||||
|
||||
prop_12x6 = ApcPerfdata.from_file('data/PERFILES2/PER3_12x6E.dat')
|
||||
|
||||
# Tutaj symulacja
|
||||
op_prop, op_mot = op_full_pizda(mot= at2826_900,
|
||||
prop= prop_12x6,
|
||||
speed= 10,
|
||||
volt= 14.6)
|
||||
|
||||
print(op_prop)
|
||||
print(op_mot)
|
||||
12
utils.py
12
utils.py
|
|
@ -7,16 +7,22 @@ class Interpolable(Protocol):
|
|||
def __mul__(self: Self, other: float, /) -> Self: ...
|
||||
def __neg__(self: Self, /) -> Self: ...
|
||||
|
||||
def inrange(x: float, xmin: float, xmax: float) -> bool:
|
||||
return xmin <= x <= xmax
|
||||
|
||||
EXTRAPOLATE_NONE = 0
|
||||
EXTRAPOLATE_CONST = 1
|
||||
EXTRAPOLATE_LIN = 2
|
||||
|
||||
class InterpolationRangeError(ValueError):
|
||||
pass
|
||||
|
||||
T1 = TypeVar('T1', bound=Interpolable)
|
||||
def lin_fun_interpolate(x_values: Sequence[float], y_values: Sequence[Callable[[], T1]], x: float, extr_down = EXTRAPOLATE_NONE, extr_up = EXTRAPOLATE_NONE) -> T1:
|
||||
# x0,x1,y0,y1 = None
|
||||
if x < x_values[0]:
|
||||
if extr_down == EXTRAPOLATE_NONE:
|
||||
raise ValueError("x is outside the interpolation range!")
|
||||
raise InterpolationRangeError("x is outside the interpolation range!")
|
||||
elif extr_down == EXTRAPOLATE_CONST:
|
||||
return y_values[0]()
|
||||
elif extr_down == EXTRAPOLATE_LIN:
|
||||
|
|
@ -28,11 +34,11 @@ def lin_fun_interpolate(x_values: Sequence[float], y_values: Sequence[Callable[[
|
|||
x0, x1 = x_values[i-1], x_values[i]
|
||||
y0, y1 = y_values[i-1](), y_values[i]()
|
||||
|
||||
if x_values[i] > x:
|
||||
if x_values[i] >= x:
|
||||
break
|
||||
else:
|
||||
if extr_up == EXTRAPOLATE_NONE:
|
||||
raise ValueError("x is outside the interpolation range!")
|
||||
raise InterpolationRangeError("x is outside the interpolation range!")
|
||||
elif extr_up == EXTRAPOLATE_CONST:
|
||||
return y1
|
||||
elif extr_up == EXTRAPOLATE_LIN:
|
||||
|
|
|
|||
Loading…
Reference in New Issue