{"id":24960,"date":"2026-10-23T01:44:40","date_gmt":"2026-10-23T01:44:40","guid":{"rendered":"https:\/\/www.mechstream.com\/?p=24960"},"modified":"2026-10-23T01:44:42","modified_gmt":"2026-10-23T01:44:42","slug":"material-fatigue-life-s-n-calculator","status":"publish","type":"post","link":"https:\/\/www.mechstream.com\/pt\/material-fatigue-life-s-n-calculator\/","title":{"rendered":"Material Fatigue Life (S\u2013N) Calculator"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">The Material Fatigue Life (S\u2013N) Calculator is a practical engineering tool designed to estimate material fatigue life under cyclic loading conditions. Based on the Basquin stress-life equation, this calculator helps engineers determine the estimated number of cycles to failure using stress amplitude, fatigue strength coefficient, and fatigue strength exponent. It also provides S\u2013N curve visualization to help users understand the relationship between cyclic stress and material durability. Ideal for mechanical engineers, material scientists, and product designers, the Material Fatigue Life (S\u2013N) Calculator supports preliminary fatigue analysis, material evaluation, and component design optimization. Improve engineering efficiency and make informed decisions with accurate formula-based fatigue life estimates.<\/p>\n\n\n\n<div id=\"snc-calculator\" class=\"snc-root\" data-snc-widget=\"material-fatigue-life-sn\">\n<style>\n#snc-calculator,#snc-calculator *,#snc-calculator *::before,#snc-calculator *::after{box-sizing:border-box}\n#snc-calculator{\n  --snc-bg:#ffffff;--snc-card:#ffffff;--snc-navy:#1f2937;--snc-text:#2d3748;--snc-muted:#5a6578;--snc-soft:#7c8798;\n  --snc-line:#cfd7e2;--snc-line-soft:#e3e8ef;--snc-panel:#f6f8fb;--snc-accent:#1d64c8;--snc-accent-dark:#154c9a;--snc-accent-soft:#e8f0fb;\n  --snc-err:#b42318;--snc-err-soft:#fdecea;--snc-warn:#7a5200;--snc-warn-soft:#fff6e0;--snc-ok:#11734b;--snc-ok-soft:#e8f6ef;\n  display:block;width:100%;max-width:1120px;margin:24px auto;padding:0;background:var(--snc-bg);color:var(--snc-text);\n  font-family:-apple-system,BlinkMacSystemFont,\"Segoe UI\",Roboto,\"Helvetica Neue\",Arial,sans-serif;\n  font-size:16px;line-height:1.55;font-weight:400;letter-spacing:normal;text-transform:none;text-indent:0;word-spacing:normal;-webkit-font-smoothing:antialiased;text-align:left;position:relative\n}\n#snc-calculator .snc-wrap{container-type:inline-size;container-name:snc;width:100%}\n#snc-calculator h1,#snc-calculator h2,#snc-calculator h3,#snc-calculator h4,#snc-calculator p,#snc-calculator ul,#snc-calculator ol,#snc-calculator li,#snc-calculator dl,#snc-calculator dt,#snc-calculator dd,#snc-calculator figure,#snc-calculator figcaption,#snc-calculator details,#snc-calculator summary,#snc-calculator fieldset,#snc-calculator legend,#snc-calculator label,#snc-calculator header,#snc-calculator section,#snc-calculator article,#snc-calculator form{\n  margin:0;padding:0;border:0;background:none;color:inherit;font-family:inherit;font-size:inherit;font-weight:inherit;font-style:normal;line-height:inherit;text-indent:0;text-transform:none;letter-spacing:normal;text-shadow:none;box-shadow:none;float:none;width:auto;max-width:none;min-width:0\n}\n#snc-calculator ul,#snc-calculator ol{list-style:none}\n#snc-calculator a{color:var(--snc-accent);text-decoration:underline}\n#snc-calculator sub,#snc-calculator sup{font-size:.72em;line-height:0;position:relative;vertical-align:baseline}\n#snc-calculator sub{bottom:-.25em}\n#snc-calculator sup{top:-.5em}\n#snc-calculator svg{display:block;max-width:none;height:auto;overflow:visible}\n#snc-calculator [hidden]{display:none!important}\n#snc-calculator .snc-sr{position:absolute!important;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0}\n#snc-calculator .snc-card{background:var(--snc-card);border:1px solid var(--snc-line-soft);border-radius:16px;padding:22px;box-shadow:0 1px 2px rgba(31,41,55,.04),0 4px 14px rgba(31,41,55,.04);min-width:0}\n#snc-calculator .snc-card-title{color:var(--snc-navy);font-size:18px;font-weight:650;line-height:1.3;margin:0 0 4px}\n#snc-calculator .snc-card-note{color:var(--snc-muted);font-size:14px;margin:0 0 16px}\n#snc-calculator .snc-main{display:grid;grid-template-columns:minmax(0,1fr);gap:18px}\n#snc-calculator .snc-group{border-top:1px solid var(--snc-line-soft);padding-top:16px;margin-top:18px}\n#snc-calculator .snc-group-title{display:block;font-size:13px;font-weight:700;letter-spacing:.04em;text-transform:uppercase;color:var(--snc-muted);margin:0 0 12px}\n#snc-calculator .snc-grid{display:grid;grid-template-columns:minmax(0,1fr);gap:14px 16px}\n#snc-calculator .snc-field{min-width:0;position:relative}\n#snc-calculator .snc-span{grid-column:1\/-1}\n#snc-calculator .snc-label-row{display:flex;align-items:center;gap:6px;margin:0 0 6px;min-height:22px}\n#snc-calculator .snc-label{display:inline;font-size:14px;font-weight:600;color:var(--snc-navy);line-height:1.3;margin:0}\n#snc-calculator .snc-opt{color:var(--snc-soft);font-weight:400;font-size:12.8px;margin-left:2px}\n#snc-calculator .snc-tip{-webkit-appearance:none;appearance:none;display:inline-flex;align-items:center;justify-content:center;flex:0 0 20px;width:20px;height:20px;min-width:0;min-height:0;margin:0;padding:0;border-radius:50%;border:1px solid var(--snc-line);background:#fff;color:var(--snc-accent);font:inherit;font-size:12px;font-weight:700;line-height:1;cursor:help;box-shadow:none;text-transform:none}\n#snc-calculator .snc-tip:hover,#snc-calculator .snc-tip[aria-expanded=\"true\"]{background:var(--snc-accent-soft);border-color:#b9cff0}\n#snc-calculator .snc-tip:focus-visible{outline:3px solid rgba(29,100,200,.4);outline-offset:2px}\n#snc-calculator .snc-tip-text{display:none;position:absolute;left:0;right:0;top:30px;z-index:20;padding:10px 12px;border-radius:10px;background:#1f2937;color:#f8fafc;font-size:13px;font-weight:400;line-height:1.45;box-shadow:0 6px 20px rgba(15,23,42,.22)}\n#snc-calculator .snc-field.snc-tip-open .snc-tip-text{display:block}\n#snc-calculator .snc-hint{display:block;color:var(--snc-soft);font-size:12.7px;margin-top:5px;line-height:1.45}\n#snc-calculator .snc-hint:empty{display:none}\n#snc-calculator .snc-error{display:block;color:var(--snc-err);font-size:13px;margin-top:4px;line-height:1.4}\n#snc-calculator .snc-error:empty{display:none}\n#snc-calculator .snc-row{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:8px;align-items:stretch}\n#snc-calculator .snc-unit{display:inline-flex;align-items:center;justify-content:center;min-width:64px;min-height:46px;padding:0 12px;border-radius:10px;background:#eef2f7;color:var(--snc-muted);font-size:14px;font-weight:600;white-space:nowrap}\n#snc-calculator input[type=number],#snc-calculator input[type=text],#snc-calculator select{\n  -webkit-appearance:none;appearance:none;display:block;width:100%;min-height:46px;height:auto;margin:0;padding:10px 14px;font:inherit;font-size:16px;line-height:1.3;\n  color:var(--snc-text);background-color:#fff;border:1px solid var(--snc-line);border-radius:10px;box-shadow:none;outline:none;max-width:none;transition:border-color .15s ease,box-shadow .15s ease\n}\n#snc-calculator select{padding-right:36px;background-image:linear-gradient(45deg,transparent 50%,#5a6578 50%),linear-gradient(135deg,#5a6578 50%,transparent 50%);background-position:calc(100% - 19px) 20px,calc(100% - 14px) 20px;background-size:5px 5px,5px 5px;background-repeat:no-repeat;cursor:pointer}\n#snc-calculator input[type=number]:focus,#snc-calculator input[type=text]:focus,#snc-calculator select:focus{border-color:var(--snc-accent);box-shadow:0 0 0 4px rgba(29,100,200,.18)}\n#snc-calculator input::placeholder{color:#a3adbb;opacity:1}\n#snc-calculator .snc-invalid{border-color:var(--snc-err)!important;box-shadow:0 0 0 3px rgba(180,35,24,.12)!important}\n#snc-calculator .snc-actions{display:flex;justify-content:center;margin-top:22px}\n#snc-calculator .snc-btn{-webkit-appearance:none;appearance:none;display:inline-flex;align-items:center;justify-content:center;gap:6px;min-height:46px;min-width:0;margin:0;padding:10px 20px;border-radius:999px;border:1px solid var(--snc-line);background:#fff;color:var(--snc-navy);font:inherit;font-size:15px;font-weight:600;line-height:1.2;cursor:pointer;text-decoration:none;text-transform:none;letter-spacing:normal;box-shadow:none;width:auto;height:auto;transition:background .15s,border-color .15s,color .15s}\n#snc-calculator .snc-btn:hover{background:#f3f6fa;border-color:#b8c3d2;color:var(--snc-navy)}\n#snc-calculator .snc-btn-primary{min-width:160px;padding:10px 32px;background:var(--snc-accent);border-color:var(--snc-accent);color:#fff}\n#snc-calculator .snc-btn-primary:hover{background:var(--snc-accent-dark);border-color:var(--snc-accent-dark);color:#fff}\n#snc-calculator .snc-btn:focus-visible{outline:3px solid rgba(29,100,200,.4);outline-offset:2px}\n#snc-calculator .snc-btn:disabled{opacity:.5;cursor:not-allowed}\n#snc-calculator .snc-form-msg{color:var(--snc-err);font-size:13.8px;margin-top:10px;min-height:1.3em}\n#snc-calculator .snc-results:focus{outline:none}\n#snc-calculator .snc-stale{margin:0 0 12px;padding:10px 13px;border-radius:10px;background:var(--snc-warn-soft);color:#5c4300;font-size:13.3px;border:1px solid #f0dca6}\n#snc-calculator .snc-is-stale .snc-dim{opacity:.5;transition:opacity .2s}\n#snc-calculator .snc-hero{border-radius:14px;padding:18px 20px;background:var(--snc-accent-soft);border:1px solid #c9dbf3;min-width:0}\n#snc-calculator .snc-hero.snc-hero-bad{background:var(--snc-err-soft);border-color:#f3c4bf}\n#snc-calculator .snc-hero-label{font-size:13.5px;font-weight:600;color:var(--snc-muted);line-height:1.35}\n#snc-calculator .snc-hero-value{font-size:clamp(26px,3.4vw,34px);font-weight:700;color:var(--snc-navy);letter-spacing:-.01em;line-height:1.2;margin-top:4px;overflow-wrap:anywhere}\n#snc-calculator .snc-hero-sub{font-size:13px;color:var(--snc-muted);margin-top:4px;line-height:1.45;overflow-wrap:anywhere}\n#snc-calculator .snc-kpis{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:10px;margin-top:12px}\n#snc-calculator .snc-kpi{background:var(--snc-panel);border:1px solid var(--snc-line-soft);border-radius:12px;padding:12px 14px;min-width:0}\n#snc-calculator .snc-kpi-label{font-size:12.8px;font-weight:600;color:var(--snc-muted);line-height:1.3}\n#snc-calculator .snc-kpi-value{font-size:clamp(17px,2vw,20px);font-weight:700;color:var(--snc-navy);margin-top:3px;line-height:1.25;overflow-wrap:anywhere}\n#snc-calculator .snc-kpi-value.snc-na{color:var(--snc-soft);font-size:15.5px;font-weight:600}\n#snc-calculator .snc-kpi-sub{font-size:12.3px;color:var(--snc-muted);margin-top:3px;line-height:1.4;overflow-wrap:anywhere}\n#snc-calculator .snc-pill{display:inline-block;padding:2px 10px;border-radius:999px;font-size:15px;font-weight:700;line-height:1.5}\n#snc-calculator .snc-pass{background:var(--snc-ok-soft);color:var(--snc-ok)}\n#snc-calculator .snc-fail{background:var(--snc-err-soft);color:var(--snc-err)}\n#snc-calculator .snc-formula{margin-top:12px;padding:11px 14px;border-radius:10px;background:var(--snc-panel);border:1px dashed var(--snc-line);font-size:13.6px;color:var(--snc-text);overflow-wrap:anywhere;line-height:1.55}\n#snc-calculator .snc-warns{margin-top:12px;display:grid;gap:8px}\n#snc-calculator .snc-warn{padding:10px 13px;border-radius:10px;font-size:13.4px;line-height:1.5;border:1px solid var(--snc-line-soft);background:var(--snc-panel);color:var(--snc-text)}\n#snc-calculator .snc-warn strong{font-weight:700}\n#snc-calculator .snc-warn-e{background:var(--snc-err-soft);border-color:#f3c4bf;color:#7a1a12}\n#snc-calculator .snc-warn-w{background:var(--snc-warn-soft);border-color:#f0dca6;color:#5c4300}\n#snc-calculator .snc-warn-i{background:#f1f6fd;border-color:#d4e2f6;color:#23406b}\n#snc-calculator .snc-interp{margin-top:12px;font-size:13.8px;color:var(--snc-muted);line-height:1.6}\n@container snc (min-width:520px){\n  #snc-calculator .snc-grid{grid-template-columns:repeat(2,minmax(0,1fr))}\n}\n@container snc (min-width:880px){\n  #snc-calculator .snc-kpis{grid-template-columns:repeat(4,minmax(0,1fr))}\n}\n@media (max-width:700px){\n  #snc-calculator{margin:12px auto}\n  #snc-calculator .snc-card{padding:18px 15px;border-radius:14px}\n}\n@media (max-width:380px){\n  #snc-calculator .snc-kpis{grid-template-columns:minmax(0,1fr)}\n}\n@media (prefers-reduced-motion:reduce){#snc-calculator *{transition:none!important}}\n@media print{#snc-calculator .snc-actions,#snc-calculator .snc-tip{display:none!important}}\n<\/style>\n<div class=\"snc-wrap\">\n<div class=\"snc-main\">\n<form class=\"snc-card snc-inputs\" id=\"snc-form\" novalidate aria-labelledby=\"snc-h-in\">\n<h2 class=\"snc-card-title\" id=\"snc-h-in\">Input Parameters<\/h2>\n<p class=\"snc-card-note\">Constant-amplitude loading. Use \u03c3<sub>f<\/sub>&#8242; and b fitted to fatigue data for your material and condition.<\/p>\n<div class=\"snc-grid\">\n<div class=\"snc-field\">\n<div class=\"snc-label-row\"><label class=\"snc-label\" for=\"snc-unit\">Stress Unit<\/label><button type=\"button\" class=\"snc-tip\" aria-label=\"About the stress unit\" aria-describedby=\"snc-unit-tip\" aria-expanded=\"false\">i<\/button><\/div>\n<span class=\"snc-tip-text\" id=\"snc-unit-tip\" role=\"tooltip\">Unit for every stress field and result. Changing it converts the values already entered. Calculations run internally in MPa.<\/span>\n<select id=\"snc-unit\" name=\"unit\">\n<option value=\"MPa\" selected>MPa<\/option>\n<option value=\"Pa\">Pa<\/option>\n<option value=\"ksi\">ksi<\/option>\n<option value=\"psi\">psi<\/option>\n<\/select>\n<\/div>\n<div class=\"snc-field\">\n<div class=\"snc-label-row\"><label class=\"snc-label\" for=\"snc-name\">Material Name<\/label><button type=\"button\" class=\"snc-tip\" aria-label=\"About the material name\" aria-describedby=\"snc-name-tip\" aria-expanded=\"false\">i<\/button><\/div>\n<span class=\"snc-tip-text\" id=\"snc-name-tip\" role=\"tooltip\">A label for your report. It does not select any properties: the calculation uses only the coefficients you enter.<\/span>\n<input id=\"snc-name\" name=\"name\" type=\"text\" maxlength=\"80\" autocomplete=\"off\" aria-describedby=\"snc-name-err\">\n<span class=\"snc-error\" id=\"snc-name-err\" aria-live=\"polite\"><\/span>\n<\/div>\n<\/div>\n<div class=\"snc-group\">\n<span class=\"snc-group-title\">Required<\/span>\n<div class=\"snc-grid\">\n<div class=\"snc-field snc-span\">\n<div class=\"snc-label-row\"><label class=\"snc-label\" for=\"snc-sa\">Alternating Stress Amplitude (\u03c3<sub>a<\/sub>)<\/label><button type=\"button\" class=\"snc-tip\" aria-label=\"About stress amplitude\" aria-describedby=\"snc-sa-tip\" aria-expanded=\"false\">i<\/button><\/div>\n<span class=\"snc-tip-text\" id=\"snc-sa-tip\" role=\"tooltip\">Half of the stress range in one cycle, \u03c3a = (\u03c3max \u2212 \u03c3min)\/2. It is the main driver of fatigue damage. Leave blank to derive it from \u03c3max and \u03c3min below.<\/span>\n<div class=\"snc-row\"><input id=\"snc-sa\" name=\"sa\" type=\"number\" inputmode=\"decimal\" step=\"any\" placeholder=\"e.g. 250\" aria-describedby=\"snc-sa-hint snc-sa-err\"><span class=\"snc-unit snc-ulabel\" aria-hidden=\"true\">MPa<\/span><\/div>\n<span class=\"snc-hint\" id=\"snc-sa-hint\">Must be greater than zero. Optional only if \u03c3max and \u03c3min are both entered.<\/span>\n<span class=\"snc-error\" id=\"snc-sa-err\" aria-live=\"polite\"><\/span>\n<\/div>\n<div class=\"snc-field\">\n<div class=\"snc-label-row\"><label class=\"snc-label\" for=\"snc-sf\">Fatigue Strength Coefficient (\u03c3<sub>f<\/sub>&#8242;)<\/label><button type=\"button\" class=\"snc-tip\" aria-label=\"About the fatigue strength coefficient\" aria-describedby=\"snc-sf-tip\" aria-expanded=\"false\">i<\/button><\/div>\n<span class=\"snc-tip-text\" id=\"snc-sf-tip\" role=\"tooltip\">Intercept of the Basquin fit: the stress amplitude extrapolated to one reversal (2Nf = 1). Take it from fatigue test data or a documented reference curve for your material, heat treatment and surface condition.<\/span>\n<div class=\"snc-row\"><input id=\"snc-sf\" name=\"sf\" type=\"number\" inputmode=\"decimal\" step=\"any\" placeholder=\"from material data\" aria-describedby=\"snc-sf-err\"><span class=\"snc-unit snc-ulabel\" aria-hidden=\"true\">MPa<\/span><\/div>\n<span class=\"snc-error\" id=\"snc-sf-err\" aria-live=\"polite\"><\/span>\n<\/div>\n<div class=\"snc-field\">\n<div class=\"snc-label-row\"><label class=\"snc-label\" for=\"snc-b\">Fatigue Strength Exponent (b)<\/label><button type=\"button\" class=\"snc-tip\" aria-label=\"About the fatigue strength exponent\" aria-describedby=\"snc-b-tip\" aria-expanded=\"false\">i<\/button><\/div>\n<span class=\"snc-tip-text\" id=\"snc-b-tip\" role=\"tooltip\">Slope of the S\u2013N line on log\u2013log axes. Always negative; for metals it commonly lies between about \u22120.05 and \u22120.15. A smaller magnitude gives a flatter curve, so life is more sensitive to stress.<\/span>\n<div class=\"snc-row\"><input id=\"snc-b\" name=\"b\" type=\"number\" inputmode=\"decimal\" step=\"any\" placeholder=\"e.g. \u22120.09\" aria-describedby=\"snc-b-err\"><span class=\"snc-unit\" aria-hidden=\"true\">\u2013<\/span><\/div>\n<span class=\"snc-error\" id=\"snc-b-err\" aria-live=\"polite\"><\/span>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"snc-group\">\n<span class=\"snc-group-title\">Optional: Stress Cycle<\/span>\n<div class=\"snc-grid\">\n<div class=\"snc-field\">\n<div class=\"snc-label-row\"><label class=\"snc-label\" for=\"snc-smax\">Maximum Stress (\u03c3<sub>max<\/sub>)<\/label><button type=\"button\" class=\"snc-tip\" aria-label=\"About maximum stress\" aria-describedby=\"snc-smax-tip\" aria-expanded=\"false\">i<\/button><\/div>\n<span class=\"snc-tip-text\" id=\"snc-smax-tip\" role=\"tooltip\">Highest stress in the cycle (tension positive). With \u03c3min it gives the mean stress \u03c3m and stress ratio R, and a check on the entered \u03c3a.<\/span>\n<div class=\"snc-row\"><input id=\"snc-smax\" name=\"smax\" type=\"number\" inputmode=\"decimal\" step=\"any\" aria-describedby=\"snc-smax-err\"><span class=\"snc-unit snc-ulabel\" aria-hidden=\"true\">MPa<\/span><\/div>\n<span class=\"snc-error\" id=\"snc-smax-err\" aria-live=\"polite\"><\/span>\n<\/div>\n<div class=\"snc-field\">\n<div class=\"snc-label-row\"><label class=\"snc-label\" for=\"snc-smin\">Minimum Stress (\u03c3<sub>min<\/sub>)<\/label><button type=\"button\" class=\"snc-tip\" aria-label=\"About minimum stress\" aria-describedby=\"snc-smin-tip\" aria-expanded=\"false\">i<\/button><\/div>\n<span class=\"snc-tip-text\" id=\"snc-smin-tip\" role=\"tooltip\">Lowest stress in the cycle (compression negative). For fully reversed loading \u03c3min = \u2212\u03c3max and R = \u22121.<\/span>\n<div class=\"snc-row\"><input id=\"snc-smin\" name=\"smin\" type=\"number\" inputmode=\"decimal\" step=\"any\" aria-describedby=\"snc-smin-hint snc-smin-err\"><span class=\"snc-unit snc-ulabel\" aria-hidden=\"true\">MPa<\/span><\/div>\n<span class=\"snc-hint\" id=\"snc-smin-hint\">Enter both values or leave both blank.<\/span>\n<span class=\"snc-error\" id=\"snc-smin-err\" aria-live=\"polite\"><\/span>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"snc-group\">\n<span class=\"snc-group-title\">Optional: Reference and Target<\/span>\n<div class=\"snc-grid\">\n<div class=\"snc-field\">\n<div class=\"snc-label-row\"><label class=\"snc-label\" for=\"snc-sut\">Ultimate Tensile Strength (S<sub>ut<\/sub>)<\/label><button type=\"button\" class=\"snc-tip\" aria-label=\"About ultimate tensile strength\" aria-describedby=\"snc-sut-tip\" aria-expanded=\"false\">i<\/button><\/div>\n<span class=\"snc-tip-text\" id=\"snc-sut-tip\" role=\"tooltip\">Used only as a reference to check whether the peak stress is plausible for an S\u2013N (high-cycle, nominally elastic) analysis. It does not change the calculated life.<\/span>\n<div class=\"snc-row\"><input id=\"snc-sut\" name=\"sut\" type=\"number\" inputmode=\"decimal\" step=\"any\" aria-describedby=\"snc-sut-err\"><span class=\"snc-unit snc-ulabel\" aria-hidden=\"true\">MPa<\/span><\/div>\n<span class=\"snc-error\" id=\"snc-sut-err\" aria-live=\"polite\"><\/span>\n<\/div>\n<div class=\"snc-field\">\n<div class=\"snc-label-row\"><label class=\"snc-label\" for=\"snc-target\">Target Number of Cycles<\/label><button type=\"button\" class=\"snc-tip\" aria-label=\"About the target number of cycles\" aria-describedby=\"snc-target-tip\" aria-expanded=\"false\">i<\/button><\/div>\n<span class=\"snc-tip-text\" id=\"snc-target-tip\" role=\"tooltip\">Required design life. The calculator compares the predicted life with it and reports the stress utilization \u03c3a \/ \u03c3a,allow, where \u03c3a,allow is the Basquin stress amplitude at the target life.<\/span>\n<div class=\"snc-row\"><input id=\"snc-target\" name=\"target\" type=\"number\" inputmode=\"decimal\" step=\"any\" placeholder=\"e.g. 1e6\" aria-describedby=\"snc-target-hint snc-target-err\"><span class=\"snc-unit\" aria-hidden=\"true\">cycles<\/span><\/div>\n<span class=\"snc-hint\" id=\"snc-target-hint\">Scientific notation is accepted, for example 1e6.<\/span>\n<span class=\"snc-error\" id=\"snc-target-err\" aria-live=\"polite\"><\/span>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"snc-actions\">\n<button type=\"submit\" class=\"snc-btn snc-btn-primary\" id=\"snc-calc\">Calculate<\/button>\n<\/div>\n<p class=\"snc-form-msg\" id=\"snc-form-msg\" aria-live=\"polite\"><\/p>\n<\/form>\n<section class=\"snc-card snc-results\" id=\"snc-results\" aria-labelledby=\"snc-h-res\" tabindex=\"-1\" hidden>\n<h2 class=\"snc-card-title\" id=\"snc-h-res\">Calculation Results<\/h2>\n<p class=\"snc-card-note\">Basquin stress-life estimate for constant-amplitude loading.<\/p>\n<div id=\"snc-res-body\">\n<p class=\"snc-stale\" id=\"snc-stale\" role=\"status\" hidden>Inputs have changed. Select Calculate to update these results.<\/p>\n<div class=\"snc-dim\">\n<div class=\"snc-hero\" id=\"snc-hero\">\n<div class=\"snc-hero-label\">Estimated Fatigue Life (N<sub>f<\/sub>)<\/div>\n<div class=\"snc-hero-value\" id=\"snc-r-life\"><\/div>\n<div class=\"snc-hero-sub\" id=\"snc-r-life-sub\"><\/div>\n<\/div>\n<div class=\"snc-kpis\" id=\"snc-kpis\"><\/div>\n<p class=\"snc-formula\" id=\"snc-r-formula\"><\/p>\n<div class=\"snc-warns\" id=\"snc-warns\"><\/div>\n<p class=\"snc-interp\" id=\"snc-interp\"><\/p>\n<\/div>\n<\/div>\n<p class=\"snc-sr\" id=\"snc-live\" aria-live=\"polite\"><\/p>\n<\/section>\n<\/div>\n<\/div>\n<script>\n(function () {\n  \"use strict\";\n  \/* =====================================================================\n     CONSTANTS\n     All stresses are handled internally in MPa.\n     ===================================================================== *\/\n  var UNITS = { MPa: 1, Pa: 1e-6, ksi: 6.894757, psi: 0.006894757 }; \/* multiply a value in the unit by this to get MPa *\/\n  var STRESS_LIMIT_MPA = 20000;   \/* sanity limit for any entered stress magnitude *\/\n  var LOG_CAP = 20;               \/* results above 10^20 cycles are reported as out of range *\/\n  var MAX_TARGET = 1e15;\n  var DEFAULTS = { unit: \"MPa\", name: \"Generic Steel\", sa: \"\", sf: \"\", b: \"\", smax: \"\", smin: \"\", sut: \"\", target: \"\" };\n  var LOG10E = 1 \/ Math.LN10;\n  function log10(x) { return Math.log(x) * LOG10E; }\n  \/* =====================================================================\n     FORMATTING HELPERS\n     ===================================================================== *\/\n  function isNum(v) { return typeof v === \"number\" ? isFinite(v) : false; }\n  var SUP = { \"0\": \"\u2070\", \"1\": \"\u00b9\", \"2\": \"\u00b2\", \"3\": \"\u00b3\", \"4\": \"\u2074\", \"5\": \"\u2075\", \"6\": \"\u2076\", \"7\": \"\u2077\", \"8\": \"\u2078\", \"9\": \"\u2079\", \"-\": \"\u207b\" };\n  function sup(n) { return String(n).split(\"\").map(function (c) { return SUP[c] || c; }).join(\"\"); }\n  function minus(s) { return String(s).replace(\/^-\/, \"\u2212\"); }\n  \/* Number with `sig` significant digits; scientific notation for very large or small magnitudes *\/\n  function fmtSig(v, sig) {\n    if (!isNum(v)) { return \"\u2014\"; }\n    if (v === 0) { return \"0\"; }\n    var a = Math.abs(v), neg = v < 0, s;\n    if (a >= 1e6 ? true : a < 1e-3) {\n      var e = Math.floor(log10(a)), m = Number((a \/ Math.pow(10, e)).toPrecision(sig));\n      if (m >= 10) { m = m \/ 10; e += 1; }\n      s = m.toFixed(Math.max(0, sig - 1)).replace(\/\\.?0+$\/, \"\") + \" \u00d7 10\" + sup(e);\n    } else {\n      var r = Number(a.toPrecision(sig));\n      var dec = Math.max(0, sig - 1 - Math.floor(log10(r) + 1e-12));\n      s = r.toLocaleString(\"en-US\", { minimumFractionDigits: 0, maximumFractionDigits: dec });\n    }\n    return (neg ? \"\u2212\" : \"\") + s;\n  }\n  \/* Cycle count from its base-10 logarithm (avoids overflow for very large lives) *\/\n  function fmtCyclesL(L) {\n    if (!isNum(L)) { return \"\u2014\"; }\n    if (L < 4) {\n      var N = Math.pow(10, L);\n      return N < 10 ? fmtSig(N, 3) : Math.round(N).toLocaleString(\"en-US\");\n    }\n    var e = Math.floor(L), m = Number(Math.pow(10, L - e).toFixed(2));\n    if (m >= 10) { m = 1; e += 1; }\n    return m.toFixed(2) + \" \u00d7 10\" + sup(e);\n  }\n  function fmtCycles(N) { return fmtCyclesL(log10(N)); }\n  function toUnit(vMPa, u) { return vMPa \/ UNITS[u]; }\n  function fmtS(vMPa, u) { return isNum(vMPa) ? fmtSig(toUnit(vMPa, u), 4) + \" \" + u : \"\u2014\"; }\n  function fmtPct(v) { return fmtSig(v * 100, 3) + \"%\"; }\n  function esc(s) { return String(s).replace(\/[&<>\"']\/g, function (c) { return { \"&\": \"&amp;\", \"<\": \"&lt;\", \">\": \"&gt;\", '\"': \"&quot;\", \"'\": \"&#39;\" }[c]; }); }\n  \/* =====================================================================\n     ENGINE (pure function, no DOM)\n     inp: { unit, name, sa, sf, b, smax, smin, sut, target } with stresses in MPa, blanks as null\n     ===================================================================== *\/\n  function compute(inp) {\n    var u = inp.unit, r = { inp: inp, warn: [] };\n    function W(level, text) { r.warn.push({ level: level, text: text }); }\n    \/* --- stress cycle --- *\/\n    r.hasMM = inp.smax !== null ? inp.smin !== null : false;\n    if (r.hasMM) {\n      r.aMM = (inp.smax - inp.smin) \/ 2;               \/* \u03c3a = (\u03c3max \u2212 \u03c3min)\/2 *\/\n      r.m = (inp.smax + inp.smin) \/ 2;                 \/* \u03c3m = (\u03c3max + \u03c3min)\/2 *\/\n      if (r.m === 0) { r.m = 0; }\n      r.R = inp.smax !== 0 ? inp.smin \/ inp.smax : null; \/* R = \u03c3min\/\u03c3max, undefined when \u03c3max = 0 *\/\n    } else { r.aMM = null; r.m = null; r.R = null; }\n    if (inp.sa !== null) { r.amp = inp.sa; r.ampSrc = \"direct\"; }\n    else { r.amp = r.aMM; r.ampSrc = \"derived\"; }\n    \/* --- Basquin: Nf = \u00bd (\u03c3a\/\u03c3f\u2032)^(1\/b), evaluated in log10 form --- *\/\n    r.L = log10(0.5) + log10(r.amp \/ inp.sf) \/ inp.b;\n    r.status = r.L < 0 ? \"lt1\" : (r.L > LOG_CAP ? \"over\" : \"ok\");\n    r.N = r.status === \"ok\" ? Math.pow(10, r.L) : null;\n    r.sN1 = inp.sf * Math.pow(2, inp.b);                \/* stress amplitude at Nf = 1 *\/\n    \/* --- target life --- *\/\n    r.hasTarget = inp.target !== null;\n    if (r.hasTarget) {\n      r.Lt = log10(inp.target);\n      r.allow = inp.sf * Math.pow(2 * inp.target, inp.b); \/* \u03c3a,allow at the target life *\/\n      r.util = r.amp \/ r.allow;\n      r.pass = r.L >= r.Lt;\n      r.ratioL = r.L - r.Lt;                            \/* log10(Nf \/ Ntarget) *\/\n    }\n    \/* --- warnings --- *\/\n    if (r.status === \"lt1\") {\n      W(\"e\", \"At this stress amplitude the Basquin fit predicts failure in less than one cycle (\u03c3a is above \u03c3f\u2032\u00b72\u1d47 = \" + fmtS(r.sN1, u) + \"). The model is not valid here: the material may fail statically or by low-cycle fatigue.\");\n    } else if (r.status === \"over\") {\n      W(\"e\", \"The predicted life exceeds 10\u00b2\u2070 cycles, which is outside the supported numerical range and far beyond any fatigue test data. Treat this as an extrapolation without engineering meaning.\");\n    } else if (r.L < 3) {\n      W(\"w\", \"Predicted life is below about 10\u00b3 cycles, in the low-cycle fatigue range where plastic strain is usually significant. A strain-life (\u03b5\u2013N) approach is more appropriate.\");\n    } else if (r.L < 4) {\n      W(\"i\", \"Predicted life is between 10\u00b3 and 10\u2074 cycles, near the transition between low- and high-cycle fatigue. Check whether local stresses stay elastic; if not, consider a strain-life (\u03b5\u2013N) approach.\");\n    }\n    if (r.status === \"ok\" ? r.L > 7 : false) {\n      W(\"w\", \"Predicted life exceeds 10\u2077 cycles. Check that \u03c3f\u2032 and b were fitted to data covering this life; otherwise the result is an extrapolation. Some materials (for example many steels) show a fatigue limit, while others (for example aluminum alloys) keep weakening at long lives.\");\n    }\n    if (inp.b < -0.2 ? true : inp.b > -0.03) {\n      W(\"w\", \"b = \" + minus(inp.b) + \" is outside the range commonly reported for metals (about \u22120.05 to \u22120.15). Check the value, its sign and that it comes from the same fit as \u03c3f\u2032.\");\n    }\n    if (r.hasMM) {\n      if (inp.sa !== null) {\n        var big = Math.max(Math.abs(inp.sa), Math.abs(r.aMM));\n        if (Math.abs(inp.sa - r.aMM) > 0.01 * big) {\n          W(\"w\", \"The entered \u03c3a (\" + fmtS(inp.sa, u) + \") does not match (\u03c3max \u2212 \u03c3min)\/2 = \" + fmtS(r.aMM, u) + \". The directly entered \u03c3a is used for the life calculation. Check the inputs.\");\n        }\n      } else {\n        W(\"i\", \"\u03c3a was derived from (\u03c3max \u2212 \u03c3min)\/2 = \" + fmtS(r.aMM, u) + \".\");\n      }\n      var mRel = r.amp > 0 ? Math.abs(r.m) \/ r.amp : 0;\n      if (r.m > 0 ? mRel > 0.05 : false) {\n        W(\"w\", \"Tensile mean stress \u03c3m = \" + fmtS(r.m, u) + \" (\" + fmtPct(mRel) + \" of \u03c3a). No mean-stress correction is applied. If \u03c3f\u2032 and b come from fully reversed (R = \u22121) tests, the predicted life is likely non-conservative. A validated correction (for example Morrow or Smith\u2013Watson\u2013Topper) with suitable material parameters may be required.\");\n      } else if (r.m < 0 ? mRel > 0.05 : false) {\n        W(\"i\", \"Compressive mean stress \u03c3m = \" + fmtS(r.m, u) + \". Compressive mean stress is usually beneficial, but no credit is taken for it and no correction is applied.\");\n      }\n    } else {\n      W(\"i\", \"\u03c3max and \u03c3min were not entered, so mean stress and R are unknown. The result assumes \u03c3a is appropriate for the loading conditions of the \u03c3f\u2032 and b data (usually fully reversed, R = \u22121).\");\n    }\n    if (inp.sut !== null) {\n      var peak = r.hasMM ? Math.max(Math.abs(inp.smax), Math.abs(inp.smin)) : r.amp;\n      r.peak = peak;\n      if (peak >= inp.sut) {\n        W(\"e\", \"Peak stress (\" + fmtS(peak, u) + \") is at or above Sut (\" + fmtS(inp.sut, u) + \"). Static failure is expected; the S\u2013N estimate does not apply.\");\n      } else {\n        W(\"i\", \"Peak stress is \" + fmtPct(peak \/ inp.sut) + \" of Sut\" + (r.hasMM ? \"\" : \" (fully reversed loading assumed)\") + \". The stress-life method assumes nominally elastic stresses; if the peak stress exceeds the yield strength, use a strain-life (\u03b5\u2013N) approach.\");\n      }\n      if (inp.sf < inp.sut) {\n        W(\"w\", \"\u03c3f\u2032 is lower than Sut. For many metals \u03c3f\u2032 is close to or above the true fracture strength, which exceeds Sut. Check that \u03c3f\u2032 is entered in the selected unit and comes from the same fit as b.\");\n      }\n    }\n    if (r.hasTarget) {\n      if (!r.pass) {\n        W(\"e\", \"Predicted life is below the target of \" + fmtCycles(inp.target) + \" cycles. At the target life the Basquin curve allows \u03c3a = \" + fmtS(r.allow, u) + \" (utilization \" + fmtPct(r.util) + \").\");\n      }\n      if (inp.target > 1e7 ? true : inp.target < 1e3) {\n        W(\"i\", \"The target life lies outside about 10\u00b3\u201310\u2077 cycles, so the allowable stress at the target relies on extending the Basquin line; confirm it against data at that life.\");\n      }\n    }\n    return r;\n  }\n  \/* =====================================================================\n     UI  \/* =====================================================================\n     UI\n     ===================================================================== *\/\n  function init() {\n    var root = document.getElementById(\"snc-calculator\");\n    if (!root) { return; }\n    if (root.getAttribute(\"data-snc-init\") === \"1\") { return; }\n    root.setAttribute(\"data-snc-init\", \"1\");\n    root.sncEngine = { compute: compute, fmtCyclesL: fmtCyclesL };\n    function $(id) { return root.querySelector(\"#\" + id); }\n    function mk(tag, cls, text) { var n = document.createElement(tag); if (cls) { n.className = cls; } if (text !== undefined) { n.textContent = text; } return n; }\n    function clear(n) { while (n.firstChild) { n.removeChild(n.firstChild); } }\n    var el = {\n      form: $(\"snc-form\"), unit: $(\"snc-unit\"), name: $(\"snc-name\"), sa: $(\"snc-sa\"), sf: $(\"snc-sf\"), b: $(\"snc-b\"),\n      smax: $(\"snc-smax\"), smin: $(\"snc-smin\"), sut: $(\"snc-sut\"), target: $(\"snc-target\"),\n      formMsg: $(\"snc-form-msg\"),\n      results: $(\"snc-results\"), body: $(\"snc-res-body\"), stale: $(\"snc-stale\"), hero: $(\"snc-hero\"),\n      life: $(\"snc-r-life\"), lifeSub: $(\"snc-r-life-sub\"), kpis: $(\"snc-kpis\"), formula: $(\"snc-r-formula\"), warns: $(\"snc-warns\"), interp: $(\"snc-interp\"),\n      live: $(\"snc-live\")\n    };\n    var STRESS_FIELDS = [el.sa, el.sf, el.smax, el.smin, el.sut];\n    var state = { last: null, stale: false, lastUnit: \"MPa\" };\n    function unit() { return UNITS[el.unit.value] ? el.unit.value : \"MPa\"; }\n    \/* ---------- reading numbers ---------- *\/\n    function readNum(input) {\n      var s = String(input.value).trim().replace(\/\u2212\/g, \"-\");\n      if (s === \"\") { return (input.validity ? input.validity.badInput : false) ? NaN : null; }\n      var v = Number(s);\n      return isFinite(v) ? v : NaN;\n    }\n    function setVal(input, v) { input.value = (v === null ? true : v === \"\") ? \"\" : String(Number(Number(v).toPrecision(8))); }\n    \/* ---------- validation ---------- *\/\n    function setErr(input, msg) {\n      var e = $(input.id + \"-err\");\n      if (e) { e.textContent = msg || \"\"; }\n      if (msg) { input.classList.add(\"snc-invalid\"); input.setAttribute(\"aria-invalid\", \"true\"); }\n      else { input.classList.remove(\"snc-invalid\"); input.removeAttribute(\"aria-invalid\"); }\n      return !msg;\n    }\n    function numCheck(input, opts) {\n      var v = readNum(input);\n      if (v === null) { return opts.optional ? setErr(input, \"\") : setErr(input, opts.req); }\n      if (isNaN(v)) { return setErr(input, \"Enter a valid number.\"); }\n      return setErr(input, opts.check(v) || \"\");\n    }\n    function limitTxt() { return fmtS(STRESS_LIMIT_MPA, unit()); }\n    function stressRange(v) { return Math.abs(v * UNITS[unit()]) > STRESS_LIMIT_MPA ? \"The magnitude must not exceed \" + limitTxt() + \". Check the unit.\" : \"\"; }\n    function bothMM() { return readNum(el.smax) !== null ? readNum(el.smin) !== null : false; }\n    function vName() {\n      var s = String(el.name.value).trim();\n      return setErr(el.name, s === \"\" ? \"Enter a material name.\" : \"\");\n    }\n    function vSa() {\n      return numCheck(el.sa, { optional: bothMM(), req: \"Enter the stress amplitude, or enter both \u03c3max and \u03c3min.\", check: function (v) {\n        if (v <= 0) { return \"Stress amplitude must be greater than zero.\"; }\n        return stressRange(v);\n      } });\n    }\n    function vSf() {\n      return numCheck(el.sf, { req: \"Enter the fatigue strength coefficient from material data.\", check: function (v) {\n        if (v <= 0) { return \"The fatigue strength coefficient must be greater than zero.\"; }\n        return stressRange(v);\n      } });\n    }\n    function vB() {\n      return numCheck(el.b, { req: \"Enter the fatigue strength exponent (a negative number).\", check: function (v) {\n        if (v === 0) { return \"b cannot be zero.\"; }\n        if (v > 0) { return \"b must be negative. Enter it with a minus sign, for example \u22120.09.\"; }\n        if (v < -1) { return \"b below \u22121 is outside the plausible range for a Basquin fit. Check the value.\"; }\n        return \"\";\n      } });\n    }\n    function vSmax() {\n      var other = readNum(el.smin);\n      return numCheck(el.smax, { optional: other === null, req: \"Enter \u03c3max as well, or clear \u03c3min.\", check: stressRange });\n    }\n    function vSmin() {\n      var other = readNum(el.smax);\n      var ok = numCheck(el.smin, { optional: other === null, req: \"Enter \u03c3min as well, or clear \u03c3max.\", check: stressRange });\n      if (!ok) { return false; }\n      var a = readNum(el.smax), b = readNum(el.smin);\n      if (isNum(a) ? isNum(b) : false) {\n        if (b > a) { return setErr(el.smin, \"\u03c3min cannot be greater than \u03c3max.\"); }\n        if (b === a) { return setErr(el.smin, \"\u03c3max and \u03c3min are equal, so there is no alternating stress.\"); }\n      }\n      return true;\n    }\n    function vSut() {\n      return numCheck(el.sut, { optional: true, check: function (v) {\n        if (v <= 0) { return \"Sut must be greater than zero, or leave it blank.\"; }\n        return stressRange(v);\n      } });\n    }\n    function vTarget() {\n      return numCheck(el.target, { optional: true, check: function (v) {\n        if (v < 1) { return \"Enter at least 1 cycle, or leave it blank.\"; }\n        if (v > MAX_TARGET) { return \"Enter at most 10\u00b9\u2075 cycles.\"; }\n        return \"\";\n      } });\n    }\n    var VALIDATORS = {\n      \"snc-name\": vName, \"snc-sa\": vSa, \"snc-sf\": vSf, \"snc-b\": vB,\n      \"snc-smax\": function () { vSmax(); vSmin(); return vSa(); }, \"snc-smin\": function () { vSmax(); vSmin(); return vSa(); },\n      \"snc-sut\": vSut, \"snc-target\": vTarget\n    };\n    function validateAll() { var res = [vName(), vSa(), vSf(), vB(), vSmax(), vSmin(), vSut(), vTarget()]; return res.every(Boolean); }\n    function nOrNull(input) { var v = readNum(input); return isNum(v) ? v : null; }\n    function sMPa(input) { var v = nOrNull(input); return v === null ? null : v * UNITS[unit()]; }\n    function readInput() {\n      return {\n        unit: unit(), name: String(el.name.value).trim(), sa: sMPa(el.sa), sf: sMPa(el.sf), b: nOrNull(el.b),\n        smax: sMPa(el.smax), smin: sMPa(el.smin), sut: sMPa(el.sut), target: nOrNull(el.target)\n      };\n    }\n    function finiteResult(r) {\n      if (!isNum(r.amp) ? true : !isNum(r.L)) { return false; }\n      if (r.hasTarget ? !(isNum(r.allow) ? isNum(r.util) : false) : false) { return false; }\n      return true;\n    }\n    \/* ---------- unit labels and conversion ---------- *\/\n    function updateUnitLabels() {\n      var a = root.querySelectorAll(\".snc-ulabel\"), i, u = unit();\n      for (i = 0; i < a.length; i++) { a[i].textContent = u; }\n    }\n    function onUnit() {\n      var u = unit(), prev = state.lastUnit;\n      if (u === prev) { return; }\n      STRESS_FIELDS.forEach(function (input) {\n        var v = readNum(input);\n        if (isNum(v)) { setVal(input, v * UNITS[prev] \/ UNITS[u]); }\n      });\n      state.lastUnit = u;\n      updateUnitLabels();\n      [\"snc-sa\", \"snc-sf\", \"snc-smax\", \"snc-smin\", \"snc-sut\"].forEach(function (id) { if ($(id).classList.contains(\"snc-invalid\")) { VALIDATORS[id](); } });\n      if (state.last ? !state.stale : false) { run(false); }\n    }\n    \/* =====================================================================\n       RENDER RESULTS\n       ===================================================================== *\/\n    function kpi(label, value, sub, opts) {\n      var c = mk(\"div\", \"snc-kpi\");\n      c.appendChild(mk(\"div\", \"snc-kpi-label\", label));\n      var v = mk(\"div\", \"snc-kpi-value\" + ((opts ? opts.na : false) ? \" snc-na\" : \"\"));\n      if (opts ? opts.pill : false) { v.appendChild(mk(\"span\", \"snc-pill \" + opts.pill, value)); } else { v.textContent = value; }\n      c.appendChild(v);\n      if (sub) { c.appendChild(mk(\"div\", \"snc-kpi-sub\", sub)); }\n      return c;\n    }\n    function lifeText(r) {\n      if (r.status === \"lt1\") { return \"Less than 1 cycle\"; }\n      if (r.status === \"over\") { return \"More than 10\u00b2\u2070 cycles\"; }\n      return fmtCyclesL(r.L) + \" cycles\";\n    }\n    function targetText(r) {\n      if (!r.hasTarget) { return null; }\n      return r.pass ? \"Pass\" : \"Below Target\";\n    }\n    function interpretation(r) {\n      var inp = r.inp, u = inp.unit, nm = inp.name;\n      if (r.status === \"lt1\") { return \"For \" + nm + \", the entered stress amplitude lies above the range where the Basquin fit can give a meaningful life. No fatigue life is reported. Check the stress, the coefficients and the unit, and consider static strength and strain-life methods.\"; }\n      var t = \"For \" + nm + \", a constant stress amplitude of \" + fmtS(r.amp, u) + \" corresponds to about \" + (r.status === \"over\" ? \"more than 10\u00b2\u2070\" : fmtCyclesL(r.L)) + \" cycles to failure on the Basquin curve defined by \u03c3f\u2032 = \" + fmtS(inp.sf, u) + \" and b = \" + minus(inp.b) + \". \";\n      t += \"This is an engineering estimate based on the entered material parameters and the assumed loading, not a guaranteed service life. Fatigue lives scatter considerably at the same stress, and surface finish, size, notches, residual stress, mean stress and environment can change the actual life. \";\n      if (r.hasTarget) { t += r.pass ? \"The predicted life exceeds the target, but this alone does not demonstrate safe operation; apply the design factors and standards relevant to your application.\" : \"The predicted life is below the target, so the design needs a lower stress amplitude, better material data or a redesign.\"; }\n      return t;\n    }\n    function render(r, announce) {\n      var inp = r.inp, u = inp.unit;\n      state.last = r; setStale(false);\n      el.results.hidden = false;\n      \/* hero *\/\n      el.life.textContent = lifeText(r);\n      el.hero.className = \"snc-hero\" + (r.status === \"lt1\" ? \" snc-hero-bad\" : \"\");\n      el.lifeSub.textContent = r.status === \"ok\" ? \"\u2248 \" + fmtCyclesL(r.L + log10(2)) + \" reversals (2Nf) \u00b7 \" + inp.name : (r.status === \"lt1\" ? \"Outside the valid range of the Basquin model\" : \"Outside the supported numerical range\");\n      \/* KPIs *\/\n      clear(el.kpis);\n      el.kpis.appendChild(kpi(\"Alternating Stress Amplitude \u03c3a\", fmtS(r.amp, u), r.ampSrc === \"direct\" ? \"Entered directly\" : \"From (\u03c3max \u2212 \u03c3min) \/ 2\"));\n      el.kpis.appendChild(r.hasMM ? kpi(\"Mean Stress \u03c3m\", fmtS(r.m, u), \"(\u03c3max + \u03c3min) \/ 2 \u00b7 not corrected\") : kpi(\"Mean Stress \u03c3m\", \"Not available\", \"Enter \u03c3max and \u03c3min\", { na: true }));\n      el.kpis.appendChild(r.hasMM ? (r.R === null ? kpi(\"Stress Ratio R\", \"Undefined\", \"\u03c3max = 0, so R = \u03c3min\/\u03c3max cannot be computed\", { na: true }) : kpi(\"Stress Ratio R\", fmtSig(r.R, 3), r.R === -1 ? \"\u03c3min \/ \u03c3max \u00b7 fully reversed\" : \"\u03c3min \/ \u03c3max\")) : kpi(\"Stress Ratio R\", \"Not available\", \"Enter \u03c3max and \u03c3min\", { na: true }));\n      if (r.hasTarget) {\n        var sub = \"Target \" + fmtCycles(inp.target) + \" cycles \u00b7 \u03c3a,allow = \" + fmtS(r.allow, u) + \" \u00b7 utilization \" + fmtPct(r.util);\n        el.kpis.appendChild(kpi(\"Target Life Assessment\", targetText(r), sub, { pill: r.pass ? \"snc-pass\" : \"snc-fail\" }));\n      } else {\n        el.kpis.appendChild(kpi(\"Target Life Assessment\", \"Not assessed\", \"Enter a target number of cycles\", { na: true }));\n      }\n      var model = kpi(\"Calculation Model\", \"Basquin Stress-Life Model\", \"\u03c3a = \u03c3f\u2032(2Nf)^b; no mean-stress correction\");\n      model.className = \"snc-kpi snc-span\"; model.style.gridColumn = \"1\/-1\";\n      el.kpis.appendChild(model);\n      \/* formula *\/\n      el.formula.textContent = \"Nf = \u00bd \u00b7 (\u03c3a \/ \u03c3f\u2032)^(1\/b) = 0.5 \u00d7 (\" + fmtS(r.amp, u) + \" \/ \" + fmtS(inp.sf, u) + \")^(1 \/ \" + minus(inp.b) + \") = \" + lifeText(r);\n      \/* warnings *\/\n      clear(el.warns);\n      var order = { e: 0, w: 1, i: 2 }, head = { e: \"Warning: \", w: \"Caution: \", i: \"Note: \" };\n      r.warn.slice().sort(function (a, b) { return order[a.level] - order[b.level]; }).forEach(function (w) {\n        var d = mk(\"div\", \"snc-warn snc-warn-\" + w.level);\n        d.setAttribute(\"role\", w.level === \"e\" ? \"alert\" : \"note\");\n        d.appendChild(mk(\"strong\", \"\", head[w.level])); d.appendChild(document.createTextNode(w.text));\n        el.warns.appendChild(d);\n      });\n      el.interp.textContent = interpretation(r);\n      el.live.textContent = \"Estimated fatigue life: \" + lifeText(r) + (r.hasTarget ? \". Target assessment: \" + targetText(r) + \".\" : \".\");\n      if (announce) { focusResults(); }\n    }\n    function setStale(on) {\n      state.stale = on;\n      el.results.classList.toggle(\"snc-is-stale\", on);\n      el.stale.hidden = !on;\n    }\n    function focusResults() {\n      try { el.results.focus({ preventScroll: true }); } catch (e) { \/* ignore *\/ }\n      var rect = el.results.getBoundingClientRect(), vh = window.innerHeight || document.documentElement.clientHeight;\n      if (rect.top < 0 ? true : rect.top > vh * 0.6) { if (el.results.scrollIntoView) { el.results.scrollIntoView({ behavior: \"smooth\", block: \"start\" }); } }\n    }\n    \/* =====================================================================\n       CALCULATE\n       ===================================================================== *\/\n    function run(fromButton) {\n      el.formMsg.textContent = \"\";\n      var ok = validateAll();\n      if (!ok) {\n        if (fromButton) {\n          el.formMsg.textContent = \"Please correct the highlighted fields.\";\n          var first = root.querySelector(\".snc-invalid\");\n          if (first) { first.focus(); }\n        }\n        if (state.last) { setStale(true); }\n        return;\n      }\n      var r = compute(readInput());\n      if (!finiteResult(r)) {\n        el.formMsg.textContent = \"These inputs produce a result outside the numerical range. Check the values and units.\";\n        if (state.last) { setStale(true); }\n        return;\n      }\n      render(r, fromButton);\n    }\n    \/* =====================================================================\n       DEFAULTS\n       ===================================================================== *\/\n    function clearErrors() {\n      var all = root.querySelectorAll(\".snc-invalid\"), i;\n      for (i = 0; i < all.length; i++) { all[i].classList.remove(\"snc-invalid\"); all[i].removeAttribute(\"aria-invalid\"); }\n      var errs = root.querySelectorAll(\".snc-error\");\n      for (i = 0; i < errs.length; i++) { errs[i].textContent = \"\"; }\n      el.formMsg.textContent = \"\";\n    }\n    function applyValues(D) {\n      el.unit.value = D.unit; state.lastUnit = D.unit;\n      el.name.value = D.name;\n      setVal(el.sa, D.sa); setVal(el.sf, D.sf); setVal(el.b, D.b); setVal(el.smax, D.smax); setVal(el.smin, D.smin); setVal(el.sut, D.sut); setVal(el.target, D.target);\n      clearErrors(); updateUnitLabels();\n    }\n    \/* =====================================================================\n       TOOLTIPS\n       ===================================================================== *\/\n    function closeTips(except) {\n      var open = root.querySelectorAll(\".snc-tip-open\"), i;\n      for (i = 0; i < open.length; i++) {\n        if (open[i] !== except) { open[i].classList.remove(\"snc-tip-open\"); var bt = open[i].querySelector(\".snc-tip\"); if (bt) { bt.setAttribute(\"aria-expanded\", \"false\"); } }\n      }\n    }\n    function setTip(btn, on) {\n      var f = btn.closest ? btn.closest(\".snc-field\") : null;\n      if (!f) { return; }\n      if (on) { closeTips(f); f.classList.add(\"snc-tip-open\"); } else { f.classList.remove(\"snc-tip-open\"); }\n      btn.setAttribute(\"aria-expanded\", on ? \"true\" : \"false\");\n    }\n    var tips = root.querySelectorAll(\".snc-tip\");\n    Array.prototype.forEach.call(tips, function (btn) {\n      btn.addEventListener(\"click\", function (e) { e.preventDefault(); setTip(btn, btn.getAttribute(\"aria-expanded\") !== \"true\"); });\n      btn.addEventListener(\"pointerenter\", function (e) { if (e.pointerType === \"mouse\") { setTip(btn, true); } });\n      btn.addEventListener(\"pointerleave\", function (e) { if (e.pointerType === \"mouse\") { setTip(btn, false); } });\n      btn.addEventListener(\"blur\", function () { setTip(btn, false); });\n      btn.addEventListener(\"keydown\", function (e) { if (e.key === \"Escape\") { setTip(btn, false); } });\n    });\n    \/* =====================================================================\n       EVENTS\n       ===================================================================== *\/\n    el.form.addEventListener(\"submit\", function (e) { e.preventDefault(); run(true); });\n    el.form.addEventListener(\"input\", function (e) {\n      var t = e.target;\n      if (!t ? true : t === el.unit) { return; }\n      if (VALIDATORS[t.id]) { VALIDATORS[t.id](); }\n      if (state.last) { setStale(true); }\n    });\n    el.unit.addEventListener(\"change\", onUnit);\n    applyValues(DEFAULTS);\n  }\n  if (document.getElementById(\"snc-calculator\")) { init(); }\n  else if (document.readyState === \"loading\") { document.addEventListener(\"DOMContentLoaded\", init); }\n  else { init(); }\n})();\n<\/script>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>The Material Fatigue Life (S\u2013N) Calculator is a practical engineering tool designed to estimate material fatigue life under cyclic loading conditions. Based on the Basquin&#8230;<\/p>","protected":false},"author":2,"featured_media":24961,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"pmpro_default_level":"","_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_feature_clip_id":0,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_post_was_ever_published":false},"categories":[8647],"tags":[8754,8759,8758,8757,8760],"class_list":["post-24960","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-materials-science-and-properties","tag-fatigue-analysis","tag-fatigue-life-calculator","tag-material-fatigue-life","tag-s-n-curve","tag-stress-life-analysis","pmpro-has-access"],"acf":[],"jetpack_sharing_enabled":true,"jetpack_featured_media_url":"https:\/\/www.mechstream.com\/wp-content\/uploads\/2026\/10\/Material-Fatigue-Life-S\u2013N-Calculator.png","_links":{"self":[{"href":"https:\/\/www.mechstream.com\/pt\/wp-json\/wp\/v2\/posts\/24960","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.mechstream.com\/pt\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.mechstream.com\/pt\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.mechstream.com\/pt\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.mechstream.com\/pt\/wp-json\/wp\/v2\/comments?post=24960"}],"version-history":[{"count":0,"href":"https:\/\/www.mechstream.com\/pt\/wp-json\/wp\/v2\/posts\/24960\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.mechstream.com\/pt\/wp-json\/wp\/v2\/media\/24961"}],"wp:attachment":[{"href":"https:\/\/www.mechstream.com\/pt\/wp-json\/wp\/v2\/media?parent=24960"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.mechstream.com\/pt\/wp-json\/wp\/v2\/categories?post=24960"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.mechstream.com\/pt\/wp-json\/wp\/v2\/tags?post=24960"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}