Skip to content

Commit

Permalink
Add "Max Pressure" tool, Kn->pressure graph
Browse files Browse the repository at this point in the history
This commit moves the function for going from kn to pressure from the motor class to the propellant class and uses it for a new graph in the propellant editor. It also adds a new tool that takes in a desired max pressure and changes the nozzle throat so the motor won't exceed it.
  • Loading branch information
reilleya committed Dec 15, 2024
1 parent 545a8e1 commit ee83ddc
Show file tree
Hide file tree
Showing 8 changed files with 81 additions and 29 deletions.
24 changes: 1 addition & 23 deletions motorlib/motor.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,29 +89,7 @@ def calcIdealPressure(self, regDepth, dThroat, kn=None):
optionally be passed in to save time on motors where calculating surface area is expensive."""
if kn is None:
kn = self.calcKN(regDepth, dThroat)
density = self.propellant.getProperty('density')
tabPressures = []
for tab in self.propellant.getProperty('tabs'):
ballA, ballN, gamma, temp, molarMass = tab['a'], tab['n'], tab['k'], tab['t'], tab['m']
num = kn * density * ballA
exponent = 1 / (1 - ballN)
denom = ((gamma / ((gasConstant / molarMass) * temp)) * ((2 / (gamma + 1)) ** ((gamma + 1) / (gamma - 1)))) ** 0.5
tabPressure = (num / denom) ** exponent
# If the pressure that a burnrate produces falls into its range, we know it is the proper burnrate
# Due to floating point error, we sometimes get a situation in which no burnrate produces the proper pressure
# For this scenario, we go by whichever produces the least error
minTabPressure = tab['minPressure']
maxTabPressure = tab['maxPressure']
if minTabPressure == self.propellant.getMinimumValidPressure() and tabPressure < maxTabPressure:
return tabPressure
if maxTabPressure == self.propellant.getMaximumValidPressure() and minTabPressure < tabPressure:
return tabPressure
if minTabPressure < tabPressure < maxTabPressure:
return tabPressure
tabPressures.append([min(abs(minTabPressure - tabPressure), abs(tabPressure - maxTabPressure)), tabPressure])

tabPressures.sort(key=lambda x: x[0]) # Sort by the pressure error
return tabPressures[0][1] # Return the pressure
return self.propellant.getPressureFromKn(kn)

def calcForce(self, chamberPres, dThroat, exitPres=None):
"""Calculates the force of the motor at a given regression depth per grain. Calculates exit pressure by
Expand Down
32 changes: 32 additions & 0 deletions motorlib/propellant.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
"""Propellant submodule that contains the propellant class."""

from scipy.optimize import fsolve

from .properties import PropertyCollection, FloatProperty, StringProperty, TabularProperty
from .simResult import SimAlert, SimAlertLevel, SimAlertType
from .constants import gasConstant
Expand Down Expand Up @@ -41,6 +43,36 @@ def getBurnRate(self, pressure):
ballA, ballN, _, _, _ = self.getCombustionProperties(pressure)
return ballA * (pressure ** ballN)

def getPressureFromKn(self, kn):
density = self.getProperty('density')
tabPressures = []
for tab in self.getProperty('tabs'):
ballA, ballN, gamma, temp, molarMass = tab['a'], tab['n'], tab['k'], tab['t'], tab['m']
num = kn * density * ballA
exponent = 1 / (1 - ballN)
denom = ((gamma / ((gasConstant / molarMass) * temp)) * ((2 / (gamma + 1)) ** ((gamma + 1) / (gamma - 1)))) ** 0.5
tabPressure = (num / denom) ** exponent
# If the pressure that a burnrate produces falls into its range, we know it is the proper burnrate
# Due to floating point error, we sometimes get a situation in which no burnrate produces the proper pressure
# For this scenario, we go by whichever produces the least error
minTabPressure = tab['minPressure']
maxTabPressure = tab['maxPressure']
if minTabPressure == self.getMinimumValidPressure() and tabPressure < maxTabPressure:
return tabPressure
if maxTabPressure == self.getMaximumValidPressure() and minTabPressure < tabPressure:
return tabPressure
if minTabPressure < tabPressure < maxTabPressure:
return tabPressure
tabPressures.append([min(abs(minTabPressure - tabPressure), abs(tabPressure - maxTabPressure)), tabPressure])

tabPressures.sort(key=lambda x: x[0]) # Sort by the pressure error
return tabPressures[0][1] # Return the pressure

def getKnFromPressure(self, pressure):
func = lambda kn: self.getPressureFromKn(kn) - pressure

return fsolve(func, [250], maxfev=1000)

