Crash and stress damage system: Difference between revisions

(→‎How to install the current system on an aircraft: Updated for better performance.)
Line 24: Line 24:
#
#
#
#
# Version 0.16
# Version 0.18
#
#
# License:
# License:
Line 169: Line 169:
    }
    }


    var prop = me.fdm.wingsFailureID;
    me.prop = me.fdm.wingsFailureID;
    var actuator_wings = set_unserviceable_cascading(prop, modes);
    me.actuator_wings = set_unserviceable_cascading(me.prop, modes);
    FailureMgr.add_failure_mode(prop, "Main wings", actuator_wings);
    FailureMgr.add_failure_mode(me.prop, "Main wings", me.actuator_wings);
},
},
# set the stresslimit for the main wings
# set the stresslimit for the main wings
setStressLimit: func (stressLimit = nil) {
setStressLimit: func (stressLimit = nil) {
if (stressLimit != nil) {
if (stressLimit != nil) {
var wingloadMax = stressLimit['wingloadMaxLbs'];
me.wingloadMax = stressLimit['wingloadMaxLbs'];
var wingloadMin = stressLimit['wingloadMinLbs'];
me.wingloadMin = stressLimit['wingloadMinLbs'];
var maxG = stressLimit['maxG'];
me.maxG = stressLimit['maxG'];
var minG = stressLimit['minG'];
me.minG = stressLimit['minG'];
var weight = stressLimit['weightLbs'];
me.weight = stressLimit['weightLbs'];
if(wingloadMax != nil) {
if(me.wingloadMax != nil) {
me.wingLoadLimitUpper = wingloadMax;
me.wingLoadLimitUpper = me.wingloadMax;
} elsif (maxG != nil and weight != nil) {
} elsif (me.maxG != nil and me.weight != nil) {
me.wingLoadLimitUpper = maxG * weight;
me.wingLoadLimitUpper = me.maxG * me.weight;
}
}


if(wingloadMin != nil) {
if(me.wingloadMin != nil) {
me.wingLoadLimitLower = wingloadMin;
me.wingLoadLimitLower = me.wingloadMin;
} elsif (minG != nil and weight != nil) {
} elsif (me.minG != nil and me.weight != nil) {
me.wingLoadLimitLower = minG * weight;
me.wingLoadLimitLower = me.minG * me.weight;
} elsif (me.wingLoadLimitUpper != nil) {
} elsif (me.wingLoadLimitUpper != nil) {
me.wingLoadLimitLower = -me.wingLoadLimitUpper * 0.4;#estimate for when lower is not specified
me.wingLoadLimitLower = -me.wingLoadLimitUpper * 0.4;#estimate for when lower is not specified
Line 201: Line 201:
# repair the aircaft
# repair the aircaft
repair: func () {
repair: func () {
var failure_modes = FailureMgr._failmgr.failure_modes;
me.failure_modes = FailureMgr._failmgr.failure_modes;
var mode_list = keys(failure_modes);
me.mode_list = keys(me.failure_modes);


foreach(var failure_mode_id; mode_list) {
foreach(var failure_mode_id; me.mode_list) {
FailureMgr.set_failure_level(failure_mode_id, 0);
FailureMgr.set_failure_level(failure_mode_id, 0);
}
}
Line 228: Line 228:
},
},
_identifyGears: func (gears) {
_identifyGears: func (gears) {
var contacts = props.globals.getNode("/gear").getChildren("gear");
me.contacts = props.globals.getNode("/gear").getChildren("gear");


foreach(var contact; contacts) {
foreach(var contact; me.contacts) {
var index = contact.getIndex();
me.index = contact.getIndex();
var isGear = me._contains(gears, index);
me.isGear = me._contains(gears, me.index);
var wow = contact.getChild("wow");
me.wow = contact.getChild("wow");
if (isGear == TRUE) {
if (me.isGear == TRUE) {
append(me.wowGear, wow);
append(me.wowGear, me.wow);
} else {
} else {
append(me.wowStructure, wow);
append(me.wowStructure, me.wow);
}
}
}
}
Line 275: Line 275:
return FALSE;
return FALSE;
}
}
var time = me.fdm.input.simTime.getValue();
me.time = me.fdm.input.simTime.getValue();
if (time != nil and time > 1) {
if (me.time != nil and me.time > 1) {
return TRUE;
return TRUE;
}
}
Line 282: Line 282:
},
},
_calcGroundSpeed: func () {
_calcGroundSpeed: func () {
   var realSpeed = me.fdm.getSpeedRelGround();
   me.realSpeed = me.fdm.getSpeedRelGround();


   return realSpeed;
   return me.realSpeed;
},
},
_impactDamage: func () {
_impactDamage: func () {
    var lat = me.input.lat.getValue();
    me.lat = me.input.lat.getValue();
var lon = me.input.lon.getValue();
me.lon = me.input.lon.getValue();
var info = geodinfo(lat, lon);
me.info = geodinfo(me.lat, me.lon);
var solid = info == nil?TRUE:(info[1] == nil?TRUE:info[1].solid);
me.solid = me.info == nil?TRUE:(me.info[1] == nil?TRUE:me.info[1].solid);
var speed = me._calcGroundSpeed();
me.speed = me._calcGroundSpeed();


if (me.exploded == FALSE) {
if (me.exploded == FALSE) {
var failure_modes = FailureMgr._failmgr.failure_modes;
me.failure_modes = FailureMgr._failmgr.failure_modes;
    var mode_list = keys(failure_modes);
    me.mode_list = keys(me.failure_modes);
    var probability = (speed * speed) / 40000.0;# 200kt will fail everything, 0kt will fail nothing.
    me.probability = (me.speed * me.speed) / 40000.0;# 200kt will fail everything, 0kt will fail nothing.
     
     
    var hitStr = "something";
    me.hitStr = "something";
    if(info != nil and info[1] != nil) {
    if(me.info != nil and me.info[1] != nil) {
    hitStr = info[1].names == nil?"something":info[1].names[0];
    me.hitStr = me.info[1].names == nil?"something":me.info[1].names[0];
    foreach(infoStr; info[1].names) {
    foreach(infoStr; me.info[1].names) {
    if(find('_', infoStr) == -1) {
    if(find('_', infoStr) == -1) {
    hitStr = infoStr;
    me.hitStr = infoStr;
    break;
    break;
    }
    }
Line 309: Line 309:
}
}
    # test for explosion
    # test for explosion
    if(probability > 0.766 and me.fdm.input.fuel.getValue() > 2500) {
    if(me.probability > 0.766 and me.fdm.input.fuel.getValue() > 2500) {
    # 175kt+ and fuel in tanks will explode the aircraft on impact.
    # 175kt+ and fuel in tanks will explode the aircraft on impact.
    me.input.simCrashed.setBoolValue(TRUE);
    me.input.simCrashed.setBoolValue(TRUE);
    me._explodeBegin("Aircraft hit "~hitStr~".");
    me._explodeBegin("Aircraft hit "~me.hitStr~".");
    return;
    return;
    }
    }


    foreach(var failure_mode_id; mode_list) {
    foreach(var failure_mode_id; me.mode_list) {
    if(rand() < probability) {
    if(rand() < me.probability) {
      FailureMgr.set_failure_level(failure_mode_id, 1);
      FailureMgr.set_failure_level(failure_mode_id, 1);
      }
      }
    }
    }


var str = "Aircraft hit "~hitStr~".";
me.str = "Aircraft hit "~me.hitStr~".";
me._output(str);
me._output(me.str);
} elsif (solid == TRUE) {
} elsif (me.solid == TRUE) {
# The aircraft is burning and will ignite the ground
# The aircraft is burning and will ignite the ground
if(me.input.wildfire.getValue() == TRUE) {
if(me.input.wildfire.getValue() == TRUE) {
var pos= geo.Coord.new().set_latlon(lat, lon);
me.pos= geo.Coord.new().set_latlon(me.lat, me.lon);
wildfire.ignite(pos, 1);
wildfire.ignite(me.pos, 1);
}
}
}
}
if(solid == TRUE) {
if(me.solid == TRUE) {
me._impactSoundBegin(speed);
me._impactSoundBegin(me.speed);
} else {
} else {
me._impactSoundWaterBegin(speed);
me._impactSoundWaterBegin(me.speed);
}
}
},
},
Line 358: Line 358:
me.input.explodeOn.setBoolValue(TRUE);
me.input.explodeOn.setBoolValue(TRUE);
me.exploded = TRUE;
me.exploded = TRUE;
var failure_modes = FailureMgr._failmgr.failure_modes;
me.failure_modes = FailureMgr._failmgr.failure_modes;
    var mode_list = keys(failure_modes);
    me.mode_list = keys(me.failure_modes);


    foreach(var failure_mode_id; mode_list) {
    foreach(var failure_mode_id; me.mode_list) {
       FailureMgr.set_failure_level(failure_mode_id, 1);
       FailureMgr.set_failure_level(failure_mode_id, 1);
    }
    }
Line 386: Line 386:
},
},
_output: func (str, override = FALSE) {
_output: func (str, override = FALSE) {
var time = me.fdm.input.simTime.getValue();
me.time = me.fdm.input.simTime.getValue();
if (override == TRUE or (time - me.lastMessageTime) > 3) {
if (override == TRUE or (me.time - me.lastMessageTime) > 3) {
me.lastMessageTime = time;
me.lastMessageTime = me.time;
print(str);
print(str);
screen.log.write(str, 0.7098, 0.5372, 0.0);# solarized yellow
screen.log.write(str, 0.7098, 0.5372, 0.0);# solarized yellow
Line 399: Line 399:
_testWaterImpact: func () {
_testWaterImpact: func () {
if(me.input.altAgl.getValue() < 0) {
if(me.input.altAgl.getValue() < 0) {
var lat = me.input.lat.getValue();
me.lat = me.input.lat.getValue();
var lon = me.input.lon.getValue();
me.lon = me.input.lon.getValue();
var info = geodinfo(lat, lon);
me.info = geodinfo(me.lat, me.lon);
var solid = info==nil?TRUE:(info[1] == nil?TRUE:info[1].solid);
me.solid = me.info==nil?TRUE:(me.info[1] == nil?TRUE:me.info[1].solid);
if(solid == FALSE) {
if(me.solid == FALSE) {
me._impactDamage();
me._impactDamage();
}
}
Line 410: Line 410:
_testStress: func () {
_testStress: func () {
if (me._isRunning() == TRUE and me.wingsAttached == TRUE) {
if (me._isRunning() == TRUE and me.wingsAttached == TRUE) {
var gForce = me.fdm.input.Nz.getValue() == nil?1:me.fdm.input.Nz.getValue();
me.gForce = me.fdm.input.Nz.getValue() == nil?1:me.fdm.input.Nz.getValue();
var weight = me.fdm.input.weight.getValue();
me.weight = me.fdm.input.weight.getValue();
var wingload = gForce * weight;
me.wingload = me.gForce * me.weight;


var broken = FALSE;
me.broken = FALSE;


if(wingload < 0) {
if(me.wingload < 0) {
broken = me._testWingload(-wingload, -me.wingLoadLimitLower);
me.broken = me._testWingload(-me.wingload, -me.wingLoadLimitLower);
if(broken == TRUE) {
if(me.broken == TRUE) {
me._stressDamage("negative");
me._stressDamage("negative");
}
}
} else {
} else {
broken = me._testWingload(wingload, me.wingLoadLimitUpper);
me.broken = me._testWingload(me.wingload, me.wingLoadLimitUpper);
if(broken == TRUE) {
if(me.broken == TRUE) {
me._stressDamage("positive");
me._stressDamage("positive");
}
}
Line 433: Line 433:
}
}
},
},
_testWingload: func (wingload, wingLoadLimit) {
_testWingload: func (wingloadCurr, wingLoadLimit) {
if (wingload > (wingLoadLimit * 0.5)) {
if (wingloadCurr > (wingLoadLimit * 0.5)) {
#me.input.trembleOn.setValue(1);
#me.input.trembleOn.setValue(1);
var tremble_max = math.sqrt((wingload - (wingLoadLimit * 0.5)) / (wingLoadLimit * 0.5));
me.tremble_max = math.sqrt((wingloadCurr - (wingLoadLimit * 0.5)) / (wingLoadLimit * 0.5));
#me.input.trembleMax.setDoubleValue(1);
#me.input.trembleMax.setDoubleValue(1);


if (wingload > (wingLoadLimit * 0.75)) {
if (wingloadCurr > (wingLoadLimit * 0.75)) {


#tremble_max = math.sqrt((wingload - (wingLoadLimit * 0.5)) / (wingLoadLimit * 0.5));
#me.tremble_max = math.sqrt((wingloadCurr - (wingLoadLimit * 0.5)) / (wingLoadLimit * 0.5));
me.input.creakVol.setDoubleValue(tremble_max);
me.input.creakVol.setDoubleValue(me.tremble_max);
me.input.creakOn.setBoolValue(TRUE);
me.input.creakOn.setBoolValue(TRUE);


if (wingload > (wingLoadLimit * 0.90)) {
if (wingloadCurr > (wingLoadLimit * 0.90)) {
me.input.crackOn.setBoolValue(TRUE);
me.input.crackOn.setBoolValue(TRUE);
me.input.crackVol.setDoubleValue(tremble_max);
me.input.crackVol.setDoubleValue(me.tremble_max);
if (wingload > wingLoadLimit) {
if (wingloadCurr > wingLoadLimit) {
me.input.crackVol.setDoubleValue(1);
me.input.crackVol.setDoubleValue(1);
me.input.creakVol.setDoubleValue(1);
me.input.creakVol.setDoubleValue(1);
Line 492: Line 492:
},
},
fps2kt: func (fps) {
fps2kt: func (fps) {
return fps * 0.5924838;
return fps * FPS2KT;
},
},
getSpeedRelGround: func () {
getSpeedRelGround: func () {
Line 506: Line 506:
fuel:      "fdm/jsbsim/propulsion/total-fuel-lbs",
fuel:      "fdm/jsbsim/propulsion/total-fuel-lbs",
simTime:    "fdm/jsbsim/simulation/sim-time-sec",
simTime:    "fdm/jsbsim/simulation/sim-time-sec",
vgFps:     "fdm/jsbsim/velocities/vg-fps",
northFps:   "velocities/speed-north-fps",
downFps:    "fdm/jsbsim/velocities/v-down-fps",
eastFps:    "velocities/speed-east-fps",
downFps:    "velocities/speed-down-fps",
Nz:        "fdm/jsbsim/accelerations/Nz",
Nz:        "fdm/jsbsim/accelerations/Nz",
},
},
getSpeedRelGround: func () {
getSpeedRelGround: func () {
var horzSpeed = me.fps2kt(me.input.vgFps.getValue());
me.northSpeed = me.input.northFps.getValue();
   var vertSpeed = me.fps2kt(me.input.downFps.getValue());
me.eastSpeed  = me.input.eastFps.getValue();
   var realSpeed = math.sqrt((horzSpeed * horzSpeed) + (vertSpeed * vertSpeed));
me.horzSpeed  = math.sqrt((me.eastSpeed * me.eastSpeed) + (me.northSpeed * me.northSpeed));
   me.vertSpeed = me.input.downFps.getValue();
   me.realSpeed = me.fps2kt(math.sqrt((me.horzSpeed * me.horzSpeed) + (me.vertSpeed * me.vertSpeed)));


   return realSpeed;
   return me.realSpeed;
},
},
wingsFailureID: "fdm/jsbsim/structural/wings",
wingsFailureID: "fdm/jsbsim/structural/wings",
Line 526: Line 529:
fuel:      "consumables/fuel/total-fuel-lbs",
fuel:      "consumables/fuel/total-fuel-lbs",
simTime:    "sim/time/elapsed-sec",
simTime:    "sim/time/elapsed-sec",
vgFps:     "velocities/groundspeed-kt",
northFps:   "velocities/speed-north-fps",
eastFps:    "velocities/speed-east-fps",
downFps:    "velocities/speed-down-fps",
downFps:    "velocities/speed-down-fps",
Nz:        "accelerations/n-z-cg-fps_sec",
Nz:        "accelerations/n-z-cg-fps_sec",
},
},
getSpeedRelGround: func () {
getSpeedRelGround: func () {
var horzSpeed = me.input.vgFps.getValue();
me.northSpeed = me.input.northFps.getValue();
  var vertSpeed = me.fps2kt(me.input.downFps.getValue());
me.eastSpeed  = me.input.eastFps.getValue();
   var realSpeed = math.sqrt((horzSpeed * horzSpeed) + (vertSpeed * vertSpeed));
me.horzSpeed  = math.sqrt((me.eastSpeed * me.eastSpeed) + (me.northSpeed * me.northSpeed));
  me.vertSpeed  = me.input.downFps.getValue();
   me.realSpeed = me.fps2kt(math.sqrt((me.horzSpeed * me.horzSpeed) + (me.vertSpeed * me.vertSpeed)));


   return realSpeed;
   return me.realSpeed;
},
},
wingsFailureID: "structural/wings",
wingsFailureID: "structural/wings",
Line 553: Line 559:
# example uses:
# example uses:
#
#
# var crashCode = CrashAndStress.new([0,1,2];  
# var crashCode = CrashAndStress.new([0,1,2]);  
#
#
# var crashCode = CrashAndStress.new([0,1,2], {"weightLbs":30000, "maxG": 12});
# var crashCode = CrashAndStress.new([0,1,2], {"weightLbs":30000, "maxG": 12});
574

edits