<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Pls on Marius Gjerd</title><link>https://mariusgjerd.github.io/no/tags/pls/</link><description>Recent content in Pls on Marius Gjerd</description><generator>Hugo -- gohugo.io</generator><language>no</language><lastBuildDate>Sun, 26 Jul 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://mariusgjerd.github.io/no/tags/pls/index.xml" rel="self" type="application/rss+xml"/><item><title>Hva 4-20mA faktisk betyr (og hvorfor null ligger på 4)</title><link>https://mariusgjerd.github.io/no/posts/what-4-20ma-actually-means/</link><pubDate>Sun, 26 Jul 2026 00:00:00 +0000</pubDate><author>Marius Gjerd</author><guid>https://mariusgjerd.github.io/no/posts/what-4-20ma-actually-means/</guid><category>420ma</category><category>sensorer</category><category>pls</category><category>scada</category><category>datakvalitet</category><category>datalifecycle</category><description>Mesteparten av industriell sensordata reiser fortsatt som strøm mellom 4 og 20 milliampere. Hva signalet er, hvordan det blir et tall i databasen din, og måtene det kan være feil på uten at du merker det.</description><content:encoded><![CDATA[<p>Temperaturen i databasen din var på et tidspunkt en strøm i en kabel. Ikke i overført betydning. Faktiske milliampere gjennom kobber. Nesten alt koden din vet om en fysisk prosess har reist som strøm gjennom en kabel før det ble et tall, og reglene for den reisen ble skrevet på 1950-tallet.</p>
<p>Standarden heter 4-20mA. Den er gammel, den er analog, og den bærer fortsatt mesteparten av verdens industrielle sensordata. Jeg har trukket kablene for den som elektriker og brukt tallene fra den som utvikler, og de to jobbene lærte meg helt forskjellige ting om det samme signalet. Dette innlegget er det jeg skulle ønske utviklersiden visste.</p>
<aside class="terms-box">
  <p class="terms-title">Ordene i dette innlegget, i klarspråk</p>
  <ul>
<li><strong>Transmitter:</strong> måleomformeren som sitter på eller ved sensoren. Den gjør om råsignalet fra sensoren (for eksempel motstanden i en PT100) til et standardisert 4-20 mA-signal.</li>
<li><strong>PLS (programmerbar logisk styring):</strong> industridatamaskinen som kjører styringslogikken i et anlegg. Den leser innganger, kjører programmet sitt og setter utganger, om og om igjen, i sanntid. I dette innlegget er det analoginngangene dens vi bryr oss om.</li>
<li><strong>Spann:</strong> måleområdet transmitteren er konfigurert med, altså hvilke fysiske verdier 4 og 20 mA tilsvarer. For eksempel 0-200°C.</li>
<li><strong>Frekvensomformer:</strong> kraftelektronikk som styrer turtallet på en motor ved å variere frekvensen og spenningen motoren mates med. Står i alt fra vifter til pumper, og dukker opp igjen i støykapittelet lenger ned.</li>
</ul>

</aside>