def getCombustionProperties(self, pressure):
"""Returns the propellant's a, n, gamma, combustion temp and molar mass for a given pressure"""
closest = {}
Expand Down
5 changes: 3 additions & 2 deletions uilib/preferencesManager.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,9 @@ def loadPreferences(self):

def savePreferences(self):
try:
logger.log('Saving preferences to "{}"'.format(getConfigPath() + 'preferences.yaml'))
saveFile(getConfigPath() + 'preferences.yaml', self.preferences.getDict(), fileTypes.PREFERENCES)
destinationPath = getConfigPath() + 'preferences.yaml'
logger.log('Saving preferences to "{}"'.format(destinationPath))
saveFile(destinationPath, self.preferences.getDict(), fileTypes.PREFERENCES)
except:
logger.warn('Unable to save preferences')

Expand Down
5 changes: 3 additions & 2 deletions uilib/propellantManager.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,9 @@ def loadPropellants(self):
def savePropellants(self):
propellants = [prop.getProperties() for prop in self.propellants]
try:
logger.log('Saving propellants to "{}"'.format(getConfigPath() + 'propellants.yaml'))
saveFile(getConfigPath() + 'propellants.yaml', propellants, fileTypes.PROPELLANTS)
destinationPath = getConfigPath() + 'propellants.yaml'
logger.log('Saving propellants to "{}"'.format(destinationPath))
saveFile(destinationPath, propellants, fileTypes.PROPELLANTS)
except:
logger.warn('Unable to save propellants!')

Expand Down
9 changes: 7 additions & 2 deletions uilib/toolManager.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from PyQt6.QtCore import QObject, pyqtSignal
from PyQt6.QtGui import QAction

from .tools import ChangeDiameterTool, InitialKNTool, MaxKNTool
from .tools import ChangeDiameterTool, InitialKNTool, MaxKNTool, MaxPressureTool
from .tools import ExpansionTool
from .tools import NeutralBatesTool
from .logger import logger
Expand All @@ -17,7 +17,12 @@ def __init__(self, app):
self.simulationManager = app.simulationManager
self.propellantManager = app.propellantManager

self.tools = {'Set': [ChangeDiameterTool(self), InitialKNTool(self), MaxKNTool(self)],
self.tools = {'Set': [
ChangeDiameterTool(self),
InitialKNTool(self),
MaxKNTool(self),
MaxPressureTool(self)
],
'Optimize': [ExpansionTool(self)],
'Design': [NeutralBatesTool(self)]}

Expand Down
1 change: 1 addition & 0 deletions uilib/tools/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from .changeDiameter import *
from .initialKN import *
from .maxKN import *
from .maxPressure import *
from .expansion import *
from .neutralBates import *
23 changes: 23 additions & 0 deletions uilib/views/forms/PropellantPreview.ui
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,23 @@
<string>Burn Rate</string>
</attribute>
</widget>
<widget class="PropellantPressureGraph" name="tabPressure">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>220</height>
</size>
</property>
<attribute name="title">
<string>Pressure</string>
</attribute>
</widget>
</widget>
</item>
</layout>
Expand All @@ -91,6 +108,12 @@
<header location="global">uilib.widgets.burnrateGraph</header>
<container>1</container>
</customwidget>
<customwidget>
<class>PropellantPressureGraph</class>
<extends>QWidget</extends>
<header location="global">uilib.widgets.propellantPressureGraph</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources/>
<connections/>
Expand Down
11 changes: 11 additions & 0 deletions uilib/widgets/propellantPreviewWidget.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,12 @@ def __init__(self):

def setPreferences(self, pref):
self.ui.tabBurnRate.setPreferences(pref)
self.ui.tabPressure.setPreferences(pref)

def loadPropellant(self, propellant):
self.ui.tabAlerts.clear()
self.ui.tabBurnRate.cleanup()
self.ui.tabPressure.cleanup()
alerts = propellant.getErrors()
for err in alerts:
self.ui.tabAlerts.addItem(err.description)
Expand All @@ -33,6 +35,15 @@ def loadPropellant(self, propellant):
burnrateData[1].append(propellant.getBurnRate(pres))
self.ui.tabBurnRate.showGraph(burnrateData)

pressureData = [[], []]
minKn = 1 # TODO: update bounds based on minimumValidPressure
maxKn = 750
for kn in range(minKn, maxKn, 10):
pressureData[0].append(kn)
pressureData[1].append(propellant.getPressureFromKn(kn))
self.ui.tabPressure.showGraph(pressureData)

def cleanup(self):
self.ui.tabAlerts.clear()
self.ui.tabBurnRate.cleanup()
self.ui.tabPressure.cleanup()

0 comments on commit ee83ddc

Please sign in to comment.