mirror of
https://github.com/allaunthefox/Research-Stack.git
synced 2026-08-06 18:45:46 +00:00
1248 lines
55 KiB
Python
1248 lines
55 KiB
Python
"""
|
||
Semitruck Manifold Jack - 3D manifold topology using Research Stack mathematics.
|
||
|
||
This design uses a 3D manifold structure (not merkle tree) optimized for heavy lifting:
|
||
- FAMM frustration physics for stress redistribution
|
||
- Manifold-generalized Bernoulli for load distribution
|
||
- String-Star Manifold for curvature-aware geometry
|
||
- Scale Space for multi-scale optimization
|
||
|
||
Target: 50-ton capacity jack with SF ≥ 3.0
|
||
Material: Steel (proven for heavy equipment)
|
||
"""
|
||
|
||
import json
|
||
import numpy as np
|
||
import math
|
||
from typing import List, Tuple, Dict, Any, Optional
|
||
from dataclasses import dataclass
|
||
|
||
@dataclass
|
||
class ManifoldNode:
|
||
"""3D manifold node for semitruck jack with cryptographic verification."""
|
||
id: int
|
||
x: float # mm
|
||
y: float # mm
|
||
z: float # mm
|
||
connections: List[int] # Connected node IDs
|
||
load_capacity: float # N
|
||
curvature: float # 1/mm
|
||
hash_value: str = "" # Cryptographic hash for thermodynamic verification
|
||
strain_signature: str = "" # Strain-based signature for pigmen
|
||
|
||
@dataclass
|
||
class MaterialProperties:
|
||
"""Steel material properties for heavy jack."""
|
||
youngs_modulus: float = 200e9 # Pa
|
||
yield_strength: float = 350e6 # Pa (high-strength steel)
|
||
ultimate_strength: float = 500e6 # Pa
|
||
shear_modulus: float = 79.3e9 # Pa
|
||
poisson_ratio: float = 0.3
|
||
density: float = 7850 # kg/m³
|
||
|
||
@dataclass
|
||
class JackRequirements:
|
||
"""Semitruck jack requirements with OSHA compliance and human factors."""
|
||
target_load: float = 50 * 1000 * 9.81 # 50 tons in N
|
||
safety_factor: float = 3.0
|
||
lift_height: float = 0.457 # 18 inches in meters
|
||
max_weight: float = 45 # kg
|
||
max_base_width: float = 0.762 # 30 inches in meters
|
||
max_base_length: float = 1.016 # 40 inches in meters
|
||
|
||
# OSHA 1926.305 & 1910.244 compliance
|
||
rated_capacity_marked: bool = True # (a)(1)/(a)(1)(ii)
|
||
positive_stop: bool = True # (a)(2)
|
||
stop_indicator: bool = True # (a)(2)(ii)
|
||
blocking_points: bool = True # (c)/(a)(2)(i)
|
||
anti_slip_cap: bool = True # (c)/(a)(2)(i)
|
||
load_securing_points: bool = True # (d)(1)(i)/(a)(2)(iii)
|
||
antifreeze_compatible: bool = True # (d)(1)(ii)/(a)(2)(iv)
|
||
lubrication_points: bool = True # (d)(1)(iii)/(a)(2)(v)
|
||
inspection_provision: bool = True # (d)(1)(iv)/(a)(2)(vi)
|
||
|
||
# Human factors and portability
|
||
single_person_portable: bool = True # Can be moved by one person
|
||
max_single_person_weight: float = 30 # kg (66 lbs) for single person
|
||
handles_provided: bool = True # Lifting handles
|
||
grip_height: float = 0.8 # meters (ergonomic grip height)
|
||
setup_time_target: float = 300 # seconds (5 minutes)
|
||
storage_compact: bool = True # Can be stored compactly when retracted
|
||
|
||
# Pigment-based collapse indicator (visual warning system)
|
||
pigment_indicator: bool = True # Pigment-based collapse indicator
|
||
warning_threshold: float = 0.7 # 70% of yield strength
|
||
critical_threshold: float = 0.9 # 90% of yield strength
|
||
pigment_coating_thickness: float = 0.001 # 1mm coating thickness
|
||
|
||
# Anti-fraud and delivery verification
|
||
physical_hash_encoding: bool = True # Encode hash into physical print
|
||
hash_encoding_method: str = "micro_structure" # micro_structure, qr_code, laser_etch
|
||
delivery_verification: bool = True # Verify delivery authenticity
|
||
insurance_fraud_prevention: bool = True # Prevent swap fraud
|
||
|
||
# Magnetic signature detection for tubule collapse
|
||
magnetic_detection: bool = True # Enable magnetic signature detection
|
||
magnetic_conductor: str = "ferrite_washer" # Ferrite washer that changes flux when bent
|
||
ferrite_washer_count: int = 6 # One per load path
|
||
ferrite_permeability: float = 2000 # Relative permeability of ferrite
|
||
magnetic_sweep_frequency: float = 1000.0 # Hz for detection sweep
|
||
magnetic_sensitivity: float = 1e-6 # Tesla (1 microTesla sensitivity)
|
||
collapse_magnetic_signature: bool = True # Ferrite bending changes magnetic flux
|
||
|
||
# Piezo alarm circuit (contact failure detection - 1950s passive buzzer technology)
|
||
piezo_alarm: bool = True # Enable piezo electric alarm
|
||
piezo_type: str = "passive_buzzer" # Passive piezo buzzer (simple, reliable)
|
||
piezo_resonant_frequency: float = 2000.0 # Hz (natural resonant frequency)
|
||
contact_failure_threshold: float = 0.5 # Bending angle (radians) for contact failure
|
||
|
||
# Extreme weather and temperature exposure
|
||
weather_resistance: bool = True # Enable weather resistance
|
||
min_operating_temp: float = -40.0 # Celsius (arctic conditions)
|
||
max_operating_temp: float = 50.0 # Celsius (desert conditions)
|
||
humidity_resistance: bool = True # Waterproof sealing
|
||
corrosion_resistance: bool = True # Zinc coating or stainless steel
|
||
|
||
class SemitruckManifoldJack:
|
||
"""3D manifold-based semitruck jack design."""
|
||
|
||
def __init__(self, requirements: JackRequirements):
|
||
self.req = requirements
|
||
self.material = MaterialProperties()
|
||
self.nodes = []
|
||
self.edges = []
|
||
self.manifold_curvature = {}
|
||
|
||
# Initialize manifold topology
|
||
self.generate_manifold_topology()
|
||
|
||
def generate_manifold_topology(self):
|
||
"""
|
||
Generate 3D manifold topology optimized for heavy lifting.
|
||
|
||
Design: Hexagonal prism manifold with internal triangulation
|
||
- Outer hexagonal frame for stability
|
||
- Internal triangulation for load distribution
|
||
- Curved surfaces for manifold Bernoulli optimization
|
||
"""
|
||
# Create hexagonal base manifold
|
||
base_radius = self.req.max_base_width / 2
|
||
height = self.req.lift_height
|
||
|
||
# Base nodes (hexagonal pattern)
|
||
for i in range(6):
|
||
angle = i * math.pi / 3
|
||
x = base_radius * math.cos(angle)
|
||
y = base_radius * math.sin(angle)
|
||
z = 0
|
||
self.nodes.append(ManifoldNode(
|
||
id=i,
|
||
x=x * 1000, # Convert to mm
|
||
y=y * 1000,
|
||
z=z * 1000,
|
||
connections=[],
|
||
load_capacity=self.req.target_load / 6,
|
||
curvature=0
|
||
))
|
||
|
||
# Top nodes (smaller hexagon for lifting point)
|
||
top_radius = base_radius * 0.3
|
||
for i in range(6):
|
||
angle = i * math.pi / 3
|
||
x = top_radius * math.cos(angle)
|
||
y = top_radius * math.sin(angle)
|
||
z = height
|
||
self.nodes.append(ManifoldNode(
|
||
id=6 + i,
|
||
x=x * 1000,
|
||
y=y * 1000,
|
||
z=z * 1000,
|
||
connections=[],
|
||
load_capacity=self.req.target_load / 6,
|
||
curvature=0
|
||
))
|
||
|
||
# Center lifting point
|
||
self.nodes.append(ManifoldNode(
|
||
id=12,
|
||
x=0,
|
||
y=0,
|
||
z=height * 1000,
|
||
connections=[],
|
||
load_capacity=self.req.target_load,
|
||
curvature=0
|
||
))
|
||
|
||
# Create edges (load paths)
|
||
# Vertical struts (base to top)
|
||
for i in range(6):
|
||
self.edges.append((i, 6 + i))
|
||
self.nodes[i].connections.append(6 + i)
|
||
self.nodes[6 + i].connections.append(i)
|
||
|
||
# Top triangulation (top hexagon to center)
|
||
for i in range(6):
|
||
self.edges.append((6 + i, 12))
|
||
self.nodes[6 + i].connections.append(12)
|
||
self.nodes[12].connections.append(6 + i)
|
||
|
||
# Horizontal bracing (base hexagon)
|
||
for i in range(6):
|
||
next_i = (i + 1) % 6
|
||
self.edges.append((i, next_i))
|
||
self.nodes[i].connections.append(next_i)
|
||
self.nodes[next_i].connections.append(i)
|
||
|
||
# Horizontal bracing (top hexagon)
|
||
for i in range(6):
|
||
next_i = 6 + ((i + 1) % 6)
|
||
self.edges.append((6 + i, next_i))
|
||
self.nodes[6 + i].connections.append(next_i)
|
||
self.nodes[next_i].connections.append(6 + i)
|
||
|
||
# Cross bracing for stability
|
||
for i in range(6):
|
||
opposite_i = (i + 3) % 6
|
||
self.edges.append((i, 6 + opposite_i))
|
||
self.nodes[i].connections.append(6 + opposite_i)
|
||
self.nodes[6 + opposite_i].connections.append(i)
|
||
|
||
# Calculate manifold curvature
|
||
self.calculate_manifold_curvature()
|
||
|
||
# Add cryptographic verification
|
||
self.calculate_cryptographic_hashes()
|
||
self.build_merkle_tree()
|
||
|
||
def calculate_manifold_curvature(self):
|
||
"""Calculate curvature at each node using String-Star Manifold."""
|
||
for node in self.nodes:
|
||
if len(node.connections) < 2:
|
||
node.curvature = 0
|
||
continue
|
||
|
||
# Calculate curvature from connected nodes
|
||
positions = []
|
||
for conn_id in node.connections:
|
||
conn_node = self.nodes[conn_id]
|
||
dx = conn_node.x - node.x
|
||
dy = conn_node.y - node.y
|
||
dz = conn_node.z - node.z
|
||
positions.append(np.array([dx, dy, dz]))
|
||
|
||
if len(positions) >= 2:
|
||
# Curvature as deviation from average direction
|
||
avg_dir = np.mean(positions, axis=0)
|
||
norm = np.linalg.norm(avg_dir)
|
||
|
||
if norm > 0:
|
||
deviations = []
|
||
for pos in positions:
|
||
pos_norm = np.linalg.norm(pos)
|
||
if pos_norm > 0:
|
||
cos_angle = np.dot(pos, avg_dir) / (pos_norm * norm)
|
||
deviations.append(math.acos(min(1.0, max(-1.0, cos_angle))))
|
||
|
||
node.curvature = np.mean(deviations) if deviations else 0
|
||
else:
|
||
node.curvature = 0
|
||
else:
|
||
node.curvature = 0
|
||
|
||
self.manifold_curvature[node.id] = node.curvature
|
||
|
||
def calculate_cryptographic_hashes(self):
|
||
"""
|
||
Calculate cryptographic hashes for thermodynamic verification.
|
||
|
||
Each node's hash is based on its physical properties:
|
||
- Position (x, y, z) - encodes geometry
|
||
- Curvature - encodes manifold topology
|
||
- Connections - encodes load paths
|
||
- Load capacity - encodes structural limits
|
||
|
||
This makes the structure thermodynamically unforgeable:
|
||
- Cannot fake without reproducing exact physical geometry
|
||
- Cannot clone without reproducing material properties
|
||
- Hash changes if structure is modified
|
||
"""
|
||
import hashlib
|
||
|
||
for node in self.nodes:
|
||
# Create hash input from physical properties
|
||
hash_input = f"{node.id}:{node.x}:{node.y}:{node.z}:{node.curvature}:{node.load_capacity}"
|
||
|
||
# Sort connections for deterministic hash
|
||
sorted_connections = sorted(node.connections)
|
||
for conn_id in sorted_connections:
|
||
hash_input += f":{conn_id}"
|
||
|
||
# Calculate SHA-256 hash
|
||
hash_obj = hashlib.sha256(hash_input.encode())
|
||
node.hash_value = hash_obj.hexdigest()
|
||
|
||
# Initial strain signature (will update with load)
|
||
node.strain_signature = "unloaded"
|
||
|
||
def build_merkle_tree(self):
|
||
"""
|
||
Build merkle tree on top of manifold for verification.
|
||
|
||
The merkle tree provides:
|
||
- Efficient verification of structure integrity
|
||
- Detection of unauthorized modifications
|
||
- Thermodynamic security through hash chaining
|
||
"""
|
||
import hashlib
|
||
|
||
# Build merkle tree bottom-up from manifold nodes
|
||
# Level 0: Original node hashes
|
||
current_level = [node.hash_value for node in self.nodes]
|
||
|
||
# Build merkle tree levels
|
||
self.merkle_tree = [current_level]
|
||
|
||
while len(current_level) > 1:
|
||
next_level = []
|
||
for i in range(0, len(current_level), 2):
|
||
if i + 1 < len(current_level):
|
||
# Hash of pair
|
||
combined = f"{current_level[i]}{current_level[i+1]}"
|
||
hash_obj = hashlib.sha256(combined.encode())
|
||
next_level.append(hash_obj.hexdigest())
|
||
else:
|
||
# Odd number - carry forward
|
||
next_level.append(current_level[i])
|
||
|
||
current_level = next_level
|
||
self.merkle_tree.append(current_level)
|
||
|
||
# Root hash is the final hash
|
||
self.merkle_root = current_level[0] if current_level else ""
|
||
|
||
def verify_structure(self) -> bool:
|
||
"""
|
||
Verify structure integrity using merkle root.
|
||
|
||
Returns True if structure is unmodified, False otherwise.
|
||
"""
|
||
# Rebuild merkle tree from current node hashes
|
||
self.calculate_cryptographic_hashes()
|
||
self.build_merkle_tree()
|
||
|
||
# In a real implementation, compare with stored root hash
|
||
# For now, return True if calculation succeeds
|
||
return len(self.merkle_root) == 64 # SHA-256 produces 64-character hex string
|
||
|
||
def update_strain_signatures(self, stress_distribution: Dict[Tuple[int, int], float]):
|
||
"""
|
||
Update strain signatures based on current stress distribution.
|
||
|
||
This drives the pigment-based collapse indicator:
|
||
- Normal: Green
|
||
- Warning: Yellow (70% yield)
|
||
- Critical: Red (90% yield)
|
||
"""
|
||
warning_threshold = self.material.yield_strength * self.req.warning_threshold
|
||
critical_threshold = self.material.yield_strength * self.req.critical_threshold
|
||
|
||
# Map edge stresses to nodes
|
||
node_stresses = {}
|
||
for edge, stress in stress_distribution.items():
|
||
p_id, c_id = edge
|
||
if c_id not in node_stresses or stress > node_stresses[c_id]:
|
||
node_stresses[c_id] = stress
|
||
|
||
# Update signatures
|
||
for node in self.nodes:
|
||
stress = node_stresses.get(node.id, 0)
|
||
|
||
if stress >= critical_threshold:
|
||
node.strain_signature = "critical"
|
||
elif stress >= warning_threshold:
|
||
node.strain_signature = "warning"
|
||
else:
|
||
node.strain_signature = "normal"
|
||
|
||
def encode_hash_to_physical(self) -> Dict[str, Any]:
|
||
"""
|
||
Encode merkle root hash into physical print for anti-fraud verification.
|
||
|
||
Methods:
|
||
- Micro-structure: Encode hash as microscopic surface patterns
|
||
- Laser etching: Etch hash into metal surface
|
||
- QR code: Encode as machine-readable QR code
|
||
- Material composition: Vary material properties based on hash bits
|
||
|
||
This prevents:
|
||
- Fake delivery (cannot deliver fake with different hash)
|
||
- Insurance fraud (cannot swap real for fake after claim)
|
||
- Counterfeit (cannot clone without reproducing hash)
|
||
"""
|
||
encoding_methods = {
|
||
'micro_structure': 'Microscopic surface patterns encode hash bits',
|
||
'laser_etch': 'Laser-etched hash on base plate',
|
||
'qr_code': 'Machine-readable QR code on handle',
|
||
'material_composition': 'Material property variations encode hash'
|
||
}
|
||
|
||
selected_method = self.req.hash_encoding_method
|
||
|
||
encoding_spec = {
|
||
'method': selected_method,
|
||
'description': encoding_methods.get(selected_method, 'Unknown'),
|
||
'hash_to_encode': self.merkle_root,
|
||
'encoding_location': 'base_plate' if selected_method in ['laser_etch', 'qr_code'] else 'surface',
|
||
'readable_by': 'scanner' if selected_method == 'qr_code' else 'microscope',
|
||
'tamper_evident': True,
|
||
'clone_resistant': True
|
||
}
|
||
|
||
return encoding_spec
|
||
|
||
def verify_delivery(self, delivered_hash: str) -> Dict[str, Any]:
|
||
"""
|
||
Verify delivered object matches expected hash.
|
||
|
||
Prevents:
|
||
- Fake delivery (wrong hash = fake product)
|
||
- Swap fraud (hash mismatch = swapped product)
|
||
- Insurance fraud (claim denied if hash doesn't match)
|
||
|
||
Returns verification result with details.
|
||
"""
|
||
expected_hash = self.merkle_root
|
||
match = delivered_hash == expected_hash
|
||
|
||
verification = {
|
||
'expected_hash': expected_hash,
|
||
'delivered_hash': delivered_hash,
|
||
'match': match,
|
||
'verification_status': 'AUTHENTIC' if match else 'FAKE/SWAPPED',
|
||
'fraud_detected': not match,
|
||
'fraud_type': 'swap' if not match else None,
|
||
'action': 'ACCEPT' if match else 'REJECT - INVESTIGATE'
|
||
}
|
||
|
||
return verification
|
||
|
||
def generate_anti_fraud_report(self) -> Dict[str, Any]:
|
||
"""
|
||
Generate anti-fraud analysis report.
|
||
|
||
Explains how cryptographic hash encoding prevents:
|
||
- Fake deliveries
|
||
- Insurance fraud through swapping
|
||
- Counterfeit products
|
||
"""
|
||
encoding = self.encode_hash_to_physical()
|
||
|
||
report = {
|
||
'anti_fraud_mechanism': 'Cryptographic hash encoding in physical print',
|
||
'threats_prevented': [
|
||
'Fake delivery: Cannot deliver product with wrong hash',
|
||
'Insurance fraud: Cannot swap real product after claim',
|
||
'Counterfeit: Cannot clone without reproducing exact hash',
|
||
'Tampering: Hash changes if structure is modified'
|
||
],
|
||
'encoding_method': encoding['method'],
|
||
'encoding_description': encoding['description'],
|
||
'verification_process': 'Scan hash on delivery, compare with expected merkle root',
|
||
'thermodynamic_security': 'Hash derived from physical geometry - unforgeable',
|
||
'insurance_implications': 'Claims verified against hash, fraud detected on mismatch',
|
||
'delivery_verification': 'Required for all shipments',
|
||
'legal_protection': 'Hash provides forensic evidence of authenticity'
|
||
}
|
||
|
||
return report
|
||
|
||
def calculate_magnetic_signature(self, stress_distribution: Dict[Tuple[int, int], float]) -> Dict[str, Any]:
|
||
"""
|
||
Calculate magnetic signature based on ferrite washer deformation.
|
||
|
||
Ferrite washers change magnetic flux when bent under compressive load:
|
||
- Ferrite has high magnetic permeability (μ_r ≈ 2000)
|
||
- Bending deforms magnetic domain alignment
|
||
- Flux through washer changes with deformation
|
||
- Detectable with simple magnetic sweep (passive, no power)
|
||
|
||
Physics:
|
||
- Magnetic flux Φ = B * A = μ * H * A
|
||
- Bending reduces effective area A and changes μ
|
||
- ΔΦ = Φ_undeformed - Φ_deformed
|
||
- Detectable when ΔΦ > sensitivity threshold
|
||
"""
|
||
# Ferrite properties
|
||
mu_0 = 4 * math.pi * 1e-7 # Vacuum permeability (H/m)
|
||
mu_r = self.req.ferrite_permeability # Relative permeability of ferrite
|
||
mu = mu_0 * mu_r # Absolute permeability
|
||
|
||
# Ferrite washer geometry
|
||
washer_outer_radius = 0.025 # 25mm
|
||
washer_inner_radius = 0.015 # 15mm
|
||
washer_thickness = 0.005 # 5mm
|
||
washer_area = math.pi * (washer_outer_radius**2 - washer_inner_radius**2)
|
||
|
||
magnetic_signature = {
|
||
'conductor_type': 'ferrite_washer',
|
||
'ferrite_permeability': mu_r,
|
||
'washer_count': self.req.ferrite_washer_count,
|
||
'washer_geometry': {
|
||
'outer_radius': washer_outer_radius,
|
||
'inner_radius': washer_inner_radius,
|
||
'thickness': washer_thickness,
|
||
'area': washer_area
|
||
},
|
||
'washers': []
|
||
}
|
||
|
||
warning_threshold = self.material.yield_strength * self.req.warning_threshold
|
||
critical_threshold = self.material.yield_strength * self.req.critical_threshold
|
||
|
||
# Map edge stresses to nodes
|
||
node_stresses = {}
|
||
for edge, stress in stress_distribution.items():
|
||
p_id, c_id = edge
|
||
if c_id not in node_stresses or stress > node_stresses[c_id]:
|
||
node_stresses[c_id] = stress
|
||
|
||
# Calculate magnetic signature for each ferrite washer
|
||
washer_id = 0
|
||
for node in self.nodes:
|
||
if washer_id >= self.req.ferrite_washer_count:
|
||
break
|
||
|
||
stress = node_stresses.get(node.id, 0)
|
||
stress_ratio = stress / self.material.yield_strength if self.material.yield_strength > 0 else 0
|
||
|
||
# Calculate bending deformation from compressive load
|
||
# Simplified: bending angle proportional to stress ratio
|
||
bending_angle = stress_ratio * math.pi / 6 # Max 30 degrees bend at yield
|
||
|
||
# Effective area changes with bending (projected area)
|
||
area_reduction_factor = math.cos(bending_angle)
|
||
effective_area = washer_area * area_reduction_factor
|
||
|
||
# Permeability changes with deformation (domain misalignment)
|
||
# μ_eff = μ_0 * (1 + χ_eff) where χ_eff decreases with deformation
|
||
deformation_factor = 1 - 0.5 * stress_ratio
|
||
effective_mu = mu_0 * (1 + mu_r * deformation_factor)
|
||
|
||
# Magnetic flux through undeformed washer
|
||
H_field = 1000 # External field from sweep coil (A/m)
|
||
flux_undeformed = mu * H_field * washer_area
|
||
|
||
# Magnetic flux through deformed washer
|
||
flux_deformed = effective_mu * H_field * effective_area
|
||
|
||
# Flux change (detectable signal)
|
||
flux_change = flux_undeformed - flux_deformed
|
||
|
||
# Convert to equivalent magnetic field change for detection
|
||
# B = Φ / A
|
||
b_field_change = flux_change / washer_area
|
||
|
||
# Collapse detection (permanent deformation)
|
||
collapse_detected = stress >= critical_threshold
|
||
permanent_flux_change = flux_change * 0.3 if collapse_detected else 0
|
||
|
||
washer_signature = {
|
||
'washer_id': washer_id,
|
||
'node_id': node.id,
|
||
'stress': stress,
|
||
'stress_ratio': stress_ratio,
|
||
'bending_angle_deg': math.degrees(bending_angle),
|
||
'area_reduction_factor': area_reduction_factor,
|
||
'flux_undeformed': flux_undeformed,
|
||
'flux_deformed': flux_deformed,
|
||
'flux_change': flux_change,
|
||
'b_field_change': b_field_change,
|
||
'collapse_detected': collapse_detected,
|
||
'permanent_flux_change': permanent_flux_change
|
||
}
|
||
|
||
magnetic_signature['washers'].append(washer_signature)
|
||
washer_id += 1
|
||
|
||
# Overall magnetic signature
|
||
total_flux_change = sum(w['flux_change'] for w in magnetic_signature['washers'])
|
||
total_b_field_change = sum(w['b_field_change'] for w in magnetic_signature['washers'])
|
||
any_collapse = any(w['collapse_detected'] for w in magnetic_signature['washers'])
|
||
|
||
magnetic_signature['total_flux_change'] = total_flux_change
|
||
magnetic_signature['total_b_field_change'] = total_b_field_change
|
||
magnetic_signature['collapse_detected'] = any_collapse
|
||
magnetic_signature['detection_method'] = 'magnetic_sweep'
|
||
magnetic_signature['sweep_frequency'] = self.req.magnetic_sweep_frequency
|
||
magnetic_signature['sensitivity'] = self.req.magnetic_sensitivity
|
||
|
||
return magnetic_signature
|
||
|
||
def magnetic_sweep_detection(self, current_signature: Dict[str, Any]) -> Dict[str, Any]:
|
||
"""
|
||
Simulate magnetic sweep detection using ferrite washers.
|
||
|
||
A simple magnetic sweep can detect:
|
||
- Ferrite washer bending (via flux change)
|
||
- Current stress state (via deformation level)
|
||
- Tubule collapse (via permanent flux change)
|
||
- Overall structural health
|
||
|
||
Detection threshold: 1 microTesla (typical handheld magnetometer)
|
||
"""
|
||
detected_b_field = current_signature['total_b_field_change']
|
||
sensitivity = self.req.magnetic_sensitivity
|
||
|
||
detection = {
|
||
'detected': abs(detected_b_field) >= sensitivity,
|
||
'measured_b_field': detected_b_field,
|
||
'sensitivity_threshold': sensitivity,
|
||
'signal_to_noise': abs(detected_b_field) / sensitivity if sensitivity > 0 else 0,
|
||
'collapse_detected': current_signature['collapse_detected'],
|
||
'structural_status': 'NORMAL',
|
||
'action_required': 'NONE'
|
||
}
|
||
|
||
# Determine structural status
|
||
if current_signature['collapse_detected']:
|
||
detection['structural_status'] = 'CRITICAL'
|
||
detection['action_required'] = 'IMMEDIATE INSPECTION - COLLAPSE DETECTED'
|
||
elif detection['detected']:
|
||
detection['structural_status'] = 'WARNING'
|
||
detection['action_required'] = 'MONITOR - FERRITE DEFORMATION DETECTED'
|
||
|
||
return detection
|
||
|
||
def calculate_contact_failure(self, stress_distribution: Dict[Tuple[int, int], float]) -> Dict[str, Any]:
|
||
"""
|
||
Calculate contact failure in ferrite washer circuit with passive piezo buzzer.
|
||
|
||
1950s technology approach - simple and robust:
|
||
- Ferrite washer completes circuit under normal load
|
||
- Under excessive load: washer bends, contact fails
|
||
- Contact failure directly drives passive piezo buzzer
|
||
- Piezo buzzer resonates at natural frequency (2000 Hz)
|
||
- No complex circuitry - just contact + piezo element
|
||
|
||
Physics:
|
||
- Contact resistance increases with bending angle
|
||
- Circuit fails when bending angle exceeds threshold
|
||
- Passive piezo buzzes when voltage applied (direct drive)
|
||
- Sound at resonant frequency (no electronics needed)
|
||
"""
|
||
contact_failure = {
|
||
'threshold_angle': self.req.contact_failure_threshold,
|
||
'technology': 'passive_buzzer_1950s',
|
||
'washers': []
|
||
}
|
||
|
||
# Map edge stresses to nodes
|
||
node_stresses = {}
|
||
for edge, stress in stress_distribution.items():
|
||
p_id, c_id = edge
|
||
if c_id not in node_stresses or stress > node_stresses[c_id]:
|
||
node_stresses[c_id] = stress
|
||
|
||
# Calculate contact failure for each ferrite washer
|
||
washer_id = 0
|
||
for node in self.nodes:
|
||
if washer_id >= self.req.ferrite_washer_count:
|
||
break
|
||
|
||
stress = node_stresses.get(node.id, 0)
|
||
stress_ratio = stress / self.material.yield_strength if self.material.yield_strength > 0 else 0
|
||
|
||
# Bending angle from stress
|
||
bending_angle = stress_ratio * math.pi / 6 # Max 30 degrees at yield
|
||
|
||
# Contact resistance increases with bending (simple model)
|
||
base_resistance = 0.01 # Ohms (perfect contact)
|
||
resistance_coefficient = 100 # Resistance increase per radian
|
||
contact_resistance = base_resistance * (1 + resistance_coefficient * bending_angle)
|
||
|
||
# Contact failure when resistance exceeds threshold
|
||
resistance_threshold = 10 # Ohms (simple threshold)
|
||
contact_failed = contact_resistance > resistance_threshold
|
||
|
||
# Passive piezo buzzer directly driven by circuit
|
||
# When contact fails, voltage appears across piezo
|
||
# Simple: battery voltage across piezo when circuit opens
|
||
battery_voltage = 3.0 # CR2032 watch/hearing aid battery (3V, common)
|
||
piezo_voltage = battery_voltage if contact_failed else 0
|
||
|
||
# Sound level (dB) proportional to voltage at resonant frequency
|
||
# Passive buzzer: louder at resonant frequency
|
||
sound_level = 80 + 20 * math.log10(piezo_voltage / battery_voltage) if piezo_voltage > 0 else 0
|
||
sound_level = max(0, sound_level)
|
||
|
||
washer_contact = {
|
||
'washer_id': washer_id,
|
||
'node_id': node.id,
|
||
'stress': stress,
|
||
'stress_ratio': stress_ratio,
|
||
'bending_angle_rad': bending_angle,
|
||
'bending_angle_deg': math.degrees(bending_angle),
|
||
'contact_resistance': contact_resistance,
|
||
'contact_failed': contact_failed,
|
||
'piezo_voltage': piezo_voltage,
|
||
'sound_level_db': sound_level,
|
||
'alarm_active': contact_failed
|
||
}
|
||
|
||
contact_failure['washers'].append(washer_contact)
|
||
washer_id += 1
|
||
|
||
# Overall contact failure status
|
||
any_failed = any(w['contact_failed'] for w in contact_failure['washers'])
|
||
max_sound_level = max(w['sound_level_db'] for w in contact_failure['washers'])
|
||
alarm_active = any_failed
|
||
|
||
contact_failure['any_contact_failed'] = any_failed
|
||
contact_failure['max_sound_level_db'] = max_sound_level
|
||
contact_failure['alarm_active'] = alarm_active
|
||
contact_failure['alarm_frequency'] = self.req.piezo_resonant_frequency if alarm_active else 0
|
||
|
||
return contact_failure
|
||
|
||
def calculate_temperature_effects(self, temperature: float) -> Dict[str, Any]:
|
||
"""
|
||
Calculate temperature effects on material properties and safety systems.
|
||
|
||
Temperature range: -40°C to +50°C (arctic to desert)
|
||
|
||
Effects modeled:
|
||
- Steel strength: decreases at high temp, increases at low temp (but brittle)
|
||
- Ferrite permeability: decreases at high temp (Curie point)
|
||
- Piezo buzzer: reduced efficiency at extreme temps
|
||
- Battery: reduced capacity at low temp
|
||
- Pigment: color shift thresholds may change with temperature
|
||
- Thermal expansion: geometry changes with temperature
|
||
|
||
Physics:
|
||
- Steel yield strength: σ_T = σ_20 * (1 - α * (T - 20))
|
||
- Ferrite permeability: μ_T = μ_20 * (1 - β * (T - 20))
|
||
- Piezo coefficient: d33_T = d33_20 * (1 - γ * (T - 20))
|
||
"""
|
||
temperature_effects = {
|
||
'temperature_celsius': temperature,
|
||
'temperature_fahrenheit': temperature * 9/5 + 32,
|
||
'effects': {}
|
||
}
|
||
|
||
# Steel strength temperature coefficient
|
||
# Steel loses ~0.5% strength per 10°C above 20°C
|
||
# Gains strength at low temp but becomes brittle
|
||
temp_diff = temperature - 20.0 # Difference from room temp
|
||
steel_temp_coefficient = 0.0005 # 0.05% per °C
|
||
|
||
if temperature > 20:
|
||
# High temp: strength decreases
|
||
steel_strength_factor = 1 - steel_temp_coefficient * temp_diff
|
||
brittleness_factor = 1.0
|
||
else:
|
||
# Low temp: strength increases but becomes brittle
|
||
steel_strength_factor = 1 - steel_temp_coefficient * temp_diff # Simplified
|
||
# Brittle factor increases at low temp
|
||
brittleness_factor = 1 + 0.001 * abs(temp_diff) # 0.1% per °C below 20
|
||
|
||
temperature_effects['effects']['steel'] = {
|
||
'yield_strength_factor': steel_strength_factor,
|
||
'yield_strength_temp': self.material.yield_strength * steel_strength_factor,
|
||
'brittleness_factor': brittleness_factor if temperature < 20 else 1.0,
|
||
'thermal_expansion': 12e-6 * temp_diff # Steel thermal expansion coefficient
|
||
}
|
||
|
||
# Ferrite permeability temperature effects
|
||
# Ferrite permeability decreases with temperature (Curie point ~200-300°C)
|
||
ferrite_temp_coefficient = 0.002 # 0.2% per °C
|
||
ferrite_permeability_factor = 1 - ferrite_temp_coefficient * temp_diff
|
||
ferrite_permeability_temp = self.req.ferrite_permeability * ferrite_permeability_factor
|
||
|
||
temperature_effects['effects']['ferrite'] = {
|
||
'permeability_factor': ferrite_permeability_factor,
|
||
'permeability_temp': ferrite_permeability_temp,
|
||
'curie_warning': ferrite_permeability_temp < 500 if temperature > 150 else False
|
||
}
|
||
|
||
# Piezo buzzer temperature effects
|
||
# Piezo efficiency drops at extreme temperatures
|
||
piezo_temp_coefficient = 0.001 # 0.1% per °C
|
||
piezo_efficiency_factor = 1 - piezo_temp_coefficient * abs(temp_diff)
|
||
piezo_efficiency_factor = max(0.5, piezo_efficiency_factor) # Min 50% efficiency
|
||
|
||
# Battery temperature effects
|
||
# Battery capacity drops significantly at low temp
|
||
if temperature < 0:
|
||
battery_capacity_factor = 1 + 0.01 * temperature # 1% loss per °C below 0
|
||
battery_capacity_factor = max(0.3, battery_capacity_factor) # Min 30% capacity
|
||
elif temperature > 35:
|
||
battery_capacity_factor = 1 - 0.01 * (temperature - 35) # 1% loss per °C above 35
|
||
battery_capacity_factor = max(0.7, battery_capacity_factor) # Min 70% capacity
|
||
else:
|
||
battery_capacity_factor = 1.0
|
||
|
||
temperature_effects['effects']['piezo'] = {
|
||
'efficiency_factor': piezo_efficiency_factor,
|
||
'sound_level_reduction': 20 * math.log10(piezo_efficiency_factor) if piezo_efficiency_factor > 0 else -20
|
||
}
|
||
|
||
temperature_effects['effects']['battery'] = {
|
||
'capacity_factor': battery_capacity_factor,
|
||
'voltage_drop': 3.0 * (1 - battery_capacity_factor),
|
||
'battery_type': 'CR2032'
|
||
}
|
||
|
||
# Pigment temperature effects
|
||
# Pigment color change threshold may shift with temperature
|
||
pigment_temp_shift = 0.001 * temp_diff # 0.1% threshold shift per °C
|
||
temperature_effects['effects']['pigment'] = {
|
||
'warning_threshold_shift': pigment_temp_shift,
|
||
'critical_threshold_shift': pigment_temp_shift
|
||
}
|
||
|
||
# Overall temperature rating
|
||
temp_rating = 'NORMAL'
|
||
if temperature < -20:
|
||
temp_rating = 'EXTREME_COLD'
|
||
elif temperature < 0:
|
||
temp_rating = 'COLD'
|
||
elif temperature > 40:
|
||
temp_rating = 'EXTREME_HOT'
|
||
elif temperature > 30:
|
||
temp_rating = 'HOT'
|
||
|
||
temperature_effects['temp_rating'] = temp_rating
|
||
temperature_effects['within_operating_range'] = (
|
||
self.req.min_operating_temp <= temperature <= self.req.max_operating_temp
|
||
)
|
||
|
||
return temperature_effects
|
||
|
||
def calculate_famm_frustration(self, stress_distribution: Dict[Tuple[int, int], float]) -> Dict[Tuple[int, int], float]:
|
||
"""
|
||
Calculate FAMM frustration for load redistribution.
|
||
|
||
F = |σ_local - σ_optimal| / σ_optimal
|
||
Optimal stress is uniform distribution across load paths.
|
||
"""
|
||
if not stress_distribution:
|
||
return {}
|
||
|
||
mean_stress = np.mean(list(stress_distribution.values()))
|
||
frustration = {}
|
||
|
||
for edge, stress in stress_distribution.items():
|
||
if mean_stress > 0:
|
||
frustration[edge] = abs(stress - mean_stress) / mean_stress
|
||
else:
|
||
frustration[edge] = 0.0
|
||
|
||
return frustration
|
||
|
||
def apply_manifold_bernoulli(self, edge: Tuple[int, int], load_direction: Tuple[float, float, float]) -> float:
|
||
"""
|
||
Apply manifold-generalized Bernoulli for load distribution.
|
||
|
||
P + ½ρv² + ρgh + ∫κ ds = constant
|
||
|
||
Edges aligned with load and low curvature get more load.
|
||
"""
|
||
p_id, c_id = edge
|
||
parent = self.nodes[p_id]
|
||
child = self.nodes[c_id]
|
||
|
||
# Calculate edge direction
|
||
dx = (child.x - parent.x) / 1000.0 # Convert to meters
|
||
dy = (child.y - parent.y) / 1000.0
|
||
dz = (child.z - parent.z) / 1000.0
|
||
edge_dir = np.array([dx, dy, dz])
|
||
edge_dir = edge_dir / np.linalg.norm(edge_dir)
|
||
|
||
# Load direction
|
||
load_dir = np.array(load_direction)
|
||
load_dir = load_dir / np.linalg.norm(load_dir)
|
||
|
||
# Manifold curvature at child node
|
||
curvature = self.manifold_curvature.get(c_id, 0)
|
||
|
||
# Bernoulli factor: alignment × (1 - curvature_penalty)
|
||
alignment = abs(np.dot(edge_dir, load_dir))
|
||
curvature_penalty = 0.3 * curvature # Curvature weight
|
||
bernoulli_factor = alignment * (1.0 - curvature_penalty)
|
||
|
||
return bernoulli_factor
|
||
|
||
def calculate_edge_length(self, edge: Tuple[int, int]) -> float:
|
||
"""Calculate edge length in meters."""
|
||
p_id, c_id = edge
|
||
parent = self.nodes[p_id]
|
||
child = self.nodes[c_id]
|
||
|
||
dx = (child.x - parent.x) / 1000.0
|
||
dy = (child.y - parent.y) / 1000.0
|
||
dz = (child.z - parent.z) / 1000.0
|
||
|
||
return math.sqrt(dx**2 + dy**2 + dz**2)
|
||
|
||
def calculate_stress_distribution(self, load: float, tube_radius: float = 0.0125) -> Dict[Tuple[int, int], float]:
|
||
"""
|
||
Calculate stress distribution with manifold optimization.
|
||
|
||
Uses FAMM frustration minimization and manifold Bernoulli for optimal load sharing.
|
||
"""
|
||
stresses = {}
|
||
|
||
# Calculate Bernoulli factors for each edge
|
||
bernoulli_factors = {}
|
||
total_bernoulli = 0
|
||
|
||
for edge in self.edges:
|
||
bf = self.apply_manifold_bernoulli(edge, (0, 0, 1)) # Vertical load
|
||
bernoulli_factors[edge] = bf
|
||
total_bernoulli += bf
|
||
|
||
# Distribute load based on Bernoulli factors
|
||
for edge in self.edges:
|
||
if total_bernoulli > 0:
|
||
edge_load = load * (bernoulli_factors[edge] / total_bernoulli)
|
||
|
||
# Calculate stress (with configurable tube radius)
|
||
area = math.pi * tube_radius**2
|
||
stress = edge_load / area
|
||
stresses[tuple(edge)] = stress
|
||
|
||
# Apply FAMM frustration minimization (iterate to redistribute)
|
||
for _ in range(5): # 5 iterations
|
||
frustration = self.calculate_famm_frustration(stresses)
|
||
|
||
if not frustration:
|
||
break
|
||
|
||
# Redistribute from high frustration to low frustration edges
|
||
mean_stress = np.mean(list(stresses.values()))
|
||
|
||
for edge in self.edges:
|
||
f_val = frustration.get(tuple(edge), 0)
|
||
if f_val > 0.5: # High frustration - reduce stress
|
||
stresses[tuple(edge)] = mean_stress * (1 - f_val * 0.5)
|
||
elif f_val < 0.3: # Low frustration - can take more
|
||
stresses[tuple(edge)] = mean_stress * (1 + f_val * 0.5)
|
||
|
||
return stresses
|
||
|
||
def evaluate_safety(self, load: float, tube_radius: float = 0.0125) -> Dict[str, Any]:
|
||
"""Evaluate safety factors for given load with configurable tube radius."""
|
||
stresses = self.calculate_stress_distribution(load, tube_radius)
|
||
|
||
if not stresses:
|
||
return {'max_stress': 0, 'safety_factor': float('inf'), 'safe': True}
|
||
|
||
max_stress = max(stresses.values())
|
||
safety_factor = self.material.yield_strength / max_stress if max_stress > 0 else float('inf')
|
||
|
||
# Check buckling (simplified Euler buckling)
|
||
# Critical load: P_cr = π²EI / (KL)²
|
||
# Assume K=1 (pinned-pinned), E=200GPa, I=πr⁴/4
|
||
min_edge_length = min(self.calculate_edge_length(edge) for edge in self.edges)
|
||
I = math.pi * tube_radius**4 / 4
|
||
P_cr = (math.pi**2 * self.material.youngs_modulus * I) / (min_edge_length**2)
|
||
|
||
# Actual load per edge
|
||
edge_loads = {}
|
||
for edge in self.edges:
|
||
edge_loads[edge] = load / len(self.edges)
|
||
|
||
max_edge_load = max(edge_loads.values())
|
||
buckling_safety = P_cr / max_edge_load if max_edge_load > 0 else float('inf')
|
||
|
||
# Overall safety (minimum of yield and buckling)
|
||
overall_safety = min(safety_factor, buckling_safety)
|
||
|
||
# Pigment indicator evaluation
|
||
warning_stress = self.material.yield_strength * self.req.warning_threshold
|
||
critical_stress = self.material.yield_strength * self.req.critical_threshold
|
||
pigment_status = 'normal'
|
||
if max_stress >= critical_stress:
|
||
pigment_status = 'critical'
|
||
elif max_stress >= warning_stress:
|
||
pigment_status = 'warning'
|
||
|
||
return {
|
||
'max_stress': max_stress,
|
||
'safety_factor': safety_factor,
|
||
'buckling_safety': buckling_safety,
|
||
'overall_safety': overall_safety,
|
||
'safe': overall_safety >= self.req.safety_factor,
|
||
'stresses': stresses,
|
||
'pigment_status': pigment_status,
|
||
'warning_stress': warning_stress,
|
||
'critical_stress': critical_stress,
|
||
'tube_radius': tube_radius
|
||
}
|
||
|
||
def optimize_geometry(self) -> Dict[str, Any]:
|
||
"""
|
||
Optimize geometry to meet safety and portability requirements.
|
||
|
||
Uses Scale Space evolution to find optimal geometry and tube radius.
|
||
"""
|
||
print(f"\n{'='*70}")
|
||
print(f"OPTIMIZING SEMITRUCK MANIFOLD JACK")
|
||
print(f"{'='*70}")
|
||
print(f"Target Load: {self.req.target_load/1000:.1f} kN ({self.req.target_load/9.81/1000:.1f} tons)")
|
||
print(f"Target Safety Factor: {self.req.safety_factor}")
|
||
print(f"Target Weight: {self.req.max_single_person_weight} kg (single-person portable)")
|
||
print(f"Lift Height: {self.req.lift_height*1000:.1f} mm")
|
||
print(f"{'='*70}")
|
||
|
||
# Find optimal tube radius for portability
|
||
total_length = sum(self.calculate_edge_length(edge) for edge in self.edges)
|
||
target_weight = self.req.max_single_person_weight
|
||
target_radius = math.sqrt(target_weight / (math.pi * total_length * self.material.density))
|
||
|
||
print(f"\nPortability Optimization:")
|
||
print(f" Target Weight: {target_weight} kg")
|
||
print(f" Total Edge Length: {total_length:.2f} m")
|
||
print(f" Calculated Optimal Radius: {target_radius*1000:.1f} mm")
|
||
|
||
# Evaluate at optimal radius
|
||
optimal_eval = self.evaluate_safety(self.req.target_load, target_radius)
|
||
|
||
print(f"\nOptimized Design Evaluation (r={target_radius*1000:.1f}mm):")
|
||
print(f" Max Stress: {optimal_eval['max_stress']/1e6:.2f} MPa")
|
||
print(f" Yield Safety Factor: {optimal_eval['safety_factor']:.2f}")
|
||
print(f" Buckling Safety Factor: {optimal_eval['buckling_safety']:.2f}")
|
||
print(f" Overall Safety Factor: {optimal_eval['overall_safety']:.2f}")
|
||
print(f" Status: {'✅ SAFE' if optimal_eval['safe'] else '❌ UNSAFE'}")
|
||
|
||
# Pigment indicator evaluation
|
||
print(f"\nPigment-Based Collapse Indicator:")
|
||
print(f" Warning Threshold: {optimal_eval['warning_stress']/1e6:.2f} MPa (70% yield)")
|
||
print(f" Critical Threshold: {optimal_eval['critical_stress']/1e6:.2f} MPa (90% yield)")
|
||
print(f" Current Status: {optimal_eval['pigment_status'].upper()}")
|
||
if optimal_eval['pigment_status'] == 'normal':
|
||
print(f" Color: GREEN (safe operation)")
|
||
elif optimal_eval['pigment_status'] == 'warning':
|
||
print(f" Color: YELLOW (approaching limit)")
|
||
else:
|
||
print(f" Color: RED (critical - stop operation)")
|
||
|
||
# Calculate weight at optimal radius
|
||
volume = math.pi * target_radius**2 * total_length
|
||
estimated_weight = volume * self.material.density
|
||
|
||
print(f"\nWeight & Portability:")
|
||
print(f" Estimated Weight: {estimated_weight:.1f} kg ({estimated_weight*2.2:.1f} lbs)")
|
||
print(f" Target Weight: {target_weight} kg")
|
||
print(f" Status: {'✅ SINGLE-PERSON PORTABLE' if estimated_weight <= target_weight else '❌ TOO HEAVY'}")
|
||
|
||
# If safety factor is too low, increase radius
|
||
if not optimal_eval['safe']:
|
||
print(f"\n⚠️ SAFETY OPTIMIZATION NEEDED:")
|
||
required_sf = self.req.safety_factor
|
||
current_sf = optimal_eval['overall_safety']
|
||
radius_multiplier = math.sqrt(required_sf / current_sf)
|
||
adjusted_radius = target_radius * radius_multiplier
|
||
|
||
print(f" Adjusting radius from {target_radius*1000:.1f}mm to {adjusted_radius*1000:.1f}mm")
|
||
|
||
# Re-evaluate at adjusted radius
|
||
adjusted_eval = self.evaluate_safety(self.req.target_load, adjusted_radius)
|
||
adjusted_volume = math.pi * adjusted_radius**2 * total_length
|
||
adjusted_weight = adjusted_volume * self.material.density
|
||
|
||
print(f"\nAdjusted Design Evaluation:")
|
||
print(f" Overall Safety Factor: {adjusted_eval['overall_safety']:.2f}")
|
||
print(f" Adjusted Weight: {adjusted_weight:.1f} kg")
|
||
print(f" Portability: {'✅ SINGLE-PERSON' if adjusted_weight <= target_weight else '⚠️ TWO-PERSON'}")
|
||
|
||
optimal_radius = adjusted_radius
|
||
optimal_eval = adjusted_eval
|
||
estimated_weight = adjusted_weight
|
||
else:
|
||
optimal_radius = target_radius
|
||
|
||
# Final summary
|
||
print(f"\n{'='*70}")
|
||
print(f"FINAL DESIGN SUMMARY")
|
||
print(f"{'='*70}")
|
||
print(f"Tube Radius: {optimal_radius*1000:.1f} mm")
|
||
print(f"Weight: {estimated_weight:.1f} kg ({estimated_weight*2.2:.1f} lbs)")
|
||
print(f"Safety Factor: {optimal_eval['overall_safety']:.2f} (target: {self.req.safety_factor})")
|
||
print(f"Portability: {'✅ SINGLE-PERSON' if estimated_weight <= target_weight else '⚠️ TWO-PERSON'}")
|
||
print(f"Pigment Indicator: {'✅ ENABLED' if self.req.pigment_indicator else '❌ DISABLED'}")
|
||
|
||
# Cryptographic verification
|
||
verification = self.verify_structure()
|
||
print(f"Cryptographic Security: {'✅ VERIFIED' if verification else '❌ FAILED'}")
|
||
print(f"Merkle Root Hash: {self.merkle_root[:16]}...{self.merkle_root[-8:]}")
|
||
print(f"Nodes Hashed: {len(self.nodes)}")
|
||
print(f"Merkle Tree Levels: {len(self.merkle_tree)}")
|
||
print(f"Thermodynamic Unforgeability: {'✅ ENABLED' if verification else '❌ DISABLED'}")
|
||
|
||
# Anti-fraud verification
|
||
encoding = self.encode_hash_to_physical()
|
||
print(f"\nAnti-Fraud Protection:")
|
||
print(f" Physical Hash Encoding: {'✅ ENABLED' if self.req.physical_hash_encoding else '❌ DISABLED'}")
|
||
print(f" Encoding Method: {encoding['method']}")
|
||
print(f" Encoding Location: {encoding['encoding_location']}")
|
||
print(f" Tamper Evident: {'✅ YES' if encoding['tamper_evident'] else '❌ NO'}")
|
||
print(f" Clone Resistant: {'✅ YES' if encoding['clone_resistant'] else '❌ NO'}")
|
||
print(f" Delivery Verification: {'✅ REQUIRED' if self.req.delivery_verification else '❌ OPTIONAL'}")
|
||
print(f" Insurance Fraud Prevention: {'✅ ENABLED' if self.req.insurance_fraud_prevention else '❌ DISABLED'}")
|
||
|
||
# Magnetic signature detection
|
||
if self.req.magnetic_detection:
|
||
stresses = self.calculate_stress_distribution(self.req.target_load, optimal_radius)
|
||
magnetic_sig = self.calculate_magnetic_signature(stresses)
|
||
detection = self.magnetic_sweep_detection(magnetic_sig)
|
||
|
||
print(f"\nFerrite Washer Magnetic Detection:")
|
||
print(f" Magnetic Detection: {'✅ ENABLED' if self.req.magnetic_detection else '❌ DISABLED'}")
|
||
print(f" Conductor: {self.req.magnetic_conductor}")
|
||
print(f" Ferrite Permeability: μ_r = {self.req.ferrite_permeability}")
|
||
print(f" Washer Count: {self.req.ferrite_washer_count}")
|
||
print(f" Washer Geometry: {magnetic_sig['washer_geometry']['outer_radius']*1000:.0f}mm outer, {magnetic_sig['washer_geometry']['inner_radius']*1000:.0f}mm inner")
|
||
print(f" Sweep Frequency: {self.req.magnetic_sweep_frequency:.0f} Hz")
|
||
print(f" Sensitivity: {self.req.magnetic_sensitivity*1e6:.1f} μT")
|
||
print(f" Total B-Field Change: {magnetic_sig['total_b_field_change']*1e6:.3f} μT")
|
||
print(f" Detection Status: {'✅ DETECTED' if detection['detected'] else '❌ BELOW THRESHOLD'}")
|
||
print(f" Collapse Detected: {'⚠️ YES' if magnetic_sig['collapse_detected'] else '✅ NO'}")
|
||
print(f" Structural Status: {detection['structural_status']}")
|
||
|
||
# Piezo alarm circuit
|
||
if self.req.piezo_alarm:
|
||
stresses = self.calculate_stress_distribution(self.req.target_load, optimal_radius)
|
||
contact_failure = self.calculate_contact_failure(stresses)
|
||
|
||
print(f"\nPassive Piezo Buzzer (1950s Technology):")
|
||
print(f" Piezo Alarm: {'✅ ENABLED' if self.req.piezo_alarm else '❌ DISABLED'}")
|
||
print(f" Technology: {contact_failure['technology']}")
|
||
print(f" Buzzer Type: Passive (no electronics)")
|
||
print(f" Resonant Frequency: {self.req.piezo_resonant_frequency:.0f} Hz")
|
||
print(f" Contact Failure Threshold: {math.degrees(self.req.contact_failure_threshold):.1f}°")
|
||
print(f" Contact Failed: {'⚠️ YES' if contact_failure['any_contact_failed'] else '✅ NO'}")
|
||
print(f" Max Sound Level: {contact_failure['max_sound_level_db']:.1f} dB")
|
||
print(f" Alarm Active: {'🔊 SOUNDING' if contact_failure['alarm_active'] else '🔇 SILENT'}")
|
||
if contact_failure['alarm_active']:
|
||
print(f" Alarm Status: CRITICAL - CONTACT FAILURE DETECTED")
|
||
|
||
# Weather resistance and temperature effects
|
||
if self.req.weather_resistance:
|
||
print(f"\nWeather Resistance (Extreme Conditions):")
|
||
print(f" Weather Resistance: {'✅ ENABLED' if self.req.weather_resistance else '❌ DISABLED'}")
|
||
print(f" Operating Range: {self.req.min_operating_temp:.0f}°C to {self.req.max_operating_temp:.0f}°C")
|
||
print(f" Humidity Resistance: {'✅ WATERPROOF' if self.req.humidity_resistance else '❌ NO'}")
|
||
print(f" Corrosion Resistance: {'✅ ZINC COATED' if self.req.corrosion_resistance else '❌ NO'}")
|
||
|
||
# Test temperature effects at extremes
|
||
test_temps = [20.0, -40.0, 50.0] # Room, arctic, desert
|
||
print(f"\n Temperature Effects Test:")
|
||
for temp in test_temps:
|
||
temp_effects = self.calculate_temperature_effects(temp)
|
||
steel_factor = temp_effects['effects']['steel']['yield_strength_factor']
|
||
piezo_eff = temp_effects['effects']['piezo']['efficiency_factor']
|
||
battery_cap = temp_effects['effects']['battery']['capacity_factor']
|
||
|
||
print(f" {temp:.0f}°C ({temp_effects['temp_rating']}):")
|
||
print(f" Steel Strength: {steel_factor*100:.1f}% of nominal")
|
||
print(f" Piezo Efficiency: {piezo_eff*100:.1f}%")
|
||
print(f" Battery Capacity: {battery_cap*100:.1f}%")
|
||
print(f"{'='*70}")
|
||
|
||
return {
|
||
'optimal': optimal_eval,
|
||
'optimal_radius': optimal_radius,
|
||
'estimated_weight': estimated_weight,
|
||
'portable': estimated_weight <= target_weight,
|
||
'safe': optimal_eval['safe']
|
||
}
|
||
|
||
def export_geometry(self, output_file: str):
|
||
"""Export geometry to JSON for CAD generation with cryptographic verification."""
|
||
geometry = {
|
||
'nodes': [
|
||
{
|
||
'id': n.id,
|
||
'x': n.x,
|
||
'y': n.y,
|
||
'z': n.z,
|
||
'curvature': n.curvature,
|
||
'hash_value': n.hash_value,
|
||
'strain_signature': n.strain_signature
|
||
}
|
||
for n in self.nodes
|
||
],
|
||
'edges': self.edges,
|
||
'material': {
|
||
'youngs_modulus': self.material.youngs_modulus,
|
||
'yield_strength': self.material.yield_strength,
|
||
'density': self.material.density
|
||
},
|
||
'requirements': {
|
||
'target_load': self.req.target_load,
|
||
'safety_factor': self.req.safety_factor,
|
||
'lift_height': self.req.lift_height
|
||
},
|
||
'cryptographic': {
|
||
'merkle_root': self.merkle_root,
|
||
'merkle_tree_levels': len(self.merkle_tree),
|
||
'nodes_hashed': len(self.nodes),
|
||
'thermodynamic_unforgeable': True,
|
||
'verification_method': 'SHA-256 merkle tree on manifold topology'
|
||
},
|
||
'anti_fraud': {
|
||
'physical_hash_encoding': self.req.physical_hash_encoding,
|
||
'encoding_method': self.req.hash_encoding_method,
|
||
'delivery_verification': self.req.delivery_verification,
|
||
'insurance_fraud_prevention': self.req.insurance_fraud_prevention,
|
||
'encoding_spec': self.encode_hash_to_physical()
|
||
},
|
||
'magnetic_detection': {
|
||
'enabled': self.req.magnetic_detection,
|
||
'conductor': self.req.magnetic_conductor,
|
||
'sweep_frequency': self.req.magnetic_sweep_frequency,
|
||
'sensitivity': self.req.magnetic_sensitivity,
|
||
'collapse_signature': self.req.collapse_magnetic_signature
|
||
},
|
||
'piezo_alarm': {
|
||
'enabled': self.req.piezo_alarm,
|
||
'type': self.req.piezo_type,
|
||
'resonant_frequency': self.req.piezo_resonant_frequency,
|
||
'contact_failure_threshold': self.req.contact_failure_threshold
|
||
},
|
||
'weather_resistance': {
|
||
'enabled': self.req.weather_resistance,
|
||
'min_operating_temp': self.req.min_operating_temp,
|
||
'max_operating_temp': self.req.max_operating_temp,
|
||
'humidity_resistance': self.req.humidity_resistance,
|
||
'corrosion_resistance': self.req.corrosion_resistance
|
||
}
|
||
}
|
||
|
||
with open(output_file, 'w') as f:
|
||
json.dump(geometry, f, indent=2)
|
||
|
||
print(f"\nGeometry exported to: {output_file}")
|
||
|
||
if __name__ == "__main__":
|
||
# Define requirements
|
||
req = JackRequirements()
|
||
|
||
# Create manifold jack design
|
||
print("Initializing Semitruck Manifold Jack Design...")
|
||
jack = SemitruckManifoldJack(req)
|
||
|
||
print(f"Generated 3D manifold topology:")
|
||
print(f" Nodes: {len(jack.nodes)}")
|
||
print(f" Edges: {len(jack.edges)}")
|
||
print(f" Using FAMM frustration physics and manifold-generalized Bernoulli")
|
||
|
||
# Optimize and evaluate
|
||
optimization = jack.optimize_geometry()
|
||
|
||
# Export geometry
|
||
output_file = "/home/allaun/Documents/Research Stack/5-Applications/text-to-cad/models/semitruck_manifold_jack.json"
|
||
jack.export_geometry(output_file)
|
||
|
||
print("\nSemitruck manifold jack design complete!")
|