<h2 id="hvorfor-null-ligger-på-4">Hvorfor null ligger på 4</h2>
<p>En 4-20mA-sensor fordeler måleområdet sitt over strømmen: 4 mA er bunnen av området, 20 mA er toppen. Måler den 0-200°C, tilsvarer 4 mA 0 grader og 20 mA 200 grader. Verdien din ligger et sted mellom, lineært skalert.</p>
<p>Det første alle lurer på: hvorfor ligger null på 4 og ikke på 0? Svaret er det smarteste i hele standarden. 0 mA er reservert for feil. En intakt sløyfe bærer alltid minst 4 mA, så hvis strømmen faller til null, er noe galt. Kabelbrudd, død transmitter, eller en sløyfe som har mistet forsyningen. Feildeteksjonen ligger i selve fysikken, og dermed kan ikke en død sensor utgi seg for å være et kaldt rør.</p>
<p>Det finnes en konvensjon som gjør dette presist, NAMUR NE43. Normal måleinformasjon ligger mellom 3,8 og 20,5 mA. Alt under 3,6 mA eller over 21,0 mA er feilsignal. Transmittere konfigureres til å drive strømmen enten høyt eller lavt når selve sensoren ryker (det kalles burnout-retning), og koden din må vite hvilken vei dine er satt opp. En sensor som feiler oppover ser nemlig helt lik ut som en prosess på vei mot overoppheting, hvis du insisterer på å lese den som en måling.</p>
<p>Så les databladet og vit hva du skal forvente. En verdi under 3,6 mA er ikke et iskaldt rør. Det er et kabelbrudd som melder fra om seg selv, på det eneste språket det har.</p>
<figure class="diagram">
  <svg viewBox="0 0 720 240" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="The 4-20 mA scale with every zone named. Below 3.6 mA and above 21 mA: fault signal. 3.6 to 3.8 and 20.5 to 21: dead band. 3.8 to 4 and 20 to 20.5: NAMUR NE43 margin. 4 to 20 mA: measurement range, mapped linearly to engineering units, here 0 to 200 degrees Celsius.">
  <style>
    .lbl { font-family: ui-sans-serif, system-ui, sans-serif; font-size: 13px; fill: var(--content, #333); }
    .sub { font-family: ui-sans-serif, system-ui, sans-serif; font-size: 12px; fill: var(--secondary, #666); }
    .leg { font-family: ui-sans-serif, system-ui, sans-serif; font-size: 11px; fill: var(--content, #333); }
    .fault-lbl { font-family: ui-sans-serif, system-ui, sans-serif; font-size: 12px; font-weight: 600; fill: #d64545; }
    .sig-lbl { font-family: ui-sans-serif, system-ui, sans-serif; font-size: 13px; font-weight: 600; fill: #ffffff; }
    .tick { stroke: var(--secondary, #666); stroke-width: 1; }
    .map { stroke: var(--border, #bbb); stroke-width: 1; stroke-dasharray: 4 4; }
  </style>

  <!-- mA bar: x = 40 + mA * (640/22) -->
  <rect x="40" y="60" width="104.7" height="28" fill="#d64545" rx="4"/>
  <rect x="144.7" y="60" width="5.8" height="28" fill="var(--border, #c8c8c8)"/>
  <rect x="636.3" y="60" width="14.6" height="28" fill="var(--border, #c8c8c8)"/>
  <rect x="150.5" y="60" width="5.8" height="28" fill="#2f6fdd" opacity="0.35"/>
  <rect x="621.8" y="60" width="14.5" height="28" fill="#2f6fdd" opacity="0.35"/>
  <rect x="156.4" y="60" width="465.4" height="28" fill="#2f6fdd"/>
  <rect x="650.9" y="60" width="29.1" height="28" fill="#d64545" rx="4"/>

  <text class="sig-lbl" x="389" y="79" text-anchor="middle">measurement range</text>
  <text class="fault-lbl" x="92" y="52" text-anchor="middle">fault: fail low</text>
  <text class="fault-lbl" x="655" y="52" text-anchor="end">fault: fail high</text>

  <!-- ticks and numbers -->
  <line class="tick" x1="40" y1="88" x2="40" y2="96"/>
  <text class="sub" x="40" y="110" text-anchor="middle">0 mA</text>
  <line class="tick" x1="144.7" y1="88" x2="144.7" y2="96"/>
  <text class="sub" x="138" y="110" text-anchor="middle">3.6</text>
  <line class="tick" x1="156.4" y1="88" x2="156.4" y2="96"/>
  <text class="sub" x="164" y="110" text-anchor="middle">4</text>
  <line class="tick" x1="389" y1="88" x2="389" y2="96"/>
  <text class="sub" x="389" y="110" text-anchor="middle">12</text>
  <line class="tick" x1="621.8" y1="88" x2="621.8" y2="96"/>
  <text class="sub" x="617" y="110" text-anchor="middle">20</text>
  <line class="tick" x1="650.9" y1="88" x2="650.9" y2="96"/>
  <text class="sub" x="655" y="110" text-anchor="middle">21</text>

  <!-- mapping to engineering units -->
  <line class="map" x1="156.4" y1="96" x2="156.4" y2="146"/>
  <line class="map" x1="389" y1="96" x2="389" y2="146"/>
  <line class="map" x1="621.8" y1="96" x2="621.8" y2="146"/>
  <line x1="156.4" y1="146" x2="621.8" y2="146" stroke="var(--content, #333)" stroke-width="1.5"/>
  <line class="tick" x1="156.4" y1="142" x2="156.4" y2="150"/>
  <line class="tick" x1="389" y1="142" x2="389" y2="150"/>
  <line class="tick" x1="621.8" y1="142" x2="621.8" y2="150"/>
  <text class="lbl" x="156.4" y="168" text-anchor="middle">0 &#176;C</text>
  <text class="lbl" x="389" y="168" text-anchor="middle">100 &#176;C</text>
  <text class="lbl" x="621.8" y="168" text-anchor="middle">200 &#176;C</text>
  <text class="sub" x="389" y="190" text-anchor="middle">what your code sees, after the span (here 0-200 &#176;C) is applied</text>

  <!-- legend: every zone named with its range -->
  <rect x="40" y="212" width="12" height="12" fill="#2f6fdd" rx="2"/>
  <text class="leg" x="58" y="222">measurement range (4-20 mA)</text>
  <rect x="222" y="212" width="12" height="12" fill="#2f6fdd" opacity="0.35" rx="2"/>
  <text class="leg" x="240" y="222">NE43 margin (3.8-4/20-20.5)</text>
  <rect x="404" y="212" width="12" height="12" fill="var(--border, #c8c8c8)" rx="2"/>
  <text class="leg" x="422" y="222">dead band (3.6-3.8/20.5-21)</text>
  <rect x="586" y="212" width="12" height="12" fill="#d64545" rx="2"/>
  <text class="leg" x="604" y="222">fault (&#60;3.6/&#62;21)</text>
</svg>
<figcaption>Hele skalaen i ett bilde: feilsoner utenfor 3,6 og 21 mA, NE43-marginene i svakt blått, dødbånd i grått mellom dem, og under: den lineære mappingen til fysiske verdier.</figcaption></figure>
<h2 id="hvorfor-strøm-og-ikke-spenning">Hvorfor strøm og ikke spenning</h2>
<p>To grunner. Den første: strømmen er lik i hele sløyfen. Et spenningssignal faller langs kabelen, og jo lengre kabel, jo større tap. Det problemet har ikke strøm. Sløyfen kan gå gjennom et halvt bygg, og milliamperene som kommer frem til tavlen er de samme som transmitteren sendte.</p>
<p>Den andre: en strømsløyfe tåler elektrisk støy mye bedre enn et spenningssignal. Og det er mye elektrisk støy i et industribygg. Mer om det lenger ned, der har jeg en historie.</p>
<p>Selve kablingen er nesten elegant. En typisk sløyfe består av bare to ledere, og de samme to lederne bærer både forsyningen (som regel 24 VDC) og signalet. Transmitteren sitter i sløyfen og regulerer hvor mye strøm den slipper gjennom. I andre enden måler analogkortet gjerne strømmen over en 250 ohm-motstand, som gjør 4-20 mA om til 1-5 V som kortet kan lese. To ledere, hundrevis av meter, forsyning og signal i samme par.</p>
<figure class="diagram">
  <svg viewBox="0 0 720 280" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="Multi-wire schematic of a 4-20 mA current loop with three separated components: a 24 VDC power supply on the left, a two-wire transmitter at the top center, and a PLC analog input on the right. The supply plus terminal feeds the transmitter plus terminal, the transmitter minus terminal feeds the analog input plus terminal, and the return wire runs from the analog input minus terminal back to the supply minus terminal. The same current flows in the whole loop.">
  <style>
    .wire { stroke: var(--content, #333); stroke-width: 2; fill: none; }
    .box { fill: var(--entry, #f6f6f6); stroke: var(--content, #333); stroke-width: 1.5; }
    .lbl { font-family: ui-sans-serif, system-ui, sans-serif; font-size: 14px; fill: var(--content, #333); }
    .sub { font-family: ui-sans-serif, system-ui, sans-serif; font-size: 12px; fill: var(--secondary, #666); }
    .pol { font-family: ui-sans-serif, system-ui, sans-serif; font-size: 13px; font-weight: 700; fill: var(--content, #333); }
    .sig { font-family: ui-sans-serif, system-ui, sans-serif; font-size: 13px; font-weight: 600; fill: #2f6fdd; }
    .term { fill: var(--content, #333); }
    .arrow { fill: #2f6fdd; }
  </style>

  <!-- transmitter, top center, separated from both -->
  <rect class="box" x="290" y="30" width="140" height="70" rx="6"/>
  <text class="lbl" x="360" y="59" text-anchor="middle">transmitter</text>
  <text class="sub" x="360" y="78" text-anchor="middle">+ sensor (2-wire)</text>
  <circle class="term" cx="320" cy="100" r="3.5"/>
  <text class="pol" x="306" y="118">+</text>
  <circle class="term" cx="400" cy="100" r="3.5"/>
  <text class="pol" x="406" y="118">&#8722;</text>

  <!-- power supply, left -->
  <rect class="box" x="40" y="110" width="140" height="110" rx="6"/>
  <text class="lbl" x="110" y="158" text-anchor="middle">24 VDC</text>
  <text class="sub" x="110" y="177" text-anchor="middle">power supply</text>
  <circle class="term" cx="180" cy="140" r="3.5"/>
  <text class="pol" x="166" y="132">+</text>
  <circle class="term" cx="180" cy="190" r="3.5"/>
  <text class="pol" x="166" y="184">&#8722;</text>

  <!-- PLC analog input, right -->
  <rect class="box" x="540" y="110" width="140" height="110" rx="6"/>
  <text class="lbl" x="610" y="150" text-anchor="middle">PLC analog input</text>
  <text class="sub" x="610" y="168" text-anchor="middle">250 &#937; &#8594; 1-5 V</text>
  <circle class="term" cx="540" cy="140" r="3.5"/>
  <text class="pol" x="548" y="132">AI+</text>
  <circle class="term" cx="540" cy="190" r="3.5"/>
  <text class="pol" x="548" y="184">AI&#8722;</text>

  <!-- wire: supply + to transmitter +, right-angle routing -->
  <polyline class="wire" points="180,140 320,140 320,100"/>
  <polygon class="arrow" points="240,134 256,140 240,146"/>
  <text class="sig" x="248" y="126" text-anchor="middle">4-20 mA</text>

  <!-- wire: transmitter - to PLC AI+ -->
  <polyline class="wire" points="400,100 400,140 540,140"/>
  <polygon class="arrow" points="462,134 478,140 462,146"/>

  <!-- return wire: PLC AI- to supply - -->
  <line class="wire" x1="540" y1="190" x2="180" y2="190"/>
  <polygon class="arrow" points="368,184 352,190 368,196"/>
  <text class="sub" x="360" y="210" text-anchor="middle">return</text>

  <!-- documentation -->
  <text class="sub" x="360" y="246" text-anchor="middle">cable: 2 x 0.75 mm&#178; shielded twisted pair, shield grounded at one end</text>
  <text class="sig" x="360" y="268" text-anchor="middle">series loop: the same 4-20 mA flows through every component</text>
</svg>
<figcaption>Én sløyfe, tre komponenter i serie. Transmitteren regulerer strømmen, og de samme milliamperene går gjennom alle punktene i sløyfen.</figcaption></figure>
<h2 id="fra-strøm-til-tall">Fra strøm til tall</h2>
<p>Det er spannet i transmitteren som bestemmer hvilket tall strømmen blir til. Spannet er det konfigurerte måleområdet, og transmitteren fordeler det lineært over 4-20 mA. Med et spann på 0-200°C betyr 12 mA 100 grader. Enkelt.</p>
<p>Og her er faren: spannet bor i transmitteren, ikke i koden din. Konfigurerer noen om området til 0-150°C uten å si fra nedstrøms, er alle verdiene i pipelinen din feilskalert fra det øyeblikket. I stillhet. Tallene ser fortsatt fornuftige ut, ingen feilmelding, ingen hull i dataene, bare en temperatur som ikke lenger er temperaturen. Endrer du et måleoppsett, må konfigurasjon og dokumentasjon følge hverandre, for den som bruker dataene tre systemer lenger ned har ingen annen måte å oppdage det på.</p>
<figure class="diagram">
  <svg viewBox="0 0 720 250" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="The same 12 mA current read against two different spans. With the transmitter's actual span of 0 to 150 degrees, 12 mA means 75 degrees. With the span your code assumes, 0 to 200 degrees, the same current computes to 100 degrees. The transmitter always wins.">
  <style>
    .lbl { font-family: ui-sans-serif, system-ui, sans-serif; font-size: 13px; fill: var(--content, #333); }
    .sub { font-family: ui-sans-serif, system-ui, sans-serif; font-size: 12px; fill: var(--secondary, #666); }
    .ok { font-family: ui-sans-serif, system-ui, sans-serif; font-size: 14px; font-weight: 700; fill: #2f6fdd; }
    .bad { font-family: ui-sans-serif, system-ui, sans-serif; font-size: 14px; font-weight: 700; fill: #d64545; }
    .track { fill: var(--border, #d8d8d8); opacity: 0.55; }
    .dash { stroke: var(--content, #333); stroke-width: 1.5; stroke-dasharray: 5 4; }
  </style>

  <!-- 12 mA line: x = 120 + (12-4)/16 * 500 = 370 -->
  <text class="lbl" x="370" y="26" text-anchor="middle" font-weight="700">the same 12 mA</text>
  <line class="dash" x1="370" y1="34" x2="370" y2="196"/>

  <!-- row 1: the transmitter's actual span -->
  <text class="lbl" x="120" y="52">span in the transmitter: 0-150 &#176;C</text>
  <rect class="track" x="120" y="60" width="500" height="22" rx="4"/>
  <circle cx="370" cy="71" r="6" fill="#2f6fdd"/>
  <text class="ok" x="384" y="76">= 75 &#176;C, what it sends</text>
  <text class="sub" x="120" y="100">4 mA = 0 &#176;C</text>
  <text class="sub" x="620" y="100" text-anchor="end">20 mA = 150 &#176;C</text>

  <!-- row 2: the span your code assumes -->
  <text class="lbl" x="120" y="140">span your code assumes: 0-200 &#176;C</text>
  <rect class="track" x="120" y="148" width="500" height="22" rx="4"/>
  <circle cx="370" cy="159" r="6" fill="#d64545"/>
  <text class="bad" x="384" y="164">= 100 &#176;C, what you compute</text>
  <text class="sub" x="120" y="188">4 mA = 0 &#176;C</text>
  <text class="sub" x="620" y="188" text-anchor="end">20 mA = 200 &#176;C</text>

  <text class="sub" x="370" y="226" text-anchor="middle">same current, two different temperatures. The transmitter always wins, silently.</text>
</svg>
<figcaption>Spann-problemet i ett bilde: strømmen er riktig, antagelsen er feil, og ingenting i dataene avslører det.</figcaption></figure>
<p>(Noen sløyfer kjører også HART, et digitalt signal oppå de samme to lederne, som kan bære diagnostikk og konfigurasjon. Verdt å vite om.)</p>
<p>Én ærlig fotnote om det aller siste steget. Inne i PLS-en gjør analogkortet strømmen om til rå heltallsverdier, counts, og programvare skalerer dem videre til fysiske enheter. Jeg har sett de rå verdiene i systemer jeg integrerer mot, og jeg har lært meg å ikke anta at jeg vet hvilken skalering som ligger bak. Selve omformerlaget har jeg ikke jobbet hands-on med ennå. Jeg begynner på industriell automasjon i høst, og det laget står høyt på listen. Når jeg har målt det selv, får det sitt eget innlegg.</p>
<h2 id="støy-eller-dagene-vi-jaktet-på-spøkelsesdata">Støy, eller dagene vi jaktet på spøkelsesdata</h2>
<p>Denne er fra elektrikertiden min. Vi var på et prosjekt i et stort bygg og trakk kabler fra en stor mengde sensorer inn til lokale noder, og videre fra nodene til en hovedtavle der alle sensordataene i bygget samlet seg. Mye kabel, mange strekk, alt terminert og ferdig. Vår del av jobben var gjort.</p>
<p>Så startet automatikerne idriftsettelsen, og dataene var søppel. Ikke døde, det hadde vært enklere å feilsøke, men feil, rare og hoppende verdier. De brukte dagevis på feilsøking før noen fant årsaken: signalkablene var uskjermet, og lange strekk lå på samme kabelbro som sterkstrømskablene. Sterkstrømmen induserte støy rett inn i signallederne, og alle avlesningene som kom inn i tavlen hadde litt av byggets elektriske aktivitet blandet inn i seg.</p>
<p>Slik ser elektrisk støy ut fra datasiden: verdier som vibrerer noen counts rundt den reelle avlesningen, og brå hopp som ser ut som prosessendringer, men egentlig er en motor som starter et sted i bygget. Frekvensomformere er beryktet her, de støyer mye, og signalkabler som ligger for nært plukker det opp. Skjerming hjelper, riktig jording av skjermen betyr mye (jorder du den i begge ender, kan du få et nytt problem, en jordsløyfe), og fysisk avstand til sterkstrømskabler er det billigste tiltaket av alle. Ingenting av dette kan koden din se. Den ser bare en temperatur som skjelver.</p>
<figure class="diagram">
  <svg viewBox="0 0 720 270" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="An unshielded signal pair lying on the same cable ladder as a power cable picks up induced noise. The signal sent by the transmitter is smooth, the signal read by the PLC trembles.">
  <style>
    .lbl { font-family: ui-sans-serif, system-ui, sans-serif; font-size: 13px; fill: var(--content, #333); }
    .sub { font-family: ui-sans-serif, system-ui, sans-serif; font-size: 12px; fill: var(--secondary, #666); }
    .noise-lbl { font-family: ui-sans-serif, system-ui, sans-serif; font-size: 12px; font-weight: 600; fill: #d64545; }
    .ladder { stroke: var(--border, #bbb); stroke-width: 2; }
    .power { stroke: var(--content, #333); stroke-width: 9; stroke-linecap: round; }
    .signal { stroke: #2f6fdd; stroke-width: 2.5; fill: none; }
    .noise { stroke: #d64545; stroke-width: 1.8; fill: none; }
  </style>

  <!-- cable ladder -->
  <line class="ladder" x1="50" y1="38" x2="670" y2="38"/>
  <line class="ladder" x1="50" y1="112" x2="670" y2="112"/>
  <line class="ladder" x1="90" y1="38" x2="90" y2="112"/>
  <line class="ladder" x1="190" y1="38" x2="190" y2="112"/>
  <line class="ladder" x1="290" y1="38" x2="290" y2="112"/>
  <line class="ladder" x1="390" y1="38" x2="390" y2="112"/>
  <line class="ladder" x1="490" y1="38" x2="490" y2="112"/>
  <line class="ladder" x1="590" y1="38" x2="590" y2="112"/>

  <!-- power cable -->
  <line class="power" x1="60" y1="58" x2="660" y2="58"/>
  <text class="lbl" x="60" y="30">power cable (motors, frequency drives)</text>

  <!-- unshielded signal pair -->
  <line class="signal" x1="60" y1="92" x2="660" y2="92"/>
  <line class="signal" x1="60" y1="99" x2="660" y2="99"/>
  <text class="sub" x="60" y="134">unshielded 4-20 mA signal pair, same ladder</text>

  <!-- induced noise arrows -->
  <path class="noise" d="M 230 64 q 5 8 -2 12 q -7 4 -2 12"/>
  <polygon fill="#d64545" points="222,86 228,90 230,82"/>
  <path class="noise" d="M 400 64 q 5 8 -2 12 q -7 4 -2 12"/>
  <polygon fill="#d64545" points="392,86 398,90 400,82"/>
  <path class="noise" d="M 570 64 q 5 8 -2 12 q -7 4 -2 12"/>
  <polygon fill="#d64545" points="562,86 568,90 570,82"/>
  <text class="noise-lbl" x="620" y="134" text-anchor="end">induced noise</text>

  <!-- sent vs read -->
  <path class="signal" d="M 70 215 C 130 215 150 195 200 195 C 250 195 270 210 320 210"/>
  <text class="sub" x="195" y="248" text-anchor="middle">what the transmitter sent</text>

  <path class="signal" d="M 400 215 L 408 213 L 414 218 L 422 210 L 430 216 L 436 194 L 444 214 L 452 210 L 458 216 L 466 197 L 474 199 L 482 194 L 490 200 L 498 190 L 506 197 L 514 212 L 522 194 L 530 208 L 538 206 L 546 213 L 554 208 L 562 215 L 570 209 L 578 213 L 586 207 L 594 212 L 602 209 L 610 212 L 618 208 L 626 211 L 634 209 L 642 210 L 650 210"/>
  <text class="sub" x="525" y="248" text-anchor="middle">what the PLC read</text>
</svg>
<figcaption>Prosjektet i én tegning: uskjermet signalkabel på samme bro som sterkstrømskabler. Transmitteren sender et rent signal, PLS-en leser et skjelvende.</figcaption></figure>
<h2 id="hva-koden-din-bør-anta">Hva koden din bør anta</h2>
<p>De praktiske rådene, i samme ånd som <a href="/no/posts/trust-your-sensor-data/">sensordata-innlegget</a>:</p>
<ul>
<li>Behandle alt under 3,6 mA og over 21 mA som feil, aldri som målinger. Ikke la feilstrømmer snike seg inn i snitt og aggregater.</li>
<li>Vit hvilken burnout-retning transmitterne dine har. En sensor som feiler høyt skal ikke utløse alarm om overoppheting.</li>
<li>Ikke stol på at spannet i dokumentasjonen er spannet i transmitteren. Verifiser når du kan, og sørg for at det synes godt i loggene når verdier slutter å gi fysisk mening.</li>
<li>Regn med noen counts støy. Alarmgrenser som er strammere enn støygulvet varsler om elektrisitet, ikke om prosessen.</li>
<li>Logg rå mA eller counts ved siden av den skalerte verdien hvis du kan. Det er den eneste måten å feilsøke en skaleringsfeil på i etterkant.</li>
</ul>
<figure class="diagram">
  <svg viewBox="0 0 720 235" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="A small ingestion flow for 4-20 mA values. A value arrives as milliamps or raw counts. If it is outside 3.8 to 20.5 milliamps it goes to the fault path: alarm it and keep it out of statistics. Otherwise apply the span, validate range and rate of change, and store the scaled value together with the raw one.">
  <style>
    .box { fill: var(--entry, #f6f6f6); stroke: var(--content, #333); stroke-width: 1.5; }
    .fbox { fill: none; stroke: #d64545; stroke-width: 1.8; }
    .lbl { font-family: ui-sans-serif, system-ui, sans-serif; font-size: 13px; fill: var(--content, #333); }
    .sub { font-family: ui-sans-serif, system-ui, sans-serif; font-size: 11.5px; fill: var(--secondary, #666); }
    .yes { font-family: ui-sans-serif, system-ui, sans-serif; font-size: 12px; font-weight: 700; fill: #2f6fdd; }
    .no { font-family: ui-sans-serif, system-ui, sans-serif; font-size: 12px; font-weight: 700; fill: #d64545; }
    .fault { font-family: ui-sans-serif, system-ui, sans-serif; font-size: 13px; font-weight: 600; fill: #d64545; }
    .wire { stroke: var(--content, #333); stroke-width: 1.8; fill: none; }
    .head { fill: var(--content, #333); }
  </style>

  <!-- value arrives -->
  <rect class="box" x="25" y="55" width="140" height="56" rx="6"/>
  <text class="lbl" x="95" y="79" text-anchor="middle">value arrives</text>
  <text class="sub" x="95" y="97" text-anchor="middle">mA or raw counts</text>

  <line class="wire" x1="165" y1="83" x2="196" y2="83"/>
  <polygon class="head" points="196,78 206,83 196,88"/>

  <!-- range check -->
  <rect class="box" x="206" y="55" width="150" height="56" rx="6"/>
  <text class="lbl" x="281" y="79" text-anchor="middle">inside 3.8-20.5 mA?</text>
  <text class="sub" x="281" y="97" text-anchor="middle">the zones from above</text>

  <!-- no: fault path -->
  <line class="wire" x1="281" y1="111" x2="281" y2="142"/>
  <polygon class="head" points="276,142 281,152 286,142"/>
  <text class="no" x="290" y="136">no</text>
  <rect class="fbox" x="191" y="152" width="180" height="56" rx="6"/>
  <text class="fault" x="281" y="176" text-anchor="middle">fault path</text>
  <text class="sub" x="281" y="194" text-anchor="middle">alarm it, keep it out of stats</text>

  <!-- yes: continue -->
  <line class="wire" x1="356" y1="83" x2="387" y2="83"/>
  <polygon class="head" points="387,78 397,83 387,88"/>
  <text class="yes" x="371" y="72" text-anchor="middle">yes</text>

  <rect class="box" x="397" y="55" width="160" height="56" rx="6"/>
  <text class="lbl" x="477" y="79" text-anchor="middle">apply the span</text>
  <text class="sub" x="477" y="97" text-anchor="middle">validate range + rate</text>

  <line class="wire" x1="557" y1="83" x2="588" y2="83"/>
  <polygon class="head" points="588,78 598,83 588,88"/>

  <rect class="box" x="598" y="55" width="100" height="56" rx="6"/>
  <text class="lbl" x="648" y="79" text-anchor="middle">store scaled</text>
  <text class="sub" x="648" y="97" text-anchor="middle">+ raw value</text>
</svg>
<figcaption>Hele listen som en flyt: feilstrømmer tar alarmstien, alt annet skaleres, valideres og lagres sammen med råverdien.</figcaption></figure>
<p>Og den største antagelsen, den som ligger bak alle de andre: anta at ingen sitter med hele bildet. Elektrikeren som trakk kabelen, automatikeren som idriftsatte anlegget, prosjektingeniøren med databladene, og du, utvikleren som bruker tallet i enden. Alle kan sitt eget lag. Ingen sjekker ditt opp mot deres uten at du spør.</p>
<p>Strømsløyfen er ærlig. Det er antagelsene dine om den som lyver.</p>
<p>Dette innlegget er steg to i en kjede. Steg én, det som skjer med verdien etter at den har blitt et tall, ligger her: <a href="/no/posts/trust-your-sensor-data/">Kan du stole på sensordataene dine?</a></p>
<hr><p><em>Originally published at <a href="https://mariusgjerd.github.io/no/posts/what-4-20ma-actually-means/">mariusgjerd.github.io</a>, where I write about what happens when code touches the real world. New posts also go out by email: <a href="https://marius-newsletter-d94bcd.beehiiv.com/">subscribe here</a>.</em></p>]]></content:encoded></item></channel></rss>