320 lines
8.8 KiB
Markdown
320 lines
8.8 KiB
Markdown
# Solver Guide
|
|
|
|
## Overview
|
|
|
|
The **Equation Solver** is a constraint-based computational engine that automatically solves rocket propulsion equations. Rather than manually plugging numbers into formulas, users specify constraints (inputs), and the solver propagates solutions through an interconnected equation network.
|
|
|
|
**Key Concept**: Drag variables onto the workspace, set values, and the solver automatically computes unknowns.
|
|
|
|
## User Interface
|
|
|
|
### Variable Palette (Left)
|
|
- Searchable list of all variables
|
|
- Organized by category (thrust, Isp, chamber, etc.)
|
|
- Drag variables onto workspace
|
|
|
|
### Workspace (Center)
|
|
- Drop zone for constraint cards
|
|
- Cards show variable name, unit, input field
|
|
- Set constraint by entering value
|
|
- Results auto-compute below
|
|
|
|
### Results Panel (Right)
|
|
- Shows all computed values
|
|
- Organized by category
|
|
- Clickable to copy values
|
|
- Unit selector for each variable
|
|
|
|
## Constraint Propagation Algorithm
|
|
|
|
The solver implements **greedy propagation**:
|
|
|
|
### Step-by-Step
|
|
|
|
1. **User Input**: Sets constraint on variable `x`
|
|
2. **Find Equations**: Locates all equations referencing `x`
|
|
3. **Attempt Solve**: For each equation, tries to solve for unknowns
|
|
- If equation has 1 unknown: solve directly
|
|
- If equation has 2+ unknowns: skip (not enough constraints)
|
|
4. **Update State**: Newly-solved variables are added to known set
|
|
5. **Recurse**: Repeat step 2 with newly-known variables
|
|
6. **Stop**: When no new variables can be computed
|
|
|
|
### Example
|
|
|
|
**Given:**
|
|
- `thrust = massFlowRate * exitVelocity`
|
|
- `exitVelocity = sqrt(2 * Cp * (T0 - Te))`
|
|
- `massFlowRate = densityO2 * densityFuel * burnRate`
|
|
|
|
**User Constraints:**
|
|
- `thrust = 50000 N`
|
|
- `massFlowRate = 100 kg/s`
|
|
|
|
**Solver Flow:**
|
|
```
|
|
1. Set thrust = 50000
|
|
2. Find equations with thrust: Eq1
|
|
3. Eq1 has 2 unknowns (massFlowRate, exitVelocity) → skip
|
|
4. Set massFlowRate = 100
|
|
5. Find equations with massFlowRate: Eq1, Eq3
|
|
6. Eq1 now has 1 unknown (exitVelocity) → solve: exitVelocity = 500 m/s
|
|
7. Find equations with exitVelocity: Eq2
|
|
8. Eq2 has 2 unknowns (T0, Te) → skip
|
|
9. No new variables → done
|
|
```
|
|
|
|
## Variable Definitions
|
|
|
|
Variables are defined in `src/engine/variables.js` with metadata:
|
|
|
|
```javascript
|
|
{
|
|
id: 'thrust',
|
|
name: 'Thrust',
|
|
unit: 'N',
|
|
category: 'performance',
|
|
type: 'number'
|
|
}
|
|
```
|
|
|
|
**Categories:**
|
|
- `thrust` — Force (N, lbf)
|
|
- `isp` — Specific impulse (s, m/s)
|
|
- `chamber` — Chamber conditions (P, T, density)
|
|
- `nozzle` — Nozzle geometry (area, diameter, angle)
|
|
- `propellant` — Fuel/oxidizer properties
|
|
- `flow` — Mass flow rate, burn rate
|
|
- `thermal` — Heat, temperature
|
|
- `structural` — Stress, strain, thickness
|
|
|
|
## Equation Library
|
|
|
|
Equations are defined in `src/engine/equations.js`. Each equation:
|
|
|
|
1. **Specifies variables** it relates
|
|
2. **Implements forward solver** (compute output given inputs)
|
|
3. **Implements per-variable solvers** (solve for each variable given others)
|
|
|
|
### Example Equation
|
|
|
|
```javascript
|
|
{
|
|
id: 'thrustEquation',
|
|
name: 'Thrust (Momentum)',
|
|
variables: ['thrust', 'massFlowRate', 'exitVelocity'],
|
|
equation: 'thrust = massFlowRate * exitVelocity',
|
|
forward: (inputs) => {
|
|
return inputs.massFlowRate * inputs.exitVelocity
|
|
},
|
|
solvers: {
|
|
exitVelocity: (inputs) => {
|
|
return inputs.thrust / inputs.massFlowRate
|
|
},
|
|
thrust: (inputs) => {
|
|
return inputs.massFlowRate * inputs.exitVelocity
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
### Transcendental Equations (Bisection)
|
|
|
|
For equations with no closed-form solution (e.g., Mach from area ratio), the solver uses **bisection**:
|
|
|
|
```javascript
|
|
// In numerics.js
|
|
function bisection(fn, target, min, max, tolerance) {
|
|
while (max - min > tolerance) {
|
|
const mid = (min + max) / 2
|
|
const fMid = fn(mid)
|
|
if (fMid < target) {
|
|
min = mid
|
|
} else {
|
|
max = mid
|
|
}
|
|
}
|
|
return (min + max) / 2
|
|
}
|
|
```
|
|
|
|
Example: Finding Mach number from area ratio
|
|
```javascript
|
|
solvers: {
|
|
machNumber: (inputs) => {
|
|
const fn = (M) => isentropicAreaRatio(M, inputs.gamma)
|
|
return bisection(fn, inputs.areaRatio, 0.01, 10, 1e-6)
|
|
}
|
|
}
|
|
```
|
|
|
|
## Common Equations
|
|
|
|
### Thrust
|
|
```
|
|
thrust = mass_flow_rate * exit_velocity
|
|
thrust = chamber_pressure * throat_area * CF
|
|
```
|
|
|
|
### Specific Impulse
|
|
```
|
|
Isp = exit_velocity / g
|
|
Isp_vac = exit_velocity / g
|
|
Isp_sl = (exit_velocity - P_exit / mass_flow_rate * area_exit) / g
|
|
```
|
|
|
|
### Chamber Conditions (Isentropic Flow)
|
|
```
|
|
T_exit = T_chamber * (P_exit / P_chamber)^((gamma - 1) / gamma)
|
|
rho_exit = rho_chamber * (P_exit / P_chamber)^(1 / gamma)
|
|
```
|
|
|
|
### Nozzle Area Ratio
|
|
```
|
|
A_exit / A_throat = (2 / (gamma + 1)) * (1 + (gamma - 1)/2 * M_exit^2))^((gamma + 1) / (2 * (gamma - 1))) / M_exit
|
|
```
|
|
(requires bisection to invert for M)
|
|
|
|
### Characteristic Velocity
|
|
```
|
|
c_star = P_chamber * A_throat / mass_flow_rate
|
|
```
|
|
|
|
### Thrust Coefficient
|
|
```
|
|
CF = sqrt(2 * gamma^2 / (gamma - 1) * (2 / (gamma + 1))^((gamma + 1) / (gamma - 1)) * (1 - (P_exit / P_chamber)^((gamma - 1) / gamma)))
|
|
```
|
|
|
|
## Workflow Examples
|
|
|
|
### Example 1: Determine Exit Velocity from Isp
|
|
|
|
**Goal:** Calculate exit velocity given Isp
|
|
|
|
**Steps:**
|
|
1. Drag `specificImpulse` onto workspace
|
|
2. Set `specificImpulse = 300 s`
|
|
3. Solver computes `exitVelocity = 300 * 9.81 ≈ 2943 m/s`
|
|
|
|
### Example 2: Find Chamber Pressure from Thrust
|
|
|
|
**Goal:** Find chamber pressure needed for 50 kN thrust
|
|
|
|
**Steps:**
|
|
1. Drag `thrust`, `throatDiameter`, `massFlowRate` onto workspace
|
|
2. Set:
|
|
- `thrust = 50000 N`
|
|
- `throatDiameter = 0.1 m`
|
|
- `massFlowRate = 100 kg/s`
|
|
3. Solver finds equations with these variables
|
|
4. Uses thrust equation to find thrust coefficient needed
|
|
5. Inverts nozzle area ratio with bisection to find Mach
|
|
6. Uses isentropic relations to find chamber pressure
|
|
7. Displays `chamberPressure = X bar`
|
|
|
|
### Example 3: Design for Specific Isp
|
|
|
|
**Goal:** Find propellant combination for Isp = 350 s
|
|
|
|
**Steps:**
|
|
1. Drag `specificImpulse`, `chamberTemperature`, `exhaustGamma` onto workspace
|
|
2. Set `specificImpulse = 350 s`
|
|
3. Click on knowledgebase to find propellant with T0 ≈ 3500 K
|
|
4. Enter that temperature
|
|
5. Solver computes `exitVelocity`, then works backward to required conditions
|
|
6. Compare against available propellants
|
|
|
|
## Advanced Features
|
|
|
|
### Unit Conversion
|
|
Every variable card has a unit selector. Setting a variable automatically converts:
|
|
```
|
|
thrust = 50000 N → 11240.44 lbf
|
|
thrust = 11240.44 lbf → 50000 N
|
|
```
|
|
|
|
### Importing Engine Design
|
|
Engine design results can be fed into the solver:
|
|
- File → Import Engine JSON
|
|
- Automatically populates thrust, Isp, chamber pressure, etc.
|
|
- Enables end-to-end rocket design workflow
|
|
|
|
### Variable Categories
|
|
Filter variables by category to reduce clutter:
|
|
- Thrust (F, Isp, c*)
|
|
- Chamber (P, T, density)
|
|
- Nozzle (area, geometry)
|
|
- Propellant (fuel/oxidizer properties)
|
|
- Flow (mass flow, burn rate)
|
|
|
|
## Limitations & Gotchas
|
|
|
|
1. **No Circular Dependencies**: If equations form a cycle, solver may loop infinitely
|
|
- Solver stops after N iterations to prevent this
|
|
- Design equations to be acyclic where possible
|
|
|
|
2. **Insufficient Constraints**: If variables are underdetermined (more unknowns than equations)
|
|
- Solver computes what it can, leaves rest as unknown
|
|
- User must provide more constraints
|
|
|
|
3. **Overdetermined System**: If too many constraints (conflicting values)
|
|
- Solver uses first constraint encountered
|
|
- Other constraints ignored (may warn in future)
|
|
|
|
4. **Transcendental Equation Tolerance**: Bisection has numerical error
|
|
- Default tolerance: 1e-6
|
|
- Results accurate to ~6 significant figures
|
|
- Adjust in `numerics.js` if higher precision needed
|
|
|
|
## Troubleshooting
|
|
|
|
### Solver not computing?
|
|
- Ensure at least one constraint is set
|
|
- Check that equation network connects the variables you're trying to solve
|
|
- Look for missing material properties (fuel, oxidizer data)
|
|
|
|
### Result seems wrong?
|
|
- Verify input units match variable definition
|
|
- Check variable category (is it the right variable?)
|
|
- Try solving step-by-step with intermediate variables
|
|
|
|
### Equation not available?
|
|
- Not all rocketry equations are implemented
|
|
- Submit a feature request to add more
|
|
- Or add the equation yourself in `src/engine/equations.js`
|
|
|
|
## Development Guide
|
|
|
|
### Adding a New Equation
|
|
|
|
1. **Define variables** in `variables.js` if needed
|
|
2. **Implement equation** in `equations.js`:
|
|
|
|
```javascript
|
|
equations.push({
|
|
id: 'myEquation',
|
|
name: 'My Equation',
|
|
variables: ['var1', 'var2', 'var3'],
|
|
equation: 'var1 = var2 * var3',
|
|
solvers: {
|
|
var1: (inputs) => inputs.var2 * inputs.var3,
|
|
var2: (inputs) => inputs.var1 / inputs.var3,
|
|
var3: (inputs) => inputs.var1 / inputs.var2
|
|
}
|
|
})
|
|
```
|
|
|
|
3. **Test** by:
|
|
- Setting constraints manually
|
|
- Verifying solver produces correct result
|
|
- Testing with known values
|
|
|
|
### Debugging Solver
|
|
- Add console logs in `solver.js` propagation loop
|
|
- Log variable state at each iteration
|
|
- Verify equation network is correct
|
|
|
|
---
|
|
|
|
**Last Updated**: 2025-02 | **Status**: Current
|