<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="sv">
	<id>http://wiki.sikvall.se/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Anders</id>
	<title>Täpp-Anders - Användarbidrag [sv]</title>
	<link rel="self" type="application/atom+xml" href="http://wiki.sikvall.se/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Anders"/>
	<link rel="alternate" type="text/html" href="http://wiki.sikvall.se/index.php/Special:Bidrag/Anders"/>
	<updated>2026-07-04T23:06:43Z</updated>
	<subtitle>Användarbidrag</subtitle>
	<generator>MediaWiki 1.43.0</generator>
	<entry>
		<id>http://wiki.sikvall.se/index.php?title=DB%C2%B5V/m&amp;diff=1927</id>
		<title>DBµV/m</title>
		<link rel="alternate" type="text/html" href="http://wiki.sikvall.se/index.php?title=DB%C2%B5V/m&amp;diff=1927"/>
		<updated>2026-07-03T07:32:51Z</updated>

		<summary type="html">&lt;p&gt;Anders: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Ofärdig}}&lt;br /&gt;
&lt;br /&gt;
Konvertera dBµV/m till dBm:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; P_{\text{dBm}} = E_{\text{dB}\mu\text{V/m}} - 20\log(f) + G_{\text{dBi}} - 77,2 &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Där &lt;br /&gt;
&amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt; anges i MHz och&lt;br /&gt;
&amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; är antennvinst jämfört med en isotrop antenn dBi.&lt;/div&gt;</summary>
		<author><name>Anders</name></author>
	</entry>
	<entry>
		<id>http://wiki.sikvall.se/index.php?title=DB%C2%B5V/m&amp;diff=1926</id>
		<title>DBµV/m</title>
		<link rel="alternate" type="text/html" href="http://wiki.sikvall.se/index.php?title=DB%C2%B5V/m&amp;diff=1926"/>
		<updated>2026-07-03T07:29:40Z</updated>

		<summary type="html">&lt;p&gt;Anders: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Ofärdig}}&lt;br /&gt;
&lt;br /&gt;
Konvertera dBµV/m till dBm:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; P_{dBm} = E_{dB\mu V/m} - 20\log(f) + G_{dBi} - 77,2 &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Där &lt;br /&gt;
&amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt; anges i MHz och&lt;br /&gt;
&amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; är antennvinst jämfört med en isotrop antenn dBi&lt;/div&gt;</summary>
		<author><name>Anders</name></author>
	</entry>
	<entry>
		<id>http://wiki.sikvall.se/index.php?title=DB%C2%B5V/m&amp;diff=1925</id>
		<title>DBµV/m</title>
		<link rel="alternate" type="text/html" href="http://wiki.sikvall.se/index.php?title=DB%C2%B5V/m&amp;diff=1925"/>
		<updated>2026-07-03T07:28:11Z</updated>

		<summary type="html">&lt;p&gt;Anders: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Ofärdig}}&lt;br /&gt;
&lt;br /&gt;
Konvertera dBµV/m till dBm:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; P_{dBm} = E_{dB\mu V/m} - 20\log(f) - 77,2 + G&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Där &lt;br /&gt;
&amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt; anges i MHz och&lt;br /&gt;
&amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; är antennvinst jämfört med en isotrop antenn dBi&lt;/div&gt;</summary>
		<author><name>Anders</name></author>
	</entry>
	<entry>
		<id>http://wiki.sikvall.se/index.php?title=DB%C2%B5V/m&amp;diff=1924</id>
		<title>DBµV/m</title>
		<link rel="alternate" type="text/html" href="http://wiki.sikvall.se/index.php?title=DB%C2%B5V/m&amp;diff=1924"/>
		<updated>2026-07-03T07:27:32Z</updated>

		<summary type="html">&lt;p&gt;Anders: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Ofärdig}}&lt;br /&gt;
&lt;br /&gt;
Konvertera dBµV/m till dBm:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; P_{dBm} = E_{dB\mu V/m} - 20\log(f) - 77,2 + G&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Där &lt;br /&gt;
&amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt; anges i MHz och&lt;br /&gt;
&amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; är antennvinst minus kabelförluster i dB&lt;/div&gt;</summary>
		<author><name>Anders</name></author>
	</entry>
	<entry>
		<id>http://wiki.sikvall.se/index.php?title=DB%C2%B5V/m&amp;diff=1923</id>
		<title>DBµV/m</title>
		<link rel="alternate" type="text/html" href="http://wiki.sikvall.se/index.php?title=DB%C2%B5V/m&amp;diff=1923"/>
		<updated>2026-07-03T07:26:38Z</updated>

		<summary type="html">&lt;p&gt;Anders: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Ofärdig}}&lt;br /&gt;
&lt;br /&gt;
Konvertera dBµV/m till dBm:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; P_{dBm} = E_{dB\mu V/m} - 20\log(f) - 77,2&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Där &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt; anges i MHz.&lt;/div&gt;</summary>
		<author><name>Anders</name></author>
	</entry>
	<entry>
		<id>http://wiki.sikvall.se/index.php?title=DB%C2%B5V/m&amp;diff=1922</id>
		<title>DBµV/m</title>
		<link rel="alternate" type="text/html" href="http://wiki.sikvall.se/index.php?title=DB%C2%B5V/m&amp;diff=1922"/>
		<updated>2026-07-03T07:25:23Z</updated>

		<summary type="html">&lt;p&gt;Anders: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Ofärdig}}&lt;br /&gt;
&lt;br /&gt;
Konvertera dBµV/m till dBm:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; P_{dBm} = E_{dB\mu V/m} - 20\log(f) - 77,2&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Detta gäller då för ett avstånd av 3 meter från sändarens antenn och inkluderar inte antenngain och andra parametrar, detta får läggas till eller dras från efter konverteringen.&lt;br /&gt;
&lt;br /&gt;
(I framtiden ska jag beskriva mer vad faktorn -95.2 kommer från)&lt;/div&gt;</summary>
		<author><name>Anders</name></author>
	</entry>
	<entry>
		<id>http://wiki.sikvall.se/index.php?title=DB%C2%B5V/m&amp;diff=1921</id>
		<title>DBµV/m</title>
		<link rel="alternate" type="text/html" href="http://wiki.sikvall.se/index.php?title=DB%C2%B5V/m&amp;diff=1921"/>
		<updated>2026-07-03T07:25:00Z</updated>

		<summary type="html">&lt;p&gt;Anders: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Ofärdig}}&lt;br /&gt;
&lt;br /&gt;
Konvertera dBµV/m till dBm:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; P_{dBm} = E_{dB\mu /m} - 20\log(f) - 77,2&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Detta gäller då för ett avstånd av 3 meter från sändarens antenn och inkluderar inte antenngain och andra parametrar, detta får läggas till eller dras från efter konverteringen.&lt;br /&gt;
&lt;br /&gt;
(I framtiden ska jag beskriva mer vad faktorn -95.2 kommer från)&lt;/div&gt;</summary>
		<author><name>Anders</name></author>
	</entry>
	<entry>
		<id>http://wiki.sikvall.se/index.php?title=Racket/Neural&amp;diff=1920</id>
		<title>Racket/Neural</title>
		<link rel="alternate" type="text/html" href="http://wiki.sikvall.se/index.php?title=Racket/Neural&amp;diff=1920"/>
		<updated>2026-07-02T14:42:43Z</updated>

		<summary type="html">&lt;p&gt;Anders: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[category:Algoritmer]]&lt;br /&gt;
[[category:Programmering]]&lt;br /&gt;
[[category:Racket]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#lang racket&lt;br /&gt;
&lt;br /&gt;
;;;;;&lt;br /&gt;
;; Neuralt nät implementerad i Racket&lt;br /&gt;
;; Täpp-Anders Sikvall 2026-07-02 &amp;lt;anders@sikvall.se&amp;gt;&lt;br /&gt;
;;;;;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;;;;; NEURALT NÄT&lt;br /&gt;
;;;&lt;br /&gt;
;; Detta program implementerar ett litet neuralt nät och tränar det på sannings-&lt;br /&gt;
;; tabellen för XOR. Efter några tusen epoker ska prediktionerna ligga extremt nära&lt;br /&gt;
;; följande:&lt;br /&gt;
;;&lt;br /&gt;
;; a,b → a XOR b&lt;br /&gt;
;; 0,0 →    0&lt;br /&gt;
;; 0,1 →    1&lt;br /&gt;
;; 1,0 →    1&lt;br /&gt;
;; 1,1 →    0&lt;br /&gt;
;;&lt;br /&gt;
;; Implementationen har två input-neuroner för a och b&lt;br /&gt;
;; det finns 5 interna (dolda neuroner) som tränas av indatat&lt;br /&gt;
;; det finns 1 output-neuron som ger svaret&lt;br /&gt;
;;&lt;br /&gt;
;;;;; Kodens uppbyggnad och de olika funktionernas användning&lt;br /&gt;
;;&lt;br /&gt;
;; sigmoid, sigmoid-deriv      Sigmoid-kurva och derivata för backpropagation&lt;br /&gt;
;;&lt;br /&gt;
;; random-matrix, met-vec-mul  Grundläggande linalg&lt;br /&gt;
;; outer-product; vec-add&lt;br /&gt;
;;&lt;br /&gt;
;; struct nn                   Nätverksstruktur, lagrar vikter och bias&lt;br /&gt;
;;&lt;br /&gt;
;; forward                     Beräknar prediktion&lt;br /&gt;
;;&lt;br /&gt;
;; train-step                  En iteration av backpropagation&lt;br /&gt;
;;&lt;br /&gt;
;; train                       Kör många epoker av in och förväntat utdata för&lt;br /&gt;
;;                             att träna modellen&lt;br /&gt;
;;&lt;br /&gt;
;; predict                     Använder nätverket på ny data!&lt;br /&gt;
;;&lt;br /&gt;
;;&lt;br /&gt;
;;;;; Viktiga delar&lt;br /&gt;
;;&lt;br /&gt;
;; * sigmoid mappar alla värden steglöst till intervallet (0,1)&lt;br /&gt;
;; * derivatan används i backpropagation för att räkna ut gradienten&lt;br /&gt;
;;&lt;br /&gt;
;; w1: vikter mellan input och hidden layer (5x2 matris)&lt;br /&gt;
;; b1: bias för hidden layer (5-vektor)&lt;br /&gt;
;; w2: viktar mellan hidden och output (1x5 matris)&lt;br /&gt;
;; b2: bias för output (1-vektor)&lt;br /&gt;
;;&lt;br /&gt;
;; Forward pass&lt;br /&gt;
;;&lt;br /&gt;
;; 1. Beräkna aktivering i hidden layer&lt;br /&gt;
;;    z1 = W1 * input + b1&lt;br /&gt;
;;    h = rho z1&lt;br /&gt;
;; 2. Beräkna output&lt;br /&gt;
;;    z2 = W2 * h +b2&lt;br /&gt;
;;    output = rho(z2)&lt;br /&gt;
;;&lt;br /&gt;
;; Backpropagation (uppdatering av viktningen)&lt;br /&gt;
;;&lt;br /&gt;
;; Hjärtat i träningen av ett neuralt nät. Algorimen är &amp;quot;gradient descent&amp;quot; med batch-&lt;br /&gt;
;; storlek 1.&lt;br /&gt;
;;&lt;br /&gt;
;; 1. Forward pass hidden → output&lt;br /&gt;
;; 2. Output-felet&lt;br /&gt;
;;    delta = (output - target) X rho&#039; (output)&lt;br /&gt;
;; 3. Hidden-felet&lt;br /&gt;
;;    delta hidden = (W2/T * delta out) X rho&#039; (hidden)&lt;br /&gt;
;; 4. Uppdatera vikternas gradienter&lt;br /&gt;
;;    W2 ← W2 - nabla * delta out * h^T&lt;br /&gt;
;;    W1 ← W1 - nabla * delta hidden * input^T&lt;br /&gt;
;; 5. Bias uppdateras på samma sätt (jo det är en genväg)&lt;br /&gt;
;;&lt;br /&gt;
&lt;br /&gt;
(require math/base)&lt;br /&gt;
&lt;br /&gt;
;; ========================================&lt;br /&gt;
;; Aktiveringsfunktioner&lt;br /&gt;
;; ========================================&lt;br /&gt;
(define (sigmoid x)&lt;br /&gt;
  (/ 1.0 (+ 1.0 (exp (- x)))))&lt;br /&gt;
&lt;br /&gt;
(define (sigmoid-deriv y)   ; y måste redan vara sigmoid(x)&lt;br /&gt;
  (* y (- 1.0 y)))&lt;br /&gt;
&lt;br /&gt;
;; ========================================&lt;br /&gt;
;; Matris-/vektorhjälp (enkel version)&lt;br /&gt;
;; ========================================&lt;br /&gt;
(define (random-matrix rows cols)&lt;br /&gt;
  (build-vector rows&lt;br /&gt;
                (λ (_) (build-vector cols (λ (_) (- (* 2.0 (random)) 1.0))))))&lt;br /&gt;
&lt;br /&gt;
(define (vec-add v1 v2)     ; elementvis addition av två vektorer&lt;br /&gt;
  (build-vector (vector-length v1)&lt;br /&gt;
                (λ (i) (+ (vector-ref v1 i) (vector-ref v2 i)))))&lt;br /&gt;
&lt;br /&gt;
(define (scalar-mul s v)&lt;br /&gt;
  (build-vector (vector-length v) (λ (i) (* s (vector-ref v i)))))&lt;br /&gt;
&lt;br /&gt;
(define (outer-product v1 v2)   ; v1 kolumn × v2 rad → matris&lt;br /&gt;
  (build-vector (vector-length v1)&lt;br /&gt;
                (λ (i)&lt;br /&gt;
                  (build-vector (vector-length v2)&lt;br /&gt;
                                (λ (j) (* (vector-ref v1 i) (vector-ref v2 j)))))))&lt;br /&gt;
&lt;br /&gt;
(define (mat-vec-mul M v)       ; M (rows×cols) × v (cols)&lt;br /&gt;
  (build-vector (vector-length M)&lt;br /&gt;
                (λ (i)&lt;br /&gt;
                  (for/sum ([j (in-range (vector-length v))])&lt;br /&gt;
                    (* (vector-ref (vector-ref M i) j)&lt;br /&gt;
                       (vector-ref v j))))))&lt;br /&gt;
&lt;br /&gt;
(define (transpose M)&lt;br /&gt;
  (build-vector (vector-length (vector-ref M 0))&lt;br /&gt;
                (λ (j)&lt;br /&gt;
                  (build-vector (vector-length M)&lt;br /&gt;
                                (λ (i) (vector-ref (vector-ref M i) j))))))&lt;br /&gt;
&lt;br /&gt;
;; ======================================== &lt;br /&gt;
;; Neuralt nätverk&lt;br /&gt;
;; ========================================&lt;br /&gt;
(struct nn (w1 b1 w2 b2) #:transparent)&lt;br /&gt;
&lt;br /&gt;
(define (make-nn in-size hidden-size out-size)&lt;br /&gt;
  (nn (random-matrix hidden-size in-size)&lt;br /&gt;
      (make-vector hidden-size 0.0)&lt;br /&gt;
      (random-matrix out-size hidden-size)&lt;br /&gt;
      (make-vector out-size 0.0)))&lt;br /&gt;
&lt;br /&gt;
(define (forward net input)          ; input är en vektor t.ex. #(0 0)&lt;br /&gt;
  (let* ([z1 (vec-add (mat-vec-mul (nn-w1 net) input)&lt;br /&gt;
                      (nn-b1 net))]&lt;br /&gt;
         [h  (build-vector (vector-length z1) (λ (i) (sigmoid (vector-ref z1 i))))]&lt;br /&gt;
         [z2 (vec-add (mat-vec-mul (nn-w2 net) h)&lt;br /&gt;
                      (nn-b2 net))]&lt;br /&gt;
         [o  (build-vector (vector-length z2) (λ (i) (sigmoid (vector-ref z2 i))))])&lt;br /&gt;
    (values o h)))&lt;br /&gt;
&lt;br /&gt;
(define (train-step net input target lr)&lt;br /&gt;
  (let-values ([(output hidden) (forward net input)])&lt;br /&gt;
    (let* ([out-err (build-vector (vector-length output)&lt;br /&gt;
                                  (λ (i) (- (vector-ref output i)&lt;br /&gt;
                                            (vector-ref target i))))]&lt;br /&gt;
           [out-delta (build-vector (vector-length output)&lt;br /&gt;
                                    (λ (i) (* (vector-ref out-err i)&lt;br /&gt;
                                              (sigmoid-deriv (vector-ref output i)))))]&lt;br /&gt;
&lt;br /&gt;
           [hidden-err (mat-vec-mul (transpose (nn-w2 net)) out-delta)]&lt;br /&gt;
           [hidden-delta (build-vector (vector-length hidden)&lt;br /&gt;
                                       (λ (i) (* (vector-ref hidden-err i)&lt;br /&gt;
                                                 (sigmoid-deriv (vector-ref hidden i)))))]&lt;br /&gt;
&lt;br /&gt;
           ;; Uppdateringar&lt;br /&gt;
           [dw2 (outer-product out-delta hidden)]&lt;br /&gt;
           [new-w2 (build-vector (vector-length (nn-w2 net))&lt;br /&gt;
                                 (λ (i)&lt;br /&gt;
                                   (build-vector (vector-length (vector-ref (nn-w2 net) i))&lt;br /&gt;
                                                 (λ (j) (- (vector-ref (vector-ref (nn-w2 net) i) j)&lt;br /&gt;
                                                           (* lr (vector-ref (vector-ref dw2 i) j)))))))]&lt;br /&gt;
           [new-b2 (build-vector (vector-length (nn-b2 net))&lt;br /&gt;
                                 (λ (i) (- (vector-ref (nn-b2 net) i)&lt;br /&gt;
                                           (* lr (vector-ref out-delta i)))))]&lt;br /&gt;
&lt;br /&gt;
           [dw1 (outer-product hidden-delta input)]&lt;br /&gt;
           [new-w1 (build-vector (vector-length (nn-w1 net))&lt;br /&gt;
                                 (λ (i)&lt;br /&gt;
                                   (build-vector (vector-length (vector-ref (nn-w1 net) i))&lt;br /&gt;
                                                 (λ (j) (- (vector-ref (vector-ref (nn-w1 net) i) j)&lt;br /&gt;
                                                           (* lr (vector-ref (vector-ref dw1 i) j)))))))]&lt;br /&gt;
           [new-b1 (build-vector (vector-length (nn-b1 net))&lt;br /&gt;
                                 (λ (i) (- (vector-ref (nn-b1 net) i)&lt;br /&gt;
                                           (* lr (vector-ref hidden-delta i)))))])&lt;br /&gt;
&lt;br /&gt;
      (nn new-w1 new-b1 new-w2 new-b2))))&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;; ========================================&lt;br /&gt;
;; Skriv ut vikter och bias – snygg tabell (fixad version)&lt;br /&gt;
;; ========================================&lt;br /&gt;
(define (print-nn net)&lt;br /&gt;
  (printf &amp;quot;\n=== NEURALT NÄTVERK - VIKTER OCH BIAS ===\n\n&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
  ;; Hjälpfunktion för att formatera tal snyggt (med minustecken på rätt plats)&lt;br /&gt;
  (define (fmt x)&lt;br /&gt;
    (~r x &lt;br /&gt;
        #:min-width 10 &lt;br /&gt;
        #:precision &#039;(= 4)&lt;br /&gt;
        #:sign #f))          ; #f = visa minus för negativa, inget tecken för positiva&lt;br /&gt;
&lt;br /&gt;
  ;; W1: Vikter från input till hidden (5×2)&lt;br /&gt;
  (printf &amp;quot;W1 (Hidden × Input):\n&amp;quot;)&lt;br /&gt;
  (printf &amp;quot;          Input0      Input1\n&amp;quot;)&lt;br /&gt;
  (for ([i (in-range (vector-length (nn-w1 net)))])&lt;br /&gt;
    (printf &amp;quot;Hidden~a  &amp;quot; i)&lt;br /&gt;
    (for ([j (in-range 2)])&lt;br /&gt;
      (printf &amp;quot;~a  &amp;quot; (fmt (vector-ref (vector-ref (nn-w1 net) i) j))))&lt;br /&gt;
    (printf &amp;quot;\n&amp;quot;))&lt;br /&gt;
  (printf &amp;quot;\n&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
  ;; b1: Bias för hidden layer&lt;br /&gt;
  (printf &amp;quot;b1 (Bias hidden layer):\n&amp;quot;)&lt;br /&gt;
  (for ([i (in-range (vector-length (nn-b1 net)))])&lt;br /&gt;
    (printf &amp;quot;~a  &amp;quot; (fmt (vector-ref (nn-b1 net) i))))&lt;br /&gt;
  (printf &amp;quot;\n\n&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
  ;; W2: Vikter från hidden till output (1×5)&lt;br /&gt;
  (printf &amp;quot;W2 (Output × Hidden):\n&amp;quot;)&lt;br /&gt;
  (printf &amp;quot;         Hidden0     Hidden1     Hidden2     Hidden3     Hidden4\n&amp;quot;)&lt;br /&gt;
  (printf &amp;quot;Output   &amp;quot;)&lt;br /&gt;
  (for ([j (in-range 5)])&lt;br /&gt;
    (printf &amp;quot;~a  &amp;quot; (fmt (vector-ref (vector-ref (nn-w2 net) 0) j))))&lt;br /&gt;
  (printf &amp;quot;\n\n&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
  ;; b2: Bias för output&lt;br /&gt;
  (printf &amp;quot;b2 (Bias output):\n&amp;quot;)&lt;br /&gt;
  (printf &amp;quot;~a\n&amp;quot; (fmt (vector-ref (nn-b2 net) 0)))&lt;br /&gt;
&lt;br /&gt;
  (printf &amp;quot;\n========================================\n&amp;quot;))&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;; Träna nätverket&lt;br /&gt;
(define (train net data epochs lr)&lt;br /&gt;
  (for ([ep (in-range epochs)])&lt;br /&gt;
    (for ([sample data])&lt;br /&gt;
      (set! net (train-step net (car sample) (cadr sample) lr)))&lt;br /&gt;
    &lt;br /&gt;
    (when (zero? (modulo ep 500))      ; oftare än var 1000:e&lt;br /&gt;
      (let ([loss (for/sum ([sample data])&lt;br /&gt;
                    (let-values ([(output _) (forward net (car sample))])&lt;br /&gt;
                      (let ([target (vector-ref (cadr sample) 0)]&lt;br /&gt;
                            [pred   (vector-ref output 0)])&lt;br /&gt;
                        (sqr (- target pred)))))])&lt;br /&gt;
        (printf &amp;quot;Epoch ~a  Loss: ~a\n&amp;quot; ep (/ loss (length data))))))&lt;br /&gt;
  (print-nn net)&lt;br /&gt;
  net)&lt;br /&gt;
&lt;br /&gt;
;; Prediktera&lt;br /&gt;
(define (predict net input)&lt;br /&gt;
  (let-values ([(output _) (forward net input)])&lt;br /&gt;
    output))&lt;br /&gt;
&lt;br /&gt;
;; ========================================&lt;br /&gt;
;; XOR-exempel&lt;br /&gt;
;; ========================================&lt;br /&gt;
(define xor-data&lt;br /&gt;
  (list (list #(0 0) #(0))&lt;br /&gt;
        (list #(0 1) #(1))&lt;br /&gt;
        (list #(1 0) #(1))&lt;br /&gt;
        (list #(1 1) #(0))))&lt;br /&gt;
&lt;br /&gt;
(define net (make-nn 2 5 1))   ; 2 input, 5 dolda neuroner, 1 output&lt;br /&gt;
(define rounds 8000) ; 2000 är i minsta laget, 5000 eller hellre 8000 är bättre&lt;br /&gt;
(define backpr 0.7)&lt;br /&gt;
(printf &amp;quot;Tränar XOR-problemet i ~a rundor med backprop styrka ~a\n&amp;quot; rounds backpr)&lt;br /&gt;
(set! net (train net xor-data rounds backpr))&lt;br /&gt;
&lt;br /&gt;
(printf &amp;quot;\n=== Testresultat ===\n&amp;quot;)&lt;br /&gt;
(for ([sample xor-data])&lt;br /&gt;
  (let ([pred (vector-ref (predict net (car sample)) 0)])&lt;br /&gt;
    (printf &amp;quot;Input ~a  →  Förväntat: ~a  Predikterat: ~a\n&amp;quot;&lt;br /&gt;
            (car sample)&lt;br /&gt;
            (vector-ref (cadr sample) 0)&lt;br /&gt;
            (if (&amp;gt; pred 0.5) 1.0 0.0))))&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>Anders</name></author>
	</entry>
	<entry>
		<id>http://wiki.sikvall.se/index.php?title=Racket/Neural&amp;diff=1919</id>
		<title>Racket/Neural</title>
		<link rel="alternate" type="text/html" href="http://wiki.sikvall.se/index.php?title=Racket/Neural&amp;diff=1919"/>
		<updated>2026-07-02T14:42:13Z</updated>

		<summary type="html">&lt;p&gt;Anders: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[category:Algoritmer]]&lt;br /&gt;
[[category:Programmering]]&lt;br /&gt;
[[category:Racket]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#lang racket&lt;br /&gt;
&lt;br /&gt;
;;;;;&lt;br /&gt;
;; Neuralt nät implementerad i Racket&lt;br /&gt;
;; Täpp-Anders Sikvall 2026-04-03 anders@sikvall.se&lt;br /&gt;
;;;;;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;;;;; NEURALT NÄT&lt;br /&gt;
;;;&lt;br /&gt;
;; Detta program implementerar ett litet neuralt nät och tränar det på sannings-&lt;br /&gt;
;; tabellen för XOR. Efter några tusen epoker ska prediktionerna ligga extremt nära&lt;br /&gt;
;; följande:&lt;br /&gt;
;;&lt;br /&gt;
;; a,b → a XOR b&lt;br /&gt;
;; 0,0 →    0&lt;br /&gt;
;; 0,1 →    1&lt;br /&gt;
;; 1,0 →    1&lt;br /&gt;
;; 1,1 →    0&lt;br /&gt;
;;&lt;br /&gt;
;; Implementationen har två input-neuroner för a och b&lt;br /&gt;
;; det finns 5 interna (dolda neuroner) som tränas av indatat&lt;br /&gt;
;; det finns 1 output-neuron som ger svaret&lt;br /&gt;
;;&lt;br /&gt;
;;;;; Kodens uppbyggnad och de olika funktionernas användning&lt;br /&gt;
;;&lt;br /&gt;
;; sigmoid, sigmoid-deriv      Sigmoid-kurva och derivata för backpropagation&lt;br /&gt;
;;&lt;br /&gt;
;; random-matrix, met-vec-mul  Grundläggande linalg&lt;br /&gt;
;; outer-product; vec-add&lt;br /&gt;
;;&lt;br /&gt;
;; struct nn                   Nätverksstruktur, lagrar vikter och bias&lt;br /&gt;
;;&lt;br /&gt;
;; forward                     Beräknar prediktion&lt;br /&gt;
;;&lt;br /&gt;
;; train-step                  En iteration av backpropagation&lt;br /&gt;
;;&lt;br /&gt;
;; train                       Kör många epoker av in och förväntat utdata för&lt;br /&gt;
;;                             att träna modellen&lt;br /&gt;
;;&lt;br /&gt;
;; predict                     Använder nätverket på ny data!&lt;br /&gt;
;;&lt;br /&gt;
;;&lt;br /&gt;
;;;;; Viktiga delar&lt;br /&gt;
;;&lt;br /&gt;
;; * sigmoid mappar alla värden steglöst till intervallet (0,1)&lt;br /&gt;
;; * derivatan används i backpropagation för att räkna ut gradienten&lt;br /&gt;
;;&lt;br /&gt;
;; w1: vikter mellan input och hidden layer (5x2 matris)&lt;br /&gt;
;; b1: bias för hidden layer (5-vektor)&lt;br /&gt;
;; w2: viktar mellan hidden och output (1x5 matris)&lt;br /&gt;
;; b2: bias för output (1-vektor)&lt;br /&gt;
;;&lt;br /&gt;
;; Forward pass&lt;br /&gt;
;;&lt;br /&gt;
;; 1. Beräkna aktivering i hidden layer&lt;br /&gt;
;;    z1 = W1 * input + b1&lt;br /&gt;
;;    h = rho z1&lt;br /&gt;
;; 2. Beräkna output&lt;br /&gt;
;;    z2 = W2 * h +b2&lt;br /&gt;
;;    output = rho(z2)&lt;br /&gt;
;;&lt;br /&gt;
;; Backpropagation (uppdatering av viktningen)&lt;br /&gt;
;;&lt;br /&gt;
;; Hjärtat i träningen av ett neuralt nät. Algorimen är &amp;quot;gradient descent&amp;quot; med batch-&lt;br /&gt;
;; storlek 1.&lt;br /&gt;
;;&lt;br /&gt;
;; 1. Forward pass hidden → output&lt;br /&gt;
;; 2. Output-felet&lt;br /&gt;
;;    delta = (output - target) X rho&#039; (output)&lt;br /&gt;
;; 3. Hidden-felet&lt;br /&gt;
;;    delta hidden = (W2/T * delta out) X rho&#039; (hidden)&lt;br /&gt;
;; 4. Uppdatera vikternas gradienter&lt;br /&gt;
;;    W2 ← W2 - nabla * delta out * h^T&lt;br /&gt;
;;    W1 ← W1 - nabla * delta hidden * input^T&lt;br /&gt;
;; 5. Bias uppdateras på samma sätt (jo det är en genväg)&lt;br /&gt;
;;&lt;br /&gt;
&lt;br /&gt;
(require math/base)&lt;br /&gt;
&lt;br /&gt;
;; ========================================&lt;br /&gt;
;; Aktiveringsfunktioner&lt;br /&gt;
;; ========================================&lt;br /&gt;
(define (sigmoid x)&lt;br /&gt;
  (/ 1.0 (+ 1.0 (exp (- x)))))&lt;br /&gt;
&lt;br /&gt;
(define (sigmoid-deriv y)   ; y måste redan vara sigmoid(x)&lt;br /&gt;
  (* y (- 1.0 y)))&lt;br /&gt;
&lt;br /&gt;
;; ========================================&lt;br /&gt;
;; Matris-/vektorhjälp (enkel version)&lt;br /&gt;
;; ========================================&lt;br /&gt;
(define (random-matrix rows cols)&lt;br /&gt;
  (build-vector rows&lt;br /&gt;
                (λ (_) (build-vector cols (λ (_) (- (* 2.0 (random)) 1.0))))))&lt;br /&gt;
&lt;br /&gt;
(define (vec-add v1 v2)     ; elementvis addition av två vektorer&lt;br /&gt;
  (build-vector (vector-length v1)&lt;br /&gt;
                (λ (i) (+ (vector-ref v1 i) (vector-ref v2 i)))))&lt;br /&gt;
&lt;br /&gt;
(define (scalar-mul s v)&lt;br /&gt;
  (build-vector (vector-length v) (λ (i) (* s (vector-ref v i)))))&lt;br /&gt;
&lt;br /&gt;
(define (outer-product v1 v2)   ; v1 kolumn × v2 rad → matris&lt;br /&gt;
  (build-vector (vector-length v1)&lt;br /&gt;
                (λ (i)&lt;br /&gt;
                  (build-vector (vector-length v2)&lt;br /&gt;
                                (λ (j) (* (vector-ref v1 i) (vector-ref v2 j)))))))&lt;br /&gt;
&lt;br /&gt;
(define (mat-vec-mul M v)       ; M (rows×cols) × v (cols)&lt;br /&gt;
  (build-vector (vector-length M)&lt;br /&gt;
                (λ (i)&lt;br /&gt;
                  (for/sum ([j (in-range (vector-length v))])&lt;br /&gt;
                    (* (vector-ref (vector-ref M i) j)&lt;br /&gt;
                       (vector-ref v j))))))&lt;br /&gt;
&lt;br /&gt;
(define (transpose M)&lt;br /&gt;
  (build-vector (vector-length (vector-ref M 0))&lt;br /&gt;
                (λ (j)&lt;br /&gt;
                  (build-vector (vector-length M)&lt;br /&gt;
                                (λ (i) (vector-ref (vector-ref M i) j))))))&lt;br /&gt;
&lt;br /&gt;
;; ======================================== &lt;br /&gt;
;; Neuralt nätverk&lt;br /&gt;
;; ========================================&lt;br /&gt;
(struct nn (w1 b1 w2 b2) #:transparent)&lt;br /&gt;
&lt;br /&gt;
(define (make-nn in-size hidden-size out-size)&lt;br /&gt;
  (nn (random-matrix hidden-size in-size)&lt;br /&gt;
      (make-vector hidden-size 0.0)&lt;br /&gt;
      (random-matrix out-size hidden-size)&lt;br /&gt;
      (make-vector out-size 0.0)))&lt;br /&gt;
&lt;br /&gt;
(define (forward net input)          ; input är en vektor t.ex. #(0 0)&lt;br /&gt;
  (let* ([z1 (vec-add (mat-vec-mul (nn-w1 net) input)&lt;br /&gt;
                      (nn-b1 net))]&lt;br /&gt;
         [h  (build-vector (vector-length z1) (λ (i) (sigmoid (vector-ref z1 i))))]&lt;br /&gt;
         [z2 (vec-add (mat-vec-mul (nn-w2 net) h)&lt;br /&gt;
                      (nn-b2 net))]&lt;br /&gt;
         [o  (build-vector (vector-length z2) (λ (i) (sigmoid (vector-ref z2 i))))])&lt;br /&gt;
    (values o h)))&lt;br /&gt;
&lt;br /&gt;
(define (train-step net input target lr)&lt;br /&gt;
  (let-values ([(output hidden) (forward net input)])&lt;br /&gt;
    (let* ([out-err (build-vector (vector-length output)&lt;br /&gt;
                                  (λ (i) (- (vector-ref output i)&lt;br /&gt;
                                            (vector-ref target i))))]&lt;br /&gt;
           [out-delta (build-vector (vector-length output)&lt;br /&gt;
                                    (λ (i) (* (vector-ref out-err i)&lt;br /&gt;
                                              (sigmoid-deriv (vector-ref output i)))))]&lt;br /&gt;
&lt;br /&gt;
           [hidden-err (mat-vec-mul (transpose (nn-w2 net)) out-delta)]&lt;br /&gt;
           [hidden-delta (build-vector (vector-length hidden)&lt;br /&gt;
                                       (λ (i) (* (vector-ref hidden-err i)&lt;br /&gt;
                                                 (sigmoid-deriv (vector-ref hidden i)))))]&lt;br /&gt;
&lt;br /&gt;
           ;; Uppdateringar&lt;br /&gt;
           [dw2 (outer-product out-delta hidden)]&lt;br /&gt;
           [new-w2 (build-vector (vector-length (nn-w2 net))&lt;br /&gt;
                                 (λ (i)&lt;br /&gt;
                                   (build-vector (vector-length (vector-ref (nn-w2 net) i))&lt;br /&gt;
                                                 (λ (j) (- (vector-ref (vector-ref (nn-w2 net) i) j)&lt;br /&gt;
                                                           (* lr (vector-ref (vector-ref dw2 i) j)))))))]&lt;br /&gt;
           [new-b2 (build-vector (vector-length (nn-b2 net))&lt;br /&gt;
                                 (λ (i) (- (vector-ref (nn-b2 net) i)&lt;br /&gt;
                                           (* lr (vector-ref out-delta i)))))]&lt;br /&gt;
&lt;br /&gt;
           [dw1 (outer-product hidden-delta input)]&lt;br /&gt;
           [new-w1 (build-vector (vector-length (nn-w1 net))&lt;br /&gt;
                                 (λ (i)&lt;br /&gt;
                                   (build-vector (vector-length (vector-ref (nn-w1 net) i))&lt;br /&gt;
                                                 (λ (j) (- (vector-ref (vector-ref (nn-w1 net) i) j)&lt;br /&gt;
                                                           (* lr (vector-ref (vector-ref dw1 i) j)))))))]&lt;br /&gt;
           [new-b1 (build-vector (vector-length (nn-b1 net))&lt;br /&gt;
                                 (λ (i) (- (vector-ref (nn-b1 net) i)&lt;br /&gt;
                                           (* lr (vector-ref hidden-delta i)))))])&lt;br /&gt;
&lt;br /&gt;
      (nn new-w1 new-b1 new-w2 new-b2))))&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;; ========================================&lt;br /&gt;
;; Skriv ut vikter och bias – snygg tabell (fixad version)&lt;br /&gt;
;; ========================================&lt;br /&gt;
(define (print-nn net)&lt;br /&gt;
  (printf &amp;quot;\n=== NEURALT NÄTVERK - VIKTER OCH BIAS ===\n\n&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
  ;; Hjälpfunktion för att formatera tal snyggt (med minustecken på rätt plats)&lt;br /&gt;
  (define (fmt x)&lt;br /&gt;
    (~r x &lt;br /&gt;
        #:min-width 10 &lt;br /&gt;
        #:precision &#039;(= 4)&lt;br /&gt;
        #:sign #f))          ; #f = visa minus för negativa, inget tecken för positiva&lt;br /&gt;
&lt;br /&gt;
  ;; W1: Vikter från input till hidden (5×2)&lt;br /&gt;
  (printf &amp;quot;W1 (Hidden × Input):\n&amp;quot;)&lt;br /&gt;
  (printf &amp;quot;          Input0      Input1\n&amp;quot;)&lt;br /&gt;
  (for ([i (in-range (vector-length (nn-w1 net)))])&lt;br /&gt;
    (printf &amp;quot;Hidden~a  &amp;quot; i)&lt;br /&gt;
    (for ([j (in-range 2)])&lt;br /&gt;
      (printf &amp;quot;~a  &amp;quot; (fmt (vector-ref (vector-ref (nn-w1 net) i) j))))&lt;br /&gt;
    (printf &amp;quot;\n&amp;quot;))&lt;br /&gt;
  (printf &amp;quot;\n&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
  ;; b1: Bias för hidden layer&lt;br /&gt;
  (printf &amp;quot;b1 (Bias hidden layer):\n&amp;quot;)&lt;br /&gt;
  (for ([i (in-range (vector-length (nn-b1 net)))])&lt;br /&gt;
    (printf &amp;quot;~a  &amp;quot; (fmt (vector-ref (nn-b1 net) i))))&lt;br /&gt;
  (printf &amp;quot;\n\n&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
  ;; W2: Vikter från hidden till output (1×5)&lt;br /&gt;
  (printf &amp;quot;W2 (Output × Hidden):\n&amp;quot;)&lt;br /&gt;
  (printf &amp;quot;         Hidden0     Hidden1     Hidden2     Hidden3     Hidden4\n&amp;quot;)&lt;br /&gt;
  (printf &amp;quot;Output   &amp;quot;)&lt;br /&gt;
  (for ([j (in-range 5)])&lt;br /&gt;
    (printf &amp;quot;~a  &amp;quot; (fmt (vector-ref (vector-ref (nn-w2 net) 0) j))))&lt;br /&gt;
  (printf &amp;quot;\n\n&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
  ;; b2: Bias för output&lt;br /&gt;
  (printf &amp;quot;b2 (Bias output):\n&amp;quot;)&lt;br /&gt;
  (printf &amp;quot;~a\n&amp;quot; (fmt (vector-ref (nn-b2 net) 0)))&lt;br /&gt;
&lt;br /&gt;
  (printf &amp;quot;\n========================================\n&amp;quot;))&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;; Träna nätverket&lt;br /&gt;
(define (train net data epochs lr)&lt;br /&gt;
  (for ([ep (in-range epochs)])&lt;br /&gt;
    (for ([sample data])&lt;br /&gt;
      (set! net (train-step net (car sample) (cadr sample) lr)))&lt;br /&gt;
    &lt;br /&gt;
    (when (zero? (modulo ep 500))      ; oftare än var 1000:e&lt;br /&gt;
      (let ([loss (for/sum ([sample data])&lt;br /&gt;
                    (let-values ([(output _) (forward net (car sample))])&lt;br /&gt;
                      (let ([target (vector-ref (cadr sample) 0)]&lt;br /&gt;
                            [pred   (vector-ref output 0)])&lt;br /&gt;
                        (sqr (- target pred)))))])&lt;br /&gt;
        (printf &amp;quot;Epoch ~a  Loss: ~a\n&amp;quot; ep (/ loss (length data))))))&lt;br /&gt;
  (print-nn net)&lt;br /&gt;
  net)&lt;br /&gt;
&lt;br /&gt;
;; Prediktera&lt;br /&gt;
(define (predict net input)&lt;br /&gt;
  (let-values ([(output _) (forward net input)])&lt;br /&gt;
    output))&lt;br /&gt;
&lt;br /&gt;
;; ========================================&lt;br /&gt;
;; XOR-exempel&lt;br /&gt;
;; ========================================&lt;br /&gt;
(define xor-data&lt;br /&gt;
  (list (list #(0 0) #(0))&lt;br /&gt;
        (list #(0 1) #(1))&lt;br /&gt;
        (list #(1 0) #(1))&lt;br /&gt;
        (list #(1 1) #(0))))&lt;br /&gt;
&lt;br /&gt;
(define net (make-nn 2 5 1))   ; 2 input, 5 dolda neuroner, 1 output&lt;br /&gt;
(define rounds 8000) ; 2000 är i minsta laget, 5000 eller hellre 8000 är bättre&lt;br /&gt;
(define backpr 0.7)&lt;br /&gt;
(printf &amp;quot;Tränar XOR-problemet i ~a rundor med backprop styrka ~a\n&amp;quot; rounds backpr)&lt;br /&gt;
(set! net (train net xor-data rounds backpr))&lt;br /&gt;
&lt;br /&gt;
(printf &amp;quot;\n=== Testresultat ===\n&amp;quot;)&lt;br /&gt;
(for ([sample xor-data])&lt;br /&gt;
  (let ([pred (vector-ref (predict net (car sample)) 0)])&lt;br /&gt;
    (printf &amp;quot;Input ~a  →  Förväntat: ~a  Predikterat: ~a\n&amp;quot;&lt;br /&gt;
            (car sample)&lt;br /&gt;
            (vector-ref (cadr sample) 0)&lt;br /&gt;
            (if (&amp;gt; pred 0.5) 1.0 0.0))))&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>Anders</name></author>
	</entry>
	<entry>
		<id>http://wiki.sikvall.se/index.php?title=Racket/Erastothenes&amp;diff=1918</id>
		<title>Racket/Erastothenes</title>
		<link rel="alternate" type="text/html" href="http://wiki.sikvall.se/index.php?title=Racket/Erastothenes&amp;diff=1918"/>
		<updated>2026-06-29T15:52:10Z</updated>

		<summary type="html">&lt;p&gt;Anders: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
#lang racket&lt;br /&gt;
&lt;br /&gt;
;;;;;&lt;br /&gt;
;; Eratosthenes såll implementerad i Racket&lt;br /&gt;
;; Täpp-Anders Sikvall 2026-04-03 anders@sikvall.se&lt;br /&gt;
;;;;;&lt;br /&gt;
&lt;br /&gt;
(require racket/format)&lt;br /&gt;
&lt;br /&gt;
;; Skapar en vektor där indexet motsvarar talet.&lt;br /&gt;
;; Om (vector-ref v n) är #t, så är n ett primtal.&lt;br /&gt;
(define (make-sieve limit)&lt;br /&gt;
  ;; 1 SKAPA VEKTORN&lt;br /&gt;
  ;; Vi skapar en vektor med storleken (limit + 1). Eftersom index börjar på 0,&lt;br /&gt;
  ;; måste vektorn vara ett element större än &#039;limit&#039; för att &#039;limit&#039; ska få plats som sista index.&lt;br /&gt;
  ;; Vi antar från början att ALLA tal är primtal (#t), och sållar sedan bort de som inte är det.&lt;br /&gt;
  (define sieve (make-vector (add1 limit) #t))&lt;br /&gt;
  &lt;br /&gt;
  ;; 2 BASFALL (0 OCH 1)&lt;br /&gt;
  ;; 0 och 1 är aldrig primtal enligt definitionen (ett primtal måste vara större än 1).&lt;br /&gt;
  ;; Om användaren har angett en limit som inkluderar dessa, markerar vi dem direkt som #f (falskt).&lt;br /&gt;
  (when (&amp;gt;= limit 0) (vector-set! sieve 0 #f))&lt;br /&gt;
  (when (&amp;gt;= limit 1) (vector-set! sieve 1 #f))&lt;br /&gt;
  &lt;br /&gt;
  ;; 3 HUVUDLOOPEN (YTTRE)&lt;br /&gt;
  ;; Vi behöver bara gå upp till kvadratroten av limit (avrundat nedåt till heltal).&lt;br /&gt;
  ;; Varför? Om ett tal har en faktor som är större än kvadratroten, måste dess &lt;br /&gt;
  ;; motsvarande partnerfaktor vara mindre än kvadratroten. Har vi redan rensat&lt;br /&gt;
  ;; alla mindre faktorer så har vi automatiskt tagit hand om de större!&lt;br /&gt;
  (for ((p (in-range 2 (add1 (integer-sqrt limit)))))&lt;br /&gt;
    &lt;br /&gt;
    ;; Om index &#039;p&#039; fortfarande är #t, så har vi hittat ett primtal.&lt;br /&gt;
    (when (vector-ref sieve p)&lt;br /&gt;
      &lt;br /&gt;
      ;; 4 SÅLLNINGSLOOPEN (INRE)&lt;br /&gt;
      ;; Markera alla multiplar av p som falska (inte primtal).&lt;br /&gt;
      ;; Optimering: Vi startar direkt vid (* p p) istället för (* p 2).&lt;br /&gt;
      ;; Varför? Alla multiplar mindre än p*p (som 2p, 3p, 4p... upp till (p-1)p) &lt;br /&gt;
      ;; har redan markerats som #f i tidigare varv av den yttre loopen.&lt;br /&gt;
      ;; Det tredje argumentet &#039;p&#039; gör att loopen hoppar med p-steg i taget (p*p, p*p+p, p*p+2p, osv).&lt;br /&gt;
      (for ((multiple (in-range (* p p) (add1 limit) p)))&lt;br /&gt;
        (vector-set! sieve multiple #f)))) ; inte primtal&lt;br /&gt;
        &lt;br /&gt;
  ;; Returnera det färdiga sållet (vektorn) till anroparen&lt;br /&gt;
  sieve)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;; Returnerar en lista med alla primtal mellan start och stop&lt;br /&gt;
(define (primes-between start stop)&lt;br /&gt;
  ;; Kontrollera om intervallet är logiskt. Om start är större än stop finns det inga tal.&lt;br /&gt;
  (if (&amp;gt; start stop)&lt;br /&gt;
      &#039;() ; Returnerar tomt om start &amp;gt; stop&lt;br /&gt;
      &lt;br /&gt;
      ;; Skapa sållet för hela intervallet upp till &#039;stop&#039;.&lt;br /&gt;
      (let ((is-prime? (make-sieve stop)))&lt;br /&gt;
        &lt;br /&gt;
        ;; for/list samlar automatiskt ihop alla &#039;n&#039; som matchar villkoret till en lista.&lt;br /&gt;
        ;; (max start 2) förhindrar att vi letar efter primtal under 2, då de inte finns.&lt;br /&gt;
        (for/list ((n (in-range (max start 2) (add1 stop)))&lt;br /&gt;
                   #:when (vector-ref is-prime? n)) ; Villkor: Endast om index n är #t i sållet&lt;br /&gt;
          n))))&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;; Hjälpmakro för att tajma hur lång tid operationen tog&lt;br /&gt;
(define-syntax-rule (timeit expr)&lt;br /&gt;
  ;; Spara starttiden i millisekunder innan uttrycket körs&lt;br /&gt;
  (let ((start (current-inexact-milliseconds)))&lt;br /&gt;
    ;; Kör uttrycket &#039;expr&#039; (t.ex. vår funktion) och spara resultatet i &#039;result&#039;&lt;br /&gt;
    (let ((result expr))&lt;br /&gt;
      ;; Skriv ut tidsskillnaden med snygg lokal formatering&lt;br /&gt;
      (printf &amp;quot;Tid: ~a ms\n&amp;quot; (~r (- (current-inexact-milliseconds) start)&lt;br /&gt;
                                #:group-sep   &amp;quot; &amp;quot;     ; tusentalsavskiljare (blanksteg)&lt;br /&gt;
                                #:decimal-sep &amp;quot;,&amp;quot;     ; decimalsavskiljare (komma)&lt;br /&gt;
                                #:precision     2))   ; avrunda till 2 decimaler&lt;br /&gt;
      result)))  ; Returnera svaret från expr så att programmet kan använda det&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;; Testkörning&lt;br /&gt;
(timeit (primes-between 10000000 10000500))&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>Anders</name></author>
	</entry>
	<entry>
		<id>http://wiki.sikvall.se/index.php?title=Racket/Erastothenes&amp;diff=1917</id>
		<title>Racket/Erastothenes</title>
		<link rel="alternate" type="text/html" href="http://wiki.sikvall.se/index.php?title=Racket/Erastothenes&amp;diff=1917"/>
		<updated>2026-06-29T15:51:49Z</updated>

		<summary type="html">&lt;p&gt;Anders: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;#lang racket&lt;br /&gt;
&lt;br /&gt;
;;;;;&lt;br /&gt;
;; Eratosthenes såll implementerad i Racket&lt;br /&gt;
;; Täpp-Anders Sikvall 2026-04-03 anders@sikvall.se&lt;br /&gt;
;;;;;&lt;br /&gt;
&lt;br /&gt;
(require racket/format)&lt;br /&gt;
&lt;br /&gt;
;; Skapar en vektor där indexet motsvarar talet.&lt;br /&gt;
;; Om (vector-ref v n) är #t, så är n ett primtal.&lt;br /&gt;
(define (make-sieve limit)&lt;br /&gt;
  ;; 1 SKAPA VEKTORN&lt;br /&gt;
  ;; Vi skapar en vektor med storleken (limit + 1). Eftersom index börjar på 0,&lt;br /&gt;
  ;; måste vektorn vara ett element större än &#039;limit&#039; för att &#039;limit&#039; ska få plats som sista index.&lt;br /&gt;
  ;; Vi antar från början att ALLA tal är primtal (#t), och sållar sedan bort de som inte är det.&lt;br /&gt;
  (define sieve (make-vector (add1 limit) #t))&lt;br /&gt;
  &lt;br /&gt;
  ;; 2 BASFALL (0 OCH 1)&lt;br /&gt;
  ;; 0 och 1 är aldrig primtal enligt definitionen (ett primtal måste vara större än 1).&lt;br /&gt;
  ;; Om användaren har angett en limit som inkluderar dessa, markerar vi dem direkt som #f (falskt).&lt;br /&gt;
  (when (&amp;gt;= limit 0) (vector-set! sieve 0 #f))&lt;br /&gt;
  (when (&amp;gt;= limit 1) (vector-set! sieve 1 #f))&lt;br /&gt;
  &lt;br /&gt;
  ;; 3 HUVUDLOOPEN (YTTRE)&lt;br /&gt;
  ;; Vi behöver bara gå upp till kvadratroten av limit (avrundat nedåt till heltal).&lt;br /&gt;
  ;; Varför? Om ett tal har en faktor som är större än kvadratroten, måste dess &lt;br /&gt;
  ;; motsvarande partnerfaktor vara mindre än kvadratroten. Har vi redan rensat&lt;br /&gt;
  ;; alla mindre faktorer så har vi automatiskt tagit hand om de större!&lt;br /&gt;
  (for ((p (in-range 2 (add1 (integer-sqrt limit)))))&lt;br /&gt;
    &lt;br /&gt;
    ;; Om index &#039;p&#039; fortfarande är #t, så har vi hittat ett primtal.&lt;br /&gt;
    (when (vector-ref sieve p)&lt;br /&gt;
      &lt;br /&gt;
      ;; 4 SÅLLNINGSLOOPEN (INRE)&lt;br /&gt;
      ;; Markera alla multiplar av p som falska (inte primtal).&lt;br /&gt;
      ;; Optimering: Vi startar direkt vid (* p p) istället för (* p 2).&lt;br /&gt;
      ;; Varför? Alla multiplar mindre än p*p (som 2p, 3p, 4p... upp till (p-1)p) &lt;br /&gt;
      ;; har redan markerats som #f i tidigare varv av den yttre loopen.&lt;br /&gt;
      ;; Det tredje argumentet &#039;p&#039; gör att loopen hoppar med p-steg i taget (p*p, p*p+p, p*p+2p, osv).&lt;br /&gt;
      (for ((multiple (in-range (* p p) (add1 limit) p)))&lt;br /&gt;
        (vector-set! sieve multiple #f)))) ; inte primtal&lt;br /&gt;
        &lt;br /&gt;
  ;; Returnera det färdiga sållet (vektorn) till anroparen&lt;br /&gt;
  sieve)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;; Returnerar en lista med alla primtal mellan start och stop&lt;br /&gt;
(define (primes-between start stop)&lt;br /&gt;
  ;; Kontrollera om intervallet är logiskt. Om start är större än stop finns det inga tal.&lt;br /&gt;
  (if (&amp;gt; start stop)&lt;br /&gt;
      &#039;() ; Returnerar tomt om start &amp;gt; stop&lt;br /&gt;
      &lt;br /&gt;
      ;; Skapa sållet för hela intervallet upp till &#039;stop&#039;.&lt;br /&gt;
      (let ((is-prime? (make-sieve stop)))&lt;br /&gt;
        &lt;br /&gt;
        ;; for/list samlar automatiskt ihop alla &#039;n&#039; som matchar villkoret till en lista.&lt;br /&gt;
        ;; (max start 2) förhindrar att vi letar efter primtal under 2, då de inte finns.&lt;br /&gt;
        (for/list ((n (in-range (max start 2) (add1 stop)))&lt;br /&gt;
                   #:when (vector-ref is-prime? n)) ; Villkor: Endast om index n är #t i sållet&lt;br /&gt;
          n))))&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;; Hjälpmakro för att tajma hur lång tid operationen tog&lt;br /&gt;
(define-syntax-rule (timeit expr)&lt;br /&gt;
  ;; Spara starttiden i millisekunder innan uttrycket körs&lt;br /&gt;
  (let ((start (current-inexact-milliseconds)))&lt;br /&gt;
    ;; Kör uttrycket &#039;expr&#039; (t.ex. vår funktion) och spara resultatet i &#039;result&#039;&lt;br /&gt;
    (let ((result expr))&lt;br /&gt;
      ;; Skriv ut tidsskillnaden med snygg lokal formatering&lt;br /&gt;
      (printf &amp;quot;Tid: ~a ms\n&amp;quot; (~r (- (current-inexact-milliseconds) start)&lt;br /&gt;
                                #:group-sep   &amp;quot; &amp;quot;     ; tusentalsavskiljare (blanksteg)&lt;br /&gt;
                                #:decimal-sep &amp;quot;,&amp;quot;     ; decimalsavskiljare (komma)&lt;br /&gt;
                                #:precision     2))   ; avrunda till 2 decimaler&lt;br /&gt;
      result)))  ; Returnera svaret från expr så att programmet kan använda det&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;; Testkörning&lt;br /&gt;
(timeit (primes-between 10000000 10000500))&lt;/div&gt;</summary>
		<author><name>Anders</name></author>
	</entry>
	<entry>
		<id>http://wiki.sikvall.se/index.php?title=Racket/Erastothenes&amp;diff=1916</id>
		<title>Racket/Erastothenes</title>
		<link rel="alternate" type="text/html" href="http://wiki.sikvall.se/index.php?title=Racket/Erastothenes&amp;diff=1916"/>
		<updated>2026-06-29T15:51:17Z</updated>

		<summary type="html">&lt;p&gt;Anders: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;#lang racket&lt;br /&gt;
&lt;br /&gt;
;;;;;&lt;br /&gt;
;; Eratosthenes såll implementerad i Racket&lt;br /&gt;
;; Täpp-Anders Sikvall 2026-04-03 anders@sikvall.se&lt;br /&gt;
;;;;;&lt;br /&gt;
&lt;br /&gt;
(require racket/format)&lt;br /&gt;
&lt;br /&gt;
;; Skapar en vektor där indexet motsvarar talet.&lt;br /&gt;
;; Om (vector-ref v n) är #t, så är n ett primtal.&lt;br /&gt;
(define (make-sieve limit)&lt;br /&gt;
  ;; 1. SKAPA VEKTORN&lt;br /&gt;
  ;; Vi skapar en vektor med storleken (limit + 1). Eftersom index börjar på 0,&lt;br /&gt;
  ;; måste vektorn vara ett element större än &#039;limit&#039; för att &#039;limit&#039; ska få plats som sista index.&lt;br /&gt;
  ;; Vi antar från början att ALLA tal är primtal (#t), och sållar sedan bort de som inte är det.&lt;br /&gt;
  (define sieve (make-vector (add1 limit) #t))&lt;br /&gt;
  &lt;br /&gt;
  ;; 2. BASFALL (0 OCH 1)&lt;br /&gt;
  ;; 0 och 1 är aldrig primtal enligt definitionen (ett primtal måste vara större än 1).&lt;br /&gt;
  ;; Om användaren har angett en limit som inkluderar dessa, markerar vi dem direkt som #f (falskt).&lt;br /&gt;
  (when (&amp;gt;= limit 0) (vector-set! sieve 0 #f))&lt;br /&gt;
  (when (&amp;gt;= limit 1) (vector-set! sieve 1 #f))&lt;br /&gt;
  &lt;br /&gt;
  ;; 3. HUVUDLOOPEN (YTTRE)&lt;br /&gt;
  ;; Vi behöver bara gå upp till kvadratroten av limit (avrundat nedåt till heltal).&lt;br /&gt;
  ;; Varför? Om ett tal har en faktor som är större än kvadratroten, måste dess &lt;br /&gt;
  ;; motsvarande partnerfaktor vara mindre än kvadratroten. Har vi redan rensat&lt;br /&gt;
  ;; alla mindre faktorer så har vi automatiskt tagit hand om de större!&lt;br /&gt;
  (for ((p (in-range 2 (add1 (integer-sqrt limit)))))&lt;br /&gt;
    &lt;br /&gt;
    ;; Om index &#039;p&#039; fortfarande är #t, så har vi hittat ett primtal.&lt;br /&gt;
    (when (vector-ref sieve p)&lt;br /&gt;
      &lt;br /&gt;
      ;; 4. SÅLLNINGSLOOPEN (INRE)&lt;br /&gt;
      ;; Markera alla multiplar av p som falska (inte primtal).&lt;br /&gt;
      ;; Optimering: Vi startar direkt vid (* p p) istället för (* p 2).&lt;br /&gt;
      ;; Varför? Alla multiplar mindre än p*p (som 2p, 3p, 4p... upp till (p-1)p) &lt;br /&gt;
      ;; har redan markerats som #f i tidigare varv av den yttre loopen.&lt;br /&gt;
      ;; Det tredje argumentet &#039;p&#039; gör att loopen hoppar med p-steg i taget (p*p, p*p+p, p*p+2p, osv).&lt;br /&gt;
      (for ((multiple (in-range (* p p) (add1 limit) p)))&lt;br /&gt;
        (vector-set! sieve multiple #f)))) ; inte primtal&lt;br /&gt;
        &lt;br /&gt;
  ;; Returnera det färdiga sållet (vektorn) till anroparen&lt;br /&gt;
  sieve)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;; Returnerar en lista med alla primtal mellan start och stop&lt;br /&gt;
(define (primes-between start stop)&lt;br /&gt;
  ;; Kontrollera om intervallet är logiskt. Om start är större än stop finns det inga tal.&lt;br /&gt;
  (if (&amp;gt; start stop)&lt;br /&gt;
      &#039;() ; Returnerar tomt om start &amp;gt; stop&lt;br /&gt;
      &lt;br /&gt;
      ;; Skapa sållet för hela intervallet upp till &#039;stop&#039;.&lt;br /&gt;
      (let ((is-prime? (make-sieve stop)))&lt;br /&gt;
        &lt;br /&gt;
        ;; for/list samlar automatiskt ihop alla &#039;n&#039; som matchar villkoret till en lista.&lt;br /&gt;
        ;; (max start 2) förhindrar att vi letar efter primtal under 2, då de inte finns.&lt;br /&gt;
        (for/list ((n (in-range (max start 2) (add1 stop)))&lt;br /&gt;
                   #:when (vector-ref is-prime? n)) ; Villkor: Endast om index n är #t i sållet&lt;br /&gt;
          n))))&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;; Hjälpmakro för att tajma hur lång tid operationen tog&lt;br /&gt;
(define-syntax-rule (timeit expr)&lt;br /&gt;
  ;; Spara starttiden i millisekunder innan uttrycket körs&lt;br /&gt;
  (let ((start (current-inexact-milliseconds)))&lt;br /&gt;
    ;; Kör uttrycket &#039;expr&#039; (t.ex. vår funktion) och spara resultatet i &#039;result&#039;&lt;br /&gt;
    (let ((result expr))&lt;br /&gt;
      ;; Skriv ut tidsskillnaden med snygg lokal formatering&lt;br /&gt;
      (printf &amp;quot;Tid: ~a ms\n&amp;quot; (~r (- (current-inexact-milliseconds) start)&lt;br /&gt;
                                #:group-sep   &amp;quot; &amp;quot;     ; tusentalsavskiljare (blanksteg)&lt;br /&gt;
                                #:decimal-sep &amp;quot;,&amp;quot;     ; decimalsavskiljare (komma)&lt;br /&gt;
                                #:precision     2))   ; avrunda till 2 decimaler&lt;br /&gt;
      result)))  ; Returnera svaret från expr så att programmet kan använda det&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;; Testkörning&lt;br /&gt;
(timeit (primes-between 10000000 10000500))&lt;/div&gt;</summary>
		<author><name>Anders</name></author>
	</entry>
	<entry>
		<id>http://wiki.sikvall.se/index.php?title=Racket/Erastothenes&amp;diff=1915</id>
		<title>Racket/Erastothenes</title>
		<link rel="alternate" type="text/html" href="http://wiki.sikvall.se/index.php?title=Racket/Erastothenes&amp;diff=1915"/>
		<updated>2026-06-29T15:42:26Z</updated>

		<summary type="html">&lt;p&gt;Anders: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[category:Algoritmer]]&lt;br /&gt;
[[category:Programmering]]&lt;br /&gt;
[[category:Racket]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#lang racket&lt;br /&gt;
&lt;br /&gt;
;;;;;&lt;br /&gt;
;; Erastothenes såll implementerad i Racket&lt;br /&gt;
;; Täpp-Anders Sikvall 2026-04-03 anders@sikvall.se&lt;br /&gt;
;;;;;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;; Skapar en vektor där indexet motsvarar talet.&lt;br /&gt;
;; Om (vector-ref v n) är #t, så är n ett primtal.&lt;br /&gt;
&lt;br /&gt;
(define (make-sieve limit)&lt;br /&gt;
  (define sieve (make-vector (add1 limit) #t))&lt;br /&gt;
  &lt;br /&gt;
  ;; 0 och 1 är aldrig primtal&lt;br /&gt;
  ;; Primtal är tal som är större än 1 och endast jämt delbara med&lt;br /&gt;
  ;; sig själv eller 1. Så börja med att markera 0 och 1 som icke-prim.&lt;br /&gt;
  (when (&amp;gt;= limit 0) (vector-set! sieve 0 #f))&lt;br /&gt;
  (when (&amp;gt;= limit 1) (vector-set! sieve 1 #f))&lt;br /&gt;
  &lt;br /&gt;
  ;; Vi behöver bara gå upp till kvadratroten av limit&lt;br /&gt;
  ;; p går från start till stopp och markerar alla multiplar som &lt;br /&gt;
  ;; icke prima. Dvs 2, 4, 6, 8, 10, 12 osv (alla multiplar av 2)&lt;br /&gt;
  ;; sedan 3, 6, 9, 12, 15 osv (alla multiplar av 3) etc&lt;br /&gt;
  ;; det som inte är markera när vi når sqrt(limit)+1 är alltså primtal&lt;br /&gt;
  (for ((p (in-range 2 (add1 (integer-sqrt limit)))))&lt;br /&gt;
    (when (vector-ref sieve p)&lt;br /&gt;
      ;; Markera alla multiplar av p som falska (starta vid p*p)&lt;br /&gt;
      (for ((multiple (in-range (* p p) (add1 limit) p)))&lt;br /&gt;
        (vector-set! sieve multiple #f)))) ; inte primtal&lt;br /&gt;
  ;; returnera sållet till anroparen&lt;br /&gt;
  sieve)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;; Returnerar en lista med alla primtal mellan start och stop&lt;br /&gt;
(define (primes-between start stop)&lt;br /&gt;
  (if (&amp;gt; start stop)&lt;br /&gt;
      &#039;() ;Returnerar tomt om start &amp;gt; stop&lt;br /&gt;
      (let ([is-prime? (make-sieve stop)])&lt;br /&gt;
        (for/list ([n (in-range (max start 2) (add1 stop))]&lt;br /&gt;
                   #:when (vector-ref is-prime? n))&lt;br /&gt;
          n))))&lt;br /&gt;
&lt;br /&gt;
;; Hjälpmakro för att tajma hur lång tid operationen tog&lt;br /&gt;
(require racket/format)&lt;br /&gt;
(define-syntax-rule (timeit expr)&lt;br /&gt;
  (let ((start (current-inexact-milliseconds)))&lt;br /&gt;
    (let ((result expr))&lt;br /&gt;
      (printf &amp;quot;Tid: ~a ms\n&amp;quot; (~r (- (current-inexact-milliseconds) start)&lt;br /&gt;
              #:group-sep &amp;quot; &amp;quot;     ;tusentalsavskiljare&lt;br /&gt;
              #:decimal-sep &amp;quot;,&amp;quot;   ;decimalsavskiljare&lt;br /&gt;
              #:precision 2))     ;antal decimaler&lt;br /&gt;
      result)))  ; returnera svaret&lt;br /&gt;
&lt;br /&gt;
;; Testkörning&lt;br /&gt;
(timeit (primes-between 10000000 10000100))&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>Anders</name></author>
	</entry>
	<entry>
		<id>http://wiki.sikvall.se/index.php?title=Racket/Erastothenes&amp;diff=1914</id>
		<title>Racket/Erastothenes</title>
		<link rel="alternate" type="text/html" href="http://wiki.sikvall.se/index.php?title=Racket/Erastothenes&amp;diff=1914"/>
		<updated>2026-06-29T14:31:10Z</updated>

		<summary type="html">&lt;p&gt;Anders: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[category:Algoritmer]]&lt;br /&gt;
[[category:Programmering]]&lt;br /&gt;
[[category:Racket]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#lang racket&lt;br /&gt;
&lt;br /&gt;
;;;;;&lt;br /&gt;
;; Erastothenes såll implementerad i Racket&lt;br /&gt;
;; Täpp-Anders Sikvall 2026-04-03 anders@sikvall.se&lt;br /&gt;
;;;;;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;; Skapar en vektor där indexet motsvarar talet.&lt;br /&gt;
;; Om (vector-ref v n) är #t, så är n ett primtal.&lt;br /&gt;
&lt;br /&gt;
(define (make-sieve limit)&lt;br /&gt;
  (define sieve (make-vector (add1 limit) #t))&lt;br /&gt;
  &lt;br /&gt;
  ;; 0 och 1 är aldrig primtal&lt;br /&gt;
  (when (&amp;gt;= limit 0) (vector-set! sieve 0 #f))&lt;br /&gt;
  (when (&amp;gt;= limit 1) (vector-set! sieve 1 #f))&lt;br /&gt;
  &lt;br /&gt;
  ;; Vi behöver bara gå upp till kvadratroten av limit&lt;br /&gt;
  (for ([p (in-range 2 (add1 (integer-sqrt limit)))])&lt;br /&gt;
    (when (vector-ref sieve p)&lt;br /&gt;
      ;; Markera alla multiplar av p som falska (starta vid p*p)&lt;br /&gt;
      (for ([multiple (in-range (* p p) (add1 limit) p)])&lt;br /&gt;
        (vector-set! sieve multiple #f))))&lt;br /&gt;
  ;; returnera sållet till anroparen&lt;br /&gt;
  sieve)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;; Returnerar en lista med alla primtal mellan start och stop&lt;br /&gt;
(define (primes-between start stop)&lt;br /&gt;
  (if (&amp;gt; start stop)&lt;br /&gt;
      &#039;() ;Returnerar tomt om start &amp;gt; stop&lt;br /&gt;
      (let ([is-prime? (make-sieve stop)])&lt;br /&gt;
        (for/list ([n (in-range (max start 2) (add1 stop))]&lt;br /&gt;
                   #:when (vector-ref is-prime? n))&lt;br /&gt;
          n))))&lt;br /&gt;
&lt;br /&gt;
;; Hjälpmakro för att tajma hur lång tid operationen tog&lt;br /&gt;
(require racket/format)&lt;br /&gt;
(define-syntax-rule (timeit expr)&lt;br /&gt;
  (let ((start (current-inexact-milliseconds)))&lt;br /&gt;
    (let ((result expr))&lt;br /&gt;
      (printf &amp;quot;Tid: ~a ms\n&amp;quot; (~r (- (current-inexact-milliseconds) start)&lt;br /&gt;
              #:group-sep &amp;quot; &amp;quot;     ;tusentalsavskiljare&lt;br /&gt;
              #:decimal-sep &amp;quot;,&amp;quot;   ;decimalsavskiljare&lt;br /&gt;
              #:precision 2))     ;antal decimaler&lt;br /&gt;
      result)))  ; returnera svaret&lt;br /&gt;
&lt;br /&gt;
;; Testkörning&lt;br /&gt;
(timeit (primes-between 10000000 10000100))&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>Anders</name></author>
	</entry>
	<entry>
		<id>http://wiki.sikvall.se/index.php?title=Viterbi&amp;diff=1913</id>
		<title>Viterbi</title>
		<link rel="alternate" type="text/html" href="http://wiki.sikvall.se/index.php?title=Viterbi&amp;diff=1913"/>
		<updated>2026-06-23T18:18:37Z</updated>

		<summary type="html">&lt;p&gt;Anders: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[category:algoritmer]]&lt;br /&gt;
[[category:felkorrigering]]&lt;br /&gt;
[[category:telekom]]&lt;br /&gt;
[[category:c]]&lt;br /&gt;
[[category:signalering]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Bakgrund = &lt;br /&gt;
&lt;br /&gt;
== Viterbis algoritm – Hur vi hittar rätt signal i bruset ==&lt;br /&gt;
&lt;br /&gt;
Inom amatörradion och digital signalbehandling stöter vi ofta på problemet med brus och fading. När vi skickar digital data över etern, till exempel med modernare digitala trafiksätt eller vid satellitkommunikation, använder vi ofta något som kallas för faltningskodning (convolutional coding). Det är en metod där varje sänd bit beror på både den nuvarande biten och ett antal tidigare bitar. Detta skapar ett mönster, ett beroende, som gör signalen robust.&lt;br /&gt;
&lt;br /&gt;
Men hur avkodar vi detta på mottagarsidan när atmosfären har ställt till det och lagt till en massa brus? Det är här Viterbis algoritm kommer in i bilden.&lt;br /&gt;
&lt;br /&gt;
Kort sagt är Viterbialgoritmen en metod för att hitta den mest troliga sekvensen av dolda tillstånd (det vi faktiskt sände) baserat på en serie observerade händelser (den brusiga signalen vi tog emot). Istället för att gissa bit för bit, tittar algoritmen på hela sammanhanget.&lt;br /&gt;
&lt;br /&gt;
== Trellis-diagrammet: Vägarna genom historien ==&lt;br /&gt;
&lt;br /&gt;
För att förstå hur algoritmen jobbar kan vi tänka oss ett nätverk av vägar, ett så kallat trellis-diagram.&lt;br /&gt;
&lt;br /&gt;
* Tillstånd (States): Radiosändarens &amp;quot;minne&amp;quot; kan vid varje given tidpunkt befinna sig i ett visst antal tillstånd (beroende på de senaste sända bitarna).&lt;br /&gt;
* Övergångar: När en ny bit ska sändas hoppar sändaren till ett nytt tillstånd och skickar ut en specifik kombination av bitar i luften.&lt;br /&gt;
&lt;br /&gt;
== Hur funkar det? ==&lt;br /&gt;
&lt;br /&gt;
När mottagaren lyssnar får den in en sekvens som kanske är halvt dränkt i brus. En nolla kanske ser ut som en svag etta, och så vidare. Viterbialgoritmen börjar nu räkna på alla möjliga vägar genom detta nätverk av tillstånd över tid.&lt;br /&gt;
Så här jobbar algoritmen steg för steg:&lt;br /&gt;
&lt;br /&gt;
# Beräkna avstånd (Metric): För varje steg i tiden tittar algoritmen på de bitar som faktiskt togs emot och jämför dem med vad som borde ha sänts för varje tänkbar väg i diagrammet. Man mäter &amp;quot;avståndet&amp;quot; (ofta Hamming-avstånd för ettor och nollor, eller Euklidiskt avstånd om man kör &amp;quot;soft decision&amp;quot; där man mäter signalstyrkan mer exakt). Ju mindre avstånd, desto mer troligt är det att den vägen är den rätta.&lt;br /&gt;
# Spara den bästa vägen (Add-Compare-Select): Till varje nytt tillstånd i diagrammet leder det oftast två olika vägar från det föregående steget. Algoritmen adderar det nya avståndet till det gamla, jämför de två alternativen, och väljer den väg som har lägst totalt avstånd (fel). Den andra vägen slängs bort för alltid. Det här är algoritmens stora styrka: den rensar hela tiden bort återvändsgränder så att beräkningsbördan inte exploderar.&lt;br /&gt;
# Lås historiken (Traceback): När hela sekvensen (eller ett tillräckligt långt block) har tagits emot, tittar man på vilket slutgiltigt tillstånd som har det absolut lägsta totala felvärdet. Sedan backar man bakåt genom de sparade &amp;quot;bästa vägarna&amp;quot; till början.&lt;br /&gt;
&lt;br /&gt;
Resultatet blir den absolut mest sannolika sekvensen av bitar som sändaren faktiskt skickade ut, trots att det var fullt av bitfel under resans gång.&lt;br /&gt;
&lt;br /&gt;
= Implementation i hyggligt modern C=&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
 * Anders Sikvall 2026 Version 1.0&lt;br /&gt;
 * &amp;lt;anders@sikvall.se&amp;gt;&lt;br /&gt;
 * &lt;br /&gt;
 * Implementation i C av en standard Viterbi-algoritm som används bl.a. av &lt;br /&gt;
 * Qualcomm och NASA och är välpublicerad.&lt;br /&gt;
 *&lt;br /&gt;
 * PUBLIC DOMAIN FOR EDUCATIONAL PURPOSES&lt;br /&gt;
 *&lt;br /&gt;
 * Kompilera med gcc -o viterbi viterbi.c&lt;br /&gt;
 *&lt;br /&gt;
 * ANVÄNDNING&lt;br /&gt;
 *         viterbi -e &amp;lt;indatastream &amp;gt;utdatastream   Kodar &amp;lt;indatastream till &amp;gt;utdatastream&lt;br /&gt;
 *         viterbi -d &amp;lt;indatastream &amp;gt;utdatastream   Avkodar &amp;lt;indatastream till &amp;gt;utdatastream&lt;br /&gt;
 *         viterbi -t                               Utför en intern test på 64 randomiserade oktetter&lt;br /&gt;
 *         viterbi -h                               Visar en kort hjälptext&lt;br /&gt;
 *         viterbi --error                          Samma sak som -t men introducerar 3 flippade bitpar&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
#include &amp;lt;string.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdbool.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdint.h&amp;gt;&lt;br /&gt;
#include &amp;lt;time.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
/* Constraint length (K=7) innebär att skiftregistret minns de senaste 7 bitarna. */&lt;br /&gt;
#define K 7&lt;br /&gt;
&lt;br /&gt;
/* Antalet tillstånd i trellis-diagrammet bestäms av de senaste K-1 bitarna.&lt;br /&gt;
   2^(7-1) = 2^6 = 64 unika tillstånd totalt. */&lt;br /&gt;
#define NUM_STATES (1 &amp;lt;&amp;lt; (K - 1))&lt;br /&gt;
&lt;br /&gt;
/* Standard NASA/Qualcomm-polynom för Rate 1/2 konvolutionskodning.&lt;br /&gt;
   POLY_G0 motsvarar oktalt 151 (1001111 binärt).&lt;br /&gt;
   POLY_G1 motsvarar oktalt 113 (1101101 binärt).&lt;br /&gt;
   Dessa maskar används för att bestämma vilka bitar i tillståndet som XOR-sammanfogas. */&lt;br /&gt;
const uint8_t POLY_G0 = 0x4F;&lt;br /&gt;
const uint8_t POLY_G1 = 0x6D;&lt;br /&gt;
&lt;br /&gt;
/* Hårdvaruoptimerad paritetsberäkning.&lt;br /&gt;
   Räknar antalet satta bitar (1:or) i ett tal och returnerar 1 om antalet är udda,&lt;br /&gt;
   eller 0 om antalet är jämnt (motsvarar en kedja av XOR-grindar). */&lt;br /&gt;
static inline uint8_t parity(uint8_t x) {&lt;br /&gt;
    return __builtin_parity(x) &amp;amp; 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// ============================================================================&lt;br /&gt;
// KODARE (-e)&lt;br /&gt;
// ============================================================================&lt;br /&gt;
void encode(FILE *in, FILE *out) {&lt;br /&gt;
    /* encoder_state lagrar historiken av de senaste K-1 (6) bitarna. */&lt;br /&gt;
    uint8_t encoder_state = 0;&lt;br /&gt;
&lt;br /&gt;
    /* out_byte används som en tillfällig buffer för att samla ihop bitar till en hel byte. */&lt;br /&gt;
    uint8_t out_byte = 0;&lt;br /&gt;
&lt;br /&gt;
    /* bit_count håller koll på hur många bitar som för tillfället ligger i utmatningsbufferten. */&lt;br /&gt;
    int bit_count = 0;&lt;br /&gt;
    int ch;&lt;br /&gt;
&lt;br /&gt;
    /* Loopa igenom infilen tecken för tecken (byte för byte). */&lt;br /&gt;
    while ((ch = fgetc(in)) != EOF) {&lt;br /&gt;
&lt;br /&gt;
        /* Gå igenom varje enskild bit i den inlästa byten, från MSB (bit 7) till LSB (bit 0). */&lt;br /&gt;
        for (int i = 7; i &amp;gt;= 0; i--) {&lt;br /&gt;
&lt;br /&gt;
            /* Isolera biten på position i. */&lt;br /&gt;
            uint8_t bit = (ch &amp;gt;&amp;gt; i) &amp;amp; 1;&lt;br /&gt;
&lt;br /&gt;
            /* Skapa det nuvarande ordet genom att skifta upp det gamla tillståndet till vänster&lt;br /&gt;
               och lägga till den nya inkommande biten som den lägsta biten (LSB). */&lt;br /&gt;
            uint8_t current_word = (encoder_state &amp;lt;&amp;lt; 1) | bit;&lt;br /&gt;
&lt;br /&gt;
            /* Beräkna de två paritetsbitarna (out0 och out1) genom att applicera polynommaskerna&lt;br /&gt;
               och köra XOR (paritet) på resultatet. */&lt;br /&gt;
            uint8_t out0 = parity(current_word &amp;amp; POLY_G0);&lt;br /&gt;
            uint8_t out1 = parity(current_word &amp;amp; POLY_G1);&lt;br /&gt;
&lt;br /&gt;
            /* Knuffa in den första paritetsbiten (out0) i utmatningsbyten. */&lt;br /&gt;
            out_byte = (out_byte &amp;lt;&amp;lt; 1) | out0;&lt;br /&gt;
            bit_count++;&lt;br /&gt;
&lt;br /&gt;
            /* Om vi har fyllt en hel byte (8 bitar), skriv ut den till utmatningsströmmen. */&lt;br /&gt;
            if (bit_count == 8) {&lt;br /&gt;
                fputc(out_byte, out);&lt;br /&gt;
                out_byte = 0;&lt;br /&gt;
                bit_count = 0;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            /* Knuffa in den andra paritetsbiten (out1) i utmatningsbyten. */&lt;br /&gt;
            out_byte = (out_byte &amp;lt;&amp;lt; 1) | out1;&lt;br /&gt;
            bit_count++;&lt;br /&gt;
&lt;br /&gt;
            /* Kontrollera återigen om utmatningsbyten blev full efter den andra biten. */&lt;br /&gt;
            if (bit_count == 8) {&lt;br /&gt;
                fputc(out_byte, out);&lt;br /&gt;
                out_byte = 0;&lt;br /&gt;
                bit_count = 0;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            /* Uppdatera kodarens interna tillstånd inför nästa bit.&lt;br /&gt;
               Vi sparar endast de lägsta K-1 bitarna med hjälp av en bitmask (63 = 0x3F). */&lt;br /&gt;
            encoder_state = current_word &amp;amp; (NUM_STATES - 1);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    /* Om det finns kvarvarande bitar i bufferten när filen slutar,&lt;br /&gt;
       skiftar vi dem till vänster så att de ligger rätt, och skriver ut den sista ofullständiga byten. */&lt;br /&gt;
    if (bit_count &amp;gt; 0) {&lt;br /&gt;
        out_byte &amp;lt;&amp;lt;= (8 - bit_count);&lt;br /&gt;
        fputc(out_byte, out);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// ============================================================================&lt;br /&gt;
// AVKODARE (-d)&lt;br /&gt;
// ============================================================================&lt;br /&gt;
void decode(FILE *in, FILE *out) {&lt;br /&gt;
    /* Startkapacitet för historikmatrisen (antalet bit-steg). Den växer linjärt vid behov. */&lt;br /&gt;
    size_t history_capacity = 1024;&lt;br /&gt;
    size_t step = 0;&lt;br /&gt;
&lt;br /&gt;
    /* Allokera historikmatrisen dynamiskt. Det är en 2D-array av storleken [kapacitet][64].&lt;br /&gt;
       Den sparar överlevnadsbesluten (0 eller 1) för varje tillstånd vid varje givet tidssteg. */&lt;br /&gt;
    uint8_t (*history)[NUM_STATES] = malloc(history_capacity * sizeof(*history));&lt;br /&gt;
    if (!history) {&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    /* path_metrics lagrar den ackumulerade felkostnaden (Hammingavståndet) för de 64 nuvarande tillstånden. */&lt;br /&gt;
    uint32_t path_metrics[NUM_STATES];&lt;br /&gt;
&lt;br /&gt;
    /* old_metrics lagrar en oförändrad kopia av kostnaderna från föregående tidssteg. */&lt;br /&gt;
    uint32_t old_metrics[NUM_STATES];&lt;br /&gt;
&lt;br /&gt;
    /* Initiera alla tillstånd till en mycket hög felkostnad (&amp;quot;oändlighet&amp;quot;).&lt;br /&gt;
       Undantaget är tillstånd 0, vilket är det kända och garanterade starttillståndet (kostnad 0). */&lt;br /&gt;
    for (int i = 1; i &amp;lt; NUM_STATES; i++) {&lt;br /&gt;
        path_metrics[i] = 1e6;&lt;br /&gt;
    }&lt;br /&gt;
    path_metrics[0] = 0;&lt;br /&gt;
&lt;br /&gt;
    int ch;&lt;br /&gt;
&lt;br /&gt;
    // ------------------------------------------------------------------------&lt;br /&gt;
    // STEG 1: Framåtpass (Forward Pass / Add-Compare-Select)&lt;br /&gt;
    // ------------------------------------------------------------------------&lt;br /&gt;
    /* Läs den kodade strömmen byte för byte. */&lt;br /&gt;
    while ((ch = fgetc(in)) != EOF) {&lt;br /&gt;
&lt;br /&gt;
        /* Varje inläst byte innehåller 4 bitpar (totalt 8 kodade bitar), vilket motsvarar 4 tidssteg. */&lt;br /&gt;
        for (int bit_pair = 3; bit_pair &amp;gt;= 0; bit_pair--) {&lt;br /&gt;
&lt;br /&gt;
            /* Extrahera de två bitarna (b0 och b1) som hör till det aktuella steget. */&lt;br /&gt;
            uint8_t b0 = (ch &amp;gt;&amp;gt; (bit_pair * 2 + 1)) &amp;amp; 1;&lt;br /&gt;
            uint8_t b1 = (ch &amp;gt;&amp;gt; (bit_pair * 2)) &amp;amp; 1;&lt;br /&gt;
&lt;br /&gt;
            /* Om vår historikmatris är full, fördubblar vi dess storlek dynamiskt med realloc.&lt;br /&gt;
               Detta gör att programmet kan hantera obegränsat stora filer och pipes. */&lt;br /&gt;
            if (step &amp;gt;= history_capacity) {&lt;br /&gt;
                history_capacity *= 2;&lt;br /&gt;
                uint8_t (*new_history)[NUM_STATES] = realloc(history, history_capacity * sizeof(*history));&lt;br /&gt;
                if (!new_history) {&lt;br /&gt;
                    free(history);&lt;br /&gt;
                    return;&lt;br /&gt;
                }&lt;br /&gt;
                history = new_history;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            /* Kopiera över nuvarande path_metrics till old_metrics inför beräkningen av nästa steg. */&lt;br /&gt;
            memcpy(old_metrics, path_metrics, sizeof(path_metrics));&lt;br /&gt;
&lt;br /&gt;
            /* Loopa igenom alla 64 möjliga måltillstånd (nästa tillstånd) i trellis-diagrammet. */&lt;br /&gt;
            for (int state = 0; state &amp;lt; NUM_STATES; state++) {&lt;br /&gt;
&lt;br /&gt;
                /* Eftersom vi skiftar till vänster, kan vi räkna ut vilka två föregående tillstånd&lt;br /&gt;
                   (prev0 och prev1) som kan ha skiftat in i det nuvarande tillståndet. */&lt;br /&gt;
                int prev0 = state &amp;gt;&amp;gt; 1;&lt;br /&gt;
                int prev1 = prev0 | (NUM_STATES &amp;gt;&amp;gt; 1);&lt;br /&gt;
&lt;br /&gt;
                /* Den inbit som krävdes för att nå &#039;state&#039; är identisk med nuvarande tillstånds LSB. */&lt;br /&gt;
                uint8_t input_bit = state &amp;amp; 1;&lt;br /&gt;
&lt;br /&gt;
                /* --- Beräkna förväntade bitar och Hammingavstånd för VÄG 0 (från prev0) --- */&lt;br /&gt;
                uint8_t word0 = (prev0 &amp;lt;&amp;lt; 1) | input_bit;&lt;br /&gt;
                uint8_t exp0_0 = parity(word0 &amp;amp; POLY_G0);&lt;br /&gt;
                uint8_t exp0_1 = parity(word0 &amp;amp; POLY_G1);&lt;br /&gt;
                /* Kostnaden ökar med 1 för varje bit som inte matchar de faktiskt mottagna bitarna. */&lt;br /&gt;
                uint32_t cost0 = (exp0_0 != b0) + (exp0_1 != b1);&lt;br /&gt;
&lt;br /&gt;
                /* --- Beräkna förväntade bitar och Hammingavstånd för VÄG 1 (från prev1) --- */&lt;br /&gt;
                uint8_t word1 = (prev1 &amp;lt;&amp;lt; 1) | input_bit;&lt;br /&gt;
                uint8_t exp1_0 = parity(word1 &amp;amp; POLY_G0);&lt;br /&gt;
                uint8_t exp1_1 = parity(word1 &amp;amp; POLY_G1);&lt;br /&gt;
                uint32_t cost1 = (exp1_0 != b0) + (exp1_1 != b1);&lt;br /&gt;
&lt;br /&gt;
                /* Addera det gamla ackumulerade felet med det nya övergångsfelet för båda vägarna. */&lt;br /&gt;
                uint32_t m0 = old_metrics[prev0] + cost0;&lt;br /&gt;
                uint32_t m1 = old_metrics[prev1] + cost1;&lt;br /&gt;
&lt;br /&gt;
                /* (Compare &amp;amp; Select): Välj den väg som har lägst totalt fel.&lt;br /&gt;
                   Spara det nya lägsta felet i path_metrics, och dokumentera valet (0 eller 1)&lt;br /&gt;
                   i historikmatrisen för att kunna återskapa vägen baklänges senare. */&lt;br /&gt;
                if (m0 &amp;lt;= m1) {&lt;br /&gt;
                    path_metrics[state] = m0;&lt;br /&gt;
                    history[step][state] = 0;&lt;br /&gt;
                } else {&lt;br /&gt;
                    path_metrics[state] = m1;&lt;br /&gt;
                    history[step][state] = 1;&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
            /* Öka räknaren för antal avklarade bit-steg. */&lt;br /&gt;
            step++;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    /* Om vi inte lyckades läsa några bitar alls, städa upp och avsluta. */&lt;br /&gt;
    if (step == 0) {&lt;br /&gt;
        free(history);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // ------------------------------------------------------------------------&lt;br /&gt;
    // STEG 2: Hitta bästa sluttillstånd&lt;br /&gt;
    // ------------------------------------------------------------------------&lt;br /&gt;
    /* Sök igenom alla 64 tillstånd vid slutet av strömmen för att hitta det tillstånd&lt;br /&gt;
       som har samlat på sig minst antal fel (lägst metric). */&lt;br /&gt;
    int curr_state = 0;&lt;br /&gt;
    uint32_t min_m = path_metrics[0];&lt;br /&gt;
    for (int i = 1; i &amp;lt; NUM_STATES; i++) {&lt;br /&gt;
        if (path_metrics[i] &amp;lt; min_m) {&lt;br /&gt;
            min_m = path_metrics[i];&lt;br /&gt;
            curr_state = i;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // ------------------------------------------------------------------------&lt;br /&gt;
    // STEG 3: Bakåtspårning (Traceback)&lt;br /&gt;
    // ------------------------------------------------------------------------&lt;br /&gt;
    /* Allokera en temporär array för att spara de avkodade bitarna.&lt;br /&gt;
       Eftersom vi vandrar baklänges kommer vi att fylla denna array bakifrån. */&lt;br /&gt;
    uint8_t *decoded_bits = malloc(step);&lt;br /&gt;
    if (!decoded_bits) {&lt;br /&gt;
        free(history);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    /* Vandra baklänges genom historiken från det sista tidssteget ner till noll. */&lt;br /&gt;
    for (int s = (int)step - 1; s &amp;gt;= 0; s--) {&lt;br /&gt;
&lt;br /&gt;
        /* Den ursprungliga inbiten är alltid LSB (bit 0) i det tillstånd vi står i. */&lt;br /&gt;
        decoded_bits[s] = curr_state &amp;amp; 1;&lt;br /&gt;
&lt;br /&gt;
        /* Hämta beslutet (0 eller 1) som fattades för detta tillstånd i tidssteg s. */&lt;br /&gt;
        int decision = history[s][curr_state];&lt;br /&gt;
        int prev0 = curr_state &amp;gt;&amp;gt; 1;&lt;br /&gt;
&lt;br /&gt;
        /* Rekonstruera vilket tillstånd vi kom ifrån baserat på det sparade beslutet. */&lt;br /&gt;
        if (decision == 0) {&lt;br /&gt;
            curr_state = prev0;&lt;br /&gt;
        } else {&lt;br /&gt;
            curr_state = prev0 | (NUM_STATES &amp;gt;&amp;gt; 1);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // ------------------------------------------------------------------------&lt;br /&gt;
    // STEG 4: Återpacka till bytes och skriv ut&lt;br /&gt;
    // ------------------------------------------------------------------------&lt;br /&gt;
    /* Bitarna ligger nu i korrekt kronologisk ordning i decoded_bits-arrayen.&lt;br /&gt;
       Vi loopar igenom dem och packar ihop dem 8 och 8 till vanliga bytes igen. */&lt;br /&gt;
    uint8_t current_byte = 0;&lt;br /&gt;
    for (size_t i = 0; i &amp;lt; step; i++) {&lt;br /&gt;
        current_byte = (current_byte &amp;lt;&amp;lt; 1) | decoded_bits[i];&lt;br /&gt;
&lt;br /&gt;
        /* Varje gång vi har samlat ihop 8 bitar skriver vi ut byten till utfilen/stdout. */&lt;br /&gt;
        if ((i + 1) % 8 == 0) {&lt;br /&gt;
            fputc(current_byte, out);&lt;br /&gt;
            current_byte = 0;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    /* Frigör det dynamiskt allokerade minnet. */&lt;br /&gt;
    free(decoded_bits);&lt;br /&gt;
    free(history);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// ============================================================================&lt;br /&gt;
// INTERNT TEST (-t OCH --error)&lt;br /&gt;
// ============================================================================&lt;br /&gt;
void run_test(bool inject_errors) {&lt;br /&gt;
    if (inject_errors) {&lt;br /&gt;
        printf(&amp;quot;[*] Startar internt test med FELKORRIGERING (64 bytes slumpdata + 3 bitpar flippade)...\n&amp;quot;);&lt;br /&gt;
    } else {&lt;br /&gt;
        printf(&amp;quot;[*] Startar internt test (64 bytes randomiserat data)...\n&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    /* Skapa en array med 64 bytes slumpmässigt data. */&lt;br /&gt;
    uint8_t original_data[64];&lt;br /&gt;
    srand((unsigned int)time(NULL));&lt;br /&gt;
    for (int i = 0; i &amp;lt; 64; i++) {&lt;br /&gt;
        original_data[i] = rand() % 256;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    /* tmpfile() skapar temporära filer som körs i RAM/hårddisk och raderas automatiskt vid stängning. */&lt;br /&gt;
    FILE *orig_stream = tmpfile();&lt;br /&gt;
    FILE *encoded_stream = tmpfile();&lt;br /&gt;
    FILE *corrupted_stream = tmpfile();&lt;br /&gt;
    FILE *decoded_stream = tmpfile();&lt;br /&gt;
&lt;br /&gt;
    if (!orig_stream || !encoded_stream || !corrupted_stream || !decoded_stream) {&lt;br /&gt;
        fprintf(stderr, &amp;quot;Kunde inte skapa temporära filer.\n&amp;quot;);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    /* Skriv originaldata till startströmmen och spola tillbaka pekaren till början. */&lt;br /&gt;
    fwrite(original_data, 1, 64, orig_stream);&lt;br /&gt;
    rewind(orig_stream);&lt;br /&gt;
&lt;br /&gt;
    /* 1. Kör kodningen (64 bytes rådata blir exakt 128 bytes packad bitström). */&lt;br /&gt;
    encode(orig_stream, encoded_stream);&lt;br /&gt;
    rewind(encoded_stream);&lt;br /&gt;
&lt;br /&gt;
    /* 2. Hantering av felinjicering (--error). */&lt;br /&gt;
    if (inject_errors) {&lt;br /&gt;
        uint8_t encoded_data[128];&lt;br /&gt;
&lt;br /&gt;
        /* Läs in hela den kodade strömmen till en lokal array. */&lt;br /&gt;
        if (fread(encoded_data, 1, 128, encoded_stream) == 128) {&lt;br /&gt;
&lt;br /&gt;
            /* Välj ut 3 slumpmässiga bytes och flippa en slumpmässig bit i var och en av dem. */&lt;br /&gt;
            for (int i = 0; i &amp;lt; 3; i++) {&lt;br /&gt;
                int byte_index = rand() % 128;&lt;br /&gt;
                int bit_index = rand() % 8;&lt;br /&gt;
&lt;br /&gt;
                /* XOR-operatör (^) flippar den valda biten (0 blir 1, 1 blir 0). */&lt;br /&gt;
                encoded_data[byte_index] ^= (1 &amp;lt;&amp;lt; bit_index);&lt;br /&gt;
                printf(&amp;quot;[i] Introducerade bitfel i kodad byte %d, bit %d\n&amp;quot;, byte_index, bit_index);&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        /* Skriv ut det saboterade datat till den korrupta strömmen. */&lt;br /&gt;
        fwrite(encoded_data, 1, 128, corrupted_stream);&lt;br /&gt;
        rewind(corrupted_stream);&lt;br /&gt;
    } else {&lt;br /&gt;
        /* Om inga fel ska testas, pekar vi bara vidare till den felfria strömmen direkt. */&lt;br /&gt;
        corrupted_stream = encoded_stream;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    /* 3. Kör avkodaren på dataströmmen. */&lt;br /&gt;
    decode(corrupted_stream, decoded_stream);&lt;br /&gt;
    rewind(decoded_stream);&lt;br /&gt;
&lt;br /&gt;
    /* 4. Läs tillbaka det färdigavkodade datat och verifiera resultatet. */&lt;br /&gt;
    uint8_t final_data[64];&lt;br /&gt;
    size_t read_bytes = fread(final_data, 1, 64, decoded_stream);&lt;br /&gt;
&lt;br /&gt;
    bool success = true;&lt;br /&gt;
    if (read_bytes != 64) {&lt;br /&gt;
        printf(&amp;quot;[FAIL] Avkodade fel antal bytes: %zu (förväntade 64)\n&amp;quot;, read_bytes);&lt;br /&gt;
        success = false;&lt;br /&gt;
    } else {&lt;br /&gt;
        /* Jämför ursprunglig array med den avkodade arrayen byte för byte. */&lt;br /&gt;
        for (int i = 0; i &amp;lt; 64; i++) {&lt;br /&gt;
            if (original_data[i] != final_data[i]) {&lt;br /&gt;
                printf(&amp;quot;[FAIL] Diff vid byte %d: Org=0x%02X, Avkodad=0x%02X\n&amp;quot;, i, original_data[i], final_data[i]);&lt;br /&gt;
                success = false;&lt;br /&gt;
                break;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    /* Stäng alla strömmar ordentligt. */&lt;br /&gt;
    fclose(orig_stream);&lt;br /&gt;
    if (inject_errors) {&lt;br /&gt;
        fclose(encoded_stream);&lt;br /&gt;
        fclose(corrupted_stream);&lt;br /&gt;
    } else {&lt;br /&gt;
        fclose(encoded_stream);&lt;br /&gt;
    }&lt;br /&gt;
    fclose(decoded_stream);&lt;br /&gt;
&lt;br /&gt;
    /* Skriv ut slutrapport för testet. */&lt;br /&gt;
    if (success) {&lt;br /&gt;
        if (inject_errors) {&lt;br /&gt;
            printf(&amp;quot;[SUCCESS] Viterbi-algoritmens felkorrigering lyckades! Alla bitfel lagades och datat matchar perfekt.\n&amp;quot;);&lt;br /&gt;
        } else {&lt;br /&gt;
            printf(&amp;quot;[SUCCESS] Testet lyckades! Allt data matchar perfekt.\n&amp;quot;);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// ============================================================================&lt;br /&gt;
// HJÄLPTEXT OCH MAIN&lt;br /&gt;
// ============================================================================&lt;br /&gt;
void print_help(const char *prog_name) {&lt;br /&gt;
    printf(&amp;quot;Användning: %s [option]\n&amp;quot;, prog_name);&lt;br /&gt;
    printf(&amp;quot;Optioner:\n&amp;quot;);&lt;br /&gt;
    printf(&amp;quot;  -e &amp;lt;infil &amp;gt;utfil   Kodar infil till utfil (Rate 1/2, K=7)\n&amp;quot;);&lt;br /&gt;
    printf(&amp;quot;  -d &amp;lt;infil &amp;gt;utfil   Avkodar infil till utfil med Viterbi\n&amp;quot;);&lt;br /&gt;
    printf(&amp;quot;  -h                 Visar denna hjälptext\n&amp;quot;);&lt;br /&gt;
    printf(&amp;quot;  -t                 Kör internt test med 64 bytes slumpdata\n&amp;quot;);&lt;br /&gt;
    printf(&amp;quot;  --error            Kör internt test men injicerar bitfel för att testa felkorrigeringen\n&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
int main(int argc, char *argv[]) {&lt;br /&gt;
    /* Säkerställ att användaren har skickat med exakt ett kommandoradsargument. */&lt;br /&gt;
    if (argc != 2) {&lt;br /&gt;
        print_help(argv[0]);&lt;br /&gt;
        return EXIT_FAILURE;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    /* Kontrollera vilket argument användaren skickade och anropa rätt funktion. */&lt;br /&gt;
    if (strcmp(argv[1], &amp;quot;-e&amp;quot;) == 0) {&lt;br /&gt;
        encode(stdin, stdout);&lt;br /&gt;
    } else if (strcmp(argv[1], &amp;quot;-d&amp;quot;) == 0) {&lt;br /&gt;
        decode(stdin, stdout);&lt;br /&gt;
    } else if (strcmp(argv[1], &amp;quot;-h&amp;quot;) == 0) {&lt;br /&gt;
        print_help(argv[0]);&lt;br /&gt;
    } else if (strcmp(argv[1], &amp;quot;-t&amp;quot;) == 0) {&lt;br /&gt;
        run_test(false);&lt;br /&gt;
    } else if (strcmp(argv[1], &amp;quot;--error&amp;quot;) == 0) {&lt;br /&gt;
        run_test(true);&lt;br /&gt;
    } else {&lt;br /&gt;
        fprintf(stderr, &amp;quot;Fel: Okänd parameter &#039;%s&#039;\n&amp;quot;, argv[1]);&lt;br /&gt;
        print_help(argv[0]);&lt;br /&gt;
        return EXIT_FAILURE;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return EXIT_SUCCESS;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>Anders</name></author>
	</entry>
	<entry>
		<id>http://wiki.sikvall.se/index.php?title=Viterbi&amp;diff=1912</id>
		<title>Viterbi</title>
		<link rel="alternate" type="text/html" href="http://wiki.sikvall.se/index.php?title=Viterbi&amp;diff=1912"/>
		<updated>2026-06-23T18:17:35Z</updated>

		<summary type="html">&lt;p&gt;Anders: /* Bakgrund */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[category:algoritmer]]&lt;br /&gt;
[[category:felkorrigering]]&lt;br /&gt;
[[category:telekom]]&lt;br /&gt;
&lt;br /&gt;
= Bakgrund = &lt;br /&gt;
&lt;br /&gt;
== Viterbis algoritm – Hur vi hittar rätt signal i bruset ==&lt;br /&gt;
&lt;br /&gt;
Inom amatörradion och digital signalbehandling stöter vi ofta på problemet med brus och fading. När vi skickar digital data över etern, till exempel med modernare digitala trafiksätt eller vid satellitkommunikation, använder vi ofta något som kallas för faltningskodning (convolutional coding). Det är en metod där varje sänd bit beror på både den nuvarande biten och ett antal tidigare bitar. Detta skapar ett mönster, ett beroende, som gör signalen robust.&lt;br /&gt;
&lt;br /&gt;
Men hur avkodar vi detta på mottagarsidan när atmosfären har ställt till det och lagt till en massa brus? Det är här Viterbis algoritm kommer in i bilden.&lt;br /&gt;
&lt;br /&gt;
Kort sagt är Viterbialgoritmen en metod för att hitta den mest troliga sekvensen av dolda tillstånd (det vi faktiskt sände) baserat på en serie observerade händelser (den brusiga signalen vi tog emot). Istället för att gissa bit för bit, tittar algoritmen på hela sammanhanget.&lt;br /&gt;
&lt;br /&gt;
== Trellis-diagrammet: Vägarna genom historien ==&lt;br /&gt;
&lt;br /&gt;
För att förstå hur algoritmen jobbar kan vi tänka oss ett nätverk av vägar, ett så kallat trellis-diagram.&lt;br /&gt;
&lt;br /&gt;
* Tillstånd (States): Radiosändarens &amp;quot;minne&amp;quot; kan vid varje given tidpunkt befinna sig i ett visst antal tillstånd (beroende på de senaste sända bitarna).&lt;br /&gt;
&lt;br /&gt;
* Övergångar: När en ny bit ska sändas hoppar sändaren till ett nytt tillstånd och skickar ut en specifik kombination av bitar i luften.&lt;br /&gt;
&lt;br /&gt;
== Hur funkar det? ==&lt;br /&gt;
&lt;br /&gt;
När mottagaren lyssnar får den in en sekvens som kanske är halvt dränkt i brus. En nolla kanske ser ut som en svag etta, och så vidare. Viterbialgoritmen börjar nu räkna på alla möjliga vägar genom detta nätverk av tillstånd över tid.&lt;br /&gt;
Så här jobbar algoritmen steg för steg:&lt;br /&gt;
&lt;br /&gt;
# Beräkna avstånd (Metric): För varje steg i tiden tittar algoritmen på de bitar som faktiskt togs emot och jämför dem med vad som borde ha sänts för varje tänkbar väg i diagrammet. Man mäter &amp;quot;avståndet&amp;quot; (ofta Hamming-avstånd för ettor och nollor, eller Euklidiskt avstånd om man kör &amp;quot;soft decision&amp;quot; där man mäter signalstyrkan mer exakt). Ju mindre avstånd, desto mer troligt är det att den vägen är den rätta.&lt;br /&gt;
# Spara den bästa vägen (Add-Compare-Select): Till varje nytt tillstånd i diagrammet leder det oftast två olika vägar från det föregående steget. Algoritmen adderar det nya avståndet till det gamla, jämför de två alternativen, och väljer den väg som har lägst totalt avstånd (fel). Den andra vägen slängs bort för alltid. Det här är algoritmens stora styrka: den rensar hela tiden bort återvändsgränder så att beräkningsbördan inte exploderar.&lt;br /&gt;
# Lås historiken (Traceback): När hela sekvensen (eller ett tillräckligt långt block) har tagits emot, tittar man på vilket slutgiltigt tillstånd som har det absolut lägsta totala felvärdet. Sedan backar man bakåt genom de sparade &amp;quot;bästa vägarna&amp;quot; till början.&lt;br /&gt;
&lt;br /&gt;
Resultatet blir den absolut mest sannolika sekvensen av bitar som sändaren faktiskt skickade ut, trots att det var fullt av bitfel under resans gång.&lt;br /&gt;
&lt;br /&gt;
= Implementation i hyggligt modern C=&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
 * Anders Sikvall 2026 Version 1.0&lt;br /&gt;
 * &amp;lt;anders@sikvall.se&amp;gt;&lt;br /&gt;
 * &lt;br /&gt;
 * Implementation i C av en standard Viterbi-algoritm som används bl.a. av &lt;br /&gt;
 * Qualcomm och NASA och är välpublicerad.&lt;br /&gt;
 *&lt;br /&gt;
 * PUBLIC DOMAIN FOR EDUCATIONAL PURPOSES&lt;br /&gt;
 *&lt;br /&gt;
 * Kompilera med gcc -o viterbi viterbi.c&lt;br /&gt;
 *&lt;br /&gt;
 * ANVÄNDNING&lt;br /&gt;
 *         viterbi -e &amp;lt;indatastream &amp;gt;utdatastream   Kodar &amp;lt;indatastream till &amp;gt;utdatastream&lt;br /&gt;
 *         viterbi -d &amp;lt;indatastream &amp;gt;utdatastream   Avkodar &amp;lt;indatastream till &amp;gt;utdatastream&lt;br /&gt;
 *         viterbi -t                               Utför en intern test på 64 randomiserade oktetter&lt;br /&gt;
 *         viterbi -h                               Visar en kort hjälptext&lt;br /&gt;
 *         viterbi --error                          Samma sak som -t men introducerar 3 flippade bitpar&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
#include &amp;lt;string.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdbool.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdint.h&amp;gt;&lt;br /&gt;
#include &amp;lt;time.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
/* Constraint length (K=7) innebär att skiftregistret minns de senaste 7 bitarna. */&lt;br /&gt;
#define K 7&lt;br /&gt;
&lt;br /&gt;
/* Antalet tillstånd i trellis-diagrammet bestäms av de senaste K-1 bitarna.&lt;br /&gt;
   2^(7-1) = 2^6 = 64 unika tillstånd totalt. */&lt;br /&gt;
#define NUM_STATES (1 &amp;lt;&amp;lt; (K - 1))&lt;br /&gt;
&lt;br /&gt;
/* Standard NASA/Qualcomm-polynom för Rate 1/2 konvolutionskodning.&lt;br /&gt;
   POLY_G0 motsvarar oktalt 151 (1001111 binärt).&lt;br /&gt;
   POLY_G1 motsvarar oktalt 113 (1101101 binärt).&lt;br /&gt;
   Dessa maskar används för att bestämma vilka bitar i tillståndet som XOR-sammanfogas. */&lt;br /&gt;
const uint8_t POLY_G0 = 0x4F;&lt;br /&gt;
const uint8_t POLY_G1 = 0x6D;&lt;br /&gt;
&lt;br /&gt;
/* Hårdvaruoptimerad paritetsberäkning.&lt;br /&gt;
   Räknar antalet satta bitar (1:or) i ett tal och returnerar 1 om antalet är udda,&lt;br /&gt;
   eller 0 om antalet är jämnt (motsvarar en kedja av XOR-grindar). */&lt;br /&gt;
static inline uint8_t parity(uint8_t x) {&lt;br /&gt;
    return __builtin_parity(x) &amp;amp; 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// ============================================================================&lt;br /&gt;
// KODARE (-e)&lt;br /&gt;
// ============================================================================&lt;br /&gt;
void encode(FILE *in, FILE *out) {&lt;br /&gt;
    /* encoder_state lagrar historiken av de senaste K-1 (6) bitarna. */&lt;br /&gt;
    uint8_t encoder_state = 0;&lt;br /&gt;
&lt;br /&gt;
    /* out_byte används som en tillfällig buffer för att samla ihop bitar till en hel byte. */&lt;br /&gt;
    uint8_t out_byte = 0;&lt;br /&gt;
&lt;br /&gt;
    /* bit_count håller koll på hur många bitar som för tillfället ligger i utmatningsbufferten. */&lt;br /&gt;
    int bit_count = 0;&lt;br /&gt;
    int ch;&lt;br /&gt;
&lt;br /&gt;
    /* Loopa igenom infilen tecken för tecken (byte för byte). */&lt;br /&gt;
    while ((ch = fgetc(in)) != EOF) {&lt;br /&gt;
&lt;br /&gt;
        /* Gå igenom varje enskild bit i den inlästa byten, från MSB (bit 7) till LSB (bit 0). */&lt;br /&gt;
        for (int i = 7; i &amp;gt;= 0; i--) {&lt;br /&gt;
&lt;br /&gt;
            /* Isolera biten på position i. */&lt;br /&gt;
            uint8_t bit = (ch &amp;gt;&amp;gt; i) &amp;amp; 1;&lt;br /&gt;
&lt;br /&gt;
            /* Skapa det nuvarande ordet genom att skifta upp det gamla tillståndet till vänster&lt;br /&gt;
               och lägga till den nya inkommande biten som den lägsta biten (LSB). */&lt;br /&gt;
            uint8_t current_word = (encoder_state &amp;lt;&amp;lt; 1) | bit;&lt;br /&gt;
&lt;br /&gt;
            /* Beräkna de två paritetsbitarna (out0 och out1) genom att applicera polynommaskerna&lt;br /&gt;
               och köra XOR (paritet) på resultatet. */&lt;br /&gt;
            uint8_t out0 = parity(current_word &amp;amp; POLY_G0);&lt;br /&gt;
            uint8_t out1 = parity(current_word &amp;amp; POLY_G1);&lt;br /&gt;
&lt;br /&gt;
            /* Knuffa in den första paritetsbiten (out0) i utmatningsbyten. */&lt;br /&gt;
            out_byte = (out_byte &amp;lt;&amp;lt; 1) | out0;&lt;br /&gt;
            bit_count++;&lt;br /&gt;
&lt;br /&gt;
            /* Om vi har fyllt en hel byte (8 bitar), skriv ut den till utmatningsströmmen. */&lt;br /&gt;
            if (bit_count == 8) {&lt;br /&gt;
                fputc(out_byte, out);&lt;br /&gt;
                out_byte = 0;&lt;br /&gt;
                bit_count = 0;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            /* Knuffa in den andra paritetsbiten (out1) i utmatningsbyten. */&lt;br /&gt;
            out_byte = (out_byte &amp;lt;&amp;lt; 1) | out1;&lt;br /&gt;
            bit_count++;&lt;br /&gt;
&lt;br /&gt;
            /* Kontrollera återigen om utmatningsbyten blev full efter den andra biten. */&lt;br /&gt;
            if (bit_count == 8) {&lt;br /&gt;
                fputc(out_byte, out);&lt;br /&gt;
                out_byte = 0;&lt;br /&gt;
                bit_count = 0;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            /* Uppdatera kodarens interna tillstånd inför nästa bit.&lt;br /&gt;
               Vi sparar endast de lägsta K-1 bitarna med hjälp av en bitmask (63 = 0x3F). */&lt;br /&gt;
            encoder_state = current_word &amp;amp; (NUM_STATES - 1);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    /* Om det finns kvarvarande bitar i bufferten när filen slutar,&lt;br /&gt;
       skiftar vi dem till vänster så att de ligger rätt, och skriver ut den sista ofullständiga byten. */&lt;br /&gt;
    if (bit_count &amp;gt; 0) {&lt;br /&gt;
        out_byte &amp;lt;&amp;lt;= (8 - bit_count);&lt;br /&gt;
        fputc(out_byte, out);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// ============================================================================&lt;br /&gt;
// AVKODARE (-d)&lt;br /&gt;
// ============================================================================&lt;br /&gt;
void decode(FILE *in, FILE *out) {&lt;br /&gt;
    /* Startkapacitet för historikmatrisen (antalet bit-steg). Den växer linjärt vid behov. */&lt;br /&gt;
    size_t history_capacity = 1024;&lt;br /&gt;
    size_t step = 0;&lt;br /&gt;
&lt;br /&gt;
    /* Allokera historikmatrisen dynamiskt. Det är en 2D-array av storleken [kapacitet][64].&lt;br /&gt;
       Den sparar överlevnadsbesluten (0 eller 1) för varje tillstånd vid varje givet tidssteg. */&lt;br /&gt;
    uint8_t (*history)[NUM_STATES] = malloc(history_capacity * sizeof(*history));&lt;br /&gt;
    if (!history) {&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    /* path_metrics lagrar den ackumulerade felkostnaden (Hammingavståndet) för de 64 nuvarande tillstånden. */&lt;br /&gt;
    uint32_t path_metrics[NUM_STATES];&lt;br /&gt;
&lt;br /&gt;
    /* old_metrics lagrar en oförändrad kopia av kostnaderna från föregående tidssteg. */&lt;br /&gt;
    uint32_t old_metrics[NUM_STATES];&lt;br /&gt;
&lt;br /&gt;
    /* Initiera alla tillstånd till en mycket hög felkostnad (&amp;quot;oändlighet&amp;quot;).&lt;br /&gt;
       Undantaget är tillstånd 0, vilket är det kända och garanterade starttillståndet (kostnad 0). */&lt;br /&gt;
    for (int i = 1; i &amp;lt; NUM_STATES; i++) {&lt;br /&gt;
        path_metrics[i] = 1e6;&lt;br /&gt;
    }&lt;br /&gt;
    path_metrics[0] = 0;&lt;br /&gt;
&lt;br /&gt;
    int ch;&lt;br /&gt;
&lt;br /&gt;
    // ------------------------------------------------------------------------&lt;br /&gt;
    // STEG 1: Framåtpass (Forward Pass / Add-Compare-Select)&lt;br /&gt;
    // ------------------------------------------------------------------------&lt;br /&gt;
    /* Läs den kodade strömmen byte för byte. */&lt;br /&gt;
    while ((ch = fgetc(in)) != EOF) {&lt;br /&gt;
&lt;br /&gt;
        /* Varje inläst byte innehåller 4 bitpar (totalt 8 kodade bitar), vilket motsvarar 4 tidssteg. */&lt;br /&gt;
        for (int bit_pair = 3; bit_pair &amp;gt;= 0; bit_pair--) {&lt;br /&gt;
&lt;br /&gt;
            /* Extrahera de två bitarna (b0 och b1) som hör till det aktuella steget. */&lt;br /&gt;
            uint8_t b0 = (ch &amp;gt;&amp;gt; (bit_pair * 2 + 1)) &amp;amp; 1;&lt;br /&gt;
            uint8_t b1 = (ch &amp;gt;&amp;gt; (bit_pair * 2)) &amp;amp; 1;&lt;br /&gt;
&lt;br /&gt;
            /* Om vår historikmatris är full, fördubblar vi dess storlek dynamiskt med realloc.&lt;br /&gt;
               Detta gör att programmet kan hantera obegränsat stora filer och pipes. */&lt;br /&gt;
            if (step &amp;gt;= history_capacity) {&lt;br /&gt;
                history_capacity *= 2;&lt;br /&gt;
                uint8_t (*new_history)[NUM_STATES] = realloc(history, history_capacity * sizeof(*history));&lt;br /&gt;
                if (!new_history) {&lt;br /&gt;
                    free(history);&lt;br /&gt;
                    return;&lt;br /&gt;
                }&lt;br /&gt;
                history = new_history;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            /* Kopiera över nuvarande path_metrics till old_metrics inför beräkningen av nästa steg. */&lt;br /&gt;
            memcpy(old_metrics, path_metrics, sizeof(path_metrics));&lt;br /&gt;
&lt;br /&gt;
            /* Loopa igenom alla 64 möjliga måltillstånd (nästa tillstånd) i trellis-diagrammet. */&lt;br /&gt;
            for (int state = 0; state &amp;lt; NUM_STATES; state++) {&lt;br /&gt;
&lt;br /&gt;
                /* Eftersom vi skiftar till vänster, kan vi räkna ut vilka två föregående tillstånd&lt;br /&gt;
                   (prev0 och prev1) som kan ha skiftat in i det nuvarande tillståndet. */&lt;br /&gt;
                int prev0 = state &amp;gt;&amp;gt; 1;&lt;br /&gt;
                int prev1 = prev0 | (NUM_STATES &amp;gt;&amp;gt; 1);&lt;br /&gt;
&lt;br /&gt;
                /* Den inbit som krävdes för att nå &#039;state&#039; är identisk med nuvarande tillstånds LSB. */&lt;br /&gt;
                uint8_t input_bit = state &amp;amp; 1;&lt;br /&gt;
&lt;br /&gt;
                /* --- Beräkna förväntade bitar och Hammingavstånd för VÄG 0 (från prev0) --- */&lt;br /&gt;
                uint8_t word0 = (prev0 &amp;lt;&amp;lt; 1) | input_bit;&lt;br /&gt;
                uint8_t exp0_0 = parity(word0 &amp;amp; POLY_G0);&lt;br /&gt;
                uint8_t exp0_1 = parity(word0 &amp;amp; POLY_G1);&lt;br /&gt;
                /* Kostnaden ökar med 1 för varje bit som inte matchar de faktiskt mottagna bitarna. */&lt;br /&gt;
                uint32_t cost0 = (exp0_0 != b0) + (exp0_1 != b1);&lt;br /&gt;
&lt;br /&gt;
                /* --- Beräkna förväntade bitar och Hammingavstånd för VÄG 1 (från prev1) --- */&lt;br /&gt;
                uint8_t word1 = (prev1 &amp;lt;&amp;lt; 1) | input_bit;&lt;br /&gt;
                uint8_t exp1_0 = parity(word1 &amp;amp; POLY_G0);&lt;br /&gt;
                uint8_t exp1_1 = parity(word1 &amp;amp; POLY_G1);&lt;br /&gt;
                uint32_t cost1 = (exp1_0 != b0) + (exp1_1 != b1);&lt;br /&gt;
&lt;br /&gt;
                /* Addera det gamla ackumulerade felet med det nya övergångsfelet för båda vägarna. */&lt;br /&gt;
                uint32_t m0 = old_metrics[prev0] + cost0;&lt;br /&gt;
                uint32_t m1 = old_metrics[prev1] + cost1;&lt;br /&gt;
&lt;br /&gt;
                /* (Compare &amp;amp; Select): Välj den väg som har lägst totalt fel.&lt;br /&gt;
                   Spara det nya lägsta felet i path_metrics, och dokumentera valet (0 eller 1)&lt;br /&gt;
                   i historikmatrisen för att kunna återskapa vägen baklänges senare. */&lt;br /&gt;
                if (m0 &amp;lt;= m1) {&lt;br /&gt;
                    path_metrics[state] = m0;&lt;br /&gt;
                    history[step][state] = 0;&lt;br /&gt;
                } else {&lt;br /&gt;
                    path_metrics[state] = m1;&lt;br /&gt;
                    history[step][state] = 1;&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
            /* Öka räknaren för antal avklarade bit-steg. */&lt;br /&gt;
            step++;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    /* Om vi inte lyckades läsa några bitar alls, städa upp och avsluta. */&lt;br /&gt;
    if (step == 0) {&lt;br /&gt;
        free(history);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // ------------------------------------------------------------------------&lt;br /&gt;
    // STEG 2: Hitta bästa sluttillstånd&lt;br /&gt;
    // ------------------------------------------------------------------------&lt;br /&gt;
    /* Sök igenom alla 64 tillstånd vid slutet av strömmen för att hitta det tillstånd&lt;br /&gt;
       som har samlat på sig minst antal fel (lägst metric). */&lt;br /&gt;
    int curr_state = 0;&lt;br /&gt;
    uint32_t min_m = path_metrics[0];&lt;br /&gt;
    for (int i = 1; i &amp;lt; NUM_STATES; i++) {&lt;br /&gt;
        if (path_metrics[i] &amp;lt; min_m) {&lt;br /&gt;
            min_m = path_metrics[i];&lt;br /&gt;
            curr_state = i;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // ------------------------------------------------------------------------&lt;br /&gt;
    // STEG 3: Bakåtspårning (Traceback)&lt;br /&gt;
    // ------------------------------------------------------------------------&lt;br /&gt;
    /* Allokera en temporär array för att spara de avkodade bitarna.&lt;br /&gt;
       Eftersom vi vandrar baklänges kommer vi att fylla denna array bakifrån. */&lt;br /&gt;
    uint8_t *decoded_bits = malloc(step);&lt;br /&gt;
    if (!decoded_bits) {&lt;br /&gt;
        free(history);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    /* Vandra baklänges genom historiken från det sista tidssteget ner till noll. */&lt;br /&gt;
    for (int s = (int)step - 1; s &amp;gt;= 0; s--) {&lt;br /&gt;
&lt;br /&gt;
        /* Den ursprungliga inbiten är alltid LSB (bit 0) i det tillstånd vi står i. */&lt;br /&gt;
        decoded_bits[s] = curr_state &amp;amp; 1;&lt;br /&gt;
&lt;br /&gt;
        /* Hämta beslutet (0 eller 1) som fattades för detta tillstånd i tidssteg s. */&lt;br /&gt;
        int decision = history[s][curr_state];&lt;br /&gt;
        int prev0 = curr_state &amp;gt;&amp;gt; 1;&lt;br /&gt;
&lt;br /&gt;
        /* Rekonstruera vilket tillstånd vi kom ifrån baserat på det sparade beslutet. */&lt;br /&gt;
        if (decision == 0) {&lt;br /&gt;
            curr_state = prev0;&lt;br /&gt;
        } else {&lt;br /&gt;
            curr_state = prev0 | (NUM_STATES &amp;gt;&amp;gt; 1);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // ------------------------------------------------------------------------&lt;br /&gt;
    // STEG 4: Återpacka till bytes och skriv ut&lt;br /&gt;
    // ------------------------------------------------------------------------&lt;br /&gt;
    /* Bitarna ligger nu i korrekt kronologisk ordning i decoded_bits-arrayen.&lt;br /&gt;
       Vi loopar igenom dem och packar ihop dem 8 och 8 till vanliga bytes igen. */&lt;br /&gt;
    uint8_t current_byte = 0;&lt;br /&gt;
    for (size_t i = 0; i &amp;lt; step; i++) {&lt;br /&gt;
        current_byte = (current_byte &amp;lt;&amp;lt; 1) | decoded_bits[i];&lt;br /&gt;
&lt;br /&gt;
        /* Varje gång vi har samlat ihop 8 bitar skriver vi ut byten till utfilen/stdout. */&lt;br /&gt;
        if ((i + 1) % 8 == 0) {&lt;br /&gt;
            fputc(current_byte, out);&lt;br /&gt;
            current_byte = 0;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    /* Frigör det dynamiskt allokerade minnet. */&lt;br /&gt;
    free(decoded_bits);&lt;br /&gt;
    free(history);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// ============================================================================&lt;br /&gt;
// INTERNT TEST (-t OCH --error)&lt;br /&gt;
// ============================================================================&lt;br /&gt;
void run_test(bool inject_errors) {&lt;br /&gt;
    if (inject_errors) {&lt;br /&gt;
        printf(&amp;quot;[*] Startar internt test med FELKORRIGERING (64 bytes slumpdata + 3 bitpar flippade)...\n&amp;quot;);&lt;br /&gt;
    } else {&lt;br /&gt;
        printf(&amp;quot;[*] Startar internt test (64 bytes randomiserat data)...\n&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    /* Skapa en array med 64 bytes slumpmässigt data. */&lt;br /&gt;
    uint8_t original_data[64];&lt;br /&gt;
    srand((unsigned int)time(NULL));&lt;br /&gt;
    for (int i = 0; i &amp;lt; 64; i++) {&lt;br /&gt;
        original_data[i] = rand() % 256;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    /* tmpfile() skapar temporära filer som körs i RAM/hårddisk och raderas automatiskt vid stängning. */&lt;br /&gt;
    FILE *orig_stream = tmpfile();&lt;br /&gt;
    FILE *encoded_stream = tmpfile();&lt;br /&gt;
    FILE *corrupted_stream = tmpfile();&lt;br /&gt;
    FILE *decoded_stream = tmpfile();&lt;br /&gt;
&lt;br /&gt;
    if (!orig_stream || !encoded_stream || !corrupted_stream || !decoded_stream) {&lt;br /&gt;
        fprintf(stderr, &amp;quot;Kunde inte skapa temporära filer.\n&amp;quot;);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    /* Skriv originaldata till startströmmen och spola tillbaka pekaren till början. */&lt;br /&gt;
    fwrite(original_data, 1, 64, orig_stream);&lt;br /&gt;
    rewind(orig_stream);&lt;br /&gt;
&lt;br /&gt;
    /* 1. Kör kodningen (64 bytes rådata blir exakt 128 bytes packad bitström). */&lt;br /&gt;
    encode(orig_stream, encoded_stream);&lt;br /&gt;
    rewind(encoded_stream);&lt;br /&gt;
&lt;br /&gt;
    /* 2. Hantering av felinjicering (--error). */&lt;br /&gt;
    if (inject_errors) {&lt;br /&gt;
        uint8_t encoded_data[128];&lt;br /&gt;
&lt;br /&gt;
        /* Läs in hela den kodade strömmen till en lokal array. */&lt;br /&gt;
        if (fread(encoded_data, 1, 128, encoded_stream) == 128) {&lt;br /&gt;
&lt;br /&gt;
            /* Välj ut 3 slumpmässiga bytes och flippa en slumpmässig bit i var och en av dem. */&lt;br /&gt;
            for (int i = 0; i &amp;lt; 3; i++) {&lt;br /&gt;
                int byte_index = rand() % 128;&lt;br /&gt;
                int bit_index = rand() % 8;&lt;br /&gt;
&lt;br /&gt;
                /* XOR-operatör (^) flippar den valda biten (0 blir 1, 1 blir 0). */&lt;br /&gt;
                encoded_data[byte_index] ^= (1 &amp;lt;&amp;lt; bit_index);&lt;br /&gt;
                printf(&amp;quot;[i] Introducerade bitfel i kodad byte %d, bit %d\n&amp;quot;, byte_index, bit_index);&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        /* Skriv ut det saboterade datat till den korrupta strömmen. */&lt;br /&gt;
        fwrite(encoded_data, 1, 128, corrupted_stream);&lt;br /&gt;
        rewind(corrupted_stream);&lt;br /&gt;
    } else {&lt;br /&gt;
        /* Om inga fel ska testas, pekar vi bara vidare till den felfria strömmen direkt. */&lt;br /&gt;
        corrupted_stream = encoded_stream;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    /* 3. Kör avkodaren på dataströmmen. */&lt;br /&gt;
    decode(corrupted_stream, decoded_stream);&lt;br /&gt;
    rewind(decoded_stream);&lt;br /&gt;
&lt;br /&gt;
    /* 4. Läs tillbaka det färdigavkodade datat och verifiera resultatet. */&lt;br /&gt;
    uint8_t final_data[64];&lt;br /&gt;
    size_t read_bytes = fread(final_data, 1, 64, decoded_stream);&lt;br /&gt;
&lt;br /&gt;
    bool success = true;&lt;br /&gt;
    if (read_bytes != 64) {&lt;br /&gt;
        printf(&amp;quot;[FAIL] Avkodade fel antal bytes: %zu (förväntade 64)\n&amp;quot;, read_bytes);&lt;br /&gt;
        success = false;&lt;br /&gt;
    } else {&lt;br /&gt;
        /* Jämför ursprunglig array med den avkodade arrayen byte för byte. */&lt;br /&gt;
        for (int i = 0; i &amp;lt; 64; i++) {&lt;br /&gt;
            if (original_data[i] != final_data[i]) {&lt;br /&gt;
                printf(&amp;quot;[FAIL] Diff vid byte %d: Org=0x%02X, Avkodad=0x%02X\n&amp;quot;, i, original_data[i], final_data[i]);&lt;br /&gt;
                success = false;&lt;br /&gt;
                break;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    /* Stäng alla strömmar ordentligt. */&lt;br /&gt;
    fclose(orig_stream);&lt;br /&gt;
    if (inject_errors) {&lt;br /&gt;
        fclose(encoded_stream);&lt;br /&gt;
        fclose(corrupted_stream);&lt;br /&gt;
    } else {&lt;br /&gt;
        fclose(encoded_stream);&lt;br /&gt;
    }&lt;br /&gt;
    fclose(decoded_stream);&lt;br /&gt;
&lt;br /&gt;
    /* Skriv ut slutrapport för testet. */&lt;br /&gt;
    if (success) {&lt;br /&gt;
        if (inject_errors) {&lt;br /&gt;
            printf(&amp;quot;[SUCCESS] Viterbi-algoritmens felkorrigering lyckades! Alla bitfel lagades och datat matchar perfekt.\n&amp;quot;);&lt;br /&gt;
        } else {&lt;br /&gt;
            printf(&amp;quot;[SUCCESS] Testet lyckades! Allt data matchar perfekt.\n&amp;quot;);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// ============================================================================&lt;br /&gt;
// HJÄLPTEXT OCH MAIN&lt;br /&gt;
// ============================================================================&lt;br /&gt;
void print_help(const char *prog_name) {&lt;br /&gt;
    printf(&amp;quot;Användning: %s [option]\n&amp;quot;, prog_name);&lt;br /&gt;
    printf(&amp;quot;Optioner:\n&amp;quot;);&lt;br /&gt;
    printf(&amp;quot;  -e &amp;lt;infil &amp;gt;utfil   Kodar infil till utfil (Rate 1/2, K=7)\n&amp;quot;);&lt;br /&gt;
    printf(&amp;quot;  -d &amp;lt;infil &amp;gt;utfil   Avkodar infil till utfil med Viterbi\n&amp;quot;);&lt;br /&gt;
    printf(&amp;quot;  -h                 Visar denna hjälptext\n&amp;quot;);&lt;br /&gt;
    printf(&amp;quot;  -t                 Kör internt test med 64 bytes slumpdata\n&amp;quot;);&lt;br /&gt;
    printf(&amp;quot;  --error            Kör internt test men injicerar bitfel för att testa felkorrigeringen\n&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
int main(int argc, char *argv[]) {&lt;br /&gt;
    /* Säkerställ att användaren har skickat med exakt ett kommandoradsargument. */&lt;br /&gt;
    if (argc != 2) {&lt;br /&gt;
        print_help(argv[0]);&lt;br /&gt;
        return EXIT_FAILURE;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    /* Kontrollera vilket argument användaren skickade och anropa rätt funktion. */&lt;br /&gt;
    if (strcmp(argv[1], &amp;quot;-e&amp;quot;) == 0) {&lt;br /&gt;
        encode(stdin, stdout);&lt;br /&gt;
    } else if (strcmp(argv[1], &amp;quot;-d&amp;quot;) == 0) {&lt;br /&gt;
        decode(stdin, stdout);&lt;br /&gt;
    } else if (strcmp(argv[1], &amp;quot;-h&amp;quot;) == 0) {&lt;br /&gt;
        print_help(argv[0]);&lt;br /&gt;
    } else if (strcmp(argv[1], &amp;quot;-t&amp;quot;) == 0) {&lt;br /&gt;
        run_test(false);&lt;br /&gt;
    } else if (strcmp(argv[1], &amp;quot;--error&amp;quot;) == 0) {&lt;br /&gt;
        run_test(true);&lt;br /&gt;
    } else {&lt;br /&gt;
        fprintf(stderr, &amp;quot;Fel: Okänd parameter &#039;%s&#039;\n&amp;quot;, argv[1]);&lt;br /&gt;
        print_help(argv[0]);&lt;br /&gt;
        return EXIT_FAILURE;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return EXIT_SUCCESS;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>Anders</name></author>
	</entry>
	<entry>
		<id>http://wiki.sikvall.se/index.php?title=Viterbi&amp;diff=1911</id>
		<title>Viterbi</title>
		<link rel="alternate" type="text/html" href="http://wiki.sikvall.se/index.php?title=Viterbi&amp;diff=1911"/>
		<updated>2026-06-23T17:58:49Z</updated>

		<summary type="html">&lt;p&gt;Anders: /* Implementation */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Bakgrund = &lt;br /&gt;
&lt;br /&gt;
== Viterbis algoritm – Hur vi hittar rätt signal i bruset ==&lt;br /&gt;
&lt;br /&gt;
Inom amatörradion och digital signalbehandling stöter vi ofta på problemet med brus och fading. När vi skickar digital data över etern, till exempel med modernare digitala trafiksätt eller vid satellitkommunikation, använder vi ofta något som kallas för faltningskodning (convolutional coding). Det är en metod där varje sänd bit beror på både den nuvarande biten och ett antal tidigare bitar. Detta skapar ett mönster, ett beroende, som gör signalen robust.&lt;br /&gt;
&lt;br /&gt;
Men hur avkodar vi detta på mottagarsidan när atmosfären har ställt till det och lagt till en massa brus? Det är här Viterbis algoritm kommer in i bilden.&lt;br /&gt;
&lt;br /&gt;
Kort sagt är Viterbialgoritmen en metod för att hitta den mest troliga sekvensen av dolda tillstånd (det vi faktiskt sände) baserat på en serie observerade händelser (den brusiga signalen vi tog emot). Istället för att gissa bit för bit, tittar algoritmen på hela sammanhanget.&lt;br /&gt;
&lt;br /&gt;
== Trellis-diagrammet: Vägarna genom historien ==&lt;br /&gt;
&lt;br /&gt;
För att förstå hur algoritmen jobbar kan vi tänka oss ett nätverk av vägar, ett så kallat trellis-diagram.&lt;br /&gt;
&lt;br /&gt;
* Tillstånd (States): Radiosändarens &amp;quot;minne&amp;quot; kan vid varje given tidpunkt befinna sig i ett visst antal tillstånd (beroende på de senaste sända bitarna).&lt;br /&gt;
&lt;br /&gt;
* Övergångar: När en ny bit ska sändas hoppar sändaren till ett nytt tillstånd och skickar ut en specifik kombination av bitar i luften.&lt;br /&gt;
&lt;br /&gt;
== Hur funkar det? ==&lt;br /&gt;
&lt;br /&gt;
När mottagaren lyssnar får den in en sekvens som kanske är halvt dränkt i brus. En nolla kanske ser ut som en svag etta, och så vidare. Viterbialgoritmen börjar nu räkna på alla möjliga vägar genom detta nätverk av tillstånd över tid.&lt;br /&gt;
Så här jobbar algoritmen steg för steg:&lt;br /&gt;
&lt;br /&gt;
# Beräkna avstånd (Metric): För varje steg i tiden tittar algoritmen på de bitar som faktiskt togs emot och jämför dem med vad som borde ha sänts för varje tänkbar väg i diagrammet. Man mäter &amp;quot;avståndet&amp;quot; (ofta Hamming-avstånd för ettor och nollor, eller Euklidiskt avstånd om man kör &amp;quot;soft decision&amp;quot; där man mäter signalstyrkan mer exakt). Ju mindre avstånd, desto mer troligt är det att den vägen är den rätta.&lt;br /&gt;
# Spara den bästa vägen (Add-Compare-Select): Till varje nytt tillstånd i diagrammet leder det oftast två olika vägar från det föregående steget. Algoritmen adderar det nya avståndet till det gamla, jämför de två alternativen, och väljer den väg som har lägst totalt avstånd (fel). Den andra vägen slängs bort för alltid. Det här är algoritmens stora styrka: den rensar hela tiden bort återvändsgränder så att beräkningsbördan inte exploderar.&lt;br /&gt;
# Lås historiken (Traceback): När hela sekvensen (eller ett tillräckligt långt block) har tagits emot, tittar man på vilket slutgiltigt tillstånd som har det absolut lägsta totala felvärdet. Sedan backar man bakåt genom de sparade &amp;quot;bästa vägarna&amp;quot; till början.&lt;br /&gt;
&lt;br /&gt;
Resultatet blir den absolut mest sannolika sekvensen av bitar som sändaren faktiskt skickade ut, trots att det var fullt av bitfel under resans gång.&lt;br /&gt;
&lt;br /&gt;
= Implementation i hyggligt modern C=&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
 * Anders Sikvall 2026 Version 1.0&lt;br /&gt;
 * &amp;lt;anders@sikvall.se&amp;gt;&lt;br /&gt;
 * &lt;br /&gt;
 * Implementation i C av en standard Viterbi-algoritm som används bl.a. av &lt;br /&gt;
 * Qualcomm och NASA och är välpublicerad.&lt;br /&gt;
 *&lt;br /&gt;
 * PUBLIC DOMAIN FOR EDUCATIONAL PURPOSES&lt;br /&gt;
 *&lt;br /&gt;
 * Kompilera med gcc -o viterbi viterbi.c&lt;br /&gt;
 *&lt;br /&gt;
 * ANVÄNDNING&lt;br /&gt;
 *         viterbi -e &amp;lt;indatastream &amp;gt;utdatastream   Kodar &amp;lt;indatastream till &amp;gt;utdatastream&lt;br /&gt;
 *         viterbi -d &amp;lt;indatastream &amp;gt;utdatastream   Avkodar &amp;lt;indatastream till &amp;gt;utdatastream&lt;br /&gt;
 *         viterbi -t                               Utför en intern test på 64 randomiserade oktetter&lt;br /&gt;
 *         viterbi -h                               Visar en kort hjälptext&lt;br /&gt;
 *         viterbi --error                          Samma sak som -t men introducerar 3 flippade bitpar&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
#include &amp;lt;string.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdbool.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdint.h&amp;gt;&lt;br /&gt;
#include &amp;lt;time.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
/* Constraint length (K=7) innebär att skiftregistret minns de senaste 7 bitarna. */&lt;br /&gt;
#define K 7&lt;br /&gt;
&lt;br /&gt;
/* Antalet tillstånd i trellis-diagrammet bestäms av de senaste K-1 bitarna.&lt;br /&gt;
   2^(7-1) = 2^6 = 64 unika tillstånd totalt. */&lt;br /&gt;
#define NUM_STATES (1 &amp;lt;&amp;lt; (K - 1))&lt;br /&gt;
&lt;br /&gt;
/* Standard NASA/Qualcomm-polynom för Rate 1/2 konvolutionskodning.&lt;br /&gt;
   POLY_G0 motsvarar oktalt 151 (1001111 binärt).&lt;br /&gt;
   POLY_G1 motsvarar oktalt 113 (1101101 binärt).&lt;br /&gt;
   Dessa maskar används för att bestämma vilka bitar i tillståndet som XOR-sammanfogas. */&lt;br /&gt;
const uint8_t POLY_G0 = 0x4F;&lt;br /&gt;
const uint8_t POLY_G1 = 0x6D;&lt;br /&gt;
&lt;br /&gt;
/* Hårdvaruoptimerad paritetsberäkning.&lt;br /&gt;
   Räknar antalet satta bitar (1:or) i ett tal och returnerar 1 om antalet är udda,&lt;br /&gt;
   eller 0 om antalet är jämnt (motsvarar en kedja av XOR-grindar). */&lt;br /&gt;
static inline uint8_t parity(uint8_t x) {&lt;br /&gt;
    return __builtin_parity(x) &amp;amp; 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// ============================================================================&lt;br /&gt;
// KODARE (-e)&lt;br /&gt;
// ============================================================================&lt;br /&gt;
void encode(FILE *in, FILE *out) {&lt;br /&gt;
    /* encoder_state lagrar historiken av de senaste K-1 (6) bitarna. */&lt;br /&gt;
    uint8_t encoder_state = 0;&lt;br /&gt;
&lt;br /&gt;
    /* out_byte används som en tillfällig buffer för att samla ihop bitar till en hel byte. */&lt;br /&gt;
    uint8_t out_byte = 0;&lt;br /&gt;
&lt;br /&gt;
    /* bit_count håller koll på hur många bitar som för tillfället ligger i utmatningsbufferten. */&lt;br /&gt;
    int bit_count = 0;&lt;br /&gt;
    int ch;&lt;br /&gt;
&lt;br /&gt;
    /* Loopa igenom infilen tecken för tecken (byte för byte). */&lt;br /&gt;
    while ((ch = fgetc(in)) != EOF) {&lt;br /&gt;
&lt;br /&gt;
        /* Gå igenom varje enskild bit i den inlästa byten, från MSB (bit 7) till LSB (bit 0). */&lt;br /&gt;
        for (int i = 7; i &amp;gt;= 0; i--) {&lt;br /&gt;
&lt;br /&gt;
            /* Isolera biten på position i. */&lt;br /&gt;
            uint8_t bit = (ch &amp;gt;&amp;gt; i) &amp;amp; 1;&lt;br /&gt;
&lt;br /&gt;
            /* Skapa det nuvarande ordet genom att skifta upp det gamla tillståndet till vänster&lt;br /&gt;
               och lägga till den nya inkommande biten som den lägsta biten (LSB). */&lt;br /&gt;
            uint8_t current_word = (encoder_state &amp;lt;&amp;lt; 1) | bit;&lt;br /&gt;
&lt;br /&gt;
            /* Beräkna de två paritetsbitarna (out0 och out1) genom att applicera polynommaskerna&lt;br /&gt;
               och köra XOR (paritet) på resultatet. */&lt;br /&gt;
            uint8_t out0 = parity(current_word &amp;amp; POLY_G0);&lt;br /&gt;
            uint8_t out1 = parity(current_word &amp;amp; POLY_G1);&lt;br /&gt;
&lt;br /&gt;
            /* Knuffa in den första paritetsbiten (out0) i utmatningsbyten. */&lt;br /&gt;
            out_byte = (out_byte &amp;lt;&amp;lt; 1) | out0;&lt;br /&gt;
            bit_count++;&lt;br /&gt;
&lt;br /&gt;
            /* Om vi har fyllt en hel byte (8 bitar), skriv ut den till utmatningsströmmen. */&lt;br /&gt;
            if (bit_count == 8) {&lt;br /&gt;
                fputc(out_byte, out);&lt;br /&gt;
                out_byte = 0;&lt;br /&gt;
                bit_count = 0;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            /* Knuffa in den andra paritetsbiten (out1) i utmatningsbyten. */&lt;br /&gt;
            out_byte = (out_byte &amp;lt;&amp;lt; 1) | out1;&lt;br /&gt;
            bit_count++;&lt;br /&gt;
&lt;br /&gt;
            /* Kontrollera återigen om utmatningsbyten blev full efter den andra biten. */&lt;br /&gt;
            if (bit_count == 8) {&lt;br /&gt;
                fputc(out_byte, out);&lt;br /&gt;
                out_byte = 0;&lt;br /&gt;
                bit_count = 0;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            /* Uppdatera kodarens interna tillstånd inför nästa bit.&lt;br /&gt;
               Vi sparar endast de lägsta K-1 bitarna med hjälp av en bitmask (63 = 0x3F). */&lt;br /&gt;
            encoder_state = current_word &amp;amp; (NUM_STATES - 1);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    /* Om det finns kvarvarande bitar i bufferten när filen slutar,&lt;br /&gt;
       skiftar vi dem till vänster så att de ligger rätt, och skriver ut den sista ofullständiga byten. */&lt;br /&gt;
    if (bit_count &amp;gt; 0) {&lt;br /&gt;
        out_byte &amp;lt;&amp;lt;= (8 - bit_count);&lt;br /&gt;
        fputc(out_byte, out);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// ============================================================================&lt;br /&gt;
// AVKODARE (-d)&lt;br /&gt;
// ============================================================================&lt;br /&gt;
void decode(FILE *in, FILE *out) {&lt;br /&gt;
    /* Startkapacitet för historikmatrisen (antalet bit-steg). Den växer linjärt vid behov. */&lt;br /&gt;
    size_t history_capacity = 1024;&lt;br /&gt;
    size_t step = 0;&lt;br /&gt;
&lt;br /&gt;
    /* Allokera historikmatrisen dynamiskt. Det är en 2D-array av storleken [kapacitet][64].&lt;br /&gt;
       Den sparar överlevnadsbesluten (0 eller 1) för varje tillstånd vid varje givet tidssteg. */&lt;br /&gt;
    uint8_t (*history)[NUM_STATES] = malloc(history_capacity * sizeof(*history));&lt;br /&gt;
    if (!history) {&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    /* path_metrics lagrar den ackumulerade felkostnaden (Hammingavståndet) för de 64 nuvarande tillstånden. */&lt;br /&gt;
    uint32_t path_metrics[NUM_STATES];&lt;br /&gt;
&lt;br /&gt;
    /* old_metrics lagrar en oförändrad kopia av kostnaderna från föregående tidssteg. */&lt;br /&gt;
    uint32_t old_metrics[NUM_STATES];&lt;br /&gt;
&lt;br /&gt;
    /* Initiera alla tillstånd till en mycket hög felkostnad (&amp;quot;oändlighet&amp;quot;).&lt;br /&gt;
       Undantaget är tillstånd 0, vilket är det kända och garanterade starttillståndet (kostnad 0). */&lt;br /&gt;
    for (int i = 1; i &amp;lt; NUM_STATES; i++) {&lt;br /&gt;
        path_metrics[i] = 1e6;&lt;br /&gt;
    }&lt;br /&gt;
    path_metrics[0] = 0;&lt;br /&gt;
&lt;br /&gt;
    int ch;&lt;br /&gt;
&lt;br /&gt;
    // ------------------------------------------------------------------------&lt;br /&gt;
    // STEG 1: Framåtpass (Forward Pass / Add-Compare-Select)&lt;br /&gt;
    // ------------------------------------------------------------------------&lt;br /&gt;
    /* Läs den kodade strömmen byte för byte. */&lt;br /&gt;
    while ((ch = fgetc(in)) != EOF) {&lt;br /&gt;
&lt;br /&gt;
        /* Varje inläst byte innehåller 4 bitpar (totalt 8 kodade bitar), vilket motsvarar 4 tidssteg. */&lt;br /&gt;
        for (int bit_pair = 3; bit_pair &amp;gt;= 0; bit_pair--) {&lt;br /&gt;
&lt;br /&gt;
            /* Extrahera de två bitarna (b0 och b1) som hör till det aktuella steget. */&lt;br /&gt;
            uint8_t b0 = (ch &amp;gt;&amp;gt; (bit_pair * 2 + 1)) &amp;amp; 1;&lt;br /&gt;
            uint8_t b1 = (ch &amp;gt;&amp;gt; (bit_pair * 2)) &amp;amp; 1;&lt;br /&gt;
&lt;br /&gt;
            /* Om vår historikmatris är full, fördubblar vi dess storlek dynamiskt med realloc.&lt;br /&gt;
               Detta gör att programmet kan hantera obegränsat stora filer och pipes. */&lt;br /&gt;
            if (step &amp;gt;= history_capacity) {&lt;br /&gt;
                history_capacity *= 2;&lt;br /&gt;
                uint8_t (*new_history)[NUM_STATES] = realloc(history, history_capacity * sizeof(*history));&lt;br /&gt;
                if (!new_history) {&lt;br /&gt;
                    free(history);&lt;br /&gt;
                    return;&lt;br /&gt;
                }&lt;br /&gt;
                history = new_history;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            /* Kopiera över nuvarande path_metrics till old_metrics inför beräkningen av nästa steg. */&lt;br /&gt;
            memcpy(old_metrics, path_metrics, sizeof(path_metrics));&lt;br /&gt;
&lt;br /&gt;
            /* Loopa igenom alla 64 möjliga måltillstånd (nästa tillstånd) i trellis-diagrammet. */&lt;br /&gt;
            for (int state = 0; state &amp;lt; NUM_STATES; state++) {&lt;br /&gt;
&lt;br /&gt;
                /* Eftersom vi skiftar till vänster, kan vi räkna ut vilka två föregående tillstånd&lt;br /&gt;
                   (prev0 och prev1) som kan ha skiftat in i det nuvarande tillståndet. */&lt;br /&gt;
                int prev0 = state &amp;gt;&amp;gt; 1;&lt;br /&gt;
                int prev1 = prev0 | (NUM_STATES &amp;gt;&amp;gt; 1);&lt;br /&gt;
&lt;br /&gt;
                /* Den inbit som krävdes för att nå &#039;state&#039; är identisk med nuvarande tillstånds LSB. */&lt;br /&gt;
                uint8_t input_bit = state &amp;amp; 1;&lt;br /&gt;
&lt;br /&gt;
                /* --- Beräkna förväntade bitar och Hammingavstånd för VÄG 0 (från prev0) --- */&lt;br /&gt;
                uint8_t word0 = (prev0 &amp;lt;&amp;lt; 1) | input_bit;&lt;br /&gt;
                uint8_t exp0_0 = parity(word0 &amp;amp; POLY_G0);&lt;br /&gt;
                uint8_t exp0_1 = parity(word0 &amp;amp; POLY_G1);&lt;br /&gt;
                /* Kostnaden ökar med 1 för varje bit som inte matchar de faktiskt mottagna bitarna. */&lt;br /&gt;
                uint32_t cost0 = (exp0_0 != b0) + (exp0_1 != b1);&lt;br /&gt;
&lt;br /&gt;
                /* --- Beräkna förväntade bitar och Hammingavstånd för VÄG 1 (från prev1) --- */&lt;br /&gt;
                uint8_t word1 = (prev1 &amp;lt;&amp;lt; 1) | input_bit;&lt;br /&gt;
                uint8_t exp1_0 = parity(word1 &amp;amp; POLY_G0);&lt;br /&gt;
                uint8_t exp1_1 = parity(word1 &amp;amp; POLY_G1);&lt;br /&gt;
                uint32_t cost1 = (exp1_0 != b0) + (exp1_1 != b1);&lt;br /&gt;
&lt;br /&gt;
                /* Addera det gamla ackumulerade felet med det nya övergångsfelet för båda vägarna. */&lt;br /&gt;
                uint32_t m0 = old_metrics[prev0] + cost0;&lt;br /&gt;
                uint32_t m1 = old_metrics[prev1] + cost1;&lt;br /&gt;
&lt;br /&gt;
                /* (Compare &amp;amp; Select): Välj den väg som har lägst totalt fel.&lt;br /&gt;
                   Spara det nya lägsta felet i path_metrics, och dokumentera valet (0 eller 1)&lt;br /&gt;
                   i historikmatrisen för att kunna återskapa vägen baklänges senare. */&lt;br /&gt;
                if (m0 &amp;lt;= m1) {&lt;br /&gt;
                    path_metrics[state] = m0;&lt;br /&gt;
                    history[step][state] = 0;&lt;br /&gt;
                } else {&lt;br /&gt;
                    path_metrics[state] = m1;&lt;br /&gt;
                    history[step][state] = 1;&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
            /* Öka räknaren för antal avklarade bit-steg. */&lt;br /&gt;
            step++;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    /* Om vi inte lyckades läsa några bitar alls, städa upp och avsluta. */&lt;br /&gt;
    if (step == 0) {&lt;br /&gt;
        free(history);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // ------------------------------------------------------------------------&lt;br /&gt;
    // STEG 2: Hitta bästa sluttillstånd&lt;br /&gt;
    // ------------------------------------------------------------------------&lt;br /&gt;
    /* Sök igenom alla 64 tillstånd vid slutet av strömmen för att hitta det tillstånd&lt;br /&gt;
       som har samlat på sig minst antal fel (lägst metric). */&lt;br /&gt;
    int curr_state = 0;&lt;br /&gt;
    uint32_t min_m = path_metrics[0];&lt;br /&gt;
    for (int i = 1; i &amp;lt; NUM_STATES; i++) {&lt;br /&gt;
        if (path_metrics[i] &amp;lt; min_m) {&lt;br /&gt;
            min_m = path_metrics[i];&lt;br /&gt;
            curr_state = i;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // ------------------------------------------------------------------------&lt;br /&gt;
    // STEG 3: Bakåtspårning (Traceback)&lt;br /&gt;
    // ------------------------------------------------------------------------&lt;br /&gt;
    /* Allokera en temporär array för att spara de avkodade bitarna.&lt;br /&gt;
       Eftersom vi vandrar baklänges kommer vi att fylla denna array bakifrån. */&lt;br /&gt;
    uint8_t *decoded_bits = malloc(step);&lt;br /&gt;
    if (!decoded_bits) {&lt;br /&gt;
        free(history);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    /* Vandra baklänges genom historiken från det sista tidssteget ner till noll. */&lt;br /&gt;
    for (int s = (int)step - 1; s &amp;gt;= 0; s--) {&lt;br /&gt;
&lt;br /&gt;
        /* Den ursprungliga inbiten är alltid LSB (bit 0) i det tillstånd vi står i. */&lt;br /&gt;
        decoded_bits[s] = curr_state &amp;amp; 1;&lt;br /&gt;
&lt;br /&gt;
        /* Hämta beslutet (0 eller 1) som fattades för detta tillstånd i tidssteg s. */&lt;br /&gt;
        int decision = history[s][curr_state];&lt;br /&gt;
        int prev0 = curr_state &amp;gt;&amp;gt; 1;&lt;br /&gt;
&lt;br /&gt;
        /* Rekonstruera vilket tillstånd vi kom ifrån baserat på det sparade beslutet. */&lt;br /&gt;
        if (decision == 0) {&lt;br /&gt;
            curr_state = prev0;&lt;br /&gt;
        } else {&lt;br /&gt;
            curr_state = prev0 | (NUM_STATES &amp;gt;&amp;gt; 1);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // ------------------------------------------------------------------------&lt;br /&gt;
    // STEG 4: Återpacka till bytes och skriv ut&lt;br /&gt;
    // ------------------------------------------------------------------------&lt;br /&gt;
    /* Bitarna ligger nu i korrekt kronologisk ordning i decoded_bits-arrayen.&lt;br /&gt;
       Vi loopar igenom dem och packar ihop dem 8 och 8 till vanliga bytes igen. */&lt;br /&gt;
    uint8_t current_byte = 0;&lt;br /&gt;
    for (size_t i = 0; i &amp;lt; step; i++) {&lt;br /&gt;
        current_byte = (current_byte &amp;lt;&amp;lt; 1) | decoded_bits[i];&lt;br /&gt;
&lt;br /&gt;
        /* Varje gång vi har samlat ihop 8 bitar skriver vi ut byten till utfilen/stdout. */&lt;br /&gt;
        if ((i + 1) % 8 == 0) {&lt;br /&gt;
            fputc(current_byte, out);&lt;br /&gt;
            current_byte = 0;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    /* Frigör det dynamiskt allokerade minnet. */&lt;br /&gt;
    free(decoded_bits);&lt;br /&gt;
    free(history);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// ============================================================================&lt;br /&gt;
// INTERNT TEST (-t OCH --error)&lt;br /&gt;
// ============================================================================&lt;br /&gt;
void run_test(bool inject_errors) {&lt;br /&gt;
    if (inject_errors) {&lt;br /&gt;
        printf(&amp;quot;[*] Startar internt test med FELKORRIGERING (64 bytes slumpdata + 3 bitpar flippade)...\n&amp;quot;);&lt;br /&gt;
    } else {&lt;br /&gt;
        printf(&amp;quot;[*] Startar internt test (64 bytes randomiserat data)...\n&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    /* Skapa en array med 64 bytes slumpmässigt data. */&lt;br /&gt;
    uint8_t original_data[64];&lt;br /&gt;
    srand((unsigned int)time(NULL));&lt;br /&gt;
    for (int i = 0; i &amp;lt; 64; i++) {&lt;br /&gt;
        original_data[i] = rand() % 256;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    /* tmpfile() skapar temporära filer som körs i RAM/hårddisk och raderas automatiskt vid stängning. */&lt;br /&gt;
    FILE *orig_stream = tmpfile();&lt;br /&gt;
    FILE *encoded_stream = tmpfile();&lt;br /&gt;
    FILE *corrupted_stream = tmpfile();&lt;br /&gt;
    FILE *decoded_stream = tmpfile();&lt;br /&gt;
&lt;br /&gt;
    if (!orig_stream || !encoded_stream || !corrupted_stream || !decoded_stream) {&lt;br /&gt;
        fprintf(stderr, &amp;quot;Kunde inte skapa temporära filer.\n&amp;quot;);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    /* Skriv originaldata till startströmmen och spola tillbaka pekaren till början. */&lt;br /&gt;
    fwrite(original_data, 1, 64, orig_stream);&lt;br /&gt;
    rewind(orig_stream);&lt;br /&gt;
&lt;br /&gt;
    /* 1. Kör kodningen (64 bytes rådata blir exakt 128 bytes packad bitström). */&lt;br /&gt;
    encode(orig_stream, encoded_stream);&lt;br /&gt;
    rewind(encoded_stream);&lt;br /&gt;
&lt;br /&gt;
    /* 2. Hantering av felinjicering (--error). */&lt;br /&gt;
    if (inject_errors) {&lt;br /&gt;
        uint8_t encoded_data[128];&lt;br /&gt;
&lt;br /&gt;
        /* Läs in hela den kodade strömmen till en lokal array. */&lt;br /&gt;
        if (fread(encoded_data, 1, 128, encoded_stream) == 128) {&lt;br /&gt;
&lt;br /&gt;
            /* Välj ut 3 slumpmässiga bytes och flippa en slumpmässig bit i var och en av dem. */&lt;br /&gt;
            for (int i = 0; i &amp;lt; 3; i++) {&lt;br /&gt;
                int byte_index = rand() % 128;&lt;br /&gt;
                int bit_index = rand() % 8;&lt;br /&gt;
&lt;br /&gt;
                /* XOR-operatör (^) flippar den valda biten (0 blir 1, 1 blir 0). */&lt;br /&gt;
                encoded_data[byte_index] ^= (1 &amp;lt;&amp;lt; bit_index);&lt;br /&gt;
                printf(&amp;quot;[i] Introducerade bitfel i kodad byte %d, bit %d\n&amp;quot;, byte_index, bit_index);&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        /* Skriv ut det saboterade datat till den korrupta strömmen. */&lt;br /&gt;
        fwrite(encoded_data, 1, 128, corrupted_stream);&lt;br /&gt;
        rewind(corrupted_stream);&lt;br /&gt;
    } else {&lt;br /&gt;
        /* Om inga fel ska testas, pekar vi bara vidare till den felfria strömmen direkt. */&lt;br /&gt;
        corrupted_stream = encoded_stream;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    /* 3. Kör avkodaren på dataströmmen. */&lt;br /&gt;
    decode(corrupted_stream, decoded_stream);&lt;br /&gt;
    rewind(decoded_stream);&lt;br /&gt;
&lt;br /&gt;
    /* 4. Läs tillbaka det färdigavkodade datat och verifiera resultatet. */&lt;br /&gt;
    uint8_t final_data[64];&lt;br /&gt;
    size_t read_bytes = fread(final_data, 1, 64, decoded_stream);&lt;br /&gt;
&lt;br /&gt;
    bool success = true;&lt;br /&gt;
    if (read_bytes != 64) {&lt;br /&gt;
        printf(&amp;quot;[FAIL] Avkodade fel antal bytes: %zu (förväntade 64)\n&amp;quot;, read_bytes);&lt;br /&gt;
        success = false;&lt;br /&gt;
    } else {&lt;br /&gt;
        /* Jämför ursprunglig array med den avkodade arrayen byte för byte. */&lt;br /&gt;
        for (int i = 0; i &amp;lt; 64; i++) {&lt;br /&gt;
            if (original_data[i] != final_data[i]) {&lt;br /&gt;
                printf(&amp;quot;[FAIL] Diff vid byte %d: Org=0x%02X, Avkodad=0x%02X\n&amp;quot;, i, original_data[i], final_data[i]);&lt;br /&gt;
                success = false;&lt;br /&gt;
                break;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    /* Stäng alla strömmar ordentligt. */&lt;br /&gt;
    fclose(orig_stream);&lt;br /&gt;
    if (inject_errors) {&lt;br /&gt;
        fclose(encoded_stream);&lt;br /&gt;
        fclose(corrupted_stream);&lt;br /&gt;
    } else {&lt;br /&gt;
        fclose(encoded_stream);&lt;br /&gt;
    }&lt;br /&gt;
    fclose(decoded_stream);&lt;br /&gt;
&lt;br /&gt;
    /* Skriv ut slutrapport för testet. */&lt;br /&gt;
    if (success) {&lt;br /&gt;
        if (inject_errors) {&lt;br /&gt;
            printf(&amp;quot;[SUCCESS] Viterbi-algoritmens felkorrigering lyckades! Alla bitfel lagades och datat matchar perfekt.\n&amp;quot;);&lt;br /&gt;
        } else {&lt;br /&gt;
            printf(&amp;quot;[SUCCESS] Testet lyckades! Allt data matchar perfekt.\n&amp;quot;);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// ============================================================================&lt;br /&gt;
// HJÄLPTEXT OCH MAIN&lt;br /&gt;
// ============================================================================&lt;br /&gt;
void print_help(const char *prog_name) {&lt;br /&gt;
    printf(&amp;quot;Användning: %s [option]\n&amp;quot;, prog_name);&lt;br /&gt;
    printf(&amp;quot;Optioner:\n&amp;quot;);&lt;br /&gt;
    printf(&amp;quot;  -e &amp;lt;infil &amp;gt;utfil   Kodar infil till utfil (Rate 1/2, K=7)\n&amp;quot;);&lt;br /&gt;
    printf(&amp;quot;  -d &amp;lt;infil &amp;gt;utfil   Avkodar infil till utfil med Viterbi\n&amp;quot;);&lt;br /&gt;
    printf(&amp;quot;  -h                 Visar denna hjälptext\n&amp;quot;);&lt;br /&gt;
    printf(&amp;quot;  -t                 Kör internt test med 64 bytes slumpdata\n&amp;quot;);&lt;br /&gt;
    printf(&amp;quot;  --error            Kör internt test men injicerar bitfel för att testa felkorrigeringen\n&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
int main(int argc, char *argv[]) {&lt;br /&gt;
    /* Säkerställ att användaren har skickat med exakt ett kommandoradsargument. */&lt;br /&gt;
    if (argc != 2) {&lt;br /&gt;
        print_help(argv[0]);&lt;br /&gt;
        return EXIT_FAILURE;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    /* Kontrollera vilket argument användaren skickade och anropa rätt funktion. */&lt;br /&gt;
    if (strcmp(argv[1], &amp;quot;-e&amp;quot;) == 0) {&lt;br /&gt;
        encode(stdin, stdout);&lt;br /&gt;
    } else if (strcmp(argv[1], &amp;quot;-d&amp;quot;) == 0) {&lt;br /&gt;
        decode(stdin, stdout);&lt;br /&gt;
    } else if (strcmp(argv[1], &amp;quot;-h&amp;quot;) == 0) {&lt;br /&gt;
        print_help(argv[0]);&lt;br /&gt;
    } else if (strcmp(argv[1], &amp;quot;-t&amp;quot;) == 0) {&lt;br /&gt;
        run_test(false);&lt;br /&gt;
    } else if (strcmp(argv[1], &amp;quot;--error&amp;quot;) == 0) {&lt;br /&gt;
        run_test(true);&lt;br /&gt;
    } else {&lt;br /&gt;
        fprintf(stderr, &amp;quot;Fel: Okänd parameter &#039;%s&#039;\n&amp;quot;, argv[1]);&lt;br /&gt;
        print_help(argv[0]);&lt;br /&gt;
        return EXIT_FAILURE;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return EXIT_SUCCESS;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>Anders</name></author>
	</entry>
	<entry>
		<id>http://wiki.sikvall.se/index.php?title=Viterbi&amp;diff=1910</id>
		<title>Viterbi</title>
		<link rel="alternate" type="text/html" href="http://wiki.sikvall.se/index.php?title=Viterbi&amp;diff=1910"/>
		<updated>2026-06-23T17:55:56Z</updated>

		<summary type="html">&lt;p&gt;Anders: /* Hur funkar det? */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Bakgrund = &lt;br /&gt;
&lt;br /&gt;
== Viterbis algoritm – Hur vi hittar rätt signal i bruset ==&lt;br /&gt;
&lt;br /&gt;
Inom amatörradion och digital signalbehandling stöter vi ofta på problemet med brus och fading. När vi skickar digital data över etern, till exempel med modernare digitala trafiksätt eller vid satellitkommunikation, använder vi ofta något som kallas för faltningskodning (convolutional coding). Det är en metod där varje sänd bit beror på både den nuvarande biten och ett antal tidigare bitar. Detta skapar ett mönster, ett beroende, som gör signalen robust.&lt;br /&gt;
&lt;br /&gt;
Men hur avkodar vi detta på mottagarsidan när atmosfären har ställt till det och lagt till en massa brus? Det är här Viterbis algoritm kommer in i bilden.&lt;br /&gt;
&lt;br /&gt;
Kort sagt är Viterbialgoritmen en metod för att hitta den mest troliga sekvensen av dolda tillstånd (det vi faktiskt sände) baserat på en serie observerade händelser (den brusiga signalen vi tog emot). Istället för att gissa bit för bit, tittar algoritmen på hela sammanhanget.&lt;br /&gt;
&lt;br /&gt;
== Trellis-diagrammet: Vägarna genom historien ==&lt;br /&gt;
&lt;br /&gt;
För att förstå hur algoritmen jobbar kan vi tänka oss ett nätverk av vägar, ett så kallat trellis-diagram.&lt;br /&gt;
&lt;br /&gt;
* Tillstånd (States): Radiosändarens &amp;quot;minne&amp;quot; kan vid varje given tidpunkt befinna sig i ett visst antal tillstånd (beroende på de senaste sända bitarna).&lt;br /&gt;
&lt;br /&gt;
* Övergångar: När en ny bit ska sändas hoppar sändaren till ett nytt tillstånd och skickar ut en specifik kombination av bitar i luften.&lt;br /&gt;
&lt;br /&gt;
== Hur funkar det? ==&lt;br /&gt;
&lt;br /&gt;
När mottagaren lyssnar får den in en sekvens som kanske är halvt dränkt i brus. En nolla kanske ser ut som en svag etta, och så vidare. Viterbialgoritmen börjar nu räkna på alla möjliga vägar genom detta nätverk av tillstånd över tid.&lt;br /&gt;
Så här jobbar algoritmen steg för steg:&lt;br /&gt;
&lt;br /&gt;
# Beräkna avstånd (Metric): För varje steg i tiden tittar algoritmen på de bitar som faktiskt togs emot och jämför dem med vad som borde ha sänts för varje tänkbar väg i diagrammet. Man mäter &amp;quot;avståndet&amp;quot; (ofta Hamming-avstånd för ettor och nollor, eller Euklidiskt avstånd om man kör &amp;quot;soft decision&amp;quot; där man mäter signalstyrkan mer exakt). Ju mindre avstånd, desto mer troligt är det att den vägen är den rätta.&lt;br /&gt;
# Spara den bästa vägen (Add-Compare-Select): Till varje nytt tillstånd i diagrammet leder det oftast två olika vägar från det föregående steget. Algoritmen adderar det nya avståndet till det gamla, jämför de två alternativen, och väljer den väg som har lägst totalt avstånd (fel). Den andra vägen slängs bort för alltid. Det här är algoritmens stora styrka: den rensar hela tiden bort återvändsgränder så att beräkningsbördan inte exploderar.&lt;br /&gt;
# Lås historiken (Traceback): När hela sekvensen (eller ett tillräckligt långt block) har tagits emot, tittar man på vilket slutgiltigt tillstånd som har det absolut lägsta totala felvärdet. Sedan backar man bakåt genom de sparade &amp;quot;bästa vägarna&amp;quot; till början.&lt;br /&gt;
&lt;br /&gt;
Resultatet blir den absolut mest sannolika sekvensen av bitar som sändaren faktiskt skickade ut, trots att det var fullt av bitfel under resans gång.&lt;br /&gt;
&lt;br /&gt;
= Implementation =&lt;br /&gt;
&lt;br /&gt;
== Modern C ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
 * Anders Sikvall 2026 Version 1.0&lt;br /&gt;
 * &amp;lt;anders@sikvall.se&amp;gt;&lt;br /&gt;
 * &lt;br /&gt;
 * Implementation i C av en standard Viterbi-algoritm som används bl.a. av &lt;br /&gt;
 * Qualcomm och NASA och är välpublicerad.&lt;br /&gt;
 *&lt;br /&gt;
 * PUBLIC DOMAIN FOR EDUCATIONAL PURPOSES&lt;br /&gt;
 *&lt;br /&gt;
 * Kompilera med gcc -o viterbi viterbi.c&lt;br /&gt;
 *&lt;br /&gt;
 * ANVÄNDNING&lt;br /&gt;
 *         viterbi -e &amp;lt;indatastream &amp;gt;utdatastream   Kodar &amp;lt;indatastream till &amp;gt;utdatastream&lt;br /&gt;
 *         viterbi -d &amp;lt;indatastream &amp;gt;utdatastream   Avkodar &amp;lt;indatastream till &amp;gt;utdatastream&lt;br /&gt;
 *         viterbi -t                               Utför en intern test på 64 randomiserade oktetter&lt;br /&gt;
 *         viterbi -h                               Visar en kort hjälptext&lt;br /&gt;
 *         viterbi --error                          Samma sak som -t men introducerar 3 flippade bitpar&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
#include &amp;lt;string.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdbool.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdint.h&amp;gt;&lt;br /&gt;
#include &amp;lt;time.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
/* Constraint length (K=7) innebär att skiftregistret minns de senaste 7 bitarna. */&lt;br /&gt;
#define K 7&lt;br /&gt;
&lt;br /&gt;
/* Antalet tillstånd i trellis-diagrammet bestäms av de senaste K-1 bitarna.&lt;br /&gt;
   2^(7-1) = 2^6 = 64 unika tillstånd totalt. */&lt;br /&gt;
#define NUM_STATES (1 &amp;lt;&amp;lt; (K - 1))&lt;br /&gt;
&lt;br /&gt;
/* Standard NASA/Qualcomm-polynom för Rate 1/2 konvolutionskodning.&lt;br /&gt;
   POLY_G0 motsvarar oktalt 151 (1001111 binärt).&lt;br /&gt;
   POLY_G1 motsvarar oktalt 113 (1101101 binärt).&lt;br /&gt;
   Dessa maskar används för att bestämma vilka bitar i tillståndet som XOR-sammanfogas. */&lt;br /&gt;
const uint8_t POLY_G0 = 0x4F;&lt;br /&gt;
const uint8_t POLY_G1 = 0x6D;&lt;br /&gt;
&lt;br /&gt;
/* Hårdvaruoptimerad paritetsberäkning.&lt;br /&gt;
   Räknar antalet satta bitar (1:or) i ett tal och returnerar 1 om antalet är udda,&lt;br /&gt;
   eller 0 om antalet är jämnt (motsvarar en kedja av XOR-grindar). */&lt;br /&gt;
static inline uint8_t parity(uint8_t x) {&lt;br /&gt;
    return __builtin_parity(x) &amp;amp; 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// ============================================================================&lt;br /&gt;
// KODARE (-e)&lt;br /&gt;
// ============================================================================&lt;br /&gt;
void encode(FILE *in, FILE *out) {&lt;br /&gt;
    /* encoder_state lagrar historiken av de senaste K-1 (6) bitarna. */&lt;br /&gt;
    uint8_t encoder_state = 0;&lt;br /&gt;
&lt;br /&gt;
    /* out_byte används som en tillfällig buffer för att samla ihop bitar till en hel byte. */&lt;br /&gt;
    uint8_t out_byte = 0;&lt;br /&gt;
&lt;br /&gt;
    /* bit_count håller koll på hur många bitar som för tillfället ligger i utmatningsbufferten. */&lt;br /&gt;
    int bit_count = 0;&lt;br /&gt;
    int ch;&lt;br /&gt;
&lt;br /&gt;
    /* Loopa igenom infilen tecken för tecken (byte för byte). */&lt;br /&gt;
    while ((ch = fgetc(in)) != EOF) {&lt;br /&gt;
&lt;br /&gt;
        /* Gå igenom varje enskild bit i den inlästa byten, från MSB (bit 7) till LSB (bit 0). */&lt;br /&gt;
        for (int i = 7; i &amp;gt;= 0; i--) {&lt;br /&gt;
&lt;br /&gt;
            /* Isolera biten på position i. */&lt;br /&gt;
            uint8_t bit = (ch &amp;gt;&amp;gt; i) &amp;amp; 1;&lt;br /&gt;
&lt;br /&gt;
            /* Skapa det nuvarande ordet genom att skifta upp det gamla tillståndet till vänster&lt;br /&gt;
               och lägga till den nya inkommande biten som den lägsta biten (LSB). */&lt;br /&gt;
            uint8_t current_word = (encoder_state &amp;lt;&amp;lt; 1) | bit;&lt;br /&gt;
&lt;br /&gt;
            /* Beräkna de två paritetsbitarna (out0 och out1) genom att applicera polynommaskerna&lt;br /&gt;
               och köra XOR (paritet) på resultatet. */&lt;br /&gt;
            uint8_t out0 = parity(current_word &amp;amp; POLY_G0);&lt;br /&gt;
            uint8_t out1 = parity(current_word &amp;amp; POLY_G1);&lt;br /&gt;
&lt;br /&gt;
            /* Knuffa in den första paritetsbiten (out0) i utmatningsbyten. */&lt;br /&gt;
            out_byte = (out_byte &amp;lt;&amp;lt; 1) | out0;&lt;br /&gt;
            bit_count++;&lt;br /&gt;
&lt;br /&gt;
            /* Om vi har fyllt en hel byte (8 bitar), skriv ut den till utmatningsströmmen. */&lt;br /&gt;
            if (bit_count == 8) {&lt;br /&gt;
                fputc(out_byte, out);&lt;br /&gt;
                out_byte = 0;&lt;br /&gt;
                bit_count = 0;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            /* Knuffa in den andra paritetsbiten (out1) i utmatningsbyten. */&lt;br /&gt;
            out_byte = (out_byte &amp;lt;&amp;lt; 1) | out1;&lt;br /&gt;
            bit_count++;&lt;br /&gt;
&lt;br /&gt;
            /* Kontrollera återigen om utmatningsbyten blev full efter den andra biten. */&lt;br /&gt;
            if (bit_count == 8) {&lt;br /&gt;
                fputc(out_byte, out);&lt;br /&gt;
                out_byte = 0;&lt;br /&gt;
                bit_count = 0;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            /* Uppdatera kodarens interna tillstånd inför nästa bit.&lt;br /&gt;
               Vi sparar endast de lägsta K-1 bitarna med hjälp av en bitmask (63 = 0x3F). */&lt;br /&gt;
            encoder_state = current_word &amp;amp; (NUM_STATES - 1);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    /* Om det finns kvarvarande bitar i bufferten när filen slutar,&lt;br /&gt;
       skiftar vi dem till vänster så att de ligger rätt, och skriver ut den sista ofullständiga byten. */&lt;br /&gt;
    if (bit_count &amp;gt; 0) {&lt;br /&gt;
        out_byte &amp;lt;&amp;lt;= (8 - bit_count);&lt;br /&gt;
        fputc(out_byte, out);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// ============================================================================&lt;br /&gt;
// AVKODARE (-d)&lt;br /&gt;
// ============================================================================&lt;br /&gt;
void decode(FILE *in, FILE *out) {&lt;br /&gt;
    /* Startkapacitet för historikmatrisen (antalet bit-steg). Den växer linjärt vid behov. */&lt;br /&gt;
    size_t history_capacity = 1024;&lt;br /&gt;
    size_t step = 0;&lt;br /&gt;
&lt;br /&gt;
    /* Allokera historikmatrisen dynamiskt. Det är en 2D-array av storleken [kapacitet][64].&lt;br /&gt;
       Den sparar överlevnadsbesluten (0 eller 1) för varje tillstånd vid varje givet tidssteg. */&lt;br /&gt;
    uint8_t (*history)[NUM_STATES] = malloc(history_capacity * sizeof(*history));&lt;br /&gt;
    if (!history) {&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    /* path_metrics lagrar den ackumulerade felkostnaden (Hammingavståndet) för de 64 nuvarande tillstånden. */&lt;br /&gt;
    uint32_t path_metrics[NUM_STATES];&lt;br /&gt;
&lt;br /&gt;
    /* old_metrics lagrar en oförändrad kopia av kostnaderna från föregående tidssteg. */&lt;br /&gt;
    uint32_t old_metrics[NUM_STATES];&lt;br /&gt;
&lt;br /&gt;
    /* Initiera alla tillstånd till en mycket hög felkostnad (&amp;quot;oändlighet&amp;quot;).&lt;br /&gt;
       Undantaget är tillstånd 0, vilket är det kända och garanterade starttillståndet (kostnad 0). */&lt;br /&gt;
    for (int i = 1; i &amp;lt; NUM_STATES; i++) {&lt;br /&gt;
        path_metrics[i] = 1e6;&lt;br /&gt;
    }&lt;br /&gt;
    path_metrics[0] = 0;&lt;br /&gt;
&lt;br /&gt;
    int ch;&lt;br /&gt;
&lt;br /&gt;
    // ------------------------------------------------------------------------&lt;br /&gt;
    // STEG 1: Framåtpass (Forward Pass / Add-Compare-Select)&lt;br /&gt;
    // ------------------------------------------------------------------------&lt;br /&gt;
    /* Läs den kodade strömmen byte för byte. */&lt;br /&gt;
    while ((ch = fgetc(in)) != EOF) {&lt;br /&gt;
&lt;br /&gt;
        /* Varje inläst byte innehåller 4 bitpar (totalt 8 kodade bitar), vilket motsvarar 4 tidssteg. */&lt;br /&gt;
        for (int bit_pair = 3; bit_pair &amp;gt;= 0; bit_pair--) {&lt;br /&gt;
&lt;br /&gt;
            /* Extrahera de två bitarna (b0 och b1) som hör till det aktuella steget. */&lt;br /&gt;
            uint8_t b0 = (ch &amp;gt;&amp;gt; (bit_pair * 2 + 1)) &amp;amp; 1;&lt;br /&gt;
            uint8_t b1 = (ch &amp;gt;&amp;gt; (bit_pair * 2)) &amp;amp; 1;&lt;br /&gt;
&lt;br /&gt;
            /* Om vår historikmatris är full, fördubblar vi dess storlek dynamiskt med realloc.&lt;br /&gt;
               Detta gör att programmet kan hantera obegränsat stora filer och pipes. */&lt;br /&gt;
            if (step &amp;gt;= history_capacity) {&lt;br /&gt;
                history_capacity *= 2;&lt;br /&gt;
                uint8_t (*new_history)[NUM_STATES] = realloc(history, history_capacity * sizeof(*history));&lt;br /&gt;
                if (!new_history) {&lt;br /&gt;
                    free(history);&lt;br /&gt;
                    return;&lt;br /&gt;
                }&lt;br /&gt;
                history = new_history;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            /* Kopiera över nuvarande path_metrics till old_metrics inför beräkningen av nästa steg. */&lt;br /&gt;
            memcpy(old_metrics, path_metrics, sizeof(path_metrics));&lt;br /&gt;
&lt;br /&gt;
            /* Loopa igenom alla 64 möjliga måltillstånd (nästa tillstånd) i trellis-diagrammet. */&lt;br /&gt;
            for (int state = 0; state &amp;lt; NUM_STATES; state++) {&lt;br /&gt;
&lt;br /&gt;
                /* Eftersom vi skiftar till vänster, kan vi räkna ut vilka två föregående tillstånd&lt;br /&gt;
                   (prev0 och prev1) som kan ha skiftat in i det nuvarande tillståndet. */&lt;br /&gt;
                int prev0 = state &amp;gt;&amp;gt; 1;&lt;br /&gt;
                int prev1 = prev0 | (NUM_STATES &amp;gt;&amp;gt; 1);&lt;br /&gt;
&lt;br /&gt;
                /* Den inbit som krävdes för att nå &#039;state&#039; är identisk med nuvarande tillstånds LSB. */&lt;br /&gt;
                uint8_t input_bit = state &amp;amp; 1;&lt;br /&gt;
&lt;br /&gt;
                /* --- Beräkna förväntade bitar och Hammingavstånd för VÄG 0 (från prev0) --- */&lt;br /&gt;
                uint8_t word0 = (prev0 &amp;lt;&amp;lt; 1) | input_bit;&lt;br /&gt;
                uint8_t exp0_0 = parity(word0 &amp;amp; POLY_G0);&lt;br /&gt;
                uint8_t exp0_1 = parity(word0 &amp;amp; POLY_G1);&lt;br /&gt;
                /* Kostnaden ökar med 1 för varje bit som inte matchar de faktiskt mottagna bitarna. */&lt;br /&gt;
                uint32_t cost0 = (exp0_0 != b0) + (exp0_1 != b1);&lt;br /&gt;
&lt;br /&gt;
                /* --- Beräkna förväntade bitar och Hammingavstånd för VÄG 1 (från prev1) --- */&lt;br /&gt;
                uint8_t word1 = (prev1 &amp;lt;&amp;lt; 1) | input_bit;&lt;br /&gt;
                uint8_t exp1_0 = parity(word1 &amp;amp; POLY_G0);&lt;br /&gt;
                uint8_t exp1_1 = parity(word1 &amp;amp; POLY_G1);&lt;br /&gt;
                uint32_t cost1 = (exp1_0 != b0) + (exp1_1 != b1);&lt;br /&gt;
&lt;br /&gt;
                /* Addera det gamla ackumulerade felet med det nya övergångsfelet för båda vägarna. */&lt;br /&gt;
                uint32_t m0 = old_metrics[prev0] + cost0;&lt;br /&gt;
                uint32_t m1 = old_metrics[prev1] + cost1;&lt;br /&gt;
&lt;br /&gt;
                /* (Compare &amp;amp; Select): Välj den väg som har lägst totalt fel.&lt;br /&gt;
                   Spara det nya lägsta felet i path_metrics, och dokumentera valet (0 eller 1)&lt;br /&gt;
                   i historikmatrisen för att kunna återskapa vägen baklänges senare. */&lt;br /&gt;
                if (m0 &amp;lt;= m1) {&lt;br /&gt;
                    path_metrics[state] = m0;&lt;br /&gt;
                    history[step][state] = 0;&lt;br /&gt;
                } else {&lt;br /&gt;
                    path_metrics[state] = m1;&lt;br /&gt;
                    history[step][state] = 1;&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
            /* Öka räknaren för antal avklarade bit-steg. */&lt;br /&gt;
            step++;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    /* Om vi inte lyckades läsa några bitar alls, städa upp och avsluta. */&lt;br /&gt;
    if (step == 0) {&lt;br /&gt;
        free(history);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // ------------------------------------------------------------------------&lt;br /&gt;
    // STEG 2: Hitta bästa sluttillstånd&lt;br /&gt;
    // ------------------------------------------------------------------------&lt;br /&gt;
    /* Sök igenom alla 64 tillstånd vid slutet av strömmen för att hitta det tillstånd&lt;br /&gt;
       som har samlat på sig minst antal fel (lägst metric). */&lt;br /&gt;
    int curr_state = 0;&lt;br /&gt;
    uint32_t min_m = path_metrics[0];&lt;br /&gt;
    for (int i = 1; i &amp;lt; NUM_STATES; i++) {&lt;br /&gt;
        if (path_metrics[i] &amp;lt; min_m) {&lt;br /&gt;
            min_m = path_metrics[i];&lt;br /&gt;
            curr_state = i;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // ------------------------------------------------------------------------&lt;br /&gt;
    // STEG 3: Bakåtspårning (Traceback)&lt;br /&gt;
    // ------------------------------------------------------------------------&lt;br /&gt;
    /* Allokera en temporär array för att spara de avkodade bitarna.&lt;br /&gt;
       Eftersom vi vandrar baklänges kommer vi att fylla denna array bakifrån. */&lt;br /&gt;
    uint8_t *decoded_bits = malloc(step);&lt;br /&gt;
    if (!decoded_bits) {&lt;br /&gt;
        free(history);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    /* Vandra baklänges genom historiken från det sista tidssteget ner till noll. */&lt;br /&gt;
    for (int s = (int)step - 1; s &amp;gt;= 0; s--) {&lt;br /&gt;
&lt;br /&gt;
        /* Den ursprungliga inbiten är alltid LSB (bit 0) i det tillstånd vi står i. */&lt;br /&gt;
        decoded_bits[s] = curr_state &amp;amp; 1;&lt;br /&gt;
&lt;br /&gt;
        /* Hämta beslutet (0 eller 1) som fattades för detta tillstånd i tidssteg s. */&lt;br /&gt;
        int decision = history[s][curr_state];&lt;br /&gt;
        int prev0 = curr_state &amp;gt;&amp;gt; 1;&lt;br /&gt;
&lt;br /&gt;
        /* Rekonstruera vilket tillstånd vi kom ifrån baserat på det sparade beslutet. */&lt;br /&gt;
        if (decision == 0) {&lt;br /&gt;
            curr_state = prev0;&lt;br /&gt;
        } else {&lt;br /&gt;
            curr_state = prev0 | (NUM_STATES &amp;gt;&amp;gt; 1);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // ------------------------------------------------------------------------&lt;br /&gt;
    // STEG 4: Återpacka till bytes och skriv ut&lt;br /&gt;
    // ------------------------------------------------------------------------&lt;br /&gt;
    /* Bitarna ligger nu i korrekt kronologisk ordning i decoded_bits-arrayen.&lt;br /&gt;
       Vi loopar igenom dem och packar ihop dem 8 och 8 till vanliga bytes igen. */&lt;br /&gt;
    uint8_t current_byte = 0;&lt;br /&gt;
    for (size_t i = 0; i &amp;lt; step; i++) {&lt;br /&gt;
        current_byte = (current_byte &amp;lt;&amp;lt; 1) | decoded_bits[i];&lt;br /&gt;
&lt;br /&gt;
        /* Varje gång vi har samlat ihop 8 bitar skriver vi ut byten till utfilen/stdout. */&lt;br /&gt;
        if ((i + 1) % 8 == 0) {&lt;br /&gt;
            fputc(current_byte, out);&lt;br /&gt;
            current_byte = 0;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    /* Frigör det dynamiskt allokerade minnet. */&lt;br /&gt;
    free(decoded_bits);&lt;br /&gt;
    free(history);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// ============================================================================&lt;br /&gt;
// INTERNT TEST (-t OCH --error)&lt;br /&gt;
// ============================================================================&lt;br /&gt;
void run_test(bool inject_errors) {&lt;br /&gt;
    if (inject_errors) {&lt;br /&gt;
        printf(&amp;quot;[*] Startar internt test med FELKORRIGERING (64 bytes slumpdata + 3 bitpar flippade)...\n&amp;quot;);&lt;br /&gt;
    } else {&lt;br /&gt;
        printf(&amp;quot;[*] Startar internt test (64 bytes randomiserat data)...\n&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    /* Skapa en array med 64 bytes slumpmässigt data. */&lt;br /&gt;
    uint8_t original_data[64];&lt;br /&gt;
    srand((unsigned int)time(NULL));&lt;br /&gt;
    for (int i = 0; i &amp;lt; 64; i++) {&lt;br /&gt;
        original_data[i] = rand() % 256;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    /* tmpfile() skapar temporära filer som körs i RAM/hårddisk och raderas automatiskt vid stängning. */&lt;br /&gt;
    FILE *orig_stream = tmpfile();&lt;br /&gt;
    FILE *encoded_stream = tmpfile();&lt;br /&gt;
    FILE *corrupted_stream = tmpfile();&lt;br /&gt;
    FILE *decoded_stream = tmpfile();&lt;br /&gt;
&lt;br /&gt;
    if (!orig_stream || !encoded_stream || !corrupted_stream || !decoded_stream) {&lt;br /&gt;
        fprintf(stderr, &amp;quot;Kunde inte skapa temporära filer.\n&amp;quot;);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    /* Skriv originaldata till startströmmen och spola tillbaka pekaren till början. */&lt;br /&gt;
    fwrite(original_data, 1, 64, orig_stream);&lt;br /&gt;
    rewind(orig_stream);&lt;br /&gt;
&lt;br /&gt;
    /* 1. Kör kodningen (64 bytes rådata blir exakt 128 bytes packad bitström). */&lt;br /&gt;
    encode(orig_stream, encoded_stream);&lt;br /&gt;
    rewind(encoded_stream);&lt;br /&gt;
&lt;br /&gt;
    /* 2. Hantering av felinjicering (--error). */&lt;br /&gt;
    if (inject_errors) {&lt;br /&gt;
        uint8_t encoded_data[128];&lt;br /&gt;
&lt;br /&gt;
        /* Läs in hela den kodade strömmen till en lokal array. */&lt;br /&gt;
        if (fread(encoded_data, 1, 128, encoded_stream) == 128) {&lt;br /&gt;
&lt;br /&gt;
            /* Välj ut 3 slumpmässiga bytes och flippa en slumpmässig bit i var och en av dem. */&lt;br /&gt;
            for (int i = 0; i &amp;lt; 3; i++) {&lt;br /&gt;
                int byte_index = rand() % 128;&lt;br /&gt;
                int bit_index = rand() % 8;&lt;br /&gt;
&lt;br /&gt;
                /* XOR-operatör (^) flippar den valda biten (0 blir 1, 1 blir 0). */&lt;br /&gt;
                encoded_data[byte_index] ^= (1 &amp;lt;&amp;lt; bit_index);&lt;br /&gt;
                printf(&amp;quot;[i] Introducerade bitfel i kodad byte %d, bit %d\n&amp;quot;, byte_index, bit_index);&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        /* Skriv ut det saboterade datat till den korrupta strömmen. */&lt;br /&gt;
        fwrite(encoded_data, 1, 128, corrupted_stream);&lt;br /&gt;
        rewind(corrupted_stream);&lt;br /&gt;
    } else {&lt;br /&gt;
        /* Om inga fel ska testas, pekar vi bara vidare till den felfria strömmen direkt. */&lt;br /&gt;
        corrupted_stream = encoded_stream;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    /* 3. Kör avkodaren på dataströmmen. */&lt;br /&gt;
    decode(corrupted_stream, decoded_stream);&lt;br /&gt;
    rewind(decoded_stream);&lt;br /&gt;
&lt;br /&gt;
    /* 4. Läs tillbaka det färdigavkodade datat och verifiera resultatet. */&lt;br /&gt;
    uint8_t final_data[64];&lt;br /&gt;
    size_t read_bytes = fread(final_data, 1, 64, decoded_stream);&lt;br /&gt;
&lt;br /&gt;
    bool success = true;&lt;br /&gt;
    if (read_bytes != 64) {&lt;br /&gt;
        printf(&amp;quot;[FAIL] Avkodade fel antal bytes: %zu (förväntade 64)\n&amp;quot;, read_bytes);&lt;br /&gt;
        success = false;&lt;br /&gt;
    } else {&lt;br /&gt;
        /* Jämför ursprunglig array med den avkodade arrayen byte för byte. */&lt;br /&gt;
        for (int i = 0; i &amp;lt; 64; i++) {&lt;br /&gt;
            if (original_data[i] != final_data[i]) {&lt;br /&gt;
                printf(&amp;quot;[FAIL] Diff vid byte %d: Org=0x%02X, Avkodad=0x%02X\n&amp;quot;, i, original_data[i], final_data[i]);&lt;br /&gt;
                success = false;&lt;br /&gt;
                break;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    /* Stäng alla strömmar ordentligt. */&lt;br /&gt;
    fclose(orig_stream);&lt;br /&gt;
    if (inject_errors) {&lt;br /&gt;
        fclose(encoded_stream);&lt;br /&gt;
        fclose(corrupted_stream);&lt;br /&gt;
    } else {&lt;br /&gt;
        fclose(encoded_stream);&lt;br /&gt;
    }&lt;br /&gt;
    fclose(decoded_stream);&lt;br /&gt;
&lt;br /&gt;
    /* Skriv ut slutrapport för testet. */&lt;br /&gt;
    if (success) {&lt;br /&gt;
        if (inject_errors) {&lt;br /&gt;
            printf(&amp;quot;[SUCCESS] Viterbi-algoritmens felkorrigering lyckades! Alla bitfel lagades och datat matchar perfekt.\n&amp;quot;);&lt;br /&gt;
        } else {&lt;br /&gt;
            printf(&amp;quot;[SUCCESS] Testet lyckades! Allt data matchar perfekt.\n&amp;quot;);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// ============================================================================&lt;br /&gt;
// HJÄLPTEXT OCH MAIN&lt;br /&gt;
// ============================================================================&lt;br /&gt;
void print_help(const char *prog_name) {&lt;br /&gt;
    printf(&amp;quot;Användning: %s [option]\n&amp;quot;, prog_name);&lt;br /&gt;
    printf(&amp;quot;Optioner:\n&amp;quot;);&lt;br /&gt;
    printf(&amp;quot;  -e &amp;lt;infil &amp;gt;utfil   Kodar infil till utfil (Rate 1/2, K=7)\n&amp;quot;);&lt;br /&gt;
    printf(&amp;quot;  -d &amp;lt;infil &amp;gt;utfil   Avkodar infil till utfil med Viterbi\n&amp;quot;);&lt;br /&gt;
    printf(&amp;quot;  -h                 Visar denna hjälptext\n&amp;quot;);&lt;br /&gt;
    printf(&amp;quot;  -t                 Kör internt test med 64 bytes slumpdata\n&amp;quot;);&lt;br /&gt;
    printf(&amp;quot;  --error            Kör internt test men injicerar bitfel för att testa felkorrigeringen\n&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
int main(int argc, char *argv[]) {&lt;br /&gt;
    /* Säkerställ att användaren har skickat med exakt ett kommandoradsargument. */&lt;br /&gt;
    if (argc != 2) {&lt;br /&gt;
        print_help(argv[0]);&lt;br /&gt;
        return EXIT_FAILURE;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    /* Kontrollera vilket argument användaren skickade och anropa rätt funktion. */&lt;br /&gt;
    if (strcmp(argv[1], &amp;quot;-e&amp;quot;) == 0) {&lt;br /&gt;
        encode(stdin, stdout);&lt;br /&gt;
    } else if (strcmp(argv[1], &amp;quot;-d&amp;quot;) == 0) {&lt;br /&gt;
        decode(stdin, stdout);&lt;br /&gt;
    } else if (strcmp(argv[1], &amp;quot;-h&amp;quot;) == 0) {&lt;br /&gt;
        print_help(argv[0]);&lt;br /&gt;
    } else if (strcmp(argv[1], &amp;quot;-t&amp;quot;) == 0) {&lt;br /&gt;
        run_test(false);&lt;br /&gt;
    } else if (strcmp(argv[1], &amp;quot;--error&amp;quot;) == 0) {&lt;br /&gt;
        run_test(true);&lt;br /&gt;
    } else {&lt;br /&gt;
        fprintf(stderr, &amp;quot;Fel: Okänd parameter &#039;%s&#039;\n&amp;quot;, argv[1]);&lt;br /&gt;
        print_help(argv[0]);&lt;br /&gt;
        return EXIT_FAILURE;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return EXIT_SUCCESS;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>Anders</name></author>
	</entry>
	<entry>
		<id>http://wiki.sikvall.se/index.php?title=Viterbi&amp;diff=1909</id>
		<title>Viterbi</title>
		<link rel="alternate" type="text/html" href="http://wiki.sikvall.se/index.php?title=Viterbi&amp;diff=1909"/>
		<updated>2026-06-23T17:47:20Z</updated>

		<summary type="html">&lt;p&gt;Anders: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Bakgrund = &lt;br /&gt;
&lt;br /&gt;
== Viterbis algoritm – Hur vi hittar rätt signal i bruset ==&lt;br /&gt;
&lt;br /&gt;
Inom amatörradion och digital signalbehandling stöter vi ofta på problemet med brus och fading. När vi skickar digital data över etern, till exempel med modernare digitala trafiksätt eller vid satellitkommunikation, använder vi ofta något som kallas för faltningskodning (convolutional coding). Det är en metod där varje sänd bit beror på både den nuvarande biten och ett antal tidigare bitar. Detta skapar ett mönster, ett beroende, som gör signalen robust.&lt;br /&gt;
&lt;br /&gt;
Men hur avkodar vi detta på mottagarsidan när atmosfären har ställt till det och lagt till en massa brus? Det är här Viterbis algoritm kommer in i bilden.&lt;br /&gt;
&lt;br /&gt;
Kort sagt är Viterbialgoritmen en metod för att hitta den mest troliga sekvensen av dolda tillstånd (det vi faktiskt sände) baserat på en serie observerade händelser (den brusiga signalen vi tog emot). Istället för att gissa bit för bit, tittar algoritmen på hela sammanhanget.&lt;br /&gt;
&lt;br /&gt;
== Trellis-diagrammet: Vägarna genom historien ==&lt;br /&gt;
&lt;br /&gt;
För att förstå hur algoritmen jobbar kan vi tänka oss ett nätverk av vägar, ett så kallat trellis-diagram.&lt;br /&gt;
&lt;br /&gt;
* Tillstånd (States): Radiosändarens &amp;quot;minne&amp;quot; kan vid varje given tidpunkt befinna sig i ett visst antal tillstånd (beroende på de senaste sända bitarna).&lt;br /&gt;
&lt;br /&gt;
* Övergångar: När en ny bit ska sändas hoppar sändaren till ett nytt tillstånd och skickar ut en specifik kombination av bitar i luften.&lt;br /&gt;
&lt;br /&gt;
== Hur funkar det? ==&lt;br /&gt;
&lt;br /&gt;
När mottagaren lyssnar får den in en sekvens som kanske är halvt dränkt i brus. En nolla kanske ser ut som en svag etta, och så vidare. Viterbialgoritmen börjar nu räkna på alla möjliga vägar genom detta nätverk av tillstånd över tid.&lt;br /&gt;
Så här jobbar algoritmen steg för steg:&lt;br /&gt;
&lt;br /&gt;
# Beräkna avstånd (Metric): För varje steg i tiden tittar algoritmen på de bitar som faktiskt togs emot och jämför dem med vad som borde ha sänts för varje tänkbar väg i diagrammet. Man mäter &amp;quot;avståndet&amp;quot; (ofta Hamming-avstånd för ettor och nollor, eller Euklidiskt avstånd om man kör &amp;quot;soft decision&amp;quot; där man mäter signalstyrkan mer exakt). Ju mindre avstånd, desto mer troligt är det att den vägen är den rätta.&lt;br /&gt;
&lt;br /&gt;
# Spara den bästa vägen (Add-Compare-Select): Till varje nytt tillstånd i diagrammet leder det oftast två olika vägar från det föregående steget. Algoritmen adderar det nya avståndet till det gamla, jämför de två alternativen, och väljer den väg som har lägst totalt avstånd (fel). Den andra vägen slängs bort för alltid. Det här är algoritmens stora styrka: den rensar hela tiden bort återvändsgränder så att beräkningsbördan inte exploderar.&lt;br /&gt;
&lt;br /&gt;
# Lås historiken (Traceback): När hela sekvensen (eller ett tillräckligt långt block) har tagits emot, tittar man på vilket slutgiltigt tillstånd som har det absolut lägsta totala felvärdet. Sedan backar man bakåt genom de sparade &amp;quot;bästa vägarna&amp;quot; till början.&lt;br /&gt;
&lt;br /&gt;
Resultatet blir den absolut mest sannolika sekvensen av bitar som sändaren faktiskt skickade ut, trots att det var fullt av bitfel under resans gång.&lt;br /&gt;
&lt;br /&gt;
= Implementation =&lt;br /&gt;
&lt;br /&gt;
== Modern C ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
 * Anders Sikvall 2026 Version 1.0&lt;br /&gt;
 * &amp;lt;anders@sikvall.se&amp;gt;&lt;br /&gt;
 * &lt;br /&gt;
 * Implementation i C av en standard Viterbi-algoritm som används bl.a. av &lt;br /&gt;
 * Qualcomm och NASA och är välpublicerad.&lt;br /&gt;
 *&lt;br /&gt;
 * PUBLIC DOMAIN FOR EDUCATIONAL PURPOSES&lt;br /&gt;
 *&lt;br /&gt;
 * Kompilera med gcc -o viterbi viterbi.c&lt;br /&gt;
 *&lt;br /&gt;
 * ANVÄNDNING&lt;br /&gt;
 *         viterbi -e &amp;lt;indatastream &amp;gt;utdatastream   Kodar &amp;lt;indatastream till &amp;gt;utdatastream&lt;br /&gt;
 *         viterbi -d &amp;lt;indatastream &amp;gt;utdatastream   Avkodar &amp;lt;indatastream till &amp;gt;utdatastream&lt;br /&gt;
 *         viterbi -t                               Utför en intern test på 64 randomiserade oktetter&lt;br /&gt;
 *         viterbi -h                               Visar en kort hjälptext&lt;br /&gt;
 *         viterbi --error                          Samma sak som -t men introducerar 3 flippade bitpar&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
#include &amp;lt;string.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdbool.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdint.h&amp;gt;&lt;br /&gt;
#include &amp;lt;time.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
/* Constraint length (K=7) innebär att skiftregistret minns de senaste 7 bitarna. */&lt;br /&gt;
#define K 7&lt;br /&gt;
&lt;br /&gt;
/* Antalet tillstånd i trellis-diagrammet bestäms av de senaste K-1 bitarna.&lt;br /&gt;
   2^(7-1) = 2^6 = 64 unika tillstånd totalt. */&lt;br /&gt;
#define NUM_STATES (1 &amp;lt;&amp;lt; (K - 1))&lt;br /&gt;
&lt;br /&gt;
/* Standard NASA/Qualcomm-polynom för Rate 1/2 konvolutionskodning.&lt;br /&gt;
   POLY_G0 motsvarar oktalt 151 (1001111 binärt).&lt;br /&gt;
   POLY_G1 motsvarar oktalt 113 (1101101 binärt).&lt;br /&gt;
   Dessa maskar används för att bestämma vilka bitar i tillståndet som XOR-sammanfogas. */&lt;br /&gt;
const uint8_t POLY_G0 = 0x4F;&lt;br /&gt;
const uint8_t POLY_G1 = 0x6D;&lt;br /&gt;
&lt;br /&gt;
/* Hårdvaruoptimerad paritetsberäkning.&lt;br /&gt;
   Räknar antalet satta bitar (1:or) i ett tal och returnerar 1 om antalet är udda,&lt;br /&gt;
   eller 0 om antalet är jämnt (motsvarar en kedja av XOR-grindar). */&lt;br /&gt;
static inline uint8_t parity(uint8_t x) {&lt;br /&gt;
    return __builtin_parity(x) &amp;amp; 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// ============================================================================&lt;br /&gt;
// KODARE (-e)&lt;br /&gt;
// ============================================================================&lt;br /&gt;
void encode(FILE *in, FILE *out) {&lt;br /&gt;
    /* encoder_state lagrar historiken av de senaste K-1 (6) bitarna. */&lt;br /&gt;
    uint8_t encoder_state = 0;&lt;br /&gt;
&lt;br /&gt;
    /* out_byte används som en tillfällig buffer för att samla ihop bitar till en hel byte. */&lt;br /&gt;
    uint8_t out_byte = 0;&lt;br /&gt;
&lt;br /&gt;
    /* bit_count håller koll på hur många bitar som för tillfället ligger i utmatningsbufferten. */&lt;br /&gt;
    int bit_count = 0;&lt;br /&gt;
    int ch;&lt;br /&gt;
&lt;br /&gt;
    /* Loopa igenom infilen tecken för tecken (byte för byte). */&lt;br /&gt;
    while ((ch = fgetc(in)) != EOF) {&lt;br /&gt;
&lt;br /&gt;
        /* Gå igenom varje enskild bit i den inlästa byten, från MSB (bit 7) till LSB (bit 0). */&lt;br /&gt;
        for (int i = 7; i &amp;gt;= 0; i--) {&lt;br /&gt;
&lt;br /&gt;
            /* Isolera biten på position i. */&lt;br /&gt;
            uint8_t bit = (ch &amp;gt;&amp;gt; i) &amp;amp; 1;&lt;br /&gt;
&lt;br /&gt;
            /* Skapa det nuvarande ordet genom att skifta upp det gamla tillståndet till vänster&lt;br /&gt;
               och lägga till den nya inkommande biten som den lägsta biten (LSB). */&lt;br /&gt;
            uint8_t current_word = (encoder_state &amp;lt;&amp;lt; 1) | bit;&lt;br /&gt;
&lt;br /&gt;
            /* Beräkna de två paritetsbitarna (out0 och out1) genom att applicera polynommaskerna&lt;br /&gt;
               och köra XOR (paritet) på resultatet. */&lt;br /&gt;
            uint8_t out0 = parity(current_word &amp;amp; POLY_G0);&lt;br /&gt;
            uint8_t out1 = parity(current_word &amp;amp; POLY_G1);&lt;br /&gt;
&lt;br /&gt;
            /* Knuffa in den första paritetsbiten (out0) i utmatningsbyten. */&lt;br /&gt;
            out_byte = (out_byte &amp;lt;&amp;lt; 1) | out0;&lt;br /&gt;
            bit_count++;&lt;br /&gt;
&lt;br /&gt;
            /* Om vi har fyllt en hel byte (8 bitar), skriv ut den till utmatningsströmmen. */&lt;br /&gt;
            if (bit_count == 8) {&lt;br /&gt;
                fputc(out_byte, out);&lt;br /&gt;
                out_byte = 0;&lt;br /&gt;
                bit_count = 0;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            /* Knuffa in den andra paritetsbiten (out1) i utmatningsbyten. */&lt;br /&gt;
            out_byte = (out_byte &amp;lt;&amp;lt; 1) | out1;&lt;br /&gt;
            bit_count++;&lt;br /&gt;
&lt;br /&gt;
            /* Kontrollera återigen om utmatningsbyten blev full efter den andra biten. */&lt;br /&gt;
            if (bit_count == 8) {&lt;br /&gt;
                fputc(out_byte, out);&lt;br /&gt;
                out_byte = 0;&lt;br /&gt;
                bit_count = 0;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            /* Uppdatera kodarens interna tillstånd inför nästa bit.&lt;br /&gt;
               Vi sparar endast de lägsta K-1 bitarna med hjälp av en bitmask (63 = 0x3F). */&lt;br /&gt;
            encoder_state = current_word &amp;amp; (NUM_STATES - 1);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    /* Om det finns kvarvarande bitar i bufferten när filen slutar,&lt;br /&gt;
       skiftar vi dem till vänster så att de ligger rätt, och skriver ut den sista ofullständiga byten. */&lt;br /&gt;
    if (bit_count &amp;gt; 0) {&lt;br /&gt;
        out_byte &amp;lt;&amp;lt;= (8 - bit_count);&lt;br /&gt;
        fputc(out_byte, out);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// ============================================================================&lt;br /&gt;
// AVKODARE (-d)&lt;br /&gt;
// ============================================================================&lt;br /&gt;
void decode(FILE *in, FILE *out) {&lt;br /&gt;
    /* Startkapacitet för historikmatrisen (antalet bit-steg). Den växer linjärt vid behov. */&lt;br /&gt;
    size_t history_capacity = 1024;&lt;br /&gt;
    size_t step = 0;&lt;br /&gt;
&lt;br /&gt;
    /* Allokera historikmatrisen dynamiskt. Det är en 2D-array av storleken [kapacitet][64].&lt;br /&gt;
       Den sparar överlevnadsbesluten (0 eller 1) för varje tillstånd vid varje givet tidssteg. */&lt;br /&gt;
    uint8_t (*history)[NUM_STATES] = malloc(history_capacity * sizeof(*history));&lt;br /&gt;
    if (!history) {&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    /* path_metrics lagrar den ackumulerade felkostnaden (Hammingavståndet) för de 64 nuvarande tillstånden. */&lt;br /&gt;
    uint32_t path_metrics[NUM_STATES];&lt;br /&gt;
&lt;br /&gt;
    /* old_metrics lagrar en oförändrad kopia av kostnaderna från föregående tidssteg. */&lt;br /&gt;
    uint32_t old_metrics[NUM_STATES];&lt;br /&gt;
&lt;br /&gt;
    /* Initiera alla tillstånd till en mycket hög felkostnad (&amp;quot;oändlighet&amp;quot;).&lt;br /&gt;
       Undantaget är tillstånd 0, vilket är det kända och garanterade starttillståndet (kostnad 0). */&lt;br /&gt;
    for (int i = 1; i &amp;lt; NUM_STATES; i++) {&lt;br /&gt;
        path_metrics[i] = 1e6;&lt;br /&gt;
    }&lt;br /&gt;
    path_metrics[0] = 0;&lt;br /&gt;
&lt;br /&gt;
    int ch;&lt;br /&gt;
&lt;br /&gt;
    // ------------------------------------------------------------------------&lt;br /&gt;
    // STEG 1: Framåtpass (Forward Pass / Add-Compare-Select)&lt;br /&gt;
    // ------------------------------------------------------------------------&lt;br /&gt;
    /* Läs den kodade strömmen byte för byte. */&lt;br /&gt;
    while ((ch = fgetc(in)) != EOF) {&lt;br /&gt;
&lt;br /&gt;
        /* Varje inläst byte innehåller 4 bitpar (totalt 8 kodade bitar), vilket motsvarar 4 tidssteg. */&lt;br /&gt;
        for (int bit_pair = 3; bit_pair &amp;gt;= 0; bit_pair--) {&lt;br /&gt;
&lt;br /&gt;
            /* Extrahera de två bitarna (b0 och b1) som hör till det aktuella steget. */&lt;br /&gt;
            uint8_t b0 = (ch &amp;gt;&amp;gt; (bit_pair * 2 + 1)) &amp;amp; 1;&lt;br /&gt;
            uint8_t b1 = (ch &amp;gt;&amp;gt; (bit_pair * 2)) &amp;amp; 1;&lt;br /&gt;
&lt;br /&gt;
            /* Om vår historikmatris är full, fördubblar vi dess storlek dynamiskt med realloc.&lt;br /&gt;
               Detta gör att programmet kan hantera obegränsat stora filer och pipes. */&lt;br /&gt;
            if (step &amp;gt;= history_capacity) {&lt;br /&gt;
                history_capacity *= 2;&lt;br /&gt;
                uint8_t (*new_history)[NUM_STATES] = realloc(history, history_capacity * sizeof(*history));&lt;br /&gt;
                if (!new_history) {&lt;br /&gt;
                    free(history);&lt;br /&gt;
                    return;&lt;br /&gt;
                }&lt;br /&gt;
                history = new_history;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            /* Kopiera över nuvarande path_metrics till old_metrics inför beräkningen av nästa steg. */&lt;br /&gt;
            memcpy(old_metrics, path_metrics, sizeof(path_metrics));&lt;br /&gt;
&lt;br /&gt;
            /* Loopa igenom alla 64 möjliga måltillstånd (nästa tillstånd) i trellis-diagrammet. */&lt;br /&gt;
            for (int state = 0; state &amp;lt; NUM_STATES; state++) {&lt;br /&gt;
&lt;br /&gt;
                /* Eftersom vi skiftar till vänster, kan vi räkna ut vilka två föregående tillstånd&lt;br /&gt;
                   (prev0 och prev1) som kan ha skiftat in i det nuvarande tillståndet. */&lt;br /&gt;
                int prev0 = state &amp;gt;&amp;gt; 1;&lt;br /&gt;
                int prev1 = prev0 | (NUM_STATES &amp;gt;&amp;gt; 1);&lt;br /&gt;
&lt;br /&gt;
                /* Den inbit som krävdes för att nå &#039;state&#039; är identisk med nuvarande tillstånds LSB. */&lt;br /&gt;
                uint8_t input_bit = state &amp;amp; 1;&lt;br /&gt;
&lt;br /&gt;
                /* --- Beräkna förväntade bitar och Hammingavstånd för VÄG 0 (från prev0) --- */&lt;br /&gt;
                uint8_t word0 = (prev0 &amp;lt;&amp;lt; 1) | input_bit;&lt;br /&gt;
                uint8_t exp0_0 = parity(word0 &amp;amp; POLY_G0);&lt;br /&gt;
                uint8_t exp0_1 = parity(word0 &amp;amp; POLY_G1);&lt;br /&gt;
                /* Kostnaden ökar med 1 för varje bit som inte matchar de faktiskt mottagna bitarna. */&lt;br /&gt;
                uint32_t cost0 = (exp0_0 != b0) + (exp0_1 != b1);&lt;br /&gt;
&lt;br /&gt;
                /* --- Beräkna förväntade bitar och Hammingavstånd för VÄG 1 (från prev1) --- */&lt;br /&gt;
                uint8_t word1 = (prev1 &amp;lt;&amp;lt; 1) | input_bit;&lt;br /&gt;
                uint8_t exp1_0 = parity(word1 &amp;amp; POLY_G0);&lt;br /&gt;
                uint8_t exp1_1 = parity(word1 &amp;amp; POLY_G1);&lt;br /&gt;
                uint32_t cost1 = (exp1_0 != b0) + (exp1_1 != b1);&lt;br /&gt;
&lt;br /&gt;
                /* Addera det gamla ackumulerade felet med det nya övergångsfelet för båda vägarna. */&lt;br /&gt;
                uint32_t m0 = old_metrics[prev0] + cost0;&lt;br /&gt;
                uint32_t m1 = old_metrics[prev1] + cost1;&lt;br /&gt;
&lt;br /&gt;
                /* (Compare &amp;amp; Select): Välj den väg som har lägst totalt fel.&lt;br /&gt;
                   Spara det nya lägsta felet i path_metrics, och dokumentera valet (0 eller 1)&lt;br /&gt;
                   i historikmatrisen för att kunna återskapa vägen baklänges senare. */&lt;br /&gt;
                if (m0 &amp;lt;= m1) {&lt;br /&gt;
                    path_metrics[state] = m0;&lt;br /&gt;
                    history[step][state] = 0;&lt;br /&gt;
                } else {&lt;br /&gt;
                    path_metrics[state] = m1;&lt;br /&gt;
                    history[step][state] = 1;&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
            /* Öka räknaren för antal avklarade bit-steg. */&lt;br /&gt;
            step++;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    /* Om vi inte lyckades läsa några bitar alls, städa upp och avsluta. */&lt;br /&gt;
    if (step == 0) {&lt;br /&gt;
        free(history);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // ------------------------------------------------------------------------&lt;br /&gt;
    // STEG 2: Hitta bästa sluttillstånd&lt;br /&gt;
    // ------------------------------------------------------------------------&lt;br /&gt;
    /* Sök igenom alla 64 tillstånd vid slutet av strömmen för att hitta det tillstånd&lt;br /&gt;
       som har samlat på sig minst antal fel (lägst metric). */&lt;br /&gt;
    int curr_state = 0;&lt;br /&gt;
    uint32_t min_m = path_metrics[0];&lt;br /&gt;
    for (int i = 1; i &amp;lt; NUM_STATES; i++) {&lt;br /&gt;
        if (path_metrics[i] &amp;lt; min_m) {&lt;br /&gt;
            min_m = path_metrics[i];&lt;br /&gt;
            curr_state = i;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // ------------------------------------------------------------------------&lt;br /&gt;
    // STEG 3: Bakåtspårning (Traceback)&lt;br /&gt;
    // ------------------------------------------------------------------------&lt;br /&gt;
    /* Allokera en temporär array för att spara de avkodade bitarna.&lt;br /&gt;
       Eftersom vi vandrar baklänges kommer vi att fylla denna array bakifrån. */&lt;br /&gt;
    uint8_t *decoded_bits = malloc(step);&lt;br /&gt;
    if (!decoded_bits) {&lt;br /&gt;
        free(history);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    /* Vandra baklänges genom historiken från det sista tidssteget ner till noll. */&lt;br /&gt;
    for (int s = (int)step - 1; s &amp;gt;= 0; s--) {&lt;br /&gt;
&lt;br /&gt;
        /* Den ursprungliga inbiten är alltid LSB (bit 0) i det tillstånd vi står i. */&lt;br /&gt;
        decoded_bits[s] = curr_state &amp;amp; 1;&lt;br /&gt;
&lt;br /&gt;
        /* Hämta beslutet (0 eller 1) som fattades för detta tillstånd i tidssteg s. */&lt;br /&gt;
        int decision = history[s][curr_state];&lt;br /&gt;
        int prev0 = curr_state &amp;gt;&amp;gt; 1;&lt;br /&gt;
&lt;br /&gt;
        /* Rekonstruera vilket tillstånd vi kom ifrån baserat på det sparade beslutet. */&lt;br /&gt;
        if (decision == 0) {&lt;br /&gt;
            curr_state = prev0;&lt;br /&gt;
        } else {&lt;br /&gt;
            curr_state = prev0 | (NUM_STATES &amp;gt;&amp;gt; 1);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // ------------------------------------------------------------------------&lt;br /&gt;
    // STEG 4: Återpacka till bytes och skriv ut&lt;br /&gt;
    // ------------------------------------------------------------------------&lt;br /&gt;
    /* Bitarna ligger nu i korrekt kronologisk ordning i decoded_bits-arrayen.&lt;br /&gt;
       Vi loopar igenom dem och packar ihop dem 8 och 8 till vanliga bytes igen. */&lt;br /&gt;
    uint8_t current_byte = 0;&lt;br /&gt;
    for (size_t i = 0; i &amp;lt; step; i++) {&lt;br /&gt;
        current_byte = (current_byte &amp;lt;&amp;lt; 1) | decoded_bits[i];&lt;br /&gt;
&lt;br /&gt;
        /* Varje gång vi har samlat ihop 8 bitar skriver vi ut byten till utfilen/stdout. */&lt;br /&gt;
        if ((i + 1) % 8 == 0) {&lt;br /&gt;
            fputc(current_byte, out);&lt;br /&gt;
            current_byte = 0;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    /* Frigör det dynamiskt allokerade minnet. */&lt;br /&gt;
    free(decoded_bits);&lt;br /&gt;
    free(history);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// ============================================================================&lt;br /&gt;
// INTERNT TEST (-t OCH --error)&lt;br /&gt;
// ============================================================================&lt;br /&gt;
void run_test(bool inject_errors) {&lt;br /&gt;
    if (inject_errors) {&lt;br /&gt;
        printf(&amp;quot;[*] Startar internt test med FELKORRIGERING (64 bytes slumpdata + 3 bitpar flippade)...\n&amp;quot;);&lt;br /&gt;
    } else {&lt;br /&gt;
        printf(&amp;quot;[*] Startar internt test (64 bytes randomiserat data)...\n&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    /* Skapa en array med 64 bytes slumpmässigt data. */&lt;br /&gt;
    uint8_t original_data[64];&lt;br /&gt;
    srand((unsigned int)time(NULL));&lt;br /&gt;
    for (int i = 0; i &amp;lt; 64; i++) {&lt;br /&gt;
        original_data[i] = rand() % 256;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    /* tmpfile() skapar temporära filer som körs i RAM/hårddisk och raderas automatiskt vid stängning. */&lt;br /&gt;
    FILE *orig_stream = tmpfile();&lt;br /&gt;
    FILE *encoded_stream = tmpfile();&lt;br /&gt;
    FILE *corrupted_stream = tmpfile();&lt;br /&gt;
    FILE *decoded_stream = tmpfile();&lt;br /&gt;
&lt;br /&gt;
    if (!orig_stream || !encoded_stream || !corrupted_stream || !decoded_stream) {&lt;br /&gt;
        fprintf(stderr, &amp;quot;Kunde inte skapa temporära filer.\n&amp;quot;);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    /* Skriv originaldata till startströmmen och spola tillbaka pekaren till början. */&lt;br /&gt;
    fwrite(original_data, 1, 64, orig_stream);&lt;br /&gt;
    rewind(orig_stream);&lt;br /&gt;
&lt;br /&gt;
    /* 1. Kör kodningen (64 bytes rådata blir exakt 128 bytes packad bitström). */&lt;br /&gt;
    encode(orig_stream, encoded_stream);&lt;br /&gt;
    rewind(encoded_stream);&lt;br /&gt;
&lt;br /&gt;
    /* 2. Hantering av felinjicering (--error). */&lt;br /&gt;
    if (inject_errors) {&lt;br /&gt;
        uint8_t encoded_data[128];&lt;br /&gt;
&lt;br /&gt;
        /* Läs in hela den kodade strömmen till en lokal array. */&lt;br /&gt;
        if (fread(encoded_data, 1, 128, encoded_stream) == 128) {&lt;br /&gt;
&lt;br /&gt;
            /* Välj ut 3 slumpmässiga bytes och flippa en slumpmässig bit i var och en av dem. */&lt;br /&gt;
            for (int i = 0; i &amp;lt; 3; i++) {&lt;br /&gt;
                int byte_index = rand() % 128;&lt;br /&gt;
                int bit_index = rand() % 8;&lt;br /&gt;
&lt;br /&gt;
                /* XOR-operatör (^) flippar den valda biten (0 blir 1, 1 blir 0). */&lt;br /&gt;
                encoded_data[byte_index] ^= (1 &amp;lt;&amp;lt; bit_index);&lt;br /&gt;
                printf(&amp;quot;[i] Introducerade bitfel i kodad byte %d, bit %d\n&amp;quot;, byte_index, bit_index);&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        /* Skriv ut det saboterade datat till den korrupta strömmen. */&lt;br /&gt;
        fwrite(encoded_data, 1, 128, corrupted_stream);&lt;br /&gt;
        rewind(corrupted_stream);&lt;br /&gt;
    } else {&lt;br /&gt;
        /* Om inga fel ska testas, pekar vi bara vidare till den felfria strömmen direkt. */&lt;br /&gt;
        corrupted_stream = encoded_stream;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    /* 3. Kör avkodaren på dataströmmen. */&lt;br /&gt;
    decode(corrupted_stream, decoded_stream);&lt;br /&gt;
    rewind(decoded_stream);&lt;br /&gt;
&lt;br /&gt;
    /* 4. Läs tillbaka det färdigavkodade datat och verifiera resultatet. */&lt;br /&gt;
    uint8_t final_data[64];&lt;br /&gt;
    size_t read_bytes = fread(final_data, 1, 64, decoded_stream);&lt;br /&gt;
&lt;br /&gt;
    bool success = true;&lt;br /&gt;
    if (read_bytes != 64) {&lt;br /&gt;
        printf(&amp;quot;[FAIL] Avkodade fel antal bytes: %zu (förväntade 64)\n&amp;quot;, read_bytes);&lt;br /&gt;
        success = false;&lt;br /&gt;
    } else {&lt;br /&gt;
        /* Jämför ursprunglig array med den avkodade arrayen byte för byte. */&lt;br /&gt;
        for (int i = 0; i &amp;lt; 64; i++) {&lt;br /&gt;
            if (original_data[i] != final_data[i]) {&lt;br /&gt;
                printf(&amp;quot;[FAIL] Diff vid byte %d: Org=0x%02X, Avkodad=0x%02X\n&amp;quot;, i, original_data[i], final_data[i]);&lt;br /&gt;
                success = false;&lt;br /&gt;
                break;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    /* Stäng alla strömmar ordentligt. */&lt;br /&gt;
    fclose(orig_stream);&lt;br /&gt;
    if (inject_errors) {&lt;br /&gt;
        fclose(encoded_stream);&lt;br /&gt;
        fclose(corrupted_stream);&lt;br /&gt;
    } else {&lt;br /&gt;
        fclose(encoded_stream);&lt;br /&gt;
    }&lt;br /&gt;
    fclose(decoded_stream);&lt;br /&gt;
&lt;br /&gt;
    /* Skriv ut slutrapport för testet. */&lt;br /&gt;
    if (success) {&lt;br /&gt;
        if (inject_errors) {&lt;br /&gt;
            printf(&amp;quot;[SUCCESS] Viterbi-algoritmens felkorrigering lyckades! Alla bitfel lagades och datat matchar perfekt.\n&amp;quot;);&lt;br /&gt;
        } else {&lt;br /&gt;
            printf(&amp;quot;[SUCCESS] Testet lyckades! Allt data matchar perfekt.\n&amp;quot;);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// ============================================================================&lt;br /&gt;
// HJÄLPTEXT OCH MAIN&lt;br /&gt;
// ============================================================================&lt;br /&gt;
void print_help(const char *prog_name) {&lt;br /&gt;
    printf(&amp;quot;Användning: %s [option]\n&amp;quot;, prog_name);&lt;br /&gt;
    printf(&amp;quot;Optioner:\n&amp;quot;);&lt;br /&gt;
    printf(&amp;quot;  -e &amp;lt;infil &amp;gt;utfil   Kodar infil till utfil (Rate 1/2, K=7)\n&amp;quot;);&lt;br /&gt;
    printf(&amp;quot;  -d &amp;lt;infil &amp;gt;utfil   Avkodar infil till utfil med Viterbi\n&amp;quot;);&lt;br /&gt;
    printf(&amp;quot;  -h                 Visar denna hjälptext\n&amp;quot;);&lt;br /&gt;
    printf(&amp;quot;  -t                 Kör internt test med 64 bytes slumpdata\n&amp;quot;);&lt;br /&gt;
    printf(&amp;quot;  --error            Kör internt test men injicerar bitfel för att testa felkorrigeringen\n&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
int main(int argc, char *argv[]) {&lt;br /&gt;
    /* Säkerställ att användaren har skickat med exakt ett kommandoradsargument. */&lt;br /&gt;
    if (argc != 2) {&lt;br /&gt;
        print_help(argv[0]);&lt;br /&gt;
        return EXIT_FAILURE;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    /* Kontrollera vilket argument användaren skickade och anropa rätt funktion. */&lt;br /&gt;
    if (strcmp(argv[1], &amp;quot;-e&amp;quot;) == 0) {&lt;br /&gt;
        encode(stdin, stdout);&lt;br /&gt;
    } else if (strcmp(argv[1], &amp;quot;-d&amp;quot;) == 0) {&lt;br /&gt;
        decode(stdin, stdout);&lt;br /&gt;
    } else if (strcmp(argv[1], &amp;quot;-h&amp;quot;) == 0) {&lt;br /&gt;
        print_help(argv[0]);&lt;br /&gt;
    } else if (strcmp(argv[1], &amp;quot;-t&amp;quot;) == 0) {&lt;br /&gt;
        run_test(false);&lt;br /&gt;
    } else if (strcmp(argv[1], &amp;quot;--error&amp;quot;) == 0) {&lt;br /&gt;
        run_test(true);&lt;br /&gt;
    } else {&lt;br /&gt;
        fprintf(stderr, &amp;quot;Fel: Okänd parameter &#039;%s&#039;\n&amp;quot;, argv[1]);&lt;br /&gt;
        print_help(argv[0]);&lt;br /&gt;
        return EXIT_FAILURE;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return EXIT_SUCCESS;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>Anders</name></author>
	</entry>
	<entry>
		<id>http://wiki.sikvall.se/index.php?title=Viterbi&amp;diff=1908</id>
		<title>Viterbi</title>
		<link rel="alternate" type="text/html" href="http://wiki.sikvall.se/index.php?title=Viterbi&amp;diff=1908"/>
		<updated>2026-06-23T17:41:16Z</updated>

		<summary type="html">&lt;p&gt;Anders: /* Bakgrund */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Bakgrund = &lt;br /&gt;
&lt;br /&gt;
== Viterbis algoritm – Hur vi hittar rätt signal i bruset ==&lt;br /&gt;
&lt;br /&gt;
Inom amatörradion och digital signalbehandling stöter vi ofta på problemet med brus och fading. När vi skickar digital data över etern, till exempel med modernare digitala trafiksätt eller vid satellitkommunikation, använder vi ofta något som kallas för faltningskodning (convolutional coding). Det är en metod där varje sänd bit beror på både den nuvarande biten och ett antal tidigare bitar. Detta skapar ett mönster, ett beroende, som gör signalen robust.&lt;br /&gt;
&lt;br /&gt;
Men hur avkodar vi detta på mottagarsidan när atmosfären har ställt till det och lagt till en massa brus? Det är här Viterbis algoritm kommer in i bilden.&lt;br /&gt;
&lt;br /&gt;
Kort sagt är Viterbialgoritmen en metod för att hitta den mest troliga sekvensen av dolda tillstånd (det vi faktiskt sände) baserat på en serie observerade händelser (den brusiga signalen vi tog emot). Istället för att gissa bit för bit, tittar algoritmen på hela sammanhanget.&lt;br /&gt;
&lt;br /&gt;
== Trellis-diagrammet: Vägarna genom historien ==&lt;br /&gt;
&lt;br /&gt;
För att förstå hur algoritmen jobbar kan vi tänka oss ett nätverk av vägar, ett så kallat trellis-diagram.&lt;br /&gt;
&lt;br /&gt;
* Tillstånd (States): Radiosändarens &amp;quot;minne&amp;quot; kan vid varje given tidpunkt befinna sig i ett visst antal tillstånd (beroende på de senaste sända bitarna).&lt;br /&gt;
&lt;br /&gt;
* Övergångar: När en ny bit ska sändas hoppar sändaren till ett nytt tillstånd och skickar ut en specifik kombination av bitar i luften.&lt;br /&gt;
&lt;br /&gt;
== Hur funkar det? ==&lt;br /&gt;
&lt;br /&gt;
När mottagaren lyssnar får den in en sekvens som kanske är halvt dränkt i brus. En nolla kanske ser ut som en svag etta, och så vidare. Viterbialgoritmen börjar nu räkna på alla möjliga vägar genom detta nätverk av tillstånd över tid.&lt;br /&gt;
Så här jobbar algoritmen steg för steg:&lt;br /&gt;
&lt;br /&gt;
# Beräkna avstånd (Metric): För varje steg i tiden tittar algoritmen på de bitar som faktiskt togs emot och jämför dem med vad som borde ha sänts för varje tänkbar väg i diagrammet. Man mäter &amp;quot;avståndet&amp;quot; (ofta Hamming-avstånd för ettor och nollor, eller Euklidiskt avstånd om man kör &amp;quot;soft decision&amp;quot; där man mäter signalstyrkan mer exakt). Ju mindre avstånd, desto mer troligt är det att den vägen är den rätta.&lt;br /&gt;
&lt;br /&gt;
# Spara den bästa vägen (Add-Compare-Select): Till varje nytt tillstånd i diagrammet leder det oftast två olika vägar från det föregående steget. Algoritmen adderar det nya avståndet till det gamla, jämför de två alternativen, och väljer den väg som har lägst totalt avstånd (fel). Den andra vägen slängs bort för alltid. Det här är algoritmens stora styrka: den rensar hela tiden bort återvändsgränder så att beräkningsbördan inte exploderar.&lt;br /&gt;
&lt;br /&gt;
# Lås historiken (Traceback): När hela sekvensen (eller ett tillräckligt långt block) har tagits emot, tittar man på vilket slutgiltigt tillstånd som har det absolut lägsta totala felvärdet. Sedan backar man bakåt genom de sparade &amp;quot;bästa vägarna&amp;quot; till början.&lt;br /&gt;
&lt;br /&gt;
Resultatet blir den absolut mest sannolika sekvensen av bitar som sändaren faktiskt skickade ut, trots att det var fullt av bitfel under resans gång.&lt;br /&gt;
&lt;br /&gt;
= Implementation =&lt;br /&gt;
&lt;br /&gt;
== Modern C ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
 * Anders Sikvall 2026 Version 1.0&lt;br /&gt;
 * &amp;lt;anders@sikvall.se&amp;gt;&lt;br /&gt;
 * &lt;br /&gt;
 * Implementation i C av en standard Viterbi-algoritm som används bl.a. av &lt;br /&gt;
 * Qualcomm och NASA och är välpublicerad.&lt;br /&gt;
 *&lt;br /&gt;
 * PUBLIC DOMAIN FOR EDUCATIONAL PURPOSES&lt;br /&gt;
 *&lt;br /&gt;
 * Kompilera med gcc -o viterbi viterbi.c&lt;br /&gt;
 *&lt;br /&gt;
 * ANVÄNDNING&lt;br /&gt;
 *         viterbi -e &amp;lt;indatastream &amp;gt;utdatastream   Kodar &amp;lt;indatastream till &amp;gt;utdatastream&lt;br /&gt;
 *         viterbi -d &amp;lt;indatastream &amp;gt;utdatastream   Avkodar &amp;lt;indatastream till &amp;gt;utdatastream&lt;br /&gt;
 *         viterbi -t                               Utför en intern test på 64 randomiserade oktetter&lt;br /&gt;
 *         viterbi -h                               Visar en kort hjälptext&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
#include &amp;lt;string.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdbool.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdint.h&amp;gt;&lt;br /&gt;
#include &amp;lt;time.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#define K 7&lt;br /&gt;
#define NUM_STATES (1 &amp;lt;&amp;lt; (K - 1))&lt;br /&gt;
&lt;br /&gt;
// Standard NASA/Qualcomm-polynom (Rate 1/2, K=7)&lt;br /&gt;
const uint8_t POLY_G0 = 0x4F; // 1001111 i binärt&lt;br /&gt;
const uint8_t POLY_G1 = 0x6D; // 1101101 i binärt&lt;br /&gt;
&lt;br /&gt;
// Hårdvaruoptimerad paritetsberäkning&lt;br /&gt;
static inline uint8_t parity(uint8_t x) {&lt;br /&gt;
    return __builtin_parity(x) &amp;amp; 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// ============================================================================&lt;br /&gt;
// KODARE (-e)&lt;br /&gt;
// ============================================================================&lt;br /&gt;
void encode(FILE *in, FILE *out) {&lt;br /&gt;
    uint8_t encoder_state = 0;&lt;br /&gt;
    uint8_t out_byte = 0;&lt;br /&gt;
    int bit_count = 0;&lt;br /&gt;
    int ch;&lt;br /&gt;
&lt;br /&gt;
    while ((ch = fgetc(in)) != EOF) {&lt;br /&gt;
        // Processa varje bit från MSB till LSB&lt;br /&gt;
        for (int i = 7; i &amp;gt;= 0; i--) {&lt;br /&gt;
            uint8_t bit = (ch &amp;gt;&amp;gt; i) &amp;amp; 1;&lt;br /&gt;
            uint8_t current_word = (encoder_state &amp;lt;&amp;lt; 1) | bit;&lt;br /&gt;
&lt;br /&gt;
            // Beräkna de två paritetsbitarna&lt;br /&gt;
            uint8_t out0 = parity(current_word &amp;amp; POLY_G0);&lt;br /&gt;
            uint8_t out1 = parity(current_word &amp;amp; POLY_G1);&lt;br /&gt;
&lt;br /&gt;
            // Packa bit 0&lt;br /&gt;
            out_byte = (out_byte &amp;lt;&amp;lt; 1) | out0;&lt;br /&gt;
            bit_count++;&lt;br /&gt;
            if (bit_count == 8) {&lt;br /&gt;
                fputc(out_byte, out);&lt;br /&gt;
                out_byte = 0;&lt;br /&gt;
                bit_count = 0;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            // Packa bit 1&lt;br /&gt;
            out_byte = (out_byte &amp;lt;&amp;lt; 1) | out1;&lt;br /&gt;
            bit_count++;&lt;br /&gt;
            if (bit_count == 8) {&lt;br /&gt;
                fputc(out_byte, out);&lt;br /&gt;
                out_byte = 0;&lt;br /&gt;
                bit_count = 0;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            // Uppdatera skiftregistret (behåll K-1 bitar)&lt;br /&gt;
            encoder_state = current_word &amp;amp; (NUM_STATES - 1);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    // Töm resterande bitar i sista byten vid behov&lt;br /&gt;
    if (bit_count &amp;gt; 0) {&lt;br /&gt;
        out_byte &amp;lt;&amp;lt;= (8 - bit_count);&lt;br /&gt;
        fputc(out_byte, out);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// ============================================================================&lt;br /&gt;
// AVKODARE (-d)&lt;br /&gt;
// ============================================================================&lt;br /&gt;
void decode(FILE *in, FILE *out) {&lt;br /&gt;
    size_t history_capacity = 1024;&lt;br /&gt;
    size_t step = 0;&lt;br /&gt;
&lt;br /&gt;
    uint8_t (*history)[NUM_STATES] = malloc(history_capacity * sizeof(*history));&lt;br /&gt;
    if (!history) {&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    uint32_t path_metrics[NUM_STATES];&lt;br /&gt;
    uint32_t old_metrics[NUM_STATES];&lt;br /&gt;
    &lt;br /&gt;
    // Initiera felkostnader (tillstånd 0 är garanterad start)&lt;br /&gt;
    for (int i = 1; i &amp;lt; NUM_STATES; i++) {&lt;br /&gt;
        path_metrics[i] = 1e6;&lt;br /&gt;
    }&lt;br /&gt;
    path_metrics[0] = 0;&lt;br /&gt;
&lt;br /&gt;
    int ch;&lt;br /&gt;
&lt;br /&gt;
    // 1. Framåtpass (Forward Pass / Add-Compare-Select)&lt;br /&gt;
    while ((ch = fgetc(in)) != EOF) {&lt;br /&gt;
        for (int bit_pair = 3; bit_pair &amp;gt;= 0; bit_pair--) {&lt;br /&gt;
            uint8_t b0 = (ch &amp;gt;&amp;gt; (bit_pair * 2 + 1)) &amp;amp; 1;&lt;br /&gt;
            uint8_t b1 = (ch &amp;gt;&amp;gt; (bit_pair * 2)) &amp;amp; 1;&lt;br /&gt;
&lt;br /&gt;
            // Expandera historikbufferten dynamiskt om det behövs&lt;br /&gt;
            if (step &amp;gt;= history_capacity) {&lt;br /&gt;
                history_capacity *= 2;&lt;br /&gt;
                uint8_t (*new_history)[NUM_STATES] = realloc(history, history_capacity * sizeof(*history));&lt;br /&gt;
                if (!new_history) {&lt;br /&gt;
                    free(history);&lt;br /&gt;
                    return;&lt;br /&gt;
                }&lt;br /&gt;
                history = new_history;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            memcpy(old_metrics, path_metrics, sizeof(path_metrics));&lt;br /&gt;
&lt;br /&gt;
            // Gå igenom alla möjliga måltillstånd&lt;br /&gt;
            for (int state = 0; state &amp;lt; NUM_STATES; state++) {&lt;br /&gt;
                int prev0 = state &amp;gt;&amp;gt; 1;&lt;br /&gt;
                int prev1 = prev0 | (NUM_STATES &amp;gt;&amp;gt; 1);&lt;br /&gt;
                uint8_t input_bit = state &amp;amp; 1;&lt;br /&gt;
&lt;br /&gt;
                // Väg 0&lt;br /&gt;
                uint8_t word0 = (prev0 &amp;lt;&amp;lt; 1) | input_bit;&lt;br /&gt;
                uint8_t exp0_0 = parity(word0 &amp;amp; POLY_G0);&lt;br /&gt;
                uint8_t exp0_1 = parity(word0 &amp;amp; POLY_G1);&lt;br /&gt;
                uint32_t cost0 = (exp0_0 != b0) + (exp0_1 != b1);&lt;br /&gt;
&lt;br /&gt;
                // Väg 1&lt;br /&gt;
                uint8_t word1 = (prev1 &amp;lt;&amp;lt; 1) | input_bit;&lt;br /&gt;
                uint8_t exp1_0 = parity(word1 &amp;amp; POLY_G0);&lt;br /&gt;
                uint8_t exp1_1 = parity(word1 &amp;amp; POLY_G1);&lt;br /&gt;
                uint32_t cost1 = (exp1_0 != b0) + (exp1_1 != b1);&lt;br /&gt;
&lt;br /&gt;
                uint32_t m0 = old_metrics[prev0] + cost0;&lt;br /&gt;
                uint32_t m1 = old_metrics[prev1] + cost1;&lt;br /&gt;
&lt;br /&gt;
                // Välj den bästa överlevande vägen&lt;br /&gt;
                if (m0 &amp;lt;= m1) {&lt;br /&gt;
                    path_metrics[state] = m0;&lt;br /&gt;
                    history[step][state] = 0;&lt;br /&gt;
                } else {&lt;br /&gt;
                    path_metrics[state] = m1;&lt;br /&gt;
                    history[step][state] = 1;&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
            step++;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (step == 0) {&lt;br /&gt;
        free(history);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // 2. Hitta bästa sluttillstånd (lägsta metric)&lt;br /&gt;
    int curr_state = 0;&lt;br /&gt;
    uint32_t min_m = path_metrics[0];&lt;br /&gt;
    for (int i = 1; i &amp;lt; NUM_STATES; i++) {&lt;br /&gt;
        if (path_metrics[i] &amp;lt; min_m) {&lt;br /&gt;
            min_m = path_metrics[i];&lt;br /&gt;
            curr_state = i;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // 3. Bakåtspårning (Traceback)&lt;br /&gt;
    uint8_t *decoded_bits = malloc(step);&lt;br /&gt;
    if (!decoded_bits) {&lt;br /&gt;
        free(history);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    for (int s = (int)step - 1; s &amp;gt;= 0; s--) {&lt;br /&gt;
        decoded_bits[s] = curr_state &amp;amp; 1;&lt;br /&gt;
        int decision = history[s][curr_state];&lt;br /&gt;
        int prev0 = curr_state &amp;gt;&amp;gt; 1;&lt;br /&gt;
        &lt;br /&gt;
        if (decision == 0) {&lt;br /&gt;
            curr_state = prev0;&lt;br /&gt;
        } else {&lt;br /&gt;
            curr_state = prev0 | (NUM_STATES &amp;gt;&amp;gt; 1);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // 4. Återpacka till bytes och skriv ut till strömmen&lt;br /&gt;
    uint8_t current_byte = 0;&lt;br /&gt;
    for (size_t i = 0; i &amp;lt; step; i++) {&lt;br /&gt;
        current_byte = (current_byte &amp;lt;&amp;lt; 1) | decoded_bits[i];&lt;br /&gt;
        if ((i + 1) % 8 == 0) {&lt;br /&gt;
            fputc(current_byte, out);&lt;br /&gt;
            current_byte = 0;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    free(decoded_bits);&lt;br /&gt;
    free(history);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// ============================================================================&lt;br /&gt;
// INTERNT TEST (-t)&lt;br /&gt;
// ============================================================================&lt;br /&gt;
void run_test(void) {&lt;br /&gt;
    printf(&amp;quot;[*] Startar internt test (64 bytes randomiserat data)...\n&amp;quot;);&lt;br /&gt;
    &lt;br /&gt;
    uint8_t original_data[64];&lt;br /&gt;
    srand((unsigned int)time(NULL));&lt;br /&gt;
    for (int i = 0; i &amp;lt; 64; i++) {&lt;br /&gt;
        original_data[i] = rand() % 256;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    FILE *orig_stream = tmpfile();&lt;br /&gt;
    FILE *encoded_stream = tmpfile();&lt;br /&gt;
    FILE *decoded_stream = tmpfile();&lt;br /&gt;
&lt;br /&gt;
    if (!orig_stream || !encoded_stream || !decoded_stream) {&lt;br /&gt;
        fprintf(stderr, &amp;quot;Kunde inte skapa temporära filer.\n&amp;quot;);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    fwrite(original_data, 1, 64, orig_stream);&lt;br /&gt;
    rewind(orig_stream);&lt;br /&gt;
&lt;br /&gt;
    encode(orig_stream, encoded_stream);&lt;br /&gt;
    rewind(encoded_stream);&lt;br /&gt;
&lt;br /&gt;
    decode(encoded_stream, decoded_stream);&lt;br /&gt;
    rewind(decoded_stream);&lt;br /&gt;
&lt;br /&gt;
    uint8_t final_data[64];&lt;br /&gt;
    size_t read_bytes = fread(final_data, 1, 64, decoded_stream);&lt;br /&gt;
&lt;br /&gt;
    bool success = true;&lt;br /&gt;
    if (read_bytes != 64) {&lt;br /&gt;
        printf(&amp;quot;[FAIL] Avkodade fel antal bytes: %zu (förväntade 64)\n&amp;quot;, read_bytes);&lt;br /&gt;
        success = false;&lt;br /&gt;
    } else {&lt;br /&gt;
        for (int i = 0; i &amp;lt; 64; i++) {&lt;br /&gt;
            if (original_data[i] != final_data[i]) {&lt;br /&gt;
                printf(&amp;quot;[FAIL] Diff vid byte %d: Org=0x%02X, Avkodad=0x%02X\n&amp;quot;, i, original_data[i], final_data[i]);&lt;br /&gt;
                success = false;&lt;br /&gt;
                break;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    fclose(orig_stream);&lt;br /&gt;
    fclose(encoded_stream);&lt;br /&gt;
    fclose(decoded_stream);&lt;br /&gt;
&lt;br /&gt;
    if (success) {&lt;br /&gt;
        printf(&amp;quot;[SUCCESS] Testet lyckades! Allt data matchar perfekt.\n&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// ============================================================================&lt;br /&gt;
// HJÄLPTEXT OCH MAIN&lt;br /&gt;
// ============================================================================&lt;br /&gt;
void print_help(const char *prog_name) {&lt;br /&gt;
    printf(&amp;quot;Användning: %s [option]\n&amp;quot;, prog_name);&lt;br /&gt;
    printf(&amp;quot;Optioner:\n&amp;quot;);&lt;br /&gt;
    printf(&amp;quot;  -e &amp;lt;infil &amp;gt;utfil   Kodar infil till utfil (Rate 1/2, K=7)\n&amp;quot;);&lt;br /&gt;
    printf(&amp;quot;  -d &amp;lt;infil &amp;gt;utfil   Avkodar infil till utfil med Viterbi\n&amp;quot;);&lt;br /&gt;
    printf(&amp;quot;  -h                 Visar denna hjälptext\n&amp;quot;);&lt;br /&gt;
    printf(&amp;quot;  -t                 Kör internt test med 64 bytes slumpdata\n&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
int main(int argc, char *argv[]) {&lt;br /&gt;
    if (argc != 2) {&lt;br /&gt;
        print_help(argv[0]);&lt;br /&gt;
        return EXIT_FAILURE;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (strcmp(argv[1], &amp;quot;-e&amp;quot;) == 0) {&lt;br /&gt;
        encode(stdin, stdout);&lt;br /&gt;
    } else if (strcmp(argv[1], &amp;quot;-d&amp;quot;) == 0) {&lt;br /&gt;
        decode(stdin, stdout);&lt;br /&gt;
    } else if (strcmp(argv[1], &amp;quot;-h&amp;quot;) == 0) {&lt;br /&gt;
        print_help(argv[0]);&lt;br /&gt;
    } else if (strcmp(argv[1], &amp;quot;-t&amp;quot;) == 0) {&lt;br /&gt;
        run_test();&lt;br /&gt;
    } else {&lt;br /&gt;
        fprintf(stderr, &amp;quot;Fel: Okänd parameter &#039;%s&#039;\n&amp;quot;, argv[1]);&lt;br /&gt;
        print_help(argv[0]);&lt;br /&gt;
        return EXIT_FAILURE;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return EXIT_SUCCESS;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>Anders</name></author>
	</entry>
	<entry>
		<id>http://wiki.sikvall.se/index.php?title=Viterbi&amp;diff=1907</id>
		<title>Viterbi</title>
		<link rel="alternate" type="text/html" href="http://wiki.sikvall.se/index.php?title=Viterbi&amp;diff=1907"/>
		<updated>2026-06-23T17:40:29Z</updated>

		<summary type="html">&lt;p&gt;Anders: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Bakgrund = &lt;br /&gt;
&lt;br /&gt;
Viterbis algoritm – Hur vi hittar rätt signal i bruset&lt;br /&gt;
&lt;br /&gt;
Inom amatörradion och digital signalbehandling stöter vi ofta på problemet med brus och fading. När vi skickar digital data över etern, till exempel med modernare digitala trafiksätt eller vid satellitkommunikation, använder vi ofta något som kallas för faltningskodning (convolutional coding). Det är en metod där varje sänd bit beror på både den nuvarande biten och ett antal tidigare bitar. Detta skapar ett mönster, ett beroende, som gör signalen robust.&lt;br /&gt;
&lt;br /&gt;
Men hur avkodar vi detta på mottagarsidan när atmosfären har ställt till det och lagt till en massa brus? Det är här Viterbis algoritm kommer in i bilden.&lt;br /&gt;
&lt;br /&gt;
Kort sagt är Viterbialgoritmen en metod för att hitta den mest troliga sekvensen av dolda tillstånd (det vi faktiskt sände) baserat på en serie observerade händelser (den brusiga signalen vi tog emot). Istället för att gissa bit för bit, tittar algoritmen på hela sammanhanget.&lt;br /&gt;
Trellis-diagrammet: Vägarna genom historien&lt;br /&gt;
&lt;br /&gt;
För att förstå hur algoritmen jobbar kan vi tänka oss ett nätverk av vägar, ett så kallat trellis-diagram.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* Tillstånd (States): Radiosändarens &amp;quot;minne&amp;quot; kan vid varje given tidpunkt befinna sig i ett visst antal tillstånd (beroende på de senaste sända bitarna).&lt;br /&gt;
&lt;br /&gt;
* Övergångar: När en ny bit ska sändas hoppar sändaren till ett nytt tillstånd och skickar ut en specifik kombination av bitar i luften.&lt;br /&gt;
&lt;br /&gt;
När mottagaren lyssnar får den in en sekvens som kanske är halvt dränkt i brus. En nolla kanske ser ut som en svag etta, och så vidare. Viterbialgoritmen börjar nu räkna på alla möjliga vägar genom detta nätverk av tillstånd över tid.&lt;br /&gt;
Så här jobbar algoritmen steg för steg:&lt;br /&gt;
&lt;br /&gt;
# Beräkna avstånd (Metric): För varje steg i tiden tittar algoritmen på de bitar som faktiskt togs emot och jämför dem med vad som borde ha sänts för varje tänkbar väg i diagrammet. Man mäter &amp;quot;avståndet&amp;quot; (ofta Hamming-avstånd för ettor och nollor, eller Euklidiskt avstånd om man kör &amp;quot;soft decision&amp;quot; där man mäter signalstyrkan mer exakt). Ju mindre avstånd, desto mer troligt är det att den vägen är den rätta.&lt;br /&gt;
&lt;br /&gt;
# Spara den bästa vägen (Add-Compare-Select): Till varje nytt tillstånd i diagrammet leder det oftast två olika vägar från det föregående steget. Algoritmen adderar det nya avståndet till det gamla, jämför de två alternativen, och väljer den väg som har lägst totalt avstånd (fel). Den andra vägen slängs bort för alltid. Det här är algoritmens stora styrka: den rensar hela tiden bort återvändsgränder så att beräkningsbördan inte exploderar.&lt;br /&gt;
&lt;br /&gt;
# Lås historiken (Traceback): När hela sekvensen (eller ett tillräckligt långt block) har tagits emot, tittar man på vilket slutgiltigt tillstånd som har det absolut lägsta totala felvärdet. Sedan backar man bakåt genom de sparade &amp;quot;bästa vägarna&amp;quot; till början.&lt;br /&gt;
&lt;br /&gt;
Resultatet blir den absolut mest sannolika sekvensen av bitar som sändaren faktiskt skickade ut, trots att det var fullt av bitfel under resans gång.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Implementation =&lt;br /&gt;
&lt;br /&gt;
== Modern C ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
 * Anders Sikvall 2026 Version 1.0&lt;br /&gt;
 * &amp;lt;anders@sikvall.se&amp;gt;&lt;br /&gt;
 * &lt;br /&gt;
 * Implementation i C av en standard Viterbi-algoritm som används bl.a. av &lt;br /&gt;
 * Qualcomm och NASA och är välpublicerad.&lt;br /&gt;
 *&lt;br /&gt;
 * PUBLIC DOMAIN FOR EDUCATIONAL PURPOSES&lt;br /&gt;
 *&lt;br /&gt;
 * Kompilera med gcc -o viterbi viterbi.c&lt;br /&gt;
 *&lt;br /&gt;
 * ANVÄNDNING&lt;br /&gt;
 *         viterbi -e &amp;lt;indatastream &amp;gt;utdatastream   Kodar &amp;lt;indatastream till &amp;gt;utdatastream&lt;br /&gt;
 *         viterbi -d &amp;lt;indatastream &amp;gt;utdatastream   Avkodar &amp;lt;indatastream till &amp;gt;utdatastream&lt;br /&gt;
 *         viterbi -t                               Utför en intern test på 64 randomiserade oktetter&lt;br /&gt;
 *         viterbi -h                               Visar en kort hjälptext&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
#include &amp;lt;string.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdbool.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdint.h&amp;gt;&lt;br /&gt;
#include &amp;lt;time.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#define K 7&lt;br /&gt;
#define NUM_STATES (1 &amp;lt;&amp;lt; (K - 1))&lt;br /&gt;
&lt;br /&gt;
// Standard NASA/Qualcomm-polynom (Rate 1/2, K=7)&lt;br /&gt;
const uint8_t POLY_G0 = 0x4F; // 1001111 i binärt&lt;br /&gt;
const uint8_t POLY_G1 = 0x6D; // 1101101 i binärt&lt;br /&gt;
&lt;br /&gt;
// Hårdvaruoptimerad paritetsberäkning&lt;br /&gt;
static inline uint8_t parity(uint8_t x) {&lt;br /&gt;
    return __builtin_parity(x) &amp;amp; 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// ============================================================================&lt;br /&gt;
// KODARE (-e)&lt;br /&gt;
// ============================================================================&lt;br /&gt;
void encode(FILE *in, FILE *out) {&lt;br /&gt;
    uint8_t encoder_state = 0;&lt;br /&gt;
    uint8_t out_byte = 0;&lt;br /&gt;
    int bit_count = 0;&lt;br /&gt;
    int ch;&lt;br /&gt;
&lt;br /&gt;
    while ((ch = fgetc(in)) != EOF) {&lt;br /&gt;
        // Processa varje bit från MSB till LSB&lt;br /&gt;
        for (int i = 7; i &amp;gt;= 0; i--) {&lt;br /&gt;
            uint8_t bit = (ch &amp;gt;&amp;gt; i) &amp;amp; 1;&lt;br /&gt;
            uint8_t current_word = (encoder_state &amp;lt;&amp;lt; 1) | bit;&lt;br /&gt;
&lt;br /&gt;
            // Beräkna de två paritetsbitarna&lt;br /&gt;
            uint8_t out0 = parity(current_word &amp;amp; POLY_G0);&lt;br /&gt;
            uint8_t out1 = parity(current_word &amp;amp; POLY_G1);&lt;br /&gt;
&lt;br /&gt;
            // Packa bit 0&lt;br /&gt;
            out_byte = (out_byte &amp;lt;&amp;lt; 1) | out0;&lt;br /&gt;
            bit_count++;&lt;br /&gt;
            if (bit_count == 8) {&lt;br /&gt;
                fputc(out_byte, out);&lt;br /&gt;
                out_byte = 0;&lt;br /&gt;
                bit_count = 0;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            // Packa bit 1&lt;br /&gt;
            out_byte = (out_byte &amp;lt;&amp;lt; 1) | out1;&lt;br /&gt;
            bit_count++;&lt;br /&gt;
            if (bit_count == 8) {&lt;br /&gt;
                fputc(out_byte, out);&lt;br /&gt;
                out_byte = 0;&lt;br /&gt;
                bit_count = 0;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            // Uppdatera skiftregistret (behåll K-1 bitar)&lt;br /&gt;
            encoder_state = current_word &amp;amp; (NUM_STATES - 1);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    // Töm resterande bitar i sista byten vid behov&lt;br /&gt;
    if (bit_count &amp;gt; 0) {&lt;br /&gt;
        out_byte &amp;lt;&amp;lt;= (8 - bit_count);&lt;br /&gt;
        fputc(out_byte, out);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// ============================================================================&lt;br /&gt;
// AVKODARE (-d)&lt;br /&gt;
// ============================================================================&lt;br /&gt;
void decode(FILE *in, FILE *out) {&lt;br /&gt;
    size_t history_capacity = 1024;&lt;br /&gt;
    size_t step = 0;&lt;br /&gt;
&lt;br /&gt;
    uint8_t (*history)[NUM_STATES] = malloc(history_capacity * sizeof(*history));&lt;br /&gt;
    if (!history) {&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    uint32_t path_metrics[NUM_STATES];&lt;br /&gt;
    uint32_t old_metrics[NUM_STATES];&lt;br /&gt;
    &lt;br /&gt;
    // Initiera felkostnader (tillstånd 0 är garanterad start)&lt;br /&gt;
    for (int i = 1; i &amp;lt; NUM_STATES; i++) {&lt;br /&gt;
        path_metrics[i] = 1e6;&lt;br /&gt;
    }&lt;br /&gt;
    path_metrics[0] = 0;&lt;br /&gt;
&lt;br /&gt;
    int ch;&lt;br /&gt;
&lt;br /&gt;
    // 1. Framåtpass (Forward Pass / Add-Compare-Select)&lt;br /&gt;
    while ((ch = fgetc(in)) != EOF) {&lt;br /&gt;
        for (int bit_pair = 3; bit_pair &amp;gt;= 0; bit_pair--) {&lt;br /&gt;
            uint8_t b0 = (ch &amp;gt;&amp;gt; (bit_pair * 2 + 1)) &amp;amp; 1;&lt;br /&gt;
            uint8_t b1 = (ch &amp;gt;&amp;gt; (bit_pair * 2)) &amp;amp; 1;&lt;br /&gt;
&lt;br /&gt;
            // Expandera historikbufferten dynamiskt om det behövs&lt;br /&gt;
            if (step &amp;gt;= history_capacity) {&lt;br /&gt;
                history_capacity *= 2;&lt;br /&gt;
                uint8_t (*new_history)[NUM_STATES] = realloc(history, history_capacity * sizeof(*history));&lt;br /&gt;
                if (!new_history) {&lt;br /&gt;
                    free(history);&lt;br /&gt;
                    return;&lt;br /&gt;
                }&lt;br /&gt;
                history = new_history;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            memcpy(old_metrics, path_metrics, sizeof(path_metrics));&lt;br /&gt;
&lt;br /&gt;
            // Gå igenom alla möjliga måltillstånd&lt;br /&gt;
            for (int state = 0; state &amp;lt; NUM_STATES; state++) {&lt;br /&gt;
                int prev0 = state &amp;gt;&amp;gt; 1;&lt;br /&gt;
                int prev1 = prev0 | (NUM_STATES &amp;gt;&amp;gt; 1);&lt;br /&gt;
                uint8_t input_bit = state &amp;amp; 1;&lt;br /&gt;
&lt;br /&gt;
                // Väg 0&lt;br /&gt;
                uint8_t word0 = (prev0 &amp;lt;&amp;lt; 1) | input_bit;&lt;br /&gt;
                uint8_t exp0_0 = parity(word0 &amp;amp; POLY_G0);&lt;br /&gt;
                uint8_t exp0_1 = parity(word0 &amp;amp; POLY_G1);&lt;br /&gt;
                uint32_t cost0 = (exp0_0 != b0) + (exp0_1 != b1);&lt;br /&gt;
&lt;br /&gt;
                // Väg 1&lt;br /&gt;
                uint8_t word1 = (prev1 &amp;lt;&amp;lt; 1) | input_bit;&lt;br /&gt;
                uint8_t exp1_0 = parity(word1 &amp;amp; POLY_G0);&lt;br /&gt;
                uint8_t exp1_1 = parity(word1 &amp;amp; POLY_G1);&lt;br /&gt;
                uint32_t cost1 = (exp1_0 != b0) + (exp1_1 != b1);&lt;br /&gt;
&lt;br /&gt;
                uint32_t m0 = old_metrics[prev0] + cost0;&lt;br /&gt;
                uint32_t m1 = old_metrics[prev1] + cost1;&lt;br /&gt;
&lt;br /&gt;
                // Välj den bästa överlevande vägen&lt;br /&gt;
                if (m0 &amp;lt;= m1) {&lt;br /&gt;
                    path_metrics[state] = m0;&lt;br /&gt;
                    history[step][state] = 0;&lt;br /&gt;
                } else {&lt;br /&gt;
                    path_metrics[state] = m1;&lt;br /&gt;
                    history[step][state] = 1;&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
            step++;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (step == 0) {&lt;br /&gt;
        free(history);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // 2. Hitta bästa sluttillstånd (lägsta metric)&lt;br /&gt;
    int curr_state = 0;&lt;br /&gt;
    uint32_t min_m = path_metrics[0];&lt;br /&gt;
    for (int i = 1; i &amp;lt; NUM_STATES; i++) {&lt;br /&gt;
        if (path_metrics[i] &amp;lt; min_m) {&lt;br /&gt;
            min_m = path_metrics[i];&lt;br /&gt;
            curr_state = i;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // 3. Bakåtspårning (Traceback)&lt;br /&gt;
    uint8_t *decoded_bits = malloc(step);&lt;br /&gt;
    if (!decoded_bits) {&lt;br /&gt;
        free(history);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    for (int s = (int)step - 1; s &amp;gt;= 0; s--) {&lt;br /&gt;
        decoded_bits[s] = curr_state &amp;amp; 1;&lt;br /&gt;
        int decision = history[s][curr_state];&lt;br /&gt;
        int prev0 = curr_state &amp;gt;&amp;gt; 1;&lt;br /&gt;
        &lt;br /&gt;
        if (decision == 0) {&lt;br /&gt;
            curr_state = prev0;&lt;br /&gt;
        } else {&lt;br /&gt;
            curr_state = prev0 | (NUM_STATES &amp;gt;&amp;gt; 1);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // 4. Återpacka till bytes och skriv ut till strömmen&lt;br /&gt;
    uint8_t current_byte = 0;&lt;br /&gt;
    for (size_t i = 0; i &amp;lt; step; i++) {&lt;br /&gt;
        current_byte = (current_byte &amp;lt;&amp;lt; 1) | decoded_bits[i];&lt;br /&gt;
        if ((i + 1) % 8 == 0) {&lt;br /&gt;
            fputc(current_byte, out);&lt;br /&gt;
            current_byte = 0;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    free(decoded_bits);&lt;br /&gt;
    free(history);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// ============================================================================&lt;br /&gt;
// INTERNT TEST (-t)&lt;br /&gt;
// ============================================================================&lt;br /&gt;
void run_test(void) {&lt;br /&gt;
    printf(&amp;quot;[*] Startar internt test (64 bytes randomiserat data)...\n&amp;quot;);&lt;br /&gt;
    &lt;br /&gt;
    uint8_t original_data[64];&lt;br /&gt;
    srand((unsigned int)time(NULL));&lt;br /&gt;
    for (int i = 0; i &amp;lt; 64; i++) {&lt;br /&gt;
        original_data[i] = rand() % 256;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    FILE *orig_stream = tmpfile();&lt;br /&gt;
    FILE *encoded_stream = tmpfile();&lt;br /&gt;
    FILE *decoded_stream = tmpfile();&lt;br /&gt;
&lt;br /&gt;
    if (!orig_stream || !encoded_stream || !decoded_stream) {&lt;br /&gt;
        fprintf(stderr, &amp;quot;Kunde inte skapa temporära filer.\n&amp;quot;);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    fwrite(original_data, 1, 64, orig_stream);&lt;br /&gt;
    rewind(orig_stream);&lt;br /&gt;
&lt;br /&gt;
    encode(orig_stream, encoded_stream);&lt;br /&gt;
    rewind(encoded_stream);&lt;br /&gt;
&lt;br /&gt;
    decode(encoded_stream, decoded_stream);&lt;br /&gt;
    rewind(decoded_stream);&lt;br /&gt;
&lt;br /&gt;
    uint8_t final_data[64];&lt;br /&gt;
    size_t read_bytes = fread(final_data, 1, 64, decoded_stream);&lt;br /&gt;
&lt;br /&gt;
    bool success = true;&lt;br /&gt;
    if (read_bytes != 64) {&lt;br /&gt;
        printf(&amp;quot;[FAIL] Avkodade fel antal bytes: %zu (förväntade 64)\n&amp;quot;, read_bytes);&lt;br /&gt;
        success = false;&lt;br /&gt;
    } else {&lt;br /&gt;
        for (int i = 0; i &amp;lt; 64; i++) {&lt;br /&gt;
            if (original_data[i] != final_data[i]) {&lt;br /&gt;
                printf(&amp;quot;[FAIL] Diff vid byte %d: Org=0x%02X, Avkodad=0x%02X\n&amp;quot;, i, original_data[i], final_data[i]);&lt;br /&gt;
                success = false;&lt;br /&gt;
                break;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    fclose(orig_stream);&lt;br /&gt;
    fclose(encoded_stream);&lt;br /&gt;
    fclose(decoded_stream);&lt;br /&gt;
&lt;br /&gt;
    if (success) {&lt;br /&gt;
        printf(&amp;quot;[SUCCESS] Testet lyckades! Allt data matchar perfekt.\n&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// ============================================================================&lt;br /&gt;
// HJÄLPTEXT OCH MAIN&lt;br /&gt;
// ============================================================================&lt;br /&gt;
void print_help(const char *prog_name) {&lt;br /&gt;
    printf(&amp;quot;Användning: %s [option]\n&amp;quot;, prog_name);&lt;br /&gt;
    printf(&amp;quot;Optioner:\n&amp;quot;);&lt;br /&gt;
    printf(&amp;quot;  -e &amp;lt;infil &amp;gt;utfil   Kodar infil till utfil (Rate 1/2, K=7)\n&amp;quot;);&lt;br /&gt;
    printf(&amp;quot;  -d &amp;lt;infil &amp;gt;utfil   Avkodar infil till utfil med Viterbi\n&amp;quot;);&lt;br /&gt;
    printf(&amp;quot;  -h                 Visar denna hjälptext\n&amp;quot;);&lt;br /&gt;
    printf(&amp;quot;  -t                 Kör internt test med 64 bytes slumpdata\n&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
int main(int argc, char *argv[]) {&lt;br /&gt;
    if (argc != 2) {&lt;br /&gt;
        print_help(argv[0]);&lt;br /&gt;
        return EXIT_FAILURE;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (strcmp(argv[1], &amp;quot;-e&amp;quot;) == 0) {&lt;br /&gt;
        encode(stdin, stdout);&lt;br /&gt;
    } else if (strcmp(argv[1], &amp;quot;-d&amp;quot;) == 0) {&lt;br /&gt;
        decode(stdin, stdout);&lt;br /&gt;
    } else if (strcmp(argv[1], &amp;quot;-h&amp;quot;) == 0) {&lt;br /&gt;
        print_help(argv[0]);&lt;br /&gt;
    } else if (strcmp(argv[1], &amp;quot;-t&amp;quot;) == 0) {&lt;br /&gt;
        run_test();&lt;br /&gt;
    } else {&lt;br /&gt;
        fprintf(stderr, &amp;quot;Fel: Okänd parameter &#039;%s&#039;\n&amp;quot;, argv[1]);&lt;br /&gt;
        print_help(argv[0]);&lt;br /&gt;
        return EXIT_FAILURE;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return EXIT_SUCCESS;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>Anders</name></author>
	</entry>
	<entry>
		<id>http://wiki.sikvall.se/index.php?title=Viterbi&amp;diff=1906</id>
		<title>Viterbi</title>
		<link rel="alternate" type="text/html" href="http://wiki.sikvall.se/index.php?title=Viterbi&amp;diff=1906"/>
		<updated>2026-06-23T17:37:23Z</updated>

		<summary type="html">&lt;p&gt;Anders: /* Modern C */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
= Implementation =&lt;br /&gt;
&lt;br /&gt;
== Modern C ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
 * Anders Sikvall 2026 Version 1.0&lt;br /&gt;
 * &amp;lt;anders@sikvall.se&amp;gt;&lt;br /&gt;
 * &lt;br /&gt;
 * Implementation i C av en standard Viterbi-algoritm som används bl.a. av &lt;br /&gt;
 * Qualcomm och NASA och är välpublicerad.&lt;br /&gt;
 *&lt;br /&gt;
 * PUBLIC DOMAIN FOR EDUCATIONAL PURPOSES&lt;br /&gt;
 *&lt;br /&gt;
 * Kompilera med gcc -o viterbi viterbi.c&lt;br /&gt;
 *&lt;br /&gt;
 * ANVÄNDNING&lt;br /&gt;
 *         viterbi -e &amp;lt;indatastream &amp;gt;utdatastream   Kodar &amp;lt;indatastream till &amp;gt;utdatastream&lt;br /&gt;
 *         viterbi -d &amp;lt;indatastream &amp;gt;utdatastream   Avkodar &amp;lt;indatastream till &amp;gt;utdatastream&lt;br /&gt;
 *         viterbi -t                               Utför en intern test på 64 randomiserade oktetter&lt;br /&gt;
 *         viterbi -h                               Visar en kort hjälptext&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
#include &amp;lt;string.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdbool.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdint.h&amp;gt;&lt;br /&gt;
#include &amp;lt;time.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#define K 7&lt;br /&gt;
#define NUM_STATES (1 &amp;lt;&amp;lt; (K - 1))&lt;br /&gt;
&lt;br /&gt;
// Standard NASA/Qualcomm-polynom (Rate 1/2, K=7)&lt;br /&gt;
const uint8_t POLY_G0 = 0x4F; // 1001111 i binärt&lt;br /&gt;
const uint8_t POLY_G1 = 0x6D; // 1101101 i binärt&lt;br /&gt;
&lt;br /&gt;
// Hårdvaruoptimerad paritetsberäkning&lt;br /&gt;
static inline uint8_t parity(uint8_t x) {&lt;br /&gt;
    return __builtin_parity(x) &amp;amp; 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// ============================================================================&lt;br /&gt;
// KODARE (-e)&lt;br /&gt;
// ============================================================================&lt;br /&gt;
void encode(FILE *in, FILE *out) {&lt;br /&gt;
    uint8_t encoder_state = 0;&lt;br /&gt;
    uint8_t out_byte = 0;&lt;br /&gt;
    int bit_count = 0;&lt;br /&gt;
    int ch;&lt;br /&gt;
&lt;br /&gt;
    while ((ch = fgetc(in)) != EOF) {&lt;br /&gt;
        // Processa varje bit från MSB till LSB&lt;br /&gt;
        for (int i = 7; i &amp;gt;= 0; i--) {&lt;br /&gt;
            uint8_t bit = (ch &amp;gt;&amp;gt; i) &amp;amp; 1;&lt;br /&gt;
            uint8_t current_word = (encoder_state &amp;lt;&amp;lt; 1) | bit;&lt;br /&gt;
&lt;br /&gt;
            // Beräkna de två paritetsbitarna&lt;br /&gt;
            uint8_t out0 = parity(current_word &amp;amp; POLY_G0);&lt;br /&gt;
            uint8_t out1 = parity(current_word &amp;amp; POLY_G1);&lt;br /&gt;
&lt;br /&gt;
            // Packa bit 0&lt;br /&gt;
            out_byte = (out_byte &amp;lt;&amp;lt; 1) | out0;&lt;br /&gt;
            bit_count++;&lt;br /&gt;
            if (bit_count == 8) {&lt;br /&gt;
                fputc(out_byte, out);&lt;br /&gt;
                out_byte = 0;&lt;br /&gt;
                bit_count = 0;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            // Packa bit 1&lt;br /&gt;
            out_byte = (out_byte &amp;lt;&amp;lt; 1) | out1;&lt;br /&gt;
            bit_count++;&lt;br /&gt;
            if (bit_count == 8) {&lt;br /&gt;
                fputc(out_byte, out);&lt;br /&gt;
                out_byte = 0;&lt;br /&gt;
                bit_count = 0;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            // Uppdatera skiftregistret (behåll K-1 bitar)&lt;br /&gt;
            encoder_state = current_word &amp;amp; (NUM_STATES - 1);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    // Töm resterande bitar i sista byten vid behov&lt;br /&gt;
    if (bit_count &amp;gt; 0) {&lt;br /&gt;
        out_byte &amp;lt;&amp;lt;= (8 - bit_count);&lt;br /&gt;
        fputc(out_byte, out);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// ============================================================================&lt;br /&gt;
// AVKODARE (-d)&lt;br /&gt;
// ============================================================================&lt;br /&gt;
void decode(FILE *in, FILE *out) {&lt;br /&gt;
    size_t history_capacity = 1024;&lt;br /&gt;
    size_t step = 0;&lt;br /&gt;
&lt;br /&gt;
    uint8_t (*history)[NUM_STATES] = malloc(history_capacity * sizeof(*history));&lt;br /&gt;
    if (!history) {&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    uint32_t path_metrics[NUM_STATES];&lt;br /&gt;
    uint32_t old_metrics[NUM_STATES];&lt;br /&gt;
    &lt;br /&gt;
    // Initiera felkostnader (tillstånd 0 är garanterad start)&lt;br /&gt;
    for (int i = 1; i &amp;lt; NUM_STATES; i++) {&lt;br /&gt;
        path_metrics[i] = 1e6;&lt;br /&gt;
    }&lt;br /&gt;
    path_metrics[0] = 0;&lt;br /&gt;
&lt;br /&gt;
    int ch;&lt;br /&gt;
&lt;br /&gt;
    // 1. Framåtpass (Forward Pass / Add-Compare-Select)&lt;br /&gt;
    while ((ch = fgetc(in)) != EOF) {&lt;br /&gt;
        for (int bit_pair = 3; bit_pair &amp;gt;= 0; bit_pair--) {&lt;br /&gt;
            uint8_t b0 = (ch &amp;gt;&amp;gt; (bit_pair * 2 + 1)) &amp;amp; 1;&lt;br /&gt;
            uint8_t b1 = (ch &amp;gt;&amp;gt; (bit_pair * 2)) &amp;amp; 1;&lt;br /&gt;
&lt;br /&gt;
            // Expandera historikbufferten dynamiskt om det behövs&lt;br /&gt;
            if (step &amp;gt;= history_capacity) {&lt;br /&gt;
                history_capacity *= 2;&lt;br /&gt;
                uint8_t (*new_history)[NUM_STATES] = realloc(history, history_capacity * sizeof(*history));&lt;br /&gt;
                if (!new_history) {&lt;br /&gt;
                    free(history);&lt;br /&gt;
                    return;&lt;br /&gt;
                }&lt;br /&gt;
                history = new_history;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            memcpy(old_metrics, path_metrics, sizeof(path_metrics));&lt;br /&gt;
&lt;br /&gt;
            // Gå igenom alla möjliga måltillstånd&lt;br /&gt;
            for (int state = 0; state &amp;lt; NUM_STATES; state++) {&lt;br /&gt;
                int prev0 = state &amp;gt;&amp;gt; 1;&lt;br /&gt;
                int prev1 = prev0 | (NUM_STATES &amp;gt;&amp;gt; 1);&lt;br /&gt;
                uint8_t input_bit = state &amp;amp; 1;&lt;br /&gt;
&lt;br /&gt;
                // Väg 0&lt;br /&gt;
                uint8_t word0 = (prev0 &amp;lt;&amp;lt; 1) | input_bit;&lt;br /&gt;
                uint8_t exp0_0 = parity(word0 &amp;amp; POLY_G0);&lt;br /&gt;
                uint8_t exp0_1 = parity(word0 &amp;amp; POLY_G1);&lt;br /&gt;
                uint32_t cost0 = (exp0_0 != b0) + (exp0_1 != b1);&lt;br /&gt;
&lt;br /&gt;
                // Väg 1&lt;br /&gt;
                uint8_t word1 = (prev1 &amp;lt;&amp;lt; 1) | input_bit;&lt;br /&gt;
                uint8_t exp1_0 = parity(word1 &amp;amp; POLY_G0);&lt;br /&gt;
                uint8_t exp1_1 = parity(word1 &amp;amp; POLY_G1);&lt;br /&gt;
                uint32_t cost1 = (exp1_0 != b0) + (exp1_1 != b1);&lt;br /&gt;
&lt;br /&gt;
                uint32_t m0 = old_metrics[prev0] + cost0;&lt;br /&gt;
                uint32_t m1 = old_metrics[prev1] + cost1;&lt;br /&gt;
&lt;br /&gt;
                // Välj den bästa överlevande vägen&lt;br /&gt;
                if (m0 &amp;lt;= m1) {&lt;br /&gt;
                    path_metrics[state] = m0;&lt;br /&gt;
                    history[step][state] = 0;&lt;br /&gt;
                } else {&lt;br /&gt;
                    path_metrics[state] = m1;&lt;br /&gt;
                    history[step][state] = 1;&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
            step++;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (step == 0) {&lt;br /&gt;
        free(history);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // 2. Hitta bästa sluttillstånd (lägsta metric)&lt;br /&gt;
    int curr_state = 0;&lt;br /&gt;
    uint32_t min_m = path_metrics[0];&lt;br /&gt;
    for (int i = 1; i &amp;lt; NUM_STATES; i++) {&lt;br /&gt;
        if (path_metrics[i] &amp;lt; min_m) {&lt;br /&gt;
            min_m = path_metrics[i];&lt;br /&gt;
            curr_state = i;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // 3. Bakåtspårning (Traceback)&lt;br /&gt;
    uint8_t *decoded_bits = malloc(step);&lt;br /&gt;
    if (!decoded_bits) {&lt;br /&gt;
        free(history);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    for (int s = (int)step - 1; s &amp;gt;= 0; s--) {&lt;br /&gt;
        decoded_bits[s] = curr_state &amp;amp; 1;&lt;br /&gt;
        int decision = history[s][curr_state];&lt;br /&gt;
        int prev0 = curr_state &amp;gt;&amp;gt; 1;&lt;br /&gt;
        &lt;br /&gt;
        if (decision == 0) {&lt;br /&gt;
            curr_state = prev0;&lt;br /&gt;
        } else {&lt;br /&gt;
            curr_state = prev0 | (NUM_STATES &amp;gt;&amp;gt; 1);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // 4. Återpacka till bytes och skriv ut till strömmen&lt;br /&gt;
    uint8_t current_byte = 0;&lt;br /&gt;
    for (size_t i = 0; i &amp;lt; step; i++) {&lt;br /&gt;
        current_byte = (current_byte &amp;lt;&amp;lt; 1) | decoded_bits[i];&lt;br /&gt;
        if ((i + 1) % 8 == 0) {&lt;br /&gt;
            fputc(current_byte, out);&lt;br /&gt;
            current_byte = 0;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    free(decoded_bits);&lt;br /&gt;
    free(history);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// ============================================================================&lt;br /&gt;
// INTERNT TEST (-t)&lt;br /&gt;
// ============================================================================&lt;br /&gt;
void run_test(void) {&lt;br /&gt;
    printf(&amp;quot;[*] Startar internt test (64 bytes randomiserat data)...\n&amp;quot;);&lt;br /&gt;
    &lt;br /&gt;
    uint8_t original_data[64];&lt;br /&gt;
    srand((unsigned int)time(NULL));&lt;br /&gt;
    for (int i = 0; i &amp;lt; 64; i++) {&lt;br /&gt;
        original_data[i] = rand() % 256;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    FILE *orig_stream = tmpfile();&lt;br /&gt;
    FILE *encoded_stream = tmpfile();&lt;br /&gt;
    FILE *decoded_stream = tmpfile();&lt;br /&gt;
&lt;br /&gt;
    if (!orig_stream || !encoded_stream || !decoded_stream) {&lt;br /&gt;
        fprintf(stderr, &amp;quot;Kunde inte skapa temporära filer.\n&amp;quot;);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    fwrite(original_data, 1, 64, orig_stream);&lt;br /&gt;
    rewind(orig_stream);&lt;br /&gt;
&lt;br /&gt;
    encode(orig_stream, encoded_stream);&lt;br /&gt;
    rewind(encoded_stream);&lt;br /&gt;
&lt;br /&gt;
    decode(encoded_stream, decoded_stream);&lt;br /&gt;
    rewind(decoded_stream);&lt;br /&gt;
&lt;br /&gt;
    uint8_t final_data[64];&lt;br /&gt;
    size_t read_bytes = fread(final_data, 1, 64, decoded_stream);&lt;br /&gt;
&lt;br /&gt;
    bool success = true;&lt;br /&gt;
    if (read_bytes != 64) {&lt;br /&gt;
        printf(&amp;quot;[FAIL] Avkodade fel antal bytes: %zu (förväntade 64)\n&amp;quot;, read_bytes);&lt;br /&gt;
        success = false;&lt;br /&gt;
    } else {&lt;br /&gt;
        for (int i = 0; i &amp;lt; 64; i++) {&lt;br /&gt;
            if (original_data[i] != final_data[i]) {&lt;br /&gt;
                printf(&amp;quot;[FAIL] Diff vid byte %d: Org=0x%02X, Avkodad=0x%02X\n&amp;quot;, i, original_data[i], final_data[i]);&lt;br /&gt;
                success = false;&lt;br /&gt;
                break;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    fclose(orig_stream);&lt;br /&gt;
    fclose(encoded_stream);&lt;br /&gt;
    fclose(decoded_stream);&lt;br /&gt;
&lt;br /&gt;
    if (success) {&lt;br /&gt;
        printf(&amp;quot;[SUCCESS] Testet lyckades! Allt data matchar perfekt.\n&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// ============================================================================&lt;br /&gt;
// HJÄLPTEXT OCH MAIN&lt;br /&gt;
// ============================================================================&lt;br /&gt;
void print_help(const char *prog_name) {&lt;br /&gt;
    printf(&amp;quot;Användning: %s [option]\n&amp;quot;, prog_name);&lt;br /&gt;
    printf(&amp;quot;Optioner:\n&amp;quot;);&lt;br /&gt;
    printf(&amp;quot;  -e &amp;lt;infil &amp;gt;utfil   Kodar infil till utfil (Rate 1/2, K=7)\n&amp;quot;);&lt;br /&gt;
    printf(&amp;quot;  -d &amp;lt;infil &amp;gt;utfil   Avkodar infil till utfil med Viterbi\n&amp;quot;);&lt;br /&gt;
    printf(&amp;quot;  -h                 Visar denna hjälptext\n&amp;quot;);&lt;br /&gt;
    printf(&amp;quot;  -t                 Kör internt test med 64 bytes slumpdata\n&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
int main(int argc, char *argv[]) {&lt;br /&gt;
    if (argc != 2) {&lt;br /&gt;
        print_help(argv[0]);&lt;br /&gt;
        return EXIT_FAILURE;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (strcmp(argv[1], &amp;quot;-e&amp;quot;) == 0) {&lt;br /&gt;
        encode(stdin, stdout);&lt;br /&gt;
    } else if (strcmp(argv[1], &amp;quot;-d&amp;quot;) == 0) {&lt;br /&gt;
        decode(stdin, stdout);&lt;br /&gt;
    } else if (strcmp(argv[1], &amp;quot;-h&amp;quot;) == 0) {&lt;br /&gt;
        print_help(argv[0]);&lt;br /&gt;
    } else if (strcmp(argv[1], &amp;quot;-t&amp;quot;) == 0) {&lt;br /&gt;
        run_test();&lt;br /&gt;
    } else {&lt;br /&gt;
        fprintf(stderr, &amp;quot;Fel: Okänd parameter &#039;%s&#039;\n&amp;quot;, argv[1]);&lt;br /&gt;
        print_help(argv[0]);&lt;br /&gt;
        return EXIT_FAILURE;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return EXIT_SUCCESS;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>Anders</name></author>
	</entry>
	<entry>
		<id>http://wiki.sikvall.se/index.php?title=Viterbi&amp;diff=1905</id>
		<title>Viterbi</title>
		<link rel="alternate" type="text/html" href="http://wiki.sikvall.se/index.php?title=Viterbi&amp;diff=1905"/>
		<updated>2026-06-23T17:34:12Z</updated>

		<summary type="html">&lt;p&gt;Anders: Skapade sidan med &amp;#039; = Implementation =  == Modern C ==  &amp;lt;pre&amp;gt;  /*  * Anders Sikvall 2026 Version 1.0  * &amp;lt;anders@sikvall.se&amp;gt;  *   * Implementation i C av en standard Viterbi-algoritm som används bl.a. av   * Qualcomm och NASA och är välpublicerad.  *  * PUBLIC DOMAIN FOR EDUCATIONAL PURPOSES  */  #include &amp;lt;stdio.h&amp;gt; #include &amp;lt;stdlib.h&amp;gt; #include &amp;lt;string.h&amp;gt; #include &amp;lt;stdbool.h&amp;gt; #include &amp;lt;stdint.h&amp;gt; #include &amp;lt;time.h&amp;gt;  #define K 7 #define NUM_STATES (1 &amp;lt;&amp;lt; (K - 1))  // Standard NASA/Qualcomm-po...&amp;#039;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
= Implementation =&lt;br /&gt;
&lt;br /&gt;
== Modern C ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
 * Anders Sikvall 2026 Version 1.0&lt;br /&gt;
 * &amp;lt;anders@sikvall.se&amp;gt;&lt;br /&gt;
 * &lt;br /&gt;
 * Implementation i C av en standard Viterbi-algoritm som används bl.a. av &lt;br /&gt;
 * Qualcomm och NASA och är välpublicerad.&lt;br /&gt;
 *&lt;br /&gt;
 * PUBLIC DOMAIN FOR EDUCATIONAL PURPOSES&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
#include &amp;lt;string.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdbool.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdint.h&amp;gt;&lt;br /&gt;
#include &amp;lt;time.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#define K 7&lt;br /&gt;
#define NUM_STATES (1 &amp;lt;&amp;lt; (K - 1))&lt;br /&gt;
&lt;br /&gt;
// Standard NASA/Qualcomm-polynom (Rate 1/2, K=7)&lt;br /&gt;
const uint8_t POLY_G0 = 0x4F; // 1001111 i binärt&lt;br /&gt;
const uint8_t POLY_G1 = 0x6D; // 1101101 i binärt&lt;br /&gt;
&lt;br /&gt;
// Hårdvaruoptimerad paritetsberäkning&lt;br /&gt;
static inline uint8_t parity(uint8_t x) {&lt;br /&gt;
    return __builtin_parity(x) &amp;amp; 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// ============================================================================&lt;br /&gt;
// KODARE (-e)&lt;br /&gt;
// ============================================================================&lt;br /&gt;
void encode(FILE *in, FILE *out) {&lt;br /&gt;
    uint8_t encoder_state = 0;&lt;br /&gt;
    uint8_t out_byte = 0;&lt;br /&gt;
    int bit_count = 0;&lt;br /&gt;
    int ch;&lt;br /&gt;
&lt;br /&gt;
    while ((ch = fgetc(in)) != EOF) {&lt;br /&gt;
        // Processa varje bit från MSB till LSB&lt;br /&gt;
        for (int i = 7; i &amp;gt;= 0; i--) {&lt;br /&gt;
            uint8_t bit = (ch &amp;gt;&amp;gt; i) &amp;amp; 1;&lt;br /&gt;
            uint8_t current_word = (encoder_state &amp;lt;&amp;lt; 1) | bit;&lt;br /&gt;
&lt;br /&gt;
            // Beräkna de två paritetsbitarna&lt;br /&gt;
            uint8_t out0 = parity(current_word &amp;amp; POLY_G0);&lt;br /&gt;
            uint8_t out1 = parity(current_word &amp;amp; POLY_G1);&lt;br /&gt;
&lt;br /&gt;
            // Packa bit 0&lt;br /&gt;
            out_byte = (out_byte &amp;lt;&amp;lt; 1) | out0;&lt;br /&gt;
            bit_count++;&lt;br /&gt;
            if (bit_count == 8) {&lt;br /&gt;
                fputc(out_byte, out);&lt;br /&gt;
                out_byte = 0;&lt;br /&gt;
                bit_count = 0;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            // Packa bit 1&lt;br /&gt;
            out_byte = (out_byte &amp;lt;&amp;lt; 1) | out1;&lt;br /&gt;
            bit_count++;&lt;br /&gt;
            if (bit_count == 8) {&lt;br /&gt;
                fputc(out_byte, out);&lt;br /&gt;
                out_byte = 0;&lt;br /&gt;
                bit_count = 0;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            // Uppdatera skiftregistret (behåll K-1 bitar)&lt;br /&gt;
            encoder_state = current_word &amp;amp; (NUM_STATES - 1);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    // Töm resterande bitar i sista byten vid behov&lt;br /&gt;
    if (bit_count &amp;gt; 0) {&lt;br /&gt;
        out_byte &amp;lt;&amp;lt;= (8 - bit_count);&lt;br /&gt;
        fputc(out_byte, out);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// ============================================================================&lt;br /&gt;
// AVKODARE (-d)&lt;br /&gt;
// ============================================================================&lt;br /&gt;
void decode(FILE *in, FILE *out) {&lt;br /&gt;
    size_t history_capacity = 1024;&lt;br /&gt;
    size_t step = 0;&lt;br /&gt;
&lt;br /&gt;
    uint8_t (*history)[NUM_STATES] = malloc(history_capacity * sizeof(*history));&lt;br /&gt;
    if (!history) {&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    uint32_t path_metrics[NUM_STATES];&lt;br /&gt;
    uint32_t old_metrics[NUM_STATES];&lt;br /&gt;
    &lt;br /&gt;
    // Initiera felkostnader (tillstånd 0 är garanterad start)&lt;br /&gt;
    for (int i = 1; i &amp;lt; NUM_STATES; i++) {&lt;br /&gt;
        path_metrics[i] = 1e6;&lt;br /&gt;
    }&lt;br /&gt;
    path_metrics[0] = 0;&lt;br /&gt;
&lt;br /&gt;
    int ch;&lt;br /&gt;
&lt;br /&gt;
    // 1. Framåtpass (Forward Pass / Add-Compare-Select)&lt;br /&gt;
    while ((ch = fgetc(in)) != EOF) {&lt;br /&gt;
        for (int bit_pair = 3; bit_pair &amp;gt;= 0; bit_pair--) {&lt;br /&gt;
            uint8_t b0 = (ch &amp;gt;&amp;gt; (bit_pair * 2 + 1)) &amp;amp; 1;&lt;br /&gt;
            uint8_t b1 = (ch &amp;gt;&amp;gt; (bit_pair * 2)) &amp;amp; 1;&lt;br /&gt;
&lt;br /&gt;
            // Expandera historikbufferten dynamiskt om det behövs&lt;br /&gt;
            if (step &amp;gt;= history_capacity) {&lt;br /&gt;
                history_capacity *= 2;&lt;br /&gt;
                uint8_t (*new_history)[NUM_STATES] = realloc(history, history_capacity * sizeof(*history));&lt;br /&gt;
                if (!new_history) {&lt;br /&gt;
                    free(history);&lt;br /&gt;
                    return;&lt;br /&gt;
                }&lt;br /&gt;
                history = new_history;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            memcpy(old_metrics, path_metrics, sizeof(path_metrics));&lt;br /&gt;
&lt;br /&gt;
            // Gå igenom alla möjliga måltillstånd&lt;br /&gt;
            for (int state = 0; state &amp;lt; NUM_STATES; state++) {&lt;br /&gt;
                int prev0 = state &amp;gt;&amp;gt; 1;&lt;br /&gt;
                int prev1 = prev0 | (NUM_STATES &amp;gt;&amp;gt; 1);&lt;br /&gt;
                uint8_t input_bit = state &amp;amp; 1;&lt;br /&gt;
&lt;br /&gt;
                // Väg 0&lt;br /&gt;
                uint8_t word0 = (prev0 &amp;lt;&amp;lt; 1) | input_bit;&lt;br /&gt;
                uint8_t exp0_0 = parity(word0 &amp;amp; POLY_G0);&lt;br /&gt;
                uint8_t exp0_1 = parity(word0 &amp;amp; POLY_G1);&lt;br /&gt;
                uint32_t cost0 = (exp0_0 != b0) + (exp0_1 != b1);&lt;br /&gt;
&lt;br /&gt;
                // Väg 1&lt;br /&gt;
                uint8_t word1 = (prev1 &amp;lt;&amp;lt; 1) | input_bit;&lt;br /&gt;
                uint8_t exp1_0 = parity(word1 &amp;amp; POLY_G0);&lt;br /&gt;
                uint8_t exp1_1 = parity(word1 &amp;amp; POLY_G1);&lt;br /&gt;
                uint32_t cost1 = (exp1_0 != b0) + (exp1_1 != b1);&lt;br /&gt;
&lt;br /&gt;
                uint32_t m0 = old_metrics[prev0] + cost0;&lt;br /&gt;
                uint32_t m1 = old_metrics[prev1] + cost1;&lt;br /&gt;
&lt;br /&gt;
                // Välj den bästa överlevande vägen&lt;br /&gt;
                if (m0 &amp;lt;= m1) {&lt;br /&gt;
                    path_metrics[state] = m0;&lt;br /&gt;
                    history[step][state] = 0;&lt;br /&gt;
                } else {&lt;br /&gt;
                    path_metrics[state] = m1;&lt;br /&gt;
                    history[step][state] = 1;&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
            step++;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (step == 0) {&lt;br /&gt;
        free(history);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // 2. Hitta bästa sluttillstånd (lägsta metric)&lt;br /&gt;
    int curr_state = 0;&lt;br /&gt;
    uint32_t min_m = path_metrics[0];&lt;br /&gt;
    for (int i = 1; i &amp;lt; NUM_STATES; i++) {&lt;br /&gt;
        if (path_metrics[i] &amp;lt; min_m) {&lt;br /&gt;
            min_m = path_metrics[i];&lt;br /&gt;
            curr_state = i;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // 3. Bakåtspårning (Traceback)&lt;br /&gt;
    uint8_t *decoded_bits = malloc(step);&lt;br /&gt;
    if (!decoded_bits) {&lt;br /&gt;
        free(history);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    for (int s = (int)step - 1; s &amp;gt;= 0; s--) {&lt;br /&gt;
        decoded_bits[s] = curr_state &amp;amp; 1;&lt;br /&gt;
        int decision = history[s][curr_state];&lt;br /&gt;
        int prev0 = curr_state &amp;gt;&amp;gt; 1;&lt;br /&gt;
        &lt;br /&gt;
        if (decision == 0) {&lt;br /&gt;
            curr_state = prev0;&lt;br /&gt;
        } else {&lt;br /&gt;
            curr_state = prev0 | (NUM_STATES &amp;gt;&amp;gt; 1);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // 4. Återpacka till bytes och skriv ut till strömmen&lt;br /&gt;
    uint8_t current_byte = 0;&lt;br /&gt;
    for (size_t i = 0; i &amp;lt; step; i++) {&lt;br /&gt;
        current_byte = (current_byte &amp;lt;&amp;lt; 1) | decoded_bits[i];&lt;br /&gt;
        if ((i + 1) % 8 == 0) {&lt;br /&gt;
            fputc(current_byte, out);&lt;br /&gt;
            current_byte = 0;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    free(decoded_bits);&lt;br /&gt;
    free(history);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// ============================================================================&lt;br /&gt;
// INTERNT TEST (-t)&lt;br /&gt;
// ============================================================================&lt;br /&gt;
void run_test(void) {&lt;br /&gt;
    printf(&amp;quot;[*] Startar internt test (64 bytes randomiserat data)...\n&amp;quot;);&lt;br /&gt;
    &lt;br /&gt;
    uint8_t original_data[64];&lt;br /&gt;
    srand((unsigned int)time(NULL));&lt;br /&gt;
    for (int i = 0; i &amp;lt; 64; i++) {&lt;br /&gt;
        original_data[i] = rand() % 256;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    FILE *orig_stream = tmpfile();&lt;br /&gt;
    FILE *encoded_stream = tmpfile();&lt;br /&gt;
    FILE *decoded_stream = tmpfile();&lt;br /&gt;
&lt;br /&gt;
    if (!orig_stream || !encoded_stream || !decoded_stream) {&lt;br /&gt;
        fprintf(stderr, &amp;quot;Kunde inte skapa temporära filer.\n&amp;quot;);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    fwrite(original_data, 1, 64, orig_stream);&lt;br /&gt;
    rewind(orig_stream);&lt;br /&gt;
&lt;br /&gt;
    encode(orig_stream, encoded_stream);&lt;br /&gt;
    rewind(encoded_stream);&lt;br /&gt;
&lt;br /&gt;
    decode(encoded_stream, decoded_stream);&lt;br /&gt;
    rewind(decoded_stream);&lt;br /&gt;
&lt;br /&gt;
    uint8_t final_data[64];&lt;br /&gt;
    size_t read_bytes = fread(final_data, 1, 64, decoded_stream);&lt;br /&gt;
&lt;br /&gt;
    bool success = true;&lt;br /&gt;
    if (read_bytes != 64) {&lt;br /&gt;
        printf(&amp;quot;[FAIL] Avkodade fel antal bytes: %zu (förväntade 64)\n&amp;quot;, read_bytes);&lt;br /&gt;
        success = false;&lt;br /&gt;
    } else {&lt;br /&gt;
        for (int i = 0; i &amp;lt; 64; i++) {&lt;br /&gt;
            if (original_data[i] != final_data[i]) {&lt;br /&gt;
                printf(&amp;quot;[FAIL] Diff vid byte %d: Org=0x%02X, Avkodad=0x%02X\n&amp;quot;, i, original_data[i], final_data[i]);&lt;br /&gt;
                success = false;&lt;br /&gt;
                break;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    fclose(orig_stream);&lt;br /&gt;
    fclose(encoded_stream);&lt;br /&gt;
    fclose(decoded_stream);&lt;br /&gt;
&lt;br /&gt;
    if (success) {&lt;br /&gt;
        printf(&amp;quot;[SUCCESS] Testet lyckades! Allt data matchar perfekt.\n&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// ============================================================================&lt;br /&gt;
// HJÄLPTEXT OCH MAIN&lt;br /&gt;
// ============================================================================&lt;br /&gt;
void print_help(const char *prog_name) {&lt;br /&gt;
    printf(&amp;quot;Användning: %s [option]\n&amp;quot;, prog_name);&lt;br /&gt;
    printf(&amp;quot;Optioner:\n&amp;quot;);&lt;br /&gt;
    printf(&amp;quot;  -e &amp;lt;infil &amp;gt;utfil   Kodar infil till utfil (Rate 1/2, K=7)\n&amp;quot;);&lt;br /&gt;
    printf(&amp;quot;  -d &amp;lt;infil &amp;gt;utfil   Avkodar infil till utfil med Viterbi\n&amp;quot;);&lt;br /&gt;
    printf(&amp;quot;  -h                 Visar denna hjälptext\n&amp;quot;);&lt;br /&gt;
    printf(&amp;quot;  -t                 Kör internt test med 64 bytes slumpdata\n&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
int main(int argc, char *argv[]) {&lt;br /&gt;
    if (argc != 2) {&lt;br /&gt;
        print_help(argv[0]);&lt;br /&gt;
        return EXIT_FAILURE;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (strcmp(argv[1], &amp;quot;-e&amp;quot;) == 0) {&lt;br /&gt;
        encode(stdin, stdout);&lt;br /&gt;
    } else if (strcmp(argv[1], &amp;quot;-d&amp;quot;) == 0) {&lt;br /&gt;
        decode(stdin, stdout);&lt;br /&gt;
    } else if (strcmp(argv[1], &amp;quot;-h&amp;quot;) == 0) {&lt;br /&gt;
        print_help(argv[0]);&lt;br /&gt;
    } else if (strcmp(argv[1], &amp;quot;-t&amp;quot;) == 0) {&lt;br /&gt;
        run_test();&lt;br /&gt;
    } else {&lt;br /&gt;
        fprintf(stderr, &amp;quot;Fel: Okänd parameter &#039;%s&#039;\n&amp;quot;, argv[1]);&lt;br /&gt;
        print_help(argv[0]);&lt;br /&gt;
        return EXIT_FAILURE;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return EXIT_SUCCESS;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>Anders</name></author>
	</entry>
	<entry>
		<id>http://wiki.sikvall.se/index.php?title=Huvudsida&amp;diff=1904</id>
		<title>Huvudsida</title>
		<link rel="alternate" type="text/html" href="http://wiki.sikvall.se/index.php?title=Huvudsida&amp;diff=1904"/>
		<updated>2026-06-23T17:32:36Z</updated>

		<summary type="html">&lt;p&gt;Anders: /* Programmering */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Om mig = &lt;br /&gt;
&lt;br /&gt;
Ansvarig för denna Wiki är Anders Sikvall&lt;br /&gt;
[mailto:anders@sikvall.se anders@sikvall.se] (Proton mail krypterad)&lt;br /&gt;
&lt;br /&gt;
Du kan hitta min PGP/GPG-nyckel på denna URL:&lt;br /&gt;
[https://sikvall.se/pgp/anders@sikvall.se https://sikvall.se/pgp/anders@sikvall.se]&lt;br /&gt;
&lt;br /&gt;
Min hemsida finns på: &lt;br /&gt;
[https://sikvall.se/ https://sikvall.se/]&lt;br /&gt;
&lt;br /&gt;
= Specialsidor =&lt;br /&gt;
&lt;br /&gt;
Specialsidor är länkar till sidor som omfattar meta-information.&lt;br /&gt;
&lt;br /&gt;
* [[:Special:Categories|Alla kategorier]]&lt;br /&gt;
* [[:Special:AllPages|Alla sidor]]&lt;br /&gt;
* [[dBµV/m]]&lt;br /&gt;
&lt;br /&gt;
= Särskilt utvalda sidor =&lt;br /&gt;
&lt;br /&gt;
== Krypto ==&lt;br /&gt;
&lt;br /&gt;
* [[GPG]]&lt;br /&gt;
&lt;br /&gt;
== Programmering ==&lt;br /&gt;
&lt;br /&gt;
* [[Fisher-Yates Shuffle]]&lt;br /&gt;
* [[Base64]] [[Base32]] [[Base24]]&lt;br /&gt;
* [[Racket]]&lt;br /&gt;
* [[Viterbi]]&lt;br /&gt;
&lt;br /&gt;
== Elektronik ==&lt;br /&gt;
&lt;br /&gt;
* [[Peukerts lag]] - [[Blyackumulator laddningstabell]]&lt;br /&gt;
* [[Pi-dämpare]]&lt;br /&gt;
&lt;br /&gt;
== Radiorelaterat ==&lt;br /&gt;
&lt;br /&gt;
* [[Amatörradio]]&lt;br /&gt;
* [[Jaktradio 155 MHz]] - [[PMR446]] - [[KDR 444]]&lt;br /&gt;
* [[Q-koden]] - [[Morsealfabetet]] - [[Svenska bokstaveringsalfabetet]]&lt;br /&gt;
* [[AM]] - [[FM]] - [[SSB]] - [[CW]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Linux ==&lt;br /&gt;
&lt;br /&gt;
* [[Diskimage i Linux]]&lt;br /&gt;
* [[Git]]&lt;br /&gt;
* [[Temporär download]]&lt;br /&gt;
* [[Swapfil i BTRFS]]&lt;br /&gt;
* [[Automatiskt tömma soptunnan]]&lt;br /&gt;
&lt;br /&gt;
== LaTeX Dokumentation ==&lt;br /&gt;
&lt;br /&gt;
* [[Brevmall]]&lt;br /&gt;
* [[Svensk stilmall]]&lt;br /&gt;
* [[Tips och Tricks i LaTeX]]&lt;br /&gt;
&lt;br /&gt;
== Friluftsliv ==&lt;br /&gt;
* [[:category:Pannlampor|Pannlampor]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;L_f&amp;lt;/math&amp;gt;&lt;/div&gt;</summary>
		<author><name>Anders</name></author>
	</entry>
	<entry>
		<id>http://wiki.sikvall.se/index.php?title=Racket/EFRW&amp;diff=1903</id>
		<title>Racket/EFRW</title>
		<link rel="alternate" type="text/html" href="http://wiki.sikvall.se/index.php?title=Racket/EFRW&amp;diff=1903"/>
		<updated>2026-06-22T08:58:41Z</updated>

		<summary type="html">&lt;p&gt;Anders: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
#lang racket&lt;br /&gt;
&lt;br /&gt;
;; Täpp-Anders Sikvall, SM5UEI&lt;br /&gt;
;; &amp;lt;sm5uei@sikvall.se&amp;gt;&lt;br /&gt;
;;&lt;br /&gt;
;; Public Domain&lt;br /&gt;
;;&lt;br /&gt;
;; Koden den är fri att använda för den som vill och återanvända &lt;br /&gt;
;; och pyssla vidare med den som du vill. Jag blir glad om &lt;br /&gt;
;; jag omnämns i vidareutvecklingar och gör du förbättringar så&lt;br /&gt;
;; skicka de gärna till mig.&lt;br /&gt;
;;&lt;br /&gt;
;; =====================================================&lt;br /&gt;
;; Ändmatad antenn – längdintervall + vilka band som träffas&lt;br /&gt;
;; =====================================================&lt;br /&gt;
&lt;br /&gt;
(define c 299.792458)   ; m×MHz&lt;br /&gt;
&lt;br /&gt;
;; Svenska band, kommentera bort de band du inte är intresserad av att köra!&lt;br /&gt;
(define bands&lt;br /&gt;
  &#039;((1.810  2.000   &amp;quot;160m&amp;quot;)&lt;br /&gt;
    (3.500  3.800   &amp;quot;80m&amp;quot;)&lt;br /&gt;
    (5.3515 5.3666  &amp;quot;60m&amp;quot;)&lt;br /&gt;
    (7.000  7.200   &amp;quot;40m&amp;quot;)&lt;br /&gt;
;    (10.100 10.150  &amp;quot;30m&amp;quot;)&lt;br /&gt;
    (14.000 14.350  &amp;quot;20m&amp;quot;)&lt;br /&gt;
    (18.068 18.168  &amp;quot;17m&amp;quot;)&lt;br /&gt;
    (21.000 21.450  &amp;quot;15m&amp;quot;)&lt;br /&gt;
    (24.890 24.990  &amp;quot;12m&amp;quot;)&lt;br /&gt;
    (28.000 29.700  &amp;quot;10m&amp;quot;)&lt;br /&gt;
    (50.000 52.000  &amp;quot;6m&amp;quot;)))&lt;br /&gt;
&lt;br /&gt;
;; Returnerar lista med band som L är dåliga för en given längd&lt;br /&gt;
(define (bad-bands L tol)&lt;br /&gt;
  (filter-map&lt;br /&gt;
   (λ (band)&lt;br /&gt;
     (define fmin (first band))&lt;br /&gt;
     (define fmax (second band))&lt;br /&gt;
     (define name (third band))&lt;br /&gt;
     (define fmin-forb (* fmin (- 1 tol)))&lt;br /&gt;
     (define fmax-forb (* fmax (+ 1 tol)))&lt;br /&gt;
     (for/or ([n (in-range 1 400)])&lt;br /&gt;
       (define f-res (/ (* n c) (* 2.0 L)))&lt;br /&gt;
       (and (&amp;gt;= f-res fmin-forb) (&amp;lt;= f-res fmax-forb)&lt;br /&gt;
            name)))&lt;br /&gt;
   bands))&lt;br /&gt;
&lt;br /&gt;
(define (bad-length? L tol)&lt;br /&gt;
  (not (null? (bad-bands L tol))))&lt;br /&gt;
&lt;br /&gt;
(define (good-lengths min-L max-L step tol)&lt;br /&gt;
  (for/list ([L (in-range min-L (+ max-L 0.0001) step)]&lt;br /&gt;
             #:when (not (bad-length? L tol)))&lt;br /&gt;
    L))&lt;br /&gt;
&lt;br /&gt;
(define (group-into-ranges goods step)&lt;br /&gt;
  (if (null? goods)&lt;br /&gt;
      &#039;()&lt;br /&gt;
      (let loop ([lst (sort goods &amp;lt;)]&lt;br /&gt;
                 [ranges &#039;()]&lt;br /&gt;
                 [start (first goods)]&lt;br /&gt;
                 [prev (first goods)])&lt;br /&gt;
        (cond&lt;br /&gt;
          [(null? lst) (reverse (cons (list start prev) ranges))]&lt;br /&gt;
          [else&lt;br /&gt;
           (define current (first lst))&lt;br /&gt;
           (if (&amp;lt;= (- current prev) (+ step 0.0001))&lt;br /&gt;
               (loop (rest lst) ranges start current)&lt;br /&gt;
               (loop (rest lst)&lt;br /&gt;
                     (cons (list start prev) ranges)&lt;br /&gt;
                     current&lt;br /&gt;
                     current))]))))&lt;br /&gt;
&lt;br /&gt;
(define (print-range r vf end-corr)&lt;br /&gt;
  (define elec-start (first r))&lt;br /&gt;
  (define elec-end   (second r))&lt;br /&gt;
  (define phys-start (* elec-start vf end-corr))&lt;br /&gt;
  (define phys-end   (* elec-end   vf end-corr))&lt;br /&gt;
  (define s1 (~r elec-start #:precision 1))&lt;br /&gt;
  (define s2 (~r elec-end   #:precision 1))&lt;br /&gt;
  (define p1 (~r phys-start #:precision 1))&lt;br /&gt;
  (define p2 (~r phys-end   #:precision 1))&lt;br /&gt;
  (if (equal? s1 s2)&lt;br /&gt;
      (printf &amp;quot;~a m (elektrisk)  →  ~a m (fysisk)\n&amp;quot; s1 p1)&lt;br /&gt;
      (printf &amp;quot;~a–~a m (elektrisk)  →  ~a–~a m (fysisk)\n&amp;quot; s1 s2 p1 p2)))&lt;br /&gt;
&lt;br /&gt;
;; ====================== HUVUDFUNKTION ======================&lt;br /&gt;
(define (print-suggestions&lt;br /&gt;
         #:min-L     [min-L     10.0]&lt;br /&gt;
         #:max-L     [max-L     70.0]&lt;br /&gt;
         #:step      [step      0.01]&lt;br /&gt;
         #:tol       [tol       0.03]&lt;br /&gt;
         #:vf        [vf        0.96]&lt;br /&gt;
         #:end-corr  [end-corr  0.97])&lt;br /&gt;
  &lt;br /&gt;
  (define goods (good-lengths min-L max-L step tol))&lt;br /&gt;
  (define ranges (group-into-ranges goods step))&lt;br /&gt;
&lt;br /&gt;
  (printf &amp;quot;=== Bra längdintervall för ändmatad antenn ===\n&amp;quot;)&lt;br /&gt;
  (printf &amp;quot;Intervall: ~a–~a m   Steg: ~a m   Tolerans: ~a%\n&amp;quot; &lt;br /&gt;
          min-L max-L step (* tol 100))&lt;br /&gt;
  (printf &amp;quot;VF: ~a   End-effect: ~a (~a% förkortning)\n\n&amp;quot;&lt;br /&gt;
          vf end-corr (round (* (- 1 end-corr) 100)))&lt;br /&gt;
&lt;br /&gt;
  (if (null? ranges)&lt;br /&gt;
      (printf &amp;quot;Inga bra längder hittades.\n&amp;quot;)&lt;br /&gt;
      (begin&lt;br /&gt;
        (for ([r ranges])&lt;br /&gt;
          (print-range r vf end-corr))&lt;br /&gt;
        (printf &amp;quot;\nTotalt ~a bra intervall (~a punkter).\n&amp;quot; &lt;br /&gt;
                (length ranges) (length goods))))&lt;br /&gt;
&lt;br /&gt;
  (printf &amp;quot;\n&amp;quot;))&lt;br /&gt;
  &lt;br /&gt;
;; =====================================================&lt;br /&gt;
;; KÖR PROGRAMMET&lt;br /&gt;
;; =====================================================&lt;br /&gt;
&lt;br /&gt;
(print-suggestions &lt;br /&gt;
  #:min-L 7        ;; Kortaste antenntråden att kika på&lt;br /&gt;
  #:max-L 50       ;; Längsta antenntråden att kika på&lt;br /&gt;
  #:step 0.01      ;; Steglängd i meter&lt;br /&gt;
  #:tol 0.03       ;; Hur nära resonans tillåter vi (3% = 0.03)&lt;br /&gt;
  #:vf 0.96        ;; Hastighetsfaktorn för plastad koppartråd&lt;br /&gt;
  #:end-corr 0.97  ;; Ändkorrigerinsfaktor&lt;br /&gt;
  )&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>Anders</name></author>
	</entry>
	<entry>
		<id>http://wiki.sikvall.se/index.php?title=Racket/EFRW&amp;diff=1902</id>
		<title>Racket/EFRW</title>
		<link rel="alternate" type="text/html" href="http://wiki.sikvall.se/index.php?title=Racket/EFRW&amp;diff=1902"/>
		<updated>2026-06-21T21:28:59Z</updated>

		<summary type="html">&lt;p&gt;Anders: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
#lang racket&lt;br /&gt;
&lt;br /&gt;
;; Denna kod är skriven av Täpp-Anders Sikvall, SM5UEI&lt;br /&gt;
;; den är fri att använda för den som vill och återanvända &lt;br /&gt;
;; och pyssla vidare med den som du vill. Jag blir glad om &lt;br /&gt;
;; jag omnämns i vidareutvecklingar och du kan gärna skicka &lt;br /&gt;
;; den till &amp;lt;anders@sikvall.se&amp;gt; om du gjort förbättringar.&lt;br /&gt;
;;&lt;br /&gt;
;; =====================================================&lt;br /&gt;
;; Ändmatad antenn – längdintervall + vilka band som träffas&lt;br /&gt;
;; =====================================================&lt;br /&gt;
&lt;br /&gt;
(define c 299.792458)   ; m×MHz&lt;br /&gt;
&lt;br /&gt;
;; Svenska band, kommentera bort de band du inte är intresserad av att köra!&lt;br /&gt;
(define bands&lt;br /&gt;
  &#039;((1.810  2.000   &amp;quot;160m&amp;quot;)&lt;br /&gt;
    (3.500  3.800   &amp;quot;80m&amp;quot;)&lt;br /&gt;
    (5.3515 5.3666  &amp;quot;60m&amp;quot;)&lt;br /&gt;
    (7.000  7.200   &amp;quot;40m&amp;quot;)&lt;br /&gt;
;    (10.100 10.150  &amp;quot;30m&amp;quot;)&lt;br /&gt;
    (14.000 14.350  &amp;quot;20m&amp;quot;)&lt;br /&gt;
    (18.068 18.168  &amp;quot;17m&amp;quot;)&lt;br /&gt;
    (21.000 21.450  &amp;quot;15m&amp;quot;)&lt;br /&gt;
    (24.890 24.990  &amp;quot;12m&amp;quot;)&lt;br /&gt;
    (28.000 29.700  &amp;quot;10m&amp;quot;)&lt;br /&gt;
    (50.000 52.000  &amp;quot;6m&amp;quot;)))&lt;br /&gt;
&lt;br /&gt;
;; Returnerar lista med band som L är dåliga för en given längd&lt;br /&gt;
(define (bad-bands L tol)&lt;br /&gt;
  (filter-map&lt;br /&gt;
   (λ (band)&lt;br /&gt;
     (define fmin (first band))&lt;br /&gt;
     (define fmax (second band))&lt;br /&gt;
     (define name (third band))&lt;br /&gt;
     (define fmin-forb (* fmin (- 1 tol)))&lt;br /&gt;
     (define fmax-forb (* fmax (+ 1 tol)))&lt;br /&gt;
     (for/or ([n (in-range 1 400)])&lt;br /&gt;
       (define f-res (/ (* n c) (* 2.0 L)))&lt;br /&gt;
       (and (&amp;gt;= f-res fmin-forb) (&amp;lt;= f-res fmax-forb)&lt;br /&gt;
            name)))&lt;br /&gt;
   bands))&lt;br /&gt;
&lt;br /&gt;
(define (bad-length? L tol)&lt;br /&gt;
  (not (null? (bad-bands L tol))))&lt;br /&gt;
&lt;br /&gt;
(define (good-lengths min-L max-L step tol)&lt;br /&gt;
  (for/list ([L (in-range min-L (+ max-L 0.0001) step)]&lt;br /&gt;
             #:when (not (bad-length? L tol)))&lt;br /&gt;
    L))&lt;br /&gt;
&lt;br /&gt;
(define (group-into-ranges goods step)&lt;br /&gt;
  (if (null? goods)&lt;br /&gt;
      &#039;()&lt;br /&gt;
      (let loop ([lst (sort goods &amp;lt;)]&lt;br /&gt;
                 [ranges &#039;()]&lt;br /&gt;
                 [start (first goods)]&lt;br /&gt;
                 [prev (first goods)])&lt;br /&gt;
        (cond&lt;br /&gt;
          [(null? lst) (reverse (cons (list start prev) ranges))]&lt;br /&gt;
          [else&lt;br /&gt;
           (define current (first lst))&lt;br /&gt;
           (if (&amp;lt;= (- current prev) (+ step 0.0001))&lt;br /&gt;
               (loop (rest lst) ranges start current)&lt;br /&gt;
               (loop (rest lst)&lt;br /&gt;
                     (cons (list start prev) ranges)&lt;br /&gt;
                     current&lt;br /&gt;
                     current))]))))&lt;br /&gt;
&lt;br /&gt;
(define (print-range r vf end-corr)&lt;br /&gt;
  (define elec-start (first r))&lt;br /&gt;
  (define elec-end   (second r))&lt;br /&gt;
  (define phys-start (* elec-start vf end-corr))&lt;br /&gt;
  (define phys-end   (* elec-end   vf end-corr))&lt;br /&gt;
  (define s1 (~r elec-start #:precision 1))&lt;br /&gt;
  (define s2 (~r elec-end   #:precision 1))&lt;br /&gt;
  (define p1 (~r phys-start #:precision 1))&lt;br /&gt;
  (define p2 (~r phys-end   #:precision 1))&lt;br /&gt;
  (if (equal? s1 s2)&lt;br /&gt;
      (printf &amp;quot;~a m (elektrisk)  →  ~a m (fysisk)\n&amp;quot; s1 p1)&lt;br /&gt;
      (printf &amp;quot;~a–~a m (elektrisk)  →  ~a–~a m (fysisk)\n&amp;quot; s1 s2 p1 p2)))&lt;br /&gt;
&lt;br /&gt;
;; ====================== HUVUDFUNKTION ======================&lt;br /&gt;
(define (print-suggestions&lt;br /&gt;
         #:min-L     [min-L     10.0]&lt;br /&gt;
         #:max-L     [max-L     70.0]&lt;br /&gt;
         #:step      [step      0.01]&lt;br /&gt;
         #:tol       [tol       0.03]&lt;br /&gt;
         #:vf        [vf        0.96]&lt;br /&gt;
         #:end-corr  [end-corr  0.97])&lt;br /&gt;
  &lt;br /&gt;
  (define goods (good-lengths min-L max-L step tol))&lt;br /&gt;
  (define ranges (group-into-ranges goods step))&lt;br /&gt;
&lt;br /&gt;
  (printf &amp;quot;=== Bra längdintervall för ändmatad antenn ===\n&amp;quot;)&lt;br /&gt;
  (printf &amp;quot;Intervall: ~a–~a m   Steg: ~a m   Tolerans: ~a%\n&amp;quot; &lt;br /&gt;
          min-L max-L step (* tol 100))&lt;br /&gt;
  (printf &amp;quot;VF: ~a   End-effect: ~a (~a% förkortning)\n\n&amp;quot;&lt;br /&gt;
          vf end-corr (round (* (- 1 end-corr) 100)))&lt;br /&gt;
&lt;br /&gt;
  (if (null? ranges)&lt;br /&gt;
      (printf &amp;quot;Inga bra längder hittades.\n&amp;quot;)&lt;br /&gt;
      (begin&lt;br /&gt;
        (for ([r ranges])&lt;br /&gt;
          (print-range r vf end-corr))&lt;br /&gt;
        (printf &amp;quot;\nTotalt ~a bra intervall (~a punkter).\n&amp;quot; &lt;br /&gt;
                (length ranges) (length goods))))&lt;br /&gt;
&lt;br /&gt;
  (printf &amp;quot;\n&amp;quot;))&lt;br /&gt;
  &lt;br /&gt;
;; =====================================================&lt;br /&gt;
;; KÖR PROGRAMMET&lt;br /&gt;
;; =====================================================&lt;br /&gt;
&lt;br /&gt;
(print-suggestions &lt;br /&gt;
  #:min-L 7        ;; Kortaste antenntråden att kika på&lt;br /&gt;
  #:max-L 50       ;; Längsta antenntråden att kika på&lt;br /&gt;
  #:step 0.01      ;; Steglängd i meter&lt;br /&gt;
  #:tol 0.03       ;; Hur nära resonans tillåter vi (3% = 0.03)&lt;br /&gt;
  #:vf 0.96        ;; Hastighetsfaktorn för plastad koppartråd&lt;br /&gt;
  #:end-corr 0.97  ;; Ändkorrigerinsfaktor&lt;br /&gt;
  )&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>Anders</name></author>
	</entry>
	<entry>
		<id>http://wiki.sikvall.se/index.php?title=Racket/EFRW&amp;diff=1901</id>
		<title>Racket/EFRW</title>
		<link rel="alternate" type="text/html" href="http://wiki.sikvall.se/index.php?title=Racket/EFRW&amp;diff=1901"/>
		<updated>2026-06-21T21:22:09Z</updated>

		<summary type="html">&lt;p&gt;Anders: Skapade sidan med &amp;#039;&amp;lt;pre&amp;gt; #lang racket  ;; ===================================================== ;; Ändmatad antenn – längdintervall + vilka band som träffas ;; =====================================================  (define c 299.792458)   ; m×MHz  ;; Svenska band, kommentera bort de band du inte är intresserad av att köra! (define bands   &amp;#039;((1.810  2.000   &amp;quot;160m&amp;quot;)     (3.500  3.800   &amp;quot;80m&amp;quot;)     (5.3515 5.3666  &amp;quot;60m&amp;quot;)     (7.000  7.200   &amp;quot;40m&amp;quot;) ;    (10.100 10.150  &amp;quot;30m&amp;quot;)     (14.00...&amp;#039;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
#lang racket&lt;br /&gt;
&lt;br /&gt;
;; =====================================================&lt;br /&gt;
;; Ändmatad antenn – längdintervall + vilka band som träffas&lt;br /&gt;
;; =====================================================&lt;br /&gt;
&lt;br /&gt;
(define c 299.792458)   ; m×MHz&lt;br /&gt;
&lt;br /&gt;
;; Svenska band, kommentera bort de band du inte är intresserad av att köra!&lt;br /&gt;
(define bands&lt;br /&gt;
  &#039;((1.810  2.000   &amp;quot;160m&amp;quot;)&lt;br /&gt;
    (3.500  3.800   &amp;quot;80m&amp;quot;)&lt;br /&gt;
    (5.3515 5.3666  &amp;quot;60m&amp;quot;)&lt;br /&gt;
    (7.000  7.200   &amp;quot;40m&amp;quot;)&lt;br /&gt;
;    (10.100 10.150  &amp;quot;30m&amp;quot;)&lt;br /&gt;
    (14.000 14.350  &amp;quot;20m&amp;quot;)&lt;br /&gt;
    (18.068 18.168  &amp;quot;17m&amp;quot;)&lt;br /&gt;
    (21.000 21.450  &amp;quot;15m&amp;quot;)&lt;br /&gt;
    (24.890 24.990  &amp;quot;12m&amp;quot;)&lt;br /&gt;
    (28.000 29.700  &amp;quot;10m&amp;quot;)&lt;br /&gt;
    (50.000 52.000  &amp;quot;6m&amp;quot;)))&lt;br /&gt;
&lt;br /&gt;
;; Returnerar lista med band som L är dåliga för en given längd&lt;br /&gt;
(define (bad-bands L tol)&lt;br /&gt;
  (filter-map&lt;br /&gt;
   (λ (band)&lt;br /&gt;
     (define fmin (first band))&lt;br /&gt;
     (define fmax (second band))&lt;br /&gt;
     (define name (third band))&lt;br /&gt;
     (define fmin-forb (* fmin (- 1 tol)))&lt;br /&gt;
     (define fmax-forb (* fmax (+ 1 tol)))&lt;br /&gt;
     (for/or ([n (in-range 1 400)])&lt;br /&gt;
       (define f-res (/ (* n c) (* 2.0 L)))&lt;br /&gt;
       (and (&amp;gt;= f-res fmin-forb) (&amp;lt;= f-res fmax-forb)&lt;br /&gt;
            name)))&lt;br /&gt;
   bands))&lt;br /&gt;
&lt;br /&gt;
(define (bad-length? L tol)&lt;br /&gt;
  (not (null? (bad-bands L tol))))&lt;br /&gt;
&lt;br /&gt;
(define (good-lengths min-L max-L step tol)&lt;br /&gt;
  (for/list ([L (in-range min-L (+ max-L 0.0001) step)]&lt;br /&gt;
             #:when (not (bad-length? L tol)))&lt;br /&gt;
    L))&lt;br /&gt;
&lt;br /&gt;
(define (group-into-ranges goods step)&lt;br /&gt;
  (if (null? goods)&lt;br /&gt;
      &#039;()&lt;br /&gt;
      (let loop ([lst (sort goods &amp;lt;)]&lt;br /&gt;
                 [ranges &#039;()]&lt;br /&gt;
                 [start (first goods)]&lt;br /&gt;
                 [prev (first goods)])&lt;br /&gt;
        (cond&lt;br /&gt;
          [(null? lst) (reverse (cons (list start prev) ranges))]&lt;br /&gt;
          [else&lt;br /&gt;
           (define current (first lst))&lt;br /&gt;
           (if (&amp;lt;= (- current prev) (+ step 0.0001))&lt;br /&gt;
               (loop (rest lst) ranges start current)&lt;br /&gt;
               (loop (rest lst)&lt;br /&gt;
                     (cons (list start prev) ranges)&lt;br /&gt;
                     current&lt;br /&gt;
                     current))]))))&lt;br /&gt;
&lt;br /&gt;
(define (print-range r vf end-corr)&lt;br /&gt;
  (define elec-start (first r))&lt;br /&gt;
  (define elec-end   (second r))&lt;br /&gt;
  (define phys-start (* elec-start vf end-corr))&lt;br /&gt;
  (define phys-end   (* elec-end   vf end-corr))&lt;br /&gt;
  (define s1 (~r elec-start #:precision 1))&lt;br /&gt;
  (define s2 (~r elec-end   #:precision 1))&lt;br /&gt;
  (define p1 (~r phys-start #:precision 1))&lt;br /&gt;
  (define p2 (~r phys-end   #:precision 1))&lt;br /&gt;
  (if (equal? s1 s2)&lt;br /&gt;
      (printf &amp;quot;~a m (elektrisk)  →  ~a m (fysisk)\n&amp;quot; s1 p1)&lt;br /&gt;
      (printf &amp;quot;~a–~a m (elektrisk)  →  ~a–~a m (fysisk)\n&amp;quot; s1 s2 p1 p2)))&lt;br /&gt;
&lt;br /&gt;
;; ====================== HUVUDFUNKTION ======================&lt;br /&gt;
(define (print-suggestions&lt;br /&gt;
         #:min-L     [min-L     10.0]&lt;br /&gt;
         #:max-L     [max-L     70.0]&lt;br /&gt;
         #:step      [step      0.01]&lt;br /&gt;
         #:tol       [tol       0.03]&lt;br /&gt;
         #:vf        [vf        0.96]&lt;br /&gt;
         #:end-corr  [end-corr  0.97])&lt;br /&gt;
  &lt;br /&gt;
  (define goods (good-lengths min-L max-L step tol))&lt;br /&gt;
  (define ranges (group-into-ranges goods step))&lt;br /&gt;
&lt;br /&gt;
  (printf &amp;quot;=== Bra längdintervall för ändmatad antenn ===\n&amp;quot;)&lt;br /&gt;
  (printf &amp;quot;Intervall: ~a–~a m   Steg: ~a m   Tolerans: ~a%\n&amp;quot; &lt;br /&gt;
          min-L max-L step (* tol 100))&lt;br /&gt;
  (printf &amp;quot;VF: ~a   End-effect: ~a (~a% förkortning)\n\n&amp;quot;&lt;br /&gt;
          vf end-corr (round (* (- 1 end-corr) 100)))&lt;br /&gt;
&lt;br /&gt;
  (if (null? ranges)&lt;br /&gt;
      (printf &amp;quot;Inga bra längder hittades.\n&amp;quot;)&lt;br /&gt;
      (begin&lt;br /&gt;
        (for ([r ranges])&lt;br /&gt;
          (print-range r vf end-corr))&lt;br /&gt;
        (printf &amp;quot;\nTotalt ~a bra intervall (~a punkter).\n&amp;quot; &lt;br /&gt;
                (length ranges) (length goods))))&lt;br /&gt;
&lt;br /&gt;
  (printf &amp;quot;\n&amp;quot;))&lt;br /&gt;
  &lt;br /&gt;
;; =====================================================&lt;br /&gt;
;; KÖR PROGRAMMET&lt;br /&gt;
;; =====================================================&lt;br /&gt;
&lt;br /&gt;
(print-suggestions &lt;br /&gt;
  #:min-L 7        ;; Kortaste antenntråden att kika på&lt;br /&gt;
  #:max-L 50       ;; Längsta antenntråden att kika på&lt;br /&gt;
  #:step 0.01      ;; Steglängd i meter&lt;br /&gt;
  #:tol 0.03       ;; Hur nära resonans tillåter vi (3% = 0.03)&lt;br /&gt;
  #:vf 0.96        ;; Hastighetsfaktorn för plastad koppartråd&lt;br /&gt;
  #:end-corr 0.97  ;; Ändkorrigerinsfaktor&lt;br /&gt;
  )&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>Anders</name></author>
	</entry>
	<entry>
		<id>http://wiki.sikvall.se/index.php?title=Racket&amp;diff=1900</id>
		<title>Racket</title>
		<link rel="alternate" type="text/html" href="http://wiki.sikvall.se/index.php?title=Racket&amp;diff=1900"/>
		<updated>2026-06-21T21:21:54Z</updated>

		<summary type="html">&lt;p&gt;Anders: /* Kodexempel (Sommarhack 2026) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Racket är ett programmeringsspråk i Lispfamiljen och underfamilj till Scheme. Det är kompatibelt med Scheme R5RS och andra varianter men har också ett eget väl utbyggt bibliotek av funktioner och rutiner och kanske en av de enklaste språken att komma igång och skapa GUI-applikationer i.&lt;br /&gt;
&lt;br /&gt;
= Installation Ubuntu = &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
sudo add-apt-repository ppa:plt/racket -y&lt;br /&gt;
sudo apt update &lt;br /&gt;
sudo apt install racket&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Kör igång det inbyggda IDE:t med &amp;quot;drracket&amp;quot; antingen från applikationsmenyn eller terminalen.&lt;br /&gt;
&lt;br /&gt;
= Kodexempel (Sommarhack 2026) =&lt;br /&gt;
&lt;br /&gt;
# [[Racket/Erastothenes]]&lt;br /&gt;
# [[Racket/Hexdump]]&lt;br /&gt;
# [[Racket/base24]]&lt;br /&gt;
# [[Racket/Personreg]]&lt;br /&gt;
# [[Racket/Fisher-Yates Shuffle]]&lt;br /&gt;
# [[Racket/RLE]]&lt;br /&gt;
# [[Racket/Lille-GUI]]&lt;br /&gt;
# [[Racket/Multitråd]]&lt;br /&gt;
# [[Racket/6502-emu]]&lt;br /&gt;
# [[Racket/Genetic]]&lt;br /&gt;
# [[Racket/Markov]]&lt;br /&gt;
# [[Racket/Neural]]&lt;br /&gt;
# [[Racket/Posits]]&lt;br /&gt;
# [[Racket/3D-boll]] -- från Olme&lt;br /&gt;
&lt;br /&gt;
= Andra kodexempel =&lt;br /&gt;
&lt;br /&gt;
# [[Racket/EFRW]]&lt;br /&gt;
&lt;br /&gt;
[[category:Racket]]&lt;br /&gt;
[[category:Programmering]]&lt;br /&gt;
[[category:Algoritmer]]&lt;br /&gt;
[[category:Förgreningssida]]&lt;/div&gt;</summary>
		<author><name>Anders</name></author>
	</entry>
	<entry>
		<id>http://wiki.sikvall.se/index.php?title=Racket/Fisher-Yates_Shuffle&amp;diff=1899</id>
		<title>Racket/Fisher-Yates Shuffle</title>
		<link rel="alternate" type="text/html" href="http://wiki.sikvall.se/index.php?title=Racket/Fisher-Yates_Shuffle&amp;diff=1899"/>
		<updated>2026-05-18T14:11:41Z</updated>

		<summary type="html">&lt;p&gt;Anders: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#lang racket&lt;br /&gt;
&lt;br /&gt;
;; Fisher-Yates shuffle för en lista (modern version, O(n))&lt;br /&gt;
(define (fisher-yates lst)&lt;br /&gt;
  (let ([v (list-&amp;gt;vector lst)])          ; Konvertera till vektor för effektiv mutation&lt;br /&gt;
    (for ([i (in-range (sub1 (vector-length v)) -1 -1)])  ; från n-1 ner till 1&lt;br /&gt;
      (let ([j (random (add1 i))])       ; slumpmässigt index 0 till i (inklusive)&lt;br /&gt;
        ;; Byt plats mellan i och j&lt;br /&gt;
        (let ([temp (vector-ref v i)])&lt;br /&gt;
          (vector-set! v i (vector-ref v j))&lt;br /&gt;
          (vector-set! v j temp))))&lt;br /&gt;
    (vector-&amp;gt;list v)))                   ; Returnera som lista igen&lt;br /&gt;
&lt;br /&gt;
;; Exempel:&lt;br /&gt;
(fisher-yates &#039;(1 2 3 4 5 6 7 8 9 10))&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>Anders</name></author>
	</entry>
	<entry>
		<id>http://wiki.sikvall.se/index.php?title=Racket/Fisher-Yates_Shuffle&amp;diff=1898</id>
		<title>Racket/Fisher-Yates Shuffle</title>
		<link rel="alternate" type="text/html" href="http://wiki.sikvall.se/index.php?title=Racket/Fisher-Yates_Shuffle&amp;diff=1898"/>
		<updated>2026-05-18T14:11:24Z</updated>

		<summary type="html">&lt;p&gt;Anders: Skapade sidan med &amp;#039;#lang racket  ;; Fisher-Yates shuffle för en lista (modern version, O(n)) (define (fisher-yates lst)   (let ([v (list-&amp;gt;vector lst)])          ; Konvertera till vektor för effektiv mutation     (for ([i (in-range (sub1 (vector-length v)) -1 -1)])  ; från n-1 ner till 1       (let ([j (random (add1 i))])       ; slumpmässigt index 0 till i (inklusive)         ;; Byt plats mellan i och j         (let ([temp (vector-ref v i)])           (vector-set! v i (vector-ref v j))...&amp;#039;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;#lang racket&lt;br /&gt;
&lt;br /&gt;
;; Fisher-Yates shuffle för en lista (modern version, O(n))&lt;br /&gt;
(define (fisher-yates lst)&lt;br /&gt;
  (let ([v (list-&amp;gt;vector lst)])          ; Konvertera till vektor för effektiv mutation&lt;br /&gt;
    (for ([i (in-range (sub1 (vector-length v)) -1 -1)])  ; från n-1 ner till 1&lt;br /&gt;
      (let ([j (random (add1 i))])       ; slumpmässigt index 0 till i (inklusive)&lt;br /&gt;
        ;; Byt plats mellan i och j&lt;br /&gt;
        (let ([temp (vector-ref v i)])&lt;br /&gt;
          (vector-set! v i (vector-ref v j))&lt;br /&gt;
          (vector-set! v j temp))))&lt;br /&gt;
    (vector-&amp;gt;list v)))                   ; Returnera som lista igen&lt;br /&gt;
&lt;br /&gt;
;; Exempel:&lt;br /&gt;
(fisher-yates &#039;(1 2 3 4 5 6 7 8 9 10))&lt;/div&gt;</summary>
		<author><name>Anders</name></author>
	</entry>
	<entry>
		<id>http://wiki.sikvall.se/index.php?title=Racket&amp;diff=1897</id>
		<title>Racket</title>
		<link rel="alternate" type="text/html" href="http://wiki.sikvall.se/index.php?title=Racket&amp;diff=1897"/>
		<updated>2026-05-18T14:11:17Z</updated>

		<summary type="html">&lt;p&gt;Anders: /* Kodexempel (Sommarhack 2026) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Racket är ett programmeringsspråk i Lispfamiljen och underfamilj till Scheme. Det är kompatibelt med Scheme R5RS och andra varianter men har också ett eget väl utbyggt bibliotek av funktioner och rutiner och kanske en av de enklaste språken att komma igång och skapa GUI-applikationer i.&lt;br /&gt;
&lt;br /&gt;
= Installation Ubuntu = &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
sudo add-apt-repository ppa:plt/racket -y&lt;br /&gt;
sudo apt update &lt;br /&gt;
sudo apt install racket&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Kör igång det inbyggda IDE:t med &amp;quot;drracket&amp;quot; antingen från applikationsmenyn eller terminalen.&lt;br /&gt;
&lt;br /&gt;
= Kodexempel (Sommarhack 2026) =&lt;br /&gt;
&lt;br /&gt;
# [[Racket/Erastothenes]]&lt;br /&gt;
# [[Racket/Hexdump]]&lt;br /&gt;
# [[Racket/base24]]&lt;br /&gt;
# [[Racket/Personreg]]&lt;br /&gt;
# [[Racket/Fisher-Yates Shuffle]]&lt;br /&gt;
# [[Racket/RLE]]&lt;br /&gt;
# [[Racket/Lille-GUI]]&lt;br /&gt;
# [[Racket/Multitråd]]&lt;br /&gt;
# [[Racket/6502-emu]]&lt;br /&gt;
# [[Racket/Genetic]]&lt;br /&gt;
# [[Racket/Markov]]&lt;br /&gt;
# [[Racket/Neural]]&lt;br /&gt;
# [[Racket/Posits]]&lt;br /&gt;
# [[Racket/3D-boll]] -- från Olme&lt;br /&gt;
&lt;br /&gt;
[[category:Racket]]&lt;br /&gt;
[[category:Programmering]]&lt;br /&gt;
[[category:Algoritmer]]&lt;br /&gt;
[[category:Förgreningssida]]&lt;/div&gt;</summary>
		<author><name>Anders</name></author>
	</entry>
	<entry>
		<id>http://wiki.sikvall.se/index.php?title=Fisher-Yates_Shuffle&amp;diff=1896</id>
		<title>Fisher-Yates Shuffle</title>
		<link rel="alternate" type="text/html" href="http://wiki.sikvall.se/index.php?title=Fisher-Yates_Shuffle&amp;diff=1896"/>
		<updated>2026-05-18T14:10:45Z</updated>

		<summary type="html">&lt;p&gt;Anders: /* C */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Bakgrund ==&lt;br /&gt;
&lt;br /&gt;
Fisher-Yates är en algoritm som används för att slumpmässigt omfördela innehållet i en grupp på ett sätt som fungerar ungefär som när man blandar en kortlek. Det ger minsta möjliga bias även om pseudoslumptalskällan inte är välfiltrerad och ren.&lt;br /&gt;
&lt;br /&gt;
Sättet som algoritmen arbetar på fungerar ungefär som när man plockar lotter ur en tombola eller blandar en kortlek där man drar en efter en tills det inte längre finns några att dra. Rätt använd är biasen väldigt låg.&lt;br /&gt;
&lt;br /&gt;
Andra namn är också &#039;&#039;the Knuth Shuffle&#039;&#039; efter matematikern Donald E. Knuth som använder denna.&lt;br /&gt;
&lt;br /&gt;
== Funktion ==&lt;br /&gt;
&lt;br /&gt;
Som ett exempel skall vi permutera numren 1 till 8 genom att använda Fisher-Yates metod. Vi skriver talen på en bit papper:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Range !! Roll !! Scratch !! Result&lt;br /&gt;
|-&lt;br /&gt;
| &amp;amp;nbsp; || &amp;amp;nbsp; || 1 2 3 4 5 6 7 8 || &amp;amp;nbsp;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Nu slumpar vi ett tal &#039;&#039;k&#039;&#039; mellan 1-8, vi kan säga att det blev 3 så vi stryker det 3:e numret från papperet och flyttar det till resultatrutan.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Range !! Roll !! Scratch !! Result&lt;br /&gt;
|-&lt;br /&gt;
| 1–8 || 3 || 1 2 &amp;lt;s&amp;gt;3&amp;lt;/s&amp;gt; 4 5 6 7 8 || 3&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Vi tar ett nytt slumpmässigt tal, denna gång från 1-7 som matchar de siffror vi ej har strukit. Låt oss säga att det blev 4, så vi stryker det fjärde ej redan strukna numret och flyttar det till resultatrutan.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Range !! Roll !! Scratch !! Result&lt;br /&gt;
|-&lt;br /&gt;
| 1–7 || 4 || 1 2 &amp;lt;s&amp;gt;3&amp;lt;&amp;lt;/s&amp;gt; 4 &amp;lt;s&amp;gt;5&amp;lt;/s&amp;gt; 6 7 8 || 3 5&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Vi fortsätter på samma vis med ett nytt slumptal, denna gång från 1-6 och sedan 1-5 osv ända tills alla tal är strukna.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Range !! Roll !! Scratch !! Result&lt;br /&gt;
|-&lt;br /&gt;
| 1-6 || 5 || 1 2 &amp;lt;s&amp;gt;3&amp;lt;/s&amp;gt; 4 &amp;lt;s&amp;gt;5&amp;lt;/s&amp;gt; 6 &amp;lt;s&amp;gt;7&amp;lt;/s&amp;gt; 8 || 3 5 7&lt;br /&gt;
|-&lt;br /&gt;
| 1-5 || 3 || 1 2 &amp;lt;s&amp;gt;3&amp;lt;/s&amp;gt; &amp;lt;s&amp;gt;4&amp;lt;/s&amp;gt; &amp;lt;s&amp;gt;5&amp;lt;/s&amp;gt; 6 &amp;lt;s&amp;gt;7&amp;lt;/s&amp;gt; 8 || 3 5 7 4&lt;br /&gt;
|-&lt;br /&gt;
| 1-4 || 4 || 1 2 &amp;lt;s&amp;gt;3&amp;lt;/s&amp;gt; &amp;lt;s&amp;gt;4&amp;lt;/s&amp;gt; &amp;lt;s&amp;gt;5&amp;lt;/s&amp;gt; 6 &amp;lt;s&amp;gt;7&amp;lt;/s&amp;gt; &amp;lt;s&amp;gt;8&amp;lt;/s&amp;gt; || 3 5 7 4 8&lt;br /&gt;
|-&lt;br /&gt;
| 1-3 || 1 || &amp;lt;s&amp;gt;1&amp;lt;/s&amp;gt; 2 &amp;lt;s&amp;gt;3&amp;lt;/s&amp;gt; &amp;lt;s&amp;gt;4&amp;lt;/s&amp;gt; &amp;lt;s&amp;gt;5&amp;lt;/s&amp;gt; 6 &amp;lt;s&amp;gt;7&amp;lt;/s&amp;gt; &amp;lt;s&amp;gt;8&amp;lt;/s&amp;gt; || 3 5 7 4 8 1&lt;br /&gt;
|-&lt;br /&gt;
| 1-2 || 2 || &amp;lt;s&amp;gt;1&amp;lt;/s&amp;gt; 2 &amp;lt;s&amp;gt;3&amp;lt;/s&amp;gt; &amp;lt;s&amp;gt;4&amp;lt;/s&amp;gt; &amp;lt;s&amp;gt;5&amp;lt;/s&amp;gt; &amp;lt;s&amp;gt;6&amp;lt;/s&amp;gt; &amp;lt;s&amp;gt;7&amp;lt;/s&amp;gt; &amp;lt;s&amp;gt;8&amp;lt;/s&amp;gt; || 3 5 7 4 8 1 6&lt;br /&gt;
|-&lt;br /&gt;
| &amp;amp;nbsp; || &amp;amp;nbsp; || &amp;lt;s&amp;gt;1&amp;lt;/s&amp;gt; &amp;lt;s&amp;gt;2&amp;lt;/s&amp;gt; &amp;lt;s&amp;gt;3&amp;lt;/s&amp;gt; &amp;lt;s&amp;gt;4&amp;lt;/s&amp;gt; &amp;lt;s&amp;gt;5&amp;lt;/s&amp;gt; &amp;lt;s&amp;gt;6&amp;lt;/s&amp;gt; &amp;lt;s&amp;gt;7&amp;lt;/s&amp;gt; &amp;lt;s&amp;gt;8&amp;lt;/s&amp;gt; || 3 5 7 4 8 1 6 2&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
För att spara tid kan man byta plats med alla strukna tal och det sista talet i serien och därmed hela tiden ha en sammanhängande ordning med ostrukna tal. Se pseudokoden nedan som gör på det sättet.&lt;br /&gt;
&lt;br /&gt;
= Implementation = &lt;br /&gt;
&lt;br /&gt;
== Pseudokod ==&lt;br /&gt;
&lt;br /&gt;
Randomisera n element på plats i en array&lt;br /&gt;
&lt;br /&gt;
 for i from n-1 down to 1 do&lt;br /&gt;
     j = random(0..i)&lt;br /&gt;
     swap a[j], a[i]&lt;br /&gt;
 done&lt;br /&gt;
&lt;br /&gt;
Initialisera en array a med n elements från en slumpmässigt ordnad kopia av source&lt;br /&gt;
&lt;br /&gt;
 a[0] = source[0]&lt;br /&gt;
 for i from 1 to n-1 do&lt;br /&gt;
     j = random(0..i)&lt;br /&gt;
     a[i] = a[j]&lt;br /&gt;
     a[j] = source[i]&lt;br /&gt;
 done&lt;br /&gt;
&lt;br /&gt;
== C ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;lt;time.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
void fyshuffle(int *array, size_t n)&lt;br /&gt;
{&lt;br /&gt;
  size_t i, j;  // Elements in array to swap&lt;br /&gt;
  int temp;     // Temp store&lt;br /&gt;
  &lt;br /&gt;
  // Set the random generator using current time&lt;br /&gt;
  srand((unsigned int)time(NULL));&lt;br /&gt;
  for (i = n - 1; i &amp;gt; 0; i--) {&lt;br /&gt;
    j = rand() % (i + 1);&lt;br /&gt;
    int temp = array[j];&lt;br /&gt;
    array[j] = array[i];&lt;br /&gt;
    array[i] = temp;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
int main(int argc, char *argv[]) {&lt;br /&gt;
  int array[15] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14};&lt;br /&gt;
  int i;&lt;br /&gt;
&lt;br /&gt;
  fyshuffle(array, 15);&lt;br /&gt;
&lt;br /&gt;
  for (i = 0; i &amp;lt; 15; i++) {&lt;br /&gt;
    printf(&amp;quot;%d &amp;quot;, array[i]);&lt;br /&gt;
  }&lt;br /&gt;
  printf(&amp;quot;\n&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Racket ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#lang racket&lt;br /&gt;
&lt;br /&gt;
;; Fisher-Yates shuffle för en lista (modern version, O(n))&lt;br /&gt;
(define (fisher-yates lst)&lt;br /&gt;
  (let ([v (list-&amp;gt;vector lst)])          ; Konvertera till vektor för effektiv mutation&lt;br /&gt;
    (for ([i (in-range (sub1 (vector-length v)) -1 -1)])  ; från n-1 ner till 1&lt;br /&gt;
      (let ([j (random (add1 i))])       ; slumpmässigt index 0 till i (inklusive)&lt;br /&gt;
        ;; Byt plats mellan i och j&lt;br /&gt;
        (let ([temp (vector-ref v i)])&lt;br /&gt;
          (vector-set! v i (vector-ref v j))&lt;br /&gt;
          (vector-set! v j temp))))&lt;br /&gt;
    (vector-&amp;gt;list v)))                   ; Returnera som lista igen&lt;br /&gt;
&lt;br /&gt;
;; Exempel:&lt;br /&gt;
(fisher-yates &#039;(1 2 3 4 5 6 7 8 9 10))&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[category:Programmering]]&lt;br /&gt;
[[category:Algoritmer]]&lt;br /&gt;
[[category:c]]&lt;/div&gt;</summary>
		<author><name>Anders</name></author>
	</entry>
	<entry>
		<id>http://wiki.sikvall.se/index.php?title=Huvudsida&amp;diff=1895</id>
		<title>Huvudsida</title>
		<link rel="alternate" type="text/html" href="http://wiki.sikvall.se/index.php?title=Huvudsida&amp;diff=1895"/>
		<updated>2026-05-18T14:07:59Z</updated>

		<summary type="html">&lt;p&gt;Anders: /* Särskilt utvalda sidor */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Om mig = &lt;br /&gt;
&lt;br /&gt;
Ansvarig för denna Wiki är Anders Sikvall&lt;br /&gt;
[mailto:anders@sikvall.se anders@sikvall.se] (Proton mail krypterad)&lt;br /&gt;
&lt;br /&gt;
Du kan hitta min PGP/GPG-nyckel på denna URL:&lt;br /&gt;
[https://sikvall.se/pgp/anders@sikvall.se https://sikvall.se/pgp/anders@sikvall.se]&lt;br /&gt;
&lt;br /&gt;
Min hemsida finns på: &lt;br /&gt;
[https://sikvall.se/ https://sikvall.se/]&lt;br /&gt;
&lt;br /&gt;
= Specialsidor =&lt;br /&gt;
&lt;br /&gt;
Specialsidor är länkar till sidor som omfattar meta-information.&lt;br /&gt;
&lt;br /&gt;
* [[:Special:Categories|Alla kategorier]]&lt;br /&gt;
* [[:Special:AllPages|Alla sidor]]&lt;br /&gt;
* [[dBµV/m]]&lt;br /&gt;
&lt;br /&gt;
= Särskilt utvalda sidor =&lt;br /&gt;
&lt;br /&gt;
== Krypto ==&lt;br /&gt;
&lt;br /&gt;
* [[GPG]]&lt;br /&gt;
&lt;br /&gt;
== Programmering ==&lt;br /&gt;
&lt;br /&gt;
* [[Fisher-Yates Shuffle]]&lt;br /&gt;
* [[Base64]] [[Base32]] [[Base24]]&lt;br /&gt;
* [[Racket]]&lt;br /&gt;
&lt;br /&gt;
== Elektronik ==&lt;br /&gt;
&lt;br /&gt;
* [[Peukerts lag]] - [[Blyackumulator laddningstabell]]&lt;br /&gt;
* [[Pi-dämpare]]&lt;br /&gt;
&lt;br /&gt;
== Radiorelaterat ==&lt;br /&gt;
&lt;br /&gt;
* [[Amatörradio]]&lt;br /&gt;
* [[Jaktradio 155 MHz]] - [[PMR446]] - [[KDR 444]]&lt;br /&gt;
* [[Q-koden]] - [[Morsealfabetet]] - [[Svenska bokstaveringsalfabetet]]&lt;br /&gt;
* [[AM]] - [[FM]] - [[SSB]] - [[CW]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Linux ==&lt;br /&gt;
&lt;br /&gt;
* [[Diskimage i Linux]]&lt;br /&gt;
* [[Git]]&lt;br /&gt;
* [[Temporär download]]&lt;br /&gt;
* [[Swapfil i BTRFS]]&lt;br /&gt;
* [[Automatiskt tömma soptunnan]]&lt;br /&gt;
&lt;br /&gt;
== LaTeX Dokumentation ==&lt;br /&gt;
&lt;br /&gt;
* [[Brevmall]]&lt;br /&gt;
* [[Svensk stilmall]]&lt;br /&gt;
* [[Tips och Tricks i LaTeX]]&lt;br /&gt;
&lt;br /&gt;
== Friluftsliv ==&lt;br /&gt;
* [[:category:Pannlampor|Pannlampor]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;L_f&amp;lt;/math&amp;gt;&lt;/div&gt;</summary>
		<author><name>Anders</name></author>
	</entry>
	<entry>
		<id>http://wiki.sikvall.se/index.php?title=Svensk_stilmall&amp;diff=1894</id>
		<title>Svensk stilmall</title>
		<link rel="alternate" type="text/html" href="http://wiki.sikvall.se/index.php?title=Svensk_stilmall&amp;diff=1894"/>
		<updated>2026-05-12T09:01:36Z</updated>

		<summary type="html">&lt;p&gt;Anders: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%&lt;br /&gt;
% ichiswedish.sty    version 1.2   date 09-JUL-2000                    %&lt;br /&gt;
%                                                                      %&lt;br /&gt;
% This style is to typeset Swedish documents in LaTeX. It is designed  %&lt;br /&gt;
% with and works well in the MikTeX environment, however it should not %&lt;br /&gt;
% be difficult to get it working well in other environments either.    %&lt;br /&gt;
%                                                                      %&lt;br /&gt;
% Any suggestions you might have on this are welcome, plese send them  %&lt;br /&gt;
% to the following email address &amp;lt;anders@sikvall.se&amp;gt; and I will        %&lt;br /&gt;
% consider incorporating them to the next release                      %&lt;br /&gt;
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%&lt;br /&gt;
% Packages that we want to be loaded ALL THE TIME %&lt;br /&gt;
% when typesetting swedish text.                  %&lt;br /&gt;
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%&lt;br /&gt;
&lt;br /&gt;
% Swedish typography&lt;br /&gt;
\usepackage[swedish]{babel}&lt;br /&gt;
&lt;br /&gt;
% Input encodings, make it easier to encode special latin &lt;br /&gt;
% characters like  å ä ö Å Ä Ö by typing them instead of&lt;br /&gt;
% using {\&amp;quot;a} for ä &amp;amp;c.&lt;br /&gt;
\usepackage[ansinew]{inputenc}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%&lt;br /&gt;
% Settings specially for swedish %&lt;br /&gt;
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%&lt;br /&gt;
&lt;br /&gt;
% Decimal comma&lt;br /&gt;
\mathchardef\CommaOrdinary=&amp;quot;013B&lt;br /&gt;
\mathchardef\CommaPunct   =&amp;quot;613B&lt;br /&gt;
\mathcode`,=&amp;quot;8000&lt;br /&gt;
{\catcode`\,=\active&lt;br /&gt;
\gdef ,{\obeyspaces\futurelet\next\CommaCheck}}&lt;br /&gt;
\def\CommaCheck{\if\space\next\CommaPunct\else\CommaOrdinary\fi}&lt;br /&gt;
&lt;br /&gt;
% Get rid of the spacing used in english typesetting&lt;br /&gt;
\frenchspacing&lt;br /&gt;
&lt;br /&gt;
% Paragraph indentation style&lt;br /&gt;
\setlength{\parindent}{1em}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%&lt;br /&gt;
% Common abbreviations in Swedish %&lt;br /&gt;
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%&lt;br /&gt;
&lt;br /&gt;
\usepackage{xspace}&lt;br /&gt;
\newcommand{\bla}{bl.\hspace{0.1em}a.\xspace}&lt;br /&gt;
\newcommand{\ca}{ca\xspace}&lt;br /&gt;
\newcommand{\dvs}{dvs.\xspace}&lt;br /&gt;
\newcommand{\etc}{etc.\xspace}&lt;br /&gt;
\newcommand{\kl}{kl.\xspace}&lt;br /&gt;
\newcommand{\mfl}{m.\hspace{0.1em}fl.\xspace}&lt;br /&gt;
\newcommand{\mm}{m.\hspace{0.1em}m.\xspace}&lt;br /&gt;
\newcommand{\obs}{obs.\xspace}&lt;br /&gt;
\newcommand{\osv}{osv.\xspace}&lt;br /&gt;
\newcommand{\pga}{p.\hspace{0.1em}g.\hspace{0.1em}a.\xspace}&lt;br /&gt;
\newcommand{\sk}{s.\hspace{0.1em}k.\xspace}&lt;br /&gt;
\newcommand{\tillex}{t.\hspace{0.1em}ex.\xspace}&lt;br /&gt;
&lt;br /&gt;
% END&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
[[category:LaTeX]]&lt;/div&gt;</summary>
		<author><name>Anders</name></author>
	</entry>
	<entry>
		<id>http://wiki.sikvall.se/index.php?title=Brevmall&amp;diff=1893</id>
		<title>Brevmall</title>
		<link rel="alternate" type="text/html" href="http://wiki.sikvall.se/index.php?title=Brevmall&amp;diff=1893"/>
		<updated>2026-05-12T08:59:48Z</updated>

		<summary type="html">&lt;p&gt;Anders: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[category:LaTeX]]&lt;br /&gt;
Detta är min standard brevmall som jag använder tillsammans med [[Svensk stilmall]] när jag skriver brev i LaTeX.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%&lt;br /&gt;
%% Letter Template for LaTeX&lt;br /&gt;
%%&lt;br /&gt;
%% Anders Sikvall&lt;br /&gt;
%% (C)2003 - Free for Personal use&lt;br /&gt;
%%&lt;br /&gt;
%% Improvmenets welcome, email to anders@sikvall.se please.&lt;br /&gt;
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%&lt;br /&gt;
&lt;br /&gt;
\documentclass[a4paper, 12pt, oneside]{letter}&lt;br /&gt;
\usepackage{a4}&lt;br /&gt;
\usepackage[ansinew]{inputenc}&lt;br /&gt;
\usepackage[T1]{fontenc}&lt;br /&gt;
\usepackage[swedish]{babel}&lt;br /&gt;
%\usepackage{palatino}&lt;br /&gt;
%\usepackage{bookman}&lt;br /&gt;
%\usepackage{utopia}&lt;br /&gt;
\usepackage{times}&lt;br /&gt;
%\usepackage{newcent}&lt;br /&gt;
%\usepackage{charter}&lt;br /&gt;
%\usepackage{avant}&lt;br /&gt;
%\usepackage{chancery}&lt;br /&gt;
%\usepackage{euler}&lt;br /&gt;
\name{YOUR NAME}&lt;br /&gt;
\signature{YOUR NAME/SIGNATURE}&lt;br /&gt;
\address{YOUR NAME AND ADDRESS}&lt;br /&gt;
&lt;br /&gt;
\begin{document}&lt;br /&gt;
&lt;br /&gt;
\begin{letter}{TO WHOM}&lt;br /&gt;
%% \begin{raggedright}&lt;br /&gt;
\opening{\underline{\textbf{START OF LETTER}}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
\closing{YOUR NAME}&lt;br /&gt;
&lt;br /&gt;
% If you want to enclose other documents, specify them here.&lt;br /&gt;
%% \encl{Bilaga 1}&lt;br /&gt;
&lt;br /&gt;
\end{letter}&lt;br /&gt;
\end{document}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>Anders</name></author>
	</entry>
	<entry>
		<id>http://wiki.sikvall.se/index.php?title=IP3&amp;diff=1892</id>
		<title>IP3</title>
		<link rel="alternate" type="text/html" href="http://wiki.sikvall.se/index.php?title=IP3&amp;diff=1892"/>
		<updated>2026-05-12T08:20:52Z</updated>

		<summary type="html">&lt;p&gt;Anders: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Tredje ordningens skärningspunkt =&lt;br /&gt;
&lt;br /&gt;
Kan definieras antingen som en harmonisk produkt till en enkel ton, eller som de två IM3-produkter som uppträder vid två stycken signaler genom en icke-linjär krets. När man ökar nyttosignalens storlek växer IM3 med 3 dB per dB nyttosignalerna ökas. Därför uppstår en skärningspunkt så småningom och det är denna som definieras som IP3 (intercept point 3rd order).&lt;br /&gt;
&lt;br /&gt;
Med alla enheter i dB får vi följande:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; \text{OIP}_3 = P + \Delta \text{IM}_3 / 2 &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Där &amp;lt;math&amp;gt;\Delta \text{IM}_3&amp;lt;/math&amp;gt; är hyr mycket högre nyttosignalen är från den högsta intermodulationsprodukten. Dvs om du har en nyttosignal på 30 dBm vilket ger en IM3 produkt på -36 dBm blir formeln&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;   \text{OIP}_3 = 30 \text{ dBm} + 66 \text{ dBc} / 2 = 63 \text{ dBm}   &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Tredje ordningens IM-produkter =&lt;br /&gt;
&lt;br /&gt;
Formlerna ger de frekvenser som IM3 uppstår vid om man sänder 2 st signaler med frekvenserna f1 och f2 genom en ickelinjär krets:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\text{IP}_{3:1} = 2f_1-f_2&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\text{IP}_{3:2}=2f_2-f_1&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[category:Radio]]&lt;br /&gt;
[[category:Fysik]]&lt;br /&gt;
[[Category:Formelsamling]]&lt;br /&gt;
[[category:IM3]]&lt;br /&gt;
[[category:IP3]]&lt;br /&gt;
[[category:Intermodulation]]&lt;/div&gt;</summary>
		<author><name>Anders</name></author>
	</entry>
	<entry>
		<id>http://wiki.sikvall.se/index.php?title=IP3&amp;diff=1891</id>
		<title>IP3</title>
		<link rel="alternate" type="text/html" href="http://wiki.sikvall.se/index.php?title=IP3&amp;diff=1891"/>
		<updated>2026-05-12T08:14:38Z</updated>

		<summary type="html">&lt;p&gt;Anders: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Tredje ordningens skärningspunkt =&lt;br /&gt;
&lt;br /&gt;
Kan definieras antingen som en harmonisk produkt till en enkel ton, eller som de två IM3-produkter som uppträder vid två stycken signaler genom en icke-linjär krets. När man ökar nyttosignalens storlek växer IM3 med 3 dB per dB nyttosignalerna ökas. Därför uppstår en skärningspunkt så småningom och det är denna som definieras som IP3 (intercept point 3rd order).&lt;br /&gt;
&lt;br /&gt;
Denna kan beräknas enligt:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; OIP3 = P + IM_{3} / 2 &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Tredje ordningens IM-produkter =&lt;br /&gt;
&lt;br /&gt;
Formlerna ger de frekvenser som IM3 uppstår vid om man sänder 2 st signaler med frekvenserna f1 och f2 genom en ickelinjär krets:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\text{IP}_{3:1} = 2f_1-f_2&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\text{IP}_{3:2}=2f_2-f_1&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[category:Radio]]&lt;br /&gt;
[[category:Fysik]]&lt;br /&gt;
[[Category:Formelsamling]]&lt;br /&gt;
[[category:IM3]]&lt;br /&gt;
[[category:IP3]]&lt;br /&gt;
[[category:Intermodulation]]&lt;/div&gt;</summary>
		<author><name>Anders</name></author>
	</entry>
	<entry>
		<id>http://wiki.sikvall.se/index.php?title=Okamura-Hata_formel_f%C3%B6r_urban_radioutbredning&amp;diff=1890</id>
		<title>Okamura-Hata formel för urban radioutbredning</title>
		<link rel="alternate" type="text/html" href="http://wiki.sikvall.se/index.php?title=Okamura-Hata_formel_f%C3%B6r_urban_radioutbredning&amp;diff=1890"/>
		<updated>2026-05-12T08:08:38Z</updated>

		<summary type="html">&lt;p&gt;Anders: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Bakgrund ==&lt;br /&gt;
&lt;br /&gt;
Utbredningsformeln för [[Friis formel för frirumsutbredning|frirumsutbredning]] fungerar inte särskilt bra i urbana miljöer och därför sökte herrarna Okamura och Hata efter en förbättrad variant. Efter många praktiska prov kom man fram till att man approximera utbredningen på större avstånd enligt följande formel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\mathrm{FSPL}=20\log_{10}{(f)} + (20+K)\log_{10}{(d)} + 32,45&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Där:&lt;br /&gt;
:&#039;&#039;f&#039;&#039; är frekvensen [MHz]&lt;br /&gt;
:&#039;&#039;d&#039;&#039; är avståndet mellan sändare och mottagare [km]&lt;br /&gt;
:&#039;&#039;K&#039;&#039; är den så kallade Okamura-Hata-konstanten&lt;br /&gt;
&lt;br /&gt;
Konstanten 32,45 kan härledas ur den klassiska formeln för [[Friis formel för frirumsutbredning|Free space path loss]] med enheterna i MHz och km i stället för exempelvis Hz och meter.&lt;br /&gt;
&lt;br /&gt;
Konstanten K antar olika värden beroende på terrängens beskaffenhet:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;table border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;5&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;th&amp;gt;Värde för K&amp;lt;/th&amp;gt;&lt;br /&gt;
&amp;lt;th&amp;gt;Terrängtyp&amp;lt;/th&amp;gt;&lt;br /&gt;
&amp;lt;th&amp;gt;Anm.&amp;lt;/th&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;10&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Lätt urban&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Villaområden, svagt kuperad terräng, inga större hinder&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;15&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Urban&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Stadskärnor med lite andel höghus, ibland större hinder&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;20&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Metropolis&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Tung urban miljö, företrädelsevis höghus, Manhattan, stora hinder&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;30&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;Öken&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;Mycket torra områden, stenöken&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[category:Radio]]&lt;br /&gt;
[[category:Formelsamling]]&lt;br /&gt;
[[category:Trådlös kommunikation]]&lt;br /&gt;
[[category:Telekommunikation]]&lt;br /&gt;
[[category:Vågutbredning]]&lt;br /&gt;
[[category:Okamura-Hata]]&lt;/div&gt;</summary>
		<author><name>Anders</name></author>
	</entry>
	<entry>
		<id>http://wiki.sikvall.se/index.php?title=F%C3%A4ltstyrka&amp;diff=1889</id>
		<title>Fältstyrka</title>
		<link rel="alternate" type="text/html" href="http://wiki.sikvall.se/index.php?title=F%C3%A4ltstyrka&amp;diff=1889"/>
		<updated>2026-05-12T07:48:37Z</updated>

		<summary type="html">&lt;p&gt;Anders: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[category:formelsamling]]&lt;br /&gt;
[[category:fältstyrka]]&lt;br /&gt;
[[category:ellära]]&lt;br /&gt;
[[category:radio]]&lt;br /&gt;
[[category:radiolära]]&lt;br /&gt;
[[category:magnetism]]&lt;br /&gt;
[[category:elektricitet]]&lt;br /&gt;
[[category:Närfält]]&lt;br /&gt;
[[category:Fjärrfält]]&lt;br /&gt;
&lt;br /&gt;
= Bakgrund =&lt;br /&gt;
&lt;br /&gt;
Fältstyrkan av en radiosignal avtar linjärt med avståndet från en sändare. Denna kan räknas ut med en enkel formel som stämmer utmärkt i fjärrfältet från antennen. I närfältet är det mer komplicerat.&lt;br /&gt;
&lt;br /&gt;
== Fjärrfältsdefinition ==&lt;br /&gt;
&lt;br /&gt;
För fjärrfältet används vanligen följande approximation vid vilket avstånd från en antenn som vi kan säga iss vara i fjärrfältet:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; r &amp;gt; \frac{2D^2}{\lambda}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Där D är antennens största utbredning i rummet i meter, för den dipol den totala längden, för en Yagi-Uda dess längsta axel, för en parabol omkretsen och &amp;lt;math&amp;gt;\lambda&amp;lt;/math&amp;gt; är våglängden i meter. &amp;lt;math&amp;gt;D^2&amp;lt;/math&amp;gt; är ett mått på antennens &amp;quot;antennarea&amp;quot; och säger något om fältbildning och utbredning i rummet.&lt;br /&gt;
&lt;br /&gt;
= Effekttäthet = &lt;br /&gt;
&lt;br /&gt;
Effekttätheten &amp;lt;math&amp;gt;S&amp;lt;/math&amp;gt; i enenheten W/m² kan beräknas ur sambandet:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
S = \frac{P \cdot G}{2 \pi r^2}&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Elektrisk fältstyrka =&lt;br /&gt;
&lt;br /&gt;
Den elektriska fältstyrkan uttrycks i regel som V/m eller i varianter därav. Vanliga varianter är t.ex. dBµV/m. Detta gäller i fjärrfältet.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
E= \frac{ \sqrt{30 \cdot P \cdot G} } { r }&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Magnetisk fältstyrka = &lt;br /&gt;
&lt;br /&gt;
== Från elektriska fältet ==&lt;br /&gt;
&lt;br /&gt;
Om du redan beräknat den elektriska fältstyrkan kan den magnetiska beräknas så som:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;H = \frac{E}{377} &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Direkt från sändaren ==&lt;br /&gt;
&lt;br /&gt;
Annars från sändarens effekt P och antennens antennvinst G fås:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;H = \frac{\sqrt{30 \cdot P \cdot G}}{377 \cdot r}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Nära en elektrisk ledare ==&lt;br /&gt;
&lt;br /&gt;
Nära en elektrisk ledare, till exempel drivet element hos en antenn så beräknas först strömmen i ledaren och därefter fås magnetfältet med relationen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
H = \frac{I}{2 \pi r}&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Storhetssamling = &lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;margin:auto&amp;quot;&lt;br /&gt;
|+ Storheter och enheter på denna sida&lt;br /&gt;
|-&lt;br /&gt;
! Storhet!! Beteckning!! Enhet&lt;br /&gt;
|-&lt;br /&gt;
| S || Effektdensitet|| W/m²&lt;br /&gt;
|-&lt;br /&gt;
| E || Elektrisk fältstyrka || V/m&lt;br /&gt;
|-&lt;br /&gt;
| H || Magnetisk fältstyrka || A/m&lt;br /&gt;
|-&lt;br /&gt;
| I || Elektrisk ström || A&lt;br /&gt;
|-&lt;br /&gt;
| P || Sändarens effekt || W&lt;br /&gt;
|-&lt;br /&gt;
| G || Antennens förstärkningsfaktor || (dimensionslös)&lt;br /&gt;
|-&lt;br /&gt;
| D || Antennarea || m²&lt;br /&gt;
|-&lt;br /&gt;
| r || Avstånd || m&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Anders</name></author>
	</entry>
	<entry>
		<id>http://wiki.sikvall.se/index.php?title=F%C3%A4ltstyrka&amp;diff=1888</id>
		<title>Fältstyrka</title>
		<link rel="alternate" type="text/html" href="http://wiki.sikvall.se/index.php?title=F%C3%A4ltstyrka&amp;diff=1888"/>
		<updated>2026-05-12T07:47:51Z</updated>

		<summary type="html">&lt;p&gt;Anders: /* Storhetssamling */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[category:formelsamling]]&lt;br /&gt;
[[category:fältstyrka]]&lt;br /&gt;
[[category:ellära]]&lt;br /&gt;
[[category:radio]]&lt;br /&gt;
[[category:radiolära]]&lt;br /&gt;
[[category:magnetism]]&lt;br /&gt;
[[category:elektricitet]]&lt;br /&gt;
&lt;br /&gt;
= Bakgrund =&lt;br /&gt;
&lt;br /&gt;
Fältstyrkan av en radiosignal avtar linjärt med avståndet från en sändare. Denna kan räknas ut med en enkel formel som stämmer utmärkt i fjärrfältet från antennen. I närfältet är det mer komplicerat.&lt;br /&gt;
&lt;br /&gt;
== Fjärrfältsdefinition ==&lt;br /&gt;
&lt;br /&gt;
För fjärrfältet används vanligen följande approximation vid vilket avstånd från en antenn som vi kan säga iss vara i fjärrfältet:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; r &amp;gt; \frac{2D^2}{\lambda}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Där D är antennens största utbredning i rummet i meter, för den dipol den totala längden, för en Yagi-Uda dess längsta axel, för en parabol omkretsen och &amp;lt;math&amp;gt;\lambda&amp;lt;/math&amp;gt; är våglängden i meter. &amp;lt;math&amp;gt;D^2&amp;lt;/math&amp;gt; är ett mått på antennens &amp;quot;antennarea&amp;quot; och säger något om fältbildning och utbredning i rummet.&lt;br /&gt;
&lt;br /&gt;
= Effekttäthet = &lt;br /&gt;
&lt;br /&gt;
Effekttätheten &amp;lt;math&amp;gt;S&amp;lt;/math&amp;gt; i enenheten W/m² kan beräknas ur sambandet:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
S = \frac{P \cdot G}{2 \pi r^2}&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Elektrisk fältstyrka =&lt;br /&gt;
&lt;br /&gt;
Den elektriska fältstyrkan uttrycks i regel som V/m eller i varianter därav. Vanliga varianter är t.ex. dBµV/m. Detta gäller i fjärrfältet.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
E= \frac{ \sqrt{30 \cdot P \cdot G} } { r }&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Magnetisk fältstyrka = &lt;br /&gt;
&lt;br /&gt;
== Från elektriska fältet ==&lt;br /&gt;
&lt;br /&gt;
Om du redan beräknat den elektriska fältstyrkan kan den magnetiska beräknas så som:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;H = \frac{E}{377} &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Direkt från sändaren ==&lt;br /&gt;
&lt;br /&gt;
Annars från sändarens effekt P och antennens antennvinst G fås:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;H = \frac{\sqrt{30 \cdot P \cdot G}}{377 \cdot r}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Nära en elektrisk ledare ==&lt;br /&gt;
&lt;br /&gt;
Nära en elektrisk ledare, till exempel drivet element hos en antenn så beräknas först strömmen i ledaren och därefter fås magnetfältet med relationen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
H = \frac{I}{2 \pi r}&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Storhetssamling = &lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;margin:auto&amp;quot;&lt;br /&gt;
|+ Storheter och enheter på denna sida&lt;br /&gt;
|-&lt;br /&gt;
! Storhet!! Beteckning!! Enhet&lt;br /&gt;
|-&lt;br /&gt;
| S || Effektdensitet|| W/m²&lt;br /&gt;
|-&lt;br /&gt;
| E || Elektrisk fältstyrka || V/m&lt;br /&gt;
|-&lt;br /&gt;
| H || Magnetisk fältstyrka || A/m&lt;br /&gt;
|-&lt;br /&gt;
| I || Elektrisk ström || A&lt;br /&gt;
|-&lt;br /&gt;
| P || Sändarens effekt || W&lt;br /&gt;
|-&lt;br /&gt;
| G || Antennens förstärkningsfaktor || (dimensionslös)&lt;br /&gt;
|-&lt;br /&gt;
| D || Antennarea || m²&lt;br /&gt;
|-&lt;br /&gt;
| r || Avstånd || m&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Anders</name></author>
	</entry>
	<entry>
		<id>http://wiki.sikvall.se/index.php?title=F%C3%A4ltstyrka&amp;diff=1887</id>
		<title>Fältstyrka</title>
		<link rel="alternate" type="text/html" href="http://wiki.sikvall.se/index.php?title=F%C3%A4ltstyrka&amp;diff=1887"/>
		<updated>2026-05-12T07:47:23Z</updated>

		<summary type="html">&lt;p&gt;Anders: /* Direkt från sändaren */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[category:formelsamling]]&lt;br /&gt;
[[category:fältstyrka]]&lt;br /&gt;
[[category:ellära]]&lt;br /&gt;
[[category:radio]]&lt;br /&gt;
[[category:radiolära]]&lt;br /&gt;
[[category:magnetism]]&lt;br /&gt;
[[category:elektricitet]]&lt;br /&gt;
&lt;br /&gt;
= Bakgrund =&lt;br /&gt;
&lt;br /&gt;
Fältstyrkan av en radiosignal avtar linjärt med avståndet från en sändare. Denna kan räknas ut med en enkel formel som stämmer utmärkt i fjärrfältet från antennen. I närfältet är det mer komplicerat.&lt;br /&gt;
&lt;br /&gt;
== Fjärrfältsdefinition ==&lt;br /&gt;
&lt;br /&gt;
För fjärrfältet används vanligen följande approximation vid vilket avstånd från en antenn som vi kan säga iss vara i fjärrfältet:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; r &amp;gt; \frac{2D^2}{\lambda}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Där D är antennens största utbredning i rummet i meter, för den dipol den totala längden, för en Yagi-Uda dess längsta axel, för en parabol omkretsen och &amp;lt;math&amp;gt;\lambda&amp;lt;/math&amp;gt; är våglängden i meter. &amp;lt;math&amp;gt;D^2&amp;lt;/math&amp;gt; är ett mått på antennens &amp;quot;antennarea&amp;quot; och säger något om fältbildning och utbredning i rummet.&lt;br /&gt;
&lt;br /&gt;
= Effekttäthet = &lt;br /&gt;
&lt;br /&gt;
Effekttätheten &amp;lt;math&amp;gt;S&amp;lt;/math&amp;gt; i enenheten W/m² kan beräknas ur sambandet:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
S = \frac{P \cdot G}{2 \pi r^2}&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Elektrisk fältstyrka =&lt;br /&gt;
&lt;br /&gt;
Den elektriska fältstyrkan uttrycks i regel som V/m eller i varianter därav. Vanliga varianter är t.ex. dBµV/m. Detta gäller i fjärrfältet.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
E= \frac{ \sqrt{30 \cdot P \cdot G} } { r }&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Magnetisk fältstyrka = &lt;br /&gt;
&lt;br /&gt;
== Från elektriska fältet ==&lt;br /&gt;
&lt;br /&gt;
Om du redan beräknat den elektriska fältstyrkan kan den magnetiska beräknas så som:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;H = \frac{E}{377} &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Direkt från sändaren ==&lt;br /&gt;
&lt;br /&gt;
Annars från sändarens effekt P och antennens antennvinst G fås:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;H = \frac{\sqrt{30 \cdot P \cdot G}}{377 \cdot r}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Nära en elektrisk ledare ==&lt;br /&gt;
&lt;br /&gt;
Nära en elektrisk ledare, till exempel drivet element hos en antenn så beräknas först strömmen i ledaren och därefter fås magnetfältet med relationen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
H = \frac{I}{2 \pi r}&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Storhetssamling = &lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;margin:auto&amp;quot;&lt;br /&gt;
|+ Storheter och enheter på denna sida&lt;br /&gt;
|-&lt;br /&gt;
! Storhet!! Beteckning!! Enhet&lt;br /&gt;
|-&lt;br /&gt;
| S || Effektdensitet|| W/m²&lt;br /&gt;
|-&lt;br /&gt;
| E || Elektrisk fältstyrka || V/m&lt;br /&gt;
|-&lt;br /&gt;
| H || Magnetisk fältstyrka || A/m&lt;br /&gt;
|-&lt;br /&gt;
| I || Elektrisk ström || A&lt;br /&gt;
|-&lt;br /&gt;
| P || Sändarens effekt || W&lt;br /&gt;
|-&lt;br /&gt;
| G || Antennens förstärkningsfaktor || (dimensionslös)&lt;br /&gt;
|-&lt;br /&gt;
| D || Antennarea || m²&lt;br /&gt;
|-&lt;br /&gt;
| r || Sträcka || m&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Anders</name></author>
	</entry>
	<entry>
		<id>http://wiki.sikvall.se/index.php?title=F%C3%A4ltstyrka&amp;diff=1886</id>
		<title>Fältstyrka</title>
		<link rel="alternate" type="text/html" href="http://wiki.sikvall.se/index.php?title=F%C3%A4ltstyrka&amp;diff=1886"/>
		<updated>2026-05-12T07:47:09Z</updated>

		<summary type="html">&lt;p&gt;Anders: /* Storhetssamling */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[category:formelsamling]]&lt;br /&gt;
[[category:fältstyrka]]&lt;br /&gt;
[[category:ellära]]&lt;br /&gt;
[[category:radio]]&lt;br /&gt;
[[category:radiolära]]&lt;br /&gt;
[[category:magnetism]]&lt;br /&gt;
[[category:elektricitet]]&lt;br /&gt;
&lt;br /&gt;
= Bakgrund =&lt;br /&gt;
&lt;br /&gt;
Fältstyrkan av en radiosignal avtar linjärt med avståndet från en sändare. Denna kan räknas ut med en enkel formel som stämmer utmärkt i fjärrfältet från antennen. I närfältet är det mer komplicerat.&lt;br /&gt;
&lt;br /&gt;
== Fjärrfältsdefinition ==&lt;br /&gt;
&lt;br /&gt;
För fjärrfältet används vanligen följande approximation vid vilket avstånd från en antenn som vi kan säga iss vara i fjärrfältet:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; r &amp;gt; \frac{2D^2}{\lambda}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Där D är antennens största utbredning i rummet i meter, för den dipol den totala längden, för en Yagi-Uda dess längsta axel, för en parabol omkretsen och &amp;lt;math&amp;gt;\lambda&amp;lt;/math&amp;gt; är våglängden i meter. &amp;lt;math&amp;gt;D^2&amp;lt;/math&amp;gt; är ett mått på antennens &amp;quot;antennarea&amp;quot; och säger något om fältbildning och utbredning i rummet.&lt;br /&gt;
&lt;br /&gt;
= Effekttäthet = &lt;br /&gt;
&lt;br /&gt;
Effekttätheten &amp;lt;math&amp;gt;S&amp;lt;/math&amp;gt; i enenheten W/m² kan beräknas ur sambandet:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
S = \frac{P \cdot G}{2 \pi r^2}&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Elektrisk fältstyrka =&lt;br /&gt;
&lt;br /&gt;
Den elektriska fältstyrkan uttrycks i regel som V/m eller i varianter därav. Vanliga varianter är t.ex. dBµV/m. Detta gäller i fjärrfältet.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
E= \frac{ \sqrt{30 \cdot P \cdot G} } { r }&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Magnetisk fältstyrka = &lt;br /&gt;
&lt;br /&gt;
== Från elektriska fältet ==&lt;br /&gt;
&lt;br /&gt;
Om du redan beräknat den elektriska fältstyrkan kan den magnetiska beräknas så som:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;H = \frac{E}{377} &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Direkt från sändaren ==&lt;br /&gt;
&lt;br /&gt;
Annars från sändarens effekt P och antennens antennvinst G fås:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\frac{\sqrt{30 \cdot P \cdot G}}{377 \cdot r}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Nära en elektrisk ledare ==&lt;br /&gt;
&lt;br /&gt;
Nära en elektrisk ledare, till exempel drivet element hos en antenn så beräknas först strömmen i ledaren och därefter fås magnetfältet med relationen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
H = \frac{I}{2 \pi r}&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Storhetssamling = &lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;margin:auto&amp;quot;&lt;br /&gt;
|+ Storheter och enheter på denna sida&lt;br /&gt;
|-&lt;br /&gt;
! Storhet!! Beteckning!! Enhet&lt;br /&gt;
|-&lt;br /&gt;
| S || Effektdensitet|| W/m²&lt;br /&gt;
|-&lt;br /&gt;
| E || Elektrisk fältstyrka || V/m&lt;br /&gt;
|-&lt;br /&gt;
| H || Magnetisk fältstyrka || A/m&lt;br /&gt;
|-&lt;br /&gt;
| I || Elektrisk ström || A&lt;br /&gt;
|-&lt;br /&gt;
| P || Sändarens effekt || W&lt;br /&gt;
|-&lt;br /&gt;
| G || Antennens förstärkningsfaktor || (dimensionslös)&lt;br /&gt;
|-&lt;br /&gt;
| D || Antennarea || m²&lt;br /&gt;
|-&lt;br /&gt;
| r || Sträcka || m&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Anders</name></author>
	</entry>
	<entry>
		<id>http://wiki.sikvall.se/index.php?title=F%C3%A4ltstyrka&amp;diff=1885</id>
		<title>Fältstyrka</title>
		<link rel="alternate" type="text/html" href="http://wiki.sikvall.se/index.php?title=F%C3%A4ltstyrka&amp;diff=1885"/>
		<updated>2026-05-12T07:46:40Z</updated>

		<summary type="html">&lt;p&gt;Anders: /* Storhetssamling */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[category:formelsamling]]&lt;br /&gt;
[[category:fältstyrka]]&lt;br /&gt;
[[category:ellära]]&lt;br /&gt;
[[category:radio]]&lt;br /&gt;
[[category:radiolära]]&lt;br /&gt;
[[category:magnetism]]&lt;br /&gt;
[[category:elektricitet]]&lt;br /&gt;
&lt;br /&gt;
= Bakgrund =&lt;br /&gt;
&lt;br /&gt;
Fältstyrkan av en radiosignal avtar linjärt med avståndet från en sändare. Denna kan räknas ut med en enkel formel som stämmer utmärkt i fjärrfältet från antennen. I närfältet är det mer komplicerat.&lt;br /&gt;
&lt;br /&gt;
== Fjärrfältsdefinition ==&lt;br /&gt;
&lt;br /&gt;
För fjärrfältet används vanligen följande approximation vid vilket avstånd från en antenn som vi kan säga iss vara i fjärrfältet:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; r &amp;gt; \frac{2D^2}{\lambda}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Där D är antennens största utbredning i rummet i meter, för den dipol den totala längden, för en Yagi-Uda dess längsta axel, för en parabol omkretsen och &amp;lt;math&amp;gt;\lambda&amp;lt;/math&amp;gt; är våglängden i meter. &amp;lt;math&amp;gt;D^2&amp;lt;/math&amp;gt; är ett mått på antennens &amp;quot;antennarea&amp;quot; och säger något om fältbildning och utbredning i rummet.&lt;br /&gt;
&lt;br /&gt;
= Effekttäthet = &lt;br /&gt;
&lt;br /&gt;
Effekttätheten &amp;lt;math&amp;gt;S&amp;lt;/math&amp;gt; i enenheten W/m² kan beräknas ur sambandet:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
S = \frac{P \cdot G}{2 \pi r^2}&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Elektrisk fältstyrka =&lt;br /&gt;
&lt;br /&gt;
Den elektriska fältstyrkan uttrycks i regel som V/m eller i varianter därav. Vanliga varianter är t.ex. dBµV/m. Detta gäller i fjärrfältet.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
E= \frac{ \sqrt{30 \cdot P \cdot G} } { r }&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Magnetisk fältstyrka = &lt;br /&gt;
&lt;br /&gt;
== Från elektriska fältet ==&lt;br /&gt;
&lt;br /&gt;
Om du redan beräknat den elektriska fältstyrkan kan den magnetiska beräknas så som:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;H = \frac{E}{377} &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Direkt från sändaren ==&lt;br /&gt;
&lt;br /&gt;
Annars från sändarens effekt P och antennens antennvinst G fås:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\frac{\sqrt{30 \cdot P \cdot G}}{377 \cdot r}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Nära en elektrisk ledare ==&lt;br /&gt;
&lt;br /&gt;
Nära en elektrisk ledare, till exempel drivet element hos en antenn så beräknas först strömmen i ledaren och därefter fås magnetfältet med relationen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
H = \frac{I}{2 \pi r}&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Storhetssamling = &lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;margin:auto&amp;quot;&lt;br /&gt;
|+ Storheter och enheter på denna sida&lt;br /&gt;
|-&lt;br /&gt;
! Storhet!! Beteckning!! Enhet&lt;br /&gt;
|-&lt;br /&gt;
| S || Effektdensitet|| W/m²&lt;br /&gt;
|-&lt;br /&gt;
| E || Elektrisk fältstyrka || V/m&lt;br /&gt;
|-&lt;br /&gt;
| H || Magnetisk fältstyrka || A/m&lt;br /&gt;
|-&lt;br /&gt;
| P || Sändarens effekt || W&lt;br /&gt;
|-&lt;br /&gt;
| G || Antennens förstärkningsfaktor || (dimensionslös)&lt;br /&gt;
|-&lt;br /&gt;
| D || Antennarea || m²&lt;br /&gt;
|-&lt;br /&gt;
| r || Sträcka || m&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Anders</name></author>
	</entry>
	<entry>
		<id>http://wiki.sikvall.se/index.php?title=F%C3%A4ltstyrka&amp;diff=1884</id>
		<title>Fältstyrka</title>
		<link rel="alternate" type="text/html" href="http://wiki.sikvall.se/index.php?title=F%C3%A4ltstyrka&amp;diff=1884"/>
		<updated>2026-05-12T07:45:59Z</updated>

		<summary type="html">&lt;p&gt;Anders: /* Bakgrund */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[category:formelsamling]]&lt;br /&gt;
[[category:fältstyrka]]&lt;br /&gt;
[[category:ellära]]&lt;br /&gt;
[[category:radio]]&lt;br /&gt;
[[category:radiolära]]&lt;br /&gt;
[[category:magnetism]]&lt;br /&gt;
[[category:elektricitet]]&lt;br /&gt;
&lt;br /&gt;
= Bakgrund =&lt;br /&gt;
&lt;br /&gt;
Fältstyrkan av en radiosignal avtar linjärt med avståndet från en sändare. Denna kan räknas ut med en enkel formel som stämmer utmärkt i fjärrfältet från antennen. I närfältet är det mer komplicerat.&lt;br /&gt;
&lt;br /&gt;
== Fjärrfältsdefinition ==&lt;br /&gt;
&lt;br /&gt;
För fjärrfältet används vanligen följande approximation vid vilket avstånd från en antenn som vi kan säga iss vara i fjärrfältet:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; r &amp;gt; \frac{2D^2}{\lambda}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Där D är antennens största utbredning i rummet i meter, för den dipol den totala längden, för en Yagi-Uda dess längsta axel, för en parabol omkretsen och &amp;lt;math&amp;gt;\lambda&amp;lt;/math&amp;gt; är våglängden i meter. &amp;lt;math&amp;gt;D^2&amp;lt;/math&amp;gt; är ett mått på antennens &amp;quot;antennarea&amp;quot; och säger något om fältbildning och utbredning i rummet.&lt;br /&gt;
&lt;br /&gt;
= Effekttäthet = &lt;br /&gt;
&lt;br /&gt;
Effekttätheten &amp;lt;math&amp;gt;S&amp;lt;/math&amp;gt; i enenheten W/m² kan beräknas ur sambandet:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
S = \frac{P \cdot G}{2 \pi r^2}&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Elektrisk fältstyrka =&lt;br /&gt;
&lt;br /&gt;
Den elektriska fältstyrkan uttrycks i regel som V/m eller i varianter därav. Vanliga varianter är t.ex. dBµV/m. Detta gäller i fjärrfältet.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
E= \frac{ \sqrt{30 \cdot P \cdot G} } { r }&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Magnetisk fältstyrka = &lt;br /&gt;
&lt;br /&gt;
== Från elektriska fältet ==&lt;br /&gt;
&lt;br /&gt;
Om du redan beräknat den elektriska fältstyrkan kan den magnetiska beräknas så som:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;H = \frac{E}{377} &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Direkt från sändaren ==&lt;br /&gt;
&lt;br /&gt;
Annars från sändarens effekt P och antennens antennvinst G fås:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\frac{\sqrt{30 \cdot P \cdot G}}{377 \cdot r}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Nära en elektrisk ledare ==&lt;br /&gt;
&lt;br /&gt;
Nära en elektrisk ledare, till exempel drivet element hos en antenn så beräknas först strömmen i ledaren och därefter fås magnetfältet med relationen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
H = \frac{I}{2 \pi r}&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Storhetssamling = &lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;margin:auto&amp;quot;&lt;br /&gt;
|+ Storheter och enheter på denna sida&lt;br /&gt;
|-&lt;br /&gt;
! Storhet!! Beteckning!! Enhet&lt;br /&gt;
|-&lt;br /&gt;
| S || Effektdensitet|| W/m²&lt;br /&gt;
|-&lt;br /&gt;
| E || Elektrisk fältstyrka || V/m&lt;br /&gt;
|-&lt;br /&gt;
| H || Magnetisk fältstyrka || A/m&lt;br /&gt;
|-&lt;br /&gt;
| P || Sändarens effekt || W&lt;br /&gt;
|-&lt;br /&gt;
| G || Antennens förstärkningsfaktor || (dimensionslös)&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Anders</name></author>
	</entry>
	<entry>
		<id>http://wiki.sikvall.se/index.php?title=F%C3%A4ltstyrka&amp;diff=1883</id>
		<title>Fältstyrka</title>
		<link rel="alternate" type="text/html" href="http://wiki.sikvall.se/index.php?title=F%C3%A4ltstyrka&amp;diff=1883"/>
		<updated>2026-05-12T07:42:49Z</updated>

		<summary type="html">&lt;p&gt;Anders: /* Elektrisk fältstyrka */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[category:formelsamling]]&lt;br /&gt;
[[category:fältstyrka]]&lt;br /&gt;
[[category:ellära]]&lt;br /&gt;
[[category:radio]]&lt;br /&gt;
[[category:radiolära]]&lt;br /&gt;
[[category:magnetism]]&lt;br /&gt;
[[category:elektricitet]]&lt;br /&gt;
&lt;br /&gt;
= Bakgrund =&lt;br /&gt;
&lt;br /&gt;
Fältstyrkan av en radiosignal avtar linjärt med avståndet från en sändare. Denna kan räknas ut med en enkel formel som stämmer utmärkt i fjärrfältet från antennen. I närfältet är det mer komplicerat.&lt;br /&gt;
&lt;br /&gt;
= Effekttäthet = &lt;br /&gt;
&lt;br /&gt;
Effekttätheten &amp;lt;math&amp;gt;S&amp;lt;/math&amp;gt; i enenheten W/m² kan beräknas ur sambandet:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
S = \frac{P \cdot G}{2 \pi r^2}&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Elektrisk fältstyrka =&lt;br /&gt;
&lt;br /&gt;
Den elektriska fältstyrkan uttrycks i regel som V/m eller i varianter därav. Vanliga varianter är t.ex. dBµV/m. Detta gäller i fjärrfältet.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
E= \frac{ \sqrt{30 \cdot P \cdot G} } { r }&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Magnetisk fältstyrka = &lt;br /&gt;
&lt;br /&gt;
== Från elektriska fältet ==&lt;br /&gt;
&lt;br /&gt;
Om du redan beräknat den elektriska fältstyrkan kan den magnetiska beräknas så som:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;H = \frac{E}{377} &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Direkt från sändaren ==&lt;br /&gt;
&lt;br /&gt;
Annars från sändarens effekt P och antennens antennvinst G fås:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\frac{\sqrt{30 \cdot P \cdot G}}{377 \cdot r}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Nära en elektrisk ledare ==&lt;br /&gt;
&lt;br /&gt;
Nära en elektrisk ledare, till exempel drivet element hos en antenn så beräknas först strömmen i ledaren och därefter fås magnetfältet med relationen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
H = \frac{I}{2 \pi r}&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Storhetssamling = &lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;margin:auto&amp;quot;&lt;br /&gt;
|+ Storheter och enheter på denna sida&lt;br /&gt;
|-&lt;br /&gt;
! Storhet!! Beteckning!! Enhet&lt;br /&gt;
|-&lt;br /&gt;
| S || Effektdensitet|| W/m²&lt;br /&gt;
|-&lt;br /&gt;
| E || Elektrisk fältstyrka || V/m&lt;br /&gt;
|-&lt;br /&gt;
| H || Magnetisk fältstyrka || A/m&lt;br /&gt;
|-&lt;br /&gt;
| P || Sändarens effekt || W&lt;br /&gt;
|-&lt;br /&gt;
| G || Antennens förstärkningsfaktor || (dimensionslös)&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Anders</name></author>
	</entry>
	<entry>
		<id>http://wiki.sikvall.se/index.php?title=F%C3%A4ltstyrka&amp;diff=1882</id>
		<title>Fältstyrka</title>
		<link rel="alternate" type="text/html" href="http://wiki.sikvall.se/index.php?title=F%C3%A4ltstyrka&amp;diff=1882"/>
		<updated>2026-05-12T07:38:13Z</updated>

		<summary type="html">&lt;p&gt;Anders: /* Magnetisk fältstyrka */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[category:formelsamling]]&lt;br /&gt;
[[category:fältstyrka]]&lt;br /&gt;
[[category:ellära]]&lt;br /&gt;
[[category:radio]]&lt;br /&gt;
[[category:radiolära]]&lt;br /&gt;
[[category:magnetism]]&lt;br /&gt;
[[category:elektricitet]]&lt;br /&gt;
&lt;br /&gt;
= Bakgrund =&lt;br /&gt;
&lt;br /&gt;
Fältstyrkan av en radiosignal avtar linjärt med avståndet från en sändare. Denna kan räknas ut med en enkel formel som stämmer utmärkt i fjärrfältet från antennen. I närfältet är det mer komplicerat.&lt;br /&gt;
&lt;br /&gt;
= Effekttäthet = &lt;br /&gt;
&lt;br /&gt;
Effekttätheten &amp;lt;math&amp;gt;S&amp;lt;/math&amp;gt; i enenheten W/m² kan beräknas ur sambandet:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
S = \frac{P \cdot G}{2 \pi r^2}&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Elektrisk fältstyrka =&lt;br /&gt;
&lt;br /&gt;
Den elektriska fältstyrkan uttrycks i regel som V/m eller i varianter därav. Vanliga varianter är t.ex. dBµV/m.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
E= \frac{ \sqrt{30 \cdot P \cdot G} } { r }&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Magnetisk fältstyrka = &lt;br /&gt;
&lt;br /&gt;
== Från elektriska fältet ==&lt;br /&gt;
&lt;br /&gt;
Om du redan beräknat den elektriska fältstyrkan kan den magnetiska beräknas så som:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;H = \frac{E}{377} &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Direkt från sändaren ==&lt;br /&gt;
&lt;br /&gt;
Annars från sändarens effekt P och antennens antennvinst G fås:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\frac{\sqrt{30 \cdot P \cdot G}}{377 \cdot r}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Nära en elektrisk ledare ==&lt;br /&gt;
&lt;br /&gt;
Nära en elektrisk ledare, till exempel drivet element hos en antenn så beräknas först strömmen i ledaren och därefter fås magnetfältet med relationen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
H = \frac{I}{2 \pi r}&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Storhetssamling = &lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;margin:auto&amp;quot;&lt;br /&gt;
|+ Storheter och enheter på denna sida&lt;br /&gt;
|-&lt;br /&gt;
! Storhet!! Beteckning!! Enhet&lt;br /&gt;
|-&lt;br /&gt;
| S || Effektdensitet|| W/m²&lt;br /&gt;
|-&lt;br /&gt;
| E || Elektrisk fältstyrka || V/m&lt;br /&gt;
|-&lt;br /&gt;
| H || Magnetisk fältstyrka || A/m&lt;br /&gt;
|-&lt;br /&gt;
| P || Sändarens effekt || W&lt;br /&gt;
|-&lt;br /&gt;
| G || Antennens förstärkningsfaktor || (dimensionslös)&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Anders</name></author>
	</entry>
	<entry>
		<id>http://wiki.sikvall.se/index.php?title=F%C3%A4ltstyrka&amp;diff=1881</id>
		<title>Fältstyrka</title>
		<link rel="alternate" type="text/html" href="http://wiki.sikvall.se/index.php?title=F%C3%A4ltstyrka&amp;diff=1881"/>
		<updated>2026-05-12T07:37:24Z</updated>

		<summary type="html">&lt;p&gt;Anders: /* Storhetssamling */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[category:formelsamling]]&lt;br /&gt;
[[category:fältstyrka]]&lt;br /&gt;
[[category:ellära]]&lt;br /&gt;
[[category:radio]]&lt;br /&gt;
[[category:radiolära]]&lt;br /&gt;
[[category:magnetism]]&lt;br /&gt;
[[category:elektricitet]]&lt;br /&gt;
&lt;br /&gt;
= Bakgrund =&lt;br /&gt;
&lt;br /&gt;
Fältstyrkan av en radiosignal avtar linjärt med avståndet från en sändare. Denna kan räknas ut med en enkel formel som stämmer utmärkt i fjärrfältet från antennen. I närfältet är det mer komplicerat.&lt;br /&gt;
&lt;br /&gt;
= Effekttäthet = &lt;br /&gt;
&lt;br /&gt;
Effekttätheten &amp;lt;math&amp;gt;S&amp;lt;/math&amp;gt; i enenheten W/m² kan beräknas ur sambandet:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
S = \frac{P \cdot G}{2 \pi r^2}&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Elektrisk fältstyrka =&lt;br /&gt;
&lt;br /&gt;
Den elektriska fältstyrkan uttrycks i regel som V/m eller i varianter därav. Vanliga varianter är t.ex. dBµV/m.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
E= \frac{ \sqrt{30 \cdot P \cdot G} } { r }&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Magnetisk fältstyrka = &lt;br /&gt;
&lt;br /&gt;
Om du redan beräknat den elektriska fältstyrkan kan den magnetiska beräknas så som:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;H = \frac{E}{377} &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Annars från sändarens effekt P och antennens antennvinst G fås:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\frac{\sqrt{30 \cdot P \cdot G}}{377 \cdot r}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Nära en elektrisk ledare, till exempel drivet element hos en antenn så beräknas först strömmen i ledaren och därefter fås magnetfältet med relationen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
H = \frac{I}{2 \pi r}&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Storhetssamling = &lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;margin:auto&amp;quot;&lt;br /&gt;
|+ Storheter och enheter på denna sida&lt;br /&gt;
|-&lt;br /&gt;
! Storhet!! Beteckning!! Enhet&lt;br /&gt;
|-&lt;br /&gt;
| S || Effektdensitet|| W/m²&lt;br /&gt;
|-&lt;br /&gt;
| E || Elektrisk fältstyrka || V/m&lt;br /&gt;
|-&lt;br /&gt;
| H || Magnetisk fältstyrka || A/m&lt;br /&gt;
|-&lt;br /&gt;
| P || Sändarens effekt || W&lt;br /&gt;
|-&lt;br /&gt;
| G || Antennens förstärkningsfaktor || (dimensionslös)&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Anders</name></author>
	</entry>
	<entry>
		<id>http://wiki.sikvall.se/index.php?title=F%C3%A4ltstyrka&amp;diff=1880</id>
		<title>Fältstyrka</title>
		<link rel="alternate" type="text/html" href="http://wiki.sikvall.se/index.php?title=F%C3%A4ltstyrka&amp;diff=1880"/>
		<updated>2026-05-12T07:37:06Z</updated>

		<summary type="html">&lt;p&gt;Anders: /* Storhetssamling */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[category:formelsamling]]&lt;br /&gt;
[[category:fältstyrka]]&lt;br /&gt;
[[category:ellära]]&lt;br /&gt;
[[category:radio]]&lt;br /&gt;
[[category:radiolära]]&lt;br /&gt;
[[category:magnetism]]&lt;br /&gt;
[[category:elektricitet]]&lt;br /&gt;
&lt;br /&gt;
= Bakgrund =&lt;br /&gt;
&lt;br /&gt;
Fältstyrkan av en radiosignal avtar linjärt med avståndet från en sändare. Denna kan räknas ut med en enkel formel som stämmer utmärkt i fjärrfältet från antennen. I närfältet är det mer komplicerat.&lt;br /&gt;
&lt;br /&gt;
= Effekttäthet = &lt;br /&gt;
&lt;br /&gt;
Effekttätheten &amp;lt;math&amp;gt;S&amp;lt;/math&amp;gt; i enenheten W/m² kan beräknas ur sambandet:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
S = \frac{P \cdot G}{2 \pi r^2}&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Elektrisk fältstyrka =&lt;br /&gt;
&lt;br /&gt;
Den elektriska fältstyrkan uttrycks i regel som V/m eller i varianter därav. Vanliga varianter är t.ex. dBµV/m.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
E= \frac{ \sqrt{30 \cdot P \cdot G} } { r }&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Magnetisk fältstyrka = &lt;br /&gt;
&lt;br /&gt;
Om du redan beräknat den elektriska fältstyrkan kan den magnetiska beräknas så som:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;H = \frac{E}{377} &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Annars från sändarens effekt P och antennens antennvinst G fås:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\frac{\sqrt{30 \cdot P \cdot G}}{377 \cdot r}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Nära en elektrisk ledare, till exempel drivet element hos en antenn så beräknas först strömmen i ledaren och därefter fås magnetfältet med relationen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
H = \frac{I}{2 \pi r}&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Storhetssamling = &lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;margin:auto&amp;quot;&lt;br /&gt;
|+ Storheter och enheter&lt;br /&gt;
|-&lt;br /&gt;
! Storhet!! Beteckning!! Enhet&lt;br /&gt;
|-&lt;br /&gt;
| S || Effektdensitet|| W/m²&lt;br /&gt;
|-&lt;br /&gt;
| E || Elektrisk fältstyrka || V/m&lt;br /&gt;
|-&lt;br /&gt;
| H || Magnetisk fältstyrka || A/m&lt;br /&gt;
|-&lt;br /&gt;
| P || Sändarens effekt || W&lt;br /&gt;
|-&lt;br /&gt;
| G || Antennens förstärkningsfaktor || (dimensionslös)&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Anders</name></author>
	</entry>
	<entry>
		<id>http://wiki.sikvall.se/index.php?title=F%C3%A4ltstyrka&amp;diff=1879</id>
		<title>Fältstyrka</title>
		<link rel="alternate" type="text/html" href="http://wiki.sikvall.se/index.php?title=F%C3%A4ltstyrka&amp;diff=1879"/>
		<updated>2026-05-12T07:25:19Z</updated>

		<summary type="html">&lt;p&gt;Anders: /* Magnetisk fältstyrka */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[category:formelsamling]]&lt;br /&gt;
[[category:fältstyrka]]&lt;br /&gt;
[[category:ellära]]&lt;br /&gt;
[[category:radio]]&lt;br /&gt;
[[category:radiolära]]&lt;br /&gt;
[[category:magnetism]]&lt;br /&gt;
[[category:elektricitet]]&lt;br /&gt;
&lt;br /&gt;
= Bakgrund =&lt;br /&gt;
&lt;br /&gt;
Fältstyrkan av en radiosignal avtar linjärt med avståndet från en sändare. Denna kan räknas ut med en enkel formel som stämmer utmärkt i fjärrfältet från antennen. I närfältet är det mer komplicerat.&lt;br /&gt;
&lt;br /&gt;
= Effekttäthet = &lt;br /&gt;
&lt;br /&gt;
Effekttätheten &amp;lt;math&amp;gt;S&amp;lt;/math&amp;gt; i enenheten W/m² kan beräknas ur sambandet:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
S = \frac{P \cdot G}{2 \pi r^2}&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Elektrisk fältstyrka =&lt;br /&gt;
&lt;br /&gt;
Den elektriska fältstyrkan uttrycks i regel som V/m eller i varianter därav. Vanliga varianter är t.ex. dBµV/m.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
E= \frac{ \sqrt{30 \cdot P \cdot G} } { r }&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Magnetisk fältstyrka = &lt;br /&gt;
&lt;br /&gt;
Om du redan beräknat den elektriska fältstyrkan kan den magnetiska beräknas så som:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;H = \frac{E}{377} &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Annars från sändarens effekt P och antennens antennvinst G fås:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\frac{\sqrt{30 \cdot P \cdot G}}{377 \cdot r}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Nära en elektrisk ledare, till exempel drivet element hos en antenn så beräknas först strömmen i ledaren och därefter fås magnetfältet med relationen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
H = \frac{I}{2 \pi r}&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Storhetssamling = &lt;br /&gt;
&lt;br /&gt;
TODO: Samla storheterna här&lt;/div&gt;</summary>
		<author><name>Anders</name></author>
	</entry>
	<entry>
		<id>http://wiki.sikvall.se/index.php?title=F%C3%A4ltstyrka&amp;diff=1878</id>
		<title>Fältstyrka</title>
		<link rel="alternate" type="text/html" href="http://wiki.sikvall.se/index.php?title=F%C3%A4ltstyrka&amp;diff=1878"/>
		<updated>2026-05-12T07:25:02Z</updated>

		<summary type="html">&lt;p&gt;Anders: /* Magnetiska fältstyrkan */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[category:formelsamling]]&lt;br /&gt;
[[category:fältstyrka]]&lt;br /&gt;
[[category:ellära]]&lt;br /&gt;
[[category:radio]]&lt;br /&gt;
[[category:radiolära]]&lt;br /&gt;
[[category:magnetism]]&lt;br /&gt;
[[category:elektricitet]]&lt;br /&gt;
&lt;br /&gt;
= Bakgrund =&lt;br /&gt;
&lt;br /&gt;
Fältstyrkan av en radiosignal avtar linjärt med avståndet från en sändare. Denna kan räknas ut med en enkel formel som stämmer utmärkt i fjärrfältet från antennen. I närfältet är det mer komplicerat.&lt;br /&gt;
&lt;br /&gt;
= Effekttäthet = &lt;br /&gt;
&lt;br /&gt;
Effekttätheten &amp;lt;math&amp;gt;S&amp;lt;/math&amp;gt; i enenheten W/m² kan beräknas ur sambandet:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
S = \frac{P \cdot G}{2 \pi r^2}&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Elektrisk fältstyrka =&lt;br /&gt;
&lt;br /&gt;
Den elektriska fältstyrkan uttrycks i regel som V/m eller i varianter därav. Vanliga varianter är t.ex. dBµV/m.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
E= \frac{ \sqrt{30 \cdot P \cdot G} } { r }&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Magnetisk fältstyrka = &lt;br /&gt;
&lt;br /&gt;
Om du redan beräknat den elektriska fältstyrkan kan den magnetiska beräknas så som:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;H = \frac{E}{377} &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Annars från sändarens effekt P och antennens antennvinst G fås:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;H = \frac{E}{377} \approx \frac{\sqrt{30 \cdot P \cdot G}}{377 \cdot r}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Nära en elektrisk ledare, till exempel drivet element hos en antenn så beräknas först strömmen i ledaren och därefter fås magnetfältet med relationen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
H = \frac{I}{2 \pi r}&lt;br /&gt;
&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Storhetssamling = &lt;br /&gt;
&lt;br /&gt;
TODO: Samla storheterna här&lt;/div&gt;</summary>
		<author><name>Anders</name></author>
	</entry>
</feed>