<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" xml:lang="tr"><generator uri="https://jekyllrb.com/" version="4.4.1">Jekyll</generator><link href="https://karaman.dev/feed.xml" rel="self" type="application/atom+xml" /><link href="https://karaman.dev/" rel="alternate" type="text/html" hreflang="tr" /><updated>2026-06-24T17:11:49+00:00</updated><id>https://karaman.dev/feed.xml</id><title type="html">M. Serdar Karaman</title><subtitle>Aviyonik yazılım, DO-178C ve emniyet kritik mühendislik üzerine sahadan notlar.</subtitle><author><name>M. Serdar Karaman</name></author><entry xml:lang="tr"><title type="html">Antikırılgan: Belirsizlikten ve Kaostan Güç Alan Sistemler</title><link href="https://karaman.dev/2026/06/24/antikirilgan-belirsizlikten-guc-alan-sistemler.html" rel="alternate" type="text/html" title="Antikırılgan: Belirsizlikten ve Kaostan Güç Alan Sistemler" /><published>2026-06-24T09:00:00+00:00</published><updated>2026-06-24T09:00:00+00:00</updated><id>https://karaman.dev/2026/06/24/antikirilgan-belirsizlikten-guc-alan-sistemler</id><content type="html" xml:base="https://karaman.dev/2026/06/24/antikirilgan-belirsizlikten-guc-alan-sistemler.html"><![CDATA[<p>Mühendislikte uzun süredir tek bir niteliğin peşinden koşarız: dayanıklılık. Sistemin şoka, yüke ve arızaya rağmen ayakta kalmasını isteriz; emniyet-kritik alanlarda bunu bir zorunluluğa çeviririz. Oysa Nassim Nicholas Taleb’in <em>Incerto</em> serisinde işlediği temel iddia, dayanıklılığın bir uç değil bir orta nokta olduğudur. Kırılganın gerçek zıttı “kırılmayan” değildir; volatiliteden, stresten ve hatadan fayda gören, yani sarsıldıkça güçlenen bir şeydir.</p>

<p>Taleb bu üçüncü hâl için yeni bir sözcük kullanır: <em>antifragile</em>, antikırılgan. Kavramın asıl değeri, belirsizlik karşısındaki alışkanlığımızı tersine çevirmesindedir: amaç bir sonraki şoku tahmin etmek değil, şoktan hangi yönde etkileneceğimizi baştan tasarlamaktır. Aşağıda önce kavramı ve altındaki asimetriyi tanımlıyor, ardından yazılımdan ürüne ve topluluğa kadar farklı sistemlere uygulanışını ele alıyoruz.</p>

<hr />

<h2 id="antikırılganlık-nedir-üçlü-yelpaze">Antikırılganlık Nedir? Üçlü Yelpaze</h2>

<p>Taleb bu noktayı bir kargo örneğiyle somutlaştırır. Bir kutunun üstünde <strong>KIRILIR</strong> yazar; karşıtı çoğu kişiye göre “dayanıklı”dır. Oysa dayanıklı kutunun üstünde hiçbir şey yazmaz, çünkü nasıl savrulduğu onu ilgilendirmez. Asıl karşıt uç, üstünde “lütfen hırpalayın” yazabilecek, sarsıldıkça içindeki daha iyi duruma gelen kutudur. Dilde böyle bir kelime yoktu; Taleb bu boşluğu “antikırılgan” ile doldurdu.</p>

<p>Buradan üçlü bir yelpaze çıkar. Her şeyi volatiliteye — yani belirsizliğe, strese, rastgeleliğe, şoka — verdiği tepkiye göre üçe ayırabiliriz:</p>

<table>
  <thead>
    <tr>
      <th> </th>
      <th>Volatiliteye tepkisi</th>
      <th>Maskotu</th>
      <th>Örnek</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>**Kırılgan**</td>
      <td>Zarar görür, bozulur</td>
      <td>Demokles’in Kılıcı</td>
      <td>İnce kristal kadeh, aşırı optimize edilmiş tedarik zinciri</td>
    </tr>
    <tr>
      <td>**Dayanıklı (Robust)**</td>
      <td>Kayıtsız kalır, aynı kalır</td>
      <td>Anka Kuşu</td>
      <td>Granit kaya, yedekli sunucu</td>
    </tr>
    <tr>
      <td>**Antikırılgan**</td>
      <td>Beslenir, güçlenir</td>
      <td>Hydra</td>
      <td>Bağışıklık sistemi, evrim, kas</td>
    </tr>
  </tbody>
</table>

<div class="mermaid">
flowchart LR
    V(["Volatilite / Şok / Stres"]) --&gt; F["KIRILGAN<br />zarar görür"]
    V --&gt; R["DAYANIKLI<br />aynı kalır"]
    V --&gt; A["ANTIKIRILGAN<br />güçlenir"]
    style V fill:#fde0e0,stroke:#c0392b,stroke-width:2px
    style F fill:#f5cccc,stroke:#c0392b,stroke-width:2px
    style R fill:#e8eef7,stroke:#4a6fa5,stroke-width:2px
    style A fill:#d5f0d5,stroke:#2e7d32,stroke-width:2px
</div>

<p>Burada sık yapılan bir karışıklık var: antikırılganlık ile dayanıklılık aynı şey değildir. Dayanıklı sistem şoktan sonra aynı kalır, antikırılgan sistem gelişir. Kas ağırlık kaldırdıkça güçlenir, kemik yük altında yoğunlaşır, bağışıklık denetimli maruziyetle öğrenir. Bu sistemlerin ortak yanı, aşırı korumanın onları güçlendirmek yerine zayıflatmasıdır; belirli bir stresin yokluğu başlı başına bir kırılganlık kaynağıdır.</p>

<h2 id="konveksite-antikırılganlığın-matematiği">Konveksite: Antikırılganlığın Matematiği</h2>

<p>Bir şeyi antikırılgan yapan nitelik asimetridir. Antikırılgan bir yapının volatilite karşısındaki kazancı kaybından büyüktür: iyi giderse çok kazanır, kötü giderse az kaybeder. Taleb bunu konveksite (dışbükeylik) olarak adlandırır. Tersi bir cam bardakta görülebilir: bardağı bir metreden bir kez düşürmek, bir santimden yüz kez düşürmekten çok daha zararlıdır. Küçük sarsıntılar etkisiz kalır, tek büyük darbe parçalar. Kayıp stresle orantısız büyüdüğünde ortaya çıkan içbükey eğri, kırılganlığın imzasıdır.</p>

<div class="mermaid">
flowchart TB
    K0["KIRILGAN<br />(içbükey ödeme)"] --&gt; K1["küçük stres:<br />az kazanç"]
    K0 --&gt; K2["büyük stres:<br />FELAKET kayıp"]
    A0["ANTIKIRILGAN<br />(dışbükey ödeme)"] --&gt; A1["küçük stres:<br />az kayıp"]
    A0 --&gt; A2["büyük stres:<br />BÜYÜK kazanç"]
    style K0 fill:#f5cccc,stroke:#c0392b,stroke-width:2px
    style K2 fill:#f5cccc,stroke:#c0392b,stroke-width:2px
    style A0 fill:#d5f0d5,stroke:#2e7d32,stroke-width:2px
    style A2 fill:#d5f0d5,stroke:#2e7d32,stroke-width:2px
</div>

<p>Antikırılgan yapıda işaret tersine döner. Bir denemenin başarısızlık maliyeti sınırlıyken (örneğin sınırlı bir zaman ve bütçe) başarısının getirisi açık uçluysa, dağılımın aşağı yönü kapalı, yukarı yönü açıktır. Taleb’in vurgusu da buradadır: geleceği tahmin etmeye değil, maruziyeti dışbükey kılmaya odaklanmak. Onun çerçevesinde volatilite, rastgelelik, stres, hata ve zaman aynı ailenin üyeleridir; düzensizliğin farklı görünümleridir ve antikırılgan yapılar bu düzensizlikten beslenir.</p>

<h2 id="antikırılganlığın-araç-çantası">Antikırılganlığın Araç Çantası</h2>

<p>Konveksite tesadüfe bırakılmak zorunda değildir; tasarlanabilir. Aşağıdaki pratikler, ilerleyen bölümlerdeki farklı alanların hepsinde tekrar eder:</p>

<ul>
  <li><strong>Barbell (halter) stratejisi:</strong> Riski iki uçta toplamak; ağırlığı aşırı güvenli tarafa koyup küçük bir payı çok sayıda yüksek riskli, açık uçlu girişime ayırmak. Belirsizliği yanlış ölçülen “orta risk” bölgesinden kaçınmak.</li>
  <li><strong>Opsiyonellik:</strong> Yükümlülük değil seçenek biriktirmek; kötü senaryoda kullanılması zorunlu olmayan, iyi senaryoda getirisi açık seçenekler.</li>
  <li><strong>Via negativa:</strong> Sağlamlığı bir şey ekleyerek değil, kırılganlık kaynaklarını çıkararak artırmak.</li>
  <li><strong>Hormesis:</strong> Küçük, sık ve iyileşmeye fırsat tanıyan stresörlerle sistemi büyük şoka hazırlamak; aşırı koruma yerine denetimli maruziyet.</li>
  <li><strong>Skin in the game:</strong> Kararı verenin sonucun riskini de taşıması; aksi hâlde kayıplar sisteme, kazançlar bireye kalır ve gizli kırılganlık birikir.</li>
  <li><strong>Artıklık ve ademimerkeziyet:</strong> Yedeklilik kısa vadede verimsizlik gibi görünse de belirsizliğe karşı bir tampondur; dağıtık karar tek bir kırılma noktasını ortadan kaldırır.</li>
</ul>

<div class="mermaid">
flowchart LR
    G["BÜYÜK KISIM<br />AŞIRI GÜVENLİ<br />(çekirdek, nakit, kanıtlanmış)"]
    B["KÜÇÜK KISIM<br />ÇOK SAYIDA<br />YÜKSEK-RİSKLİ BAHİS"]
    G -.-&gt;|ortayı boş bırak| B
    style G fill:#e8eef7,stroke:#4a6fa5,stroke-width:2px
    style B fill:#d5f0d5,stroke:#2e7d32,stroke-width:2px
</div>

<h2 id="uygulama-altı-alanda-antikırılganlık">Uygulama: Altı Alanda Antikırılganlık</h2>

<h3 id="yazılıma">Yazılıma</h3>

<p>Yazılım, kavramın en doğrudan uygulandığı alanlardan biridir; sektör buna Chaos Engineering adını bile vermiştir. Netflix’in Chaos Monkey aracı, üretim ortamında rastgele sunucuları bilerek devre dışı bırakır. Mantık hormesistir: sistemi her gün küçük ve denetimli arızalara maruz bırakan ekip, büyük arıza geldiğinde ona dayanacak biçimde olgunlaşmış bir mimariye sahip olur. Aynı asimetriyi error budget, feature flag ile birlikte otomatik geri alma (hatanın etkisini saniyeler içinde sınırlar), fuzzing ve hatayı suç değil veri olarak ele alan suçlamasız postmortem kurar. Buradaki örtük kırılganlık genellikle aşırı optimizasyondur: her şeyi sıkıca birbirine bağlayıp son damla verimi sıkan bir sistem, beklenmedik tek bir girdide bütünüyle çöker. <a href="/2026/06/04/coupling-dengesi.html">Coupling’i Dengelemek</a> yazısında ele alındığı gibi, amaç bağımlılığı yok etmek değil dengede tutmak ve bir bileşen çökerken sistemin bütününün denetimli biçimde geri çekilmesine (graceful degradation) izin vermektir.</p>

<h3 id="bir-proje-ekibine">Bir Proje Ekibine</h3>

<p>Bir ekip de strese maruz kalan bir sistemdir ve antikırılganlığı, kriz sonrasında dağılıp dağılmadığıyla ölçülür. Belirleyici etken psikolojik güvenliktir: hatayı açıkça dile getirebilen bir ekipte her hata ortak hafızaya yazılır, hatanın gizlendiği ekipte ise hatalar birikip aynı anda açığa çıkar. Bunu mümkün kılan pratikler tanıdıktır; bilgi tek kişiye bağlı kalmasın diye çapraz eğitim, belirsizliğe pay bırakan plan boşluğu (slack), ucuza denenip ucuza vazgeçilebilen küçük denemeler ve olaylardan sonuç çıkaran düzenli değerlendirmeler. Ekibi her çatışmadan ve başarısızlıktan yalıtmak, çoğu zaman onu güçlendirmek yerine kırılganlaştırır.</p>

<h3 id="bir-şirkete">Bir Şirkete</h3>

<p>Şirket ölçeğinde antikırılganlık çoğu zaman bir barbell yapısına benzer: gelirin büyük kısmı kanıtlanmış, nakit üreten çekirdekte dururken küçük bir pay çok sayıda ucuz ve açık uçlu girişime ayrılır. Bu girişimlerin çoğu sonuç vermez, ancak tutan birkaçı tüm portföyü taşıyabilir. Kırılgan şirketin işaretleri ise bellidir: tek bir müşteriye veya tedarikçiye bağımlılık, yüksek borç ve kaldıraç, her şeyi verimlilik adına en sınıra kadar yontmak, kararı tek merkezde toplamak. Antikırılgan şirket daha ademimerkezidir, elinde seçenek tutar, durgunlukta rakipleri elenirken pay kazanır ve kararı verenle sonucun riskini taşıyanı aynı tarafta tutar.</p>

<h3 id="bir-ürüne">Bir Ürüne</h3>

<p>Bir ürünün antikırılganlığı, gerçek kullanımla temas ettikçe bozulacak mı yoksa öğrenecek mi biçimde tasarlandığına bağlıdır. MVP ve hızlı yineleme, baştan doğru ürünü tahmin etme iddiasından vazgeçip ürünü kullanım geri bildirimiyle biçimlendirme yaklaşımıdır; tahminin yerini denetimli maruziyet alır. A/B testleri her özelliği küçük ve geri alınabilir bir denemeye dönüştürür, böylece zayıf seçenek düşük maliyetle elenir. Kademeli dağıtım (canary), beta kanalları, ekibin kendi ürününü kullanması (dogfooding) ve kullanıcı hata bildirimlerini birincil veri olarak ele alan döngüler, ürünü sürekli küçük stresörlere maruz bırakarak olgunlaştırır.</p>

<h3 id="bir-topluluğa">Bir Topluluğa</h3>

<p>Açık kaynak toplulukları bu özelliği belirgin biçimde taşır. Bir bakımcı ayrıldığında proje çatallanabilir (fork) ve tek bir kişiye ya da sunucuya bağlı kalmaz. Katkıcı çeşitliliği fikirleri sürekli sınamaya tabi tutar; zayıf öneriler tartışmada elenir, işe yarayanlar kalır. Bu yapıda eleştiri bir tehdit değil bir bağışıklık mekanizmasıdır: kod incelemeleri, açık anlaşmazlıklar ve kamuya açık tartışma topluluğu güçlendirir. Buna karşılık tek kişiye bağlı, merkezîleşmiş ve eleştiriye kapalı bir topluluk, dışarıdan uyumlu görünse de tek bir ayrılışa veya itiraza karşı kırılgandır.</p>

<h3 id="bir-sisteme">Bir Sisteme</h3>

<p>Daha genel olarak, birbiriyle etkileşen parçalardan oluşan her sistemde ilkeler benzerdir. Dağıtık sistemlerde N+1 artıklık, devre kesici (circuit breaker) ve bölme perdesi (bulkhead) desenleri, tek bir arızanın zincirleme bütün sistemi durdurmasını engeller; su alan bölmesi yalıtılırken geminin yüzmeye devam etmesi gibi. Aynı düşünce emniyet-kritik aviyonikte yedekli (redundant) kanallar ve hata sınırlandırma (fault containment) olarak kurumsallaşmıştır. Doğadaki karşılığı evrimdir: çok sayıda küçük başarısızlık üzerinden türü güçlendiren bir süreç işler; birey kırılgan kalırken tür bütününde antikırılgan davranır. Buradaki yaygın hata verimlilik takıntısıdır, çünkü tek bir senaryoya kusursuz biçimde optimize edilen sistem, o senaryonun dışındaki koşullara karşı kırılganlaşır. Bu nitelikler de <a href="/2026/05/26/sistem-muhendisligi-nedir.html">Sistem Mühendisliği Nedir?</a> yazısındaki beliren özellikler gibi sistem düzeyinde ortaya çıkar ve tek bir parçaya indirgenemez.</p>

<p>Altı alandaki örüntüyü tek bir tabloda karşılaştırmak mümkün:</p>

<table>
  <thead>
    <tr>
      <th>Alan</th>
      <th>Kırılgan kalıp</th>
      <th>Antikırılgan kalıp</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Yazılım</td>
      <td>El değmemiş "kutsal" sunucu, manuel dağıtım</td>
      <td>Chaos engineering, otomatik rollback, blameless postmortem</td>
    </tr>
    <tr>
      <td>Proje ekibi</td>
      <td>Tek uzmana bağımlılık, hatayı gizleme</td>
      <td>Çapraz eğitim, psikolojik güvenlik, küçük deneyler</td>
    </tr>
    <tr>
      <td>Şirket</td>
      <td>Tek müşteri, aşırı borç, merkezî karar</td>
      <td>Barbell portföy, opsiyonellik, skin in the game</td>
    </tr>
    <tr>
      <td>Ürün</td>
      <td>Büyük "mükemmel" lansman</td>
      <td>MVP, A/B testi, kademeli dağıtım, geri bildirim döngüsü</td>
    </tr>
    <tr>
      <td>Topluluk</td>
      <td>Tek bakımcı, eleştiriye kapalılık</td>
      <td>Fork edilebilirlik, çeşitlilik, açık tartışma</td>
    </tr>
    <tr>
      <td>Sistem</td>
      <td>Tek senaryoya aşırı optimizasyon</td>
      <td>Artıklık, circuit breaker, ademimerkeziyet</td>
    </tr>
  </tbody>
</table>

<h2 id="tuzaklar-her-şey-antikırılgan-olmalı-mı">Tuzaklar: Her Şey Antikırılgan Olmalı mı?</h2>

<p>Burada önemli bir sınır var. “Antikırılganlık iyiyse, o hâlde her şeyi üretimde kırarak öğrenelim” çıkarımı tehlikeli bir yanlış okumadır. Her sistem antikırılgan olmak zorunda değildir; bazıları yalnızca dayanıklı olmalıdır. Bir uçağın uçuş kontrol yazılımında, üretim ortamında bilerek arıza üretmek söz konusu olamaz. DO‑178C ve özellikle en yüksek güvence seviyesi olan DAL A’nın bütün varlık nedeni, sistemin sahada deneme yanılmayla değil, daha uçmadan önce kanıtlanmış biçimde doğru çalıştığını göstermektir. Hatanın sonucunun geri döndürülemez olduğu alanlarda hedef dışbükeylik değil, öngörülebilir ve kanıtlanmış güvenilirliktir.</p>

<p>Bunun altında daha temel bir kural yatar: antikırılganlık ancak hayatta kalındığı sürece bir anlam taşır. Sistem bir kez tamamen çökerse, sonraki denemelerin beklenen getirisi ne olursa olsun konu dışıdır; Taleb bunu yıkım (ruin) ve ergodisite kavramlarıyla anlatır. Barbell stratejisinin önce aşağı yönü koruması da bu yüzdendir. Doğru sıra, önce sistemi tümüyle oyun dışı bırakacak şokları olanaksız kılmak, ardından kalan alanı volatiliteden faydalanmaya açmaktır. Bu sıranın tersine çevrilmesi, yani koruma sağlamadan risk almak, antikırılganlık değil yalnızca kumardır.</p>

<h2 id="sonuç">Sonuç</h2>

<p>Antikırılganlık, geleceği daha iyi tahmin etme çabası değil, tahmine bağımlı kalmadan belirsizlik karşısında doğru konumlanma yaklaşımıdır. Kırılgan bir yapı dünyanın tam olarak beklendiği gibi ilerlemesine bel bağlar; dayanıklı yapı sapmalara kayıtsız kalır; antikırılgan yapı ise sapmalardan yararlanacak biçimde kurulmuştur. Pratikte sorulması gereken soru “bu şoktan nasıl kaçınırım” değildir, çünkü bir sonraki şok çoğu zaman öngörülemez; daha verimli soru, hangi yapıların şoktan zarar yerine fayda görecek biçimde tasarlanabileceğidir. Taleb’in via negativa ilkesi gereği bu çoğu zaman yeni bir şey eklemekle değil, sistemi yıkıma açan kırılganlık kaynaklarını (tek bağımlılık noktası, aşırı kaldıraç, hatayı cezalandıran kültür, sınıra kadar yontulmuş optimizasyon) tek tek ortadan kaldırmakla başlar.</p>

<h2 id="kaynaklar">Kaynaklar</h2>

<ul>
  <li>Nassim Nicholas Taleb — <em>Antifragile: Things That Gain from Disorder</em>, Random House, 2012. (Türkçesi: <em>Antikırılgan: Belirsizlikten Nasıl Faydalanılır</em>)</li>
  <li>Nassim Nicholas Taleb — <em>The Black Swan: The Impact of the Highly Improbable</em>, Random House, 2007.</li>
  <li>Nassim Nicholas Taleb — <em>Skin in the Game: Hidden Asymmetries in Daily Life</em>, Random House, 2018.</li>
  <li>Nassim Nicholas Taleb — <em>Fooled by Randomness</em>, Texere, 2001.</li>
  <li>Principles of Chaos Engineering — <a href="https://principlesofchaos.org/">https://principlesofchaos.org/</a></li>
  <li>A. Basiri vd. — “Chaos Engineering”, <em>IEEE Software</em>, 2016 (Netflix Chaos Monkey / Simian Army).</li>
  <li>B. Beyer, C. Jones, J. Petoff, N. R. Murphy (ed.) — <em>Site Reliability Engineering</em>, O’Reilly, 2016 (error budget, blameless postmortem).</li>
  <li><a href="/2026/06/04/coupling-dengesi.html">Coupling’i Dengelemek: Yazılım Tasarımında Bağımlılığı Yönetmek</a></li>
  <li><a href="/2026/05/26/sistem-muhendisligi-nedir.html">Sistem Mühendisliği Nedir?</a></li>
</ul>]]></content><author><name>M. Serdar Karaman</name></author><summary type="html"><![CDATA[Mühendislikte uzun süredir tek bir niteliğin peşinden koşarız: dayanıklılık. Sistemin şoka, yüke ve arızaya rağmen ayakta kalmasını isteriz; emniyet-kritik alanlarda bunu bir zorunluluğa çeviririz. Oysa Nassim Nicholas Taleb’in Incerto serisinde işlediği temel iddia, dayanıklılığın bir uç değil bir orta nokta olduğudur. Kırılganın gerçek zıttı “kırılmayan” değildir; volatiliteden, stresten ve hatadan fayda gören, yani sarsıldıkça güçlenen bir şeydir.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://karaman.dev/img/og-default.webp" /><media:content medium="image" url="https://karaman.dev/img/og-default.webp" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry xml:lang="tr"><title type="html">Coupling’i Dengelemek: Yazılım Tasarımında Bağımlılığı Yönetmek</title><link href="https://karaman.dev/2026/06/04/coupling-dengesi.html" rel="alternate" type="text/html" title="Coupling’i Dengelemek: Yazılım Tasarımında Bağımlılığı Yönetmek" /><published>2026-06-04T09:00:00+00:00</published><updated>2026-06-04T09:00:00+00:00</updated><id>https://karaman.dev/2026/06/04/coupling-dengesi</id><content type="html" xml:base="https://karaman.dev/2026/06/04/coupling-dengesi.html"><![CDATA[<p>Bir satırlık bir değişiklik yaptınız: bir alanın adını <code class="language-plaintext highlighter-rouge">userId</code>‘den <code class="language-plaintext highlighter-rouge">accountId</code>‘ye çevirdiniz. Derleyici hata vermeye başladı. Bir dosyayı düzelttiniz, üç dosya daha kırmızı yandı. Onları da düzelttiniz; bu kez testler patladı. Yarım saat sonra “küçücük” değişikliğiniz on iki dosyaya, iki servise ve bir veritabanı şemasına dokunmuştu. Tanıdık geldi mi?</p>

<p>Çoğumuz bu acıya bir isim veririz: <strong>coupling</strong> (bağlaşım). Ve hemen ardından bir reçete yazarız: “Demek ki daha az coupling lazım, her şeyi birbirinden ayıralım (<em>decouple</em> edelim).” Ekip bu uğurda kodu mikroservislere böler — ve birkaç ay sonra, ağ üzerinden birbirine eskisinden de sıkı bağlı, ama bu kez hata ayıklaması çok daha zor bir sisteme uyanır.</p>

<p>Sorun coupling’in <em>kötü</em> olması değil; sorun onu yanlış anlamamız. Vlad Khononov’un 2024 tarihli kitabı <strong><em>Balancing Coupling in Software Design</em></strong> tam da bunu söylüyor: coupling, yok edilecek bir kusur değil, <strong>dengelenecek bir tasarım niteliğidir</strong>. Bu yazıda önce coupling’in ne olduğunu ve neden ondan tamamen kurtulamayacağımızı göreceğiz; sonra Khononov’un onu ölçmek için sunduğu üç boyutlu modeli inceleyeceğiz; ve son olarak bu fikrin en uca taşındığı yere, aviyonik yazılımın <strong>DO‑178C</strong> standardına bakacağız — orada coupling’i analiz etmek bir tercih değil, bir sertifikasyon şartıdır.</p>

<hr />

<h2 id="coupling-nedir-ve-neden-ondan-tamamen-kurtulamayız">Coupling Nedir? (Ve Neden Ondan Tamamen Kurtulamayız?)</h2>

<p>En yalın tanımıyla coupling, iki bileşen arasındaki bağımlılıktır: <em>birindeki değişikliğin diğerinde de değişiklik gerektirme ihtimali.</em> İki modül birbirine ne kadar sıkı bağlıysa, birlikte değişme olasılıkları da o kadar yüksektir.</p>

<p>Khononov bu bağımlılığın özünde iki şeyin yattığını söyler: <strong>paylaşılan bilgi</strong> (<em>shared knowledge</em>) ve <strong>paylaşılan yaşam döngüsü</strong> (<em>shared lifecycle</em>). Bir bileşen, diğeri hakkında ne kadar çok şey “bilmek” zorundaysa — onun veri yapısını, kurallarını, iç işleyişini — o kadar bağlıdır. Ve o bilgi değiştiğinde, ona bağlı her yerin de değişmesi gerekir.</p>

<p>Burada kritik bir nokta var: coupling yalnızca yazılıma özgü değildir. Aynı ilişki bir organizasyonda (bir departmanın kararı diğerini etkiler), bir makinede (bir dişlinin dönüşü diğerini sürer), hatta bir takımda da vardır. Coupling, <em>birbiriyle etkileşen parçalardan oluşan her sistemin</em> doğal bir özelliğidir.</p>

<p>Peki neden ondan tamamen kurtulamayız? Çünkü <strong>sıfır coupling’e sahip bir sistem, aslında bir sistem değildir.</strong> Birbiriyle hiç konuşmayan, hiçbir bilgi paylaşmayan bileşenler bir bütün oluşturmaz; yalnızca yan yana duran, birbirinden habersiz parçalar yığını olur. Bir sistemin değeri — uçağın uçması, uygulamanın iş görmesi — tam da parçaların <em>birlikte</em> çalışmasından, yani onları birbirine bağlayan ilişkilerden doğar. Daha önce <a href="/2026/05/26/sistem-muhendisligi-nedir.html">Sistem Mühendisliği Nedir?</a> yazısında değindiğimiz <strong>beliren özellikler</strong> (<em>emergent properties</em>) işte bu bağlardan ortaya çıkar.</p>

<p>Coupling, sistemi bir arada tutan tutkaldır. Tutkalsız sistem dağılır; ama her yeri tutkala bulanmış sistem de kıpırdayamaz. O yüzden doğru soru “coupling’den nasıl kurtulurum?” değildir. Doğru soru şudur: <strong>Ne tür, ne kadar ve nerede?</strong></p>

<hr />

<h2 id="decoupling-her-zaman-i̇yidir-efsanesi">“Decoupling Her Zaman İyidir” Efsanesi</h2>

<p>Yazılım kültüründe neredeyse bir slogan vardır: “sıkı bağ değil, gevşek bağ” (<em>loose coupling</em>). Bu öğüt iyi niyetlidir ama yarım kalmıştır; çünkü madalyonun iki yüzü vardır.</p>

<p>Bir uçta <strong>aşırı coupling</strong> bulunur: her şeyin her şeye bağlı olduğu, tek bir değişikliğin sistemin yarısını tetiklediği, kimsenin elini sürmeye cesaret edemediği “büyük çamur topu” (<em>big ball of mud</em>). Bunu hepimiz biliriz.</p>

<p>Diğer uçta ise daha sinsi bir tehlike vardır: <strong>aşırı decoupling</strong>. Bağımlılıktan kaçmak uğruna araya gereksiz katmanlar, soyutlamalar ve dolaylılıklar (<em>indirection</em>) koyarsınız. Tek bir akışı anlamak için yedi dosya ile üç arayüz arasında zıplamak gerekir. En meşhur örneği, gerçekte birbirine sıkı sıkıya bağlı bileşenleri ayrı servislere bölüp aralarına bir de ağ koyan <strong>dağıtık çamur topu</strong> (<em>distributed big ball of mud</em>) — yani yanlış kurgulanmış mikroservislerdir. Bağımlılık ortadan kalkmamıştır; yalnızca görünmez olmuş, üstüne bir de ağ gecikmesi ve dağıtık hata ayıklama derdi eklenmiştir.</p>

<p>Khononov bunu <strong>arızi karmaşıklık</strong> (<em>accidental complexity</em>) ile açıklar: problemin kendisinden değil, onu çözmek için yaptığımız kötü tasarım tercihlerinden doğan karmaşıklık. Hem aşırı coupling hem de aşırı decoupling arızi karmaşıklık üretir. Demek ki iyi tasarım bir uçta değil, <strong>dengededir</strong>. Geriye tek soru kalıyor: Bu dengeyi nasıl bulacağız? İşte Khononov’un asıl katkısı burada başlıyor.</p>

<hr />

<h2 id="couplingi-ölçmek-khononovun-üç-boyutu">Coupling’i Ölçmek: Khononov’un Üç Boyutu</h2>

<p>Khononov’un en güçlü fikri, coupling’i tek bir “az/çok” ölçeğine sıkıştırmayı bırakıp onu <strong>üç ayrı boyutta</strong> ele almaktır. Bir bağlantının iyi mi kötü mü olduğunu bu üç boyut birlikte belirler:</p>

<ol>
  <li><strong>Entegrasyon gücü</strong> — ne kadar bilgi paylaşılıyor?</li>
  <li><strong>Mesafe</strong> — bileşenler birbirine ne kadar uzak?</li>
  <li><strong>Oynaklık</strong> — ne sıklıkta değişiyor?</li>
</ol>

<p>Bunları tek tek görelim.</p>

<h3 id="1-entegrasyon-gücü-integration-strength">1. Entegrasyon Gücü (Integration Strength)</h3>

<p>Entegrasyon gücü, iki bileşenin birbiriyle <em>ne tür ve ne kadar</em> bilgi paylaştığını anlatır. Khononov bunu, en güçlüden (en çok bilgi paylaşan, en kırılgan) en zayıfa (en az bilgi paylaşan, en sağlam) doğru dört seviyeye ayırır:</p>

<table>
  <thead>
    <tr>
      <th>Seviye</th>
      <th>Ne paylaşılır?</th>
      <th>Sonuç</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>**İçe nüfuz eden** (*intrusive*)</td>
      <td>Başka bir bileşenin *iç* detayları: private alanları, veritabanı tabloları, gizli varsayımları</td>
      <td>En kırılgan ve en örtük. Karşı taraf habersizce her an değişebilir</td>
    </tr>
    <tr>
      <td>**Fonksiyonel** (*functional*)</td>
      <td>Ortak bir iş kuralı / fonksiyonel gereksinim</td>
      <td>Kural değişince bağlı tüm bileşenler birlikte değişmek zorunda</td>
    </tr>
    <tr>
      <td>**Model** (*model*)</td>
      <td>Ortak bir alan (*domain*) modeli</td>
      <td>Model evrildikçe onu paylaşan herkes etkilenir</td>
    </tr>
    <tr>
      <td>**Sözleşme** (*contract*)</td>
      <td>Yalnızca açıkça yayımlanmış bir arayüz/sözleşme</td>
      <td>En zayıf ve en sağlam. İç detaylar gizlenir; sözleşme sabit kaldıkça taraflar bağımsız değişir</td>
    </tr>
  </tbody>
</table>

<div class="mermaid">
flowchart LR
    A["İçe nüfuz eden<br />intrusive"] --&gt; B["Fonksiyonel<br />functional"] --&gt; C["Model<br />model"] --&gt; D["Sözleşme<br />contract"]
    style A fill:#f6c1c1,stroke:#c0392b,stroke-width:2px
    style B fill:#f6d8c1,stroke:#cb6b2b,stroke-width:2px
    style C fill:#f6edc1,stroke:#b39a2b,stroke-width:2px
    style D fill:#cfe8cf,stroke:#2e7d32,stroke-width:2px
</div>

<p>Soldan sağa gidildikçe paylaşılan bilgi azalır, sağlamlık artar. En tepedeki <em>içe nüfuz eden</em> bağlaşım, bir bileşenin başka bir bileşenin kapağını açıp içine elini sokmasıdır — örneğin onun veritabanı tablosunu doğrudan okumak. En alttaki <em>sözleşme</em> bağlaşımı ise kapıdaki posta kutusundan konuşmaktır: arkada ne olduğunu bilmezsiniz, yalnızca sözleşmeye güvenirsiniz.</p>

<p>Aradaki farkı küçük bir örnekle görelim:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># KIRILGAN — içe nüfuz eden bağlaşım (intrusive)
# Sipariş modülü, Kullanıcı modülünün VERİTABANI TABLOSUNU doğrudan okuyor.
# "users" tablosunun yapısı değişirse sipariş modülü de kırılır.
</span><span class="k">def</span> <span class="nf">siparis_indirimi</span><span class="p">(</span><span class="n">kullanici_id</span><span class="p">):</span>
    <span class="n">row</span> <span class="o">=</span> <span class="n">db</span><span class="p">.</span><span class="nf">query</span><span class="p">(</span><span class="sh">"</span><span class="s">SELECT loyalty_tier FROM users WHERE id = ?</span><span class="sh">"</span><span class="p">,</span> <span class="n">kullanici_id</span><span class="p">)</span>
    <span class="k">return</span> <span class="mf">0.20</span> <span class="k">if</span> <span class="n">row</span><span class="p">.</span><span class="n">loyalty_tier</span> <span class="o">==</span> <span class="sh">"</span><span class="s">GOLD</span><span class="sh">"</span> <span class="k">else</span> <span class="mf">0.0</span>
</code></pre></div></div>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># SAĞLAM — sözleşme bağlaşımı (contract)
# Sipariş modülü, Kullanıcı modülünün YAYIMLADIĞI arayüzü çağırıyor.
# Kullanıcı modülü içeride ne yaparsa yapsın, sözleşme sabit kaldıkça sağlam kalır.
</span><span class="k">def</span> <span class="nf">siparis_indirimi</span><span class="p">(</span><span class="n">kullanici_id</span><span class="p">):</span>
    <span class="n">seviye</span> <span class="o">=</span> <span class="n">kullanici_servisi</span><span class="p">.</span><span class="nf">sadakat_seviyesi</span><span class="p">(</span><span class="n">kullanici_id</span><span class="p">)</span>   <span class="c1"># sözleşme
</span>    <span class="k">return</span> <span class="n">INDIRIM_TABLOSU</span><span class="p">[</span><span class="n">seviye</span><span class="p">]</span>
</code></pre></div></div>

<p>İki kod da aynı işi yapıyor. Ama ilki, Kullanıcı modülünün veritabanı şemasına <em>gizlice</em> bağımlı; ikincisi yalnızca yayımlanmış bir sözleşmeye. Birincisinde <code class="language-plaintext highlighter-rouge">users</code> tablosuna eklenen masum bir değişiklik sipariş modülünü çökertebilir; ikincisinde Kullanıcı modülü içini baştan yazsa bile, <code class="language-plaintext highlighter-rouge">sadakat_seviyesi</code> sözleşmesi durduğu sürece sipariş modülü habersizdir.</p>

<p>Bu dört seviyelik fikir gökten zembille inmedi. Khononov burada, yazılım tasarımının köklerindeki iki klasik fikri — Larry Constantine’in 1970’lerdeki coupling türlerini ve Meilir Page‑Jones’un connascence kavramını — tek bir ölçekte birleştirir. (Birazdan bu soy ağacına döneceğiz.)</p>

<h3 id="2-mesafe-distance">2. Mesafe (Distance)</h3>

<p>İkinci boyut, coupling’in <em>mekânsal</em> ölçüsüdür: birbirine bağlı iki bileşen fiziksel ve örgütsel olarak ne kadar uzakta? Yakından uzağa doğru bir yelpaze düşünün:</p>

<blockquote>
  <p>aynı metot içi → aynı sınıf → aynı modül → aynı namespace → ayrı servis → ayrı sistem → ayrı ekip/şirket</p>
</blockquote>

<p>Mesafe neden önemli? Çünkü zincirleme bir değişiklik gerektiğinde, <strong>o değişikliği hayata geçirmenin maliyeti mesafeyle birlikte artar.</strong> Aynı sınıftaki iki metodu birlikte değiştirmek dakikalar sürer. Ama iki bağımlı bileşen, ayrı ekiplerin sahip olduğu ayrı servislerdeyse, aynı değişiklik artık toplantılar, sürüm planları, API versiyonlama ve ekipler arası koordinasyon demektir. Khononov buna <strong>sahiplik mesafesi</strong> (<em>ownership distance</em>) der: bilgi ne kadar uzun yol kat ederse, onu değiştirmenin koordinasyon yükü o kadar büyür.</p>

<h3 id="3-oynaklık-volatility">3. Oynaklık (Volatility)</h3>

<p>Üçüncü boyut zamansaldır: bu bileşen ne sıklıkta değişiyor? Çünkü coupling’in bedeli ancak <strong>değişiklik olduğunda</strong> ödenir. Hiç değişmeyen bir bileşene sımsıkı bağlı olmak neredeyse bedavadır — bağ asla “tetiklenmez”. Ama sürekli evrilen, oynak bir bileşene aynı sıkılıkta bağlı olmak, her değişiklikte zincirleme acı demektir.</p>

<p>Bir kodun ne kadar oynak olduğunu kestirmek için Khononov, Alan Güdümlü Tasarım’ın (<em>Domain-Driven Design</em>) alt‑alan (<em>subdomain</em>) sınıflamasından yararlanır: işin kalbindeki, rekabet avantajı yaratan <strong>çekirdek</strong> (<em>core</em>) alanlar en sık değişir; <strong>destekleyici</strong> (<em>supporting</em>) ve hazır çözülebilen <strong>genel</strong> (<em>generic</em>) alanlar daha durağandır. Khononov’un çarpıcı sözüyle: <strong><em>oynaklık, modülerliği opsiyonel kılar.</em></strong> Kararlı koda sıkıca bağlanmak başlı başına bir sorun değildir; çünkü o bağ pratikte hiç sınanmaz.</p>

<hr />

<h2 id="üçünü-birleştirmek-denge-formülü">Üçünü Birleştirmek: Denge Formülü</h2>

<p>Asıl güzellik, bu üç boyut bir araya geldiğinde ortaya çıkar. Khononov tüm kitabın özünü tek bir mantıksal ifadeye sığdırır:</p>

<blockquote>
  <p><strong>denge = (güç XOR mesafe) VEYA DEĞİL(oynaklık)</strong></p>
</blockquote>

<p>Korkutucu görünebilir ama söylediği şey son derece sezgiseldir. <code class="language-plaintext highlighter-rouge">XOR</code> (özel veya), “ikisinden <em>yalnızca biri</em>” demektir. Yani sağlıklı bir tasarımda güç ile mesafe <strong>birbirine zıt</strong> olmalıdır:</p>

<table>
  <thead>
    <tr>
      <th> </th>
      <th>**Yakın mesafe**</th>
      <th>**Uzak mesafe**</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>**Güçlü bağ**</td>
      <td>✅ İyi — birlikte değişenleri yan yana tut</td>
      <td>❌ **Küresel karmaşıklık**</td>
    </tr>
    <tr>
      <td>**Zayıf bağ**</td>
      <td>⚠️ **Yerel karmaşıklık**</td>
      <td>✅ İyi — modüler, bağımsız evrilir</td>
    </tr>
  </tbody>
</table>

<p>Köşeleri okuyalım:</p>

<ul>
  <li><strong>Güçlü + yakın = iyi.</strong> Çok bilgi paylaşan iki şey aynı yerde durursa, onları birlikte değiştirmek kolaydır. Sıkı bağ burada sorun değil.</li>
  <li><strong>Zayıf + uzak = iyi.</strong> Az bilgi paylaşan şeyleri ayrı servislere/modüllere dağıtmak modülerliktir; her biri kendi başına yaşar.</li>
  <li><strong>Güçlü + uzak = felaket.</strong> Çok şey paylaşan ama birbirinden uzak bileşenler <strong>küresel karmaşıklık</strong> üretir; bir bilgi parçası sistemin bir ucundan diğerine yolculuk eder. Buna bir de oynaklık eklenince ortaya o meşhur <strong>dağıtık çamur topu</strong> çıkar.</li>
  <li><strong>Zayıf + yakın = israf.</strong> Birbiriyle alakasız şeyleri aynı sınıfa tıkıştırmak gereksiz <strong>yerel karmaşıklık</strong> yaratır.</li>
</ul>

<p>Peki <code class="language-plaintext highlighter-rouge">VEYA DEĞİL(oynaklık)</code> kısmı? O da şunu söyler: bir bileşen <strong>kararlıysa (oynak değilse)</strong>, yukarıdaki dengesizliğe katlanabilirsiniz — çünkü o bağ zaten hiç sınanmayacaktır. Modülerlik bedava değildir; ödediğiniz “modülerlik vergisini” yalnızca sık değişen yerlerde ödemeye değer.</p>

<p>Bu modeli pratiğe dökmek üç basit sezgisel kurala iner:</p>

<ul>
  <li><strong>Çok bilgi paylaşıyorlarsa, yakın tut.</strong> (Güçlü bağı kısa mesafeyle dengele.)</li>
  <li><strong>Uzaktalarsa, paylaşılan bilgiyi azalt.</strong> (Mikroservis sınırını ancak gerçek bir sözleşmeyle geç.)</li>
  <li><strong>Kararlıysa, modülerlik zahmetine girme.</strong> (Oynak olmayan yere mühendislik gücü harcama.)</li>
</ul>

<p>Dikkat edin: bu, “küçük ve dağıtık her zaman daha basittir” diyen popüler mikroservis söylemine doğrudan bir itirazdır. Bileşenleri küçültüp uzaklaştırmak, aralarındaki bilgi paylaşımı (güç) hâlâ yüksekse, sistemi <em>basitleştirmez</em>; tam tersine küresel karmaşıklığı artırır.</p>

<hr />

<h2 id="kısa-bir-tarih-constantineden-connascencea">Kısa Bir Tarih: Constantine’den Connascence’a</h2>

<p>Coupling, yazılım mühendisliğinin en eski kavramlarından biridir; Khononov’un modeli de bu birikimin üzerine kuruludur.</p>

<ul>
  <li><strong>Larry Constantine (1970’ler).</strong> <em>Yapısal Tasarım</em> (<em>Structured Design</em>) çalışmasında coupling’i ilk kez sistematik biçimde sınıflandırdı. En güçlüden (en kötü) en zayıfa (en iyi) doğru türleri şöyleydi: <em>içerik</em> (<em>content</em>), <em>ortak</em> (<em>common</em>), <em>dış</em> (<em>external</em>), <em>kontrol</em> (<em>control</em>), <em>damga</em> (<em>stamp</em>) ve <em>veri</em> (<em>data</em>) bağlaşımı. Bu sınıflama on yıllar boyunca — ve birazdan göreceğimiz gibi DO‑178C dâhil — sahada referans oldu.</li>
  <li><strong>Meilir Page‑Jones (1990’lar).</strong> <em>Connascence</em> kavramıyla coupling’i ölçülebilir hâle getirdi. İki bileşen, biri değişince diğeri de değişmek zorundaysa “connascent”tir. Page‑Jones bağı üç eksende değerlendirdi: <strong>güç</strong> (değiştirmek ne kadar zor), <strong>yerellik</strong> (bileşenler ne kadar yakın) ve <strong>derece</strong> (kaç bileşeni etkiliyor) — Khononov’un güç ve mesafe boyutlarının doğrudan atası.</li>
  <li><strong>David Parnas.</strong> <em>Bilgi gizleme</em> (<em>information hiding</em>) ilkesiyle modüllerin birbirinden iç kararları değil yalnızca <em>sözleşmeyi</em> bilmesi gerektiğini savundu — yani “sözleşme bağlaşımı”nın felsefi temelini attı.</li>
</ul>

<p>Khononov’un katkısı, bu dağınık mirası tek bir tutarlı çerçevede — entegrasyon gücü, mesafe, oynaklık — toplamasıdır. Ve buradan güvenlik‑kritik dünyaya zarif bir köprü uzanır: DO‑178C’nin coupling diline doğrudan Constantine’in terimleriyle, <strong>veri bağlaşımı</strong> ve <strong>kontrol bağlaşımı</strong> ile gireriz.</p>

<hr />

<h2 id="güvenlikkritik-dünyada-coupling-do178c">Güvenlik‑Kritik Dünyada Coupling: DO‑178C</h2>

<p>Şimdiye kadar coupling’i bir tasarım <em>tercihi</em> olarak konuştuk: iyi mühendis dengeyi gözetir, kötüsü gözetmez. Peki ya yanlış dengenin bedeli bir insanın canıysa?</p>

<p>Uçak yazılımının geliştirildiği dünyada coupling artık bir üslup meselesi değildir; <strong>kanıtlanması zorunlu bir sertifikasyon şartıdır.</strong> Sivil havacılıkta uçuş yazılımı, RTCA ve EUROCAE’nin ortaklaşa hazırladığı <strong>DO‑178C</strong> standardına (Avrupa’daki adıyla <em>ED‑12C</em>) göre geliştirilir ve denetlenir. Bu, daha önce <a href="/2026/04/05/misra-c-2025-ile-neler-degisti.html">MISRA C</a> yazısında değindiğimiz türden emniyet‑kritik bir disiplindir — ama bir adım öteye geçip doğrudan bileşenler <em>arasındaki</em> bağları hedef alır.</p>

<p>DO‑178C, Constantine’den miras aldığı iki terimi resmî olarak tanımlar:</p>

<blockquote>
  <p><strong>Veri bağlaşımı (<em>data coupling</em>):</strong> Bir bileşenin, münhasıran kendi kontrolünde olmayan veriye bağımlılığı.</p>
</blockquote>

<blockquote>
  <p><strong>Kontrol bağlaşımı (<em>control coupling</em>):</strong> Bir bileşenin, başka bir bileşenin yürütülmesini (ne zaman, hangi koşulda çalışacağını) etkileme biçimi veya derecesi.</p>
</blockquote>

<p>Standart, bu bağların yalnızca <em>var olduğunu</em> kabul etmekle yetinmez; doğrulama sürecinin bir <strong>objektifi</strong> olarak (DO‑178C’nin meşhur <em>Tablo A‑7</em>‘sinde) şunu talep eder: <strong>Gereksinim temelli testlerin, bileşenler arasındaki veri ve kontrol bağımlılıklarını gerçekten <em>çalıştırdığını</em> kanıtlayın.</strong> Burada DO‑178C, selefi DO‑178B’den ayrılır: eskiden bağları yalnızca <em>tanımlamak</em> yeterken, DO‑178C onların testlerle <em>uygulandığını</em> göstermeyi ister.</p>

<p>Bu gereklilik her yazılım için aynı değildir. DO‑178C, olası bir arızanın yol açacağı sonucun ağırlığına göre beş <strong>tasarım güvence seviyesi</strong> (<em>Design Assurance Level</em>, DAL) tanımlar:</p>

<table>
  <thead>
    <tr>
      <th>DAL</th>
      <th>Arıza sonucu</th>
      <th>Coupling analizi</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>**A**</td>
      <td>Felaketle sonuçlanan (uçak kaybı)</td>
      <td>Gerekli — *bağımsızlıkla*</td>
    </tr>
    <tr>
      <td>**B**</td>
      <td>Tehlikeli</td>
      <td>Gerekli — *bağımsızlıkla*</td>
    </tr>
    <tr>
      <td>**C**</td>
      <td>Büyük</td>
      <td>Gerekli</td>
    </tr>
    <tr>
      <td>**D**</td>
      <td>Küçük</td>
      <td>Gerekmez</td>
    </tr>
    <tr>
      <td>**E**</td>
      <td>Emniyete etkisiz</td>
      <td>Gerekmez</td>
    </tr>
  </tbody>
</table>

<p>En kritik A ve B seviyelerinde, coupling analizinin geliştiriciden <strong>bağımsız</strong> bir gözle doğrulanması şarttır. (Daha önce <a href="/2022/07/11/fonksiyonel-olmayan-yazilim-gereksinimleri.html">Fonksiyonel Olmayan Yazılım Gereksinimleri</a> yazısında bir aviyonik projenin DAL A gereksinimlerine kısaca değinmiştik.)</p>

<p>Peki bu analiz tam olarak ne yapar? Burada güzel bir tamamlayıcılık vardır. Klasik <strong>yapısal kapsama</strong> ölçütleri — deyim (<em>statement</em>), karar (<em>decision</em>) ve modern uçakların A seviyesinde istediği <strong>MC/DC</strong> (<em>Modified Condition/Decision Coverage</em>) — bir bileşenin <em>içindeki</em> tüm kod yollarının test edildiğini gösterir. Ama bir bileşen tek başına kusursuz olabilir ve yine de başka bir bileşenle <em>birleştiğinde</em> patlayabilir. Veri ve kontrol bağlaşım analizi tam bu boşluğu kapatır: bileşenlerin <em>arasındaki</em> etkileşimleri hedefler — yani <a href="/2022/04/29/yazilim-sistem-muhendisligi.html">yazılım sistem mühendisliğinde</a> V modelinin sağ kolundaki entegrasyon ve doğrulama adımlarının ta kendisidir.</p>

<div class="mermaid">
flowchart LR
    subgraph A["Bileşen A"]
      AI["iç mantık"]
    end
    subgraph B["Bileşen B"]
      BI["iç mantık"]
    end
    A == "kontrol bağlaşımı: çağrı / dönüş" ==&gt; B
    A -. "veri bağlaşımı: paylaşılan veri" .-&gt; B
    style AI fill:#e8eef7,stroke:#4a6fa5,stroke-width:2px
    style BI fill:#e8eef7,stroke:#4a6fa5,stroke-width:2px
</div>

<p>Yapısal kapsama kutuların <em>içini</em> test eder; veri ve kontrol bağlaşım analizi ise kutular <em>arasındaki okları</em> test eder. Pratikte ölçüm iki ayrı şekilde yapılır: <strong>kontrol bağlaşımı</strong> için çağrı‑çiftleri (<em>call‑pair</em>) ve dönüşlerin kapsanması — yani bileşenler arası her çağrının en az bir testte gerçekten yürütülmüş olması; <strong>veri bağlaşımı</strong> için ise “yaz‑oku” (<em>set‑use</em> / <em>define‑use</em>) çiftlerinin kapsanması — yani bir bileşenin yazdığı her verinin, onu okuyan bileşen tarafından bir testte gerçekten kullanılmış olması.</p>

<p>Bütün bu titizliğin sebebi tek bir kavramdır: <strong>birleşim tehlikesi</strong> (<em>composition hazard</em>). Havacılık tarihi, tek tek doğru çalışan bileşenlerin birleştiğinde — beklenmedik bir veri paylaşımı, dokümante edilmemiş bir yan etki ya da yanlış sırada tetiklenen bir çağrı yüzünden — başarısız olabildiğini acı tecrübelerle öğrendi. Hatalar çoğu zaman bileşenlerin <em>içinde</em> değil, <strong>aralarındaki arayüzlerde</strong> yaşar. DO‑178C, bu arayüzlerin görünür kılınmasını ve test edilmesini <em>zorunlu</em> tutarak riski kökünden hedefler.</p>

<hr />

<h2 id="i̇ki-dünya-tek-ders">İki Dünya, Tek Ders</h2>

<p>İlk bakışta bir tasarım kitabıyla bir havacılık standardı uzak akrabalar gibi görünür. Oysa ikisi aynı gerçeğin iki yüzüdür.</p>

<p>Khononov bize bir <strong>akıl yürütme çerçevesi</strong> verir: coupling’i üç boyutta düşün, dengeyi bilinçli kur, nereye ne kadar bağ koyacağına <em>karar ver</em>. DO‑178C ise bir <strong>doğrulama disiplini</strong> dayatır: bağları belgele, görünür kıl ve testlerle <em>çalıştığını kanıtla</em>. Biri “nasıl tasarlamalı”, diğeri “nasıl ispatlamalı” sorusunu yanıtlar.</p>

<p>Ama ikisinin de altında yatan içgörü aynıdır: <strong>risk, bileşenlerin içinde değil, aralarındaki bağlarda ve paylaşılan bilgide yoğunlaşır.</strong> İster Khononov’un entegrasyon gücü merdiveni olsun, ister DO‑178C’nin veri/kontrol bağlaşımı ayrımı — ikisi de aynı şeyi söyler: coupling’i örtük bırakma; onu açık, bilinçli ve mümkünse test edilebilir kıl.</p>

<p>Aradaki tek fark <strong>bahsin büyüklüğüdür</strong>. Bir CRUD uygulamasında yanlış kurulmuş bir bağ, en kötü ihtimalle bir gece yarısı acil yamasıdır. Bir uçuş kontrol bilgisayarında aynı hata, can demektir. Bu yüzden havacılık, iyi mühendisin her yerde <em>gönüllü</em> yapması gerekeni <em>zorunlu</em> kılar. Disiplin aynıdır; yalnızca hata payı farklıdır.</p>

<p>Khononov’un üç boyutuyla DO‑178C’nin iki bağlaşım türü arasında hoş bir yankı da vardır: kontrol bağlaşımı, “bir bileşen diğerinin <em>ne zaman</em> çalışacağını etkiliyor” demektir; veri bağlaşımı ise “bir bileşen diğerinin <em>neyi gördüğünü</em> etkiliyor”. Paylaşılan kontrol akışı ve paylaşılan veri — coupling dediğimiz şeyin en temel iki biçimi, ister bir mikroservis mimarisinde ister bir uçuş bilgisayarında olsun.</p>

<hr />

<h2 id="sonuç">Sonuç</h2>

<p>Coupling’i yıllarca yanlış sevdik: ondan kaçmaya, onu yok etmeye çalıştık. Oysa coupling, sistemi sistem yapan şeydir; mesele onu <em>yok etmek</em> değil, <strong>dengelemektir</strong>.</p>

<p>Khononov’un bıraktığı pratik miras birkaç cümleye sığar:</p>

<ul>
  <li>Coupling kaçınılmaz ve gereklidir; hedef sıfır bağ değil, <strong>doğru bağdır</strong>.</li>
  <li>Her bağı üç boyutta tart: <strong>güç</strong> (ne kadar bilgi paylaşılıyor), <strong>mesafe</strong> (ne kadar uzak), <strong>oynaklık</strong> (ne sıklıkta değişiyor).</li>
  <li>Dengeyi kur: <em>güçlü bağları yakın tut, uzaktakileri sözleşmeyle gevşet, kararlı yerlere modülerlik vergisi ödeme.</em></li>
  <li>Ve en önemlisi: coupling’i <strong>örtük bırakma</strong>. Onu görünür, bilinçli ve — bahis büyükse — test edilebilir kıl.</li>
</ul>

<p>Havacılık bu son ilkeyi bir standarda yazıp imza zorunluluğu getirdi. Geri kalanımız için ise bu, henüz yazılmamış ama her iyi tasarımın içinde yaşayan bir sözleşmedir. İster bir mobil uygulama yazın, ister bir uçuş kontrol sistemi: er ya da geç, sistemin kaderini bileşenlerin tek tek kalitesi değil, <strong>aralarındaki bağların dengesi</strong> belirleyecektir.</p>

<hr />

<p><strong>Kaynaklar:</strong></p>

<ul>
  <li>Vlad Khononov — <a href="https://www.informit.com/store/balancing-coupling-in-software-design-universal-design-9780137353538"><em>Balancing Coupling in Software Design</em></a> (Addison‑Wesley, 2024).</li>
  <li><a href="https://coupling.dev/">coupling.dev</a> — kitabın kavramlarını derleyen tamamlayıcı kaynak.</li>
  <li>Meilir Page‑Jones — <em>What Every Programmer Should Know About Object-Oriented Design</em> (1995). Ayrıca <a href="https://en.wikipedia.org/wiki/Connascence">Connascence (Wikipedia)</a>.</li>
  <li>Edward Yourdon, Larry Constantine — <em>Structured Design</em> (Prentice Hall, 1979).</li>
  <li>RTCA/EUROCAE — DO‑178C / ED‑12C, <em>Software Considerations in Airborne Systems and Equipment Certification</em> (2011). Genel bakış: <a href="https://en.wikipedia.org/wiki/DO-178C">DO‑178C (Wikipedia)</a>.</li>
  <li>Rapita Systems — <a href="https://www.rapitasystems.com/dccc">Data Coupling &amp; Control Coupling for DO‑178C</a>.</li>
  <li>LDRA — <a href="https://ldra.com/capabilities/data-couplingcontrol-coupling/">Data Coupling and Control Coupling (DCCC) analysis</a>.</li>
  <li>FAA — <a href="https://www.faa.gov/regulations_policies/advisory_circulars/index.cfm/go/document.information/documentID/1032046">AC 20‑115D, Airborne Software Development Assurance</a>.</li>
</ul>]]></content><author><name>M. Serdar Karaman</name></author><category term="yazilim" /><category term="yazilim-tasarimi" /><category term="yazilim-muhendisligi" /><summary type="html"><![CDATA[Bir satırlık bir değişiklik yaptınız: bir alanın adını userId‘den accountId‘ye çevirdiniz. Derleyici hata vermeye başladı. Bir dosyayı düzelttiniz, üç dosya daha kırmızı yandı. Onları da düzelttiniz; bu kez testler patladı. Yarım saat sonra “küçücük” değişikliğiniz on iki dosyaya, iki servise ve bir veritabanı şemasına dokunmuştu. Tanıdık geldi mi?]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://karaman.dev/img/og-default.webp" /><media:content medium="image" url="https://karaman.dev/img/og-default.webp" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry xml:lang="tr"><title type="html">Kalman Filtresi ve EKF: Gürültülü Veriden Gizli Durumu Kestirmek</title><link href="https://karaman.dev/2026/06/02/kalman-filtresi.html" rel="alternate" type="text/html" title="Kalman Filtresi ve EKF: Gürültülü Veriden Gizli Durumu Kestirmek" /><published>2026-06-02T09:00:00+00:00</published><updated>2026-06-02T09:00:00+00:00</updated><id>https://karaman.dev/2026/06/02/kalman-filtresi</id><content type="html" xml:base="https://karaman.dev/2026/06/02/kalman-filtresi.html"><![CDATA[<p>Telefonunuz masanın üzerinde dururken bile GPS noktası birkaç metre oraya buraya zıplar. Arabadaki ivmeölçer mükemmel veri verir ama integralini aldığınızda hata saniyeler içinde birikip sürüklenir (drift). Tek başına ne sensöre ne de modele güvenebilirsiniz — yine de haritadaki maviniz pürüzsüz, kararlı bir çizgi çizer. Bu sihrin arkasındaki makine çoğu zaman aynıdır: <strong>Kalman filtresi</strong>.</p>

<p>Kalman filtresi, 1960’ta Rudolf Kálmán’ın ortaya koyduğundan beri uzay araçlarından telefonunuza, robotlardan finansal modellere kadar her yerde çalışan, gürültülü ölçümler ile kusurlu bir hareket modelini optimal şekilde <strong>harmanlayan</strong> özyinelemeli bir kestirimcidir. Bu yazıda filtreyi sıfırdan kuracağız: önce Gauss dağılımlarını birleştirme sezgisiyle, sonra doğrusal durum-uzay modeliyle, ardından doğrusal-olmayan dünyaya geçişi sağlayan <strong>Genişletilmiş Kalman Filtresi (EKF)</strong> ile. Yol boyunca hem NumPy ile tam çalışan Python kodları hem de tarayıcınızda canlı oynayabileceğiniz iki etkileşimli simülatör olacak.</p>

<hr />

<h2 id="problem-gizli-durumu-gürültünün-altından-çıkarmak">Problem: Gizli Durumu Gürültünün Altından Çıkarmak</h2>

<p>Bir sistemin gerçekten bilmek istediğimiz büyüklüklerine <strong>durum</strong> (state) diyelim ve <code class="language-plaintext highlighter-rouge">x</code> ile gösterelim — bir cismin konumu ve hızı, bir uydunun yörünge parametreleri, bir bataryanın şarj seviyesi. Sorun şu ki durumu doğrudan göremeyiz. Elimizde sadece iki kusurlu bilgi kaynağı vardır:</p>

<ol>
  <li><strong>Bir hareket modeli.</strong> Fizik bize “bir sonraki adımda durum kabaca şu olur” der. Ama model idealdir; rüzgâr, sürtünme, modellenmemiş ivmeler yüzünden gerçekten sapar ve bu sapma adım adım <strong>birikir</strong>.</li>
  <li><strong>Gürültülü ölçümler.</strong> Sensör bize durumla ilgili bir şey söyler (<code class="language-plaintext highlighter-rouge">z</code>), ama her okumanın üzerinde rastgele gürültü vardır. Üstelik sensör çoğu zaman durumun tamamını değil, bir fonksiyonunu ölçer (örneğin yalnızca konumu, hızı değil).</li>
</ol>

<p>Kalman filtresinin yaptığı tam olarak şudur: her adımda modelin tahminiyle yeni ölçümü, <strong>her birinin ne kadar güvenilir olduğunu hesaba katarak</strong> birleştirir. Kritik nokta, filtrenin yalnızca en iyi tahmini (<code class="language-plaintext highlighter-rouge">x̂</code>) değil, o tahmine <strong>ne kadar güvendiğini</strong> de (kovaryans matrisi <code class="language-plaintext highlighter-rouge">P</code>) taşımasıdır. Tüm zekâ bu ikinci büyüklükte saklıdır.</p>

<p>Bir de güzel özelliği var: filtre <strong>özyinelemelidir</strong> (recursive). Tüm geçmiş ölçümleri saklamaz; her an yalnızca güncel <code class="language-plaintext highlighter-rouge">x̂</code> ve <code class="language-plaintext highlighter-rouge">P</code> değerlerini tutar, yeni ölçüm gelince bunları günceller. Bu yüzden gömülü bir mikrodenetleyicide, sabit hafızayla, gerçek zamanlı çalışabilir.</p>

<hr />

<h2 id="gauss-dağılımı-ve-i̇ki-bilgiyi-birleştirmek">Gauss Dağılımı ve İki Bilgiyi Birleştirmek</h2>

<p>Kalman filtresinin kalbinde tek bir varsayım yatar: belirsizliği <strong>Gauss (normal) dağılımıyla</strong> temsil ederiz. Bir Gauss iki sayıyla tanımlanır: ortalama <code class="language-plaintext highlighter-rouge">μ</code> (“en iyi tahminim”) ve varyans <code class="language-plaintext highlighter-rouge">σ²</code> (“ne kadar eminim” — küçük varyans = sivri, emin; büyük varyans = yayvan, belirsiz).</p>

<p>Şimdi sihirli kısım. Elimizde aynı büyüklük hakkında iki bağımsız Gauss bilgi olsun: biri modelin tahmini, diğeri ölçüm. Bu ikisini <strong>çarptığımızda</strong> ortaya çıkan şey yine bir Gauss’tur — ve bu yeni Gauss, her ikisinden de <strong>daha dardır</strong>, ortalaması da ikisinin “kesinliklerine göre ağırlıklı” ortasındadır:</p>

<p>$$
\mu = \mu_1 + \frac{\sigma_1^2}{\sigma_1^2 + \sigma_2^2}\,(\mu_2 - \mu_1), \qquad
\sigma^2 = \sigma_1^2 - \frac{\sigma_1^4}{\sigma_1^2 + \sigma_2^2}
$$</p>

<figure>
  <img src="/img/posts/gaussian-fusion.webp" alt="İki Gauss dağılımının çarpımı: posterior her ikisinden de dar" class="img-fluid rounded" />
  <figcaption><strong>Şekil 1.</strong> Model tahmini (mavi, μ=4, σ=1.6) ile ölçümü (kırmızı, μ=7, σ=1.0) birleştirince ortaya çıkan posterior (yeşil) <em>her ikisinden de dar</em> (σ=0.85) ve ortalaması ikisinin arasında (μ=6.16), daha emin olduğumuz ölçüme yakın. Kalman güncellemesinin tüm özü bu tek resimde.</figcaption>
</figure>

<p>İki şeye dikkat edin. Birincisi, ortalamanın kaydığı miktar <code class="language-plaintext highlighter-rouge">σ₁²/(σ₁²+σ₂²)</code> ağırlığıyla belirlenir — bu ifade tam olarak skaler <strong>Kalman kazancıdır</strong> (<code class="language-plaintext highlighter-rouge">K</code>). İkincisi, sonuçtaki varyans her iki girdiden de küçüktür: iki bağımsız bilgiyi birleştirmek belirsizliği <strong>azaltır</strong>, asla artırmaz. Güncelleme denklemini şöyle de yazabiliriz:</p>

<p>$$
\mu = \mu_1 + K\,(\mu_2 - \mu_1), \qquad K = \frac{\sigma_1^2}{\sigma_1^2 + \sigma_2^2}
$$</p>

<p>Bu, birazdan göreceğimiz tam Kalman güncellemesinin (<code class="language-plaintext highlighter-rouge">x̂ = x̂⁻ + K(z − x̂⁻)</code>) bire bir skaler hâlidir. Geriye kalan tek iş, bunu tek boyuttan matrislere taşımak.</p>

<hr />

<h2 id="doğrusal-durum-uzay-modeli">Doğrusal Durum-Uzay Modeli</h2>

<p>Çok boyutlu durumda <code class="language-plaintext highlighter-rouge">μ</code> yerine durum vektörü <code class="language-plaintext highlighter-rouge">x</code>, <code class="language-plaintext highlighter-rouge">σ²</code> yerine <strong>kovaryans matrisi</strong> <code class="language-plaintext highlighter-rouge">P</code> geçer. Sistemi şu iki denklemle modelleriz:</p>

<p>$$
x_k = F\,x_{k-1} + B\,u_{k-1} + w_{k-1}, \qquad w_{k-1} \sim \mathcal{N}(0, Q)
$$</p>

<p>$$
z_k = H\,x_k + v_k, \qquad v_k \sim \mathcal{N}(0, R)
$$</p>

<p>Terimleri tek tek tanıyalım:</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">F</code> — <strong>durum geçiş matrisi</strong>: bir adımda durumun fizikçe nasıl evrildiği.</li>
  <li><code class="language-plaintext highlighter-rouge">B</code>, <code class="language-plaintext highlighter-rouge">u</code> — <strong>kontrol matrisi</strong> ve <strong>kontrol girdisi</strong>: dışarıdan uyguladığımız, bildiğimiz etkiler (örneğin gaz/fren). Kontrol yoksa bu terim düşer.</li>
  <li><code class="language-plaintext highlighter-rouge">H</code> — <strong>ölçüm matrisi</strong>: durumun hangi bileşeninin, nasıl ölçüldüğü.</li>
  <li><code class="language-plaintext highlighter-rouge">Q</code> — <strong>süreç gürültüsü kovaryansı</strong>: modele ne kadar güvenmediğimiz. Büyük <code class="language-plaintext highlighter-rouge">Q</code> = “modelim kaba, gerçek bundan sapabilir”.</li>
  <li><code class="language-plaintext highlighter-rouge">R</code> — <strong>ölçüm gürültüsü kovaryansı</strong>: sensöre ne kadar güvenmediğimiz. Genelde sensörün datasheet’inden ya da kalibrasyondan bilinir.</li>
  <li><code class="language-plaintext highlighter-rouge">P</code> — <strong>kestirim kovaryansı</strong>: filtrenin o anki tahminine olan güveni. Filtre bunu kendisi üretir ve günceller.</li>
</ul>

<p>Somut bir örnek kuralım: bir doğru üzerinde, yaklaşık sabit hızla giden bir cisim. Durumu konum ve hızdan oluşsun, <code class="language-plaintext highlighter-rouge">Δt</code> adım süresi olsun. Yalnızca konumu ölçebildiğimizi varsayalım. O zaman:</p>

<p>$$
x_k = \begin{bmatrix} p_k \\ \dot{p}_k \end{bmatrix}, \quad
F = \begin{bmatrix} 1 &amp; \Delta t \\ 0 &amp; 1 \end{bmatrix}, \quad
H = \begin{bmatrix} 1 &amp; 0 \end{bmatrix}
$$</p>

<p><code class="language-plaintext highlighter-rouge">F</code>‘in anlamı net: yeni konum = eski konum + hız·Δt; yeni hız = eski hız (sabit hız varsayımı). <code class="language-plaintext highlighter-rouge">H = [1, 0]</code> ise “ölçüm sadece konumu görür, hızı görmez” der. Hızı hiç ölçmediğimiz hâlde filtre onu konum ölçümlerinin zaman içindeki değişiminden <strong>çıkarsayacak</strong> — Kalman filtresinin en şık tarafı budur.</p>

<p>Süreç gürültüsünü, modellenmemiş bir ivmeden gelir gibi düşünürüz (beyaz-gürültü ivme modeli):</p>

<p>$$
Q = q\begin{bmatrix} \tfrac{\Delta t^4}{4} &amp; \tfrac{\Delta t^3}{2} \[4pt] \tfrac{\Delta t^3}{2} &amp; \Delta t^2 \end{bmatrix}, \qquad
R = \begin{bmatrix} \sigma_{\text{ölç}}^2 \end{bmatrix}
$$</p>

<p>Buradaki <code class="language-plaintext highlighter-rouge">q</code> skaler bir “süreç gürültüsü yoğunluğu”dur ve birazdan en kritik ayar düğmemiz olacak.</p>

<hr />

<h2 id="tahmin-adımı-predict">Tahmin Adımı (Predict)</h2>

<p>Filtre iki adımlı bir danstır. İlk adım <strong>tahmin</strong>: mevcut durumu ve belirsizliği, modeli kullanarak bir adım ileri taşırız.</p>

<p>$$
\hat{x}_k^- = F\,\hat{x}_{k-1} + B\,u_{k-1}
$$</p>

<p>$$
P_k^- = F\,P_{k-1}\,F^{\mathsf{T}} + Q
$$</p>

<p>Üstteki <code class="language-plaintext highlighter-rouge">−</code> işareti “henüz ölçümü görmeden, sadece modele dayalı a-priori tahmin” demektir. Birinci denklem sezgisel: durumu fizik kurallarıyla ileri sür. İkinci denklem daha derin: belirsizliği de ileri taşırız, ama <code class="language-plaintext highlighter-rouge">F P Fᵀ</code> ile dönüştürüp üzerine <code class="language-plaintext highlighter-rouge">+ Q</code> ekleriz. Bu <strong><code class="language-plaintext highlighter-rouge">+ Q</code></strong> çok önemli — tahmin adımı belirsizliği daima <strong>büyütür</strong>. Mantıklı: modele güvenerek geleceğe baktıkça emin olduğumuz şey azalır. Konum-hız örneğinde belirsizlik elipsi, hız yönünde uzar; çünkü hızdaki ufak bir hata, zamanla konumda büyük bir belirsizliğe dönüşür.</p>

<hr />

<h2 id="güncelleme-adımı-update">Güncelleme Adımı (Update)</h2>

<p>İkinci adım <strong>güncelleme</strong>: yeni ölçüm gelince tahmini düzeltiriz. Burası Gauss çarpımının matris hâlidir.</p>

<p>$$
y_k = z_k - H\,\hat{x}_k^-
$$</p>

<p>$$
S_k = H\,P_k^-\,H^{\mathsf{T}} + R
$$</p>

<p>$$
K_k = P_k^-\,H^{\mathsf{T}}\,S_k^{-1}
$$</p>

<p>$$
\hat{x}_k = \hat{x}_k^- + K_k\,y_k
$$</p>

<p>$$
P_k = (I - K_k H)\,P_k^-
$$</p>

<p>Sırayla:</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">y</code> — <strong>yenilik</strong> (innovation): ölçüm bizi ne kadar şaşırttı? Beklediğimiz ölçüm (<code class="language-plaintext highlighter-rouge">H x̂⁻</code>) ile gerçek ölçüm (<code class="language-plaintext highlighter-rouge">z</code>) arasındaki fark. Yenilik küçükse model isabetli, büyükse ölçümde yeni bilgi var.</li>
  <li><code class="language-plaintext highlighter-rouge">S</code> — yeniliğin kovaryansı: bu şaşkınlığın ne kadarı beklenen (gürültü + model belirsizliği).</li>
  <li><code class="language-plaintext highlighter-rouge">K</code> — <strong>Kalman kazancı</strong>: filtrenin kalbi. Yeniliğin ne kadarına güveneceğimizi belirleyen, hassasiyete göre ağırlıklı harman oranı. <code class="language-plaintext highlighter-rouge">K → 1</code> ise “sensöre güven, ölçümü kabul et”; <code class="language-plaintext highlighter-rouge">K → 0</code> ise “modele güven, ölçümü neredeyse yok say”.</li>
  <li>Durum güncellemesi: a-priori tahmine, yeniliğin <code class="language-plaintext highlighter-rouge">K</code> katını ekle.</li>
  <li>Kovaryans güncellemesi: tahmin belirsizliği <strong>azalır</strong> (yeni bilgi geldi).</li>
</ul>

<p>Pratikte son denklem yerine sayısal olarak daha kararlı olan <strong>Joseph formu</strong> tercih edilir; her durumda simetrik ve pozitif yarı-tanımlı bir <code class="language-plaintext highlighter-rouge">P</code> üretir:</p>

<p>$$
P_k = (I - K_k H)\,P_k^-\,(I - K_k H)^{\mathsf{T}} + K_k R\,K_k^{\mathsf{T}}
$$</p>

<p>Buna birazdan “Mühendislik Notları”nda döneceğiz.</p>

<hr />

<h2 id="tam-algoritma-i̇ki-adımın-dansı">Tam Algoritma: İki Adımın Dansı</h2>

<p>Tüm filtre, bu iki adımın sonsuza dek tekrarından ibarettir:</p>

<div class="mermaid">
flowchart LR
    INIT["Başlangıç<br />x₀ , P₀ (büyük)"] --&gt; PRED
    subgraph TAHMIN["① TAHMİN (Predict)"]
      PRED["x⁻ = F·x + B·u<br />P⁻ = F·P·Fᵀ + Q<br />(belirsizlik artar)"]
    end
    subgraph GUNC["② GÜNCELLEME (Update)"]
      UPD["y = z − H·x⁻<br />K = P⁻·Hᵀ·S⁻¹<br />x = x⁻ + K·y<br />P = (I − K·H)·P⁻<br />(belirsizlik azalır)"]
    end
    PRED --&gt;|a priori tahmin| UPD
    Z(["ölçüm z"]) --&gt; UPD
    UPD --&gt;|a posteriori kestirim| PRED
    UPD --&gt; OUT["çıktı: x , P"]
    style INIT fill:#e8eef7,stroke:#4a6fa5,stroke-width:2px
    style PRED fill:#cee0f3,stroke:#3a5f95,stroke-width:2px
    style UPD fill:#bfd6f0,stroke:#3a5f95,stroke-width:2px
    style Z fill:#fde0e0,stroke:#c0392b,stroke-width:2px
    style OUT fill:#d5f0d5,stroke:#2e7d32,stroke-width:2px
</div>

<p>Başlangıçta <code class="language-plaintext highlighter-rouge">x̂₀</code> için bir tahmin (bilmiyorsak sıfır) ve <code class="language-plaintext highlighter-rouge">P₀</code> için <strong>büyük</strong> bir değer veririz — “başta hiçbir şey bilmiyorum” demenin yolu budur. İlk birkaç ölçümde filtre hızla kendine gelir; kötü bir başlangıcı çabucak unutur. Bu, Kalman filtresinin pratikteki en sevimli huylarından biridir.</p>

<hr />

<h2 id="elde-çalışan-1b-örnek">Elde Çalışan 1B Örnek</h2>

<p>Soyut kalmasın; ilk iterasyonu elle yapalım. Konum-hız modelimizde <code class="language-plaintext highlighter-rouge">Δt = 1</code>, <code class="language-plaintext highlighter-rouge">σ_ölç = 2</code> (yani <code class="language-plaintext highlighter-rouge">R = 4</code>), <code class="language-plaintext highlighter-rouge">q = 0.01</code> olsun. Başlangıç: <code class="language-plaintext highlighter-rouge">x̂₀ = [0, 0]</code>, <code class="language-plaintext highlighter-rouge">P₀ = 500·I</code> (çok belirsiz).</p>

<p><strong>Tahmin:</strong> <code class="language-plaintext highlighter-rouge">x̂⁻ = F·[0,0]ᵀ = [0, 0]</code>. Kovaryans için <code class="language-plaintext highlighter-rouge">P⁻ = F P₀ Fᵀ + Q</code>. Hesabı yapınca <code class="language-plaintext highlighter-rouge">P⁻[0,0] ≈ 1000</code> çıkar (belirsizlik tahminle daha da büyüdü).</p>

<p><strong>İlk ölçüm geldi:</strong> diyelim <code class="language-plaintext highlighter-rouge">z₁ = 2.64</code>. O zaman:</p>

<ul>
  <li>Yenilik: <code class="language-plaintext highlighter-rouge">y = z₁ − x̂⁻[0] = 2.64 − 0 = 2.64</code></li>
  <li>Yenilik kovaryansı: <code class="language-plaintext highlighter-rouge">S = P⁻[0,0] + R = 1000 + 4 = 1004</code></li>
  <li>Kalman kazancı: <code class="language-plaintext highlighter-rouge">K = [P⁻[0,0], P⁻[0,1]]ᵀ / S = [0.996, 0.498]ᵀ</code></li>
  <li>Durum: <code class="language-plaintext highlighter-rouge">x̂ = x̂⁻ + K·y = [0.996·2.64, 0.498·2.64] = [2.63, 1.31]</code></li>
  <li>Kovaryans: <code class="language-plaintext highlighter-rouge">P[0,0] = (1 − 0.996)·1000 ≈ 4.0</code></li>
</ul>

<p>İlk adımda <code class="language-plaintext highlighter-rouge">K ≈ 1</code> çıkması tesadüf değil: <code class="language-plaintext highlighter-rouge">P₀</code> kocaman olduğu için filtre “modelime hiç güvenmiyorum, ölçüm neredeyse aynen doğrudur” diyor ve ilk ölçümü olduğu gibi kabul ediyor. Konum varyansı 1000’den 4’e düştü; bir ölçümle ne kadar çok şey öğrendiğimize bakın. Adımlar ilerledikçe <code class="language-plaintext highlighter-rouge">K</code> küçülerek kararlı bir değere oturacak — filtre artık modeline de güvenmeye başlayacak.</p>

<hr />

<h2 id="numpy-ile-sıfırdan-lineer-kf">NumPy ile Sıfırdan Lineer KF</h2>

<p>Teori güzel ama her zaman dediğim gibi, gözünüzle görmediğiniz hiçbir şeye güvenmeyin. Aşağıdaki kod modeli kurar, gerçek bir yörünge ile gürültülü ölçümler üretir ve filtreyi çalıştırır. Toplam 20 satırlık bir döngü.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="n">numpy</span> <span class="k">as</span> <span class="n">np</span>
<span class="kn">import</span> <span class="n">matplotlib.pyplot</span> <span class="k">as</span> <span class="n">plt</span>

<span class="n">dt</span> <span class="o">=</span> <span class="mf">1.0</span>
<span class="n">F</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="nf">array</span><span class="p">([[</span><span class="mi">1</span><span class="p">,</span> <span class="n">dt</span><span class="p">],</span>
              <span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mf">1.0</span><span class="p">]])</span>          <span class="c1"># sabit-hız geçiş matrisi
</span><span class="n">H</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="nf">array</span><span class="p">([[</span><span class="mf">1.0</span><span class="p">,</span> <span class="mf">0.0</span><span class="p">]])</span>        <span class="c1"># yalnızca konumu ölçüyoruz
</span><span class="n">q</span> <span class="o">=</span> <span class="mf">0.01</span>                          <span class="c1"># süreç gürültüsü yoğunluğu
</span><span class="n">Q</span> <span class="o">=</span> <span class="n">q</span> <span class="o">*</span> <span class="n">np</span><span class="p">.</span><span class="nf">array</span><span class="p">([[</span><span class="n">dt</span><span class="o">**</span><span class="mi">4</span><span class="o">/</span><span class="mi">4</span><span class="p">,</span> <span class="n">dt</span><span class="o">**</span><span class="mi">3</span><span class="o">/</span><span class="mi">2</span><span class="p">],</span>
                  <span class="p">[</span><span class="n">dt</span><span class="o">**</span><span class="mi">3</span><span class="o">/</span><span class="mi">2</span><span class="p">,</span> <span class="n">dt</span><span class="o">**</span><span class="mi">2</span><span class="p">]])</span>
<span class="n">R</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="nf">array</span><span class="p">([[</span><span class="mf">4.0</span><span class="p">]])</span>             <span class="c1"># ölçüm gürültüsü (σ=2 → R=σ²=4)
</span>
<span class="c1"># 1) Gerçek yörünge + gürültülü ölçümler üret
</span><span class="n">rng</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">random</span><span class="p">.</span><span class="nf">default_rng</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
<span class="n">N</span> <span class="o">=</span> <span class="mi">60</span>
<span class="n">x</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="nf">array</span><span class="p">([</span><span class="mf">0.0</span><span class="p">,</span> <span class="mf">1.0</span><span class="p">])</span>          <span class="c1"># [konum, hız]
</span><span class="n">truth</span><span class="p">,</span> <span class="n">meas</span> <span class="o">=</span> <span class="p">[],</span> <span class="p">[]</span>
<span class="k">for</span> <span class="n">_</span> <span class="ow">in</span> <span class="nf">range</span><span class="p">(</span><span class="n">N</span><span class="p">):</span>
    <span class="n">x</span> <span class="o">=</span> <span class="n">F</span> <span class="o">@</span> <span class="n">x</span> <span class="o">+</span> <span class="n">np</span><span class="p">.</span><span class="nf">array</span><span class="p">([</span><span class="mf">0.0</span><span class="p">,</span> <span class="n">rng</span><span class="p">.</span><span class="nf">normal</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">np</span><span class="p">.</span><span class="nf">sqrt</span><span class="p">(</span><span class="n">q</span><span class="p">))])</span>
    <span class="n">truth</span><span class="p">.</span><span class="nf">append</span><span class="p">(</span><span class="n">x</span><span class="p">.</span><span class="nf">copy</span><span class="p">())</span>
    <span class="n">meas</span><span class="p">.</span><span class="nf">append</span><span class="p">((</span><span class="n">H</span> <span class="o">@</span> <span class="n">x</span><span class="p">)[</span><span class="mi">0</span><span class="p">]</span> <span class="o">+</span> <span class="n">rng</span><span class="p">.</span><span class="nf">normal</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mf">2.0</span><span class="p">))</span>
<span class="n">truth</span><span class="p">,</span> <span class="n">meas</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="nf">array</span><span class="p">(</span><span class="n">truth</span><span class="p">),</span> <span class="n">np</span><span class="p">.</span><span class="nf">array</span><span class="p">(</span><span class="n">meas</span><span class="p">)</span>

<span class="c1"># 2) Kalman filtresini çalıştır
</span><span class="n">xhat</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="nf">array</span><span class="p">([</span><span class="mf">0.0</span><span class="p">,</span> <span class="mf">0.0</span><span class="p">])</span>
<span class="n">P</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="nf">eye</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span> <span class="o">*</span> <span class="mf">500.0</span>             <span class="c1"># başlangıçta çok belirsiziz
</span><span class="n">I</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="nf">eye</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span>
<span class="n">est</span><span class="p">,</span> <span class="n">var_p</span><span class="p">,</span> <span class="n">gain</span> <span class="o">=</span> <span class="p">[],</span> <span class="p">[],</span> <span class="p">[]</span>
<span class="k">for</span> <span class="n">k</span> <span class="ow">in</span> <span class="nf">range</span><span class="p">(</span><span class="n">N</span><span class="p">):</span>
    <span class="c1"># --- TAHMİN ---
</span>    <span class="n">xhat</span> <span class="o">=</span> <span class="n">F</span> <span class="o">@</span> <span class="n">xhat</span>
    <span class="n">P</span> <span class="o">=</span> <span class="n">F</span> <span class="o">@</span> <span class="n">P</span> <span class="o">@</span> <span class="n">F</span><span class="p">.</span><span class="n">T</span> <span class="o">+</span> <span class="n">Q</span>
    <span class="c1"># --- GÜNCELLEME ---
</span>    <span class="n">y</span> <span class="o">=</span> <span class="n">meas</span><span class="p">[</span><span class="n">k</span><span class="p">]</span> <span class="o">-</span> <span class="n">H</span> <span class="o">@</span> <span class="n">xhat</span>                  <span class="c1"># yenilik
</span>    <span class="n">S</span> <span class="o">=</span> <span class="n">H</span> <span class="o">@</span> <span class="n">P</span> <span class="o">@</span> <span class="n">H</span><span class="p">.</span><span class="n">T</span> <span class="o">+</span> <span class="n">R</span>
    <span class="n">K</span> <span class="o">=</span> <span class="n">P</span> <span class="o">@</span> <span class="n">H</span><span class="p">.</span><span class="n">T</span> <span class="o">@</span> <span class="n">np</span><span class="p">.</span><span class="n">linalg</span><span class="p">.</span><span class="nf">inv</span><span class="p">(</span><span class="n">S</span><span class="p">)</span>          <span class="c1"># Kalman kazancı
</span>    <span class="n">xhat</span> <span class="o">=</span> <span class="n">xhat</span> <span class="o">+</span> <span class="p">(</span><span class="n">K</span> <span class="o">@</span> <span class="n">y</span><span class="p">)</span>
    <span class="n">P</span> <span class="o">=</span> <span class="p">(</span><span class="n">I</span> <span class="o">-</span> <span class="n">K</span> <span class="o">@</span> <span class="n">H</span><span class="p">)</span> <span class="o">@</span> <span class="n">P</span>
    <span class="n">est</span><span class="p">.</span><span class="nf">append</span><span class="p">(</span><span class="n">xhat</span><span class="p">.</span><span class="nf">copy</span><span class="p">());</span> <span class="n">var_p</span><span class="p">.</span><span class="nf">append</span><span class="p">(</span><span class="n">P</span><span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">]);</span> <span class="n">gain</span><span class="p">.</span><span class="nf">append</span><span class="p">(</span><span class="n">K</span><span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">])</span>
<span class="n">est</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="nf">array</span><span class="p">(</span><span class="n">est</span><span class="p">)</span>

<span class="n">rmse_kf</span>  <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="nf">sqrt</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="nf">mean</span><span class="p">((</span><span class="n">est</span><span class="p">[:,</span> <span class="mi">0</span><span class="p">]</span> <span class="o">-</span> <span class="n">truth</span><span class="p">[:,</span> <span class="mi">0</span><span class="p">])</span><span class="o">**</span><span class="mi">2</span><span class="p">))</span>
<span class="n">rmse_raw</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="nf">sqrt</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="nf">mean</span><span class="p">((</span><span class="n">meas</span> <span class="o">-</span> <span class="n">truth</span><span class="p">[:,</span> <span class="mi">0</span><span class="p">])</span><span class="o">**</span><span class="mi">2</span><span class="p">))</span>
<span class="nf">print</span><span class="p">(</span><span class="sa">f</span><span class="sh">"</span><span class="s">KF RMSE=</span><span class="si">{</span><span class="n">rmse_kf</span><span class="si">:</span><span class="p">.</span><span class="mi">2</span><span class="n">f</span><span class="si">}</span><span class="s">   ham ölçüm RMSE=</span><span class="si">{</span><span class="n">rmse_raw</span><span class="si">:</span><span class="p">.</span><span class="mi">2</span><span class="n">f</span><span class="si">}</span><span class="sh">"</span><span class="p">)</span>
<span class="c1"># -&gt; KF RMSE=0.73   ham ölçüm RMSE=1.64
</span></code></pre></div></div>

<p>Sonuç çarpıcı: ham ölçümlerin gerçek konuma göre RMSE’si <strong>1.64</strong> iken, Kalman kestiriminin RMSE’si <strong>0.73</strong> — kabaca <strong>2.25 kat</strong> daha iyi. Hem de tek bir ekstra sensör eklemeden, yalnızca bir hareket modelini akıllıca kullanarak.</p>

<figure>
  <img src="/img/posts/kalman-1d-tracking.webp" alt="Lineer Kalman filtresiyle 1B konum takibi" class="img-fluid rounded" />
  <figcaption><strong>Şekil 2.</strong> Gerçek konum (yeşil), gürültülü ölçümler (kırmızı nokta) ve KF kestirimi (mavi), ±2σ güven bandıyla birlikte. Mavi çizgi kırmızı bulutun ortasından pürüzsüzce geçiyor; güven bandı ilk adımlarda geniş, sonra daralıyor.</figcaption>
</figure>

<p>Bir de filtrenin “kendine güveni” olan <code class="language-plaintext highlighter-rouge">P</code> ve kazanç <code class="language-plaintext highlighter-rouge">K</code>‘nin zaman içindeki davranışına bakalım:</p>

<figure>
  <img src="/img/posts/kalman-covariance-convergence.webp" alt="Kovaryans P ve Kalman kazancı K kararlı duruma oturuyor" class="img-fluid rounded" />
  <figcaption><strong>Şekil 3.</strong> Konum varyansı P[0,0] başlangıçtaki 500'den birkaç adımda ~1'e iner (logaritmik eksen). Kalman kazancı K[0] ise ~1.0'dan başlayıp ~0.27'ye oturur. Sabit `F`, `H`, `Q`, `R` için kazanç bir <strong>kararlı duruma</strong> yakınsar — bu, gömülü sistemlerde "sabit kazançlı Kalman filtresi" olarak önceden hesaplanabilir.</figcaption>
</figure>

<p><code class="language-plaintext highlighter-rouge">R</code> ve <code class="language-plaintext highlighter-rouge">q</code> değerleriyle oynayıp kodu yeniden çalıştırın: <code class="language-plaintext highlighter-rouge">R</code>‘yi büyütürseniz filtre ölçümlere daha az güvenir, kestirim pürüzsüzleşir ama yavaşlar. <code class="language-plaintext highlighter-rouge">q</code>‘yu büyütürseniz modele daha az güvenir, kestirim ölçümlerin peşinden koşar. Bu dengeyi en iyi, doğrudan elinizle hissederek anlarsınız — buyrun.</p>

<hr />

<h2 id="etkileşimli-simülatör-lineer-kalman-filtresi">Etkileşimli Simülatör: Lineer Kalman Filtresi</h2>

<p>Aşağıdaki simülatör gerçek zamanlı çalışır. Üç düğme var: ölçüm gürültüsü <code class="language-plaintext highlighter-rouge">σ</code>, filtrenin <strong>varsaydığı</strong> süreç gürültüsü <code class="language-plaintext highlighter-rouge">q</code> ve cismin gerçek hızı. Gerçek dünya sabit (ama hafif manevra yapan) bir hızla ilerler; siz filtreyi nasıl ayarladığınıza göre sonucu izleyin.</p>

<div class="card my-3" id="kf-demo">
  <div class="card-header py-2"><strong>Lineer Kalman Filtresi Simülatörü</strong></div>
  <div class="card-body">
    <div class="form-row mb-2">
      <div class="col-md-4 mb-2">
        <label class="mb-0 small">Ölçüm gürültüsü σ = <b id="kf-v-R">2.0</b></label>
        <input type="range" class="custom-range" id="kf-sl-R" min="0.2" max="8" value="2" step="0.1" />
      </div>
      <div class="col-md-4 mb-2">
        <label class="mb-0 small">Süreç gürültüsü q (filtre) = <b id="kf-v-Q">0.0100</b></label>
        <input type="range" class="custom-range" id="kf-sl-Q" min="0.0001" max="1" value="0.01" step="0.0001" />
      </div>
      <div class="col-md-4 mb-2">
        <label class="mb-0 small">Gerçek hız = <b id="kf-v-V">1.0</b> br/adım</label>
        <input type="range" class="custom-range" id="kf-sl-V" min="-2" max="2" value="1" step="0.1" />
      </div>
    </div>
    <div class="mb-2">
      <button class="btn btn-sm btn-primary" id="kf-btn-play" type="button">⏸ Duraklat</button>
      <button class="btn btn-sm btn-outline-secondary" id="kf-btn-reset" type="button">↻ Yeni gerçekleştirme</button>
    </div>
    <div id="kf-status" class="px-2 py-1 mb-2 rounded small" style="font-family:monospace;min-height:2.2em;background:#f1f5fb;"></div>
    <canvas id="kf-canvas" style="width:100%;display:block;border-radius:4px;border:1px solid #dee2e6;"></canvas>
    <p class="text-muted small mt-1 mb-0">σ'yı büyüt → kestirim pürüzsüzleşir ama gecikir. q'yu büyüt → kestirim her ölçümün peşinden koşar. q'yu çok küçültürsen filtre fazla kendine güvenir: ±2σ bandı incelir ama gerçek konum bandın dışına taşar (ıraksamanın habercisi).</p>
  </div>
</div>

<script src="/assets/js/posts/kalman-linear.js"></script>

<p>Birkaç deney önerisi: <code class="language-plaintext highlighter-rouge">q</code>‘yu en küçük değere çekin ve birkaç saniye izleyin — güven bandı kâğıt inceliğine düşerken gerçek (yeşil) çizginin bandın dışına kaçtığını göreceksiniz. Filtre kendine olduğundan fazla güveniyor; bu, gerçek sistemlerde <strong>ıraksamanın</strong> (divergence) klasik reçetesidir. Sonra <code class="language-plaintext highlighter-rouge">q</code>‘yu sonuna kadar açın: bu sefer kestirim her gürültülü noktanın peşine takılır, filtrenin tüm pürüzsüzleştirme faydası kaybolur. İyi ayar ikisinin arasındadır.</p>

<hr />

<h2 id="doğrusal-olmama-problemi-sensör-düz-konuşmaz">Doğrusal Olmama Problemi: Sensör Düz Konuşmaz</h2>

<p>Şimdiye kadar her şey doğrusaldı: <code class="language-plaintext highlighter-rouge">x = F x</code> ve <code class="language-plaintext highlighter-rouge">z = H x</code>. Gerçek dünyaysa nadiren bu kadar kibardır. Çoğu sensör, durumun <strong>doğrusal-olmayan</strong> bir fonksiyonunu ölçer.</p>

<p>Klasik örnek: orijine yerleştirilmiş bir sensör, hareketli bir cisme olan <strong>uzaklığı</strong> (menzil, <code class="language-plaintext highlighter-rouge">r</code>) ve <strong>açıyı</strong> (<code class="language-plaintext highlighter-rouge">θ</code>) ölçsün. Cismin konumu Kartezyen <code class="language-plaintext highlighter-rouge">(p_x, p_y)</code> ise, ölçüm şudur:</p>

<p>$$
h(x) = \begin{bmatrix} r \\ \theta \end{bmatrix}
     = \begin{bmatrix} \sqrt{p_x^2 + p_y^2} \[4pt] \operatorname{atan2}(p_y, p_x) \end{bmatrix}
$$</p>

<p>İçindeki karekök ve <code class="language-plaintext highlighter-rouge">atan2</code> yüzünden bu fonksiyon durumda doğrusal değildir. İşte sorun: Kalman filtresinin tüm matematiği “Gauss içeri girer, Gauss dışarı çıkar” varsayımına dayanır. Ama bir Gauss dağılımını doğrusal-olmayan bir fonksiyondan geçirirseniz, çıkan şey <strong>artık Gauss değildir</strong> — çarpık, eğri büğrü bir dağılımdır. <code class="language-plaintext highlighter-rouge">H</code> matrisi diye bir şey de yoktur; <code class="language-plaintext highlighter-rouge">h(x)</code> bir matrisle yazılamaz. Klasik KF burada çalışmaz.</p>

<p>(Aynı sorun ölçümde değil <strong>süreçte</strong> de olabilir: <code class="language-plaintext highlighter-rouge">x = f(x, u)</code> doğrusal-olmayan bir hareket modeli olabilir — dönen bir cisim, sürtünmeli bir sarkaç. Çözüm her iki durumda da aynıdır.)</p>

<hr />

<h2 id="ekfin-fikri-lineerizasyon-ve-jacobianlar">EKF’in Fikri: Lineerizasyon ve Jacobian’lar</h2>

<p>Genişletilmiş Kalman Filtresi’nin (EKF) çözümü zarif ve pragmatiktir: <strong>doğrusal-olmayan fonksiyonu, içinde bulunduğumuz çalışma noktasının yakınında bir doğruyla (teğetle) değiştir.</strong> Yani her adımda, güncel tahmin <code class="language-plaintext highlighter-rouge">x̂</code> etrafında birinci-dereceden Taylor açılımı yaparız. Bu teğetin eğimi, fonksiyonun <strong>Jacobian matrisidir</strong>:</p>

<p>$$
F_k = \left.\frac{\partial f}{\partial x}\right|_{\hat{x}_{k-1},\,u_{k-1}}, \qquad
H_k = \left.\frac{\partial h}{\partial x}\right|_{\hat{x}_k^-}
$$</p>

<p>Fikir basit ama güçlü: kovaryansı taşırken ve Kalman kazancını hesaplarken, sabit <code class="language-plaintext highlighter-rouge">F</code> ve <code class="language-plaintext highlighter-rouge">H</code> matrislerinin yerine bu <strong>her adımda yeniden hesaplanan</strong> Jacobian’ları kullanırız. Durumun kendisini taşırken ise gerçek doğrusal-olmayan <code class="language-plaintext highlighter-rouge">f</code> ve <code class="language-plaintext highlighter-rouge">h</code> fonksiyonlarını kullanmaya devam ederiz (teğeti değil, eğrinin kendisini).</p>

<figure>
  <img src="/img/posts/ekf-linearization.webp" alt="EKF doğrusallaştırma: eğri ve çalışma noktasındaki teğeti" class="img-fluid rounded" />
  <figcaption><strong>Şekil 4.</strong> EKF'in tek fikri: doğrusal-olmayan ölçüm fonksiyonunu (yeşil eğri) çalışma noktasındaki teğetiyle (mavi kesik çizgi — Jacobian) değiştirmek. Çalışma noktasına yakın bölgede teğet eğriye iyi uyar; uzaklaştıkça doğrusallaştırma hatası (kırmızı taralı bölge) büyür. EKF'in tüm güçlü ve zayıf yanları bu resimde gizli.</figcaption>
</figure>

<p>Bu yaklaşımın bedeli de aynı resimde: EKF artık <strong>optimal değildir</strong> ve doğrusallık varsayımı yalnızca çalışma noktasının yakınında geçerlidir. Tahmin gerçekten uzaksa veya fonksiyon çok bükülmüşse, teğet kötü bir yaklaşım olur ve filtre ıraksayabilir. Yine de pratikte EKF, on yıllardır navigasyon ve takip sistemlerinin bel kemiğidir; çünkü çoğu sistem, adım adım bakıldığında “yeterince doğrusal”dır.</p>

<hr />

<h2 id="range-bearing-jacobianını-elle-türetmek">Range-Bearing Jacobian’ını Elle Türetmek</h2>

<p>EKF’i uygulamak demek, Jacobian’ı doğru türetmek demektir; gerisi neredeyse klasik KF’tir. Menzil-açı ölçümümüz için <code class="language-plaintext highlighter-rouge">H_k = ∂h/∂x</code> türevini eleman eleman alalım. Durumumuz <code class="language-plaintext highlighter-rouge">[p_x, p_y, v_x, v_y]</code> ve <code class="language-plaintext highlighter-rouge">r = √(p_x² + p_y²)</code>.</p>

<p>Menzil satırı için:</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">∂r/∂p_x = p_x / r</code>,  <code class="language-plaintext highlighter-rouge">∂r/∂p_y = p_y / r</code></li>
</ul>

<p>Açı satırı için (<code class="language-plaintext highlighter-rouge">θ = atan2(p_y, p_x)</code> türevinin standart sonucu):</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">∂θ/∂p_x = −p_y / r²</code>,  <code class="language-plaintext highlighter-rouge">∂θ/∂p_y = p_x / r²</code></li>
</ul>

<p>Hız bileşenlerine göre türevler sıfırdır, çünkü ölçüm hıza doğrudan bağlı değil. Hepsini bir matriste toplayınca:</p>

<p>$$
H_k = \frac{\partial h}{\partial x}
= \begin{bmatrix}
\dfrac{p_x}{r} &amp; \dfrac{p_y}{r} &amp; 0 &amp; 0 \[8pt]
-\dfrac{p_y}{r^2} &amp; \dfrac{p_x}{r^2} &amp; 0 &amp; 0
\end{bmatrix}
$$</p>

<p>El ile türetilen bir Jacobian, hata yapmaya en açık yerdir; bu yüzden onu daima <strong>sayısal türevle</strong> doğrulayın. <code class="language-plaintext highlighter-rouge">(h(x+ε) − h(x−ε)) / 2ε</code> merkezî farkı, analitik Jacobian’a çok yakın çıkmalıdır:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="n">numpy</span> <span class="k">as</span> <span class="n">np</span>
<span class="k">def</span> <span class="nf">h</span><span class="p">(</span><span class="n">x</span><span class="p">):</span> <span class="k">return</span> <span class="n">np</span><span class="p">.</span><span class="nf">array</span><span class="p">([</span><span class="n">np</span><span class="p">.</span><span class="nf">hypot</span><span class="p">(</span><span class="n">x</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">x</span><span class="p">[</span><span class="mi">1</span><span class="p">]),</span> <span class="n">np</span><span class="p">.</span><span class="nf">arctan2</span><span class="p">(</span><span class="n">x</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="n">x</span><span class="p">[</span><span class="mi">0</span><span class="p">])])</span>
<span class="k">def</span> <span class="nf">H_jac</span><span class="p">(</span><span class="n">x</span><span class="p">):</span>
    <span class="n">px</span><span class="p">,</span> <span class="n">py</span> <span class="o">=</span> <span class="n">x</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">x</span><span class="p">[</span><span class="mi">1</span><span class="p">];</span> <span class="n">r2</span> <span class="o">=</span> <span class="n">px</span><span class="o">*</span><span class="n">px</span> <span class="o">+</span> <span class="n">py</span><span class="o">*</span><span class="n">py</span><span class="p">;</span> <span class="n">r</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="nf">sqrt</span><span class="p">(</span><span class="n">r2</span><span class="p">)</span>
    <span class="k">return</span> <span class="n">np</span><span class="p">.</span><span class="nf">array</span><span class="p">([[</span> <span class="n">px</span><span class="o">/</span><span class="n">r</span><span class="p">,</span>   <span class="n">py</span><span class="o">/</span><span class="n">r</span><span class="p">,</span>  <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">],</span>
                     <span class="p">[</span><span class="o">-</span><span class="n">py</span><span class="o">/</span><span class="n">r2</span><span class="p">,</span>  <span class="n">px</span><span class="o">/</span><span class="n">r2</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">]])</span>

<span class="n">x</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="nf">array</span><span class="p">([</span><span class="mf">3.0</span><span class="p">,</span> <span class="mf">4.0</span><span class="p">,</span> <span class="mf">1.0</span><span class="p">,</span> <span class="o">-</span><span class="mf">2.0</span><span class="p">])</span>          <span class="c1"># r = 5
</span><span class="n">eps</span> <span class="o">=</span> <span class="mf">1e-6</span><span class="p">;</span> <span class="n">J_num</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="nf">zeros</span><span class="p">((</span><span class="mi">2</span><span class="p">,</span> <span class="mi">4</span><span class="p">))</span>
<span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nf">range</span><span class="p">(</span><span class="mi">4</span><span class="p">):</span>
    <span class="n">e</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="nf">zeros</span><span class="p">(</span><span class="mi">4</span><span class="p">);</span> <span class="n">e</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="n">eps</span>
    <span class="n">J_num</span><span class="p">[:,</span> <span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="p">(</span><span class="nf">h</span><span class="p">(</span><span class="n">x</span><span class="o">+</span><span class="n">e</span><span class="p">)</span> <span class="o">-</span> <span class="nf">h</span><span class="p">(</span><span class="n">x</span><span class="o">-</span><span class="n">e</span><span class="p">))</span> <span class="o">/</span> <span class="p">(</span><span class="mi">2</span><span class="o">*</span><span class="n">eps</span><span class="p">)</span>

<span class="nf">print</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="nf">max</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="nf">abs</span><span class="p">(</span><span class="nc">H_jac</span><span class="p">(</span><span class="n">x</span><span class="p">)</span> <span class="o">-</span> <span class="n">J_num</span><span class="p">)))</span>      <span class="c1"># -&gt; ~7e-9  (analitik = sayısal)
</span><span class="nf">print</span><span class="p">(</span><span class="nc">H_jac</span><span class="p">(</span><span class="n">x</span><span class="p">))</span>   <span class="c1"># [[ 0.6 ,  0.8 , 0, 0], [-0.16,  0.12, 0, 0]]
</span></code></pre></div></div>

<p>Maksimum fark <code class="language-plaintext highlighter-rouge">~10⁻⁹</code> mertebesinde; Jacobian’ımız doğru. (<code class="language-plaintext highlighter-rouge">p_x=3, p_y=4</code> için <code class="language-plaintext highlighter-rouge">r=5</code>; <code class="language-plaintext highlighter-rouge">3/5=0.6</code>, <code class="language-plaintext highlighter-rouge">4/5=0.8</code>, <code class="language-plaintext highlighter-rouge">−4/25=−0.16</code>, <code class="language-plaintext highlighter-rouge">3/25=0.12</code> — elle de doğrulayabilirsiniz.)</p>

<hr />

<h2 id="ekf-algoritması">EKF Algoritması</h2>

<p>EKF döngüsü, klasik KF’ten yalnızca iki yerde ayrılır. Önce ölçüm modelimizin sabit <code class="language-plaintext highlighter-rouge">F</code> matrisini (bu örnekte hareket doğrusal: 2B sabit hız) ve <code class="language-plaintext highlighter-rouge">Q</code>‘yu kuralım:</p>

<p>$$
F = \begin{bmatrix} 1&amp;0&amp;\Delta t&amp;0 \\ 0&amp;1&amp;0&amp;\Delta t \\ 0&amp;0&amp;1&amp;0 \\ 0&amp;0&amp;0&amp;1 \end{bmatrix}, \qquad
Q = G\,\sigma_a^2\,G^{\mathsf{T}},\quad
G = \begin{bmatrix} \tfrac{\Delta t^2}{2}&amp;0 \[2pt] 0&amp;\tfrac{\Delta t^2}{2} \[2pt] \Delta t&amp;0 \[2pt] 0&amp;\Delta t \end{bmatrix}
$$</p>

<p>EKF adımları:</p>

<p>$$
\hat{x}_k^- = f(\hat{x}_{k-1}, u_{k-1}), \qquad P_k^- = F_k\,P_{k-1}\,F_k^{\mathsf{T}} + Q
$$</p>

<p>$$
y_k = z_k - h(\hat{x}_k^-), \qquad S_k = H_k\,P_k^-\,H_k^{\mathsf{T}} + R
$$</p>

<p>$$
K_k = P_k^-\,H_k^{\mathsf{T}}\,S_k^{-1}, \quad
\hat{x}_k = \hat{x}_k^- + K_k\,y_k, \quad
P_k = (I - K_k H_k)\,P_k^-
$$</p>

<p>İki kritik fark:</p>

<ol>
  <li><strong>Ortalama gerçek fonksiyonla, kovaryans Jacobian’la taşınır.</strong> Yeniliği <code class="language-plaintext highlighter-rouge">z − H x̂⁻</code> değil, <code class="language-plaintext highlighter-rouge">z − h(x̂⁻)</code> ile hesaplarız; ama <code class="language-plaintext highlighter-rouge">S</code>, <code class="language-plaintext highlighter-rouge">K</code>, <code class="language-plaintext highlighter-rouge">P</code> denklemlerinde <code class="language-plaintext highlighter-rouge">H</code> yerine <code class="language-plaintext highlighter-rouge">H_k</code> Jacobian’ı kullanırız.</li>
  <li><strong>Açı farkını sarmak (wrapping).</strong> <code class="language-plaintext highlighter-rouge">atan2</code> değerleri <code class="language-plaintext highlighter-rouge">[−π, π]</code> aralığındadır. <code class="language-plaintext highlighter-rouge">179°</code> beklerken <code class="language-plaintext highlighter-rouge">−179°</code> ölçerseniz, ham fark <code class="language-plaintext highlighter-rouge">−358°</code> çıkar; oysa gerçek fark sadece <code class="language-plaintext highlighter-rouge">+2°</code>‘dir. Bu yüzden açı yeniliğini daima <code class="language-plaintext highlighter-rouge">[−π, π]</code> aralığına sararız:</li>
</ol>

<p>$$
y_\theta \leftarrow \big((y_\theta + \pi)\bmod 2\pi\big) - \pi
$$</p>

<p>Bu küçük detayı atlamak, takip sistemlerinin açı sıçramalarında neden aniden çıldırdığının bir numaralı sebebidir. Aşağıdaki diyagram iki filtrenin yapısal farkını özetliyor:</p>

<div class="mermaid">
flowchart TB
    subgraph KF["Lineer Kalman Filtresi"]
      direction TB
      K1["Model: x = F·x + B·u<br />(doğrusal)"]
      K2["Ölçüm: z = H·x<br />(doğrusal)"]
      K3["Kovaryans: F ve H<br />sabit matrisler"]
      K1 --&gt; K2 --&gt; K3
    end
    subgraph EKF["Genişletilmiş KF (EKF)"]
      direction TB
      E1["Model: x = f(x, u)<br />(doğrusal-olmayabilir)"]
      E2["Ölçüm: z = h(x)<br />(doğrusal-olmayan)"]
      E3["Kovaryans: her adımda<br />Jacobian Fₖ = ∂f/∂x , Hₖ = ∂h/∂x"]
      E1 --&gt; E2 --&gt; E3
    end
    KF -. "aynı 2 adımlı döngü;<br />tek fark: lineerizasyon" .-&gt; EKF
    style KF fill:#e8f0fb,stroke:#3a5f95,stroke-width:2px
    style EKF fill:#fbf0e8,stroke:#a05a2c,stroke-width:2px
    style K3 fill:#cee0f3,stroke:#3a5f95
    style E3 fill:#f5dcc3,stroke:#a05a2c
</div>

<hr />

<h2 id="numpy-ile-sıfırdan-ekf-range-bearing-takibi">NumPy ile Sıfırdan EKF: Range-Bearing Takibi</h2>

<p>Hepsini bir araya getirelim. Aşağıdaki kod, sabit hızla giden (ama yavaşça dönen) bir hedefi, orijindeki menzil-açı sensörüyle takip eder. Klasik KF kodumuzdan tek farkı, <code class="language-plaintext highlighter-rouge">h</code> fonksiyonu, <code class="language-plaintext highlighter-rouge">H_jac</code> Jacobian’ı ve açı sarması.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="n">numpy</span> <span class="k">as</span> <span class="n">np</span>

<span class="n">dt</span> <span class="o">=</span> <span class="mf">1.0</span>
<span class="n">F</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="nf">array</span><span class="p">([[</span><span class="mi">1</span><span class="p">,</span><span class="mi">0</span><span class="p">,</span><span class="n">dt</span><span class="p">,</span><span class="mi">0</span><span class="p">],[</span><span class="mi">0</span><span class="p">,</span><span class="mi">1</span><span class="p">,</span><span class="mi">0</span><span class="p">,</span><span class="n">dt</span><span class="p">],[</span><span class="mi">0</span><span class="p">,</span><span class="mi">0</span><span class="p">,</span><span class="mi">1</span><span class="p">,</span><span class="mi">0</span><span class="p">],[</span><span class="mi">0</span><span class="p">,</span><span class="mi">0</span><span class="p">,</span><span class="mi">0</span><span class="p">,</span><span class="mf">1.0</span><span class="p">]])</span>   <span class="c1"># 2B sabit hız
</span><span class="n">G</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="nf">array</span><span class="p">([[</span><span class="n">dt</span><span class="o">**</span><span class="mi">2</span><span class="o">/</span><span class="mi">2</span><span class="p">,</span><span class="mi">0</span><span class="p">],[</span><span class="mi">0</span><span class="p">,</span><span class="n">dt</span><span class="o">**</span><span class="mi">2</span><span class="o">/</span><span class="mi">2</span><span class="p">],[</span><span class="n">dt</span><span class="p">,</span><span class="mi">0</span><span class="p">],[</span><span class="mi">0</span><span class="p">,</span><span class="n">dt</span><span class="p">]])</span>
<span class="n">Q</span> <span class="o">=</span> <span class="n">G</span> <span class="o">@</span> <span class="p">(</span><span class="mf">0.02</span><span class="o">*</span><span class="n">np</span><span class="p">.</span><span class="nf">eye</span><span class="p">(</span><span class="mi">2</span><span class="p">))</span> <span class="o">@</span> <span class="n">G</span><span class="p">.</span><span class="n">T</span>
<span class="n">sr</span><span class="p">,</span> <span class="n">sth</span> <span class="o">=</span> <span class="mf">0.5</span><span class="p">,</span> <span class="n">np</span><span class="p">.</span><span class="nf">deg2rad</span><span class="p">(</span><span class="mf">1.0</span><span class="p">)</span>               <span class="c1"># menzil (m) ve açı (rad) gürültüsü
</span><span class="n">R</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="nf">diag</span><span class="p">([</span><span class="n">sr</span><span class="o">**</span><span class="mi">2</span><span class="p">,</span> <span class="n">sth</span><span class="o">**</span><span class="mi">2</span><span class="p">])</span>

<span class="k">def</span> <span class="nf">h</span><span class="p">(</span><span class="n">x</span><span class="p">):</span>                                     <span class="c1"># doğrusal-olmayan ölçüm
</span>    <span class="k">return</span> <span class="n">np</span><span class="p">.</span><span class="nf">array</span><span class="p">([</span><span class="n">np</span><span class="p">.</span><span class="nf">hypot</span><span class="p">(</span><span class="n">x</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">x</span><span class="p">[</span><span class="mi">1</span><span class="p">]),</span> <span class="n">np</span><span class="p">.</span><span class="nf">arctan2</span><span class="p">(</span><span class="n">x</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="n">x</span><span class="p">[</span><span class="mi">0</span><span class="p">])])</span>

<span class="k">def</span> <span class="nf">H_jac</span><span class="p">(</span><span class="n">x</span><span class="p">):</span>                                 <span class="c1"># ölçüm Jacobian'ı (2x4)
</span>    <span class="n">px</span><span class="p">,</span> <span class="n">py</span> <span class="o">=</span> <span class="n">x</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">x</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span>
    <span class="n">r2</span> <span class="o">=</span> <span class="n">px</span><span class="o">*</span><span class="n">px</span> <span class="o">+</span> <span class="n">py</span><span class="o">*</span><span class="n">py</span><span class="p">;</span> <span class="n">r</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="nf">sqrt</span><span class="p">(</span><span class="n">r2</span><span class="p">)</span>
    <span class="k">return</span> <span class="n">np</span><span class="p">.</span><span class="nf">array</span><span class="p">([[</span> <span class="n">px</span><span class="o">/</span><span class="n">r</span><span class="p">,</span>   <span class="n">py</span><span class="o">/</span><span class="n">r</span><span class="p">,</span>  <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">],</span>
                     <span class="p">[</span><span class="o">-</span><span class="n">py</span><span class="o">/</span><span class="n">r2</span><span class="p">,</span>  <span class="n">px</span><span class="o">/</span><span class="n">r2</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">]])</span>

<span class="k">def</span> <span class="nf">wrap</span><span class="p">(</span><span class="n">a</span><span class="p">):</span>                                  <span class="c1"># açıyı [-π, π] aralığına sar
</span>    <span class="nf">return </span><span class="p">(</span><span class="n">a</span> <span class="o">+</span> <span class="n">np</span><span class="p">.</span><span class="n">pi</span><span class="p">)</span> <span class="o">%</span> <span class="p">(</span><span class="mi">2</span><span class="o">*</span><span class="n">np</span><span class="p">.</span><span class="n">pi</span><span class="p">)</span> <span class="o">-</span> <span class="n">np</span><span class="p">.</span><span class="n">pi</span>

<span class="c1"># Gerçek hedef: sabit hız + yavaş dönüş; sensör orijinde
</span><span class="n">rng</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">random</span><span class="p">.</span><span class="nf">default_rng</span><span class="p">(</span><span class="mi">4</span><span class="p">)</span>
<span class="n">N</span> <span class="o">=</span> <span class="mi">55</span>
<span class="n">xt</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="nf">array</span><span class="p">([</span><span class="o">-</span><span class="mf">26.0</span><span class="p">,</span> <span class="mf">9.0</span><span class="p">,</span> <span class="mf">1.4</span><span class="p">,</span> <span class="mf">0.25</span><span class="p">])</span>
<span class="n">c</span><span class="p">,</span> <span class="n">s</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="nf">cos</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="nf">deg2rad</span><span class="p">(</span><span class="mf">2.2</span><span class="p">)),</span> <span class="n">np</span><span class="p">.</span><span class="nf">sin</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="nf">deg2rad</span><span class="p">(</span><span class="mf">2.2</span><span class="p">))</span>
<span class="n">truth</span><span class="p">,</span> <span class="n">meas</span> <span class="o">=</span> <span class="p">[],</span> <span class="p">[]</span>
<span class="k">for</span> <span class="n">_</span> <span class="ow">in</span> <span class="nf">range</span><span class="p">(</span><span class="n">N</span><span class="p">):</span>
    <span class="n">truth</span><span class="p">.</span><span class="nf">append</span><span class="p">(</span><span class="n">xt</span><span class="p">.</span><span class="nf">copy</span><span class="p">())</span>
    <span class="n">meas</span><span class="p">.</span><span class="nf">append</span><span class="p">(</span><span class="nf">h</span><span class="p">(</span><span class="n">xt</span><span class="p">)</span> <span class="o">+</span> <span class="n">np</span><span class="p">.</span><span class="nf">array</span><span class="p">([</span><span class="n">rng</span><span class="p">.</span><span class="nf">normal</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">sr</span><span class="p">),</span> <span class="n">rng</span><span class="p">.</span><span class="nf">normal</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">sth</span><span class="p">)]))</span>
    <span class="n">xt</span> <span class="o">=</span> <span class="n">F</span> <span class="o">@</span> <span class="n">xt</span>
    <span class="n">xt</span><span class="p">[</span><span class="mi">2</span><span class="p">:]</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="nf">array</span><span class="p">([[</span><span class="n">c</span><span class="p">,</span> <span class="o">-</span><span class="n">s</span><span class="p">],</span> <span class="p">[</span><span class="n">s</span><span class="p">,</span> <span class="n">c</span><span class="p">]])</span> <span class="o">@</span> <span class="n">xt</span><span class="p">[</span><span class="mi">2</span><span class="p">:]</span>      <span class="c1"># hız vektörünü döndür
</span><span class="n">truth</span><span class="p">,</span> <span class="n">meas</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="nf">array</span><span class="p">(</span><span class="n">truth</span><span class="p">),</span> <span class="n">np</span><span class="p">.</span><span class="nf">array</span><span class="p">(</span><span class="n">meas</span><span class="p">)</span>

<span class="c1"># EKF döngüsü
</span><span class="n">xhat</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="nf">array</span><span class="p">([</span><span class="o">-</span><span class="mf">24.0</span><span class="p">,</span> <span class="mf">12.0</span><span class="p">,</span> <span class="mf">0.0</span><span class="p">,</span> <span class="mf">0.0</span><span class="p">])</span>
<span class="n">P</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="nf">diag</span><span class="p">([</span><span class="mf">16.</span><span class="p">,</span> <span class="mf">16.</span><span class="p">,</span> <span class="mf">9.</span><span class="p">,</span> <span class="mf">9.</span><span class="p">])</span>
<span class="n">I</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="nf">eye</span><span class="p">(</span><span class="mi">4</span><span class="p">);</span> <span class="n">est</span> <span class="o">=</span> <span class="p">[]</span>
<span class="k">for</span> <span class="n">k</span> <span class="ow">in</span> <span class="nf">range</span><span class="p">(</span><span class="n">N</span><span class="p">):</span>
    <span class="c1"># --- TAHMİN (f doğrusal → F sabit) ---
</span>    <span class="n">xhat</span> <span class="o">=</span> <span class="n">F</span> <span class="o">@</span> <span class="n">xhat</span>
    <span class="n">P</span> <span class="o">=</span> <span class="n">F</span> <span class="o">@</span> <span class="n">P</span> <span class="o">@</span> <span class="n">F</span><span class="p">.</span><span class="n">T</span> <span class="o">+</span> <span class="n">Q</span>
    <span class="c1"># --- GÜNCELLEME (h doğrusal-olmayan → Jacobian) ---
</span>    <span class="n">Hk</span> <span class="o">=</span> <span class="nc">H_jac</span><span class="p">(</span><span class="n">xhat</span><span class="p">)</span>
    <span class="n">y</span> <span class="o">=</span> <span class="n">meas</span><span class="p">[</span><span class="n">k</span><span class="p">]</span> <span class="o">-</span> <span class="nf">h</span><span class="p">(</span><span class="n">xhat</span><span class="p">);</span> <span class="n">y</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="nf">wrap</span><span class="p">(</span><span class="n">y</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span>    <span class="c1"># açı farkını sar!
</span>    <span class="n">S</span> <span class="o">=</span> <span class="n">Hk</span> <span class="o">@</span> <span class="n">P</span> <span class="o">@</span> <span class="n">Hk</span><span class="p">.</span><span class="n">T</span> <span class="o">+</span> <span class="n">R</span>
    <span class="n">K</span> <span class="o">=</span> <span class="n">P</span> <span class="o">@</span> <span class="n">Hk</span><span class="p">.</span><span class="n">T</span> <span class="o">@</span> <span class="n">np</span><span class="p">.</span><span class="n">linalg</span><span class="p">.</span><span class="nf">inv</span><span class="p">(</span><span class="n">S</span><span class="p">)</span>
    <span class="n">xhat</span> <span class="o">=</span> <span class="n">xhat</span> <span class="o">+</span> <span class="n">K</span> <span class="o">@</span> <span class="n">y</span>
    <span class="n">P</span> <span class="o">=</span> <span class="p">(</span><span class="n">I</span> <span class="o">-</span> <span class="n">K</span> <span class="o">@</span> <span class="n">Hk</span><span class="p">)</span> <span class="o">@</span> <span class="n">P</span>
    <span class="n">est</span><span class="p">.</span><span class="nf">append</span><span class="p">(</span><span class="n">xhat</span><span class="p">.</span><span class="nf">copy</span><span class="p">())</span>
<span class="n">est</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="nf">array</span><span class="p">(</span><span class="n">est</span><span class="p">)</span>

<span class="n">rmse</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="nf">sqrt</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="nf">mean</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="nf">sum</span><span class="p">((</span><span class="n">est</span><span class="p">[:,</span> <span class="p">:</span><span class="mi">2</span><span class="p">]</span> <span class="o">-</span> <span class="n">truth</span><span class="p">[:,</span> <span class="p">:</span><span class="mi">2</span><span class="p">])</span><span class="o">**</span><span class="mi">2</span><span class="p">,</span> <span class="n">axis</span><span class="o">=</span><span class="mi">1</span><span class="p">)))</span>
<span class="nf">print</span><span class="p">(</span><span class="sa">f</span><span class="sh">"</span><span class="s">EKF konum RMSE = </span><span class="si">{</span><span class="n">rmse</span><span class="si">:</span><span class="p">.</span><span class="mi">2</span><span class="n">f</span><span class="si">}</span><span class="s"> m</span><span class="sh">"</span><span class="p">)</span>         <span class="c1"># -&gt; 0.56 m
</span></code></pre></div></div>

<p>Burada hareketin doğrusal olduğuna (<code class="language-plaintext highlighter-rouge">f</code> = sabit <code class="language-plaintext highlighter-rouge">F</code>) ama ölçümün doğrusal-olmadığına dikkat edin: tüm doğrusal-olmama <code class="language-plaintext highlighter-rouge">h</code> ve <code class="language-plaintext highlighter-rouge">H_k</code>‘de yaşıyor. Her adımda yeniden hesaplanan tek şey <code class="language-plaintext highlighter-rouge">Hk</code> Jacobian’ı. Sonuç: 1°’lik açı ve 0.5 m’lik menzil gürültüsüne rağmen konum RMSE’si <strong>0.56 m</strong> — sensörün ham gürültüsünün epey altında.</p>

<figure>
  <img src="/img/posts/ekf-trajectory.webp" alt="EKF ile menzil-açı sensöründen 2B hedef takibi" class="img-fluid rounded" />
  <figcaption><strong>Şekil 5.</strong> Orijindeki sensör (siyah elmas), gerçek yörünge (yeşil), menzil-açı ölçümlerinin xy'ye çevrilmiş hâli (kırmızı) ve EKF kestirimi (mavi). Seçili adımlardaki 2σ kovaryans elipsleri, filtrenin konum belirsizliğini gösterir; gürültülü kırmızı bulutun içinden mavi çizgi pürüzsüzce süzülüyor.</figcaption>
</figure>

<hr />

<h2 id="etkileşimli-simülatör-genişletilmiş-kalman-filtresi">Etkileşimli Simülatör: Genişletilmiş Kalman Filtresi</h2>

<p>Şimdi EKF’i canlı izleyelim. Bu sefer üstten bakışlı 2B bir görünüm var: orijinde sensör, dönen bir hedef ve EKF’in kovaryans elipsi. Menzil ve açı gürültüsünü, filtrenin süreç gürültüsünü ve hedefin dönüş hızını ayarlayabilirsiniz.</p>

<div class="card my-3" id="ekf-demo">
  <div class="card-header py-2"><strong>Genişletilmiş Kalman Filtresi (EKF) Simülatörü</strong></div>
  <div class="card-body">
    <div class="form-row mb-2">
      <div class="col-md-3 mb-2">
        <label class="mb-0 small">Menzil gürültüsü σ<sub>r</sub> = <b id="ekf-v-sr">0.50</b> m</label>
        <input type="range" class="custom-range" id="ekf-sl-sr" min="0.05" max="3" value="0.5" step="0.05" />
      </div>
      <div class="col-md-3 mb-2">
        <label class="mb-0 small">Açı gürültüsü σ<sub>θ</sub> = <b id="ekf-v-sth">1.0</b>°</label>
        <input type="range" class="custom-range" id="ekf-sl-sth" min="0.1" max="5" value="1" step="0.1" />
      </div>
      <div class="col-md-3 mb-2">
        <label class="mb-0 small">Süreç gürültüsü q = <b id="ekf-v-q">0.0100</b></label>
        <input type="range" class="custom-range" id="ekf-sl-q" min="0.0001" max="0.5" value="0.01" step="0.0001" />
      </div>
      <div class="col-md-3 mb-2">
        <label class="mb-0 small">Dönüş hızı = <b id="ekf-v-turn">0.5</b>°/adım</label>
        <input type="range" class="custom-range" id="ekf-sl-turn" min="0" max="3" value="0.5" step="0.1" />
      </div>
    </div>
    <div class="mb-2">
      <button class="btn btn-sm btn-primary" id="ekf-btn-play" type="button">⏸ Duraklat</button>
      <button class="btn btn-sm btn-outline-secondary" id="ekf-btn-reset" type="button">↻ Yeni gerçekleştirme</button>
    </div>
    <div id="ekf-status" class="px-2 py-1 mb-2 rounded small" style="font-family:monospace;min-height:2.2em;background:#f1f5fb;"></div>
    <canvas id="ekf-canvas" style="width:100%;display:block;border-radius:4px;border:1px solid #dee2e6;"></canvas>
    <p class="text-muted small mt-1 mb-0">Sensör orijinde. Hedef uzaktayken 2σ elipsi açı (teğet) yönünde şişer — uzakta küçük bir açı hatası büyük yanal hataya dönüşür. Hedef sensöre yaklaştıkça elips daralır: gözlemlenebilirliğin (observability) görünür hâli.</p>
  </div>
</div>

<script src="/assets/js/posts/kalman-ekf.js"></script>

<p>En öğretici deney: açı gürültüsünü (<code class="language-plaintext highlighter-rouge">σ_θ</code>) büyütün ve kovaryans elipsinin nasıl bir <strong>muz</strong> şeklini aldığını izleyin. Elips, sensöre olan doğrultuya <strong>dik</strong> (teğetsel) yönde uzar; çünkü uzak bir hedefte 1°’lik açı hatası, metrelerce yanal konum hatası demektir — oysa menzil yönündeki belirsizlik küçük kalır. Dönüş hızını artırırsanız, sabit-hız varsayan filtrenin manevra anlarında gerçek yörüngenin <strong>dışına savrularak</strong> geciktiğini görürsünüz; bu, model uyumsuzluğunun (model mismatch) doğrudan görsel kanıtıdır.</p>

<hr />

<h2 id="mühendislik-notları-q-r-ayarı-iraksama-ve-sayısal-kararlılık">Mühendislik Notları: Q, R Ayarı, Iraksama ve Sayısal Kararlılık</h2>

<p>Filtreyi çalıştırmak kolay; <strong>doğru</strong> çalıştırmak ustalık ister. Sahaya çıkmadan önce kontrol listesi:</p>

<ol>
  <li>
    <p><strong>Asıl mesele <code class="language-plaintext highlighter-rouge">Q/R</code> oranıdır.</strong> <code class="language-plaintext highlighter-rouge">R</code> çoğu zaman sensörün veri sayfasından ya da statik kalibrasyondan bilinir; gerçek ayar düğmesi <code class="language-plaintext highlighter-rouge">Q</code>‘dur. Mutlak değerlerden çok, <code class="language-plaintext highlighter-rouge">Q</code> ile <code class="language-plaintext highlighter-rouge">R</code> arasındaki <strong>oran</strong> filtrenin karakterini belirler: büyük <code class="language-plaintext highlighter-rouge">Q/R</code> → çevik ama gürültülü; küçük <code class="language-plaintext highlighter-rouge">Q/R</code> → pürüzsüz ama tembel ve manevrada geciken. Simülatörlerde bunu elinizle hissettiniz.</p>
  </li>
  <li>
    <p><strong>Filtrenin tutarlılığını ölçün (NIS/NEES).</strong> Filtre yalnızca doğru tahmin etmemeli, belirsizliği hakkında da <strong>dürüst</strong> olmalı. Yenilik <code class="language-plaintext highlighter-rouge">y</code> ile kovaryansı <code class="language-plaintext highlighter-rouge">S</code> kullanılarak hesaplanan normalize yenilik karesi (NIS), istatistiksel olarak bir χ² dağılımına uymalıdır. Yenilikler <code class="language-plaintext highlighter-rouge">S</code>‘in öngördüğünden sürekli büyükse filtre fazla iyimserdir (<code class="language-plaintext highlighter-rouge">Q</code> veya <code class="language-plaintext highlighter-rouge">R</code> küçük); sürekli küçükse fazla karamsardır. NIS, “filtrem yalan söylüyor mu?” sorusunun nicel cevabıdır.</p>
  </li>
  <li>
    <p><strong>Iraksamaya (divergence) karşı uyanık olun.</strong> En sinsi hata, <code class="language-plaintext highlighter-rouge">P</code>‘nin gerçek hatadan çok daha küçük olması — filtre kendine güvenir, gelen ölçümleri “aykırı” sanıp reddeder, gerçekten gitgide kopar. Sebepleri: çok küçük <code class="language-plaintext highlighter-rouge">Q</code>, modellenmemiş bir dinamik, ya da sayısal yuvarlama. Lineer simülatörde <code class="language-plaintext highlighter-rouge">q</code>‘yu dibe çekerek bunu birebir görebilirsiniz.</p>
  </li>
  <li>
    <p><strong>Sayısal kararlılık için Joseph formunu kullanın.</strong> <code class="language-plaintext highlighter-rouge">P = (I − KH)P⁻</code> denklemi, kayan-nokta yuvarlamasıyla <code class="language-plaintext highlighter-rouge">P</code>‘yi asimetrik veya negatif-tanımlı yapabilir; bu da filtreyi çökertir. Joseph formu <code class="language-plaintext highlighter-rouge">P = (I−KH)P⁻(I−KH)ᵀ + KRKᵀ</code> her zaman simetrik ve pozitif yarı-tanımlı sonuç verir. Ek maliyet birkaç matris çarpımıdır; gömülü sistemlerde ucuz bir sigortadır. Her adımda <code class="language-plaintext highlighter-rouge">P</code>‘yi <code class="language-plaintext highlighter-rouge">(P + Pᵀ)/2</code> ile simetrikleştirmek de yaygın, ucuz bir önlemdir. (Kayan-nokta tuzakları üzerine ayrı bir yazı yazmıştım; Kalman filtresi bu tuzakların en çok ısırdığı yerlerden biridir.)</p>
  </li>
  <li>
    <p><strong>Gözlemlenebilirliği (observability) sorgulayın.</strong> Yalnızca menzil ölçen bir sensör, hedefin açısal konumunu tek başına belirleyemez; takip ancak hedef hareket ettikçe ve geometri değiştikçe oturur. EKF simülatöründe elipsin yöne bağlı şişmesi tam da bunun resmidir. Durumunuzun ölçümlerinizden gerçekten <strong>çıkarılabilir</strong> olduğundan emin olun.</p>
  </li>
  <li>
    <p><strong>EKF’e özgü tehlike: lineerizasyon hatası.</strong> Başlangıç tahmini gerçekten uzaksa ya da fonksiyon çok bükülmüşse, teğet kötü bir yaklaşım olur ve EKF ıraksar. Çok keskin doğrusal-olmamalıkta, türev almayan <strong>Unscented Kalman Filtresi (UKF)</strong> — dağılımı seçili “sigma noktalarıyla” temsil eder — genellikle daha sağlamdır ve Jacobian türetme derdini ortadan kaldırır. Dağılım çok-modlu (multimodal) veya gürültü Gauss’tan çok uzaksa, sıra <strong>parçacık filtresine</strong> (particle filter) gelir: dağılımı binlerce örnekle temsil eden, hesapça pahalı ama çok genel bir yöntem.</p>
  </li>
</ol>

<hr />

<h2 id="sonuç">Sonuç</h2>

<p>Kalman filtresi, ilk bakışta matris denklemlerinden oluşan korkutucu bir reçete gibi görünür. Oysa altında yatan fikir tek bir cümleyle özetlenir: <strong>iki Gauss bilgiyi — modelin tahmini ile sensörün ölçümünü — her birinin belirsizliğine göre tartarak birleştir, sonra tekrarla.</strong> Tahmin adımı belirsizliği büyütür, güncelleme adımı küçültür; bu nefes alıp verme sonsuza dek sürer.</p>

<p>EKF ise aynı makinenin doğrusal-olmayan dünyaya uzanmış hâlidir: her adımda fonksiyonları çalışma noktasında bir teğetle değiştirir, gerisini değiştirmez. Bu küçük numara, onu yarım asırdır navigasyondan robotiğe kadar her yerde çalışan bir iş atı yapmıştır — kusursuz değil, ama şaşırtıcı derecede dayanıklı.</p>

<p>Tasarımınızın kaderini üç şey belirler: modelin (<code class="language-plaintext highlighter-rouge">F</code>, <code class="language-plaintext highlighter-rouge">H</code> ya da <code class="language-plaintext highlighter-rouge">f</code>, <code class="language-plaintext highlighter-rouge">h</code>) gerçeğe sadakati, <code class="language-plaintext highlighter-rouge">Q</code>‘nun ve <code class="language-plaintext highlighter-rouge">R</code>‘nin doğru ayarı. Bu üçünü yerine oturtursanız, gürültünün altından şaşırtıcı netlikte bir gerçek çıkarırsınız. Yanlış ayarlarsanız, filtre ya tembelce gerçeğin peşinden sürüklenir ya da kendine aşırı güvenip sessizce ıraksar. Her iki sonu da sahada görmek mümkün — ve artık ikisini de tanıyorsunuz.</p>

<p>Devamı için iyi konular: durum boyutu büyüdüğünde <strong>kare-kök (square-root) filtreleri</strong> sayısal kararlılığı nasıl kurtarır; <strong>UKF</strong> sigma noktalarıyla Jacobian’a neden hiç ihtiyaç duymaz; ve birden çok hareket modelini paralel koşturan <strong>IMM</strong> (Interacting Multiple Model) manevra yapan hedeflerde neden EKF’i döver. Bunlar defterimde duruyor.</p>

<hr />

<p><strong>Kaynaklar:</strong></p>

<ul>
  <li>R. E. Kálmán — <a href="https://doi.org/10.1115/1.3662552">“A New Approach to Linear Filtering and Prediction Problems”</a>, Journal of Basic Engineering, Vol. 82, No. 1, 1960, pp. 35–45. (Her şeyin başladığı makale.)</li>
  <li>Greg Welch, Gary Bishop — <a href="https://www.cs.unc.edu/~welch/kalman/"><em>An Introduction to the Kalman Filter</em></a>, UNC-Chapel Hill, TR 95-041. (Klasik, sade giriş.)</li>
  <li>Sebastian Thrun, Wolfram Burgard, Dieter Fox — <em>Probabilistic Robotics</em> (MIT Press, 2005), Bölüm 3: “Gaussian Filters”. (KF ve EKF’in olasılıksal türetimi.)</li>
  <li>Dan Simon — <em>Optimal State Estimation: Kalman, H∞, and Nonlinear Approaches</em> (Wiley, 2006). (Joseph formu, kare-kök filtreleri ve sayısal konular için referans.)</li>
  <li>Yaakov Bar-Shalom, X.-Rong Li, Thiagalingam Kirubarajan — <em>Estimation with Applications to Tracking and Navigation</em> (Wiley, 2001). (Menzil-açı takibi, NIS/NEES tutarlılık testleri.)</li>
  <li>S. J. Julier, J. K. Uhlmann — <a href="https://doi.org/10.1109/JPROC.2003.823141">“Unscented Filtering and Nonlinear Estimation”</a>, Proceedings of the IEEE, Vol. 92, No. 3, 2004. (EKF’in ötesi: UKF.)</li>
  <li>Roger Labbe — <a href="https://github.com/rlabbe/Kalman-and-Bayesian-Filters-in-Python"><em>Kalman and Bayesian Filters in Python</em></a>. (Etkileşimli, kod-ağırlıklı ücretsiz kitap.)</li>
</ul>]]></content><author><name>M. Serdar Karaman</name></author><category term="aviyonik" /><category term="sinyal-isleme" /><category term="aviyonik" /><summary type="html"><![CDATA[Telefonunuz masanın üzerinde dururken bile GPS noktası birkaç metre oraya buraya zıplar. Arabadaki ivmeölçer mükemmel veri verir ama integralini aldığınızda hata saniyeler içinde birikip sürüklenir (drift). Tek başına ne sensöre ne de modele güvenebilirsiniz — yine de haritadaki maviniz pürüzsüz, kararlı bir çizgi çizer. Bu sihrin arkasındaki makine çoğu zaman aynıdır: Kalman filtresi.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://karaman.dev/img/og-default.webp" /><media:content medium="image" url="https://karaman.dev/img/og-default.webp" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry xml:lang="tr"><title type="html">Sistem Mühendisliği Nedir?</title><link href="https://karaman.dev/2026/05/26/sistem-muhendisligi-nedir.html" rel="alternate" type="text/html" title="Sistem Mühendisliği Nedir?" /><published>2026-05-26T09:00:00+00:00</published><updated>2026-05-26T09:00:00+00:00</updated><id>https://karaman.dev/2026/05/26/sistem-muhendisligi-nedir</id><content type="html" xml:base="https://karaman.dev/2026/05/26/sistem-muhendisligi-nedir.html"><![CDATA[<p>Modern bir yolcu uçağında milyonlarca parça, onlarca farklı mühendislik disiplini ve binlerce gereksinim bir arada bulunur. Aerodinamikçi kanadı, yazılımcı uçuş kontrol bilgisayarını, elektronik mühendisi aviyonik veri yolunu, malzeme mühendisi gövde alaşımını tasarlar. Hiçbiri tek başına diğerinin işini bilmek zorunda değildir. Peki bütün bu parçaların <em>birlikte</em> güvenli bir şekilde uçan tek bir uçak oluşturduğundan kim emin olur?</p>

<p>İşte bu sorunun cevabı <strong>sistem mühendisliğidir</strong>. Sistem mühendisi, tek tek parçaları tasarlayan kişi değil; parçaların oluşturduğu <em>bütünün</em> doğru çalışmasından sorumlu olan kişidir.</p>

<p>Daha önce <a href="/2022/04/29/yazilim-sistem-muhendisligi.html">Yazılım Sistem Mühendisliği</a> yazısında bu disiplinin yazılıma özel halini ele almıştık. Bu yazıda ise konuya bir adım geri çekilip sistem mühendisliğinin genel resmine bakacağız: ne olduğuna, neden gerekli olduğuna, yaşam döngüsünün nasıl yönetildiğine ve hangi standartların bu işi disipline ettiğine.</p>

<hr />

<h2 id="önce-sistem-nedir">Önce “Sistem” Nedir?</h2>

<p>Sistem mühendisliğini anlamak için önce <strong>sistem</strong> kelimesinin mühendislikteki anlamını netleştirmek gerekir. Sistem; ortak bir amaca hizmet etmek üzere bir araya gelmiş, birbiriyle etkileşen parçaların oluşturduğu bütündür. Bu parçalar yalnızca donanım değildir; <strong>donanım, yazılım, insanlar, prosedürler, veri ve tesisler</strong> birlikte bir sistemi oluşturabilir.</p>

<p>Sistemin en kritik özelliği, parçaların toplamından <em>fazlası</em> olmasıdır. Bir sistemin sergilediği ama hiçbir bileşeninde tek başına bulunmayan özelliklere <strong>beliren özellikler</strong> (<em>emergent properties</em>) denir:</p>

<ul>
  <li>Bir uçağın “uçabilmesi” hiçbir tek parçasının özelliği değildir; parçaların doğru birleşiminden doğar.</li>
  <li>Bir sistemin “emniyetli” veya “güvenli” olması, bütünsel bir niteliktir; tek bir vidaya bakarak ölçülemez.</li>
  <li>Tam tersi de geçerlidir: Her bileşeni ayrı ayrı kusursuz çalışan bir sistem, arayüzlerdeki uyumsuzluk yüzünden bütün olarak başarısız olabilir.</li>
</ul>

<p>İşte sistem mühendisliği tam da bu <strong>bütünsel</strong> ve <strong>beliren</strong> özelliklerle ilgilenir. Tek tek bileşenlerin mükemmelliği değil, onların birlikte çalıştığında ortaya çıkardığı davranış esas konudur.</p>

<hr />

<h2 id="sistem-mühendisliğinin-tanımı">Sistem Mühendisliğinin Tanımı</h2>

<p>Alanın en yetkili kurumu olan <strong>INCOSE</strong> (International Council on Systems Engineering) sistem mühendisliğini şöyle tanımlar:</p>

<blockquote>
  <p><em>Sistem mühendisliği; mühendislik ürünü sistemlerin başarılı bir şekilde gerçekleştirilmesini, kullanılmasını ve hizmetten çıkarılmasını sağlamak amacıyla sistem ilke ve kavramlarını, bilimsel, teknolojik ve yönetimsel yöntemlerle birleştiren disiplinler ötesi ve bütünleştirici bir yaklaşımdır.</em></p>
</blockquote>

<p>Bu tanımın iki anahtar kelimesi vardır:</p>

<ul>
  <li><strong>Disiplinler ötesi (transdisciplinary):</strong> Sistem mühendisi tek bir uzmanlık alanına gömülmez; mekanik, elektronik, yazılım, güvenilirlik, maliyet ve insan faktörleri gibi alanların <em>kesişiminde</em> çalışır.</li>
  <li><strong>Bütünleştirici (integrative):</strong> Asıl görev, farklı uzmanların ürettiği parçaları tutarlı bir bütün hâlinde birleştirmek ve aralarındaki arayüzleri yönetmektir.</li>
</ul>

<p>Buna sıkça eşlik eden bir benzetme vardır: Uzmanlık mühendisleri (yazılımcı, elektronikçi, makineci) bir orkestranın enstrüman sanatçılarıysa, sistem mühendisi <strong>orkestra şefidir</strong>. Şef hiçbir enstrümanı en iyi çalan kişi değildir; ama bütünün uyum içinde, doğru tempoda ve doğru notalarla çalmasından sorumludur.</p>

<hr />

<h2 id="neden-sistem-mühendisliğine-i̇htiyaç-var">Neden Sistem Mühendisliğine İhtiyaç Var?</h2>

<p>Küçük ve basit bir ürün için ayrı bir sistem mühendisliği faaliyetine ihtiyaç olmayabilir. Sistemler büyüdükçe, karmaşıklaştıkça ve disiplin sayısı arttıkça üç temel problem ortaya çıkar:</p>

<ol>
  <li><strong>Karmaşıklık:</strong> Bileşen sayısı arttıkça aralarındaki olası etkileşim sayısı <em>karesel</em> olarak büyür. On bileşenli bir sistemde 45 olası ikili arayüz vardır; yüz bileşende bu sayı 4950’ye çıkar. Kimse bu karmaşıklığı kafasında tutamaz; yönetilmesi gerekir.</li>
  <li><strong>Disiplinler arası çatışma:</strong> Yazılımcının “kolay” dediği şey elektronikçi için imkânsız, ağırlık mühendisi için kabul edilemez olabilir. Bu çelişen kısıtların dengelenmesi (<em>trade-off</em>) gerekir.</li>
  <li><strong>Hataların geç fark edilmesinin maliyeti:</strong> Bir hatayı gereksinim aşamasında yakalamakla sahada yakalamak arasında binlerce kat maliyet farkı vardır.</li>
</ol>

<p>Bu son madde, sistem mühendisliğinin varlık sebebini en çarpıcı biçimde özetler. Barry Boehm’in klasik çalışmaları ve NASA verileriyle desteklenen meşhur <strong>hata maliyeti tırmanması</strong> aşağıdaki grafikte gösterilmektedir:</p>

<figure>
  <img src="/img/posts/sistem-muhendisligi-hata-maliyeti.webp" alt="Hatanın yakalandığı aşamaya göre göreli düzeltme maliyetini gösteren, logaritmik ölçekli çubuk grafik" class="img-fluid rounded" />
  <figcaption><strong>Şekil 1.</strong> Bir hatanın düzeltme maliyeti, yakalandığı aşama geciktikçe logaritmik olarak büyür: gereksinim aşamasında 1× olan maliyet, sistem sahaya çıktıktan sonra 100–1000× seviyesine tırmanır. Dikey eksen logaritmik ölçektedir; çubuklardaki bıyıklar literatürde verilen alt–üst aralığı gösterir.</figcaption>
</figure>

<p>Buradaki ders nettir: Sistem mühendisliği maliyetin <strong>büyük kısmının henüz harcanmadığı</strong>, fakat o maliyetin <strong>büyük kısmının taahhüt edildiği</strong> erken aşamalara yoğunlaşır. Yaşam döngüsünün ilk %15’inde verilen kararlar, toplam maliyetin yaklaşık %80’ini kilitler. Doğru yatırım yeri burasıdır.</p>

<hr />

<h2 id="sistem-mühendisliği-yaşam-döngüsü-v-modeli">Sistem Mühendisliği Yaşam Döngüsü: V Modeli</h2>

<p>Sistem mühendisliği sürecini anlatmak için en yaygın kullanılan görsel, <strong>V modelidir</strong>. V’nin sol kolu yukarıdan aşağıya <strong>ayrıştırma ve tanımlama</strong> sürecini, sağ kolu ise aşağıdan yukarıya <strong>entegrasyon ve doğrulama</strong> sürecini temsil eder. V’nin tabanında ise gerçekleştirme (kodlama/üretim) yer alır.</p>

<p><img src="/img/posts/sistem-muhendisligi-v-modeli.webp" alt="Sistem Mühendisliği V Modeli" style="display:block; margin-left:auto; margin-right:auto" class="img-fluid" /></p>

<p>Bu modelin en güçlü fikri, sol koldaki her seviyenin sağ kolda <strong>kendisine eşlenen bir doğrulama seviyesi</strong> olmasıdır:</p>

<ul>
  <li>Sistem gereksinimleri ↔ Sistem doğrulama testleri</li>
  <li>Mimari tasarım ↔ Entegrasyon testleri</li>
  <li>Birim tasarımı ↔ Birim testleri</li>
</ul>

<p>Yani bir gereksinim yazılırken daha o anda “bu gereksinimi <em>nasıl</em> doğrulayacağım?” sorusu sorulur. Doğrulanamayan bir gereksinim, kötü bir gereksinimdir. V modelinin yatay okları bu izlenebilirlik (<em>traceability</em>) ilişkisini gösterir.</p>

<hr />

<h2 id="temel-süreçler">Temel Süreçler</h2>

<p>Modern sistem mühendisliği, <strong>ISO/IEC/IEEE 15288</strong> standardıyla resmî bir çerçeveye oturtulmuştur. Bu standart, sistem yaşam döngüsü süreçlerini dört grupta toplar: anlaşma süreçleri, organizasyonel proje destek süreçleri, teknik yönetim süreçleri ve teknik süreçler. Pratikte sistem mühendisinin günlük işini oluşturan <strong>teknik süreçler</strong> şunlardır:</p>

<h3 id="gereksinim-mühendisliği">Gereksinim Mühendisliği</h3>

<p>Her şey paydaşların ihtiyaçlarıyla başlar. Sistem mühendisi bu ihtiyaçları toplar, çelişkilerini çözer ve onları ölçülebilir, test edilebilir <strong>sistem gereksinimlerine</strong> dönüştürür. Gereksinimler genellikle bir hiyerarşi oluşturur:</p>

<div class="mermaid">
graph TD
    S[Paydaş İhtiyaçları] --&gt; SR[Sistem Gereksinimleri]
    SR --&gt; H[Donanım Gereksinimleri]
    SR --&gt; Y[Yazılım Gereksinimleri]
    SR --&gt; M[Mekanik Gereksinimler]
    H --&gt; H1[Bileşen Gereksinimleri]
    Y --&gt; Y1[Modül Gereksinimleri]
</div>

<p>İyi bir gereksinim; tek anlamlı, doğrulanabilir, ulaşılabilir ve izlenebilir olmalıdır. Gereksinimler genellikle iki kümeye ayrılır:</p>

<ul>
  <li><strong>Fonksiyonel gereksinimler:</strong> Sistemin <em>ne yapacağını</em> tanımlar (“Sistem, hedefe X saniye içinde kilitlenmelidir”).</li>
  <li><strong>Fonksiyonel olmayan gereksinimler</strong> (<em>-ilities</em>): Sistemin <em>nasıl olacağını</em> tanımlar — güvenilirlik (<em>reliability</em>), kullanılabilirlik (<em>availability</em>), bakım yapılabilirlik (<em>maintainability</em>), emniyet (<em>safety</em>), güvenlik (<em>security</em>), performans, taşınabilirlik. Sistemlerin başarısı çoğu zaman bu niteliklerde gizlidir.</li>
</ul>

<h3 id="mimari-ve-tasarım-tanımı">Mimari ve Tasarım Tanımı</h3>

<p>Gereksinimler belirlendikten sonra sistem mühendisi sistemin <strong>mimarisini</strong> kurar: hangi fonksiyon hangi bileşene atanacak, bileşenler hangi arayüzlerle konuşacak, veri nasıl akacak. Bu aşamada en kritik ürün <strong>arayüz kontrol belgeleridir</strong> (<em>interface control documents</em>, ICD). Sistemlerin çoğu, bileşenlerin içinde değil, bileşenler <em>arasındaki</em> arayüzlerde patlar.</p>

<h3 id="sistem-analizi-ve-trade-study">Sistem Analizi ve Trade Study</h3>

<p>Hiçbir tasarım kararı tek başına doğru ya da yanlış değildir; bir denge içerir. Daha hafif mi yoksa daha ucuz mu? Daha hızlı mı yoksa daha güç-verimli mi? Sistem mühendisi bu alternatifleri <strong>trade study</strong> (denge analizi) ile sistematik biçimde değerlendirir: kriterleri belirler, ağırlıklandırır, seçenekleri puanlar ve kararı <em>gerekçesiyle</em> kayıt altına alır.</p>

<h3 id="entegrasyon-doğrulama-ve-onaylama">Entegrasyon, Doğrulama ve Onaylama</h3>

<p>Bileşenler üretildikten sonra sıra V’nin sağ kolundaki birleştirme ve sınama sürecine gelir. Burada sistem mühendisliğinin belki de en sık karıştırılan iki kavramı devreye girer:</p>

<ul>
  <li><strong>Doğrulama (Verification) — “Sistemi doğru mu yaptık?”</strong> Ürünün belirlenmiş gereksinimlere uyup uymadığının kontrolüdür. Referans, yazılı gereksinim ve tasarım belgeleridir.</li>
  <li><strong>Onaylama (Validation) — “Doğru sistemi mi yaptık?”</strong> Ürünün, gerçek kullanım ortamında paydaşın asıl ihtiyacını karşılayıp karşılamadığının gösterilmesidir.</li>
</ul>

<p>Bir sistem her gereksinimini eksiksiz karşılayıp (doğrulamayı geçip) yine de yanlış sistem olabilir — çünkü gereksinimlerin kendisi baştan yanlış yazılmış olabilir. İyi sistem mühendisliği her ikisini de güvenceye alır.</p>

<h3 id="süreç-boyunca-yatay-faaliyetler">Süreç Boyunca Yatay Faaliyetler</h3>

<p>Bu teknik süreçlere ek olarak, projenin tamamına yayılan yönetimsel faaliyetler vardır: <strong>risk yönetimi</strong>, <strong>konfigürasyon yönetimi</strong> (hangi versiyon, hangi değişiklik), <strong>izlenebilirlik yönetimi</strong> ve <strong>teknik gözden geçirmeler</strong> (SRR, PDR, CDR gibi kapı niteliğindeki tasarım gözden geçirmeleri).</p>

<hr />

<h2 id="standartlar-ve-çerçeveler">Standartlar ve Çerçeveler</h2>

<p>Sistem mühendisliği, sektöre göre farklılaşan zengin bir standart ekosistemine sahiptir. Başlıcaları:</p>

<table>
  <thead>
    <tr>
      <th>Standart / Çerçeve</th>
      <th>Alan</th>
      <th>Kapsam</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>**ISO/IEC/IEEE 15288**</td>
      <td>Genel</td>
      <td>Sistem yaşam döngüsü süreçlerinin temel standardı</td>
    </tr>
    <tr>
      <td>**INCOSE SE Handbook** (v5, 2023)</td>
      <td>Genel</td>
      <td>Uygulamaya dönük en yaygın başvuru kaynağı</td>
    </tr>
    <tr>
      <td>**NASA SE Handbook** (SP-2016-6105)</td>
      <td>Uzay</td>
      <td>NASA’nın sistem mühendisliği uygulama kılavuzu</td>
    </tr>
    <tr>
      <td>**SAE ARP4754B** (2023)</td>
      <td>Sivil havacılık</td>
      <td>Uçak ve sistem geliştirme süreçleri</td>
    </tr>
    <tr>
      <td>**DO-178C / DO-254**</td>
      <td>Havacılık</td>
      <td>Aviyonik yazılım / donanım geliştirme</td>
    </tr>
    <tr>
      <td>**ISO 26262**</td>
      <td>Otomotiv</td>
      <td>Yol araçlarında fonksiyonel emniyet</td>
    </tr>
    <tr>
      <td>**IEC 61508**</td>
      <td>Endüstri</td>
      <td>Genel fonksiyonel emniyet ana standardı</td>
    </tr>
    <tr>
      <td>**CMMI**</td>
      <td>Süreç olgunluğu</td>
      <td>Geliştirme süreçlerinin olgunluk değerlendirmesi</td>
    </tr>
  </tbody>
</table>

<p>Tarihsel olarak alanın kökleri 1950–60’lı yıllarda ABD savunma ve uzay programlarına (örneğin <strong>MIL-STD-499</strong>) ve Bell Labs’in karmaşık telekomünikasyon projelerine dayanır. Apollo programı, sistem mühendisliğini bir disiplin olarak olgunlaştıran kilometre taşı kabul edilir.</p>

<hr />

<h2 id="belge-merkezliden-model-merkezliye-mbse">Belge Merkezliden Model Merkezliye: MBSE</h2>

<p>Geleneksel sistem mühendisliği büyük ölçüde <strong>belge merkezlidir</strong>: yüzlerce sayfalık gereksinim dokümanları, Word ve Excel tablolarında yönetilen izlenebilirlik matrisleri. Bu yaklaşımın sorunu, belgelerin kolayca tutarsız hâle gelmesi ve büyük sistemlerde senkronizasyonun imkânsızlaşmasıdır.</p>

<p><strong>Model Tabanlı Sistem Mühendisliği</strong> (<em>Model-Based Systems Engineering</em>, MBSE) bu soruna yanıttır. INCOSE’un tanımıyla MBSE; gereksinim, tasarım, analiz, doğrulama ve onaylama faaliyetlerini desteklemek için modellemenin, kavramsal tasarım aşamasından itibaren resmî olarak kullanılmasıdır.</p>

<p>MBSE’de “tek doğru kaynak” artık belgeler değil, <strong>tutarlı bir sistem modelidir</strong>. Bu modelden gereksinim raporları, arayüz tanımları ve diyagramlar otomatik türetilir. Modelin standart dili çoğunlukla <strong>SysML</strong>‘dir (Systems Modeling Language); son yıllarda olgunlaşan <strong>SysML v2</strong>, dilin ifade gücünü ve araç birlikte çalışabilirliğini önemli ölçüde artırmıştır.</p>

<p>Bu dönüşüm, <strong>dijital iplik</strong> (<em>digital thread</em>) ve <strong>dijital ikiz</strong> (<em>digital twin</em>) gibi kavramların da temelini oluşturur: Sistemin kavramdan operasyona kadar tüm yaşam döngüsünün dijital, izlenebilir ve simüle edilebilir bir kopyasının tutulması.</p>

<hr />

<h2 id="sistem-mühendisinin-rolü">Sistem Mühendisinin Rolü</h2>

<p>Yaygın bir yanılgı, sistem mühendisinin “her şeyi en iyi bilen süper mühendis” olduğudur. Gerçekte iyi bir sistem mühendisi genellikle <strong>T biçimli</strong> bir profile sahiptir: Bir alanda derin uzmanlık (T’nin dikey çizgisi) ile birlikte birçok alana yayılan geniş bir kavrayış (T’nin yatay çizgisi).</p>

<p>Sistem mühendisinin asıl katma değeri teknik değil, çoğu zaman <strong>bütünleştirici</strong> ve <strong>iletişimsel</strong> olmasıdır:</p>

<ul>
  <li>Farklı disiplinlerin dilini anlar ve aralarında tercümanlık yapar.</li>
  <li>Bütünü görür; lokal optimizasyonun (bir bileşeni mükemmelleştirirken sistemi bozmanın) tuzağına düşmez.</li>
  <li>Kararların <em>gerekçesini</em> (<em>rationale</em>) kayıt altına alır; “neden böyle yapıldı?” sorusunun cevabını yıllar sonrasına taşır.</li>
  <li>Projenin <strong>teknik vicdanıdır</strong>: Takvim baskısı altında “bunu sonra hallederiz” denen riskleri görünür kılar.</li>
</ul>

<hr />

<h2 id="sonuç">Sonuç</h2>

<p>Sistem mühendisliği, parlak bileşenler üretmekle ilgili değildir; o bileşenlerin <strong>birlikte, doğru ve güvenli biçimde çalışan bir bütün</strong> oluşturmasını sağlamakla ilgilidir. Karmaşıklık arttıkça, başarısızlığın asıl kaynağı tek tek parçaların kalitesi değil, parçalar arasındaki arayüzler, yanlış anlaşılan gereksinimler ve geç fark edilen tutarsızlıklar olur.</p>

<p>Bu yüzden sistem mühendisliği yatırımını yaşam döngüsünün başına — gereksinimlerin yazıldığı, mimarinin kurulduğu, doğrulama stratejisinin belirlendiği erken aşamalara — yoğunlaştırır. Hata maliyeti grafiğinin acımasız matematiği bunu zorunlu kılar.</p>

<p>İster bir uçak, ister bir otomobil, ister büyük ölçekli bir yazılım platformu geliştiriyor olun, soru hep aynıdır: <em>Parçaların hepsi bir araya geldiğinde gerçekten işe yarayacak mı?</em> Bu sorunun sorumluluğunu üstlenen kişi sistem mühendisidir.</p>

<hr />

<p><strong>Kaynaklar:</strong></p>

<ul>
  <li>INCOSE — <a href="https://www.incose.org/products-and-publications/se-handbook">Systems Engineering Handbook, 5th Edition</a> (Wiley, 2023).</li>
  <li>ISO/IEC/IEEE 15288:2023 — <a href="https://www.iso.org/standard/81702.html">Systems and software engineering — System life cycle processes</a>.</li>
  <li>NASA — <a href="https://www.nasa.gov/reference/systems-engineering-handbook/">Systems Engineering Handbook, NASA/SP-2016-6105 Rev2</a>.</li>
  <li>Barry W. Boehm — <em>Software Engineering Economics</em> (Prentice Hall, 1981).</li>
  <li>SAE International — <a href="https://www.sae.org/standards/content/arp4754b/">ARP4754B: Guidelines for Development of Civil Aircraft and Systems</a> (2023).</li>
  <li>Object Management Group — <a href="https://www.omg.org/spec/SysML/">OMG Systems Modeling Language (SysML)</a>.</li>
  <li>R. H. Thayer — “Software system engineering: a tutorial,” <em>IEEE Computer</em>, vol. 35, no. 4, pp. 68-73, March 2002, DOI: 10.1109/MC.2002.993773.</li>
</ul>]]></content><author><name>M. Serdar Karaman</name></author><category term="muhendislik" /><category term="sistem-muhendisligi" /><category term="aviyonik" /><summary type="html"><![CDATA[Modern bir yolcu uçağında milyonlarca parça, onlarca farklı mühendislik disiplini ve binlerce gereksinim bir arada bulunur. Aerodinamikçi kanadı, yazılımcı uçuş kontrol bilgisayarını, elektronik mühendisi aviyonik veri yolunu, malzeme mühendisi gövde alaşımını tasarlar. Hiçbiri tek başına diğerinin işini bilmek zorunda değildir. Peki bütün bu parçaların birlikte güvenli bir şekilde uçan tek bir uçak oluşturduğundan kim emin olur?]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://karaman.dev/img/og-default.webp" /><media:content medium="image" url="https://karaman.dev/img/og-default.webp" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry xml:lang="tr"><title type="html">Bandpass Sampling: 1 GHz Sinyali 50 MHz Clock ile Örneklemek</title><link href="https://karaman.dev/2026/05/21/bandpass-sampling.html" rel="alternate" type="text/html" title="Bandpass Sampling: 1 GHz Sinyali 50 MHz Clock ile Örneklemek" /><published>2026-05-21T09:00:00+00:00</published><updated>2026-05-21T09:00:00+00:00</updated><id>https://karaman.dev/2026/05/21/bandpass-sampling</id><content type="html" xml:base="https://karaman.dev/2026/05/21/bandpass-sampling.html"><![CDATA[<p>Mühendislik mülakatlarında klasik bir soru vardır: <em>“1090 MHz’deki ADS-B sinyalini sayısal olarak yakalamak istiyorsun. Hangi hızda ADC kullanırsın?”</em></p>

<p>Nyquist–Shannon teoremini hatırlayan herkes refleksle cevaplar: <em>“En az 2.18 GSPS.”</em> Mantıklı görünür: en yüksek frekansın iki katı. Cevap teknik olarak yanlış olmasa da, gerçek hayatta hiçbir ADS-B alıcısı 2 GSPS’lik bir ADC ile çalışmaz. Tipik bir donanım 1090 MHz’i önce bir mixer ile düşük bir IF’e indirir; yeterince temiz bir clock ve geniş analog bantlı bir ADC varsa bu adımı tamamen atlayıp 1090 MHz’in komşuluğundaki <strong>2 MHz</strong> civarındaki dar bandı doğrudan 50 MSPS hatta daha yavaş clock ile örneklemek de mümkündür — ve hiçbir şey kaybolmaz.</p>

<p>Burada işin sırrı <strong>bandpass sampling</strong> (veya <em>IF sampling</em>, <em>undersampling</em>) denilen, klasik örnekleme teoreminin az bilinen kuzenidir. Bu yazıda teoremin geometrisine, izinli/yasak örnekleme oranlarının nasıl ortaya çıktığına, spektral ters çevrilme tuzağına ve modern ADC’lerin neden GHz mertebesinde analog bant genişliği ilan ettiğine inip somut bir Python örneğiyle her şeyi yerine oturtacağız.</p>

<figure>
  <img src="/img/posts/bandpass-sampling-signal.webp" alt="70 MHz IF bandpass sinyali ve 31.25 MSPS örnekleme noktaları" class="img-fluid rounded" />
  <figcaption><strong>Şekil 1.</strong> 70 MHz IF sinyali (67.5 + 72.5 MHz iki ton, mavi) ve 31.25 MSPS örnekleme noktaları (kırmızı). Örnekler arasındaki boşluk T = 32 ns; sinyalin kendi periyodu ise yaklaşık 14 ns — klasik Nyquist açısından yetersiz ama bandpass sampling açısından mükemmel.</figcaption>
</figure>

<hr />

<h2 id="nyquistin-saklı-varsayımı">Nyquist’in Saklı Varsayımı</h2>

<p>Genel anlamıyla Nyquist–Shannon teoremi şunu söyler: bir sinyalin <strong>en yüksek frekans bileşeninin</strong> en az iki katı hızla örneklersen, bilgiyi kaybetmeden geri çevirebilirsin. Bu formülasyondaki gizli varsayım, sinyalin <strong>baseband</strong> (taban bant) olduğudur — yani spektrumun <code class="language-plaintext highlighter-rouge">[0, f_max]</code> aralığında yaşadığını kabul eder.</p>

<p>Oysa modern bir RF alıcısının önündeki sinyaller hiç de böyle değildir. Bir VHF havacılık telsizi <code class="language-plaintext highlighter-rouge">[118, 137]</code> MHz aralığında çalışır; ADS-B 1090 MHz civarında birkaç megahertz’lik bir bantta yaşar; GPS L1 1575.42 MHz taşıyıcısının etrafında C/A kodu için yaklaşık ±1 MHz, P(Y) kodu içinse ±10 MHz mertebesinde bir spektruma sahiptir. Bu sinyallerin ortak özelliği <strong>dar bantlı</strong> olmalarıdır: f_H − f_L değeri f_c değerine kıyasla çok küçüktür. Spektrumun büyük bölümü zaten boş.</p>

<p>Eğer boş alanı saymayı bırakırsak — ki kimse 0 ile f_L arasındaki sessizliği örneklemek için ADC çevirmiyor — gerçek bilgi yükümüz sadece <code class="language-plaintext highlighter-rouge">B = f_H − f_L</code> kadardır. Information-theoretic alt sınır da bu: f_s ≥ 2B yeterli <strong>olmalı</strong>. Tek soru, <em>hangi</em> 2B’nin (ya da 3B’nin, 5B’nin) işe yarayacağıdır.</p>

<hr />

<h2 id="bandpass-sampling-teoremi">Bandpass Sampling Teoremi</h2>

<p>Resmi formülasyonu 1991’de Vaughan, Scott ve White, IEEE Transactions on Signal Processing’de yayınladığı <strong>“The Theory of Bandpass Sampling”</strong> makalesinde verdi (cilt 39, sayı 9, ss. 1973–1984). Teorem şunu söyler:</p>

<p>Spektrumu <code class="language-plaintext highlighter-rouge">[f_L, f_H]</code> aralığında yaşayan, B = f_H − f_L bant genişliğine sahip bir bandpass sinyali, aşağıdaki eşitsizliği sağlayan herhangi bir f_s ile birinci-derece tek-tip örnekleme (uniform first-order sampling) altında geri çevrilebilir biçimde sayısallaştırılabilir:</p>

<p>$$
\frac{2 f_H}{n} \le f_s \le \frac{2 f_L}{n - 1}
$$</p>

<p>burada <code class="language-plaintext highlighter-rouge">n</code>, <code class="language-plaintext highlighter-rouge">1 ≤ n ≤ ⌊f_H / B⌋</code> aralığında bir tamsayıdır.</p>

<p><code class="language-plaintext highlighter-rouge">n = 1</code> aldığımızda eşitsizliğin sağ tarafı tanımsızdır (bölü sıfır); bu, klasik Nyquist durumudur: f_s ≥ 2·f_H. Daha büyük n değerleri, daha düşük örnekleme hızlarına izin verir — <strong>ama tüm aralıklar değil</strong>, sadece belirli aralıklar.</p>

<p>Burada <code class="language-plaintext highlighter-rouge">n</code>, sinyalin sonuçta yerleşeceği <strong>Nyquist bölgesinin</strong> indeksidir. Nyquist bölgesi <code class="language-plaintext highlighter-rouge">n</code>: <code class="language-plaintext highlighter-rouge">[(n−1)·f_s/2, n·f_s/2]</code> aralığını kapsar. Sinyalin tamamı tek bir Nyquist bölgesinin <strong>içine</strong> sığmak zorundadır — bir bölgenin sınırına denk gelirse iki komşu bölgeden alias’lar birbiriyle çakışır ve veri umutsuzca bozulur.</p>

<hr />

<h2 id="sayısal-bir-örnek-70-mhz-if-10-mhz-bant">Sayısal Bir Örnek: 70 MHz IF, 10 MHz Bant</h2>

<p>Klasik bir ara frekans (intermediate frequency, IF) seçimini düşünelim: f_c = 70 MHz, B = 10 MHz, dolayısıyla f_L = 65 MHz, f_H = 75 MHz.</p>

<p>Bu durumda izin verilen n değerleri <code class="language-plaintext highlighter-rouge">1 ≤ n ≤ ⌊75 / 10⌋ = 7</code> aralığındadır. Her n için izinli aralık şudur:</p>

<table>
  <thead>
    <tr>
      <th>n</th>
      <th>f_s_min = 2·f_H / n</th>
      <th>f_s_max = 2·f_L / (n−1)</th>
      <th>Aralık genişliği</th>
      <th>Yerleşeceği bölge</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>1</td>
      <td>150 MSPS</td>
      <td>∞ (üst sınır yok)</td>
      <td>—</td>
      <td>klasik Nyquist</td>
    </tr>
    <tr>
      <td>2</td>
      <td>75 MSPS</td>
      <td>130 MSPS</td>
      <td>55 MSPS</td>
      <td>zone 2 (ters)</td>
    </tr>
    <tr>
      <td>3</td>
      <td>50 MSPS</td>
      <td>65 MSPS</td>
      <td>15 MSPS</td>
      <td>zone 3 (düz)</td>
    </tr>
    <tr>
      <td>4</td>
      <td>37.5 MSPS</td>
      <td>43.33 MSPS</td>
      <td>5.83 MSPS</td>
      <td>zone 4 (ters)</td>
    </tr>
    <tr>
      <td>5</td>
      <td>30 MSPS</td>
      <td>32.5 MSPS</td>
      <td>2.5 MSPS</td>
      <td>zone 5 (düz)</td>
    </tr>
    <tr>
      <td>6</td>
      <td>25 MSPS</td>
      <td>26 MSPS</td>
      <td>1 MSPS</td>
      <td>zone 6 (ters)</td>
    </tr>
    <tr>
      <td>7</td>
      <td>21.43 MSPS</td>
      <td>21.67 MSPS</td>
      <td>0.24 MSPS</td>
      <td>zone 7 (düz)</td>
    </tr>
  </tbody>
</table>

<p>Üç şey hemen göze çarpıyor:</p>

<ol>
  <li><strong>Yasak bölgeler vardır.</strong> Örneğin 43 MSPS ile 50 MSPS arasında <em>hiçbir</em> n çalışmaz. Bu aralıkta sinyal mutlaka iki komşu Nyquist bölgesi arasındaki sınırı keser ve alias’lar çakışır.</li>
  <li><strong>n büyüdükçe izinli aralık daralır.</strong> n = 7’de pencere yalnızca 240 kHz genişliktedir. Clock kaynağınızın drift’i, anti-alias filtresinin roll-off bölgesi, sıcaklık değişimi — hepsi bu dar yarığa sığmak zorundadır. Pratikte n = 7 ile bir tasarım yapmak intihardır.</li>
  <li><strong>Daha düşük hızlara inerken ciddi bir kazanım var.</strong> 75 MSPS yerine 31 MSPS’de çalışan bir ADC seçmek, hem güç tüketimini hem dijital arka uçtaki örnek hızını yarıdan fazla düşürür. Cortex-M tabanlı bir alıcıda bu ciddi bir mimari kazançtır.</li>
</ol>

<p>İyi bir tasarımcı aralığın <strong>ortasında</strong> durur. n = 3 için 50–65 MSPS aralığının ortası ~57.5 MSPS’tir; clock’la 5 MSPS sapsa bile hâlâ izinli bölgenin içindedir.</p>

<hr />

<h2 id="wedge-diyagramı-geometriye-bakmak">Wedge Diyagramı: Geometriye Bakmak</h2>

<p>Bu yasak ve izinli bölgeler bir grafiğe dökülünce ortaya <strong>wedge</strong> (kama) diyagramı çıkar. X ekseninde normalize merkez frekansı <code class="language-plaintext highlighter-rouge">f_c / B</code>, Y ekseninde normalize örnekleme hızı <code class="language-plaintext highlighter-rouge">f_s / B</code> vardır.</p>

<p>İzinli bölgeler, her biri bir n değerine karşılık gelen, üçgen şeklinde “kamalar”dır. Kamaların ortak özelliği:</p>

<ul>
  <li><strong>Üst kenarı</strong> f_s = 2·f_L / (n − 1) doğrusudur.</li>
  <li><strong>Alt kenarı</strong> f_s = 2·f_H / n doğrusudur.</li>
  <li><strong>Sol ucu</strong> noktada (kamanın tepesi) f_s = 2·B’dir — teorik alt sınır.</li>
</ul>

<p>Yasak bölgeler, kamalar arasındaki üçgen “boşluklar”dır. Bir zone sınırının (m·f_s/2) bandın içine düştüğü her f_s yasaktır; bu da f_s ekseninde <code class="language-plaintext highlighter-rouge">[2·f_L/m, 2·f_H/m]</code> aralıklarına — yani kabaca 2·f_c/m noktalarının etrafına — denk gelir. f_s teorik alt sınır 2B’ye yaklaştıkça kamalar daralır ve yasak bölgeler sıklaşır. Bu yüzden “f_s’i 2B’ye çok yakın seçme” sezgisi vardır: tepe noktasının yakınında çalışan bir tasarım için clock drift’inin minik bir parçası dahi sistemi yasak bölgeye sürüklemeye yeter.</p>

<p>Yine de wedge diyagramı sadece bir gözlem aracıdır. Saha tasarımının değişmez kuralı şudur: <strong>bir kamanın iç noktasında dur, kenardan uzak kal.</strong> Vaughan’ın 1991 makalesi bu hassasiyet analizini ayrı bir bölümle ele alır.</p>

<figure>
  <img src="/img/posts/bandpass-sampling-zones.webp" alt="70 MHz IF için izinli ve yasak örnekleme hızları" class="img-fluid rounded" />
  <figcaption><strong>Şekil 2.</strong> 70 MHz IF (65–75 MHz bant) için izinli (mavi/mor) ve yasak (kırmızı) örnekleme hızları. Mavi bölgeler n tek → spektrum düz; mor bölgeler n çift → spektrum ters. Kırmızı aralar hiçbir n için çalışmaz. Dikey çizgiler: n = 5 için kullanılan 31.25 MSPS (lacivert) ve n = 3 için ideal orta nokta ~57.5 MSPS (teal). Teorik alt sınır 2B = 20 MSPS noktalı çizgiyle gösterilmiş.</figcaption>
</figure>

<hr />

<h2 id="spectral-inversion-çift-n-hayatınızı-berbat-eder">Spectral Inversion: Çift n Hayatınızı Berbat Eder</h2>

<p>Bandpass sampling’in en sinsi tuzağı <strong>spektral inversiyon</strong>dur. Sinyalin Nyquist bölgesinin paritesine bağlı olarak baseband’e indiğinde <strong>ters çevrilmiş</strong> olabilir.</p>

<p>Lyons’un <em>Understanding Digital Signal Processing</em> kitabındaki konvansiyonu kullanırsak:</p>

<ul>
  <li><strong>n tek</strong> → spektrum yukarı doğru (“upright”), orijinaliyle aynı yönde.</li>
  <li><strong>n çift</strong> → spektrum <strong>ters çevrilmiş</strong> (zone 1’de f_s/4 etrafında aynalanmış).</li>
</ul>

<table>
  <tbody>
    <tr>
      <td>Hızlı bir mental doğrulama: f_s = 10 Hz, gerçek sinyalin 11.5 ila 12.5 Hz aralığında bir spektrumu olsun. Zone 3’e (n = 3, tek) düşer. Alias:</td>
      <td>12 − 1·10</td>
      <td>= 2 Hz. 12.5 → 2.5, 11.5 → 1.5 — alt-üst sıralama korunur. Üst kenar yine üstte.</td>
    </tr>
  </tbody>
</table>

<p>Şimdi gerçek sinyali 7.5 ila 8.5 Hz arasına koyalım — zone 2 (n = 2, çift). Alias: 8.5 → 1.5, 7.5 → 2.5. Üst kenar artık altta. Ters çevrilmiş.</p>

<p>Bu, simetrik modülasyonlarda (DSB, gerçek değerli BPSK gibi) görünmez bir hatadır — spektrum simetrik olduğu için ters de aynı görünür. Ama <strong>single sideband (SSB), asimetrik PSK, ya da Doppler işareti taşıyan FM</strong> sinyallerinde alıcının demodülatörü tam tersine çalışır. Bandpass sampling tasarımlarında klasik bir bug kaynağıdır ve genelde “neden konuşma anlaşılır ama yön bilgisi tersine” gibi anlamsız belirtilerle kendini gösterir.</p>

<p>Düzeltmesi basit: örnekleri <code class="language-plaintext highlighter-rouge">(−1)^k</code> ile çarpmak ya da downconversion sonrası I/Q kanallarından birinin işaretini çevirmek yeter. Önemli olan, hangi rejimde olduğunuzu <em>bilmektir</em>.</p>

<hr />

<h2 id="adcde-önemli-olan-f_s-değil-analog-bant-genişliğidir">ADC’de Önemli Olan f_s Değil, Analog Bant Genişliğidir</h2>

<p>Bandpass sampling’in pratik mühendisliği burada başlar. Bir ADC’yi 50 MSPS’de örnekleyip 1090 MHz’lik bir sinyal yakalamak istiyorsanız, <strong>ADC’nin analog girişi 1090 MHz’i geçirebilmek zorundadır.</strong></p>

<p>İşte tam burası, Nyquist’i ezbere bilen mühendislerin tökezlediği yerdir. Çoğu kişi ADC datasheet’ine baktığında “100 MSPS” gibi sayısal hıza odaklanır ve <strong>analog input bandwidth</strong> (veya <em>full-power input bandwidth</em>) satırını kaçırır. Halbuki bandpass sampling’in fizibilitesi tamamen o satırla belirlenir.</p>

<p>Üç somut örnek üzerinden bakalım:</p>

<table>
  <thead>
    <tr>
      <th>ADC</th>
      <th>Çözünürlük</th>
      <th>Örnekleme</th>
      <th>Analog BW</th>
      <th>Notlar</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Analog Devices **AD9265**</td>
      <td>16-bit</td>
      <td>125 MSPS</td>
      <td>**650 MHz**</td>
      <td>Datasheet açıkça "IF sampling up to 300 MHz" diyor</td>
    </tr>
    <tr>
      <td>Texas Instruments **ADS5474**</td>
      <td>14-bit</td>
      <td>400 MSPS</td>
      <td>**1.4 GHz**</td>
      <td>400 MHz üzerindeki sinyaller için pazarlanıyor</td>
    </tr>
    <tr>
      <td>Linear Technology **LTC2208**</td>
      <td>16-bit</td>
      <td>130 MSPS</td>
      <td>**700 MHz**</td>
      <td>70 fs RMS aperture jitter, undersampling için satılıyor</td>
    </tr>
  </tbody>
</table>

<p>Bu cihazların ilan ettikleri “Nyquist hızlarının çok üstündeki analog bant genişliği” tesadüf değildir — bandpass sampling pazarı için <strong>kasıtlı olarak</strong> öyle tasarlanmışlardır. Sample-and-hold devresinin RC zaman sabiti, takip kapasitansı, switch açma süresi: hepsi yüzlerce megahertz hatta gigahertz ölçeğinde sinyalin “doğru” anda yakalanmasına izin verecek şekilde optimize edilmiştir.</p>

<p>Bir tasarım kuralı olarak: <strong>f_H &lt; analog BW / 2</strong> koşulu sağlanmadan o ADC bandpass sampling’e uygun değildir. Spec edge’inde çalışmak istemezsiniz.</p>

<hr />

<h2 id="sınırı-belirleyen-aslında-jitter">Sınırı Belirleyen Aslında Jitter</h2>

<p>ADC analog bant genişliği yeterli olsa bile, yüksek IF’te sinyali sınırlandıran başka bir parametre ortaya çıkar: <strong>clock jitter’ı</strong>, yani aperture jitter. Tipik formülü şudur:</p>

<!-- Formüllerde }_{ kalıbından kaçının: kramdown kelime sınırına denk gelen
     alt çizgi çiftini <em> olarak eşleştirip MathJax'ten önce TeX'i bozuyor. -->
<p>$$
\mathrm{SNR_{jitter}} = -20 \log_{10}(2\pi \cdot f_{\text{in}} \cdot \sigma_t)
$$</p>

<p>Burada f_in <strong>analog giriş</strong> frekansıdır (örnekleme hızı değil!) ve σ_t clock kaynağının RMS jitter değeridir. Formülde gizli olan korkutucu gerçek şudur: SNR, sinyal frekansıyla doğrudan azalır. Baseband’de problem olmayan jitter, 1 GHz IF’te uygulamayı imkânsız hale getirebilir.</p>

<p>Somut bir hesap: σ_t = 100 fs (modern bir VCXO için iyi bir değer), f_in = 1 GHz:</p>

<p>$$
\text{SNR} = -20 \log_{10}(2\pi \cdot 10^9 \cdot 10^{-13}) \approx 64 \text{ dB}
$$</p>

<p>64 dB SNR, etkin bit sayısı (ENOB) cinsinden yaklaşık 10.3 bit’e karşılık gelir. Yani 78 dB SNR (≈12.6 ENOB) ilan eden LTC2208’i 1 GHz’de örneklerseniz, jitter tavanı yüzünden <strong>2 etkin bitten fazlasını clock kaynağına kurban etmiş</strong> olursunuz — 16-bit’lik nominal çözünürlüğe göre kayıp 5 bit’i aşar. ADC’nin ilan ettiği 78 dB SNR’ı görmek için çok daha düşük IF’te kalmanız ya da çok daha temiz bir clock (örneğin 10 fs sınıfı bir SAW veya kristal osilatör) kullanmanız gerekir.</p>

<p>Bu yüzden bandpass sampling tasarımlarında clock kaynağı, alıcının LO’su kadar — bazen daha fazla — özen ister. Phase noise spektrumunun, sinyal yakınında −150 dBc/Hz’in altına inebilmesi tipik bir hedeftir.</p>

<hr />

<h2 id="anti-alias-filtresi-artık-bir-bandpass">Anti-Alias Filtresi Artık Bir Bandpass</h2>

<p>Klasik baseband örneklemede anti-alias filtresi bir <strong>alçak geçirendir</strong> (lowpass): f_s/2 üzerindeki her şeyi keser. Bandpass sampling’de ise işin doğası değişir: hedeflediğiniz tek Nyquist bölgesinden <strong>başka her şey</strong> alias olur ve bandın içine düşer.</p>

<p>Yani filtre artık şunu yapmak zorundadır:</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">[f_L, f_H]</code> arasını geçirmek</li>
  <li>Diğer <strong>tüm</strong> Nyquist bölgelerine düşen sinyali ve gürültüyü bastırmak — özellikle DC’den f_L’e kadar olan geniş bant ve f_H’in üstündeki ADC analog BW’sine kadar olan bant.</li>
</ul>

<p>Bunu sağlamak ciddi bir RF filtre tasarımı işidir. SAW (Surface Acoustic Wave) filtreleri, cavity filtreleri ya da seramik filtreler kullanılır. Pasif L-C ile yapmak istediğinizde, gereken yan-bant bastırma seviyesi (60–80 dB) ve gerçek RF uygulamalarındaki dar göreli bant (örneğin 1090 MHz’de 2 MHz, yani B/f_c ≈ %0.2; bu yazıdaki 70 MHz / 10 MHz örneği didaktik olarak geniş tutulmuştur) yüksek-Q kapasitörler ve hassas frekans cevabı ister.</p>

<p>İkinci ve daha önemli nokta: filtre sinyali geçirirken bantlardaki <strong>gürültüyü de geçirir</strong>. Bandpass sampling’de gürültü integration aralığı <code class="language-plaintext highlighter-rouge">f_s/2</code> ile sınırlı değildir — ADC’nin analog BW’sine kadardır. Yani filtreyi geçen 600 MHz’lik geniş bir bant gürültüsü, sinyalle birlikte zone 1’e alias’lanır. Bu, Vaughan’ın 1991 makalesinin önemli bir sonucudur ve sıklıkla göz ardı edilir.</p>

<hr />

<h2 id="python-ile-sayısal-doğrulama">Python ile Sayısal Doğrulama</h2>

<p>Teori güzel, ama her zaman dediğim gibi <em>gözlerinizle görmediğiniz hiçbir şeye güvenmeyin.</em> Aşağıdaki Python kodu 70 MHz IF’teki 10 MHz bant genişlikli bir sinyali üretir, n = 5 için izinli olan 31.25 MSPS’de örnekler ve sonucun zone 1’de doğru yere düştüğünü gösterir.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="n">numpy</span> <span class="k">as</span> <span class="n">np</span>
<span class="kn">import</span> <span class="n">matplotlib.pyplot</span> <span class="k">as</span> <span class="n">plt</span>

<span class="c1"># Sinyal parametreleri
</span><span class="n">f_c</span>    <span class="o">=</span> <span class="mf">70e6</span>        <span class="c1"># taşıyıcı (IF merkezi)
</span><span class="n">B</span>      <span class="o">=</span> <span class="mf">10e6</span>        <span class="c1"># bant genişliği
</span><span class="n">T</span>      <span class="o">=</span> <span class="mf">100e-6</span>      <span class="c1"># toplam süre
</span><span class="n">f_high</span> <span class="o">=</span> <span class="mf">1.0e9</span>       <span class="c1"># "sürekli zaman" benzetimi için yüksek hızda örnekleme
</span><span class="n">t_high</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="nf">arange</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">T</span><span class="p">,</span> <span class="mi">1</span><span class="o">/</span><span class="n">f_high</span><span class="p">)</span>

<span class="c1"># Bandpass sinyali: basitlik için f_c ± B/4 konumunda iki ton
</span><span class="n">x_high</span> <span class="o">=</span> <span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="nf">cos</span><span class="p">(</span><span class="mi">2</span><span class="o">*</span><span class="n">np</span><span class="p">.</span><span class="n">pi</span><span class="o">*</span><span class="p">(</span><span class="n">f_c</span> <span class="o">-</span> <span class="n">B</span><span class="o">/</span><span class="mi">4</span><span class="p">)</span><span class="o">*</span><span class="n">t_high</span><span class="p">)</span>
        <span class="o">+</span> <span class="n">np</span><span class="p">.</span><span class="nf">cos</span><span class="p">(</span><span class="mi">2</span><span class="o">*</span><span class="n">np</span><span class="p">.</span><span class="n">pi</span><span class="o">*</span><span class="p">(</span><span class="n">f_c</span> <span class="o">+</span> <span class="n">B</span><span class="o">/</span><span class="mi">4</span><span class="p">)</span><span class="o">*</span><span class="n">t_high</span><span class="p">))</span>

<span class="c1"># Bandpass sampling: f_s = 31.25 MSPS, n = 5 (izinli aralık [30, 32.5])
</span><span class="n">step</span> <span class="o">=</span> <span class="mi">32</span>                       <span class="c1"># 1.0e9 / 32 = 31.25 MSPS
</span><span class="n">f_s</span>  <span class="o">=</span> <span class="n">f_high</span> <span class="o">/</span> <span class="n">step</span>
<span class="n">x_bp</span> <span class="o">=</span> <span class="n">x_high</span><span class="p">[::</span><span class="n">step</span><span class="p">]</span>

<span class="c1"># FFT
</span><span class="n">N</span>    <span class="o">=</span> <span class="nf">len</span><span class="p">(</span><span class="n">x_bp</span><span class="p">)</span>
<span class="n">X</span>    <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">fft</span><span class="p">.</span><span class="nf">fft</span><span class="p">(</span><span class="n">x_bp</span><span class="p">)</span>
<span class="n">freq</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">fft</span><span class="p">.</span><span class="nf">fftfreq</span><span class="p">(</span><span class="n">N</span><span class="p">,</span> <span class="n">d</span><span class="o">=</span><span class="mi">1</span><span class="o">/</span><span class="n">f_s</span><span class="p">)</span>
<span class="n">mag</span>  <span class="o">=</span> <span class="mi">20</span><span class="o">*</span><span class="n">np</span><span class="p">.</span><span class="nf">log10</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="nf">abs</span><span class="p">(</span><span class="n">X</span><span class="p">)</span> <span class="o">+</span> <span class="mf">1e-12</span><span class="p">)</span>

<span class="c1"># n = 5 tek → upright; kayma miktarı (n-1)/2 · f_s = 2·f_s
</span><span class="n">shift</span> <span class="o">=</span> <span class="p">(</span><span class="mi">5</span> <span class="o">-</span> <span class="mi">1</span><span class="p">)</span> <span class="o">/</span> <span class="mi">2</span> <span class="o">*</span> <span class="n">f_s</span>
<span class="nf">print</span><span class="p">(</span><span class="sh">"</span><span class="s">Beklenen alias tonları (MHz):</span><span class="sh">"</span><span class="p">,</span>
      <span class="nf">sorted</span><span class="p">([(</span><span class="n">f</span> <span class="o">-</span> <span class="n">shift</span><span class="p">)</span> <span class="o">/</span> <span class="mf">1e6</span> <span class="k">for</span> <span class="n">f</span> <span class="ow">in</span> <span class="p">(</span><span class="n">f_c</span> <span class="o">-</span> <span class="n">B</span><span class="o">/</span><span class="mi">4</span><span class="p">,</span> <span class="n">f_c</span> <span class="o">+</span> <span class="n">B</span><span class="o">/</span><span class="mi">4</span><span class="p">)]))</span>

<span class="n">pos</span> <span class="o">=</span> <span class="n">freq</span> <span class="o">&gt;=</span> <span class="mi">0</span>
<span class="n">peaks</span> <span class="o">=</span> <span class="n">freq</span><span class="p">[</span><span class="n">pos</span><span class="p">][</span><span class="n">np</span><span class="p">.</span><span class="nf">argsort</span><span class="p">(</span><span class="n">mag</span><span class="p">[</span><span class="n">pos</span><span class="p">])[</span><span class="o">-</span><span class="mi">2</span><span class="p">:]]</span>
<span class="nf">print</span><span class="p">(</span><span class="sh">"</span><span class="s">Ölçülen alias tonları (MHz):</span><span class="sh">"</span><span class="p">,</span> <span class="nf">sorted</span><span class="p">(</span><span class="n">peaks</span> <span class="o">/</span> <span class="mf">1e6</span><span class="p">))</span>

<span class="n">plt</span><span class="p">.</span><span class="nf">plot</span><span class="p">(</span><span class="n">freq</span><span class="p">[</span><span class="n">pos</span><span class="p">]</span> <span class="o">/</span> <span class="mf">1e6</span><span class="p">,</span> <span class="n">mag</span><span class="p">[</span><span class="n">pos</span><span class="p">])</span>
<span class="n">plt</span><span class="p">.</span><span class="nf">xlabel</span><span class="p">(</span><span class="sh">"</span><span class="s">Frekans (MHz)</span><span class="sh">"</span><span class="p">);</span> <span class="n">plt</span><span class="p">.</span><span class="nf">ylabel</span><span class="p">(</span><span class="sh">"</span><span class="s">Genlik (dB)</span><span class="sh">"</span><span class="p">)</span>
<span class="n">plt</span><span class="p">.</span><span class="nf">title</span><span class="p">(</span><span class="sa">f</span><span class="sh">"</span><span class="s">f_s = </span><span class="si">{</span><span class="n">f_s</span><span class="o">/</span><span class="mf">1e6</span><span class="si">:</span><span class="p">.</span><span class="mi">2</span><span class="n">f</span><span class="si">}</span><span class="s"> MSPS, n = 5 — zone 1 alias</span><span class="sh">'</span><span class="s">ı</span><span class="sh">"</span><span class="p">)</span>
<span class="n">plt</span><span class="p">.</span><span class="nf">grid</span><span class="p">();</span> <span class="n">plt</span><span class="p">.</span><span class="nf">show</span><span class="p">()</span>
</code></pre></div></div>

<p>Çalıştırınca pozitif yarıda <strong>5 MHz ve 10 MHz</strong> civarında iki keskin tepe görmelisiniz. Hesap doğrudan modulodur: n = 5 için kayma miktarı <code class="language-plaintext highlighter-rouge">(n−1)/2 · f_s = 2 · 31.25 = 62.5 MHz</code>; alt ton 67.5 − 62.5 = 5 MHz’e, üst ton 72.5 − 62.5 = 10 MHz’e iner. n tek olduğu için spektrum upright kalır, yani alt-üst sıra korunur.</p>

<figure>
  <img src="/img/posts/bandpass-sampling-fft.webp" alt="Orijinal analog spektrum ve örneklenmiş alias spektrumu karşılaştırması" class="img-fluid rounded" />
  <figcaption><strong>Şekil 3.</strong> <em>Sol:</em> 70 MHz IF sinyalinin orijinal analog spektrumu — tonlar 67.5 MHz ve 72.5 MHz'de. <em>Sağ:</em> 31.25 MSPS örnekleme sonrası zone 1'deki alias spektrumu — aynı tonlar 5 MHz ve 10 MHz'e inmiş, spektrum düz (n = 5 tek). Bilgi kayıpsız: tonlar arasındaki frekans farkı (5 MHz) ve göreli konumları korunuyor.</figcaption>
</figure>

<p>Şimdi denemeye değer bir alıştırma: <code class="language-plaintext highlighter-rouge">step = 29</code> yapın — bu, f_s ≈ 34.48 MSPS demektir ve 65–75 MHz bandı için hiçbir n çalışmaz (n = 5’in tavanı 32.5, n = 4’ün tabanı 37.5 MSPS). Zone 4/5 sınırı (4·f_s/2 ≈ 68.97 MHz) iki tonun tam arasından geçer: 67.5 MHz tonu zone 4’ten (çift → ters), 72.5 MHz tonu zone 5’ten (tek → düz) alias’lanır. Tonlar 1.47 ve 3.53 MHz’e iner; aralarındaki 5 MHz’lik fark korunamaz ve <code class="language-plaintext highlighter-rouge">f − shift</code> formülü alt ton için yanlış sonuç verir. Yasak bölgenin gözlemlenebilir kanıtı budur.</p>

<p>İnce bir nokta: <code class="language-plaintext highlighter-rouge">step = 30</code> (33.33 MSPS) da nominal 65–75 MHz bandı için yasak olmasına rağmen bu demoda spektrumu <em>bozmaz</em> — zone 4/5 sınırı 66.67 MHz, iki tonun da altında kaldığından ikisi de zone 5’te kalır ve tonlar temiz biçimde 0.83 ile 5.83 MHz’e iner. Yasak bölge tanımı sinyal bandının <em>tamamına</em> bakar; iki ayrık tondan oluşan demo sinyalimiz o bandı doldurmadığı için, zone sınırı tonların arasına denk gelmedikçe kaza olmaz. Gerçek bir modüle sinyal bandın tamamını doldurur ve aynı f_s’te geri dönülmez biçimde bozulurdu.</p>

<hr />

<h2 id="etkileşimli-simülatör">Etkileşimli Simülatör</h2>

<p>Aşağıdaki araçla f<sub>c</sub>, B ve f<sub>s</sub> değerlerini değiştirerek alias konumunu ve izinli/yasak bölge sınırlarını anlık görebilirsiniz.</p>

<div class="card my-3" id="bps-demo">
  <div class="card-header py-2"><strong>Bandpass Sampling Simülatörü</strong></div>
  <div class="card-body">
    <div class="form-row mb-2">
      <div class="col-md-4 mb-2">
        <label class="mb-0 small">f<sub>c</sub> (IF merkezi) = <b id="v-fc">70</b> MHz</label>
        <input type="range" class="custom-range" id="sl-fc" min="10" max="400" value="70" step="1" />
      </div>
      <div class="col-md-4 mb-2">
        <label class="mb-0 small">B (bant genişliği) = <b id="v-bw">10</b> MHz</label>
        <input type="range" class="custom-range" id="sl-bw" min="1" max="80" value="10" step="1" />
      </div>
      <div class="col-md-4 mb-2">
        <label class="mb-0 small">f<sub>s</sub> (örnekleme) = <b id="v-fs">31.25</b> MSPS</label>
        <input type="range" class="custom-range" id="sl-fs" min="5" max="300" value="31.25" step="0.25" />
      </div>
    </div>
    <div id="bps-status" class="px-2 py-1 mb-2 rounded small" style="font-family:monospace;min-height:2.2em;"></div>
    <canvas id="bps-canvas" style="width:100%;display:block;border-radius:4px;border:1px solid #dee2e6;"></canvas>
    <p class="text-muted small mt-1 mb-0">Sol: analog spektrum. Sağ: örneklenmiş zone-1 alias'ı. Yasak bölgede iki farklı zone'dan alias çakışır.</p>
  </div>
</div>

<!-- JS extracted to an external file so jekyll-spaceship/kramdown don't
     mangle `[` and `(` characters inside the simulator's source. -->
<script src="/assets/js/posts/bandpass-sampling.js"></script>

<hr />

<h2 id="mühendislik-notları-ve-pratik-tuzaklar">Mühendislik Notları ve Pratik Tuzaklar</h2>

<p>Bandpass sampling’i sahaya çıkarmadan önce kontrol listesi:</p>

<ol>
  <li><strong>Önce f_H’i, sonra f_s’i seç.</strong> Sinyal yüksek bandının ADC’nin analog input BW’sinin yarısını aşmaması ilk koşuldur. Bunu hesaplamadan datasheet’in MSPS satırına bakmak hatalıdır.</li>
  <li><strong>Wedge’in tepe noktasından kaç.</strong> Pratik bir kural: izinli aralığın ortasına denk gelen n’i seç. Eğer ortası çok dar bir kamaya düşüyorsa daha küçük n’e geç.</li>
  <li><strong>Clock’un phase noise’unu RF mühendisliği gibi düşün.</strong> σ_t = 1 ps’lik bir clock, baseband alıcısında lüks; 1 GHz IF’te facia.</li>
  <li><strong>Anti-alias filtresini erken seç.</strong> SAW filtresinin sipariş süresi haftalar olabilir. Sistem mimarisinde yeri belirlenmeden FPGA yazılımına geçmek riskli.</li>
  <li><strong>Spektral inversiyonu cebine yaz.</strong> n çift kullanıyorsan downstream demodülatörün önüne <code class="language-plaintext highlighter-rouge">(-1)^k</code> veya I/Q swap ekle. Test günü “neden tersine konuşuyor?” diye paniklemekten daha ucuza geliyor.</li>
  <li><strong>Gürültü figürünü unutma.</strong> Filtreyi geçen out-of-band gürültü doğrudan baseband’e iner. Aktif önyükselticinin gürültü figürü, geniş analog BW’de etkin gürültüye dönüşür.</li>
  <li><strong>Sıcaklık üzerinden clock drift’ini düşün.</strong> −40 °C’de farklı bir TCXO frekansı, izinli kamadan çıkmana neden olabilir. Tasarım marjı somut olarak hesaplanmalı.</li>
</ol>

<hr />

<h2 id="bandpass-sampling-nerede-kullanılır">Bandpass Sampling Nerede Kullanılır?</h2>

<p>Modern alıcı mimarilerinin büyük kısmı hâlâ analog ön-karıştırıcı (mixer) ile bandı önce baseband’e ya da düşük IF’e indirir, sonra örnekler. Bunun nedeni hem analog BW yeterli ADC’lerin pahalı olması, hem de clock phase noise’unun maliyetli yönetimi.</p>

<p>Ama doğrudan-IF veya doğrudan-RF örnekleme yapan tasarımlar son 10 yılda hızla yayıldı:</p>

<ul>
  <li><strong>AMD/Xilinx Zynq UltraScale+ RFSoC</strong> (ZCU111, ZCU216 değerlendirme kartları) — yongaya entegre GSPS-sınıf doğrudan RF örnekleme ADC ve DAC blokları, FPGA fabric’i içinde sert IP olarak dijital downconverter/upconverter. Birkaç GHz’e ulaşan analog girişlerle, klasik mixer + IF + ADC zincirini tek yonga ile değiştirme amacı taşır.</li>
  <li><strong>Ettus USRP X410</strong> — Zynq RFSoC tabanlı, kanal başına 400 MHz anlık bant genişliği veren doğrudan RF örnekleme platformu.</li>
  <li><strong>Yazılım tanımlı askeri telsizler</strong> ve doğrudan-IF örnekleme yapan üst-uç ölçüm cihazları (modern spektrum analizörleri, vektör sinyal analizörleri).</li>
</ul>

<p>Buna karşılık <strong>PlutoSDR</strong>, <strong>RTL-SDR</strong> gibi popüler hobi/laboratuvar SDR’ler bandpass sampling kullanmaz — bunların hepsinde analog quadrature downconversion yapan tuner yongaları (AD9363, R820T2 vb.) vardır. ADC görece düşük IF’te (RTL-SDR için ~3.57 MHz) çalışır. Bandpass sampling görüldüğü kadar bedava değildir; ödediği bedel, clock ve filtre alt sisteminin yüksek karmaşıklığıdır.</p>

<hr />

<h2 id="sonuç">Sonuç</h2>

<p>Nyquist–Shannon teoremi temel bir doğrudur, ama <strong>“en yüksek frekansın iki katı”</strong> ezberi onu bir nevi karikatürleştirir. Sinyalin baseband değil dar-bantlı olduğu durumda, gerçek alt sınır bilgi yüküdür: f_s ≥ 2B. Bandpass sampling, bu alt sınıra hangi sayısal hilelerle nasıl yaklaşacağımızı söyler.</p>

<p>Pratikte bandpass sampling’i benimseyen tasarımlarda kritik karar üç sayıyla özetlenir: hangi n, hangi ADC analog BW, hangi clock jitter’ı. Bu üç sayıyı doğru yere koyarsanız, gerçekten <strong>1 GHz’lik sinyali 50 MHz clockla örneklemek</strong> mümkündür — ve sahada her gün çalışır. Yanlış yere koyarsanız sistem ya hiç çalışmaz ya da bazen, anlayamadığınız zamanlarda kendi kendine gizemli biçimde bozulur. RF mühendisliğinde her iki son da görülmüştür.</p>

<p>Sonraki yazı için iyi bir devam konusu: bandpass sampling’in çıktısı zone 1’e indikten sonra <strong>dijital downconversion (DDC)</strong> ile I/Q ayrımı nasıl yapılır, ve neden “f_s/4 trick” denilen küçük sihir hem CIC filtresinden hem de NCO’dan tasarruf sağlar. Bu defterimde duruyor.</p>

<hr />

<p><strong>Kaynaklar:</strong></p>

<ul>
  <li>R. G. Vaughan, N. L. Scott, D. R. White — <a href="https://doi.org/10.1109/78.134430">“The Theory of Bandpass Sampling”</a>, IEEE Transactions on Signal Processing, Vol. 39, No. 9, Sept. 1991, pp. 1973–1984.</li>
  <li>Richard G. Lyons — <em>Understanding Digital Signal Processing</em> (3rd ed., Pearson, 2010), Bölüm 2: “Sampling Bandpass Signals” ve “Spectral Inversion in Bandpass Sampling”.</li>
  <li>Walt Kester (Analog Devices) — <a href="https://www.analog.com/media/en/training-seminars/tutorials/MT-007.pdf">MT-007 Tutorial, “Aperture Time, Aperture Jitter, Aperture Delay Time — Removing the Confusion”</a>.</li>
  <li>Walt Kester (ed.) — <a href="https://www.analog.com/en/education/education-library/data-conversion-handbook.html"><em>Analog-Digital Conversion</em></a>, Analog Devices Education Library, 2004.</li>
  <li>Analog Devices — <a href="https://www.analog.com/en/products/ad9265.html">AD9265 datasheet (16-bit, 125 MSPS, 650 MHz analog BW)</a>.</li>
  <li>Texas Instruments — <a href="https://www.ti.com/product/ADS5474">ADS5474 datasheet (14-bit, 400 MSPS, 1.4 GHz analog BW)</a>.</li>
  <li>Analog Devices — <a href="https://www.analog.com/en/products/ltc2208.html">LTC2208 datasheet (16-bit, 130 MSPS, 700 MHz analog BW, 70 fs aperture jitter)</a>.</li>
  <li>AMD/Xilinx — <a href="https://www.amd.com/en/products/adaptive-socs-and-fpgas/soc/zynq-ultrascale-plus-rfsoc.html">Zynq UltraScale+ RFSoC ürün sayfası ve veri sayfaları</a>.</li>
</ul>]]></content><author><name>M. Serdar Karaman</name></author><category term="aviyonik" /><category term="sinyal-isleme" /><category term="aviyonik" /><summary type="html"><![CDATA[Mühendislik mülakatlarında klasik bir soru vardır: “1090 MHz’deki ADS-B sinyalini sayısal olarak yakalamak istiyorsun. Hangi hızda ADC kullanırsın?”]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://karaman.dev/img/og-default.webp" /><media:content medium="image" url="https://karaman.dev/img/og-default.webp" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry xml:lang="tr"><title type="html">Renode ile Zynq7000 Simülasyonu</title><link href="https://karaman.dev/2026/05/14/renode-ile-zynq7000-simulasyonu.html" rel="alternate" type="text/html" title="Renode ile Zynq7000 Simülasyonu" /><published>2026-05-14T09:00:00+00:00</published><updated>2026-05-14T09:00:00+00:00</updated><id>https://karaman.dev/2026/05/14/renode-ile-zynq7000-simulasyonu</id><content type="html" xml:base="https://karaman.dev/2026/05/14/renode-ile-zynq7000-simulasyonu.html"><![CDATA[<p>Gömülü sistem geliştirmenin en yorucu yanlarından biri donanımın kendisidir. FPGA bitstream’leri saatler süren sentez işlemleri gerektirir, geliştirme kartları ekipler arasında paylaşılır, JTAG bağlantıları kopar, sahada hata ayıklamak ise çoğu zaman pratik değildir. Sürekli entegrasyon (CI) altyapısına fiziksel kart bağlamak ayrı bir mühendislik problemidir.</p>

<p>İşte bu noktada <strong>Renode</strong> devreye giriyor. Bu yazıda, Xilinx (artık AMD) <strong>Zynq7000</strong> SoC ailesinin Renode üzerinde nasıl simüle edildiğine, donanım çevre birimleri ile FPGA tarafının nasıl modellendiğine ve bu yaklaşımın hangi avantajları getirdiğine bakacağız.</p>

<hr />

<h2 id="renode-nedir">Renode Nedir?</h2>

<p><a href="https://renode.io">Renode</a>, <a href="https://antmicro.com/">Antmicro</a> tarafından geliştirilen ve <strong>MIT</strong> lisansı ile dağıtılan açık kaynak bir tam-SoC emülatörüdür. QEMU’nun aksine yalnızca CPU emülasyonuna odaklanmaz; çevre birimlerini, sensörleri, ağ arayüzlerini, kablosuz iletişim modüllerini ve hatta birden fazla cihazın aynı anda çalıştığı sistemleri tek bir simülasyon ortamında ele alır.</p>

<p>Renode’un öne çıkan özellikleri:</p>

<ul>
  <li><strong>Geniş platform desteği:</strong> 100’den fazla SoC ve geliştirme kartı (ARM Cortex-M/A, RISC-V, x86, PowerPC)</li>
  <li><strong>Python ile genişletilebilirlik:</strong> Yeni bir çevre birimi, birkaç satırlık bir Python betiği ile eklenebilir</li>
  <li><strong>Deterministik yürütme:</strong> Aynı senaryo her çalıştırıldığında tıpatıp aynı sonucu üretir</li>
  <li><strong>Robot Framework entegrasyonu:</strong> Test otomasyonu doğrudan desteklenir</li>
  <li><strong>Yerleşik GDB sunucusu:</strong> Hata ayıklama için ek araç gerekmez</li>
</ul>

<p>Renode’un QEMU’dan en belirgin farkı, <strong>sistem entegrasyon testlerine</strong> odaklı tasarlanmış olmasıdır. UART çıktısını yakalamak, GPIO durumunu değiştirmek, sensörden değer “enjekte etmek” ya da ağ trafiğini iki sanal cihaz arasında köprülemek gibi işlemler Renode’da birinci sınıf vatandaş muamelesi görür.</p>

<hr />

<h2 id="zynq7000-mimarisine-kısa-bir-bakış">Zynq7000 Mimarisine Kısa Bir Bakış</h2>

<p>Zynq7000, tek bir silikon üzerinde iki dünyayı birleştirir:</p>

<ul>
  <li><strong>PS (Processing System):</strong> Çift çekirdekli <strong>ARM Cortex-A9</strong> (1 GHz’e kadar, parça hızına göre), NEON SIMD birimi, donanımsal FPU, L1/L2 önbellek, DDR3 denetleyicisi ve sabit çevre birimleri (UART, SPI, I2C, GPIO, USB, Gigabit Ethernet, SD/MMC).</li>
  <li><strong>PL (Programmable Logic):</strong> Artix-7 ya da Kintex-7 ailesinden bir <strong>FPGA dokusu</strong>; geliştiricinin kendi IP bloklarını, hızlandırıcılarını veya özel arayüzlerini sentezlediği alandır.</li>
  <li><strong>AXI Interconnect:</strong> PS ile PL arasındaki yüksek bant genişlikli köprüdür. AXI3 / AXI4 protokolü üzerinden General-Purpose (GP), High-Performance (HP) ve Accelerator Coherency Port (ACP) bağlantılarını sunar.</li>
</ul>

<p>PS tarafı, donanım üreticisi tarafından sabitlenmiş bir mikrodenetleyiciye benzer. PL tarafı ise tamamen sizin elinizdedir; bitstream ile yeniden programlayabilirsiniz. Renode’un bu iki dünyayı simüle ederken nasıl ele aldığı, yazının kalbini oluşturuyor.</p>

<div class="mermaid">
graph TB
    subgraph PS[Processing System - PS]
        CPU0[Cortex-A9 #0]
        CPU1[Cortex-A9 #1]
        GIC[GIC Interrupt Controller]
        UART[PS7_UART]
        GPIO[PS7_GPIO]
        TIMER[Triple Timer Counter]
        DDR[DDR3 Controller]
    end
    subgraph PL[Programmable Logic - PL / FPGA]
        IP1[Özel IP Bloğu]
        IP2[AXI Slave Peripheral]
        IP3[DMA Hızlandırıcı]
    end
    AXI{AXI Interconnect}
    CPU0 --&gt; AXI
    CPU1 --&gt; AXI
    UART --&gt; GIC
    GPIO --&gt; GIC
    TIMER --&gt; GIC
    AXI --&gt; IP1
    AXI --&gt; IP2
    AXI --&gt; IP3
</div>

<hr />

<h2 id="kurulum">Kurulum</h2>

<p>Renode’u edinmenin birkaç yolu vardır. Linux üzerinde en hızlı yol resmi paket deposunu kullanmaktır:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Ubuntu / Debian</span>
wget https://github.com/renode/renode/releases/latest/download/renode_latest.deb
<span class="nb">sudo </span>apt <span class="nb">install</span> ./renode_latest.deb

<span class="c"># Çalıştır</span>
renode
</code></pre></div></div>

<p>Docker tercih edenler için resmi imaj da mevcuttur:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>docker run <span class="nt">-it</span> <span class="nt">--rm</span> antmicro/renode:latest
</code></pre></div></div>

<p>Kaynaktan derlemek isteyenler <code class="language-plaintext highlighter-rouge">dotnet</code> SDK 8.0 ile depoyu çekip <code class="language-plaintext highlighter-rouge">build.sh</code> betiğini çalıştırabilir. macOS ve Windows için de hazır paketler mevcuttur.</p>

<p>Kurulum doğrulaması basittir: <code class="language-plaintext highlighter-rouge">renode</code> komutu sizi <code class="language-plaintext highlighter-rouge">(monitor)</code> istemi ile karşılayacaktır.</p>

<hr />

<h2 id="i̇lk-simülasyon-resc-senaryo-dosyası">İlk Simülasyon: .resc Senaryo Dosyası</h2>

<p>Renode iki tür dosya kullanır:</p>

<ul>
  <li><strong><code class="language-plaintext highlighter-rouge">.repl</code></strong> (Renode Platform) — Platformun tanımı: hangi çevre birimleri hangi adreslerde, hangi IRQ’lara bağlı.</li>
  <li><strong><code class="language-plaintext highlighter-rouge">.resc</code></strong> (Renode Script) — Senaryo: hangi platformu yükle, hangi firmware’i çalıştır, hangi pencereleri aç.</li>
</ul>

<p>Renode kurulumu, Zynq tabanlı popüler kartlar için hazır platform dosyaları içerir. Örneğin <strong>ZedBoard</strong> için tipik bir senaryo şöyle görünür:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>:name: ZedBoard ile Zynq7000 Simulasyonu
:description: Zynq7000 uzerinde bare-metal firmware

mach create "zedboard"
machine LoadPlatformDescription @platforms/boards/zedboard.repl

# UART cikti penceresini ac
showAnalyzer sysbus.uart1

# Firmware'i yukle
sysbus LoadELF @firmware.elf

# CPU0'i belirli bir adresten baslat
cpu0 PC 0x00100000

start
</code></pre></div></div>

<p>Bu senaryoyu <code class="language-plaintext highlighter-rouge">renode boot.resc</code> ile çalıştırdığınızda yeni bir pencere açılır ve UART çıktısı orada akmaya başlar. <code class="language-plaintext highlighter-rouge">pause</code>, <code class="language-plaintext highlighter-rouge">step</code>, <code class="language-plaintext highlighter-rouge">start</code> komutlarıyla zamanı tamamen kontrol edebilirsiniz: simülasyonu istediğiniz anda dondurabilir, talimatları tek tek ilerletebilir veya gerçek zamandan kat kat hızlı çalıştırabilirsiniz.</p>

<hr />

<h2 id="platform-tanımı-repl-dosyaları">Platform Tanımı: .repl Dosyaları</h2>

<p>Bir <code class="language-plaintext highlighter-rouge">.repl</code> dosyası, platformun adres haritasını, kesme bağlantılarını ve reset değerlerini tanımlar. ZedBoard platformunun küçük bir parçası:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>gic: IRQControllers.ARM_GenericInterruptController @ {
        sysbus new Bus.BusMultiRegistration { address: 0xF8F01000; size: 0x1000; region: "distributor" };
        sysbus new Bus.BusMultiRegistration { address: 0xF8F00100; size: 0x100; region: "cpuInterface" }
    }
    [0-1] -&gt; cpu0@[0-1]

uart1: UART.Cadence_UART @ sysbus 0xE0001000
    -&gt; gic@50

gpio: GPIOPort.XilinxGPIOPS @ sysbus 0xE000A000
    IRQ -&gt; gic@52

ttc0: Timers.Cadence_TTC @ sysbus 0xF8001000
    [0-2] -&gt; gic@[10-12]
</code></pre></div></div>

<p>Burada <code class="language-plaintext highlighter-rouge">Cadence_UART</code>, <code class="language-plaintext highlighter-rouge">XilinxGPIOPS</code> gibi tip adları, Renode içinde hazır olarak gelen çevre birimi modellerine karşılık gelir. Adres alanı (<code class="language-plaintext highlighter-rouge">0xE0001000</code>), reset davranışı ve IRQ numarası, fiziksel Zynq7000 ile birebir eşleşir. Bu sayede aynı sürücü kodu, hem Renode’da hem de gerçek kartta değişiklik gerektirmeden çalışır.</p>

<p>İhtiyacınız olan bir çevre birimi platformda yoksa iki seçeneğiniz var: kendi <code class="language-plaintext highlighter-rouge">.repl</code> dosyanızı baştan yazmak, ya da mevcut olanı <code class="language-plaintext highlighter-rouge">using</code> ile dahil edip üzerine ekleme yapmak.</p>

<hr />

<h2 id="donanım-çevre-birimlerinin-simülasyonu">Donanım Çevre Birimlerinin Simülasyonu</h2>

<p>Renode, çevre birimlerini <strong>kayıt davranış seviyesinde</strong> (register-transaction-level) modeller. Cycle-accurate değildir; yani saat döngüsü hassasiyetinde zamanlama yapmaz. Bunun yerine, yazılımın gördüğü her şeyin doğru olmasına odaklanır: aynı register adresleri, aynı bit alanları, aynı IRQ tetikleme davranışı, aynı protokol durum makineleri.</p>

<p>Zynq7000 için yerleşik olarak modellenen başlıca çevre birimler:</p>

<ul>
  <li><strong>UART (PS7_UART / Cadence_UART)</strong> — Tam fonksiyonel; FIFO seviyesi, baud rate, IRQ davranışı</li>
  <li><strong>GIC (Generic Interrupt Controller)</strong> — ARM PrimeCell standart GIC modeli</li>
  <li><strong>TTC (Triple Timer Counter)</strong> — Üç bağımsız 16-bit sayaç</li>
  <li><strong>GPIO (XilinxGPIOPS)</strong> — 4 banka, MIO ve EMIO pinleri</li>
  <li><strong>I2C, SPI</strong> — Cadence master/slave denetleyicileri</li>
  <li><strong>DMA, Ethernet (GEM), SD/MMC</strong> — Temel düzeyde modellenmiştir</li>
</ul>

<p>Eksik bir çevre birimi varsa, <strong>Python ile birkaç satırda</strong> basit bir model yazılabilir. Renode’un <code class="language-plaintext highlighter-rouge">PythonPeripheral</code> sınıfı, harici <code class="language-plaintext highlighter-rouge">.py</code> dosyalarını doğrudan çevre birimi olarak yükler. Önce platforma yeni cihazı ekleriz:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>my_sensor: Python.PythonPeripheral @ sysbus 0x43C00000
    size: 0x100
    initable: true
    filename: "@scripts/my_sensor.py"
</code></pre></div></div>

<p>Sonra Python betiğini yazarız. Her bus erişiminde <code class="language-plaintext highlighter-rouge">request</code> nesnesi otomatik olarak sağlanır:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># my_sensor.py
</span><span class="k">if</span> <span class="n">request</span><span class="p">.</span><span class="n">IsInit</span><span class="p">:</span>
    <span class="n">sensor_value</span> <span class="o">=</span> <span class="mi">0</span>

<span class="k">elif</span> <span class="n">request</span><span class="p">.</span><span class="n">IsRead</span><span class="p">:</span>
    <span class="k">if</span> <span class="n">request</span><span class="p">.</span><span class="n">Offset</span> <span class="o">==</span> <span class="mh">0x00</span><span class="p">:</span>
        <span class="n">request</span><span class="p">.</span><span class="n">Value</span> <span class="o">=</span> <span class="n">sensor_value</span>      <span class="c1"># sicaklik degeri
</span>    <span class="k">elif</span> <span class="n">request</span><span class="p">.</span><span class="n">Offset</span> <span class="o">==</span> <span class="mh">0x04</span><span class="p">:</span>
        <span class="n">request</span><span class="p">.</span><span class="n">Value</span> <span class="o">=</span> <span class="mh">0x0001</span>            <span class="c1"># durum bayragi: hazir
</span>
<span class="k">elif</span> <span class="n">request</span><span class="p">.</span><span class="n">IsWrite</span><span class="p">:</span>
    <span class="k">if</span> <span class="n">request</span><span class="p">.</span><span class="n">Offset</span> <span class="o">==</span> <span class="mh">0x08</span><span class="p">:</span>
        <span class="n">sensor_value</span> <span class="o">=</span> <span class="n">request</span><span class="p">.</span><span class="n">Value</span>      <span class="c1"># firmware kalibrasyon yazabilir
</span></code></pre></div></div>

<p>Hepsi bu kadar — sınıf, kalıtım ya da derleme adımı yok. Renode konsolundan simülasyon sırasında <code class="language-plaintext highlighter-rouge">sysbus.my_sensor WriteDoubleWord 0x08 42</code> yazarak sensör değerini değiştirebilirsiniz; firmware tam o anda farklı bir koda dallanır. Bu, <strong>fault injection</strong> testleri için son derece güçlü bir araçtır.</p>

<hr />

<h2 id="uartı-tcpye-bağlamak">UART’ı TCP’ye Bağlamak</h2>

<p>Renode’un en pratik özelliklerinden biri, sanal UART’ları <strong>TCP soketleri</strong> olarak dışa açabilmesidir. Bu sayede ekransız ortamlarda (CI sunucuları, Docker konteynerleri, uzak makineler) simülasyonu çalıştırıp <code class="language-plaintext highlighter-rouge">telnet</code>, <code class="language-plaintext highlighter-rouge">netcat</code> ya da kendi test betiğinizle bağlanabilirsiniz.</p>

<p>Renode tarafında iki komut yeter:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>emulation CreateServerSocketTerminal 3456 "uart_term"
connector Connect sysbus.uart1 uart_term
start
</code></pre></div></div>

<p>İlk komut 3456 portunda bir TCP sunucusu açar, ikincisi sanal UART’ı bu sokete bağlar. Artık başka bir terminalden bağlanabilirsiniz:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>telnet localhost 3456
Trying 127.0.0.1...
Connected to localhost.
Boot tamamlandi
Sensor degeri: 42
<span class="o">&gt;</span> <span class="nb">help
</span>Komutlar: status, reset, dump
</code></pre></div></div>

<p>Klavyeden yazdığınız her karakter firmware’in UART RX FIFO’suna düşer; firmware’in TX FIFO’suna yazdığı her karakter terminale akar. Tıpkı gerçek bir kart gibi.</p>

<p>Bu, <strong>otomatik testleri Python ile yazmanın</strong> en temiz yoludur. Pexpect ya da düz <code class="language-plaintext highlighter-rouge">socket</code>:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="n">socket</span>

<span class="n">s</span> <span class="o">=</span> <span class="n">socket</span><span class="p">.</span><span class="nf">socket</span><span class="p">(</span><span class="n">socket</span><span class="p">.</span><span class="n">AF_INET</span><span class="p">,</span> <span class="n">socket</span><span class="p">.</span><span class="n">SOCK_STREAM</span><span class="p">)</span>
<span class="n">s</span><span class="p">.</span><span class="nf">connect</span><span class="p">((</span><span class="sh">"</span><span class="s">localhost</span><span class="sh">"</span><span class="p">,</span> <span class="mi">3456</span><span class="p">))</span>

<span class="c1"># Boot tamamlanmasini bekle
</span><span class="n">buf</span> <span class="o">=</span> <span class="sa">b</span><span class="sh">""</span>
<span class="k">while</span> <span class="sa">b</span><span class="sh">"</span><span class="s">Boot tamamlandi</span><span class="sh">"</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">buf</span><span class="p">:</span>
    <span class="n">buf</span> <span class="o">+=</span> <span class="n">s</span><span class="p">.</span><span class="nf">recv</span><span class="p">(</span><span class="mi">4096</span><span class="p">)</span>

<span class="c1"># Komut gonder, cevabi yakala
</span><span class="n">s</span><span class="p">.</span><span class="nf">sendall</span><span class="p">(</span><span class="sa">b</span><span class="sh">"</span><span class="s">sensor read</span><span class="se">\n</span><span class="sh">"</span><span class="p">)</span>
<span class="n">buf</span> <span class="o">=</span> <span class="sa">b</span><span class="sh">""</span>
<span class="k">while</span> <span class="sa">b</span><span class="sh">"</span><span class="se">\n</span><span class="sh">"</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">buf</span><span class="p">:</span>
    <span class="n">buf</span> <span class="o">+=</span> <span class="n">s</span><span class="p">.</span><span class="nf">recv</span><span class="p">(</span><span class="mi">4096</span><span class="p">)</span>

<span class="nf">print</span><span class="p">(</span><span class="sh">"</span><span class="s">Firmware cevabi:</span><span class="sh">"</span><span class="p">,</span> <span class="n">buf</span><span class="p">.</span><span class="nf">decode</span><span class="p">().</span><span class="nf">strip</span><span class="p">())</span>
<span class="n">s</span><span class="p">.</span><span class="nf">close</span><span class="p">()</span>
</code></pre></div></div>

<p>Birden fazla UART’ı aynı anda farklı portlardan dışa açabilirsiniz — örneğin debug UART’ı 3456, telemetri UART’ı 3457 portundan. Aynı simülasyona iki ayrı Python istemcisi, iki ayrı porttan bağlanır.</p>

<p>Ek olarak UART’ı dosyaya yazdırmak da mümkündür:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sysbus.uart1 CreateFileBackend @uart.log true
</code></pre></div></div>

<p>CI’da test başarısız olduğunda bu log dosyası paha biçilmezdir.</p>

<hr />

<h2 id="fpga--pl-tarafı-nasıl-simüle-edilir">FPGA / PL Tarafı Nasıl Simüle Edilir?</h2>

<p>Renode’un en sık sorulan sorularından biri: “Peki ya FPGA?” Renode kendi başına Verilog ya da VHDL kodunu yorumlamaz. PL tarafını ele almak için iki yaygın yaklaşım vardır:</p>

<h3 id="a-python-peripheral-tlm-modeli">a) Python Peripheral (TLM Modeli)</h3>

<p>FPGA’da yapılacak işin <strong>davranışsal modelini</strong> Python ile yazarsınız. Renode peripheral’ları <strong>register-transaction seviyesinde</strong> (TLM) modellendiği için AXI handshake’i, burst transfer’leri ve back-pressure gibi protokol detayları Renode tarafından soyutlanır; sizin kodunuz yalnızca register okuma/yazma çağrılarına yanıt verir. Bu yaklaşımda RTL test edilmez, ancak yazılım entegrasyonu sorunsuz ilerler.</p>

<p>Yukarıdaki <code class="language-plaintext highlighter-rouge">my_sensor.py</code> basit bir sensör modeliydi. PL tarafında daha tipik bir şey de — örneğin yazılan veriyi sayıp hazır bayrağı tutan minimal bir AXI slave — aynı yapıyla yazılır:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># axi_fifo.py - Yazilanlari sayan basit AXI slave
</span><span class="k">if</span> <span class="n">request</span><span class="p">.</span><span class="n">IsInit</span><span class="p">:</span>
    <span class="n">write_count</span> <span class="o">=</span> <span class="mi">0</span>
    <span class="n">last_data</span> <span class="o">=</span> <span class="mi">0</span>

<span class="k">elif</span> <span class="n">request</span><span class="p">.</span><span class="n">IsRead</span><span class="p">:</span>
    <span class="k">if</span> <span class="n">request</span><span class="p">.</span><span class="n">Offset</span> <span class="o">==</span> <span class="mh">0x00</span><span class="p">:</span>
        <span class="n">request</span><span class="p">.</span><span class="n">Value</span> <span class="o">=</span> <span class="mh">0xDEADBEEF</span>       <span class="c1"># IP ID register
</span>    <span class="k">elif</span> <span class="n">request</span><span class="p">.</span><span class="n">Offset</span> <span class="o">==</span> <span class="mh">0x04</span><span class="p">:</span>
        <span class="n">request</span><span class="p">.</span><span class="n">Value</span> <span class="o">=</span> <span class="n">write_count</span>      <span class="c1"># kac kez yazildi
</span>    <span class="k">elif</span> <span class="n">request</span><span class="p">.</span><span class="n">Offset</span> <span class="o">==</span> <span class="mh">0x08</span><span class="p">:</span>
        <span class="n">request</span><span class="p">.</span><span class="n">Value</span> <span class="o">=</span> <span class="n">last_data</span>        <span class="c1"># son yazilan veri
</span>
<span class="k">elif</span> <span class="n">request</span><span class="p">.</span><span class="n">IsWrite</span><span class="p">:</span>
    <span class="k">if</span> <span class="n">request</span><span class="p">.</span><span class="n">Offset</span> <span class="o">==</span> <span class="mh">0x08</span><span class="p">:</span>
        <span class="n">last_data</span> <span class="o">=</span> <span class="n">request</span><span class="p">.</span><span class="n">Value</span>
        <span class="n">write_count</span> <span class="o">+=</span> <span class="mi">1</span>
</code></pre></div></div>

<p>Bu kadar küçük bir model bile sürücü geliştirmek ve yazılım entegrasyonunu test etmek için yeterlidir.</p>

<p><strong>Ne zaman uygun?</strong> Henüz HDL yazılmamışken yazılımın ilerlemesi gerektiğinde, PoC ve erken aşama firmware geliştirmede ve fault injection senaryolarını hızla kurmak istediğinizde.</p>

<h3 id="b-verilator-co-simülasyon">b) Verilator Co-simülasyon</h3>

<p>Renode, <strong>Verilator</strong> ile sıkı entegrasyona sahiptir. HDL kaynak dosyaları Verilator ile C++’a derlenir; ortaya çıkan paylaşılan kütüphane Renode’a bağlanır. Renode’un AXI işlemleri (read/write transaction’lar) bu köprü üzerinden Verilator’a iletilir, Verilator yanıtı geri döner. PL bloğunuz <strong>gerçek RTL</strong> ile test edilmiş olur.</p>

<p>Önce <code class="language-plaintext highlighter-rouge">.repl</code> dosyasında co-simüle edilecek peripheral’ı tanımlarız:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>my_axi_ip: CoSimulated.CoSimulatedPeripheral @ sysbus &lt;0x43C00000, +0x1000&gt;
    frequency: 100000000
</code></pre></div></div>

<p>Sonra <code class="language-plaintext highlighter-rouge">.resc</code> betiğinde Verilator çıktısı paylaşımlı kütüphaneyi bağlarız:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sysbus.my_axi_ip SimulationFilePath @libVtop.so
</code></pre></div></div>

<p>Bundan sonra firmware’in <code class="language-plaintext highlighter-rouge">0x43C00000</code> adresine yaptığı her AXI okuma/yazma, Verilator simülasyonuna iletilir; RTL’in yanıtı geri döner.</p>

<p><strong>Ne zaman uygun?</strong> PL bloğunuzun RTL doğrulamasını da sistem testine dahil etmek istediğinizde. Saf RTL simülasyonuna kıyasla yavaş kalsa da, yazılım sürücüleriyle birlikte uçtan uca test imkânı sağlar.</p>

<h3 id="i̇ki-yaklaşımın-karşılaştırması">İki Yaklaşımın Karşılaştırması</h3>

<table>
  <thead>
    <tr>
      <th>Yaklaşım</th>
      <th>Hız</th>
      <th>Gerçekçilik</th>
      <th>Kurulum Zorluğu</th>
      <th>RTL Testi</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Python peripheral</td>
      <td>Çok yüksek</td>
      <td>TLM seviyesi</td>
      <td>Çok kolay</td>
      <td>Hayır</td>
    </tr>
    <tr>
      <td>Verilator co-sim</td>
      <td>Düşük</td>
      <td>Cycle-accurate</td>
      <td>Yüksek</td>
      <td>Evet</td>
    </tr>
  </tbody>
</table>

<p>Pratikte ekipler bu iki yaklaşımı <strong>birlikte</strong> kullanır: yazılım ekibi Python peripheral ile hızlıca ilerler, RTL hazır olduğunda Verilator co-simülasyonuna geçilir.</p>

<hr />

<h2 id="hata-ayıklama-gdb-ile-bağlanmak">Hata Ayıklama: GDB ile Bağlanmak</h2>

<p>Renode, her sanal CPU için <strong>GDB Remote Serial Protocol</strong> sunucusu açabilir. Bu, fiziksel JTAG bağlantısının yerine geçer; üstelik çok daha hızlıdır ve sorun çıkarmaz. Kablosu kopmaz, hedef “wedge” olmaz, sürücü çakışması yaşanmaz.</p>

<p>Renode tarafında:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>machine StartGdbServer 3333
</code></pre></div></div>

<p>Başka terminalde:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>arm-none-eabi-gdb firmware.elf
<span class="o">(</span>gdb<span class="o">)</span> target remote :3333
<span class="o">(</span>gdb<span class="o">)</span> b main
Breakpoint 1 at 0x100040
<span class="o">(</span>gdb<span class="o">)</span> c
Continuing.
Breakpoint 1, main <span class="o">()</span> at main.c:42

<span class="o">(</span>gdb<span class="o">)</span> info registers
r0   0x00000000
r1   0xe0001000
...
<span class="o">(</span>gdb<span class="o">)</span> x/16wx 0xE0001000   <span class="c"># UART register'larini incele</span>
</code></pre></div></div>

<p>Tüm standart GDB özellikleri çalışır:</p>

<ul>
  <li><strong>Breakpoint, watchpoint, conditional break:</strong> Hardware watchpoint sayısı simülasyonda sınırsızdır</li>
  <li><strong>Stack trace, frame inspection:</strong> Tam debug bilgisi varsa kaynak satırına kadar</li>
  <li><strong>Memory read/write:</strong> Aktif simülasyonda istediğiniz adresi okuyup yazabilirsiniz</li>
  <li><strong>Source-level stepping:</strong> <code class="language-plaintext highlighter-rouge">step</code>, <code class="language-plaintext highlighter-rouge">next</code>, <code class="language-plaintext highlighter-rouge">finish</code></li>
</ul>

<p>Bir watchpoint örneği — GPIO data register’ı her değiştiğinde dur:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>(gdb) watch *(uint32_t*)0xE000A040
Hardware watchpoint 1: *(unsigned int*)0xE000A040
(gdb) c
Hardware watchpoint 1: *(unsigned int*)0xE000A040
Old value = 0
New value = 1
</code></pre></div></div>

<p><strong>Time-travel hata ayıklama:</strong> Renode deterministik olduğu için, hatadan önce snapshot alıp koşumu tamamlayabilir, sonra snapshot’ı yeniden yükleyip farklı bir yol deneyebilirsiniz. Heisenbug avına alışkın olanlar için bu çok değerli bir yetenektir.</p>

<h3 id="reverse-debugging--geri-adım-atmak">Reverse Debugging — Geri Adım Atmak</h3>

<p>Renode’un belki de en az bilinen yeteneklerinden biri <strong>GDB reverse execution</strong> desteğidir. Yani simülasyonu sadece duraklatmakla kalmaz, <strong>geriye doğru</strong> da çalıştırabilirsiniz.</p>

<p>Açmak için, GDB bağlanmadan önce Renode tarafında tek satırlık bir ayar yeterlidir:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>machine StartGdbServer 3333
reverseExecMode true
</code></pre></div></div>

<p>Sonra GDB’de standart “reverse” komutları çalışır:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>(gdb) target remote :3333
(gdb) b main
(gdb) c
Breakpoint 1, main () at main.c:42

(gdb) n                # 5 satir ileri git
(gdb) n
(gdb) n
(gdb) n
(gdb) n

(gdb) reverse-step     # bir satir geri (rs kisaltmasi)
(gdb) reverse-stepi    # bir assembly instruction geri (rsi)
(gdb) reverse-continue # son breakpoint'e ya da ilk snapshot'a kadar geri
(gdb) rsi 50           # 50 instruction geri
</code></pre></div></div>

<p>Mekanizma snapshot tabanlıdır: Renode arka planda periyodik state snapshot’ları alır; reverse komutları, en yakın snapshot’a dönüp oradan tekrar ileri koşturarak istenen noktaya ulaşır. Bu yüzden:</p>

<ul>
  <li>Reverse hız olarak forward’dan yavaş çalışır</li>
  <li>Snapshot sıklığı performans/granülerlik dengesini belirler</li>
  <li><strong>Tek çekirdek (single-core) emülasyonlarda</strong> desteklenir; çift Cortex-A9’lu Zynq7000’de bu özelliği kullanmak isterseniz SMP yerine yalnızca tek CPU başlatan bir senaryo kurmanız gerekir</li>
</ul>

<p><strong>Pratik değer:</strong> Diyelim ki zor yeniden üretilen bir hata yakaladınız. Kritik anı geçtikten sonra, bir register’ın yanlış değer aldığını fark ettiniz. Forward debugging’de tüm koşumu sıfırdan başlatıp doğru noktada durmaya çalışırsınız. Reverse ile bulunduğunuz noktadan <strong>geriye doğru</strong> giderek ilk yanlış adımı bulursunuz — çoğu zaman dakikalar yerine saniyeler içinde.</p>

<p>VS Code, CLion, Eclipse’in GDB entegrasyonu doğrudan çalışır. Tipik bir <code class="language-plaintext highlighter-rouge">launch.json</code>:</p>

<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span><span class="w">
    </span><span class="nl">"type"</span><span class="p">:</span><span class="w"> </span><span class="s2">"cppdbg"</span><span class="p">,</span><span class="w">
    </span><span class="nl">"request"</span><span class="p">:</span><span class="w"> </span><span class="s2">"launch"</span><span class="p">,</span><span class="w">
    </span><span class="nl">"program"</span><span class="p">:</span><span class="w"> </span><span class="s2">"${workspaceFolder}/build/firmware.elf"</span><span class="p">,</span><span class="w">
    </span><span class="nl">"miDebuggerServerAddress"</span><span class="p">:</span><span class="w"> </span><span class="s2">"localhost:3333"</span><span class="p">,</span><span class="w">
    </span><span class="nl">"miDebuggerPath"</span><span class="p">:</span><span class="w"> </span><span class="s2">"/usr/bin/arm-none-eabi-gdb"</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>

<p>Tek değişiklik şudur: gerçek board için kullanılan OpenOCD adresinin yerine Renode portu yazılır. Geri kalan tüm IDE deneyimi aynıdır.</p>

<hr />

<h2 id="hooklar-renodeun-süper-gücü">Hook’lar: Renode’un Süper Gücü</h2>

<p>Hook’lar, simülasyon sırasında belirli olaylara <strong>Python callback</strong> bağlamanın yoludur. Renode’u QEMU’dan ya da basit bir emülatörden ayıran en güçlü özellik budur. Hook’lar sayesinde, gerçek donanımda asla erişemeyeceğiniz iç durumlara müdahale edebilirsiniz.</p>

<h3 id="adres-tabanlı-watchpoint-hook">Adres tabanlı (watchpoint) hook</h3>

<p>Belirli bir adrese yapılan her yazmayı yakalayalım:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sysbus AddWatchpointHook 0xE000A040 DoubleWord Write "print('GPIO yazildi: ' + hex(value))"
</code></pre></div></div>

<p>Parametreler: adres, genişlik (<code class="language-plaintext highlighter-rouge">Byte</code> / <code class="language-plaintext highlighter-rouge">Word</code> / <code class="language-plaintext highlighter-rouge">DoubleWord</code> / <code class="language-plaintext highlighter-rouge">QuadWord</code> ya da numerik <code class="language-plaintext highlighter-rouge">1</code>/<code class="language-plaintext highlighter-rouge">2</code>/<code class="language-plaintext highlighter-rouge">4</code>/<code class="language-plaintext highlighter-rouge">8</code>), erişim modu (<code class="language-plaintext highlighter-rouge">Read</code> / <code class="language-plaintext highlighter-rouge">Write</code> / <code class="language-plaintext highlighter-rouge">ReadWrite</code>), Python ifadesi. Firmware bu register’a her yazdığında ekrana satır basılır. Bu yöntemle protokol trace’i çıkarmak, fiziksel donanımda son derece zordur.</p>

<h3 id="fonksiyon-başı-hook">Fonksiyon başı hook</h3>

<p>Bir sembole varıldığında çalışacak callback’i kurmak için <code class="language-plaintext highlighter-rouge">AddSymbolHook</code> kullanılır; komut sembolün adresini otomatik olarak çözer:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>cpu0 AddSymbolHook "panic" "print('PANIC! PC=' + hex(pc))"
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">panic</code> fonksiyonu çağrıldığında log basılır — ya da <code class="language-plaintext highlighter-rouge">machine Pause</code> ile simülasyonu durdurursunuz. Hata yakalama için idealdir.</p>

<h3 id="fault-injection-hook">Fault injection hook</h3>

<p>Diyelim ki SPI flash okuma fonksiyonunun <strong>17. çağrısında</strong> hata enjekte etmek istiyorsunuz. Fiziksel donanımda bunu yapmak çok zordur; Renode’da Python ile birkaç satır yeterlidir:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># fault_inject.py
</span><span class="n">call_count</span> <span class="o">=</span> <span class="mi">0</span>

<span class="k">def</span> <span class="nf">on_spi_read_entry</span><span class="p">(</span><span class="n">cpu</span><span class="p">):</span>
    <span class="k">global</span> <span class="n">call_count</span>
    <span class="n">call_count</span> <span class="o">+=</span> <span class="mi">1</span>
    <span class="k">if</span> <span class="n">call_count</span> <span class="o">==</span> <span class="mi">17</span><span class="p">:</span>
        <span class="c1"># R0 (donus degeri) = 0xFFFFFFFF (hata)
</span>        <span class="n">cpu</span><span class="p">.</span><span class="nc">SetRegisterUnsafe</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mh">0xFFFFFFFF</span><span class="p">)</span>
        <span class="c1"># Fonksiyonu erken sonlandir
</span>        <span class="n">cpu</span><span class="p">.</span><span class="n">PC</span> <span class="o">=</span> <span class="n">cpu</span><span class="p">.</span><span class="nc">GetRegisterUnsafe</span><span class="p">(</span><span class="mi">14</span><span class="p">).</span><span class="n">RawValue</span>  <span class="c1"># LR
</span></code></pre></div></div>

<p>Bu betiği Renode’a yükleyip <code class="language-plaintext highlighter-rouge">spi_read</code> sembolüne bağlayın. Test, retry mantığını gerçekçi koşullar altında doğrular.</p>

<h3 id="coverage-toplama">Coverage toplama</h3>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>cpu0 EnableProfilerCollapsedStack @coverage.txt false
</code></pre></div></div>

<p>Her instruction’ı yakalar; hangi fonksiyonların ne kadar çalıştığını ortaya çıkarır. Çıktıyı <code class="language-plaintext highlighter-rouge">inferno-flamegraph</code> ile besleyerek bir gecede eksiksiz bir <strong>flame graph</strong> üretebilirsiniz. Donanımda coverage toplamak <code class="language-plaintext highlighter-rouge">gcov</code> ile dahi bu kadar temiz olmaz.</p>

<h3 id="irq-hook">IRQ hook</h3>

<p>Bir kesme tetiklendiğinde, CPU üzerinden hook bağlanır:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>cpu0 AddHookAtInterruptBegin "print('IRQ basladi')"
cpu0 AddHookAtInterruptEnd   "print('IRQ bitti')"
</code></pre></div></div>

<p>IRQ akışını anlamak için altın değerindedir. Çoklu kesme yarış koşullarını çözmekte de yardımcı olur.</p>

<p><strong>Önemli:</strong> Hook’lar simülasyon ömrü boyunca aktif kalır. Test izolasyonu için her test başlangıcında <code class="language-plaintext highlighter-rouge">Reset Emulation</code> ile makine durumunu tertemiz başlatın; aksi takdirde hook’lar sonraki testlere taşınır ve flakiness kaynağı olur.</p>

<p>Hook’lar, Renode’u sıradan bir emülatörden, <strong>gözlemlenebilir ve müdahale edilebilir</strong> bir sisteme dönüştürür.</p>

<hr />

<h2 id="diğer-i̇leri-düzey-özellikler">Diğer İleri Düzey Özellikler</h2>

<p>Renode’un günlük kullanımda ezberlenmesi gereken birkaç başka özelliği:</p>

<h3 id="logger-seviyeleri-ve-filtreleri">Logger seviyeleri ve filtreleri</h3>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sysbus.uart1 LogLevel 0    # NOISY - her byte'i logla
sysbus.gpio  LogLevel 3    # WARNING ve uzeri
logFile @sim.log true
</code></pre></div></div>

<p>Her çevre birimi bağımsız log seviyesi alır. Sorunlu modülü debug log’una yükseltip diğerlerini sessizleştirebilirsiniz; CI loglarınız böylece yönetilebilir kalır.</p>

<h3 id="snapshot--restore">Snapshot / Restore</h3>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Save @before-test.snapshot
# ... test calistir, sistemde degisiklik yap
Load @before-test.snapshot
# ... tertemiz bastan basla
</code></pre></div></div>

<p>Tipik kullanım: Linux boot edildikten sonra snapshot alın, her test bu snapshot’tan başlasın. 30 saniyelik boot, 50 ms’lik restore’a düşer. Bu yaklaşım CI suite süresini dramatik şekilde kısaltır.</p>

<h3 id="multi-machine-simülasyonu">Multi-machine simülasyonu</h3>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>mach create "node1"
machine LoadPlatformDescription @platforms/boards/zedboard.repl
mach create "node2"
machine LoadPlatformDescription @platforms/boards/zedboard.repl

emulation CreateSwitch "switch1"
connector Connect node1.eth0 switch1
connector Connect node2.eth0 switch1
</code></pre></div></div>

<p>İki Zynq7000 kartı arasında Ethernet trafiği simüle edilir. Dağıtık sistem firmware’i, master/slave protokoller ve redundans senaryoları için olmazsa olmazdır.</p>

<h3 id="time-control">Time control</h3>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>emulation SetGlobalQuantum '0.000010'   # 10 us quantum
machine Pause
machine Resume
</code></pre></div></div>

<p>Simülasyonu duraklatabilir, yavaşlatabilir veya hızlandırabilirsiniz. Gerçek zaman zorunluluğu olmayan testler, simülasyonu <strong>gerçek zamandan kat kat hızlı</strong> koşturarak saatlerce sürecek bir testi dakikalara indirebilir.</p>

<h3 id="wireless-ve-pcap">Wireless ve PCAP</h3>

<p>Renode’un IEEE 802.15.4 (Zigbee) ve Bluetooth Low Energy için sanal “radio medium” desteği vardır. Birden fazla cihaz aynı medyumda paket alıp gönderir, Wireshark uyumlu PCAP dosyası kaydedilir (Ethernet, 802.15.4 ve BLE için). Mesh ağ firmware’i geliştirenler için biçilmiş kaftan.</p>

<h3 id="sembol-bazlı-cpu0-logfunctionnames">Sembol bazlı <code class="language-plaintext highlighter-rouge">cpu0 LogFunctionNames</code></h3>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>cpu0 LogFunctionNames true
</code></pre></div></div>

<p>Her fonksiyon çağrısını log’a yazar. Boot sırasında nelerin çağrıldığını görmek ve çağrı grafiğini anlamak için son derece hızlı bir araçtır.</p>

<hr />

<h2 id="test-otomasyonu">Test Otomasyonu</h2>

<p>Renode, kutudan çıktığı haliyle <strong>Robot Framework</strong> desteği sunar. Bu özellik, simülasyonun CI/CD ortamlarına entegrasyonunu çok kolaylaştırır. Tipik bir test dosyası şuna benzer:</p>

<div class="language-robot highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gh">*** Settings ***</span><span class="w">
</span><span class="bp">Suite Setup</span><span class="w">     </span><span class="nf">Setup</span><span class="w">
</span><span class="bp">Suite Teardown</span><span class="w">  </span><span class="nf">Teardown</span><span class="w">
</span><span class="bp">Test Setup</span><span class="w">      </span><span class="nf">Reset Emulation</span><span class="w">
</span><span class="bp">Resource</span><span class="w">        </span><span class="nv">${RENODEKEYWORDS}</span><span class="w">

</span><span class="gh">*** Test Cases ***</span><span class="w">
</span><span class="nl">Boot ZedBoard Firmware</span><span class="w">
    </span><span class="nf">Execute Command</span><span class="w">          </span><span class="s">include @scripts/boot.resc</span><span class="w">
    </span><span class="nf">Create Terminal Tester</span><span class="w">   </span><span class="s">sysbus.uart1</span><span class="w">
    </span><span class="nf">Start Emulation</span><span class="w">
    </span><span class="nf">Wait For Line On Uart</span><span class="w">    </span><span class="s">Boot tamamlandi</span><span class="w">
    </span><span class="nf">Wait For Line On Uart</span><span class="w">    </span><span class="s">Sensor degeri: 42</span><span class="w">

</span><span class="nl">GPIO Pini Yuksek Cikmali</span><span class="w">
    </span><span class="nf">Execute Command</span><span class="w">          </span><span class="s">include @scripts/boot.resc</span><span class="w">
    </span><span class="nf">Start Emulation</span><span class="w">
    </span><span class="nf">Execute Command</span><span class="w">          </span><span class="s">sysbus.gpio WritePin 7 true</span><span class="w">
    </span><span class="c"># Firmware'in pini okuyup yanit vermesini bekle</span><span class="w">
    </span><span class="nf">Wait For Line On Uart</span><span class="w">    </span><span class="s">Pin 7 yuksek</span><span class="w">
</span></code></pre></div></div>

<p>Çalıştırma komutu: <code class="language-plaintext highlighter-rouge">renode-test test.robot</code>. CI ortamında bu komut, fiziksel kart gerektirmeden bütün regresyon testlerini koşturur. Uzun boot sürelerini atlamak için <strong>snapshot / restore</strong> mekanizmasını kullanabilirsiniz: simülasyonu bir kez boot edip durumu snapshot olarak kaydedersiniz, sonraki testler o noktadan başlar.</p>

<hr />

<h2 id="geliştirme-debug-ve-test-için-avantajlar">Geliştirme, Debug ve Test için Avantajlar</h2>

<p>Renode ile Zynq7000 simülasyonunun fiziksel kartla yüksek seviyeli karşılaştırması:</p>

<table>
  <thead>
    <tr>
      <th>Özellik</th>
      <th>Fiziksel Kart</th>
      <th>Renode Simülasyon</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Birim maliyet</td>
      <td>Yüksek (~$200+)</td>
      <td>Sıfır</td>
    </tr>
    <tr>
      <td>CI/CD entegrasyonu</td>
      <td>Karmaşık (kart farm gerekir)</td>
      <td>Tek Docker imajı</td>
    </tr>
    <tr>
      <td>Paralel test</td>
      <td>1 kart = 1 test</td>
      <td>Sınırsız (CPU sayısı kadar)</td>
    </tr>
    <tr>
      <td>Determinizm</td>
      <td>Düşük (zamanlama varyasyonu)</td>
      <td>Yüksek (bit-bit tekrarlanabilir)</td>
    </tr>
    <tr>
      <td>Hata ayıklama</td>
      <td>JTAG + ek donanım</td>
      <td>Yerleşik GDB sunucusu</td>
    </tr>
    <tr>
      <td>Zaman kontrolü</td>
      <td>Yok</td>
      <td>Pause / step / hızlandır</td>
    </tr>
    <tr>
      <td>Multi-node senaryo</td>
      <td>Karmaşık</td>
      <td>Yerleşik</td>
    </tr>
    <tr>
      <td>Sensör değeri enjeksiyonu</td>
      <td>Donanım hilesi</td>
      <td>Tek komut</td>
    </tr>
    <tr>
      <td>Boot süresi</td>
      <td>Saniyeler</td>
      <td>Snapshot ile ms</td>
    </tr>
  </tbody>
</table>

<p>Bu tablo özet sunuyor; üç ayrı disiplin için somut faydalara bakalım.</p>

<h3 id="geliştirme-tarafında">Geliştirme tarafında</h3>

<ul>
  <li><strong>Donanım gelmeden başlanır.</strong> Yeni bir Zynq7000 kartı tasarlandığı sırada yazılım ekibi simülasyon üzerinde sürücüleri yazmaya başlayabilir. PCB üretimi 6 hafta sürüyorsa, o 6 hafta boşa gitmez.</li>
  <li><strong>Hızlı iterasyon.</strong> Bitstream sentezi 30 dakika sürüyorsa, Renode’da platform değişikliği 2 saniye sürer. Yazılım geliştiricilerin donanım ekibinin bir sonraki sentezini beklemesine gerek kalmaz.</li>
  <li><strong>Yeni katılım eşiği düşer.</strong> Yeni gelen mühendise kart, JTAG, USB-UART ve lab erişimi ayarlamak yerine <code class="language-plaintext highlighter-rouge">git clone &amp;&amp; renode boot.resc</code> yeterli olur.</li>
  <li><strong>Aynı kod hem simülasyonda hem gerçek donanımda çalışır.</strong> Renode’un adresleri ve davranışı fiziksel SoC ile birebir eşleşir; sürücü kodu port etmeden iki tarafta da koşar.</li>
</ul>

<h3 id="debug-tarafında">Debug tarafında</h3>

<ul>
  <li><strong>Determinizm.</strong> Aynı bug aynı şekilde tekrar üretilir; “bende çalışıyor” durumu yoktur. Reproducer’lar snapshot ya da <code class="language-plaintext highlighter-rouge">.resc</code> betiği olarak paylaşılır.</li>
  <li><strong>Time-travel.</strong> Bug’dan önce snapshot alın, koşumu tamamlayın, sonra snapshot’ı yükleyip farklı bir yolda deneyin. Heisenbug’ları çözmek için fiziksel donanımda imkansıza yakın bir yetenektir.</li>
  <li><strong>Görünürlük.</strong> Hook’lar ve logger sayesinde gerçek donanımda görünmez olan iç durumlar (register snapshot’ı, IRQ akışı, AXI handshake) izlenebilir hale gelir.</li>
  <li><strong>GDB her zaman bağlı.</strong> JTAG kopmaz, hedef wedge olmaz. İstediğiniz anda durdurursunuz, durumu incelersiniz, devam ettirirsiniz.</li>
  <li><strong>Coverage temiz toplanır.</strong> Renode tarafından üretilen instruction trace tamamen offline işlenebilir; gerçek donanımda bunu yapmak için ek donanım ya da kod enstrümantasyonu gerekir.</li>
</ul>

<h3 id="test-tarafında">Test tarafında</h3>

<ul>
  <li><strong>CI/CD entegrasyonu.</strong> Robot Framework + ekransız Renode + Docker = her commit’te tam sistem testi. Kart farmının operasyonel maliyeti yoktur.</li>
  <li><strong>Paralel koşum.</strong> Tek bir makinede 16 simülasyon paralel çalışır; aynısını fiziksel kart farmında yapmak 16 ayrı kart gerektirir.</li>
  <li><strong>Fault injection.</strong> “Şu IRQ kaybolsa ne olur? DMA timeout olursa? Sensör NaN dönerse?” Hepsi tek hook satırı ile test edilebilir; fiziksel donanımda kurulması haftalar sürecek senaryolar dakikalara iner.</li>
  <li><strong>Regresyon süresi.</strong> Snapshot’lar sayesinde bir gecede onlarca kat fazla test koşturulur; günlük geri bildirim döngüsü çok daha sıkı hale gelir.</li>
  <li><strong>Veri odaklı test.</strong> Sensör girdilerini dosyadan besleyen Python peripheral’lar, aynı testi yüzlerce farklı veri kümesiyle koşturmayı mümkün kılar.</li>
</ul>

<hr />

<h2 id="kullanım-alanları">Kullanım Alanları</h2>

<p>Renode + Zynq7000 ikilisinin somut kullanım alanları:</p>

<p><strong>1. Bootloader geliştirme.</strong> U-Boot, FSBL, SPL ve özel bootloader’lar Renode’da boot edilir. SD kart imajı yüklenir, JTAG ya da USB-UART kurmaya gerek kalmaz. Her commit’te boot tamamlanma süresi otomatik ölçülür ve regresyon olarak işaretlenebilir.</p>

<p><strong>2. Linux kernel hata ayıklama.</strong> Custom kernel patch’leri Renode üzerinde test edilir. <code class="language-plaintext highlighter-rouge">kgdb</code> çalıştırmak fiziksel kartta yorucudur; Renode’un yerleşik GDB sunucusu doğrudan çekirdek sembollerine bağlanır.</p>

<p><strong>3. Avionik ve fonksiyonel güvenlik.</strong> DO-178C, IEC 61508, EN 50128 gibi standartlar yüksek test kapsamı ve <strong>kanıtlanabilir tekrarlanabilirlik</strong> gerektirir. Renode’un deterministik yapısı bu beklentiyi doğal olarak karşılar; testi <code class="language-plaintext highlighter-rouge">.resc</code> betiği olarak sertifikasyon dosyasına eklemek mümkündür.</p>

<p><strong>4. Drone, robot ve otonom sistemler.</strong> Mock peripheral’lar üzerinden GPS, IMU ve lidar girdileri dosyadan simüle edilerek uçuş kontrol algoritmaları test edilir. Saha uçuşu yapmadan algoritma doğrulanmış olur.</p>

<p><strong>5. Eğitim laboratuvarları.</strong> Üniversite ya da kurum içi eğitimlerde, her öğrenci için kart sağlamak yerine herkesin laptop’ında Renode çalışır. Yanlış kod yazılsa bile kart yanmaz.</p>

<p><strong>6. Güvenlik araştırması.</strong> Firmware fuzzing’i hızlandırır; AFL veya libFuzzer ile birlikte koşturulur. Side-channel analizi için instruction trace çıkarılabilir. CVE PoC’leri snapshot olarak paylaşılır, reproducer net olur.</p>

<p><strong>7. Firmware OTA güncelleme testleri.</strong> OTA başarısız olursa fiziksel kart bricklenir; Renode’da bricklendiyse <code class="language-plaintext highlighter-rouge">Reset</code> komutu yeterlidir. Riskli bootloader değişikliklerini Renode’da yüzlerce kez test edip karta yalnızca kararlı sürümü atabilirsiniz.</p>

<p><strong>8. Müşteri demo’ları ve eğitim.</strong> Sahaya kart götürmeden firmware’in çalıştığını gösterebilirsiniz. Müşteriye veya entegrasyon ortağına Docker imajı bırakırsanız, kart olmadan da deneyebilirler.</p>

<p><strong>9. Hızlı PoC ve teklif aşaması.</strong> Müşteri “şu çevre birimi destekleniyor mu?” diye sorduğunda, fiziksel kart sipariş etmeden Renode’da basit bir prototip yapıp gösterebilirsiniz.</p>

<hr />

<h2 id="best-practices">Best Practices</h2>

<p>Renode’u proje sürecine sokarken biriken pratik dersler:</p>

<p><strong>1. <code class="language-plaintext highlighter-rouge">.resc</code> ve <code class="language-plaintext highlighter-rouge">.repl</code> dosyalarını versiyon kontrolünde tutun.</strong> Bunlar projeye ait konfigürasyondur; firmware kaynak kodu kadar değerlidir. Repo’da <code class="language-plaintext highlighter-rouge">sim/</code> klasörü açıp betikleri orada tutun ve kod incelemesine tabi kılın.</p>

<p><strong>2. Renode versiyonunu pinleyin.</strong> <code class="language-plaintext highlighter-rouge">renode --version</code> çıktısını CI loglarına yazdırın; Dockerfile’da spesifik tag (örn. <code class="language-plaintext highlighter-rouge">antmicro/renode:1.14.0</code>) kullanın. Determinizm bunu gerektirir; aynı testin aynı sonucu üretmesi versiyon sabitliğiyle başlar.</p>

<p><strong>3. Snapshot stratejisi kurun.</strong> Uzun boot’ları her test başında tekrarlamak israftır. “Linux boot tamamlandıktan sonra” ya da “init betiği çalıştıktan sonra” gibi tipik anlarda snapshot alıp test suite’lerini bu noktadan başlatın. Bu yaklaşım, karmaşık bir projede toplam CI süresini saatlerden dakikalara çekebilir.</p>

<p><strong>4. Logger seviyesini ortama göre ayarlayın.</strong> CI’da <code class="language-plaintext highlighter-rouge">LogLevel 3</code> (Warning); lokal debug’da <code class="language-plaintext highlighter-rouge">LogLevel 0</code> (Noisy). Aksi takdirde CI logu fazlasıyla şişer, gerçek sorunlar gürültü altında kaybolur.</p>

<p><strong>5. Test başlangıçlarını izole edin.</strong> Her test başında <code class="language-plaintext highlighter-rouge">Reset Emulation</code> çağırın; bu, kalan hook’lar dahil makine durumunu tertemiz sıfırlar. Hook sızıntısı, en sinsi flakiness kaynağıdır.</p>

<p><strong>6. Custom peripheral’lar küçük olsun.</strong> Bir Python peripheral 50 satırı geçiyorsa ayrı bir <code class="language-plaintext highlighter-rouge">.py</code> dosyasına alın ve <code class="language-plaintext highlighter-rouge">pytest</code> ile birim testini yazın. Test edilmemiş bir peripheral, ana firmware’in hatalarını maskeleyebilir.</p>

<p><strong>7. Robot Framework testlerini paralel koşturun.</strong> <code class="language-plaintext highlighter-rouge">pabot</code> ile paralel koşum mümkündür. Her test kendi makine örneğinde izole olsun; <code class="language-plaintext highlighter-rouge">Reset Emulation</code>, <code class="language-plaintext highlighter-rouge">Test Setup</code> adımında zorunlu olsun.</p>

<p><strong>8. UART çıktısını dosyaya da yazdırın.</strong> <code class="language-plaintext highlighter-rouge">sysbus.uart1 CreateFileBackend @uart.log true</code> ile UART akışını dosyaya kaydedin. CI’da test başarısız olduğunda bu log paha biçilmezdir.</p>

<p><strong>9. Ekransız modu kullanın.</strong> Renode GUI yerel hata ayıklama için iyidir; CI için ise <code class="language-plaintext highlighter-rouge">--disable-xwt --console</code> veya <code class="language-plaintext highlighter-rouge">--hide-monitor</code> bayraklarıyla başlatın. Hem hız kazanırsınız hem de ekran bağımlılığı kalmaz.</p>

<p><strong>10. Real-time bağımlılıkları dikkatli ele alın.</strong> Renode <code class="language-plaintext highlighter-rouge">RealTimeMode</code>‘da fiziksel zamana hizalanmaya çalışır ama saat doğruluğu çekirdek kullanımına bağlıdır. Sıkı timing testleri için <code class="language-plaintext highlighter-rouge">emulation SetGlobalQuantum</code> ile deterministik time-step kullanın; gerçek zamana güvenmeyin.</p>

<p><strong>11. Sensör akışlarını dosyadan besleyin.</strong> Sensör simülasyonunu kod içine gömmek yerine, JSON / CSV dosyasından okuyacak şekilde yazın. Aynı test senaryosu farklı veri kümeleriyle koşturulabilir — veri odaklı test (data-driven testing) kapısı böylece açılır.</p>

<p><strong>12. Mevcut platformları kopyalayıp özelleştirin.</strong> <code class="language-plaintext highlighter-rouge">@platforms/boards/zedboard.repl</code>‘i kopyalayıp <code class="language-plaintext highlighter-rouge">my_board.repl</code> yapın, <code class="language-plaintext highlighter-rouge">using</code> ile orijinali dahil edip üzerine <strong>sadece farkları</strong> yazın. Renode güncellemelerinde temel platform iyileşirken sizin patch’iniz korunur.</p>

<p><strong>13. Coverage’ı simülasyondan toplayın.</strong> <code class="language-plaintext highlighter-rouge">cpu0 EnableProfilerCollapsedStack</code> ile çıkan log + <code class="language-plaintext highlighter-rouge">inferno-flamegraph</code> = bir gecede test kapsamı raporu. Manuel kart üzerinde coverage almak çok daha pahalıdır.</p>

<p><strong>14. PR’lara Renode test sonucu ekleyin.</strong> GitHub Actions’ta <code class="language-plaintext highlighter-rouge">renode-test</code> çıktısını PR yorumuna yapıştıran bir adım kurun. İnceleyiciler testin yeşil olduğunu görerek incelemeye başlar; bu, “deneyip baktım” kültürünü destekler.</p>

<p><strong>15. Renode dokümantasyonunu sıkça açın.</strong> Renode hızla gelişiyor; <code class="language-plaintext highlighter-rouge">renode.readthedocs.io</code> yeni özellikler için en güncel kaynaktır. Antmicro blog’u Verilator entegrasyonu, yeni platformlar ve case study’ler için kıymetlidir.</p>

<hr />

<h2 id="sınırlamalar">Sınırlamalar</h2>

<p>Renode’un her şeye çare olmadığını da unutmamak gerekir:</p>

<ul>
  <li><strong>Cycle-accurate değildir.</strong> Gerçek zamanlı performans profili ölçümü için uygun değildir. Cache miss oranları, DDR3 timing’i, pipeline davranışı gerçek donanımdaki sonuçlarla birebir örtüşmez.</li>
  <li><strong>Tüm çevre birimleri tam modellenmemiştir.</strong> Zynq7000’in PCIe, USB OTG gibi bazı blokları yalnızca temel düzeyde simüle edilir.</li>
  <li><strong>FPGA HDL doğrulaması için Verilator gibi ek bir araç gerekir.</strong> Renode tek başına RTL çalıştıramaz.</li>
  <li><strong>Analog dünya kısıtlıdır.</strong> ADC/DAC kanalları yerleşik olarak gelmez; veri akışını siz “enjekte etmelisiniz”.</li>
</ul>

<p>Bu sınırlamalara rağmen, sistem entegrasyon testlerinin <strong>%80’i</strong> Renode üzerinde yapılabilir. Geri kalan kısım fiziksel donanımda son doğrulamayla tamamlanır.</p>

<hr />

<h2 id="sonuç">Sonuç</h2>

<p>Zynq7000 gibi PS+PL hibrit bir SoC’yi geliştirmek, donanım kaynaklı bekleme süreleri ve test maliyetleri yüzünden çoğu zaman acı verici olur. Renode, açık kaynak doğası, geniş çevre birim kütüphanesi ve Verilator ile co-simülasyon yeteneği sayesinde bu sürecin önemli bir bölümünü masaüstüne ya da CI sunucusuna taşımanıza imkân tanır.</p>

<p>Yazılım, donanım gelmeden hazır olabilir; testler her commit’te otomatik koşabilir; “şu hatayı tekrarlat” denildiğinde simülasyon snapshot’ı paylaşmak yeterli olabilir. Üstelik bunların tümü için herhangi bir lisans ücreti ödemezsiniz.</p>

<p>Renode’un Zynq7000’i ile başlamak için yapmanız gereken yalnızca <code class="language-plaintext highlighter-rouge">renode</code> komutunu çalıştırıp <code class="language-plaintext highlighter-rouge">start @scripts/single-node/zedboard.resc</code> yazmaktır. Gerisi, zaten gömülü mühendisin bildiği iştir.</p>

<hr />

<p><strong>Kaynaklar:</strong></p>

<ul>
  <li><a href="https://renode.io">Renode resmi sitesi</a></li>
  <li><a href="https://github.com/renode/renode">Renode GitHub deposu</a></li>
  <li><a href="https://renode.readthedocs.io">Renode dokümantasyonu</a></li>
  <li><a href="https://antmicro.com/blog/2020/06/co-simulating-rtl-with-renode/">Antmicro — Verilator ile Renode co-simülasyon</a></li>
  <li><a href="https://www.amd.com/en/products/adaptive-socs-and-fpgas/soc/zynq-7000.html">AMD/Xilinx Zynq7000 SoC ailesi</a></li>
  <li><a href="https://renode.readthedocs.io/en/latest/introduction/testing.html">Renode Robot Framework rehberi</a></li>
</ul>]]></content><author><name>M. Serdar Karaman</name></author><category term="aviyonik" /><category term="gomulu-sistemler" /><category term="araclar" /><summary type="html"><![CDATA[Gömülü sistem geliştirmenin en yorucu yanlarından biri donanımın kendisidir. FPGA bitstream’leri saatler süren sentez işlemleri gerektirir, geliştirme kartları ekipler arasında paylaşılır, JTAG bağlantıları kopar, sahada hata ayıklamak ise çoğu zaman pratik değildir. Sürekli entegrasyon (CI) altyapısına fiziksel kart bağlamak ayrı bir mühendislik problemidir.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://karaman.dev/img/og-default.webp" /><media:content medium="image" url="https://karaman.dev/img/og-default.webp" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry xml:lang="tr"><title type="html">Saatçinin Saatini Kim Kalibre Eder? Kalibrasyon Zincirinin Tepesi</title><link href="https://karaman.dev/2026/05/07/kalibrasyon-zincirinin-tepesi-birincil-standartlar.html" rel="alternate" type="text/html" title="Saatçinin Saatini Kim Kalibre Eder? Kalibrasyon Zincirinin Tepesi" /><published>2026-05-07T09:00:00+00:00</published><updated>2026-05-07T09:00:00+00:00</updated><id>https://karaman.dev/2026/05/07/kalibrasyon-zincirinin-tepesi-birincil-standartlar</id><content type="html" xml:base="https://karaman.dev/2026/05/07/kalibrasyon-zincirinin-tepesi-birincil-standartlar.html"><![CDATA[<script src="https://cdn.plot.ly/plotly-basic-2.27.0.min.js"></script>

<p>Akreditasyon denetimi sabahı. Denetçi elinde bir kalem, masanızdaki Keysight 34465A multimetreyi gösteriyor.</p>

<p>— “Bu cihazı neyle kalibre ediyorsunuz?”
— “Yan rafta duran Fluke 5720A kalibratörle.”
— “Peki Fluke 5720A neyle kalibre edildi?”
— “Geçen yıl TÜBİTAK UME’ye gönderdik.”
— “Peki UME neyle kalibre etti?”</p>

<p>Kısa bir sessizlik. Cevabı tahmin ediyorsunuz ama ifadeyi bulamıyorsunuz: <em>daha iyi bir kalibratörle</em>. Peki o kalibratör neyle? <em>Daha iyisiyle.</em> Sonra? Sonsuza mı gidiyor bu zincir?</p>

<p><a href="/2026/05/06/olcum-belirsizligi-gum-annex-f-ncsli-rp-12.html">Bir önceki yazıda</a> bir cihazın belirsizliğinin nasıl hesaplandığını adım adım gördük. Belirsizlik bütçesinin son satırında “kalibrasyon belgesi (UME, k=2)” diye bir kaynak vardı; o satıra bir sayı yazıp geçtik. Bu yazıda o satırın <strong>arkasını</strong> açacağız. Kalibrasyon belgesindeki belirsizlik nereden geliyor? UME bu sayıyı nasıl üretiyor? Ve zincirin en tepesindeki cihazlar — ki onlar bu sektörün gerçekten en hassas ölçüm aletleri — <em>nasıl</em> doğrulanıyorlar?</p>

<p>Cevap, mühendislikten yavaş yavaş fiziğe doğru kayıyor. Zincirin tepesinde başka bir cihaz yok. Doğa yasaları var.</p>

<hr />

<h2 id="i̇zlenebilirlik-piramidi">İzlenebilirlik Piramidi</h2>

<p>Önceki yazıda izlenebilirlik zincirini lineer bir akış olarak çizmiştik: SI → UME → akredite lab → cihaz. Aslında bu akış bir piramidin yan kesiti. Tepede bir avuç birincil standart var; tabanda dünyadaki milyonlarca ölçüm cihazı.</p>

<div class="mermaid">
flowchart TB
    SI["<b>Seviye 0</b> &nbsp; SI Birim Tanımları<br />7 doğa sabiti — h, c, e, k, N_A, Δν_Cs, K_cd<br /><i>belirsizlik: tanım gereği sıfır</i>"]
    PRI["<b>Seviye 1</b> &nbsp; Birincil Standartlar<br />NMI'ler — UME, NIST, PTB, NPL, BIPM<br />Sezyum fıskiyesi, Kibble terazisi, Josephson, kuantum Hall<br /><i>belirsizlik: 10⁻⁹ – 10⁻¹⁶</i>"]
    REF["<b>Seviye 2</b> &nbsp; İkincil / Transfer Standartlar<br />Akredite kalibrasyon laboratuvarları, TÜRKAK<br />Fluke 732C, ESI SR104, Agilent 3458A<br /><i>belirsizlik: 10⁻⁷ – 10⁻⁸</i>"]
    WORK["<b>Seviye 3</b> &nbsp; Çalışma Standartları<br />Sanayinin lab referansı<br />Fluke 5720A/5730A, Druck DPI 620<br /><i>belirsizlik: 10⁻⁶</i>"]
    UUT["<b>Seviye 4</b> &nbsp; Saha Cihazları (UUT)<br />Multimetre, basınç sensörü, sıcaklık probu<br /><i>belirsizlik: 10⁻⁴ – 10⁻⁵</i>"]
    SI --&gt; PRI --&gt; REF --&gt; WORK --&gt; UUT
    style SI fill:#1a73e8,color:#fff,stroke:#0c4ea2,stroke-width:2px
    style PRI fill:#2e7d32,color:#fff,stroke:#1b5e20,stroke-width:2px
    style REF fill:#e8711a,color:#fff,stroke:#a14b00,stroke-width:2px
    style WORK fill:#c62828,color:#fff,stroke:#8a1010,stroke-width:2px
    style UUT fill:#6a1b9a,color:#fff,stroke:#3c0d59,stroke-width:2px
</div>

<p>Piramidi okumanın iki yolu var. Yukarıdan aşağı baktığınızda her seviyede <strong>belirsizlik artar, maliyet düşer, erişim genişler</strong>. Aşağıdan yukarı baktığınızda her cihaz “bir üstündeki seviyenin daha hassas örneğine” karşı kalibre edilir. Bu mantığın doğal sonucu, en üstte de bir cihaz olması gerektiği — ve onun da bir başkasına karşı kalibre edilmesi gerektiği. Ama bir yerde durması lazım. Yoksa kalibrasyon kavramının kendisi anlamsız.</p>

<table>
  <thead>
    <tr>
      <th>Seviye</th>
      <th>Tipik cihaz</th>
      <th>Kim sahibi</th>
      <th>Tipik belirsizlik (10 V için)</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>0</td>
      <td>(cihaz yok, doğa sabiti)</td>
      <td>doğa</td>
      <td>0 (tanım)</td>
    </tr>
    <tr>
      <td>1</td>
      <td>Programlanabilir Josephson voltaj standardı</td>
      <td>UME, NIST, PTB</td>
      <td>~0,05 µV (5 ppb)</td>
    </tr>
    <tr>
      <td>2</td>
      <td>Fluke 732C / ESI SR104 / Agilent 3458A</td>
      <td>TÜRKAK akrediteli lab</td>
      <td>~5 µV (0,5 ppm)</td>
    </tr>
    <tr>
      <td>3</td>
      <td>Fluke 5720A / 5730A</td>
      <td>Sanayi lab</td>
      <td>~50 µV (5 ppm)</td>
    </tr>
    <tr>
      <td>4</td>
      <td>Keysight 34465A multimetre</td>
      <td>Test mühendisi</td>
      <td>~500 µV (50 ppm)</td>
    </tr>
  </tbody>
</table>

<p>Piramidin her seviyesinde belirsizlik yaklaşık <strong>bir mertebe</strong> (10×) artıyor. Bu rastlantı değil. Pratik bir kuraldır: <strong>referans cihazınız, kalibre edeceğiniz cihazdan en az dört kat daha iyi olmalı</strong> (TUR ≥ 4 kuralı, önceki yazıdaki Z540.3 sınırı). Üreticiler ve akredite laboratuvarlar piramidi bu kurala göre kurarlar; tipik aralık 4 ile 10 arasında değişir. Daha iyi olmak şart değil çünkü pahalı; ama 4’ün altına düşmek de pratik olarak kararı bozar.</p>

<hr />

<h2 id="kim-kalibre-eder-sorusunun-sonu">“Kim Kalibre Eder?” Sorusunun Sonu</h2>

<p>Şimdi denetçinin sorusuna geri dönelim. Piramitte hep yukarı çıkıyoruz: cihaz, kalibratör, transfer standardı, NMI’nin birincil standardı. Sonunda Seviye 1’e ulaşıyoruz. UME’deki sezyum fıskiyesi. Kibble terazisi. Josephson eklem dizisi. <strong>Bunları kim kalibre ediyor?</strong></p>

<p>Yanıt iki kademede gelir.</p>

<p>İlk kademe pratiğin cevabıdır: <strong>kimse</strong>. Birincil standart başka bir cihaza karşı doğrulanmaz. Çünkü daha hassası yok. Eğer birinci sınıf bir Josephson voltaj standardından sapma görmek isterseniz, bunu görmenin tek yolu <strong>başka bir Josephson standardı</strong> ile karşılaştırmaktır. Bu da “kalibrasyon” değil, <strong>karşılaştırma</strong> olarak tanımlanır. (Bu konuya bölüm 6’da döneceğiz.)</p>

<p>İkinci kademe felsefenin cevabıdır: <strong>doğa yasaları</strong>. Modern birincil standartlar, başka bir cihazın değerlerine karşı değil, <strong>fiziğin sabit niceliklerine</strong> karşı tanımlanır. Sezyum fıskiyesinin doğru çalışıp çalışmadığını anlamanın yolu, ürettiği frekansın gerçekten sezyum-133 atomunun hiperince geçişine denk düşüp düşmediğine bakmaktır. Bu geçiş frekansı (Δν_Cs) ise <strong>tam tanım gereği</strong> 9 192 631 770 Hz’tir; SI saniyesi tam olarak böyle tanımlanmıştır.</p>

<p>Yani saat “kalibre” edilmez. <strong>Sayar.</strong> Saatin görevi sezyum-133 atomlarını gözlemleyip kaç hiperince geçiş geçtiğini saymaktır. Eğer 9 192 631 770 saymışsa, üzerinden 1 saniye geçmiş demektir. Tanım, fizik ve cihaz aynı şeyi söylüyor.</p>

<p>Tarih boyunca her zaman böyle değildi.</p>

<p>1889’dan 2019’a kadar <strong>kilogram</strong>ın tanımı şöyleydi: “Uluslararası Kilogram Prototipi (IPK), Saint-Cloud’daki Pavillon de Breteuil’de (posta adresi: Sèvres) BIPM kasasında saklanan platin-iridyum silindirin kütlesi.” Yani dünyadaki <em>bir tek</em> gerçek 1 kg vardı; o silindir. Diğer her şey ona göre tanımlanmıştı. IPK günlük çalışma için kullanılmıyordu; yanında BIPM’in kendi yedekleri (témoin) ve bir avuç çalışma standardı vardı. Tarih boyunca yalnızca dört defa kasadan çıkarıldı — 1889 onayı ve üç doğrulama kampanyası (1939-46, 1989-92, 2014). Bu kampanyalarda BIPM yedekleri ve ülkelerin ulusal prototipleri (K20, K54…) IPK ile karşılaştırıldı. IPK’nın kendisinin bir kalibrasyonu yoktu — <em>o</em>, kalibrasyonun referansıydı.</p>

<p>Sorun şuydu: özellikle 1989-92 karşılaştırmasında, IPK ile resmi yedekleri arasında ortalama yaklaşık <strong>50 µg</strong>‘lık bir farklılaşma raporlandı (yedeklerin çoğu IPK’ya göre kütle kazandı, ya da IPK kütle kaybetti). Yaklaşık bir asırlık değişim 50 mikrogram. Az gibi duruyor — ama önemli olan miktarı değil, ilkesi: <strong>eğer 1 kg’ın tanımı bu silindirse</strong>, silindir değişirse 1 kg da değişir. Mantık olarak silindirin <em>yanlış</em> olması mümkün değildi. Yanlış olan, dünyadaki diğer tüm 1 kg ölçümleriydi.</p>

<p>Bu durum, dünyanın en hassas ölçümlerini yapan kuruluşları rahatsız etti. Birim tanımı bir esere bağlıyken, eserin iyi durumda olup olmadığından asla emin olamazdınız.</p>

<p>16 Kasım 2018’de BIPM’in <strong>26. Genel Konferansı (CGPM)</strong> çözümü oybirliğiyle kabul etti: SI birimleri artık eserlere değil, <strong>doğa sabitlerine</strong> bağlanacak. Planck sabiti tam değer atandı, belirsizlik sıfır. IPK emekli edildi. Aynı şey amper, kelvin ve mol için de yapıldı. Yeni tanımlar 20 Mayıs 2019’da — Metre Konvansiyonu’nun 144. yıl dönümünde, yani Dünya Metroloji Günü’nde — yürürlüğe girdi.</p>

<p>Bu, 130 yılın en büyük metroloji reformuydu. Ve şimdi zincirin tepesinde <em>cihaz</em> yok; <em>fizik</em> var.</p>

<blockquote>
  <p><strong>Akılda kalsın — birincil standart kalibre edilmez:</strong> Bir sezyum fıskiyesini “şuna karşı kalibre ettik” diyemezsiniz. Sadece başka bir sezyum fıskiyesiyle <strong>karşılaştırırsınız</strong>. Anlaşmazlık olursa fizik konuşur, cihaz değil.</p>
</blockquote>

<hr />

<h2 id="2019-devrimi-sabitler-tanımlanır-birimler-türetilir">2019 Devrimi: Sabitler Tanımlanır, Birimler Türetilir</h2>

<p>Reformun mantığı tek satırla şu: önceden birim tanımı belliydi, doğa sabiti ölçülürdü; şimdi doğa sabiti tanımlıdır, birim ölçülür.</p>

<div class="mermaid">
flowchart LR
    subgraph eski["1889 – 2019: Eserden Birime"]
        A1["Eser<br />(IPK, metre çubuğu)"] --&gt; A2["Birim<br />(kg, m)"]
        A2 --&gt; A3["Sabit<br />(h, c) ölçülür"]
    end
    subgraph yeni["2019 sonrası: Sabitten Birime"]
        B1["Sabit<br />(h, c, e, k, ...)<br /><i>tam değer atanır</i>"] --&gt; B2["Birim<br />(kg, m, A, K, ...)"]
        B2 --&gt; B3["Gerçekleme<br />(Kibble, Josephson, ...)"]
    end
    style A1 fill:#fce4ec,stroke:#c2185b
    style A2 fill:#f8bbd0,stroke:#c2185b
    style A3 fill:#f48fb1,stroke:#c2185b
    style B1 fill:#e3f2fd,stroke:#1565c0
    style B2 fill:#90caf9,stroke:#1565c0
    style B3 fill:#42a5f5,stroke:#1565c0,color:#fff
</div>

<p>Reformun yarım asrı bulan tarihsel dönüm noktaları:</p>

<div class="mermaid">
flowchart TB
    Y1875["<b>1875</b><br />Metre Konvansiyonu imzalandı<br />BIPM kuruldu"]
    Y1889["<b>1889</b><br />1. CGPM<br />IPK ve metre prototipi onaylandı<br /><i>(eserlerle tanım çağı başlar)</i>"]
    Y1960["<b>1960</b><br />11. CGPM<br />SI resmi olarak ilan edildi<br />metre kripton-86'ya bağlandı"]
    Y1967["<b>1967</b><br />13. CGPM<br />saniye sezyum-133'e bağlandı<br /><i>(ilk fiziksel sabit tabanlı tanım)</i>"]
    Y1983["<b>1983</b><br />17. CGPM<br />metre ışık hızıyla tanımlandı<br />(c = tam değer)"]
    Y2005["<b>2005</b><br />CIPM tavsiyesi<br />kilogramın yeniden tanımı önerildi"]
    Y2018["<b>2018-11-16</b><br />26. CGPM oybirliği<br />h, e, k, N_A tam değer atandı"]
    Y2019["<b>2019-05-20</b><br />Yeni SI yürürlükte<br /><i>(IPK emekli; tüm tanımlar sabit tabanlı)</i>"]
    Y1875 --&gt; Y1889 --&gt; Y1960 --&gt; Y1967 --&gt; Y1983 --&gt; Y2005 --&gt; Y2018 --&gt; Y2019
    style Y1875 fill:#fce4ec,stroke:#c2185b
    style Y1889 fill:#f8bbd0,stroke:#c2185b
    style Y1960 fill:#e1bee7,stroke:#7b1fa2
    style Y1967 fill:#d1c4e9,stroke:#512da8
    style Y1983 fill:#c5cae9,stroke:#3949ab
    style Y2005 fill:#bbdefb,stroke:#1565c0
    style Y2018 fill:#90caf9,stroke:#1565c0
    style Y2019 fill:#1a73e8,color:#fff,stroke:#0c4ea2,stroke-width:2px
</div>

<p>Eski sistemde Planck sabitinin “ölçülmüş değeri” vardı, sürekli daha hassas ölçüm yapmaya çalışıyorduk. Yeni sistemde Planck sabiti <strong>tam olarak</strong> 6,626 070 15 × 10⁻³⁴ J·s. Belirsizlik sıfır, çünkü tanım böyle. Ölçtüğümüz şey artık Planck sabiti değil — <strong>kilogram</strong>. Yani Kibble terazisi, kilogramı Planck sabitinden ne kadar iyi <em>gerçekleyebildiğimizi</em> sınar.</p>

<p>Yedi tanımlayıcı sabit (defining constants):</p>

<table>
  <thead>
    <tr>
      <th>Sabit</th>
      <th>Sembol</th>
      <th>Tam değer</th>
      <th>Tanımladığı SI birimi</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Sezyum-133 hiperince geçiş frekansı</td>
      <td>Δν_Cs</td>
      <td>9 192 631 770 Hz</td>
      <td>saniye (s)</td>
    </tr>
    <tr>
      <td>Vakumda ışık hızı</td>
      <td>c</td>
      <td>299 792 458 m/s</td>
      <td>metre (m)</td>
    </tr>
    <tr>
      <td>Planck sabiti</td>
      <td>h</td>
      <td>6,626 070 15 × 10⁻³⁴ J·s</td>
      <td>kilogram (kg)</td>
    </tr>
    <tr>
      <td>Temel yük</td>
      <td>e</td>
      <td>1,602 176 634 × 10⁻¹⁹ C</td>
      <td>amper (A)</td>
    </tr>
    <tr>
      <td>Boltzmann sabiti</td>
      <td>k</td>
      <td>1,380 649 × 10⁻²³ J/K</td>
      <td>kelvin (K)</td>
    </tr>
    <tr>
      <td>Avogadro sabiti</td>
      <td>N_A</td>
      <td>6,022 140 76 × 10²³ mol⁻¹</td>
      <td>mol</td>
    </tr>
    <tr>
      <td>540 THz ışınım için aydınlanma etkinliği</td>
      <td>K_cd</td>
      <td>683 lm/W</td>
      <td>kandela (cd)</td>
    </tr>
  </tbody>
</table>

<p>Tablonun anlamı şu: bu yedi sayıyı doğa kanunu olarak kabul ediyoruz. Diğer her şey buradan türüyor. Saniye Δν_Cs’den, metre c × s’den, kilogram h’den, amper e’den, kelvin k’den… Dünyanın her yerinde aynı yedi sayı kullanılıyor; herkes aynı birime sahip.</p>

<p>Pratik bir test: bir Türk laboratuvarındaki 1 kg ile bir Alman laboratuvarındaki 1 kg birbirinden farklı olabilir mi? Eski sistemde <strong>evet</strong> — Türk silindiri Sèvres’deki orijinalden ne kadar farklılaştığına bağlı. Yeni sistemde <strong>hayır</strong> — her ikisi de aynı Planck sabitinden türetiliyor; en kötü ihtimalle gerçekleme cihazlarının belirsizliği kadar farklılık olur, sistematik bir kayma yok.</p>

<blockquote>
  <p><strong>Akılda kalsın — gerçekleme (realization) ile kalibrasyonun farkı:</strong> Kalibrasyon, bir cihazın değerini <em>üst seviyedeki</em> başka bir cihaza göre düzeltmektir. Gerçekleme, bir cihazın değerini <em>birim tanımına</em> — yani fiziksel bir olguya — göre üretmektir. Birincil standart kalibre edilmez, birimi gerçekler.</p>
</blockquote>

<hr />

<h2 id="birincil-standartlar-yakın-plan">Birincil Standartlar Yakın Plan</h2>

<p>Sırayla altı birimin birincil gerçeklenişine bakalım. Her biri için soracağımız sorular: cihaz nedir, hangi sabite dayanır, tipik belirsizlik nedir, dünyada ve Türkiye’de kim çalıştırıyor.</p>

<h3 id="saniye-sezyum-fıskiyesi-ve-optik-saatler">Saniye: Sezyum Fıskiyesi ve Optik Saatler</h3>

<p>SI tüm birimleri arasında en hassas tanımlananı saniyedir. Çünkü sezyum-133 atomunun hiperince geçişi, doğanın sunduğu en kararlı periyodik olgu sayılıyor.</p>

<p>İlk pratik sezyum atomik saati 1955’te NPL’de (İngiltere) Louis Essen ve Jack Parry tarafından yapıldı; sıcak bir fırından çıkan atom demetini frekans rezonansından geçiren bir düzendi, doğruluğu 1×10⁻⁹ mertebesindeydi. <strong>Sezyum fıskiyesi</strong> ise modern tasarım: atomlar lazerle soğutuluyor (mikrokelvin mertebesinde), yukarı doğru fırlatılıyor, yerçekimiyle aşağı düşüyor. Bu “fıskiye” geometrisi atomların rezonans bölgesinden iki kez geçmesini sağlıyor — birincide frekansı işaretliyor, ikincide kontrol ediyor. Daha uzun gözlem süresi, daha keskin rezonans, daha düşük belirsizlik.</p>

<div class="mermaid">
flowchart TB
    OVEN["Sezyum atom kaynağı<br />(katı sezyum-133, ısıtılır)"]
    COOL["Lazer soğutma<br />µK seviyesine indir"]
    TOSS["Yukarı doğru lazerle fırlat<br />(saniyede ~5 m hız)"]
    UP["Yukarı çıkış<br />mikrodalga kavitesinden geç (1. geçiş)"]
    PEAK["Tepe noktası<br />(yerçekimi atomları durdurur)"]
    DOWN["Aşağı düşüş<br />aynı kaviteden tekrar geç (2. geçiş)"]
    DETECT["Floresan dedektörü<br />kaç atom 'işaretli' durumda?"]
    SERVO["Mikrodalga frekansını ayarla<br />maksimum işaretli atom sayısı için"]
    OVEN --&gt; COOL --&gt; TOSS --&gt; UP --&gt; PEAK --&gt; DOWN --&gt; DETECT --&gt; SERVO
    SERVO -.-&gt; UP
    style OVEN fill:#fce4ec,stroke:#c2185b
    style COOL fill:#e1bee7,stroke:#7b1fa2
    style TOSS fill:#c5cae9,stroke:#3949ab
    style UP fill:#bbdefb,stroke:#1565c0
    style PEAK fill:#b3e5fc,stroke:#0277bd
    style DOWN fill:#bbdefb,stroke:#1565c0
    style DETECT fill:#c8e6c9,stroke:#388e3c
    style SERVO fill:#fff9c4,stroke:#f57f17
</div>

<p>Tipik kararlılıklar:</p>

<ul>
  <li>1955 NPL sezyum demet saati (Essen-Parry): ~10⁻⁹ (~30 yılda 1 s — yine de mekanik saatlerden bin kat daha iyi)</li>
  <li>Klasik sezyum demet saati (1990’lar): ~10⁻¹³ – 10⁻¹⁴</li>
  <li>Modern sezyum fıskiyesi (NIST-F1 hâlâ aktif, PTB-CSF1/CSF2): ~5×10⁻¹⁶ – 1×10⁻¹⁵</li>
  <li>En iyi optik latis saati (JILA/NIST stronsiyum, 2024): 8,1×10⁻¹⁹</li>
</ul>

<p>10⁻¹⁶ kararlılık ne demek? Saat ~300 milyon yılda 1 saniye sapar demek. 8×10⁻¹⁹’un anlamı ise <strong>evrenin yaşının iki katı boyunca 1 saniyeden az sapma</strong>.</p>

<p>Sezyum saatinin doğruluğu yetmiş yılda yaklaşık 10 milyar kat iyileşti — bilim tarihinde belki de en büyük tek kuantitatif ilerleme:</p>

<div id="grafik-saat-tarihi" style="width:100%;max-width:760px;margin:1.5rem auto 2.5rem auto;height:380px;"></div>
<script>
(function(){
  var data = [{
    type: 'scatter',
    mode: 'lines+markers',
    x: [1955, 1968, 1991, 1999, 2005, 2014, 2019, 2024],
    y: [1e-9, 1e-12, 1e-13, 1.5e-15, 1e-15, 1.1e-16, 9.4e-19, 8.1e-19],
    text: ['NPL Essen-Parry sezyum demet', 'NBS-3 sezyum demet', 'Klasik sezyum demet (PTB)', 'NIST-F1 sezyum fıskiyesi', 'Optik atom saati ilk gösterimler', 'NIST-F2 ilk değerlendirme', 'NIST Al+ kuantum mantık saati', 'JILA Sr optik latis saati'],
    hovertemplate: '%{x}<br>%{text}<br>Bağıl belirsizlik: %{y:.2e}<extra></extra>',
    marker: { size: 10, color: '#1a73e8' },
    line: { color: '#1a73e8', width: 2 }
  }];
  var layout = {
    title: { text: 'Sezyum/optik atom saatlerinin doğruluğu (1955–2024)', font: { size: 14 } },
    xaxis: { title: 'Yıl' },
    yaxis: { title: 'Bağıl belirsizlik (log eksen)', type: 'log', autorange: true },
    margin: { l: 80, r: 30, t: 50, b: 50 },
    plot_bgcolor: '#ffffff',
    paper_bgcolor: '#ffffff'
  };
  Plotly.newPlot('grafik-saat-tarihi', data, layout, {responsive: true, displayModeBar: false});
})();
</script>

<p>Türkiye tarafında UME’nin Zaman ve Frekans Laboratuvarı 1994’ten beri BIPM’in koordine ettiği Uluslararası Atom Zamanı (TAI) ağına katkı sağlıyor. UME birincil standardı bir <strong>sezyum fıskiyesi değil</strong>, hidrojen maser (1 adet) + ticari sezyum atom saati ensemble’ı (5 adet) + GPS alıcılarından (2 adet) oluşan bir sistem. UTC(UME) zaman ölçeğinin belirsizliği 2×10⁻¹⁴’ün altında. UME ayrıca <strong>stronsiyum tabanlı optik latis saati</strong> projesini sürdürüyor; tamamlandığında Türkiye’nin zaman birimi gerçekleme doğruluğu 100 kattan fazla iyileşecek.</p>

<p>Optik saatler bir sonraki SI yeniden tanımının başında. CCTF (Time &amp; Frequency Consultative Committee) yol haritası 2030’a kadar saniye tanımının optik geçişlere kaymasını öngörüyor. O zaman sezyum, kilogramın IPK silindiri gibi tarihe karışacak.</p>

<h3 id="metre-saniyeden-türeyen-mesafe">Metre: Saniyeden Türeyen Mesafe</h3>

<p>Metre tanımı 1983’ten beri şudur: vakumda ışığın 1/299 792 458 saniyede aldığı yol. Yani metreyi gerçekleme problemi, <strong>ışık hızı</strong> ile bağlanmış bir frekans/zaman ölçme problemine indirgenir.</p>

<p>Pratikte metre, <strong>stabilize edilmiş lazerlerle</strong> gerçeklenir:</p>

<ul>
  <li>633 nm iyot-stabilize He-Ne lazer (BIPM önerilen liste, ~10⁻¹¹ kararlılık)</li>
  <li>532 nm iyot-stabilize Nd:YAG lazer</li>
  <li>1542 nm asetilen-stabilize lazer (telekomünikasyon dalga boyu)</li>
</ul>

<p>Bu lazerlerin frekansı sezyum saatine karşı sayılır (frekans tarağı/optik kombinasyon teknolojisi); böylece metre dolaylı olarak sezyumdan geliyor. Boy ölçümü ⇒ frekans ölçümü ⇒ saniye standardı ⇒ sezyum.</p>

<p>UME’de uzunluk laboratuvarı 633 nm iyot-stabilize HeNe lazerle çalışıyor; mekanik mihenkleri, blok mihenklerini, koordinat ölçüm cihazlarını bu lazerden türetilen interferometrik ölçümlerle kalibre ediyor.</p>

<h3 id="kilogram-kibble-terazisi-ve-planck-sabiti">Kilogram: Kibble Terazisi ve Planck Sabiti</h3>

<p>Reformun en dramatik tarafı kilogramda. 130 yıl boyunca kütle birimini Saint-Cloud’daki bir silindir tanımlıyordu. 20 Mayıs 2019’dan itibaren tanım şu: kilogram, Planck sabiti tam değerinden Kibble terazisi (veya eşdeğer yöntem) ile gerçeklenen kütledir.</p>

<p>Kibble terazisi (eskiden “watt terazisi”, Haziran 2016’da mucidi Bryan Kibble [1938-2016] anısına CCU kararıyla yeniden adlandırıldı) iki aşamada çalışır:</p>

<div class="mermaid">
flowchart TB
    subgraph weighing["1. TARTMA FAZI (statik)"]
        W1["Test kütlesi yerçekiminde:<br />F_grav = m · g"]
        W2["Bobinden akım geçer:<br />F_coil = B · L · I"]
        W3["Denge kurulur:<br /><b>m · g = B · L · I</b>"]
        W1 --&gt; W3
        W2 --&gt; W3
    end
    subgraph moving["2. HAREKET FAZI (dinamik)"]
        M1["Bobin manyetik alanda<br />kontrollü hızda hareket: v"]
        M2["Bobinde indüklenen voltaj:<br /><b>V = B · L · v</b>"]
        M1 --&gt; M2
    end
    COMBINE["İki fazı çarp ⇒ B·L sadeleşir<br /><b>m · g · v = V · I</b><br />(mekanik güç = elektrik güç)"]
    QUANTUM["V Josephson'dan (∝ h)<br />I = V_R / R, R kuantum Hall'den (∝ h/e²)<br />⇒ V·I tamamen Planck sabitiyle ifade edilir"]
    KG["m = h · (sayılan frekanslar²) / (g · v) · (sayısal sabitler)<br /><i>kilogram, başka bir kütleye değil h'ye karşı tartılır</i>"]
    weighing --&gt; COMBINE
    moving --&gt; COMBINE
    COMBINE --&gt; QUANTUM --&gt; KG
    style weighing fill:#fce4ec,stroke:#c2185b
    style moving fill:#e3f2fd,stroke:#1565c0
    style COMBINE fill:#fff9c4,stroke:#f57f17
    style QUANTUM fill:#e8f5e9,stroke:#2e7d32
    style KG fill:#1a73e8,color:#fff,stroke:#0c4ea2
</div>

<p>İki fazın püf noktası: tek başına <code class="language-plaintext highlighter-rouge">B·L</code> (manyetik alan × bobin uzunluğu) çarpımı çok hassas ölçülemez. Ama tartma fazında <code class="language-plaintext highlighter-rouge">B·L = m·g/I</code> ve hareket fazında <code class="language-plaintext highlighter-rouge">B·L = V/v</code> aynı çarpımdır; iki ifadeyi eşitlediğinizde <code class="language-plaintext highlighter-rouge">B·L</code> tamamen sadeleşir. Geriye kalan <code class="language-plaintext highlighter-rouge">m·g·v = V·I</code> ilişkisi, kütleyi yerçekimi ivmesi (g, mutlak gravimetrelerle ölçülür), hız (v, lazer interferometre), voltaj (V, Josephson) ve akım (I, kuantum Hall direnciyle ölçülen voltaj farkından) cinsinden verir. Sonuç: <code class="language-plaintext highlighter-rouge">m</code> doğrudan Planck sabitine bağlanır.</p>

<p>Kibble terazileri NIST-4 (ABD), NRC (Kanada), BIPM (Fransa), PTB (Almanya), NIM (Çin), KRISS (Güney Kore), LNE (Fransa) tarafından çalıştırılıyor. Tipik bağıl belirsizlikler 10⁻⁸ mertebesinde.</p>

<p><strong>Türkiye tarafı:</strong> UME, Kibble terazisi geliştirmesini 2014’te başlattı; ülke için kilogramın salınımlı mıknatıs (oscillating magnet) tipi Kibble terazisiyle gerçeklenmesi yolunu seçti. Bu tasarımda mıknatıs hareketsiz kütleyle birlikte titrer; sinyal frekans alanında okunur. Yayımlanan ön ölçümlerde 1 kg paslanmaz çelik artefakt 54 ppb (yaklaşık ±54 µg) bağıl belirsizlikle ölçüldü; aynı düzenekle Planck sabiti 6 ppm bağıl standart belirsizlikle elde edildi. Günlük kalibrasyon hizmeti hâlâ BIPM kalibrasyonlu transfer kilogram referansı üzerinden veriliyor; Kibble teraziyle gerçekleme tam üretim seviyesine geçildiğinde devreye alınacak.</p>

<p>Alternatif yöntem: <strong>Avogadro projesi</strong> veya <strong>X-ışını kristal yoğunluk (XRCD) yöntemi</strong>. Hassas işlenmiş tek kristal silisyum küresinin atom sayısı X-ışını difraksiyonu ile sayılıyor; N_A tam değer olduğundan kütle hesaplanıyor. Almanya’daki PTB bu yöntemin başlıca yürütücüsü; uluslararası IAC (International Avogadro Coordination) konsorsiyumunda LNE, NMIJ, INRIM, NIST de var. 2019’daki ilk uluslararası <code class="language-plaintext highlighter-rouge">kg</code> karşılaştırmasında (CCM.M-K8.2019) Kibble terazisi sonuçları XRCD sonuçlarıyla iyi tutarlılık gösterdi.</p>

<h3 id="volt-josephson-eklem-dizileri">Volt: Josephson Eklem Dizileri</h3>

<p>Süperiletken bir eklemden geçen elektronlar, eklem mikrodalga ile ışınlandığında <strong>kuantize voltaj basamakları</strong> üretir:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>V_n = n · f / K_J
K_J = 2e / h  (Josephson sabiti)
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">n</code> tam sayı (basamak numarası), <code class="language-plaintext highlighter-rouge">f</code> mikrodalga frekansı (sezyum saatten gelir), K_J ise temel sabitlerden türeyen <em>tam</em> bir sayı. Yani V tamamen sayılan bir frekansa bağlı; sıvı helyum sıcaklığında (4 K) eklem doğru çalıştığı sürece, voltaj <strong>doğa kanunu</strong> kadar kararlı.</p>

<p>Pratik cihaz: <strong>Programlanabilir Josephson Voltaj Standardı (PJVS)</strong>. On binlerce eklemin diziliminde dijital olarak basamak seçilebiliyor; istenen voltaj (0 – 10 V arası) belirleniyor. Tipik belirsizlik 1 part in 10⁹ — yani 10 V’ta ~0,01 µV.</p>

<p>Cihaz kullanışlı ama maliyetli ve karmaşık altyapı gerektiriyor: ya sıvı helyum (geleneksel) ya da kapalı çevrim cryocooler (modern, tercih edilen) ile 4 K civarına soğutma, hassas mikrodalga jeneratörü, manyetik ekranlama, geri besleme elektroniği. Bu nedenle PJVS dünyada büyük ölçüde NMI’lerde ve birkaç askeri/araştırma laboratuvarında bulunuyor; sıvı helyum tedariğinde dünya çapındaki sıkıntılar son yıllarda cryocooler tabanlı sistemlere geçişi hızlandırdı. UME’de DC Voltaj Laboratuvarı Josephson tabanlı sistemiyle hizmet veriyor; Türkiye’deki akredite kalibrasyon laboratuvarları DC voltaj izlenebilirliklerini buradan alıyor.</p>

<p>Dünyada NIST, PTB, NPL, BIPM, NMIJ, KRISS, NMIA başta olmak üzere pek çok NMI PJVS işletiyor. Bunların hepsi BIPM’in koordine ettiği sürekli karşılaştırmalara katılıyor (<strong>BIPM.EM-K10</strong> DC voltaj Josephson karşılaştırması; bağlı olarak BIPM.EM-K11 ile 1,018 V ve 10 V Zener referans karşılaştırmaları).</p>

<h3 id="ohm-kuantum-hall-etkisi">Ohm: Kuantum Hall Etkisi</h3>

<p>İki boyutlu elektron gazına sahip bir GaAs/AlGaAs yarı iletkeni 1,5 K sıcaklıkta ve 10 T manyetik alan altında ölçtüğünüzde, Hall direnci sürekli değil <strong>kuantize</strong> değerler alır:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>R_H = R_K / i
R_K = h / e²  (von Klitzing sabiti)
R_K = 25 812,807 45 Ω  (tam değer, h ve e tam olduğundan)
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">i</code> tam sayı (Landau seviyesi numarası, tipik olarak 1, 2, 3, 4); R_K von Klitzing sabiti, hidrojenden tutun da galaktik bulutlara kadar her yerde aynı.</p>

<p>i=2 platosunda direnç <strong>tam olarak</strong> 12 906,403 725 Ω — laboratuvarda hiç direnç telini ölçmeden, sadece manyetik alan ve sıcaklık doğru ayarlandığında. Bu plato genişliği yeterince büyükse (manyetik alan birkaç tesla aralığında), direnç değerinin kararlılığı 10⁻⁹ mertebesinde.</p>

<p>UME’de Kuantum Hall laboratuvarı 2010’lardan beri çalışıyor. Türkiye’deki tüm DC direnç ölçümlerinin tepe noktası burası. Direnç laboratuvarları periyodik olarak ESI SR104 veya benzeri 10 kΩ standart dirençlerini UME’ye gönderir; UME bunları kuantum Hall ile karşılaştırır, sertifikayla geri verir.</p>

<p>Josephson + kuantum Hall kombinasyonunun önemli bir yan etkisi var: ikisi birlikte kullanıldığında <strong>akım</strong> ve <strong>güç</strong> de doğrudan h ve e cinsinden ölçülebilir. Kibble terazisinin işleyişi tam olarak bu birlikteliğe dayanıyor. Aynı laboratuvar üç temel elektriksel birimi (V, Ω, A) ortak fizikten türetir.</p>

<h3 id="kelvin-boltzmanndan-pratik-sıcaklığa">Kelvin: Boltzmann’dan Pratik Sıcaklığa</h3>

<p>Sıcaklık biraz farklı bir hikâye. 2019 reformunda kelvin tanımı Boltzmann sabitine bağlandı:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>T = E / k  (E enerji, k Boltzmann sabiti)
</code></pre></div></div>

<p>Termodinamik sıcaklık ilkesel olarak ya <strong>akustik gaz termometresi</strong> (gaz içindeki ses hızı T’ye bağlı) ya da <strong>Johnson gürültüsü termometresi</strong> (bir direnç üzerinde termal gürültünün gücü T’ye bağlı) ile ölçülür. Bu yöntemler temel; ama günlük kalibrasyon için pratik değil — saatlerce ölçüm gerektiriyorlar.</p>

<p>Pratik dünyada kelvin <strong>ITS-90 (International Temperature Scale 1990)</strong> ile gerçeklenir. ITS-90, 0,65 K’den 1357 K’ye kadar sıcaklık aralığını <strong>17 sabit faz geçişi</strong> ile etiketler:</p>

<table>
  <thead>
    <tr>
      <th>Sabit nokta</th>
      <th>Sıcaklık (K)</th>
      <th>Sıcaklık (°C)</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Suyun üçlü noktası</td>
      <td>273,16</td>
      <td>0,01</td>
    </tr>
    <tr>
      <td>Galyum erime</td>
      <td>302,9146</td>
      <td>29,7646</td>
    </tr>
    <tr>
      <td>İndiyum donma</td>
      <td>429,7485</td>
      <td>156,5985</td>
    </tr>
    <tr>
      <td>Kalay donma</td>
      <td>505,078</td>
      <td>231,928</td>
    </tr>
    <tr>
      <td>Çinko donma</td>
      <td>692,677</td>
      <td>419,527</td>
    </tr>
    <tr>
      <td>Alüminyum donma</td>
      <td>933,473</td>
      <td>660,323</td>
    </tr>
    <tr>
      <td>Gümüş donma</td>
      <td>1234,93</td>
      <td>961,78</td>
    </tr>
  </tbody>
</table>

<p>Suyun üçlü noktası en kritiği: özel olarak hazırlanmış cam hücrelerde (TPW cell, triple point of water) buz, sıvı ve buhar dengede; sıcaklık tam olarak 273,16 K. Bu hücreler dünyada birkaç laboratuvarda üretilir; UME’nin de kendi TPW hücreleri var.</p>

<p>Sıcaklık piramidi şöyle çalışıyor: SI tanımı (Boltzmann) ile birincil termometreler (akustik gaz/Johnson gürültüsü) ITS-90 sabit noktalarını <strong>doğrular</strong>; UME bu sabit noktaları muhafaza eder; akredite laboratuvarlar UME’den izlenebilirlik alır; sanayi termometreleri akredite laboratuvarlardan kalibre olur. Sıradan bir PT100 sensörünün kalibrasyon belgesindeki belirsizlik, son tahlilde Boltzmann sabitine ve ITS-90 hücrelerine bağlanır.</p>

<blockquote>
  <p><strong>Akılda kalsın — birincil ile pratik aynı şey değil:</strong> Kelvin SI’da Boltzmann üzerinden tanımlı, ama dünyada hiçbir kalibrasyon laboratuvarı doğrudan akustik gaz termometresi kullanmaz. Pratik referans ITS-90’dır. Tanım fiziksel, gerçekleme tarihsel ve pratik. İkisi arasındaki tutarlılığı NMI’ler üst düzey karşılaştırmalarla kontrol eder.</p>
</blockquote>

<h3 id="birincil-gerçeklemelerin-karşılaştırması">Birincil Gerçeklemelerin Karşılaştırması</h3>

<p>Yedi SI temel biriminin en iyi gerçekleme belirsizlikleri arasında 15 mertebelik bir uçurum var. Saniye en hassas, kandela en kaba. Bu fark hem tarihsel hem de fiziksel: bazı olgular daha kararlı, bazılarını ölçmek daha zor.</p>

<div id="grafik-si-belirsizlik" style="width:100%;max-width:760px;margin:1.5rem auto 2.5rem auto;height:380px;"></div>
<script>
(function(){
  var data = [{
    type: 'bar',
    orientation: 'h',
    x: [8.1e-19, 1e-11, 1.5e-8, 1e-9, 1e-9, 1e-7, 1e-4],
    y: ['Saniye (Sr optik latis saati)', 'Metre (iyot-stabilize HeNe)', 'Kilogram (Kibble terazisi)', 'Amper (Josephson + QHE üzerinden)', 'Mol (XRCD / Si küre)', 'Kelvin (akustik gaz termometresi)', 'Kandela (kriyojenik radyometre)'],
    text: ['8×10⁻¹⁹', '~10⁻¹¹', '~1,5×10⁻⁸', '~10⁻⁹', '~10⁻⁹', '~10⁻⁷', '~10⁻⁴'],
    textposition: 'auto',
    marker: { color: ['#1a73e8', '#1976d2', '#1565c0', '#0d47a1', '#2e7d32', '#c62828', '#b71c1c'] }
  }];
  var layout = {
    title: { text: '7 SI temel biriminin en iyi gerçekleme belirsizlikleri (bağıl, log eksen)', font: { size: 14 } },
    xaxis: { title: 'Bağıl belirsizlik (log eksen)', type: 'log', autorange: true },
    yaxis: { autorange: 'reversed' },
    margin: { l: 280, r: 30, t: 50, b: 60 },
    plot_bgcolor: '#ffffff',
    paper_bgcolor: '#ffffff'
  };
  Plotly.newPlot('grafik-si-belirsizlik', data, layout, {responsive: true, displayModeBar: false});
})();
</script>

<p>Grafiği okumak: saniye gerçeklemesi 10¹⁵ kat daha hassas (8×10⁻¹⁹) iken kandelanın gerçeklemesi 10⁻⁴ mertebesinde. Bu, kandelanın “kötü” tanımlanması demek değil — fiziksel olgu (insan gözünün spektral duyarlılığı) doğası gereği belirsiz. Saniye ise atomik geçişe dayanıyor; daha kararlı bir olgu yok.</p>

<p>Pratik sonuç: bir test mühendisi için frekans ölçümü daima en güvenilir; sıcaklık ve aydınlatma ölçümleri en kaba. Belirsizlik bütçenizde bu mertebe farkı yansır.</p>

<hr />

<h2 id="uluslararası-karşılaştırmalar-cipm-mra">Uluslararası Karşılaştırmalar (CIPM MRA)</h2>

<p>Diyelim UME’nin Josephson voltaj standardı 10 V’ta 0,01 µV belirsizlik beyan ediyor. Bunun gerçekten doğru olduğunu nasıl biliyoruz? Hiçbir cihaza karşı kalibre etmediğimize göre — peki <em>yanılıyor</em> olabilir mi? Mesela laboratuvarın mikrodalga jeneratörü kalibrasyondan kaymış, ekleme yanlış frekans gönderiyor olabilir mi?</p>

<p>Bu olasılığı sıfırlamanın tek yolu <strong>uluslararası karşılaştırma</strong>. Aynı 10 V’u dünyanın farklı bir laboratuvarında, bağımsız bir Josephson sisteminde de üretip iki sonucu karşılaştırırsanız, ikisinin tutarlı olması (beyan edilen belirsizliklerin altında) sistemin sağlıklı çalıştığının kanıtıdır.</p>

<p>Bu süreç <strong>CIPM MRA (Mutual Recognition Arrangement)</strong> çatısı altında yürütülür. 14 Ekim 1999’da Paris’te 38 üye devletin NMI direktörleri ve iki uluslararası kuruluş tarafından imzalanan MRA, üye ülkelerin metroloji enstitülerinin birbirinin sertifikalarını karşılıklı tanımasını sağlar. <strong>Türkiye TÜBİTAK UME aracılığıyla 1999 kuruluş imzacılarından biri.</strong> Bugün 62 üye devlet, 40 ortak ve 4 uluslararası kuruluşu, toplam 250’yi aşkın enstitüyü kapsıyor. MRA’nın iki ayağı var: <strong>Anahtar Karşılaştırmalar (Key Comparisons)</strong> ve <strong>CMC kayıtları</strong>.</p>

<div class="mermaid">
flowchart TB
    BIPM["<b>BIPM</b><br />Karşılaştırmayı koordine eder<br />Pilot laboratuvar atar"]
    TS["<b>Transfer Standardı</b><br />(örn. zener voltaj referansı,<br />1 kg paslanmaz çelik kütle, ...)"]
    NMI1["NMI 1 (NIST)<br />ölçer, raporlar"]
    NMI2["NMI 2 (PTB)<br />ölçer, raporlar"]
    NMI3["NMI 3 (UME)<br />ölçer, raporlar"]
    NMI4["NMI 4 (NPL)<br />ölçer, raporlar"]
    PILOT["<b>Pilot Lab</b><br />verileri toplar<br />Referans değer (KCRV)<br />her NMI için ofset (D_i)"]
    KCDB["<b>KCDB</b><br />(Key Comparison Database)<br />açık erişim"]
    BIPM --&gt; TS
    TS --&gt; NMI1
    TS --&gt; NMI2
    TS --&gt; NMI3
    TS --&gt; NMI4
    NMI1 --&gt; PILOT
    NMI2 --&gt; PILOT
    NMI3 --&gt; PILOT
    NMI4 --&gt; PILOT
    PILOT --&gt; KCDB
    style BIPM fill:#1a73e8,color:#fff
    style TS fill:#fbbc04,color:#000
    style PILOT fill:#34a853,color:#fff
    style KCDB fill:#673ab7,color:#fff
</div>

<p>Akış şöyle: BIPM bir karşılaştırma planlar, pilot laboratuvar atar. Pilot, bir transfer standardını (örneğin Fluke 7000 zener voltaj referansı, 1 kg paslanmaz çelik kütle, 100 Ω resistör) hazırlar ve katılımcı NMI’lere gönderir. Her NMI standardı kendi birincil sistemine karşı ölçer ve sonucu raporlar. Pilot, sonuçları toplar; ağırlıklı ortalamadan <strong>referans değeri (KCRV — Key Comparison Reference Value)</strong> hesaplar; her NMI için sapmayı (D_i) yayınlar. Tüm sonuçlar <strong>KCDB</strong> açık veritabanında saklanır.</p>

<p>Karşılaştırmaların adlandırması: koordinatör kuruluşun kodu + alanı belirten alt komite + sıra numarası. Birkaç tipik örnek:</p>

<table>
  <thead>
    <tr>
      <th>Kod</th>
      <th>Karşılaştırma alanı</th>
      <th>Tipik transfer standardı</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>BIPM.EM-K10</td>
      <td>DC voltaj — Josephson (sürekli karşılaştırma)</td>
      <td>BIPM transfer Josephson sistemi</td>
    </tr>
    <tr>
      <td>BIPM.EM-K11</td>
      <td>1,018 V ve 10 V Zener referansları</td>
      <td>zener voltaj referansı (Fluke 732B vb.)</td>
    </tr>
    <tr>
      <td>CCT-K7 / CCT-K7.2021</td>
      <td>suyun üçlü noktası (TPW)</td>
      <td>TPW hücreleri</td>
    </tr>
    <tr>
      <td>CCT-K9</td>
      <td>ITS-90 sabit noktaları (83,8 K – 692,7 K, çinko, galyum, kalay vb.)</td>
      <td>platin direnç termometre</td>
    </tr>
    <tr>
      <td>CCM.M-K8</td>
      <td>1 kg gerçeklemeleri (Kibble + XRCD, 2019/2021/2024)</td>
      <td>paslanmaz çelik kütle</td>
    </tr>
    <tr>
      <td>CCL-K11</td>
      <td>optik frekans / dalga boyu (sürekli)</td>
      <td>iyot-stabilize He-Ne 633 nm vb.</td>
    </tr>
  </tbody>
</table>

<p>Her NMI’nin verdiği değerin <strong>belirsizlik bütçesini aşacak şekilde</strong> sapması, problem işaretidir. Örnek olarak 2021-2022’de yapılan <strong>CCT-K7.2021</strong> karşılaştırmasında, 21 katılımcı NMI’nin TPW gerçeklemeleri arasındaki <strong>maksimum fark 111 µK, standart sapma 28 µK</strong> olarak rapor edildi — yani uluslararası sıcaklık ölçeğinin koordinasyonu sub-mK seviyesinde tutarlı. Eğer bir NMI 1 mK saparsa, hücreleri yeniden değerlendirilir, kapsamı revize edilir, sertifikalardaki belirsizlik artar.</p>

<p>Karşılaştırmaların ikinci ürünü <strong>CMC (Calibration and Measurement Capability)</strong> beyanları. CMC, bir NMI’nin sunduğu rutin kalibrasyon hizmeti için <strong>beyan edilebilir en iyi belirsizliği</strong> ifade eder. Akran değerlendirmesinden geçer, KCDB’de yayınlanır. Türk sanayicisi UME’den hangi alanda hangi belirsizlikle hizmet alabileceğini buradan görür; aynı sayfada NIST veya PTB’nin aynı kapsamı görür ve karşılaştırır.</p>

<blockquote>
  <p><strong>Akılda kalsın — birincil standart kontrolü iki katmanlıdır:</strong> İçsel olarak fiziksel sabite bağlanır (gerçekleme), dışsal olarak başka NMI’lerin gerçeklemeleriyle karşılaştırılır (KC). Tek katmandan biri kaymışsa diğer katmandan yakalanır.</p>
</blockquote>

<hr />

<h2 id="tübi̇tak-ume-ve-türkiyenin-birincil-standartları">TÜBİTAK UME ve Türkiye’nin Birincil Standartları</h2>

<p>UME, 11 Ocak 1992’de TÜBİTAK Marmara Araştırma Merkezi bünyesinde, Gebze’de kuruldu. Bugün çok sayıda laboratuvarda zaman/frekans, elektriksel, kütle, uzunluk, sıcaklık, basınç, kuvvet, akustik, fotometri ve iyonlaştırıcı radyasyon alanlarında birincil standart işletiyor.</p>

<p>Yaklaşık başlık başlık birincil yetenekler (kesin değerler için KCDB’ye bakılmalı):</p>

<table>
  <thead>
    <tr>
      <th>Alan</th>
      <th>Birincil cihaz/yöntem</th>
      <th>Tipik belirsizlik mertebesi</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Zaman/frekans</td>
      <td>1 hidrojen maser + 5 sezyum atom saati ensemble (UTC(UME)); TAI’ye katkı 1994’ten beri; stronsiyum optik latis saati geliştirme aşamasında</td>
      <td>UTC(UME) &lt; 2×10⁻¹⁴</td>
    </tr>
    <tr>
      <td>DC voltaj</td>
      <td>Programlanabilir Josephson (PJVS)</td>
      <td>~10⁻⁹</td>
    </tr>
    <tr>
      <td>DC direnç</td>
      <td>Kuantum Hall etkisi</td>
      <td>~10⁻⁹</td>
    </tr>
    <tr>
      <td>Kütle (1 kg)</td>
      <td>Salınımlı mıknatıs Kibble terazisi (geliştirme; ön ölçümler 54 ppb); BIPM kalibrasyonlu transfer prototipi (servis)</td>
      <td>~50 µg (transfer)</td>
    </tr>
    <tr>
      <td>Uzunluk</td>
      <td>İyot-stabilize He-Ne lazer (633 nm) + frekans tarağı</td>
      <td>~10⁻¹¹</td>
    </tr>
    <tr>
      <td>Sıcaklık</td>
      <td>ITS-90 sabit nokta hücreleri + SPRT’ler + birincil radyasyon termometresi</td>
      <td>~50 µK (suyun üçlü noktası mertebesi)</td>
    </tr>
    <tr>
      <td>Basınç</td>
      <td>Piston-silindir basınç dengesi</td>
      <td>~10⁻⁵ mertebesi</td>
    </tr>
    <tr>
      <td>Kuvvet</td>
      <td>Karşılaştırma kuvvet ölçer makinesi</td>
      <td>~10⁻⁵ mertebesi</td>
    </tr>
    <tr>
      <td>Akustik</td>
      <td>Karşılıklı (reciprocity) basınç-pistonfon kalibrasyonu</td>
      <td>~0,05 dB</td>
    </tr>
  </tbody>
</table>

<p>UME’nin KCDB’deki CMC kayıtları herkese açık. Türk akredite kalibrasyon laboratuvarları (TÜRKAK belgesi alanlar) UME’den izlenebilirlik alır; akredite olmayan iç laboratuvarlar (örneğin bir fabrikanın kalite kontrol bölümü) ya doğrudan UME’ye giderler ya da bir akredite labdan hizmet alırlar.</p>

<p>Aviyonik ve savunmada tipik bir akış şöyle olur. TUSAS’ın bir uçak gövdesinde kullandığı <strong>PT100 sıcaklık sensörü</strong>, üretici dokümanına göre 6 ayda bir kalibre edilmeli. TUSAS bunu TÜRKAK akredite bir kalibrasyon laboratuvarına gönderir; lab kendi referans termometresini (genelde ikinci sınıf Standart Platin Direnç Termometresi, SPRT) kullanarak fırın içinde sensörü doğrular. O lab kendi SPRT’sini her 1-2 yılda UME’ye gönderir; UME ITS-90 sabit noktalarında SPRT’yi karakterize eder. UME’nin sabit nokta hücreleri belirli aralıklarla CCT-K7, CCT-K9 anahtar karşılaştırmalarına katılır — yani başka NMI’lerin TPW hücreleriyle, başka galyum-erime hücreleriyle çapraz kontrol edilir.</p>

<p>Bu zincirin yedi halkası var: <strong>Boltzmann sabiti → ITS-90 → UME hücreleri → SPRT → akredite lab → PT100 → uçak</strong>. Her halka bir kalibrasyon belgesi, bir izlenebilirlik kanıtı taşır. Ucundaki sayı (uçaktaki PT100’ün okuduğu sıcaklık) ancak zincir baştan sona sağlamsa anlamlı.</p>

<hr />

<h2 id="belirsizlik-piramidi-yukarıdan-aşağıya">Belirsizlik Piramidi: Yukarıdan Aşağıya</h2>

<p>Önceki yazıda <strong>u_birleşik</strong> kavramını tanıttık: birden çok belirsizlik kaynağının karekök kareler toplamı. İzlenebilirlik zincirinin her aktarımı, mevcut belirsizliğin üzerine yeni bir katkı ekler. Tipik bir DC voltaj zincirinde aşağıdaki gibi büyür:</p>

<table>
  <thead>
    <tr>
      <th>Seviye</th>
      <th>Cihaz</th>
      <th>Tipik U(10 V)</th>
      <th>Bağıl belirsizlik</th>
      <th>Tipik maliyet</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>1 — UME</td>
      <td>Programlanabilir Josephson</td>
      <td>0,05 µV</td>
      <td>5 ppb</td>
      <td>$400k+</td>
    </tr>
    <tr>
      <td>2 — Akredite lab</td>
      <td>Fluke 732C bank + 3458A</td>
      <td>5 µV</td>
      <td>0,5 ppm</td>
      <td>$80k+</td>
    </tr>
    <tr>
      <td>3 — Sanayi lab</td>
      <td>Fluke 5720A kalibratör</td>
      <td>50 µV</td>
      <td>5 ppm</td>
      <td>$30k+</td>
    </tr>
    <tr>
      <td>4 — Saha</td>
      <td>Keysight 34465A multimetre</td>
      <td>500 µV</td>
      <td>50 ppm</td>
      <td>$4k+</td>
    </tr>
  </tbody>
</table>

<p>Her seviyede bağıl belirsizlik yaklaşık 10× kötüleşiyor. Bu pratik bir sonuç değil, kalibrasyon sürecinin doğasından geliyor: her aktarımda transfer cihazının kendi katkısı, ortam etkileri (sıcaklık, nem, EMG), operatör katkısı, kabloların direnci eklenir. Üç-dört katkıyı kareli toplamla birleştirdiğinizde sonuç yaklaşık on kat artar.</p>

<div id="grafik-zincir" style="width:100%;max-width:760px;margin:1.5rem auto 2.5rem auto;height:380px;"></div>
<script>
(function(){
  var data = [{
    type: 'bar',
    orientation: 'h',
    x: [0.05, 5, 50, 500],
    y: ['Seviye 1: UME (Josephson)', 'Seviye 2: Akredite lab (Fluke 732C + 3458A)', 'Seviye 3: Sanayi lab (Fluke 5720A)', 'Seviye 4: Saha multimetresi (Keysight 34465A)'],
    text: ['0,05 µV (5 ppb)', '5 µV (0,5 ppm)', '50 µV (5 ppm)', '500 µV (50 ppm)'],
    textposition: 'auto',
    marker: { color: ['#1a73e8', '#e8711a', '#c62828', '#6a1b9a'] }
  }];
  var layout = {
    title: { text: '10 V için Beklenen Belirsizlik (zincirin her seviyesinde)', font: { size: 14 } },
    xaxis: { title: 'Genişletilmiş belirsizlik U (µV) — log eksen', type: 'log' },
    yaxis: { autorange: 'reversed' },
    margin: { l: 280, r: 30, t: 50, b: 60 },
    plot_bgcolor: '#ffffff',
    paper_bgcolor: '#ffffff'
  };
  Plotly.newPlot('grafik-zincir', data, layout, {responsive: true, displayModeBar: false});
})();
</script>

<p>Grafikten çıkan ders şu: <strong>alttaki cihazınızın belirsizliği üstteki halkaların belirsizliklerine bağımlıdır</strong>. Multimetreyle 50 ppm okuyabiliyorsanız, kalibratörünüz 5 ppm sunuyor olmalı; kalibratörünüzü kalibre eden lab 0,5 ppm sunmalı; o labın referansı 5 ppb olmalı. Dört halka. Birinde sorun varsa, sayısal değer altta düzgün okunsa bile <strong>anlamı yok</strong>.</p>

<p>Bunun pratik karşılığı: kalibrasyon sertifikasında “UME izlenebilirliği” yazsa bile zincirde halka eksikse (bir halkadaki cihazın geçerli akreditasyonu yoksa, ya da belge süresi geçmişse) tüm zincir geçersiz. Akreditasyon denetiminde ilk sorulan sorular tam olarak bunu test eder.</p>

<blockquote>
  <p><strong>Akılda kalsın — TUR’unuz sizinle değil zincirinizle başlar:</strong> Multimetrenizle 50 ppm okuyabilmek için zincirin tepesinde 5 ppb belirsizlikli bir Josephson sistemine ihtiyacınız var. Aradaki halkalardan biri kayarsa hepsi etkilenir. Belirsizlik bütçenizdeki “sertifika belirsizliği” tek satırı, aslında tüm üst zincirin damıtılmış halidir.</p>
</blockquote>

<hr />

<h2 id="kalibrasyon-sertifikasından-i̇zlenebilirlik-çıkarımı">Kalibrasyon Sertifikasından İzlenebilirlik Çıkarımı</h2>

<p>Önceki yazıda akreditasyon denetiminde sorulanlar listesi vermiştik. Bu yazının pratik sonucu olarak listeyi izlenebilirlik tarafına genişletelim. Eline kalibrasyon sertifikası geldiğinde test mühendisinin sorması gereken sorular:</p>

<ul>
  <li><strong>Sertifikayı veren laboratuvar akredite mi?</strong> TÜRKAK numarası (örn. AB-0001-K) veya muadil bir ILAC üyesi akreditasyon kuruluşu numarası olmalı. Akreditasyon kapsam belgesi sorularak doğrulanır; ölçüm büyüklüğünüzün kapsamda olduğundan emin olun.</li>
  <li><strong>Kullanılan üst kademe ekipmanın seri numarası belirtilmiş mi?</strong> “Fluke 5720A, S/N 9876543” gibi. Bu olmadan zincir kanıtlanamaz.</li>
  <li><strong>Üst kademe ekipmanın bir önceki kalibrasyonunun belge numarası ve tarihi yazılmış mı?</strong> “Reference instrument: UME ID K-2024-…” şeklinde. Sertifika tarihiniz, üst kademe sertifikanın geçerlilik süresi içinde olmalı.</li>
  <li><strong>Beyan edilen belirsizlik U + k + PDF varsayımı içeriyor mu?</strong> “U = 28 µV, k=2, normal dağılım” yeterli; sadece “± 28 µV” yetersiz.</li>
  <li><strong>TUR ≥ 4 sağlanıyor mu?</strong> Cihazınızın spec’i ile sertifika belirsizliği oranı 4’ün altındaysa, kabul/red kararı için güvenlik payı (guard band) hesaplanmalı.</li>
  <li><strong>Çevre koşulları belgelenmiş mi?</strong> Sertifika ölçüm sırasındaki sıcaklık (genelde 23 ± 2 °C) ve nem değerlerini içermeli. Sizin laboratuvarınızda koşullar farklıysa düzeltme veya ek belirsizlik gerekir.</li>
  <li><strong>Süre sonu belirtilmiş mi?</strong> “Geçerlilik 1 yıl”, “kalibrasyon aralığı kullanıcı sorumluluğunda” vb. ayrımına dikkat edin.</li>
  <li><strong>Izlenebilirlik beyanı genel mi yoksa NMI numarasıyla mı?</strong> “Traceable to SI through UME via … “ spesifikse iyi; sadece “Traceable to NIST/UME” cümlesi tek başına yeterli kanıt değil.</li>
</ul>

<p>Bu sekiz madde aslında zincirin her halkasını sorgulayan tek bir kontrol listesi. Bir tanesi cevapsız kalıyorsa zincirde kopukluk var demektir; bu durumda kalibrasyon sertifikası işinize yaramaz.</p>

<hr />

<h2 id="sonuç">Sonuç</h2>

<p>“Saatçinin saatini kim kalibre eder?” sorusunun cevabı — biraz şaşırtıcı bir biçimde — <em>kimse</em>. Zincirin tepesinde bir cihaz değil, bir doğa kanunu var. Sezyum fıskiyesi, Kibble terazisi, Josephson eklem dizisi, kuantum Hall örnekleri başka bir cihaza karşı kalibre edilmez; doğrudan fiziksel sabitleri <strong>gerçekler</strong>. 2019 SI yeniden tanımı bu fikri tüm temel birimlere taşıdı: artık bir kilogram bile bir parçaya değil, Planck sabitine bağlı.</p>

<p>Birincil standartların kendi içlerindeki tutarlılığı <strong>uluslararası karşılaştırmalar</strong> garanti ediyor. CIPM MRA çatısı altında BIPM koordinasyonunda yürütülen anahtar karşılaştırmalar (KC), her NMI’nin gerçeklemesini diğerleriyle düzenli olarak çapraz kontrol ediyor; sonuçlar KCDB’de açık. UME bu sürecin aktif bir parçası — Türk sanayisi ve test mühendisi, UME üzerinden dünya birincil standart sistemine bağlı.</p>

<p>Bir test mühendisi için pratik mesaj kalın çizgilerle şu: kalibrasyon sertifikanızı sadece imzalı bir kâğıt olarak değil, bir <strong>zincir kanıtı</strong> olarak okuyun. Halkaları sayın. Eksik halka varsa “geçti/kaldı” kararınızın altında imzanız var, onun altında da sizin doğruladığınızı varsaydığınız zincir. Zincir kopuksa karar da kopuktur.</p>

<p>Önceki yazıda söz verdiğimiz <strong>Monte Carlo simülasyonu</strong> yazısı hâlâ yolda. Doğrusal olmayan ölçüm modellerinde GUM’un karekök kareler toplam yaklaşımı yetersiz kalıyor; bilgisayarda 100 000 simülasyon yaparak dağılımı doğrudan üretmek gerekiyor. Bir sonraki yazıda RP-12 Ek B’nin uygulamalı versiyonunu yazacağız — önceki yazıdaki üç örneği Monte Carlo ile yeniden çözeceğiz, sonuçları klasik GUM hesabıyla karşılaştıracağız.</p>

<hr />

<h2 id="kaynaklar">Kaynaklar</h2>

<ul>
  <li><a href="https://www.bipm.org/en/publications/si-brochure">BIPM — SI Brochure (9. baskı, 2019)</a></li>
  <li><a href="https://www.bipm.org/en/committees/cg/cgpm/26-2018/resolution-1">BIPM — Resolution 1 of the 26th CGPM (2018) — SI yeniden tanımı</a></li>
  <li><a href="https://www.bipm.org/en/cipm-mra">BIPM — CIPM MRA ana sayfası</a></li>
  <li><a href="https://www.bipm.org/kcdb/">BIPM — KCDB (Key Comparison Database)</a></li>
  <li><a href="https://www.bipm.org/en/mass-metrology/kibble-balance">BIPM — Kibble balance ana sayfası</a></li>
  <li><a href="https://www.nist.gov/si-redefinition">NIST — SI Yeniden Tanımı (2019) genel sayfası</a></li>
  <li><a href="https://www.nist.gov/atomic-clocks/how-atomic-clocks-work/fountains-atoms-exquisite-timekeepers">NIST — “How Atomic Clocks Work” (sezyum fıskiyesi açıklaması)</a></li>
  <li><a href="https://www.nist.gov/programs-projects/redefining-kilogram-kibble-balance">NIST — NIST-4 Kibble Balance proje sayfası</a></li>
  <li><a href="https://www.npl.co.uk/si-units">NPL — “What is the SI?” eğitim sayfası</a></li>
  <li><a href="https://www.npl.co.uk/about-us/history/famous/bryan-kibble">NPL — Bryan Kibble biyografi</a></li>
  <li><a href="https://www.ptb.de/cms/en/ptb/fachabteilungen/abt4/fb-44/ag-441/realisation-of-the-si-second.html">PTB — Atomic Fountain Clock CSF1 ve CSF2</a></li>
  <li><a href="https://iopscience.iop.org/article/10.1088/0026-1394/53/5/A46">Stock, M. — “The Watt or Kibble Balance: a Technique for Implementing the New SI Definition of the Unit of Mass”, <em>Metrologia</em> 53 (2016)</a></li>
  <li><a href="https://www.bipm.org/en/committees/cc/cct/publications-cc.html">BIPM — ITS-90 Defining Document</a></li>
  <li><a href="https://www.researchgate.net/publication/365573229_A_UME_Kibble_balance_displacement_measurement_procedure">Ahmedov H. ve ark. — “A UME Kibble Balance Displacement Measurement Procedure” (UME Kibble terazisi)</a></li>
  <li><a href="https://www.ume.tubitak.gov.tr/en/laboratuvarlarimiz/time-frequency-and-wavelength-laboratories">TÜBİTAK UME — Zaman ve Frekans Laboratuvarı</a></li>
  <li><a href="https://www.ume.tubitak.gov.tr/">TÜBİTAK UME — Ulusal Metroloji Enstitüsü ana sayfası</a></li>
  <li><a href="https://www.turkak.org.tr/">TÜRKAK — Akreditasyon Kapsam Sorgulama</a></li>
  <li><a href="https://ilac.org/">ILAC — Uluslararası Laboratuvar Akreditasyonu Birliği</a></li>
  <li><a href="https://jila.colorado.edu/yelabs">JILA — Optik Latis Saat Çalışmaları (Ye Lab)</a></li>
  <li><a href="https://en.wikipedia.org/wiki/2019_revision_of_the_SI">Wikipedia — 2019 redefinition of the SI base units (özet)</a></li>
</ul>]]></content><author><name>M. Serdar Karaman</name></author><category term="muhendislik" /><category term="metroloji" /><summary type="html"><![CDATA[]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://karaman.dev/img/og-default.webp" /><media:content medium="image" url="https://karaman.dev/img/og-default.webp" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry xml:lang="tr"><title type="html">Ölçtüğünüz Sayı Ne Kadar Doğru? Ölçüm Belirsizliği için Bir Rehber</title><link href="https://karaman.dev/2026/05/06/olcum-belirsizligi-gum-annex-f-ncsli-rp-12.html" rel="alternate" type="text/html" title="Ölçtüğünüz Sayı Ne Kadar Doğru? Ölçüm Belirsizliği için Bir Rehber" /><published>2026-05-06T09:00:00+00:00</published><updated>2026-05-06T09:00:00+00:00</updated><id>https://karaman.dev/2026/05/06/olcum-belirsizligi-gum-annex-f-ncsli-rp-12</id><content type="html" xml:base="https://karaman.dev/2026/05/06/olcum-belirsizligi-gum-annex-f-ncsli-rp-12.html"><![CDATA[<script src="https://cdn.plot.ly/plotly-basic-2.27.0.min.js"></script>

<p>Test laboratuvarındaki ilk gününüz. Önünüzdeki multimetre 24,98 V gösteriyor. Test belgesi diyor ki: cihazın çıkışı 24 V ± 1 V olmalı. Yan masadaki kıdemli mühendis formun üstüne büyük harflerle “GEÇTİ” yazıyor. Doğru değer 24,98 V. Sınırın çok içinde. Tamam.</p>

<p>Ama dur. O ekrandaki 24,98 sayısı ne kadar gerçeği yansıtıyor? Multimetre dün kalibre edildi. Kabloların kendi direnci var. Oda sıcaklığı sabah 21 °C iken öğleden sonra 25 °C oldu. Bakır konnektörlerde küçük gerilimler oluşuyor. Bunların hepsi, ekrandaki sayının yanına bir hata payı ekliyor. Eğer bu pay 5 mV ise sorun yok. Ama ya 1,5 V ise? O zaman cihaz gerçekte 23,5 V ya da 26,5 V çıkış veriyor olabilir. Sınırın dışında, yani aslında geçmemiş.</p>

<p>İşte bu hata payına <strong>ölçüm belirsizliği</strong> diyoruz. Bu yazının amacı, belirsizliği nasıl hesapladığınızı sıfırdan anlatmak. İki uluslararası kılavuza dayanacağız. Birincisi <strong>GUM</strong> (Türkçe açılımıyla “Ölçüm Belirsizliğinin İfadesi Kılavuzu”), uluslararası referans. İkincisi <strong>NCSLI RP-12</strong>, ABD kalibrasyon mühendislerinin yazdığı pratik el kitabı. Üç gerçek örnek üzerinden hesabı tamamlayacağız: bir voltmetre, bir sıcaklık sensörü, bir basınç sensörü. Sonra aviyonik UUT üreticisi bir şirketin neden farklı bir disiplinle çalışması gerektiğini somut bir VOR/ILS alıcısı örneği üzerinden inceleyeceğiz. Sayılar gerçek, formüller gerçek; dil olabildiğince sade.</p>

<hr />

<h2 id="bu-belgeler-nereden-çıktı">Bu Belgeler Nereden Çıktı?</h2>

<p>Ölçüm belirsizliği bilimi yaklaşık 50 yıllık. Aşağıdaki zaman çizelgesi ana adımları gösteriyor.</p>

<div class="mermaid">
flowchart TB
    A["<b>1977</b> &nbsp; CIPM, BIPM'e talimat verdi<br /><i>Ortak bir dile geçilmesi sağlanmalı</i>"]
    B["<b>1980</b> &nbsp; INC-1 kararı<br />Tip A ve Tip B kavramları ilk kez"]
    C["<b>1993</b> &nbsp; İlk GUM yayını<br />ISO + IEC + OIML + BIPM ortak imza"]
    D["<b>1995</b> &nbsp; İlk NCSLI RP-12 yayımlandı"]
    E["<b>2006</b> &nbsp; ANSI Z540.3 standardı<br />Yanlış kabul olasılığı %2 sınırı"]
    F["<b>2008</b> &nbsp; JCGM 100:2008 + JCGM 101<br />GUM yenilendi, Monte Carlo eklendi"]
    G["<b>2013</b> &nbsp; NCSLI RP-12 yeni baskı<br />Howard Castrup öncülüğünde"]
    H["<b>2020</b> &nbsp; JCGM GUM-6<br />Modelleme ve uygulama rehberi"]
    A --&gt; B --&gt; C --&gt; D --&gt; E --&gt; F --&gt; G --&gt; H
    style A fill:#e8eef7,stroke:#4a6fa5,stroke-width:2px
    style B fill:#dbe7f5,stroke:#4a6fa5,stroke-width:2px
    style C fill:#cee0f3,stroke:#4a6fa5,stroke-width:2px
    style D fill:#bfd6f0,stroke:#4a6fa5,stroke-width:2px
    style E fill:#aecbed,stroke:#4a6fa5,stroke-width:2px
    style F fill:#9cc0e9,stroke:#3a5f95,stroke-width:2px
    style G fill:#88b3e5,stroke:#3a5f95,stroke-width:2px
    style H fill:#73a6e0,stroke:#2a4f85,stroke-width:2px,color:#fff
</div>

<p>1970’lerde dünyada ölçüm yapan büyük kurumlar — Amerika’da NIST, İngiltere’de NPL, Almanya’da PTB, Fransa’da BIPM — ortak bir derde sahipti. Hepsi aynı miktarı ölçüyordu (1 metrenin uzunluğu, 1 kilogramın ağırlığı), ama her biri farklı şekilde rapor ediyordu. Kimi “± 0,1 mm” yazıyordu, kimi “%95 güvenle 0,15 mm”. Sonuçları karşılaştırmak çok zordu.</p>

<p>1977’de uluslararası ağırlıklar ve ölçümler komitesi <strong>CIPM</strong>, alt birimi olan BIPM’den bu sorunu çözmesini istedi. BIPM, 1980’de 11 ulusal metroloji laboratuvarından uzmanları bir araya getirdi ve “Belirsizlik Beyanı Çalışma Grubu” toplandı. Çalışma grubunun çıkardığı <strong>INC-1 (1980)</strong> kararı, bugün hâlâ kullandığımız iki kavramı tanımladı:</p>

<ul>
  <li><strong>Tip A belirsizlik:</strong> Aynı ölçümü defalarca yaparak, çıkan sayıların ne kadar dağıldığına bakarak hesaplanan belirsizlik. Örneğin cihazı 10 kez ölçüp standart sapmayı hesaplamak.</li>
  <li><strong>Tip B belirsizlik:</strong> Tekrarlı ölçüm dışındaki her bilgi. Kalibrasyon belgesi, üretici kataloğu, geçmiş deneyim.</li>
</ul>

<p>13 yıl sonra, 1993’te bu fikirler genişletildi ve uluslararası dört kuruluş (ISO, IEC, OIML, BIPM) ortak bir el kitabı yayımladı: <strong>GUM</strong>. 2008’de küçük düzeltmelerle yeniden basıldı, bugün <strong>JCGM 100:2008</strong> adıyla kullanılıyor. Sonra ek belgeler geldi: <strong>JCGM 101</strong> (Monte Carlo simülasyonu ile belirsizlik hesabı, 2008), <strong>JCGM 102</strong> (birden fazla sonuç veren ölçümler, 2011), <strong>JCGM 106</strong> (uyum kararı, 2012).</p>

<p>Amerika tarafında <strong>NCSL International</strong> kalibrasyon mühendislerinin oluşturduğu bir dernek. 1995’te ilk <strong>RP-12</strong> belgesini yayımladılar, 2013’te tamamen yeniden yazdılar. RP-12, GUM’un akademik dilini günlük kalibrasyon laboratuvarının diline çevirir. Yanına 2006’da yayımlanan <strong>ANSI Z540.3</strong> standardı kalibrasyon laboratuvarları için bağlayıcı kurallar getirir.</p>

<p>Türkiye’de <strong>TÜBİTAK UME</strong> (Ulusal Metroloji Enstitüsü) ulusal ölçüm referanslarını korur. <strong>TÜRKAK</strong> kalibrasyon laboratuvarlarına akreditasyon verir. Aldığınız kalibrasyon belgesinin doğruluğu, bu zincirden geçerek Paris’in batısındaki Sèvres ilçesinde bulunan BIPM merkezine ve oradan da SI birim tanımlarına bağlanır. Bu bağlantıya <strong>izlenebilirlik</strong> deniyor.</p>

<p>İzlenebilirlik zinciri görsel olarak şu şekilde:</p>

<div class="mermaid">
flowchart TB
    SI[SI Birim Tanımları<br />BIPM, Sèvres - Fransa<br />2019'dan beri Planck sabiti, c, e, k_B, ...]
    UME[TÜBİTAK UME<br />Ulusal Metroloji Enstitüsü<br />Türkiye'nin birincil referansı]
    KAL[Akredite Kalibrasyon Laboratuvarı<br />TÜRKAK belgeli<br />ISO 17025 uyumlu]
    UUT[Test edilen cihaz<br />multimetre, PT100, basınç sensörü...]
    URUN[Ürün ölçümü<br />uçak, otomobil, medikal cihaz...]
    SI --&gt; UME
    UME --&gt; KAL
    KAL --&gt; UUT
    UUT --&gt; URUN
    style SI fill:#1a73e8,color:#fff
    style UME fill:#2e7d32,color:#fff
    style KAL fill:#e8711a,color:#fff
    style UUT fill:#c62828,color:#fff
    style URUN fill:#6a1b9a,color:#fff
</div>

<p>Her okun başında ve sonunda bir <strong>belirsizlik kazanımı</strong> olur. SI tanımlarındaki belirsizlik atomik mertebede sıfıra yakındır. UME’nin referansları nano düzeyde belirsizlik taşır. Akredite laboratuvarın belirsizliği biraz daha büyük, sizin cihazınızın daha da. Ürün ölçümünüzün belirsizliği zincirin son halkası — ve eğer zincirde kopukluk varsa (mesela “akredite olmayan bir laboratuvarda kalibre ettirdik”) tüm zincir geçersiz olur.</p>

<hr />

<h2 id="belirsizlik-nedir-birkaç-temel-kavram">Belirsizlik Nedir? Birkaç Temel Kavram</h2>

<p>Önce küçük bir sözlük. Bu kavramları sık karıştırırız:</p>

<table>
  <thead>
    <tr>
      <th>Terim</th>
      <th>Anlamı</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>**Hata**</td>
      <td>Ölçtüğümüz değer eksi gerçek değer. Gerçek değeri hiçbir zaman tam bilemediğimiz için hatayı da tam bilemeyiz.</td>
    </tr>
    <tr>
      <td>**Belirsizlik**</td>
      <td>Ölçüme atfedebileceğimiz değerlerin dağılımı. "Sayım şu civarda olabilir" demek.</td>
    </tr>
    <tr>
      <td>**Doğruluk (accuracy)**</td>
      <td>Ölçümün gerçek değere ne kadar yakın olduğu.</td>
    </tr>
    <tr>
      <td>**Kesinlik (precision)**</td>
      <td>Aynı ölçümü tekrarladığımızda sayıların birbirine ne kadar yakın çıktığı.</td>
    </tr>
    <tr>
      <td>**Tolerans**</td>
      <td>Ürünün kabul edilebilir aralığı (örn. 24 V ± 1 V).</td>
    </tr>
    <tr>
      <td>**İzlenebilirlik**</td>
      <td>Ölçüm cihazımızın doğruluğunun zincir halinde uluslararası referansa bağlanması.</td>
    </tr>
  </tbody>
</table>

<p>Doğruluk ve kesinlik birbirinden bağımsız iki şey. Bir cihaz çok doğru ama az kesin olabilir, ya da çok kesin ama doğru olmayabilir. Bunu anlatmanın en kolay yolu nişan tahtasıdır. Aşağıda dört durum var: her tahtada beş atış var; merkez gerçek değer, atışlar ölçümler.</p>

<div id="grafik-dogruluk" style="width:100%;max-width:760px;margin:1.5rem auto 2.5rem auto;height:680px;"></div>
<script>
(function(){
  var MEAS = '#c62828';
  var CENTER = '#1a73e8';

  function meas(xs, ys, xaxis, yaxis, showleg){
    return {x:xs, y:ys, mode:'markers', type:'scatter',
            marker:{size:12, color:MEAS, line:{color:'#000', width:1}},
            xaxis:xaxis, yaxis:yaxis,
            name:'Ölçüm sonucu (5 tekrar)',
            legendgroup:'meas', showlegend:showleg};
  }
  function center(xaxis, yaxis, showleg){
    return {x:[0], y:[0], mode:'markers', type:'scatter',
            marker:{size:20, color:CENTER, symbol:'star', line:{color:'#000', width:1.5}},
            xaxis:xaxis, yaxis:yaxis,
            name:'Gerçek değer (hedef merkezi)',
            legendgroup:'center', showlegend:showleg};
  }
  function targetShapes(xref, yref){
    var shapes = [];
    [3, 2, 1].forEach(function(r){
      shapes.push({
        type:'circle', xref:xref, yref:yref,
        x0:-r, y0:-r, x1:r, y1:r,
        line:{color:'#888', width:1},
        fillcolor: r===3 ? 'rgba(220,220,220,0.4)' : (r===2 ? 'rgba(240,240,240,0.4)' : 'rgba(255,255,255,0.6)')
      });
    });
    return shapes;
  }

  var data = [
    meas([0.15,-0.1,0.05,-0.05,0.1], [0.05,0.1,-0.1,0.15,-0.05], 'x1', 'y1', true),
    center('x1', 'y1', true),
    meas([0.9,0.7,0.6,1.0,0.8], [-0.5,-0.3,-0.7,-0.4,-0.6], 'x2', 'y2', false),
    center('x2', 'y2', false),
    meas([1.2,-0.8,0.5,-1.4,1.5], [1.3,-1.0,1.4,0.6,-0.9], 'x3', 'y3', false),
    center('x3', 'y3', false),
    meas([1.6,-1.2,0.9,-0.6,1.4], [-1.5,1.7,-1.6,-1.8,-2.0], 'x4', 'y4', false),
    center('x4', 'y4', false)
  ];
  var shapes = []
    .concat(targetShapes('x1','y1'))
    .concat(targetShapes('x2','y2'))
    .concat(targetShapes('x3','y3'))
    .concat(targetShapes('x4','y4'));
  var ax = function(){ return {range:[-3.2,3.2], showgrid:false, zeroline:false, showticklabels:false, fixedrange:true};};

  var layout = {
    grid: {rows:2, columns:2, pattern:'independent', ygap:0.30, xgap:0.10},
    xaxis: ax(), yaxis: ax(),
    xaxis2: ax(), yaxis2: ax(),
    xaxis3: ax(), yaxis3: ax(),
    xaxis4: ax(), yaxis4: ax(),
    annotations:[
      {text:'<b>1) Doğru ve kesin</b><br><span style="font-size:11px;color:#555">merkezde toplanmış</span>',
       x:0.225, y:1.04, xref:'paper', yref:'paper', showarrow:false, font:{size:13}, align:'center', xanchor:'center', yanchor:'bottom'},
      {text:'<b>2) Doğru değil ama kesin</b><br><span style="font-size:11px;color:#555">sapma (bias) var, ama tutarlı</span>',
       x:0.775, y:1.04, xref:'paper', yref:'paper', showarrow:false, font:{size:13}, align:'center', xanchor:'center', yanchor:'bottom'},
      {text:'<b>3) Doğru ama kesin değil</b><br><span style="font-size:11px;color:#555">merkez etrafı, dağınık</span>',
       x:0.225, y:0.46, xref:'paper', yref:'paper', showarrow:false, font:{size:13}, align:'center', xanchor:'center', yanchor:'bottom'},
      {text:'<b>4) Ne doğru ne kesin</b><br><span style="font-size:11px;color:#555">her yerde, sapma + dağınık</span>',
       x:0.775, y:0.46, xref:'paper', yref:'paper', showarrow:false, font:{size:13}, align:'center', xanchor:'center', yanchor:'bottom'}
    ],
    shapes: shapes,
    margin:{l:30, r:30, t:80, b:80},
    plot_bgcolor:'#ffffff', paper_bgcolor:'#ffffff',
    legend:{orientation:'h', x:0.5, xanchor:'center', y:-0.02, yanchor:'top', font:{size:12},
            bgcolor:'rgba(255,255,255,0.85)', bordercolor:'#ccc', borderwidth:1},
    showlegend:true
  };
  Plotly.newPlot('grafik-dogruluk', data, layout, {responsive:true, displayModeBar:false});
})();
</script>

<p>İdeal durum tabii ki sol üst: hem doğru hem kesin. Sağ üst tehlikeli; cihaz çok kesin ölçüm yapıyor (atışlar bir arada) ama hep yanlış yönde sapıyor. <strong>Sapma (bias)</strong> dediğimiz durum bu. Sağ alt durumda atışlar merkezi etrafına yığılmış ama dağınık; ortalamasını alırsak doğru cevaba ulaşırız. Kalibrasyon ve belirsizlik analizinin işi, bu dört durumdan hangisinde olduğumuzu bulup uygun şekilde raporlamaktır.</p>

<p>Belirsizliği iki adımda hesaplıyoruz. Önce her bir kaynağı <strong>standart belirsizlik</strong> denilen bir sayıya dönüştürüyoruz (1 sigmaya, yani normal dağılımın bir standart sapmasına denk düşen değer). Sonra hepsini birleştirip <strong>birleşik belirsizlik</strong> elde ediyoruz. Birleştirme yöntemi şu: her bileşeni karesel olarak topla, sonra karekökünü al. Buna “<strong>karekök kareler toplamı</strong>” diyelim, kısaltılmışı <strong>KKT</strong> (İngilizce literatürde RSS).</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>u_birleşik² = u_1² + u_2² + u_3² + ...
u_birleşik = √(u_1² + u_2² + u_3² + ...)
</code></pre></div></div>

<p>Neden böyle topluyoruz? Çünkü farklı kaynaklardan gelen küçük rastlantısal hatalar, doğrudan toplanmaz; istatistik kuralı gereği kareleri toplanır. İki adet ±1 mm hata yan yana geldiğinde sonuç ±2 mm değil, ±1,4 mm olur (√2 ≈ 1,41).</p>

<p>Son olarak, <strong>kapsama faktörü</strong> denilen bir sayı (genelde k=2) ile çarparak <strong>genişletilmiş belirsizliği</strong> elde ederiz. k=2, yaklaşık olarak %95 güven düzeyine karşılık gelir. Yani “U=56 µV (k=2)” demek, “gerçek değer büyük olasılıkla ölçtüğümüz sayının 56 µV içinde” demek.</p>

<blockquote>
  <p><strong>Akılda kalsın — üç temel formül:</strong></p>
  <ul>
    <li><strong>Standart belirsizlik:</strong> her bileşeni 1σ’a çevir (Tip A için s/√n; Tip B için aralığı dağılım faktörüne böl).</li>
    <li><strong>Birleşik belirsizlik:</strong> u_birleşik = √(u₁² + u₂² + … + uₙ²)</li>
    <li><strong>Genişletilmiş belirsizlik:</strong> U = k × u_birleşik (genelde k = 2, ≈ %95 güven)</li>
  </ul>
</blockquote>

<p>Tip B belirsizlikleri standart belirsizliğe çevirirken bir varsayım yapmamız gerekir: dağılım nasıl dağılıyor? Üretici “±1 mV” diyorsa o aralığın içinde her değer eşit ihtimalli mi, yoksa orta yoğun mu? Üç tipik durum:</p>

<ul>
  <li><strong>Düz (üniform) dağılım:</strong> Aralık içinde her nokta eşit olası. Standart belirsizliği = a / √3.</li>
  <li><strong>Üçgen dağılım:</strong> Orta nokta daha olası, kenarlar düşer. Standart belirsizliği = a / √6.</li>
  <li><strong>Normal dağılım:</strong> Genelde sertifikadan gelir. k ile birlikte verilirse, standart belirsizlik = U / k.</li>
</ul>

<p>Bilgi yoksa, en güvenli tercih düz dağılım varsaymaktır. Aşağıdaki grafik dört dağılım tipini yan yana gösteriyor; hepsinde aralık ±1 birim, ama içerideki olasılık şekli farklı.</p>

<div id="grafik-pdf" style="width:100%;max-width:780px;margin:1.5rem auto 2.5rem auto;height:340px;"></div>
<script>
(function(){
  var x = [];
  for (var i=-150; i<=150; i++) x.push(i/100);
  var uniform = x.map(function(v){return (v>=-1 && v<=1) ? 0.5 : 0;});
  var triangular = x.map(function(v){return (v>=-1 && v<=1) ? (1-Math.abs(v)) : 0;});
  var normal = x.map(function(v){var s=0.5; return Math.exp(-v*v/(2*s*s))/(s*Math.sqrt(2*Math.PI));});
  var ushape = x.map(function(v){return (v>-1 && v<1) ? 1/(Math.PI*Math.sqrt(1-v*v)) : 0;});
  var common = {type:'scatter', mode:'lines', fill:'tozeroy', line:{width:2}};
  var data = [
    Object.assign({}, common, {x:x, y:uniform, name:'Düz', xaxis:'x1', yaxis:'y1', line:{color:'#1a73e8', width:2}, fillcolor:'rgba(26,115,232,0.25)'}),
    Object.assign({}, common, {x:x, y:triangular, name:'Üçgen', xaxis:'x2', yaxis:'y2', line:{color:'#e8711a', width:2}, fillcolor:'rgba(232,113,26,0.25)'}),
    Object.assign({}, common, {x:x, y:normal, name:'Normal', xaxis:'x3', yaxis:'y3', line:{color:'#2e7d32', width:2}, fillcolor:'rgba(46,125,50,0.25)'}),
    Object.assign({}, common, {x:x, y:ushape, name:'U-shape', xaxis:'x4', yaxis:'y4', line:{color:'#6a1b9a', width:2}, fillcolor:'rgba(106,27,154,0.25)'})
  ];
  var ax = function(){ return {range:[-1.5,1.5], showgrid:false, zeroline:false, showticklabels:false, fixedrange:true};};
  var ay = function(){ return {showgrid:false, zeroline:false, showticklabels:false, fixedrange:true};};
  var layout = {
    grid:{rows:1, columns:4, pattern:'independent'},
    xaxis:ax(), yaxis:ay(), xaxis2:ax(), yaxis2:ay(),
    xaxis3:ax(), yaxis3:ay(), xaxis4:ax(), yaxis4:ay(),
    annotations:[
      {text:'<b>Düz</b><br>u = a/√3', x:0, y:1.15, xref:'x1', yref:'paper', showarrow:false, font:{size:13}},
      {text:'<b>Üçgen</b><br>u = a/√6', x:0, y:1.15, xref:'x2', yref:'paper', showarrow:false, font:{size:13}},
      {text:'<b>Normal</b><br>u = U/k', x:0, y:1.15, xref:'x3', yref:'paper', showarrow:false, font:{size:13}},
      {text:'<b>U-shape</b><br>u = a/√2', x:0, y:1.15, xref:'x4', yref:'paper', showarrow:false, font:{size:13}}
    ],
    showlegend:false,
    margin:{l:10, r:10, t:50, b:30},
    plot_bgcolor:'#ffffff', paper_bgcolor:'#ffffff'
  };
  Plotly.newPlot('grafik-pdf', data, layout, {responsive:true, displayModeBar:false});
})();
</script>

<p>U-shape dağılım sıcaklık dalgalanmaları gibi durumlarda görülür: termostatlı bir oda sıcaklığı çoğunlukla alt sınır veya üst sınıra yakın salınır, orta noktada nadir kalır. Klasik üç dağılım dışında ihtiyaç doğdukça başka dağılımlar da kullanılır.</p>

<blockquote>
  <p><strong>Akılda kalsın — aralığı standart belirsizliğe çevirme:</strong></p>

  <table>
    <thead>
      <tr>
        <th>Elinizde olan</th>
        <th>Yapacağınız</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>Sertifika "U = … (k=2)" der</td>
        <td>u = U / 2</td>
      </tr>
      <tr>
        <td>Sertifika "U = … (k=3)" der</td>
        <td>u = U / 3</td>
      </tr>
      <tr>
        <td>Üretici "±a" der, ek bilgi yok</td>
        <td>u = a / √3 *(düz/üniform)*</td>
      </tr>
      <tr>
        <td>"Merkez yakını daha olası" notu var</td>
        <td>u = a / √6 *(üçgen)*</td>
      </tr>
      <tr>
        <td>Termostat dalgalanması, ±a sınırlı</td>
        <td>u = a / √2 *(U-shape)*</td>
      </tr>
    </tbody>
  </table>

  <p>Şüpheliyseniz <strong>düz dağılım</strong> seçin — en muhafazakâr olanı.</p>
</blockquote>

<hr />

<h2 id="gum-annex-f-pratik-uyarılar">GUM Annex F: Pratik Uyarılar</h2>

<p>GUM’un ana metni biraz akademik dilde yazılmış: integraller, kovaryans matrisleri. Yeni başlayan biri için zorlu bir okuma. Ama belgenin <strong>F eki</strong> (Annex F) bambaşka. Doğrudan ölçüm yapan mühendise sesleniyor, en sık yapılan yanlışları sıralıyor, çözüm öneriyor. Aşağıda en önemli yedi noktayı açıklayalım.</p>

<h3 id="1-tekrar-ölçümleriniz-gerçekten-rastgele-mi">1. Tekrar ölçümleriniz gerçekten “rastgele” mi?</h3>

<p>10 ölçüm aldınız, standart sapmasını hesapladınız, “Tip A belirsizlik = 5 mV” dediniz. Ama o 10 ölçüm sırasında oda sıcaklığı 1 °C arttı, kalibratör yavaşça kaymaya başladı, kablonun bağlantı noktasında küçük voltajlar birikti. Bu durumda standart sapma rastgele dalgalanmayı değil, <strong>sıralı bir gidişatı</strong> ölçer. GUM uyarısı: tekrar ölçümler arasında koşulları gerçekten yenileyin. Cihazı kapatıp açın, sıfırlayın, kabloyu temizleyin, ısıl dengelenmeyi bekleyin.</p>

<h3 id="2-ortalamanın-belirsizliği-ile-tek-ölçümün-belirsizliği-farklı-şeyler">2. Ortalamanın belirsizliği ile tek ölçümün belirsizliği farklı şeyler.</h3>

<p>10 ölçümün ortalamasının standart belirsizliği s/√10 olur. Yani standart sapmayı √10 ile bölersiniz. Ama gelecekte yapılacak tek bir ölçümün belirsizliği s’in kendisidir. Test prosedüründe gelecekte hep 10 kez ölçüp ortalama mı raporlayacaksınız, yoksa tek ölçüm mü? Birinciyse s/√10, ikinciyse s. Pek çok kişi bu ikisini karıştırır.</p>

<h3 id="3-birden-fazla-küçük-örnek-varsa-havuzlayın">3. Birden fazla küçük örnek varsa havuzlayın.</h3>

<p>Diyelim ki 10 farklı günde, her gün 5 ölçüm yapıyorsunuz. Toplam 50 ölçüm var ama her gün için ayrı bir standart sapma çıkıyor. Hangisini kullanacaksınız? GUM cevabı: hepsini “havuzlayın”. Şu formülle:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>        Σ ν_i · s_i²
s² =  ──────────────
          Σ ν_i
</code></pre></div></div>

<p>Burada her grubun “serbestlik derecesi” ν_i = n_i − 1. Sonuç: tek bir küçük gruba göre çok daha güvenilir bir s. Ölçüm tekrarlanabilirliği çalışmalarının (R&amp;R çalışmaları) matematiksel temeli budur.</p>

<h3 id="4-üreticinin-verdiği-değerleri-olduğu-gibi-alın">4. Üreticinin verdiği değerleri olduğu gibi alın.</h3>

<p>Tip B belirsizliği hesaplarken sık yapılan bir hata: “Üretici ±100 µV demiş ama ben yine de 200 µV koyayım, daha güvenli olsun.” Bu yanlış. Elinizdeki kanıt ne ise onu kullanın. Sertifika varsa sertifikadan, üretici belgesi varsa o belgeden, geçmiş ölçüm verisi varsa o veriden. Kendi sezginizle “biraz daha kötümser olalım” demek, sayıları güvenilmez yapar.</p>

<h3 id="5-pdf-varsayımı-yargı-gerektirir">5. PDF varsayımı yargı gerektirir.</h3>

<p>Üretici “±1%” diyorsa, içindeki dağılım nasıl? Üretici belirtmediyse düz dağılım varsayın. “Çoğunlukla orta yakınında çıkar” diye bir not varsa üçgen dağılım. Ama bu kararı belgenizde yazılı olarak gerekçelendirmelisiniz.</p>

<h3 id="6-bağımsızlık-varsayımı-çoğu-zaman-yanlıştır">6. Bağımsızlık varsayımı çoğu zaman yanlıştır.</h3>

<p>Birleşik belirsizlik formülü (“kareler toplamının karekökü”) sadece <strong>birbirinden bağımsız</strong> kaynaklar için geçerli. Eğer iki ölçüm aynı kalibratörden besleniyorsa, sertifikalarındaki belirsizlikler ilişkili demektir. Aynı operatör, aynı oda, aynı ortam koşulları… bunlar belirsizlikleri ilişkili kılar. İlişkili kaynakları “bağımsız” kabul edip topladığınızda, sonuç gerçeğin altında ya da üstünde çıkar. GUM bunun için ek bir terim ekler:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>u² = Σ u_i² + 2 · Σ u_ij
</code></pre></div></div>

<p>İkinci terim, ilişkili kaynak çiftleri arasında pozitifse belirsizliği büyütür, negatifse küçültür.</p>

<h3 id="7-sertifika-belirsizliklerinde-gizli-sıcaklık-tuzağı">7. Sertifika belirsizliklerinde gizli sıcaklık tuzağı</h3>

<p>Bu özellikle test laboratuvarlarında sık görülen bir tuzak. Kalibrasyon belgesi diyor ki: “Cihazın belirsizliği ±28 µV (k=2)”. Sonra ayrıca “ölçümler 23 °C ± 1 °C odada yapıldı” notu var. Şimdi siz cihazı kendi laboratuvarınızda 23 °C ± 3 °C koşullarda kullanıyorsunuz. Cihazın sıcaklık katsayısı bilgisini kataloga bakıp ayrıca ekliyorsunuz.</p>

<p>Burada gizli bir çift sayma var. Cihazın 23 °C ± 1 °C aralığındaki davranışı zaten kalibrasyon belgesindeki ±28 µV içine girmiş. Siz “±3 °C” aralığını eklerken sadece <strong>fark olan ±2 °C’lik kısmı</strong> hesaba katmalısınız, tüm ±3 °C’yi değil. Aksi halde sıcaklık etkisini iki kez sayarsınız ve belirsizliği gerçeğin üstünde gösterirsiniz.</p>

<blockquote>
  <p><strong>Bu yedi maddenin ortak fikri:</strong> Belirsizlik bir tahmin değil, bir hesap. Her seçiminizi (dağılım varsayımı, bağımsızlık kararı, hangi sertifika değerinin kullanıldığı) belgenizde yazılı tutun. Akreditasyon denetiminde her birinin gerekçesi sorulur.</p>
</blockquote>

<hr />

<h2 id="k2-mi-k3-mü-sorusu">“k=2 mi, k=3 mü?” Sorusu</h2>

<p>Genişletilmiş belirsizliği hesaplarken k değerini seçmemiz gerekiyor. Çoğu uygulamada k=2 (yaklaşık %95 güven) standart. Bazı kritik uygulamalarda k=3 (yaklaşık %99 güven) tercih ediliyor. Ama ikisi arasında dikkat etmemiz gereken bir ayrıntı var.</p>

<p>k=2 yaklaşık %95’lik güven düzeyine <strong>sadece ölçüm sayısı yeterince çoksa</strong> karşılık geliyor. Eğer Tip A hesaplamasında az sayıda ölçüm yaptıysanız (örneğin sadece 5), istatistiksel dağılım normal değil <strong>Student-t</strong> dağılımı oluyor. Bu durumda k=2 yerine biraz daha büyük bir değer kullanmak gerekir.</p>

<p>Bu hesabı <strong>Welch-Satterthwaite formülü</strong> yapar:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>                u_birleşik⁴
ν_etkin =  ──────────────────
              Σ (u_i⁴ / ν_i)
</code></pre></div></div>

<p>Buradaki ν_etkin “etkin serbestlik derecesi”. Tip A bileşeninin serbestlik derecesi n−1, Tip B bileşenleri için (sertifikadan veya katalog değerinden geldikleri için) genelde sonsuz kabul edilir. Etkin serbestlik derecesi yeterince büyükse (genelde 30’dan büyük) k=2 güvenle kullanılabilir. Daha küçükse Student-t tablosundan k değerini bakarsınız.</p>

<p>Pratik tavsiye: ölçümlerinizi en az 30 kere yapıyorsanız k=2 düşünmeyin bile, doğrudan kullanın. Daha az ölçüm yapıyorsanız etkin serbestlik derecesini hesaplayın. Hesabı kolaylaştıran bedava araçlar var; örneğin Amerika’nın NIST kurumunun yayımladığı “NIST Uncertainty Machine” web aracı bu hesabı tek tıkla yapar.</p>

<hr />

<h2 id="ncsli-rp-12-pratik-bir-el-kitabı">NCSLI RP-12: Pratik Bir El Kitabı</h2>

<p>GUM size “ne yapmanız gerektiğini” söyler. NCSLI RP-12 ise “nasıl yaparsınız, hangi tabloları kullanırsınız, hangi şablonu doldurursunuz” sorusunu yanıtlar. 2013 baskısı NCSLI’nin Belirsizlik Analizi Komitesi tarafından yazıldı; komitenin başında belirsizlik analizinin önde gelen isimlerinden Howard Castrup (Integrated Sciences Group kurucusu, NCSLI Wildhack Ödülü 2002 sahibi) vardı.</p>

<p>RP-12’nin yapısı GUM’dan biraz farklı. GUM “Tip A vs Tip B” ayrımıyla giderken, RP-12 hata kaynaklarını günlük dile daha yakın gruplara ayırır:</p>

<ul>
  <li><strong>Sapma (bias):</strong> Cihazın gerçek değerden sürekli aynı yönde sapması.</li>
  <li><strong>Rastgele:</strong> Ölçümden ölçüme sebepsiz dalgalanma.</li>
  <li><strong>Kayma (drift):</strong> Zamanla yavaş değişme.</li>
  <li><strong>Çevre:</strong> Sıcaklık, nem, EMG (elektromanyetik girişim).</li>
  <li><strong>Operatör:</strong> Kim ölçtü.</li>
  <li><strong>Yöntem:</strong> Hangi adımlarla ölçüldü.</li>
</ul>

<p>Bu sınıflandırma, kalibrasyon laboratuvarı çalışanlarının kafasındaki gerçeğe daha yakın. Bir sorun bulduklarında “bu hangi kategoriden?” sorusuna kolay cevap verirler.</p>

<p>RP-12’de işine yarayacak özel bölümler:</p>

<ul>
  <li><strong>Üretici belgesinden belirsizlik çıkarmak:</strong> Hangi belge satırı hangi belirsizlik kaynağına karşılık geliyor; hangi durumlarda hangi PDF varsayılmalı.</li>
  <li><strong>Aynı anda birden çok cihazı kalibre etmek:</strong> Kalibrasyon prosedürü tek bir referansla 10 cihazı doğruluyorsa, belirsizlik nasıl bölüştürülür.</li>
  <li><strong>Düzeltilmemiş sapmalar için belirsizlik:</strong> Sertifika “+0,12 mV sapma” diyor ama prosedürünüz düzeltme uygulamıyor. Bu sapmayı belirsizliğe nasıl yansıtırsınız.</li>
  <li><strong>Monte Carlo simülasyonu:</strong> Doğrusal olmayan ölçüm modellerinde klasik GUM yöntemi yetersiz kalır. Bilgisayarda 100.000 simülasyon yapıp dağılımı doğrudan üretirsiniz. RP-12 bu yöntemi pratik bir şekilde anlatır.</li>
</ul>

<p><strong>ANSI Z540.3 ile bağlantı.</strong> Bu standart bir kalibrasyon laboratuvarının uyması gereken kurallardan biri. Ana maddesi şudur: kalibrasyon sonucu yanlış kabul olasılığı %2’den fazla olamaz. Ya da bunu hesaplamak zorsa, <strong>TUR ≥ 4:1</strong> olmalıdır. TUR, “test belirsizlik oranı” demek; cihazın toleransının kalibrasyon belirsizliğine oranı. Örnek: cihazın toleransı ±100 µV, kalibrasyon belirsizliği ±25 µV ise TUR = 4. RP-12 bu kuralı sağlamak için gerekli hesap yöntemlerini sunar.</p>

<p><strong>Türkiye uygulaması.</strong> TÜRKAK akreditasyonlu kalibrasyon laboratuvarları çoğunlukla Avrupa rehberi EA-4/02’yi takip eder. Ama Türkiye’nin aviyonik (TUSAS, BAYKAR), savunma (ASELSAN, ROKETSAN) ve otomotiv (Togg ve tedarikçileri) firmaları ABD merkezli müşterilere de iş yapıyor. ABD ortağına rapor verdiğinizde NCSLI RP-12 ve Z540.3’e atıf gerekiyor. Yani Türk test mühendisinin masasında giderek artan oranda her iki belge de bulunmalı.</p>

<hr />

<h2 id="örnek-1-voltmetre-kalibrasyonu">Örnek 1: Voltmetre Kalibrasyonu</h2>

<p><strong>Senaryo.</strong> Sistem entegrasyon laboratuvarında elinizdeki voltmetre (Keysight 34465A, 6½ haneli) referans bir kalibratörle (Fluke 5720A) doğrulanıyor. Kalibratör tam olarak 10,000 V veriyor. Voltmetrenin bu değeri ne kadar doğru okuduğunu ve okumanın ne kadar belirsizlik içerdiğini hesaplayacağız. Ortam sıcaklığı (23 ± 2) °C.</p>

<h3 id="adım-1-tip-a--10-kez-ölçüm-yapın">Adım 1: Tip A — 10 kez ölçüm yapın</h3>

<p>Aynı koşullarda 10 ardı ardına ölçüm. Her ölçüm öncesinde voltmetrenin girişini açıp kapayıp kabloyu temizliyoruz (önceki bölümdeki 1. uyarı). Sonuçlar:</p>

<table>
  <thead>
    <tr>
      <th>Ölçüm</th>
      <th>Değer (V)</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>1</td>
      <td>9,999870</td>
    </tr>
    <tr>
      <td>2</td>
      <td>9,999910</td>
    </tr>
    <tr>
      <td>3</td>
      <td>9,999890</td>
    </tr>
    <tr>
      <td>4</td>
      <td>9,999895</td>
    </tr>
    <tr>
      <td>5</td>
      <td>9,999860</td>
    </tr>
    <tr>
      <td>6</td>
      <td>9,999900</td>
    </tr>
    <tr>
      <td>7</td>
      <td>9,999875</td>
    </tr>
    <tr>
      <td>8</td>
      <td>9,999895</td>
    </tr>
    <tr>
      <td>9</td>
      <td>9,999920</td>
    </tr>
    <tr>
      <td>10</td>
      <td>9,999875</td>
    </tr>
  </tbody>
</table>

<ul>
  <li>Ortalama: x̄ = 9,999889 V</li>
  <li>Standart sapma: s ≈ 19 µV</li>
  <li>Ortalamanın standart belirsizliği: u_A = s / √10 ≈ 6 µV</li>
</ul>

<h3 id="adım-2-tip-b--diğer-kaynakları-listeleyin">Adım 2: Tip B — Diğer kaynakları listeleyin</h3>

<p>Her kaynağı düzgün bir tabloya koyarız. Aralığı (üreticinin verdiği değer) ilgili dağılım varsayımıyla bölerek standart belirsizliğe geçeriz.</p>

<table>
  <thead>
    <tr>
      <th>Kaynak</th>
      <th>Aralık</th>
      <th>Dağılım</th>
      <th>Bölme</th>
      <th>u (µV)</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Kalibratör sertifikası (UME, k=2)</td>
      <td>±28 µV</td>
      <td>normal</td>
      <td>2</td>
      <td>14,0</td>
    </tr>
    <tr>
      <td>Voltmetre çözünürlüğü (1 µV son hane)</td>
      <td>±0,5 µV</td>
      <td>düz</td>
      <td>√3</td>
      <td>0,29</td>
    </tr>
    <tr>
      <td>Sıcaklık katsayısı (±2 °C, 2 ppm/°C × 10 V)</td>
      <td>±40 µV</td>
      <td>düz</td>
      <td>√3</td>
      <td>23,1</td>
    </tr>
    <tr>
      <td>Bakır konnektörlerde gerilim oluşumu</td>
      <td>±3 µV</td>
      <td>düz</td>
      <td>√3</td>
      <td>1,73</td>
    </tr>
    <tr>
      <td>Hat gürültüsü (50 Hz)</td>
      <td>±2 µV</td>
      <td>normal</td>
      <td>1</td>
      <td>2,0</td>
    </tr>
    <tr>
      <td>Kalibratörün 1 yıllık kayması</td>
      <td>±5 µV</td>
      <td>düz</td>
      <td>√3</td>
      <td>2,89</td>
    </tr>
  </tbody>
</table>

<h3 id="adım-3-birleşik-belirsizliği-hesaplayın">Adım 3: Birleşik belirsizliği hesaplayın</h3>

<p>Her bileşeni karesel olarak topla, karekök al:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>u² = 6² + 14² + 0,29² + 23,1² + 1,73² + 2² + 2,89²
u² = 36 + 196 + 0,08 + 533,6 + 3 + 4 + 8,4
u² ≈ 781
u  ≈ 28 µV
</code></pre></div></div>

<h3 id="adım-4-genişletilmiş-belirsizlik">Adım 4: Genişletilmiş belirsizlik</h3>

<p>Kapsama faktörü k=2 ile çarpın:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>U = 2 × 28 = 56 µV
</code></pre></div></div>

<h3 id="adım-5-sonucu-ifade-edin">Adım 5: Sonucu ifade edin</h3>

<p>Voltmetrenin okuması = (9,999889 ± 0,000056) V, k = 2.</p>

<p>Yani gerçek değer büyük olasılıkla 9,999833 V ile 9,999945 V arasında.</p>

<h3 id="hangi-kaynak-en-çok-katkı-veriyor">Hangi kaynak en çok katkı veriyor?</h3>

<p>Aşağıdaki grafikte, yedi belirsizlik kaynağının her birinin katkısını sıralı görüyorsunuz. Sıcaklık katsayısı toplam belirsizliğin yarısından fazlasını oluşturuyor.</p>

<div id="grafik-multimetre" style="width:100%;max-width:760px;margin:1.5rem auto 2.5rem auto;height:380px;"></div>
<script>
(function(){
  var data = [{
    type: 'bar',
    orientation: 'h',
    x: [533.6, 196, 36, 8.4, 4, 3, 0.08],
    y: ['Sıcaklık katsayısı', 'Kalibratör sertifikası', 'Tekrar ölçüm (Tip A)', 'Kalibratör kayması', 'Hat gürültüsü', 'Bakır konnektör', 'Voltmetre çözünürlüğü'],
    text: ['68,3%', '25,1%', '4,6%', '1,1%', '0,5%', '0,4%', '0,01%'],
    textposition: 'auto',
    marker: { color: '#1a73e8' }
  }];
  var layout = {
    title: { text: 'Voltmetre Belirsizlik Bütçesi (varyans katkısı)', font: { size: 14 } },
    xaxis: { title: 'Varyans katkısı (µV²)' },
    yaxis: { autorange: 'reversed' },
    margin: { l: 180, r: 30, t: 50, b: 50 },
    plot_bgcolor: '#ffffff',
    paper_bgcolor: '#ffffff'
  };
  Plotly.newPlot('grafik-multimetre', data, layout, {responsive: true, displayModeBar: false});
})();
</script>

<p>Grafiğin söylediği şey net. Belirsizliği düşürmek isteseniz nereye yatırım yaparsınız? Voltmetreye değil. Daha pahalı bir kalibratöre de değil. <strong>Oda sıcaklığını sabitlemeye.</strong> Sıcaklık aralığı ±2 °C yerine ±0,5 °C olsa, sıcaklık katkısı 23 µV’den 6 µV’ye düşer; toplam belirsizlik 28 µV’den 16 µV’ye iner. Hiçbir cihaz yatırımı yapmadan, sadece klimayı düzgün ayarlayarak belirsizliği yarıya indirdiniz.</p>

<blockquote>
  <p><strong>Akılda kalsın — Pareto kuralı:</strong>
Belirsizlik bütçesindeki bileşenleri varyans katkısına göre sıralayın. <strong>İlk iki kaynak çoğu zaman toplamın %80–90’ını oluşturur.</strong> İyileştirmeye onlardan başlayın; küçük katkılarla uğraşmak vakit ve para kaybı. Önce en büyük katkıyı yarıya indirmek, geri kalan altıyla uğraşmaktan daha çok kazandırır.</p>
</blockquote>

<h3 id="bu-sonucu-kabul-etmeli-miyiz">Bu sonucu kabul etmeli miyiz?</h3>

<p>Voltmetrenin teknik kataloğu diyor ki cihazın 10 V’ta toleransı ±100 µV. Şimdi TUR hesaplayalım:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>TUR = Tolerans / Belirsizlik = 100 / 56 ≈ 1,8
</code></pre></div></div>

<p>Z540.3’ün 4:1 sınırının çok altında. Ya kabul kararı verirken çok dikkatli olacağız (güvenlik payı uygulayacağız), ya da belirsizliği düşüreceğiz. Üç seçenek var:</p>

<ol>
  <li><strong>Sıcaklığı sabitle.</strong> Yukarıda anlatıldı. Belirsizlik 16 µV’ye iner, TUR = 6,3 olur. En ucuz çözüm.</li>
  <li><strong>Daha iyi kalibratör kullan.</strong> UME’nin daha düşük belirsizlikle kalibre ettiği bir referans kaynağa geç. Sertifika belirsizliği ±10 µV olabilir. Ama maliyet artar.</li>
  <li><strong>Müşteriyle konuş.</strong> Belki ±100 µV toleransı çok sıkı, gerçek uygulamada ±200 µV bile yeterli olabilir.</li>
</ol>

<p>Bir test mühendisinin işi sadece sayı üretmek değil, bu üç seçeneği masaya getirip yöneticisiyle tartışmak. Belirsizlik bütçesi olmadan bu konuşmayı yapamazsınız.</p>

<hr />

<h2 id="örnek-2-sıcaklık-sensörü-ile-test-fırını-ölçümü">Örnek 2: Sıcaklık Sensörü ile Test Fırını Ölçümü</h2>

<p><strong>Senaryo.</strong> Endüstriyel bir parçanın yüksek sıcaklık dayanım testini yapıyorsunuz. Test gereksinimi: parça 200 °C ± 2 °C ortamda 30 dakika çalışmalı. Fırının içine bir <strong>PT100</strong> sensörü koymuşsunuz. (PT100, 0 °C’de tam 100 ohm direnç gösteren platin tel sensörü; sıcaklıkla direnç doğrusal artar; çalışma aralığı tipik olarak −200 °C ile +650 °C arası.) Sensör bir <strong>veri toplama kartına</strong> (DAQ kartı, NI 9217) bağlı, kart bilgisayara veriyor.</p>

<p>Sıcaklığın gerçek değeri ne olabilir? Belirsizlik bütçesi:</p>

<table>
  <thead>
    <tr>
      <th>Kaynak</th>
      <th>Aralık</th>
      <th>Dağılım</th>
      <th>u (°C)</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>PT100 kalibrasyon belgesi (UME, k=2)</td>
      <td>±0,15 °C</td>
      <td>normal</td>
      <td>0,075</td>
    </tr>
    <tr>
      <td>Sensörün kendi kendine ısınması (1 mA × 100 Ω = 0,1 mW; ısıl direnç 0,5 K/mW)</td>
      <td>±0,05 °C</td>
      <td>düz</td>
      <td>0,029</td>
    </tr>
    <tr>
      <td>Bir yıllık kayma (kalibrasyondan bu yana)</td>
      <td>±0,10 °C</td>
      <td>düz</td>
      <td>0,058</td>
    </tr>
    <tr>
      <td>Fırın iç hacminde sıcaklık dağılımı (önceki ölçümlerden 0,3 °C tepe-tepe)</td>
      <td>±0,15 °C</td>
      <td>üçgen</td>
      <td>0,061</td>
    </tr>
    <tr>
      <td>DAQ kartı (NI 9217 katalog değeri, 200 °C civarı)</td>
      <td>±0,15 °C</td>
      <td>normal</td>
      <td>0,075</td>
    </tr>
    <tr>
      <td>4 telli kablo direnç dengesizliği</td>
      <td>±0,02 °C</td>
      <td>düz</td>
      <td>0,012</td>
    </tr>
    <tr>
      <td>30 ölçümün dağılımı (Tip A, s=0,04 °C)</td>
      <td>s/√30</td>
      <td>normal</td>
      <td>0,007</td>
    </tr>
  </tbody>
</table>

<p><strong>Birleşik belirsizlik:</strong></p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>u² = 0,075² + 0,029² + 0,058² + 0,061² + 0,075² + 0,012² + 0,007²
u² = 0,00563 + 0,00084 + 0,00336 + 0,00372 + 0,00563 + 0,00014 + 0,00005
u² ≈ 0,0194
u  ≈ 0,14 °C
</code></pre></div></div>

<p><strong>Genişletilmiş belirsizlik (k=2):</strong></p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>U = 2 × 0,14 = 0,28 °C
</code></pre></div></div>

<p><strong>Sonuç:</strong> Fırının iç sıcaklığı = (200,00 ± 0,28) °C, k = 2.</p>

<p>Hangi bileşenler en çok katkı yapıyor? Bakalım:</p>

<div id="grafik-pt100" style="width:100%;max-width:760px;margin:1.5rem auto 2.5rem auto;height:380px;"></div>
<script>
(function(){
  var data = [{
    type: 'bar',
    orientation: 'h',
    x: [0.00563, 0.00563, 0.00372, 0.00336, 0.00084, 0.00014, 0.00005],
    y: ['PT100 kalibrasyon belgesi', 'DAQ kartı', 'Fırın sıcaklık dağılımı', 'Kayma', 'Kendi kendine ısınma', 'Kablo dengesizliği', 'Tekrar ölçüm (Tip A)'],
    text: ['29,1%', '29,1%', '19,2%', '17,3%', '4,3%', '0,7%', '0,3%'],
    textposition: 'auto',
    marker: { color: '#e8711a' }
  }];
  var layout = {
    title: { text: 'PT100 Belirsizlik Bütçesi (varyans katkısı)', font: { size: 14 } },
    xaxis: { title: 'Varyans katkısı (°C²)' },
    yaxis: { autorange: 'reversed' },
    margin: { l: 200, r: 30, t: 50, b: 50 },
    plot_bgcolor: '#ffffff',
    paper_bgcolor: '#ffffff'
  };
  Plotly.newPlot('grafik-pt100', data, layout, {responsive: true, displayModeBar: false});
})();
</script>

<p><strong>Test mühendisi olarak ne dersiniz?</strong> Gereksinim 200 ± 2 °C, ölçüm belirsizliği 0,28 °C. TUR = 2 / 0,28 ≈ 7,1. Z540.3’ün 4:1 sınırının çok üstünde, sorunsuz.</p>

<p>Ama gereksinim daha sıkı olsaydı (örneğin 200 ± 0,5 °C), TUR = 1,8’e düşerdi. Bu durumda yapılacak iş şu: önce belirsizliği düşürmek lazım. Grafiğe bakın. İlk üç kaynak (PT100 belgesi, DAQ kartı, fırın dağılımı) toplam belirsizliğin %75’ini oluşturuyor. İyileştirme öncelikleri:</p>

<ol>
  <li>PT100’ü TÜBİTAK UME’de daha düşük belirsizlikle yeniden kalibre ettirin. ±0,15 yerine ±0,05 °C.</li>
  <li>Daha yüksek doğruluklu DAQ kartı alın (NI 9226 gibi).</li>
  <li>Fırın içine ek termal blok koyun, hava sirkülasyonunu artırın.</li>
</ol>

<p>Bu üç adım belirsizliği yarıya indirir. Hangi kaynağa dokunmadan da ayrı ayrı denenebilir. Mantığı: önce büyüğü azalt, sonra küçükleri düşün.</p>

<hr />

<h2 id="örnek-3-bir-sensörü-kabul-mü-edelim-reddedelim-mi">Örnek 3: Bir Sensörü Kabul mü Edelim, Reddedelim mi?</h2>

<p><strong>Senaryo.</strong> Bir otomotiv basınç sensörü 0–100 bar arasında ölçüm yapıyor. Kalite kontrolünden geçmesi için toleransı ±0,10 bar. Yani ölçüm cihazı bir referans değer verirken sensör ±0,10 bar içinde okumalı. Kalibrasyon sürecinin belirsizliği: U = 0,025 bar.</p>

<p><strong>TUR hesabı:</strong></p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>TUR = Tolerans / Belirsizlik = 0,10 / 0,025 = 4
</code></pre></div></div>

<p>Z540.3’ün 4:1 sınırına tam denk geldi. Bu sayı yetiyor mu?</p>

<p>Soruyu şöyle çevirelim: ölçüm cihazı sensörü “geçti” diye işaretlediği halde sensör aslında toleransın dışındaysa, bu <strong>yanlış kabul</strong> olur. Yanlış kabul olasılığı (PFA = Probability of False Accept) ne kadar?</p>

<p>Önce yanlış kabulun ne demek olduğunu görsel olarak görelim. Aşağıda bir sensörün ölçüm dağılımı çizilmiş. Sensörün gerçek değeri 0,098 bar diyelim — yani toleransın iç sınırına çok yakın. Ölçüm cihazı U = 0,025 bar belirsizlikle bu sensörü ölçüyor. Ölçüm sonucu, gerçek değer civarında bir normal dağılımdan rastgele bir nokta gibi düşünebiliriz. Ölçüm 0,10’un altında çıkarsa “geçti” diyoruz — ama gerçek değer 0,098’de bile, ölçüm dağılımının bir kısmı 0,10’un üstüne taşar. Taşan bu kısım yanlış kabul bölgesidir.</p>

<div id="grafik-pfa-gorsel" style="width:100%;max-width:760px;margin:1.5rem auto 2.5rem auto;height:400px;"></div>
<script>
(function(){
  var x = [];
  for (var i=0; i<=400; i++) x.push(0.05 + i*(0.15-0.05)/400);
  var mu = 0.098, sigma = 0.0125;
  var pdf = x.map(function(v){return Math.exp(-(v-mu)*(v-mu)/(2*sigma*sigma))/(sigma*Math.sqrt(2*Math.PI));});
  var maxY = Math.max.apply(null, pdf);
  var xAccept = x.filter(function(v){return v <= 0.10;});
  var pdfAccept = xAccept.map(function(v){return Math.exp(-(v-mu)*(v-mu)/(2*sigma*sigma))/(sigma*Math.sqrt(2*Math.PI));});
  var xReject = x.filter(function(v){return v > 0.10;});
  var pdfReject = xReject.map(function(v){return Math.exp(-(v-mu)*(v-mu)/(2*sigma*sigma))/(sigma*Math.sqrt(2*Math.PI));});
  var data = [
    {x:xAccept, y:pdfAccept, type:'scatter', mode:'lines', fill:'tozeroy',
     line:{color:'#2e7d32', width:2}, fillcolor:'rgba(46,125,50,0.30)',
     name:'Doğru kabul (geçti)', hoverinfo:'skip'},
    {x:xReject, y:pdfReject, type:'scatter', mode:'lines', fill:'tozeroy',
     line:{color:'#c62828', width:2}, fillcolor:'rgba(198,40,40,0.55)',
     name:'Yanlış kabul (gerçekte tolerans dışı)', hoverinfo:'skip'}
  ];
  var layout = {
    title:{text:'Ölçüm Dağılımı ve Yanlış Kabul Bölgesi', font:{size:14}},
    xaxis:{title:'Ölçüm değeri (bar)', range:[0.05, 0.15], zeroline:false},
    yaxis:{title:'Olasılık yoğunluğu', showticklabels:false, zeroline:false},
    shapes:[
      {type:'line', x0:0.10, x1:0.10, y0:0, y1:maxY*1.05,
       line:{color:'#000', width:2, dash:'dash'}},
      {type:'line', x0:mu, x1:mu, y0:0, y1:maxY*0.85,
       line:{color:'#1a73e8', width:1.5, dash:'dot'}}
    ],
    annotations:[
      {x:0.10, y:maxY*1.10, text:'Tolerans sınırı<br>0,10 bar', showarrow:false, font:{size:11}},
      {x:mu, y:maxY*0.92, text:'Gerçek değer<br>0,098 bar', showarrow:false, font:{size:11, color:'#1a73e8'}},
      {x:0.115, y:maxY*0.30, text:'Yanlış<br>kabul', showarrow:true, arrowhead:2, ax:-25, ay:-30, font:{size:11, color:'#c62828'}}
    ],
    showlegend:true, legend:{x:0.02, y:0.98},
    margin:{l:60, r:30, t:50, b:60},
    plot_bgcolor:'#ffffff', paper_bgcolor:'#ffffff'
  };
  Plotly.newPlot('grafik-pfa-gorsel', data, layout, {responsive:true, displayModeBar:false});
})();
</script>

<p>Yeşil alan: ölçüm 0,10’un altında çıkıyor, doğru kabul. Kırmızı alan: ölçüm 0,10’un üstünde çıkıyor (gerçekte sensör tolerans içinde olduğu halde). Burada ölçüm cihazı “reddet” diyecek — ama bu durumda <strong>yanlış red</strong>. Tam tersi durum, yani sensörün gerçek değeri 0,103 bar olursa (tolerans dışı), ölçüm yine dağılım gösterir, ve dağılımın bir kısmı 0,10’un altına düşer; o zaman ölçüm cihazı “geçti” diyor ama sensör aslında tolerans dışı — <strong>yanlış kabul</strong>. Bu yazının kalan kısmında yanlış kabul bizi daha çok ilgilendiriyor (üreticinin çıkardığı bozuk ürün).</p>

<p>Aşağıdaki ikinci grafik, TUR’a göre yanlış kabul olasılığının nasıl değiştiğini gösteriyor. Eğri, sensörün gerçek değerinin tolerans içinde <strong>uniform dağıldığı</strong> varsayımı altında.</p>

<div id="grafik-tur-pfa" style="width:100%;max-width:760px;margin:1.5rem auto 2.5rem auto;height:380px;"></div>
<script>
(function(){
  var data = [{
    type: 'scatter',
    mode: 'lines+markers',
    x: [1, 1.5, 2, 2.5, 3, 4, 6, 10],
    y: [30, 15, 8, 5, 3, 1.5, 0.5, 0.1],
    line: { color: '#c62828', width: 3 },
    marker: { size: 8, color: '#c62828' },
    name: 'Yanlış kabul olasılığı'
  }];
  var layout = {
    title: { text: 'TUR ile Yanlış Kabul Olasılığının Değişimi', font: { size: 14 } },
    xaxis: { title: 'TUR (Tolerans / Belirsizlik)' },
    yaxis: { title: 'Yanlış kabul olasılığı (%)', type: 'log' },
    shapes: [{
      type: 'line', x0: 4, x1: 4, y0: 0.05, y1: 30,
      line: { color: '#888', width: 2, dash: 'dash' }
    }],
    annotations: [{
      x: 4, y: 1.5, xref: 'x', yref: 'y',
      text: 'Z540.3 sınırı (4:1)', showarrow: true, arrowhead: 2, ax: 60, ay: -30
    }],
    margin: { l: 70, r: 30, t: 50, b: 60 },
    plot_bgcolor: '#ffffff',
    paper_bgcolor: '#ffffff'
  };
  Plotly.newPlot('grafik-tur-pfa', data, layout, {responsive: true, displayModeBar: false});
})();
</script>

<p>TUR = 4’te bile yanlış kabul olasılığı yaklaşık %1,5. 10.000 sensör sevkiyatında 150 hatalı kabul demek. Bu yüzden Z540.3 ek bir önlem öneriyor: <strong>kabul aralığını güvenlik payı kadar daraltmak</strong>. Buna <strong>güvenlik payı</strong> (İngilizcesi guard band) deniyor.</p>

<p>Z540.3 6. yöntemde güvenlik payı çarpanı M, TUR’a göre tablodan okunur. PFA’yı %2’nin altında tutmak için tipik değerler:</p>

<table>
  <thead>
    <tr>
      <th>TUR</th>
      <th>M çarpanı</th>
      <th>Güvenlik payı (= M × U)</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>4:1</td>
      <td>≈ 0,053</td>
      <td>%5,3 × U</td>
    </tr>
    <tr>
      <td>3:1</td>
      <td>≈ 0,155</td>
      <td>%15,5 × U</td>
    </tr>
    <tr>
      <td>2:1</td>
      <td>≈ 0,282</td>
      <td>%28,2 × U</td>
    </tr>
    <tr>
      <td>1:1</td>
      <td>≈ 0,457</td>
      <td>%45,7 × U</td>
    </tr>
  </tbody>
</table>

<p>TUR azaldıkça güvenlik payı büyür; bu mantıklı, çünkü belirsizlik tolerans büyüklüğüne yaklaştıkça yanlış kabul riski artıyor. Bizim örneğimiz için TUR = 4:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Güvenlik payı = 0,053 × 0,025 = 0,00133 bar
Yeni kabul aralığı = ±(0,10 − 0,00133) = ±0,09867 bar
</code></pre></div></div>

<p>Yani sensörün ölçümü 0,099 bar çıkarsa: tolerans içinde ama güvenlik payı dışında. “Sınırda, manuel inceleme” durumu.</p>

<p>Karşılaştırma için: ILAC G8 (Avrupa) güvenlik payını sade bir şekilde <strong>U</strong> olarak alır (M = 1). Bu daha muhafazakâr; bizim örneğimizde güvenlik payı 0,025 bar olur, kabul aralığı ±0,075 bar’a kadar daralır. ILAC ve ANSI farkı sahada önemli; müşterinizin hangi standardı şart koştuğuna bakın.</p>

<p><strong>Önemli bir uyarı.</strong> “TUR ≥ 4 yeter” varsayımı eski bir kuraldır. Henry Zumbrun adlı uzman 2021’de yazdığı “TUR=4 Neden Yeterli Değil” makalesinde gerçek üretim verisi üzerinden gösterdi: bir ölçüm sınıra çok yakın çıktığında TUR=4 bile %30+ yanlış kabul olasılığı yaratabilir. Bu yüzden modern uygulama, sadece TUR’a bakmak değil, gerçek PFA’yı hesaplamaktır. Z540.3 6. yöntem ya da <strong>ILAC G8</strong> (Avrupa eşdeğeri, güvenlik payı = 1×U formülünü kullanır) bu işi yapar.</p>

<blockquote>
  <p><strong>Akılda kalsın — kabul/red kararı:</strong></p>
  <ul>
    <li><strong>TUR = Tolerans / Genişletilmiş belirsizlik (U)</strong></li>
    <li><strong>Z540.3 (ABD):</strong> Yanlış kabul olasılığı (PFA) ≤ %2 olmalı; pratik değilse TUR ≥ 4. Method 6 ile güvenlik payı: TUR=4 için ≈ 0,053×U; TUR=2 için ≈ 0,28×U.</li>
    <li><strong>ILAC G8 (Avrupa):</strong> Güvenlik payı = 1×U (kabul aralığı her iki yandan U kadar daraltılır).</li>
    <li><strong>Önemli:</strong> TUR ≥ 4 yeter zannetmeyin. Ölçüm sınıra çok yakın çıkarsa TUR=4 bile %30+ yanlış kabul üretebilir. Karar verirken hem TUR’a hem ölçümün sınıra uzaklığına bakın.</li>
  </ul>
</blockquote>

<hr />

<h2 id="aviyonik-uut-üreticisi-i̇çin-ölçüm-disiplini">Aviyonik UUT Üreticisi İçin Ölçüm Disiplini</h2>

<p>Yukarıdaki üç örnek genel bir test laboratuvarı bakışıyla yazıldı. Ama bir aviyonik UUT (Unit Under Test, “test edilen cihaz”) üreten şirketin tablosu farklı. Bir VOR/ILS alıcısı üretiyorsunuz, datasheet’inize “azimuth accuracy ±0,1°” yazdınız, müşteriniz uçak üreticisi (TUSAS, Airbus, Sikorsky) bu beyana güvenerek tip sertifikasyonunu yürütüyor. Sahaya çıkan her cihaz için bu beyanı doğrulamak zorundasınız.</p>

<p>Test ekipmanınız bir RF sinyal üreticisi. Datasheet’inde “azimuth çıkış doğruluğu ±0,001°” yazıyor. Sayılar büyüleyici görünüyor: TUR = 0,1 / 0,001 = 100. Yazının ilk yarısındaki “≥ 10 → sorunsuz” kategorisinin çok ötesinde. Burada bitti, geçtik mi?</p>

<p>Hayır. Bu noktada üç gizli tuzak var ve aviyonik bağlamda her birine düşmek pahalıya patlıyor.</p>

<h3 id="önce-kavram-belirsizlik-çıkarılır-mı-eklenir-mi-yoksa-hiç-dokunulmaz-mı">Önce kavram: belirsizlik çıkarılır mı, eklenir mi, yoksa hiç dokunulmaz mı?</h3>

<p>Test laboratuvarında kabul/red kararı verirken belirsizlik üç farklı şekilde işlenebilir. Aşağıdaki grafik aynı toleransı (örnek olarak ±0,1) ve aynı ölçüm belirsizliğini (U = 0,025) üç yaklaşımla yan yana gösteriyor; her satırın yeşil bandı <strong>kabul aralığını</strong>, gri bandı toleransı temsil ediyor.</p>

<div id="grafik-uut-uretici-yaklasimlar" style="width:100%;max-width:780px;margin:1.5rem auto 2.5rem auto;height:420px;"></div>
<script>
(function(){
  var T = 0.1;
  var U = 0.025;

  var shapes = [
    // 1) Paylaşılan risk - tolerans = kabul aralığı
    {type:'rect', x0:-T,    x1:T,    y0:2.65, y1:3.35, fillcolor:'#cccccc', line:{color:'#999', width:1}},
    {type:'rect', x0:-T,    x1:T,    y0:2.85, y1:3.15, fillcolor:'#2e7d32', line:{color:'#1b5e20', width:1}, opacity:0.85},

    // 2) Korumalı kabul - kabul aralığı içeri daraltılmış (DOĞRU yaklaşım)
    {type:'rect', x0:-T,    x1:T,    y0:1.65, y1:2.35, fillcolor:'#cccccc', line:{color:'#999', width:1}},
    {type:'rect', x0:-(T-U), x1:(T-U), y0:1.85, y1:2.15, fillcolor:'#2e7d32', line:{color:'#1b5e20', width:1}, opacity:0.85},

    // 3) Korumalı red - kabul aralığı dışarı genişletilmiş (RİSK)
    {type:'rect', x0:-T,    x1:T,    y0:0.65, y1:1.35, fillcolor:'#cccccc', line:{color:'#999', width:1}},
    {type:'rect', x0:-(T+U), x1:(T+U), y0:0.85, y1:1.15, fillcolor:'#c62828', line:{color:'#8e0000', width:1}, opacity:0.75}
  ];

  var data = [
    // Tolerans sınır çizgileri (referans için her panelde)
    {x:[-T, T], y:[3, 3], type:'scatter', mode:'markers', marker:{size:0.1, color:'rgba(0,0,0,0)'}, showlegend:false, hoverinfo:'skip'},
    // Legend için sahte traceler
    {x:[null], y:[null], type:'scatter', mode:'markers', marker:{size:14, color:'#cccccc', symbol:'square', line:{color:'#999', width:1}}, name:'Tolerans aralığı (±T)'},
    {x:[null], y:[null], type:'scatter', mode:'markers', marker:{size:14, color:'#2e7d32', symbol:'square', line:{color:'#1b5e20', width:1}}, name:'Kabul aralığı (yeşil = doğru karar bölgesi)'},
    {x:[null], y:[null], type:'scatter', mode:'markers', marker:{size:14, color:'#c62828', symbol:'square', line:{color:'#8e0000', width:1}}, name:'Kabul aralığı (kırmızı = riskli, PFA yüksek)'}
  ];

  var layout = {
    title:{text:'Üç Yaklaşım: Belirsizliği Toleransla Nasıl İlişkilendirmeli?', font:{size:14}},
    xaxis:{
      title:'Ölçüm değeri',
      range:[-0.16, 0.16], zeroline:true, zerolinecolor:'#444', zerolinewidth:1,
      tickvals:[-T-U, -T, 0, T, T+U],
      ticktext:['−(T+U)', '−T', '0', '+T', '+(T+U)']
    },
    yaxis:{
      tickvals:[1, 2, 3],
      ticktext:[
        '<b>3) Korumalı red</b><br><span style="font-size:10px;color:#c62828">PFR↓, PFA↑ — RİSK</span>',
        '<b>2) Korumalı kabul</b><br><span style="font-size:10px;color:#2e7d32">UUT üreticisi: DOĞRU</span>',
        '<b>1) Paylaşılan risk</b><br><span style="font-size:10px;color:#666">eski yaklaşım</span>'
      ],
      range:[0.4, 3.6], showgrid:false, zeroline:false
    },
    shapes:shapes,
    annotations:[
      {x:0, y:3, text:'Kabul aralığı = ±T', showarrow:false, font:{size:11, color:'#fff'}, bgcolor:'rgba(0,0,0,0.35)', borderpad:2},
      {x:0, y:2, text:'Kabul aralığı = ±(T − U)', showarrow:false, font:{size:11, color:'#fff'}, bgcolor:'rgba(0,0,0,0.35)', borderpad:2},
      {x:0, y:1, text:'Kabul aralığı = ±(T + U)', showarrow:false, font:{size:11, color:'#fff'}, bgcolor:'rgba(0,0,0,0.35)', borderpad:2},
      {x:T+U, y:1, ax:T+U+0.02, ay:1, xref:'x', yref:'y', axref:'x', ayref:'y',
       text:'Tolerans dışına<br>taşıyor!', showarrow:true, arrowhead:2, font:{size:10, color:'#c62828'}, xanchor:'left'}
    ],
    showlegend:true,
    legend:{orientation:'h', x:0.5, xanchor:'center', y:-0.18, yanchor:'top', font:{size:11}},
    margin:{l:170, r:40, t:55, b:90},
    plot_bgcolor:'#ffffff', paper_bgcolor:'#ffffff'
  };
  Plotly.newPlot('grafik-uut-uretici-yaklasimlar', data, layout, {responsive:true, displayModeBar:false});
})();
</script>

<ul>
  <li><strong>1) Paylaşılan risk:</strong> Belirsizliği hesaba katmazsınız. Ölçüm tolerans içindeyse “geçti”. Eski test laboratuvarı uygulaması; ISO/IEC 17025 ile uyumlu beyan üretiyorsanız artık kabul edilmez.</li>
  <li><strong>2) Korumalı kabul (guarded acceptance):</strong> Belirsizlik tolerans sınırından <strong>içeri</strong> doğru çekilir. Müşteriyi/son kullanıcıyı korur, <strong>yanlış kabul</strong> olasılığını (PFA) düşürür. UUT üreticisi konumunda <strong>doğru</strong> yaklaşım.</li>
  <li><strong>3) Korumalı red (guarded rejection):</strong> Belirsizlik tolerans sınırından <strong>dışarı</strong> doğru itilir. Üreticiyi yanlış red’den korur ama yanlış kabul artar. Aviyonik bağlamda gerekçelendirilmesi zor.</li>
</ul>

<p>UUT üreticisi olarak ikinci sütundayım — bu yazının kalan kısmı bunu sayısal hale getiriyor.</p>

<h3 id="risk-yönü-tartışılır-değil">Risk yönü tartışılır değil</h3>

<p>Test laboratuvarında “shared risk” denilen bir uygulama yaygındır: belirsizliği hesaba katmazsın, ölçüm tolerans içindeyse geçer. Bunun temeli müşteri ile laboratuvar arasında risk paylaşımıdır. UUT üreticisi konumunda bu seçeneğiniz <strong>yok</strong>. Beyan size ait, kabul kararı sizin, sahaya çıkan cihazın sorumluluğu da sizin. İki olası hatanın bedeli aynı değildir:</p>

<table>
  <thead>
    <tr>
      <th>Hata türü</th>
      <th>Bedel</th>
      <th>Kim öder</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Yanlış kabul (PFA)</td>
      <td>Bozuk cihaz uçar</td>
      <td>Pilot, yolcu, üretici (sertifika kaybı)</td>
    </tr>
    <tr>
      <td>Yanlış red (PFR)</td>
      <td>Sağlam cihaz hurdaya gider</td>
      <td>Sadece üretici (üretim maliyeti)</td>
    </tr>
  </tbody>
</table>

<p>Bu asimetrik risk profilinde <strong>belirsizlik her zaman içeri çekilir</strong>, yani kabul aralığı toleranstan daraltılır. Yukarıdaki üç yaklaşımdan tek meşru olanı bu. Ekleme (kabul aralığını genişletme) yönü, DO-178C DAL A bir LRU için sertifikasyon denetiminde gerekçelendirilemez.</p>

<h3 id="hangi-standart-ilac-g8-default">Hangi standart: ILAC G8 default</h3>

<p>Türkiye’de TÜRKAK akreditasyonu üzerinden çalıştığınız için doğal default <strong>ILAC G8</strong> ve onun Avrupa eşdeğeri <strong>EA-4/02</strong>:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Kabul aralığı = ±(T − U)
</code></pre></div></div>

<p>Müşteriniz ABD merkezliyse (Lockheed, Raytheon, Boeing tedarik zincirinde değilseniz bile) sözleşme <strong>Z540.3</strong> atfı içerebilir. O durumda Method 6 ile TUR’a bağlı M çarpanı kullanırsınız. Pratik fark: ILAC G8 bütün TUR değerleri için 1×U çıkarır; Z540.3 yüksek TUR’da daha az çıkarır. Yani yüksek TUR’da Z540.3 daha gevşek, ILAC G8 daha muhafazakâr. Aviyonik için muhafazakâr olan tarafta kalın.</p>

<p>İki müşteri tipi de varsa rapor şablonunu çift sütun yapın: “ILAC G8 kabul aralığı: ±X” ve “Z540.3 kabul aralığı: ±Y”. Sahada hangisini uygulayacağınızı sözleşme belirler.</p>

<h3 id="datasheet-speci-son-çaredir">Datasheet spec’i son çaredir</h3>

<p>Sinyal üreticinizin datasheet’inde “±0,001°” yazıyor. Bu satır, üreticinin geniş bir cihaz popülasyonu için garanti ettiği en kötü durumdur. Sizin elinizdeki tek tek cihaz büyük olasılıkla daha iyidir. Ama bunu nasıl bilirsiniz?</p>

<p><strong>Akredite kalibrasyon belgesi.</strong> Sinyal üreticinizi TÜRKAK akredite (veya ulusal eşdeğer) bir laboratuvarda yıllık olarak kalibre ettirdiğinizde belgenizde “ölçülen değer = X, U = ±0,0002° (k=2)” tarzında bir veri olur. Bu sayı genelde datasheet spec’inin 3-10 katı küçüktür. Belirsizlik bütçenizde <strong>datasheet spec’i değil bu belgenin U’sunu</strong> kullanın.</p>

<p>Datasheet spec ne zaman kullanılır? İki durumda:</p>

<ol>
  <li>Sinyal üretici hiç kalibre edilmedi (kötü uygulama, akreditasyon denetimi takılır).</li>
  <li>Kalibrasyon belgesi var ama ölçüm yaptığınız belirli noktayı kapsamıyor (interpolasyon yapamıyorsunuz).</li>
</ol>

<p>Spec’i kullanırken yazıdaki kuralı uygulayın: bilgi yoksa düz dağılım, u = a / √3.</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>u_kaynak (datasheet)                       = 0,001 / √3   ≈ 0,000577°
u_kaynak (akredite belge, U=0,0002, k=2)   = 0,0002 / 2   = 0,0001°
</code></pre></div></div>

<p>Akredite belgeyle çalışırsanız bu bileşenden gelen katkı yaklaşık <strong>6 kat</strong> azalır.</p>

<h3 id="specin-geçerlilik-kapsamına-bakın">Spec’in geçerlilik kapsamına bakın</h3>

<p>Datasheet spec’i her zaman bir koşullar paketinin içinde geçerlidir:</p>

<ul>
  <li><strong>Sıcaklık aralığı:</strong> “23 °C ± 5 °C” tipik. Lab sıcaklığınız bu aralık dışında salınıyorsa spec geçersiz, ek bir tempco (sıcaklık katsayısı) bileşeni ekleyin.</li>
  <li><strong>Takvim:</strong> “90 gün spec” ve “1 yıl spec” sayıları farklıdır. Son kalibrasyondan bu yana ne kadar zaman geçti?</li>
  <li><strong>Isınma süresi:</strong> “30 dakika ısınma sonrası” yazıyorsa, üretimdeki testlerde bunu uygulayın.</li>
  <li><strong>Ölçüm bandı:</strong> Spec belli bir frekans ya da seviye aralığında geçerli olabilir. VOR sinyali için 108–118 MHz, ILS için 108–112 MHz gibi.</li>
</ul>

<p>Bu kapsam dışında kullanırsanız spec’i kullanmaya hakkınız yok. F Eki 7. uyarısının (gizli sıcaklık tuzağı) tersi: <strong>kapsam içindeyken çift saymak</strong>, <strong>kapsam dışındayken eksik saymak</strong> sık yapılan hata.</p>

<h3 id="bileşen-listesi-tek-satıra-düşmez">Bileşen listesi tek satıra düşmez</h3>

<p>±0,001° spec’ini tek bileşen olarak kullanmak yetmez. Bir VOR alıcısı azimuth doğruluğu testi için tipik bütçe şöyle görünür:</p>

<table>
  <thead>
    <tr>
      <th>#</th>
      <th>Kaynak</th>
      <th>Aralık</th>
      <th>Dağılım</th>
      <th>Bölme</th>
      <th>u (°)</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>1</td>
      <td>Sinyal üretici (akredite belge, k=2)</td>
      <td>±0,0002</td>
      <td>normal</td>
      <td>2</td>
      <td>0,0001</td>
    </tr>
    <tr>
      <td>2</td>
      <td>Sinyal üretici 1 yıllık drift</td>
      <td>±0,0005</td>
      <td>düz</td>
      <td>√3</td>
      <td>0,00029</td>
    </tr>
    <tr>
      <td>3</td>
      <td>Sinyal üretici tempco (lab Δ=±3 °C)</td>
      <td>±0,0003</td>
      <td>düz</td>
      <td>√3</td>
      <td>0,00017</td>
    </tr>
    <tr>
      <td>4</td>
      <td>UUT çözünürlüğü (0,01° son hane)</td>
      <td>±0,005</td>
      <td>düz</td>
      <td>√3</td>
      <td>0,00289</td>
    </tr>
    <tr>
      <td>5</td>
      <td>RF kablo kayıp/faz</td>
      <td>±0,002</td>
      <td>düz</td>
      <td>√3</td>
      <td>0,00115</td>
    </tr>
    <tr>
      <td>6</td>
      <td>Tip A (n=10 ölçüm, s=0,003°)</td>
      <td>s/√10</td>
      <td>normal</td>
      <td>√10</td>
      <td>0,00095</td>
    </tr>
    <tr>
      <td>7</td>
      <td>Multipath / antenna kuplajı</td>
      <td>±0,001</td>
      <td>düz</td>
      <td>√3</td>
      <td>0,00058</td>
    </tr>
    <tr>
      <td>8</td>
      <td>UUT ısınma + tempco</td>
      <td>±0,002</td>
      <td>düz</td>
      <td>√3</td>
      <td>0,00115</td>
    </tr>
  </tbody>
</table>

<p>Birleşik belirsizlik:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>u² = 0,0001² + 0,00029² + 0,00017² + 0,00289² + 0,00115²
   + 0,00095² + 0,00058² + 0,00115²
u² ≈ 1,24 × 10⁻⁵
u  ≈ 0,0035°

U  = 2 × 0,0035 ≈ 0,007°  (k=2)
</code></pre></div></div>

<p>Yani gerçek ölçüm belirsizliğiniz <code class="language-plaintext highlighter-rouge">±0,007°</code> mertebesinde. Datasheet spec’inden gelen <code class="language-plaintext highlighter-rouge">±0,001°</code> ise toplamın yalnızca <strong>küçük bir parçası</strong>. Çözünürlük (4. satır) ve RF kablolama (5. ve 8. satırlar) çok daha büyük katkı veriyor.</p>

<h3 id="kabul-aralığı-ve-karar">Kabul aralığı ve karar</h3>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>TUR     = 0,1 / 0,007 ≈ 14,3
Kabul aralığı (ILAC G8) = ±(0,1 − 0,007) = ±0,093°
</code></pre></div></div>

<p>UUT’nin ölçülen azimuth hatası <code class="language-plaintext highlighter-rouge">±0,093°</code> içindeyse “azimuth accuracy ±0,1° spec’ini karşılıyor” beyanı verebilirsiniz. <code class="language-plaintext highlighter-rouge">±0,093°</code> ile <code class="language-plaintext highlighter-rouge">±0,1°</code> arasındaysa cihaz <strong>sınır bölgesinde</strong> — yazılı prosedürünüze göre bu cihazları ya tekrar test edersiniz, ya manuel inceleme yaparsınız, ya da reddedersiniz. Fail-safe tarafa düşmek için reddetmek en güvenlisidir.</p>

<h3 id="üç-katmanlı-koruma">Üç katmanlı koruma</h3>

<p>Bütün bu hesabı yapsanız bile sahaya çıkan her cihazın spec içinde kalması garanti değildir. Aviyonikte standart pratik <strong>çift güvence</strong>:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Tasarım hedefi   ⊆   Kabul aralığı   ⊆   Beyan toleransı
   (±0,05°)            (±0,093°)            (±0,1°)
</code></pre></div></div>

<ul>
  <li><strong>Tasarım hedefi (±0,05°):</strong> R&amp;D ekibi devre tasarımını bu hedefe göre yapar; üretim sürecindeki normal varyasyonun beyana taşması engellenir.</li>
  <li><strong>Kabul aralığı (±0,093°):</strong> Üretim sonu testte kullanılan eşik. Ölçüm belirsizliği çıkarılmış halidir.</li>
  <li><strong>Beyan toleransı (±0,1°):</strong> Datasheet’te yazan, müşteriye verilen söz.</li>
</ul>

<p>Bu üç sınır arasındaki boşluklar — <code class="language-plaintext highlighter-rouge">0,05°</code> tasarım marjı ve <code class="language-plaintext highlighter-rouge">0,007°</code> ölçüm marjı — emniyet kritik sistemde “ücretsiz öğle yemeği” değildir; üretim verim kaybı (yield loss) olarak para olarak ödenir. Ama VOR/ILS bir LRU’nun sahada <code class="language-plaintext highlighter-rouge">±0,12°</code> ile gelmesinin bedeli, bir avukatın saatlik ücretiyle ölçülür. Yatırım bu açıdan değerlendirilir.</p>

<h3 id="do-178c-do-254-ve-veri-yönetimi">DO-178C, DO-254 ve veri yönetimi</h3>

<p>Bütün belirsizlik bütçeniz konfigürasyon yönetimi altında saklanmalı. Pratik kontroller:</p>

<ul>
  <li>Bütçe dökümanı bir baseline’a (DOORS, SVN vb.) bağlı; revizyon geçmişi var.</li>
  <li>Test prosedürü (TPS) bütçeyi atıf olarak gösteriyor.</li>
  <li>Sinyal üretici kalibrasyon belgeleri (PDF) prosedürün ek dosyaları olarak kayıtlı.</li>
  <li>ATR (Acceptance Test Report) her seri için: ölçüm değeri, U, k, kabul aralığı, karar — dört sütunlu.</li>
  <li>Akreditasyon denetiminde her bütçe satırı için <strong>gerekçe belgesi</strong> istenir (PDF varsayımı, dağılım seçimi, bağımsızlık kararı).</li>
</ul>

<p>DO-178C’nin doğrudan ölçüm belirsizliği zorunluluğu yoktur — yazılım standardıdır. Ama DO-254 (donanım), ARP4761 (emniyet değerlendirme) ve müşteriye verilen Hardware Acceptance Data Sheet’ler bütçeyi varsayar. ARP4761 FHA/PSSA aşamalarında “ölçüm doğrulanmamış” bir donanım performansı argüman olarak kullanılamaz.</p>

<h3 id="aviyonik-uut-üreticisi-için-kontrol-listesi">Aviyonik UUT üreticisi için kontrol listesi</h3>

<ol>
  <li><strong>Default ILAC G8’i seçin</strong>, müşteri Z540.3 isterse iki sütunlu rapor verin. Eklemeyi (genişletmeyi) hiçbir koşulda kullanmayın.</li>
  <li><strong>Sinyal üreticilerini akredite labda kalibre ettirin</strong>, datasheet spec’ini sadece son çare olarak kullanın.</li>
  <li><strong>Spec geçerlilik kapsamını okuyun</strong>: sıcaklık, takvim, ısınma, frekans, seviye. Lab koşullarınız dışındaysa ek bileşen ekleyin.</li>
  <li><strong>Bütçeyi tek satıra düşürmeyin</strong>: çözünürlük, RF kablolama, multipath, UUT tempco — hepsi aviyonikte kayda değer katkı verir.</li>
  <li><strong>Üç katmanlı koruma</strong>: tasarım hedefi &lt; kabul aralığı &lt; beyan toleransı. Tasarım marjı R&amp;D’nin işidir, ölçüm marjı sizin işiniz.</li>
  <li><strong>TUR yeterli sayılmaz</strong>: TUR=14 olsa bile guard band uygulayın. TUR &lt; 4 olursa ya bütçeyi düşürün ya beyanı gevşetin — denetimde “işte böyle çıkıyor” demek geçerli savunma değil.</li>
  <li><strong>Bütçeyi konfigürasyon yönetimi altına alın</strong>: revizyon, gerekçe, ek belgeler. Akreditasyon ve sertifikasyon denetiminde her satır sorulur.</li>
</ol>

<blockquote>
  <p><strong>Akılda kalsın — UUT üreticisi için altın kural:</strong></p>
  <ul>
    <li>Risk size ait → belirsizlik <strong>çıkarılır</strong>, eklenmez.</li>
    <li>Datasheet spec değil, akredite kalibrasyon belgesi.</li>
    <li>Spec geçerlilik kapsamı dışındaysa, ek bileşen.</li>
    <li>Tasarım hedefi, kabul aralığı ve beyan toleransı <strong>üç ayrı sayıdır</strong>; arada para kaybedersiniz, kaybetmek zorundasınız.</li>
    <li>TUR ≥ 4 yeterli değil; PFA hesaplı guard band uygulayın.</li>
  </ul>
</blockquote>

<hr />

<h2 id="yedi-pratik-tavsiye">Yedi Pratik Tavsiye</h2>

<p>Yazıyı bir el kitabına dönüştürelim. Yarın işe gittiğinizde uygulayabileceğiniz somut yedi madde:</p>

<ol>
  <li>
    <p><strong>Belirsizlik bütçesini test prosedürünün parçası yapın.</strong> Test belgesinin içine “belirsizlik bütçesi” başlıklı bir bölüm koyun. Sonradan eklenen bütçe çoğunlukla eksik kalır.</p>
  </li>
  <li>
    <p><strong>Tek ölçüm yapmayın.</strong> En az 10 tekrar ölçüm. Mümkünse iki farklı operatör, iki farklı gün. Kıdemli mühendis “bir kez ölçtüm geçti” derse, “tekrar yapalım” deyin.</p>
  </li>
  <li>
    <p><strong>Kalibrasyon belgelerini saklayın.</strong> Her cihazın izlenebilirlik zincirinde TÜRKAK akreditasyonlu bir laboratuvarın belgesi olmalı. Belge numaralarını test belgesine yazın. Akreditasyon denetiminde her birinin sorulması olası.</p>
  </li>
  <li>
    <p><strong>İlişkili kaynakları arayın.</strong> Aynı kalibratörden iki cihaz besleniyorsa, sertifika belirsizlikleri ilişkili. Aynı oda, aynı kullanıcı, aynı kablolar; bunlar ilişki yaratır. Bağımsızlık varsayımı doğal değildir, doğru olduğunu göstermek size düşer.</p>
  </li>
  <li>
    <p><strong>PDF varsayımlarını yazılı gerekçelendirin.</strong> “Düz dağılım kullandım çünkü üretici belirtmedi” gibi bir not her satırın yanında olsun.</p>
  </li>
  <li>
    <p><strong>TUR ≥ 4 yeterli demeyin.</strong> Yanlış kabul olasılığını hesaplayın. Z540.3 6. yöntem ya da ILAC G8 ile güvenlik payı ekleyin.</p>
  </li>
  <li>
    <p><strong>Sonucu doğru ifade edin.</strong> “Geçti” yerine: “9,999889 V, U = 56 µV (k=2). Tolerans 10,000 V ± 100 µV. Sonuç: tolerans içinde, güvenlik payı içinde.” Sayı + birim + belirsizlik + k dörtlüsü eksik olduğunda rapor da eksik.</p>
  </li>
</ol>

<hr />

<h2 id="hızlı-referans-kartı">Hızlı Referans Kartı</h2>

<p>Bu bölümü ayrı bir sayfaya yazdırıp masanızın üstüne koyabilirsiniz. Belirsizlik bütçesi yaparken sürekli geri dönülen şablon.</p>

<h3 id="adım-adım-belirsizlik-hesabı">Adım adım belirsizlik hesabı</h3>

<ol>
  <li>Ölçtüğünüz büyüklüğün <strong>bileşenlerini listeleyin</strong> (Tip A + Tip B kaynakları).</li>
  <li>Her bileşen için <strong>standart belirsizliği</strong> (u) hesaplayın:
    <ul>
      <li>Tip A: birden fazla ölçüm → s/√n</li>
      <li>Tip B: aralığı dağılım faktörüne böl</li>
    </ul>
  </li>
  <li><strong>Birleşik belirsizlik:</strong> u = √(Σ uᵢ²)</li>
  <li><strong>Genişletilmiş belirsizlik:</strong> U = k × u (genelde k = 2)</li>
  <li><strong>Sonucu yazın:</strong> “X = (değer ± U) birim, k = 2”</li>
  <li><strong>TUR kontrol edin:</strong> TUR = Tolerans / U; gerekirse güvenlik payı uygulayın.</li>
</ol>

<h3 id="aralık--standart-belirsizlik-dönüşüm-tablosu">Aralık → standart belirsizlik dönüşüm tablosu</h3>

<table>
  <thead>
    <tr>
      <th>Veri kaynağı</th>
      <th>Standart belirsizlik formülü</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Sertifika "U, k=2"</td>
      <td>u = U / 2</td>
    </tr>
    <tr>
      <td>Sertifika "U, k=3"</td>
      <td>u = U / 3</td>
    </tr>
    <tr>
      <td>Üretici spec "±a" (bilgi yok)</td>
      <td>u = a / √3</td>
    </tr>
    <tr>
      <td>"Merkez yakını daha olası"</td>
      <td>u = a / √6</td>
    </tr>
    <tr>
      <td>Termostat dalgalanması</td>
      <td>u = a / √2</td>
    </tr>
    <tr>
      <td>Tip A: n ölçüm, ortalama raporlanır</td>
      <td>u = s / √n</td>
    </tr>
    <tr>
      <td>Tip A: tek ölçüm raporlanır</td>
      <td>u = s</td>
    </tr>
  </tbody>
</table>

<h3 id="karar-kuralı">Karar kuralı</h3>

<table>
  <thead>
    <tr>
      <th>TUR (Tolerans / U)</th>
      <th>Yaklaşık PFA</th>
      <th>Yapılacak</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>≥ 10</td>
      <td>≤ %0,1</td>
      <td>Sorunsuz</td>
    </tr>
    <tr>
      <td>≥ 4</td>
      <td>≤ %1,5</td>
      <td>Z540.3 sınırı, dikkat</td>
    </tr>
    <tr>
      <td>2–4</td>
      <td>%2–8</td>
      <td>Güvenlik payı şart</td>
    </tr>
    <tr>
      <td>&lt; 2</td>
      <td>%8+</td>
      <td>Belirsizliği düşür ya da toleransı gevşet</td>
    </tr>
  </tbody>
</table>

<h3 id="akreditasyon-denetiminde-sorulanlar">Akreditasyon denetiminde sorulanlar</h3>

<ul>
  <li>Her cihazın izlenebilirlik zinciri belge numarası var mı?</li>
  <li>Tip B bileşenleri için PDF varsayımı <strong>yazılı gerekçesi</strong> var mı?</li>
  <li>Bağımsızlık varsayımı kontrol edildi mi (aynı kalibratör, aynı operatör)?</li>
  <li>Tip A ölçümleri arasında koşullar gerçekten yenilendi mi?</li>
  <li>TUR &lt; 4 ise PFA hesabı belgelenmiş mi?</li>
  <li>Sonuç raporu “değer + birim + U + k” dörtlüsünü içeriyor mu?</li>
</ul>

<h3 id="belirsizlik-bütçesi-şablonu-kopyala-doldur">Belirsizlik bütçesi şablonu (kopyala-doldur)</h3>

<table>
  <thead>
    <tr>
      <th>#</th>
      <th>Kaynak</th>
      <th>Aralık</th>
      <th>Dağılım</th>
      <th>Bölme</th>
      <th>u (birim)</th>
      <th>u²</th>
      <th>Katkı %</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>1</td>
      <td>(örn. kalibrasyon belgesi)</td>
      <td>± …</td>
      <td>normal</td>
      <td>2</td>
      <td>…</td>
      <td>…</td>
      <td>…</td>
    </tr>
    <tr>
      <td>2</td>
      <td>(örn. çözünürlük)</td>
      <td>± …</td>
      <td>düz</td>
      <td>√3</td>
      <td>…</td>
      <td>…</td>
      <td>…</td>
    </tr>
    <tr>
      <td>3</td>
      <td>(örn. sıcaklık etkisi)</td>
      <td>± …</td>
      <td>düz</td>
      <td>√3</td>
      <td>…</td>
      <td>…</td>
      <td>…</td>
    </tr>
    <tr>
      <td>4</td>
      <td>(örn. drift)</td>
      <td>± …</td>
      <td>düz</td>
      <td>√3</td>
      <td>…</td>
      <td>…</td>
      <td>…</td>
    </tr>
    <tr>
      <td>5</td>
      <td>(Tip A, n ölçüm)</td>
      <td>s = …</td>
      <td>normal</td>
      <td>√n</td>
      <td>…</td>
      <td>…</td>
      <td>…</td>
    </tr>
    <tr>
      <td> </td>
      <td>**Birleşik (u)**</td>
      <td> </td>
      <td> </td>
      <td> </td>
      <td>**√Σ**</td>
      <td>**= ?**</td>
      <td>%100</td>
    </tr>
    <tr>
      <td> </td>
      <td>**Genişletilmiş (U, k=2)**</td>
      <td> </td>
      <td> </td>
      <td> </td>
      <td>**2u**</td>
      <td> </td>
      <td> </td>
    </tr>
  </tbody>
</table>

<p>Tabloyu doldurduktan sonra “Katkı %” sütunu hangi bileşenin en çok katkıyı verdiğini gösterir; iyileştirmeye en büyük yüzdeden başlayın.</p>

<hr />

<h2 id="sonuç">Sonuç</h2>

<p>GUM teorik temeli kuruyor, <strong>F eki</strong> günlük ölçüm yapan mühendise yönelik en pratik bölüm. NCSLI RP-12 GUM’u günlük dile çeviriyor, somut tablo ve şablonlar veriyor. ANSI Z540.3 ile birleşince kalibrasyon laboratuvarlarının uyması gereken kurallar bütünü ortaya çıkıyor.</p>

<p>Türkiye’de uçak elektroniği (TUSAS, BAYKAR), savunma (ASELSAN, ROKETSAN), otomotiv (Togg ve tedarikçileri) ve medikal cihaz alanında bu disiplin yavaş yavaş zorunlu hale geliyor. Akreditasyon denetimleri sertleşiyor, müşteriler belirsizlik bütçesini bir formalite değil mühendislik ürünü olarak istiyor. Aviyonik UUT üreticisi konumunda olanlar için ek bir disiplin var: belirsizlik daima toleranstan <strong>çıkarılır</strong>, üç katmanlı koruma (tasarım hedefi → kabul aralığı → beyan toleransı) standart pratiktir, ve bütün bütçe konfigürasyon yönetimi altında izlenebilir olmalıdır.</p>

<p>Bir test mühendisinin işi sadece sayı üretmek değil. Sayının yanına eklenecek “± şu kadar” değerini de üretmek. Bu olmadan “geçti” sözünün ölçüsel bir karşılığı yok; sadece bir tahmin.</p>

<p>Bir sonraki yazıda aynı problemleri <strong>Monte Carlo simülasyonu</strong> ile çözeceğiz. Doğrusal olmayan ölçüm modellerinde (radyo frekans güç ölçümü, dinamik basınç gibi) klasik kareli toplam yaklaşımı yetersiz kalır; bilgisayarda 100.000 simülasyon yaparak dağılımı doğrudan üretmek gerekir.</p>

<hr />

<h2 id="kaynaklar">Kaynaklar</h2>

<ul>
  <li><a href="https://www.bipm.org/documents/20126/2071204/JCGM_100_2008_E.pdf">JCGM 100:2008 — Ölçüm Belirsizliğinin İfadesi Kılavuzu (BIPM PDF)</a></li>
  <li><a href="https://www.bipm.org/documents/20126/2071204/JCGM_101_2008_E.pdf">JCGM 101:2008 — Monte Carlo ile Belirsizlik Dağılımı (Ek 1)</a></li>
  <li><a href="https://www.bipm.org/documents/20126/2071204/JCGM_GUM_6_2020.pdf">JCGM GUM-6:2020 — Ölçüm Modelleri Geliştirme ve Kullanma</a></li>
  <li><a href="https://www.iso.org/sites/JCGM/GUM/JCGM100/C045315e-html/C045315e_FILES/MAIN_C045315e/AF_e.html">GUM F Eki — Belirsizlik Bileşenlerini Hesaplamak için Pratik Rehber (HTML)</a></li>
  <li><a href="https://www.iso.org/sites/JCGM/GUM/JCGM100/C045315e-html/C045315e_FILES/MAIN_C045315e/AH_e.html">GUM H Eki — Sayısal Örnekler (HTML)</a></li>
  <li><a href="https://ncsli.org/store/viewproduct.aspx?id=16960491">NCSLI RP-12: Ölçüm Belirsizliklerini Belirleme ve Raporlama (2013)</a></li>
  <li><a href="https://www.isobudgets.com/pdf/uncertainty-guides/ea-4-02-m-2013-expression-of-the-uncertainty-of-measurement-in-calibration.pdf">EA-4/02 M:2013 — Avrupa Kalibrasyon Belirsizliği Rehberi</a></li>
  <li><a href="https://ilac.org/publications-and-resources/ilac-guidance-series/">ILAC G8:09/2019 — Uygunluk Beyanı Kuralları için Rehber</a></li>
  <li><a href="https://mhforce.com/wp-content/uploads/2021/04/TUR-is-not-enough-1-1.pdf">Henry Zumbrun — TUR=4 Neden Yeterli Değil (Morehouse, 2021)</a></li>
  <li><a href="https://incompliancemag.com/using-welch-satterthwaite-formula-in-uncertainty-analysis/">Welch-Satterthwaite Formülü Pratik Açıklaması (In Compliance Magazine)</a></li>
  <li><a href="https://www.isobudgets.com/calculating-effective-degrees-of-freedom/">Etkin Serbestlik Derecesi Hesabı (ISOBudgets)</a></li>
  <li><a href="https://www.isobudgets.com/guard-banding-how-to-take-uncertainty-into-account/">Güvenlik Payı (Guard Band) Açıklaması (ISOBudgets)</a></li>
  <li><a href="https://www.fluke.com/en-us/learn/blog/pressure-calibration/guide-determining-pressure-measurement-uncertainty">Basınç Ölçüm Belirsizliği Rehberi (Fluke Calibration)</a></li>
  <li><a href="https://www.rtca.org/training-courses/do-254-design-assurance-guidance-for-airborne-electronic-hardware/">RTCA DO-254 — Aviyonik Donanım Tasarım Güvencesi Rehberi</a></li>
  <li><a href="https://www.sae.org/standards/content/arp4761/">SAE ARP4761 — Sivil Hava Sistemleri Güvenlik Değerlendirme Rehberi</a></li>
  <li><a href="https://www.ume.tubitak.gov.tr/">TÜBİTAK UME — Ulusal Metroloji Enstitüsü</a></li>
  <li><a href="https://www.turkak.org.tr/">TÜRKAK — Türk Akreditasyon Kurumu</a></li>
</ul>]]></content><author><name>M. Serdar Karaman</name></author><category term="muhendislik" /><category term="metroloji" /><summary type="html"><![CDATA[]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://karaman.dev/img/og-default.webp" /><media:content medium="image" url="https://karaman.dev/img/og-default.webp" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry xml:lang="tr"><title type="html">Yöneylem Araştırması Yöntemleri: Kesin ve Metasezgisel Yaklaşımlar</title><link href="https://karaman.dev/2026/04/14/operasyonel-arastirma-yontemleri.html" rel="alternate" type="text/html" title="Yöneylem Araştırması Yöntemleri: Kesin ve Metasezgisel Yaklaşımlar" /><published>2026-04-14T09:00:00+00:00</published><updated>2026-04-14T09:00:00+00:00</updated><id>https://karaman.dev/2026/04/14/operasyonel-arastirma-yontemleri</id><content type="html" xml:base="https://karaman.dev/2026/04/14/operasyonel-arastirma-yontemleri.html"><![CDATA[<p>Gündelik hayatın ve iş süreçlerinin pek çok problemi yüzeyde sezgisel bir karar gibi görünse de aslında birer <strong>optimizasyon</strong> problemidir. Hangi ürünü ne kadar üreteceğiz? Sınırlı kamyon filosuyla siparişleri hangi rotada dağıtacağız? Bir çantaya ağırlık ve değer kısıtları altında hangi eşyaları koyacağız? Bir hastanede hemşire nöbet çizelgesini nasıl yapacağız? Bu soruların ortak paydası şudur: <strong>sınırlı kaynakları sınırlı kısıtlar altında bir amaca göre en iyileyecek şekilde dağıtmak.</strong></p>

<p>İşte <strong>Yöneylem Araştırması</strong> (İngilizce <em>Operational Research</em> veya <em>Operations Research</em>, kısaca OR), bu sorunları sistematik biçimde çözmek için geliştirilmiş disiplinin adıdır. Bu yazıda OR’un iki büyük yöntem ailesini — <strong>kesin (exact) yöntemler</strong> ve <strong>metasezgisel (metaheuristic) yöntemler</strong> — tanımları ve klasik örnekleriyle inceleyeceğiz. Linear Programming (LP), Integer Programming (IP), Binary Integer Programming (BIP), Mixed-Integer Programming (MIP) ve Dynamic Programming (DP) kesin yöntemleri oluşturur. Genetic Algorithm (GA), Simulated Annealing (SA), Tabu Search (TS) ve Ant Colony Optimization (ACO) ise problem çok büyüdüğünde devreye giren metasezgisel ailenin temsilcileridir. Sonunda iki dünyayı birleştiren <strong>matheuristic</strong> yaklaşıma ve “hangi problem hangi yöntemi ister?” sorusuna pratik bir çerçeve sunacağız.</p>

<hr />

<h2 id="kısa-bir-tarihçe-or-nasıl-doğdu">Kısa Bir Tarihçe: OR Nasıl Doğdu?</h2>

<p>Yöneylem araştırmasının kökleri İkinci Dünya Savaşı’na uzanır. 1940 Ağustos’unda, Britanya Hava Savaşı’nın tam ortasında, fizikçi <strong>Patrick Blackett</strong> İngiliz ordusunun Anti-Aircraft Command’ı için bir bilim insanları grubu kurdu. Bu grup — tarihe “Blackett’s Circus” (Blackett’ın Sirki) olarak geçti — anti-uçak toplarının düşman bombardımanlarını düşürme oranını iyileştirmek için mekanik hesaplama sistemlerini analiz etti. Sonuç çarpıcıydı: bir düşman uçağını düşürmek için gereken ortalama mermi sayısı, Britanya Hava Savaşı’nın başlangıcındaki <strong>20.000’den 1941’de 4.000’e</strong> indirildi.</p>

<p>1941’de Blackett RAF Coastal Command’a geçti ve burada başka bir ekip kurarak Alman U-botlarına karşı kullanılan konvoy taktiklerini, derinlik bombası ayarlarını ve uçak kamuflajını analiz etti. Kaleme aldığı “Scientists at the Operational Level” (Operasyonel Düzeyde Bilim İnsanları) başlıklı dâhili memorandum, modern “operational research” kavramının ilk resmi tanımlarından biri kabul edilir. Savaş bitmeden çok önce OR, stratejik askeri karar vermenin vazgeçilmez parçası olmuştu.</p>

<p>Savaş sonrasında disiplin hızla sanayiye taşındı. 1946’da Amerikan Ordusu için mekanizasyon çalışmaları yürüten genç bir matematikçi olan <strong>George Dantzig</strong>, 1947 yılının yazında <strong>simpleks yöntemini</strong> geliştirdi; böylece doğrusal programlama (linear programming) tekniği doğmuş oldu. “Linear programming” terimini kendisi değil, 1948’de Dantzig’in RAND Corporation’a yaptığı ziyarette meslektaşı <strong>Tjalling Koopmans</strong> önermiştir. 1952’de RAND’e katılan <strong>Richard Bellman</strong>, çok aşamalı karar problemlerini modellemek için <strong>dinamik programlama</strong>yı geliştirdi ve 1957’de aynı adı taşıyan klasik kitabı yayımladı.</p>

<p>1960’larda Ailsa Land ve Alison Doig’in <strong>dal-sınır (branch-and-bound)</strong> algoritması, Ralph Gomory’nin <strong>kesme düzlemleri</strong> (cutting planes) ve 1970’lerde John Holland’ın <strong>genetik algoritmaları</strong> ile alan hızla zenginleşti. 1980’lerle birlikte Kirkpatrick ve ekibinin <strong>benzetimli tavlaması</strong>, Glover’ın <strong>tabu araması</strong> ve Dorigo’nun <strong>karınca kolonisi optimizasyonu</strong> metasezgisel devrimi başlattı. Bugün OR, üretimden lojistiğe, sağlıktan finansa, enerjiden telekomünikasyona pek çok sektörün arka planında sessizce çalışan bir bilim dalıdır.</p>

<p>İlginçtir, OR’un bu erken dönem araştırmacılarının birçoğu Nobel ödülü kazandı: Koopmans 1975’te “kaynakların optimal tahsisi” üzerine yaptığı çalışmalarla Ekonomi Nobel’i aldı; 1994’te John Nash, John Harsanyi ve Reinhard Selten oyun teorisi üzerinden ödüle layık görüldü. Dantzig’in adı uzun yıllar Nobel için geçmesine rağmen ödül sadece ekonomi ve barış gibi alanlara verildiğinden matematiğe özgü Fields Madalyası’na da uygun olmadığı için resmi bir büyük ödül alamadı; fakat akademik camiada SIAM tarafından onun adına “Dantzig Prize” oluşturuldu ve her iki yılda bir matematiksel programlamaya katkı yapan bir bilim insanına verilir.</p>

<hr />

<h2 id="yöneylem-araştırması-nedir">Yöneylem Araştırması Nedir?</h2>

<p>Her OR probleminin üç temel bileşeni vardır:</p>

<ol>
  <li><strong>Karar değişkenleri</strong> (decision variables): Çözümü oluşturan, kontrol edebildiğimiz büyüklükler. Bir işçi sayısı, bir makinenin çalışma süresi, “bu kamyon o depoya gidecek mi?” gibi ikili kararlar.</li>
  <li><strong>Amaç fonksiyonu</strong> (objective function): Maksimize ya da minimize etmek istediğimiz ölçüt. Kâr, maliyet, süre, yakıt tüketimi gibi.</li>
  <li><strong>Kısıtlar</strong> (constraints): Gerçek hayatın çözüme dayattığı sınırlar. Bütçe, kapasite, zaman pencereleri, talep miktarları gibi.</li>
</ol>

<p>Genel bir optimizasyon problemi matematiksel olarak şöyle yazılır:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>min (veya max)    f(x)
s.t.              g_i(x) ≤ 0,   i = 1..m
                  h_j(x) = 0,   j = 1..k
                  x ∈ X
</code></pre></div></div>

<p>Burada <code class="language-plaintext highlighter-rouge">f</code> amaç fonksiyonu, <code class="language-plaintext highlighter-rouge">g_i</code> eşitsizlik kısıtları, <code class="language-plaintext highlighter-rouge">h_j</code> eşitlik kısıtları ve <code class="language-plaintext highlighter-rouge">X</code> karar değişkenlerinin bulunabileceği bölgedir (sürekli sayılar, tam sayılar, ikili değerler vb.).</p>

<p>Bu üçlü formüle edildikten sonra iki temel soru ortaya çıkar: <strong>(a)</strong> çözüm uzayı ne kadar büyük? ve <strong>(b)</strong> garantili optimal mi, yoksa makul sürede “yeterince iyi” bir çözüm mü istiyoruz? Bu iki soruya verilen yanıt sizi ya kesin yöntemlere ya da metasezgisellere yöneltir. Bir sonraki bölümlerde bu iki aileyi tek tek ele alacağız.</p>

<hr />

<h2 id="kesin-exact-yöntemler">Kesin (Exact) Yöntemler</h2>

<p>Kesin yöntemler, problem boyutu ve yapısı izin verdiğinde <strong>matematiksel olarak garantili optimal çözümü</strong> üreten tekniklerdir. Simpleks, dal-sınır ve dinamik programlama gibi algoritmalar bu ailenin temel taşlarıdır. Karşılığında ödenen bedel genellikle artan problem boyutlarında üstel mertebede büyüyen çalışma süresidir.</p>

<h3 id="doğrusal-programlama-linear-programming--lp">Doğrusal Programlama (Linear Programming — LP)</h3>

<p>LP, yöneylem araştırmasının en eski ve en temel aracıdır. Hem amaç fonksiyonunun hem de kısıtların <strong>doğrusal</strong> olduğu, karar değişkenlerinin ise <strong>sürekli (gerçek sayı)</strong> olabildiği problemleri çözer. Standart formu şöyle yazılır:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>max    z = c₁x₁ + c₂x₂ + ... + cₙxₙ
s.t.   a₁₁x₁ + a₁₂x₂ + ... + a₁ₙxₙ ≤ b₁
       a₂₁x₁ + a₂₂x₂ + ... + a₂ₙxₙ ≤ b₂
       ...
       xᵢ ≥ 0   (∀ i)
</code></pre></div></div>

<p>Dantzig’in 1947’de geliştirdiği <strong>simpleks yöntemi</strong>, LP çözmek için hâlâ en yaygın kullanılan algoritmadır. Simpleks’in arkasındaki sezgi saf geometriktir: LP’nin uygulanabilir bölgesi (feasible region) çok boyutlu bir çokyüzlüdür (polyhedron); optimum değer bu çokyüzlünün <strong>köşelerinden birinde</strong> bulunur. Simpleks tam olarak bunu yapar: bir köşeden komşu köşeye geçerek amaç fonksiyonunu iyileştirir, iyileştirme kalmayınca durur. Pratikte son derece hızlıdır; ama en kötü durumda üstel zamanda çalışabilir. 1979’da Leonid Khachiyan’ın elipsoid yöntemi ile LP’nin polinom zamanda çözülebildiğini kanıtlaması ve 1984’te Narendra Karmarkar’ın projektif <strong>iç nokta yöntemleri</strong>ni (interior point methods) geliştirmesi, alanın iki büyük teorik sıçramasıdır. Modern çözücüler bu iki aileyi birlikte kullanır.</p>

<p>LP’nin bir diğer güzelliği <strong>ikilik teoremi</strong>dir (duality theorem): Her LP’nin bir “eşleniği” (dual) vardır. Primal problem “kârı maksimize et” ise dual “minimum kaynak kullan” gibi yorumlanır. Dualin çözüm değeri, primale ait <strong>gölge fiyatları</strong> (shadow prices) verir: “Kısıt <em>i</em>‘yi bir birim gevşetirsem amaç fonksiyonu ne kadar değişir?” sorusunun yanıtı. Duyarlılık analizi (sensitivity analysis), kapasite yatırımı ve fiyatlama gibi iş kararlarının temelidir.</p>

<p><strong>Klasik örnek — Üretim karışımı:</strong> Bir mobilya atölyesi masa ve sandalye üretiyor. Her masadan 40 TL, her sandalyeden 30 TL kâr ediyor. Elimizde 400 saatlik marangozluk ve 240 saatlik cila kapasitesi var. Bir masa 4 saat marangozluk, 2 saat cila; bir sandalye 2 saat marangozluk, 2 saat cila gerektiriyor. Kârı maksimize etmek için kaç masa ve kaç sandalye üretmeliyiz?</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>max    z = 40x₁ + 30x₂
s.t.   4x₁ + 2x₂ ≤ 400   (marangozluk)
       2x₁ + 2x₂ ≤ 240   (cila)
       x₁, x₂ ≥ 0
</code></pre></div></div>

<p>Bu küçük LP’nin optimum noktası uygulanabilir bölgenin köşelerinden birindedir. Grafik yöntemle çözüldüğünde kısıtların kesiştiği nokta <code class="language-plaintext highlighter-rouge">(x₁=80, x₂=40)</code> optimal çözüm olur ve kâr <code class="language-plaintext highlighter-rouge">40·80 + 30·40 = 4.400</code> TL’dir. Simpleks aynı sonucu saniyenin milyonda birinde bulur.</p>

<p>LP’nin en bilinen uygulama kategorileri:</p>

<ul>
  <li><strong>Diet problem</strong> (beslenme): En düşük maliyetle günlük besin gereksinimlerini karşılamak üzere hangi yiyeceklerden ne kadar tüketilmeli? Dantzig’in 1945’te başlayan klasik çalışmalarından biri.</li>
  <li><strong>Transportation problem</strong> (ulaşım): <em>m</em> fabrikadan <em>n</em> depoya, her fabrika-depo çifti için farklı taşıma maliyetleri ile en ucuz akış nasıl sağlanır?</li>
  <li><strong>Assignment problem</strong> (atama): <em>n</em> işi <em>n</em> kişiye, her eşleşme için farklı yetkinlikle en verimli şekilde nasıl atarız?</li>
  <li><strong>Blending problem</strong> (karışım): Rafinerilerde ham petrolün benzin/dizel karışımlarına dağıtımı; en düşük maliyetli kimyasal bileşim.</li>
  <li><strong>Production planning</strong> (üretim planlama): Birden çok ürün, birden çok dönem, kapasite ve envanter kısıtları altında toplam kârı maksimize etme.</li>
</ul>

<p>LP pratikte <strong>milyonlarca değişken ve kısıt</strong> içeren modelleri modern çözücüler (Gurobi, CPLEX, HiGHS) ile saniyeler–dakikalar mertebesinde çözebilir. Bu olağanüstü ölçeklenebilirlik, LP’yi diğer tüm kesin yöntemlerin “çözüm zemini” hâline getirir: IP, BIP ve MIP’in pek çok algoritması arka planda binlerce LP çözer.</p>

<p>Simpleksin bir takım patolojik durumları da vardır ve bunlar pratikte bilinir: <strong>Dejenerasyon</strong> (degeneracy), birden fazla kısıtın aynı köşede kesişmesi durumudur; bu durumda amaç fonksiyonu iyileşmeden birkaç iterasyon yapılabilir ve en kötü durumda <strong>çevrim</strong> (cycling) oluşabilir. Bland’in anti-çevrim kuralı ve sözlükbilimsel kurallar (lexicographic rule) bu sorunu çözer. <strong>Gözden geçirilmiş simpleks</strong> (revised simplex) ise tüm tabloyu her iterasyonda güncellemek yerine yalnızca bazın tersini çarpanlara ayırarak bellek ve hesap verimini artırır; modern çözücüler bu versiyonu kullanır. Dahası büyük ölçekli ve özel yapılı LP’ler için <strong>Dantzig-Wolfe ayrıştırması</strong> (decomposition) ve ona dual olan <strong>Benders ayrıştırması</strong> gibi teknikler, problemi daha küçük alt problemlere bölerek çözer.</p>

<h3 id="tam-sayı-programlama-integer-programming--ip">Tam Sayı Programlama (Integer Programming — IP)</h3>

<p>Karar değişkenleri <strong>yalnızca tam sayı</strong> değerler alabildiğinde IP’den söz ederiz. “2.4 adet çalışan işe al” gibi anlamsız sonuçlardan kaçınmak için kullanılır:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>max    z = cᵀx
s.t.   Ax ≤ b
       xᵢ ∈ ℤ   (∀ i)
</code></pre></div></div>

<p>IP, LP’den çok daha zordur; genel IP <strong>NP-zor</strong> sınıfına girer. Teorik çözüm yöntemleri Land ve Doig’in 1960’ta <em>Econometrica</em> dergisinde tanıttığı <strong>dal-sınır algoritması</strong> ve Gomory’nin 1958’de önerdiği <strong>kesme düzlemleri</strong>dir. Modern çözücüler bu ikisini <strong>dal-ve-kesme</strong> (branch-and-cut) şemasında birleştirir.</p>

<p><strong>Dal-sınır mekanizması:</strong> Önce LP gevşetmesi (tam sayı şartı kaldırılmış hâli) çözülür. Eğer sonuç zaten tam sayıysa bitti. Değilse kesirli bir değişken seçilir (örneğin <code class="language-plaintext highlighter-rouge">x₃ = 2.7</code>) ve problem iki alt probleme bölünür: <code class="language-plaintext highlighter-rouge">x₃ ≤ 2</code> ve <code class="language-plaintext highlighter-rouge">x₃ ≥ 3</code>. Her alt problem kendi LP gevşetmesiyle çözülür; “sınır” değeri mevcut en iyi tam sayı çözümden daha kötüyse o dal budanır (bound). Algoritma bir ağaç biçiminde gezinerek tüm olası tam sayı çözümleri kapsadığına emin olur.</p>

<p><strong>Kesme düzlemleri</strong> aynı zamanda güçlü bir fikirdir: LP gevşetmesine, tüm tam sayı çözümleri dışarıda bırakmayan ama mevcut kesirli LP çözümünü kesip atan yeni eşitsizlikler eklenir. Bu şekilde uygulanabilir bölge sıkılaştırılır, dallanma sayısı azalır. Gomory mixed-integer cuts, MIR, lift-and-project, flow cover gibi onlarca kesi ailesi modern çözücülerde yer alır.</p>

<p>IP için bir özel durum daha önemlidir: <strong>tamamen unimodular</strong> (totally unimodular) matrisler. Eğer kısıt matrisinin tüm karesel alt determinantları <code class="language-plaintext highlighter-rouge">{-1, 0, +1}</code> kümesinde yer alıyorsa, LP gevşetmesinin optimum çözümü zaten tam sayıdır. Bu özellik ağ akış problemleri, bazı çizelgeleme problemleri ve çift yönlü eşleme (bipartite matching) için geçerlidir — bunlar polinom zamanda çözülür.</p>

<p><strong>Klasik örnek — Tesis yerleşimi:</strong> Bir kargo şirketi <em>m</em> aday lokasyondan bazılarını depo olarak açmak istiyor. Her depo açma maliyeti ve her müşteriye hizmet maliyeti biliniyor. Her müşterinin hangi depodan hizmet alacağı (tam sayı atama) ve hangi depoların açılacağı (0/1 karar) birlikte modellenir; toplam maliyet minimize edilir. Az sayıda aday varken dakikalarla çözülürken, yüzlerce aday için saatlere çıkabilir. Benzer yapıdaki <strong>makine atama</strong> ve <strong>üniversite ders programı</strong> problemleri de IP ile çözülür.</p>

<p>IP için bir diğer önemli klasik teknik <strong>Lagrange gevşetmesi</strong>dir (Lagrangian relaxation): Zor kısıtlar amaç fonksiyonuna ceza (Lagrange çarpanı) olarak eklenir; elde edilen gevşek problem genelde yapısal olarak daha kolaydır (çoğu kez bağımsız alt problemlere ayrışır). Çarpanlar subgradient yöntemiyle iteratif olarak güncellenir. Çıkan Lagrange duali, orijinal IP için bir alt sınır verir ve dal-sınır ağacında güçlü budama sağlar. 1970’lerde Held ve Karp’ın TSP için kullandığı bu yaklaşım, o dönemin en iyi alt sınırlarını vermiştir ve hâlâ özel yapılı büyük IP’lerde tercih edilir.</p>

<h3 id="i̇kili-tam-sayı-programlama-binary-integer-programming--bip">İkili Tam Sayı Programlama (Binary Integer Programming — BIP)</h3>

<p>Karar değişkenlerinin yalnızca <strong>{0, 1}</strong> değerlerini alabildiği özel bir IP türüdür. “Bir iş yapılacak mı?”, “Bu rota seçilecek mi?”, “Bu eşya çantaya girecek mi?” gibi <strong>evet/hayır</strong> kararlarında doğal modeldir:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>min    z = cᵀx
s.t.   Ax ≤ b
       xᵢ ∈ {0, 1}   (∀ i)
</code></pre></div></div>

<p>BIP, kombinatoryal optimizasyonun pek çok klasik problemini kapsar:</p>

<ul>
  <li><strong>Knapsack problem</strong> (sırt çantası): Hangi eşyaları seçelim?</li>
  <li><strong>Set covering</strong> (küme örtme): Elimizdeki <em>m</em> gereksinimin tamamını karşılayacak en az sayıda araç/hizmet/eleman nasıl seçilir? Hizmet merkezi yerleştirme, elektrik ağı tasarımı, test kümesi seçimi bu sınıftadır.</li>
  <li><strong>Set partitioning</strong> (küme bölüntüleme): Elemanları tam olarak tek bir alt kümeye düşecek şekilde nasıl gruplayalım? Havayolu mürettebat eşleme, araç rotalama sorunlarında kullanılır.</li>
  <li><strong>Matching</strong> (eşleme): İki grup arasındaki maksimum kâra ulaşan eşleşmeyi bul.</li>
  <li><strong>Graph coloring</strong> (çizge renklendirme): Komşu düğümler farklı renklere sahip olmak üzere minimum renk sayısı.</li>
</ul>

<p><strong>Klasik örnek — Sırt çantası (Knapsack) problemi:</strong> <em>n</em> eşya var; her biri için ağırlık <em>wᵢ</em> ve değer <em>vᵢ</em> biliniyor. Taşıyabileceğimiz maksimum toplam ağırlık <em>W</em>. Hangi eşyaları alırız?</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>max    Σᵢ vᵢ · xᵢ
s.t.   Σᵢ wᵢ · xᵢ ≤ W
       xᵢ ∈ {0, 1}
</code></pre></div></div>

<p>Somut örnek: 4 eşya (ağırlık-değer): (2-3), (3-4), (4-5), (5-6); kapasite <em>W</em>=5. Hangi eşyaları alırız? Dört eşya var, bu yüzden 2⁴ = 16 olası alt küme var; küçük bir örnekte bile el hesabı uzar. Çözüm: <code class="language-plaintext highlighter-rouge">{x₁=1, x₂=1, x₃=0, x₄=0}</code>, toplam ağırlık 5, toplam değer 7.</p>

<p>Knapsack, BIP’nin ders kitabı örneği olmakla kalmaz, aynı zamanda dinamik programlama ile de çözülebilir (aşağıda DP bölümünde göreceğiz) — kesin yöntemlerin birbirine nasıl bağlandığına güzel bir örnektir. Benzer şekilde “hangi işi kabul edelim?”, “hangi reklamı yayımlayalım?”, “hangi yatırım projesine girelim?” gibi pek çok günlük problem BIP olarak modellenebilir.</p>

<h3 id="karma-tam-sayı-programlama-mixed-integer-programming--mip">Karma Tam Sayı Programlama (Mixed-Integer Programming — MIP)</h3>

<p>MIP, LP ile IP/BIP’i aynı model içinde birleştirir: bazı değişkenler sürekli (akış, süre, miktar), bazıları ise tam sayı ya da ikilidir (bir tesis açılacak mı, bir rota seçilecek mi). Gerçek dünya problemlerinin büyük çoğunluğu doğal olarak MIP’tir:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>min    cᵀx + dᵀy
s.t.   Ax + By ≤ b
       x ≥ 0,   y ∈ ℤⁿ
</code></pre></div></div>

<p>MIP çözücüleri son 25 yılda <strong>milyon kat</strong> performans artışı yaşamış bir alandır; bunun büyük kısmı donanımdan değil algoritmik iyileştirmelerden (daha iyi ön işleme, güçlü kesiler, primal sezgisel ve dallanma stratejileri) gelir. Gurobi, CPLEX ve FICO Xpress gibi araçlar pek çok endüstriyel problemi dakikalar içinde çözer.</p>

<p>MIP modelleri sıkça <strong>Big-M tekniği</strong> kullanır. “Eğer tesis <em>i</em> açıksa, akış olabilir” tipi mantıksal kuralları doğrusallaştırmak için yapılan klasik hile şudur:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>x_ij ≤ M · y_i       (y_i = 0 ise x_ij = 0'a zorlanır; y_i = 1 ise x_ij serbest)
</code></pre></div></div>

<p>Burada <code class="language-plaintext highlighter-rouge">M</code> yeterince büyük bir sabittir. <code class="language-plaintext highlighter-rouge">M</code>‘nin çok büyük seçilmesi LP gevşetmesini zayıflatır ve çözümü yavaşlatır; çok küçük seçilmesi gerçek çözümleri dışarıda bırakır. Doğru <code class="language-plaintext highlighter-rouge">M</code> seçimi iyi MIP modellemenin sanatıdır.</p>

<p><strong>Klasik örnek — Tedarik zinciri ağ tasarımı:</strong> Hangi fabrikaların açılacağı (ikili), hangi fabrikadan hangi dağıtım merkezine ne kadar ürün akacağı (sürekli), hangi kamyon rotalarının kullanılacağı (ikili) kararlarının birleşimi saf bir MIP’dir. Çok katmanlı modelde açma/kapama kararları ile akış kararları aynı anda optimize edilir. Toplam maliyet = sabit açılış maliyetleri + değişken üretim ve taşıma maliyetleri. Kısıtlar: müşteri talebini karşılamak, kapasiteyi aşmamak, sadece açık tesisten akış olmak.</p>

<p>Benzer bir yapı <strong>unit commitment</strong> (birim taahhüt) probleminde de görülür: Hangi elektrik santrali hangi saatte açık olacak (ikili) ve açıkken ne kadar güç üretecek (sürekli)? Bu problem, Türkiye dahil tüm elektrik piyasalarında günlük olarak çözülür ve piyasa fiyatını belirler.</p>

<h3 id="dinamik-programlama-dynamic-programming--dp">Dinamik Programlama (Dynamic Programming — DP)</h3>

<p>Richard Bellman’ın 1957’de yayımladığı <em>Dynamic Programming</em> kitabında formalize ettiği DP, problemi <strong>örtüşen alt problemlere</strong> ayıran ve her alt problemi yalnızca bir kere çözerek sonucu ezberleyen bir stratejidir. Kalbinde Bellman’ın meşhur <strong>optimallik ilkesi</strong> (principle of optimality) yatar:</p>

<blockquote>
  <p><em>“Bir optimal politika, başlangıç durumu ve kararı ne olursa olsun, kalan kararların ilk karardan ortaya çıkan duruma göre de optimal bir politika oluşturmasını gerektirir.”</em></p>
</blockquote>

<p>Özyinelemeli bir değer fonksiyonu (value function) ile ifade edilir:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>V(s) = min   { g(s, a) + V(T(s, a)) }
       a∈A(s)
</code></pre></div></div>

<p>Burada <em>s</em> durum, <em>a</em> aksiyon, <em>g</em> anlık maliyet, <em>T</em> geçiş fonksiyonu, <em>V</em> optimal maliyet fonksiyonudur. Durum uzayı sonlu ve ayrık olduğunda DP polinom zamanda optimal politika üretir; sürekli ve yüksek boyutlu durumlarda ise <strong>boyutun laneti</strong> (curse of dimensionality) devreye girer ve yaklaşık DP (Approximate Dynamic Programming) ya da pekiştirmeli öğrenme (reinforcement learning) yaklaşımlarına geçilir. Aslında modern pekiştirmeli öğrenme doğrudan DP matematiğinin üzerine kuruludur.</p>

<p>DP iki farklı biçimde uygulanabilir:</p>

<ul>
  <li><strong>Top-down (memoization):</strong> Özyinelemeli fonksiyon, önceden hesaplanmış değerleri bir cache’de tutar.</li>
  <li><strong>Bottom-up (tabulation):</strong> Taban durumundan başlayarak tablo sistematik olarak doldurulur. Pratikte daha hızlıdır çünkü rekürsiyon yığını yoktur.</li>
</ul>

<p><strong>Klasik örnek — Knapsack (tekrar):</strong> Sırt çantası <em>O(nW)</em> DP ile çözülebilir. <code class="language-plaintext highlighter-rouge">f(i, w)</code>: ilk <em>i</em> eşya ve ağırlık bütçesi <em>w</em> ile elde edilebilecek maksimum değer.</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>f(i, w) = max{ f(i-1, w),  f(i-1, w - wᵢ) + vᵢ }
</code></pre></div></div>

<p>4 eşya ve <code class="language-plaintext highlighter-rouge">W=5</code> için (<code class="language-plaintext highlighter-rouge">wᵢ = 2,3,4,5</code>, <code class="language-plaintext highlighter-rouge">vᵢ = 3,4,5,6</code>) DP tablosu:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>i\w   0  1  2  3  4  5
 0    0  0  0  0  0  0
 1    0  0  3  3  3  3
 2    0  0  3  4  4  7
 3    0  0  3  4  5  7
 4    0  0  3  4  5  7
</code></pre></div></div>

<p>Hücre <code class="language-plaintext highlighter-rouge">f(2,5) = 7</code>: ilk iki eşya ve 5 birim kapasiteyle elde edilebilecek en büyük değer. DP tabloyu aşağıdan yukarıya doldurur; <code class="language-plaintext highlighter-rouge">O(nW)</code> zaman ve bellek kullanır.</p>

<p>DP, bilgisayar biliminin tamamen olmazsa olmaz aracıdır. Birkaç yaygın uygulama:</p>

<ul>
  <li><strong>Fibonacci sayıları:</strong> <em>F(n) = F(n-1) + F(n-2)</em>. Saf rekürsiyon üstel, DP ile doğrusal.</li>
  <li><strong>En kısa yol (Bellman-Ford):</strong> Negatif kenar ağırlıklarıyla çalışan tek klasik en kısa yol algoritması DP tabanlıdır.</li>
  <li><strong>Edit distance (Levenshtein mesafesi):</strong> İki metin arasında kaç ekleme/silme/değişiklik var? Otomatik yazım denetiminin ve DNA dizi hizalamanın temeli.</li>
  <li><strong>Matrix chain multiplication:</strong> <code class="language-plaintext highlighter-rouge">A·B·C·D</code> çarpımını hangi sıralama ile yapalım? Sonuç aynı ama ara hesap sayısı çok farklı.</li>
  <li><strong>Seçenek fiyatlaması:</strong> Finansta opsiyon fiyatları geri yönde (backward induction) DP ile hesaplanır.</li>
  <li><strong>Viterbi algoritması:</strong> Dijital iletişim ve konuşma tanımada gizli Markov modellerinin en olası yolunu bulur.</li>
</ul>

<hr />

<h2 id="metasezgisel-yöntemler">Metasezgisel Yöntemler</h2>

<p>Kesin yöntemler garantili optimal sağlar; fakat problem boyutu bir yerden sonra “makul” sürelerde çözülebilir olmaktan çıkar. Çizelgeleme, rotalama ve yerleşim gibi NP-zor problemlerin endüstriyel ölçekli örneklerinde “kanıtlanmış optimal” lüks bir hedef hâline gelir; kısa sürede üretilen <strong>yeterince iyi</strong> bir çözüm yeterlidir. Metasezgisel yöntemler bu boşluğu doldurur: doğadan (evrim, fizik, karınca kolonisi) ya da bilişsel süreçlerden (bellek, öğrenme) esinlenen, <strong>genel amaçlı</strong> ve <strong>problem bağımsız</strong> çerçeveler sunarlar.</p>

<p>Her metasezgiselin iki temel bileşenini ayırt etmek önemlidir:</p>

<ul>
  <li><strong>Keşif (exploration, diversification):</strong> Çözüm uzayının geniş bir bölgesini taramak.</li>
  <li><strong>Sömürü (exploitation, intensification):</strong> Umut verici bölgeleri detaylıca araştırmak.</li>
</ul>

<p>Bu iki eğilimin dengesi, algoritmanın yerel minimumlarda takılmadan küresel ölçekte iyi çözümler bulmasını sağlar. Ayarlar yanlış olursa algoritma ya hedefsizce dolaşır (çok fazla keşif) ya da ilk bulduğu yerel minimumda donar (çok fazla sömürü).</p>

<h3 id="genetik-algoritma-genetic-algorithm--ga">Genetik Algoritma (Genetic Algorithm — GA)</h3>

<p>John Holland’ın 1975’te yayımladığı <em>Adaptation in Natural and Artificial Systems</em> kitabıyla ana hatları çizilen, David Goldberg’in 1989 kitabıyla da pratikte yaygınlaşan GA, evrim kuramından esinlenen bir <strong>topluluk (population) tabanlı</strong> aramadır. Her çözüm bir <strong>kromozom</strong> olarak kodlanır; topluluk her iterasyonda <strong>seçim</strong> (selection), <strong>çaprazlama</strong> (crossover) ve <strong>mutasyon</strong> (mutation) operatörleriyle yenilenir.</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>1. Rastgele başlangıç topluluğu üret
2. her iterasyon için:
     her kromozomun uygunluk (fitness) değerini hesapla
     turnuva / rulet tekerleği ile ebeveynleri seç
     çaprazlama + mutasyon ile yeni kromozomlar üret
     elitizm: en iyi k bireyi koru
3. durdurma kriteri karşılanınca en iyi kromozomu döndür
</code></pre></div></div>

<p>Holland’ın çalışmasının teorik kalbi <strong>şema teoremi</strong>dir (schema theorem): İyi kısa “şema”lar (belirli bir bit örüntüsüne sahip kromozom parçaları) topluluğa üstel hızla yayılır. Bu, GA’nın neden işe yaradığının teorik bir açıklamasıdır.</p>

<p>GA’nın gücü, kromozom kodlamasının esnekliğinden gelir:</p>

<ul>
  <li><em>İkili kodlama:</em> Knapsack için 0/1 diziler. Çaprazlama tek/çok nokta, mutasyon bit ters çevirme.</li>
  <li><em>Permütasyon kodlama:</em> TSP için şehir sırası. Standart crossover bozuk permütasyonlar üretir, bu yüzden OX (order crossover), PMX (partially mapped crossover) gibi özel operatörler tasarlanmıştır.</li>
  <li><em>Gerçek sayı kodlama:</em> Sürekli parametreler için. SBX (simulated binary crossover) ve polinom mutasyon yaygındır.</li>
  <li><em>Ağaç kodlama (Genetic Programming):</em> Program/fonksiyon sentezi için; yapraklar sabitler/değişkenler, düğümler operatörlerdir.</li>
</ul>

<p>Seçim operatörünün çeşitli varyantları vardır: <strong>turnuva</strong> (rastgele birkaç bireyin en iyisini seç), <strong>rulet tekerleği</strong> (fitness oranlı olasılıkla seç), <strong>rank-based</strong> (sıralama esaslı olasılık), <strong>elitizm</strong> (en iyi <em>k</em> bireyi değişiklik yapmadan sonraki kuşağa aktar). Çok amaçlı optimizasyonda klasik GA yerine <strong>NSGA-II</strong> gibi Pareto-cephe koruyan varyantlar kullanılır.</p>

<p><strong>Klasik örnek — Gezgin satıcı problemi (TSP):</strong> <em>n</em> şehri birer kez ziyaret ederek başlangıç şehrine dönen en kısa turu bul. Kromozom permütasyon olarak temsil edilir. Çaprazlama iki ebeveynden alt turları birleştirir; mutasyon iki şehrin sırasını değiştirir. Binlerce şehirli örneklerde GA, saniyeler içinde saf rastgeleden çok daha iyi turlar üretir. TSP aynı zamanda GA, SA, TS ve ACO’nun hepsinin karşılaştırma ortak paydasıdır.</p>

<h3 id="benzetimli-tavlama-simulated-annealing--sa">Benzetimli Tavlama (Simulated Annealing — SA)</h3>

<p>Kirkpatrick, Gelatt ve Vecchi’nin 13 Mayıs 1983’te <em>Science</em> dergisinde yayımladığı seminer makale, SA’yı optimizasyon dünyasına tanıtmıştır. Fiziksel tavlama sürecinden (bir metalin yavaş soğutularak minimum enerji konfigürasyonuna gelmesi) esinlenen SA, tek çözüm üzerinden yerel arama yapar; fakat yerel minimuma sıkışmamak için <strong>kontrollü olarak kötü hareketleri kabul eder</strong>.</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>T ← T₀   (başlangıç sıcaklığı)
x ← x₀   (başlangıç çözümü)
her iterasyon için:
    x' ← komşu(x)
    Δ ← f(x') - f(x)
    if Δ &lt; 0:
        x ← x'                         (daha iyiyi daima kabul et)
    else:
        x ← x' olasılıkla exp(-Δ / T)  (kötüyü bazen kabul et)
    T ← α · T   (0 &lt; α &lt; 1, "soğutma")
</code></pre></div></div>

<p>Kabul kuralının matematiksel kökeni 1953’te Metropolis ve arkadaşlarının istatistiksel mekanik için önerdiği <strong>Metropolis-Hastings</strong> algoritmasıdır; kuralın arkasındaki Boltzmann dağılımı, termodinamik dengede bir parçacığın enerji durumlarının olasılıklarını verir. Sıcaklık <em>T</em> yüksekken olasılık 1’e yakın, yani kötü hareket neredeyse her zaman kabul edilir (geniş keşif); <em>T</em> 0’a yaklaşırken olasılık 0’a iner ve algoritma saf tepeye-tırmanma’ya (hill climbing) dönüşür.</p>

<p>Pratikteki kritik parametre, <strong>soğutma şemasıdır</strong>:</p>

<ul>
  <li><strong>Geometrik soğutma:</strong> <code class="language-plaintext highlighter-rouge">T ← α·T</code>, tipik <code class="language-plaintext highlighter-rouge">α ∈ [0.8, 0.99]</code>. En yaygını.</li>
  <li><strong>Logaritmik soğutma:</strong> <code class="language-plaintext highlighter-rouge">T = T₀ / ln(1 + k)</code>. Teorik olarak küresel optimali garantiler ama çok yavaştır.</li>
  <li><strong>Adaptif soğutma:</strong> İlerleme durumuna göre hız ayarlanır; duraklamada yeniden ısıtma (reheating) uygulanır.</li>
</ul>

<p>Doğru <code class="language-plaintext highlighter-rouge">T₀</code>, <code class="language-plaintext highlighter-rouge">α</code> ve durdurma kriteri problem bağımlıdır; ama SA’nın pratikteki popülaritesi, kodlamasının basit olması ve çoğu problemde makul parametrelerle iyi iş çıkarmasıdır.</p>

<p><strong>Klasik örnek — Gezgin satıcı problemi (TSP):</strong> Kirkpatrick’in orijinal makalesi TSP üzerinde somut sonuçlar gösterir. Bir permütasyonun “komşusu” genelde iki kenarı ters çeviren 2-opt hareketidir; SA, büyük TSP örneklerinde kısa sürede kaliteli turlar bulur. SA ayrıca kombinatoryal yerleşim problemleri, makine çizelgeleme, hiperparametre ayarı ve yapay sinir ağı eğitimi gibi pek çok alanda başarıyla kullanılır.</p>

<p>SA’nın teorik zarafeti, Hajek’in 1988’de ispatladığı bir <strong>yakınsama teoremi</strong>nde yatar: Soğutma yeterince yavaş olursa (logaritmik soğutma ile) SA sonsuz sürede küresel optimali olasılık 1 ile bulur. Pratikte elbette kimse logaritmik soğutma kullanmaz; geometrik soğutma ile “sonlu sürede çok iyi çözüm” tercih edilir. Çağdaş varyantları arasında <strong>paralel tavlama</strong> (parallel tempering — birden fazla sıcaklıkta paralel zincirler çalıştırılır ve aralarında değişim yapılır), <strong>quantum annealing</strong> (D-Wave bilgisayarlarının altyapısı) ve <strong>threshold accepting</strong> (kötü hareketler olasılıkla değil sabit eşikle kabul edilir) sayılabilir.</p>

<h3 id="tabu-arama-tabu-search--ts">Tabu Arama (Tabu Search — TS)</h3>

<p>Fred Glover’ın 1986’daki çalışmasıyla tanıtılan ve 1989’da <em>ORSA Journal on Computing</em>‘de “Tabu Search — Part I” başlığıyla formalize ettiği TS’in ayırt edici özelliği <strong>bellek (memory)</strong> kullanmasıdır: daha önce yapılan hareketleri <strong>tabu listesi</strong>nde tutar ve kısa süreliğine tekrarlanmalarını yasaklar. Bu, yerel minimumdan çıkmayı ve döngülere düşmemeyi sağlar.</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>x ← x₀
tabu_listesi ← ∅
best ← x
her iterasyon için:
    N(x) \ tabu_listesi içindeki en iyi komşu x'ı seç
    x ← x'
    if f(x) &lt; f(best): best ← x
    tabu_listesi.append(x hareketinin tersine çevrilmesi)
    tabu_listesi FIFO ile güncelle
</code></pre></div></div>

<p>TS’in zarafeti hiyerarşik bellek yapısındadır:</p>

<ul>
  <li><strong>Kısa dönem bellek</strong> (short-term memory): Son yapılan hareketlerin listesi; yasaklıdır. Döngüleri engeller.</li>
  <li><strong>Orta dönem bellek</strong> (intermediate-term memory / intensification): İyi çözümlerin ortak özelliklerini hatırlar; bu bölgelere yoğunlaştırma yapar.</li>
  <li><strong>Uzun dönem bellek</strong> (long-term memory / diversification): Nadir ziyaret edilen bölgeleri takip eder; zaman zaman oralara atlar.</li>
</ul>

<p><strong>Aspirasyon kriteri:</strong> Bir hareket tabuda olsa bile, o zamana kadar görülen en iyi çözümü iyileştirecekse yasak kaldırılır. Bu basit kural, TS’in yerel minimuma sıkışmadan küresel olarak ilerleyebilmesinin temelidir. Glover’ın tanıttığı <strong>stratejik osilasyon</strong> (strategic oscillation) ise çözümün uygun bölge ile uygun olmayan bölge arasında kontrollü geçişler yapmasına izin verir; bazen kısıtları kasıtlı olarak ihlal ederek daha iyi aday çözümlere ulaşılır.</p>

<p><strong>Klasik örnek — Araç rotalama problemi (VRP):</strong> Bir depodan çıkan <em>k</em> araçla <em>n</em> müşteriye teslimat yapacağız. Her müşterinin talebi, her aracın kapasitesi ve her rotanın toplam mesafe/zaman kısıtı var. Amaç: toplam kat edilen yolu minimize etmek. TS, 1990’larda klasik VRP üzerinde o dönemin en iyi sonuçlarını üreten yöntemlerden biri olmuştur ve bugün de kargo/lojistik uygulamalarında yaygın şekilde kullanılır. TS ayrıca zaman çizelgesi oluşturma, grafik renklendirme ve uyarlanabilir üretim sistemlerinde de etkilidir.</p>

<h3 id="karınca-kolonisi-optimizasyonu-ant-colony-optimization--aco">Karınca Kolonisi Optimizasyonu (Ant Colony Optimization — ACO)</h3>

<p>Marco Dorigo’nun 1992’de Politecnico di Milano’da savunduğu <em>Optimization, Learning and Natural Algorithms</em> başlıklı (aslında İtalyanca yazılmış) doktora tezinde tanıttığı ACO, gerçek karıncaların yiyecek arama davranışından esinlenir. Karıncalar yiyecek ile yuva arasında <strong>feromon izi</strong> bırakır; sonraki karıncalar olasılıksal olarak daha yoğun feromonlu yolları tercih eder; kısa yolların feromonu daha hızlı pekişir ve koloni zamanla en kısa yolu keşfeder. Dorigo’nun tezi sırasında Alberto Colorni ve Vittorio Maniezzo ile yakın çalışması, alanın ilk temel algoritmalarını şekillendirmiştir.</p>

<p>Algoritmik olarak:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>feromon matrisi τ_ij'yi başlat
her iterasyon için:
    her karınca k için:
        k'yi rastgele bir düğüme yerleştir
        tur tamamlanana kadar:
            komşu j'ye geçme olasılığı:
                p_ij ∝ τ_ij^α · η_ij^β       (η: sezgisel bilgi, örn. 1/d_ij)
    feromonları güncelle:
        τ_ij ← (1 - ρ) · τ_ij + Σ_k Δτ_ij^k   (ρ: buharlaşma oranı)
        Δτ_ij^k = Q / L_k                     (L_k: karınca k'nın tur uzunluğu)
</code></pre></div></div>

<p>Parametrelerin anlamı:</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">α</code>: feromon ağırlığı. Yüksekse kolektif hafızaya güven; düşükse rastgeleye yakın.</li>
  <li><code class="language-plaintext highlighter-rouge">β</code>: sezgisel bilgi ağırlığı. Yüksekse kısa mesafeyi sever; düşükse sadece feromonla ilerler.</li>
  <li><code class="language-plaintext highlighter-rouge">ρ</code>: buharlaşma oranı. Yüksekse hızlı unutur; düşükse eski bilgi uzun kalır.</li>
</ul>

<p>ACO’nun çok sayıda varyantı geliştirilmiştir: <strong>Ant System</strong> (orijinal Dorigo), <strong>Elitist Ant System</strong> (en iyi turun feromonu ek olarak artırılır), <strong>Max-Min Ant System</strong> (feromon değerleri bir aralıkta sınırlı tutulur, erken yakınsama engellenir), <strong>Ant Colony System</strong> (Dorigo ve Gambardella’nın 1997’deki güçlendirilmiş versiyonu; lokal feromon güncellemesi eklendi).</p>

<p><strong>Klasik örnek — Gezgin satıcı problemi (TSP):</strong> ACO’nun en yaygın gösterildiği problem TSP’dir. Her iterasyonda koloni farklı turlar deneyerek en kısa yol üzerinde feromonu pekiştirir. ACO ayrıca araç rotalama, çizelgeleme, ağ rotalama ve protein katlanması problemlerinde de yaygın olarak kullanılır. Dağıtık doğası, paralel donanımda iyi ölçeklenmesini sağlar.</p>

<hr />

<h2 id="kesin-vs-metasezgisel-karşılaştırma-ve-karar-çerçevesi">Kesin vs. Metasezgisel: Karşılaştırma ve Karar Çerçevesi</h2>

<p>Hem kesin hem metasezgisel dünyayı dolaştık; şimdi bir karar çerçevesi kuralım. Aşağıdaki tablo iki yaklaşımın temel niteliklerini karşılaştırır:</p>

<table>
  <thead>
    <tr>
      <th>Özellik</th>
      <th>Kesin Yöntemler (LP / IP / BIP / MIP / DP)</th>
      <th>Metasezgisel (GA / SA / TS / ACO)</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Optimallik garantisi</td>
      <td>Evet (kanıtlanmış optimal)</td>
      <td>Hayır (yakın optimal)</td>
    </tr>
    <tr>
      <td>Tipik problem boyutu</td>
      <td>Küçük–orta (bazı LP’ler çok büyük)</td>
      <td>Büyük / devasa</td>
    </tr>
    <tr>
      <td>Çözüm süresi</td>
      <td>Dakika–saat; bazen üstel</td>
      <td>Ayarlanabilir; erken durdurulabilir</td>
    </tr>
    <tr>
      <td>Modelleme esnekliği</td>
      <td>Düşük (doğrusal / sonlu durum şart)</td>
      <td>Yüksek (her fitness fonksiyonu uygulanabilir)</td>
    </tr>
    <tr>
      <td>Parametre hassasiyeti</td>
      <td>Düşük</td>
      <td>Yüksek (soğutma, popülasyon, feromon vb.)</td>
    </tr>
    <tr>
      <td>Duyarlılık analizi</td>
      <td>Doğal (LP duality)</td>
      <td>Zayıf</td>
    </tr>
    <tr>
      <td>Tipik alan</td>
      <td>Atama, akış, çizelgeleme (küçük–orta)</td>
      <td>NP-zor, büyük ölçekli problemler</td>
    </tr>
  </tbody>
</table>

<p>Bu karşılaştırma arka planında iki önemli teorik çerçeve vardır. Birincisi <strong>karmaşıklık sınıflarıdır</strong> (P, NP, NP-zor): P sınıfı polinom zamanda çözülen problemleri, NP sınıfı çözümü polinom zamanda doğrulanabilen problemleri, NP-zor sınıfı ise NP’deki her problemin polinom zamanda kendisine indirgenebildiği problemleri kapsar. Saf IP, knapsack, TSP ve VRP hepsi NP-zordur; bu, problem boyutu büyüdükçe kesin yöntemlerle çözüm zamanının katlanarak artacağı anlamına gelir.</p>

<p>İkincisi ise Wolpert ve Macready’nin 1997’de formülize ettiği <strong>No Free Lunch</strong> teoremidir: Hiçbir optimizasyon algoritması, tüm problem sınıfları üzerinde ortalama olarak diğerinden daha iyi değildir. Bu, “evrensel en iyi metasezgisel” iddialarını çürüten önemli bir teorik sonuçtır. GA, SA, TS, ACO’nun hepsinin farklı problem sınıflarında farklı güçlü yanları vardır.</p>

<p>Peki pratikte hangisini seçeceğiz? Aşağıdaki akış diyagramı basit bir karar çerçevesi sunar:</p>

<div class="mermaid">
graph TD
    A[Optimizasyon problemi] --&gt; B{Amaç ve kısıtlar doğrusal mı?}
    B --&gt;|Evet| C{Karar değişkenleri sürekli mi?}
    B --&gt;|Hayır| H{Ayrık durum + örtüşen alt problem?}
    C --&gt;|Evet| D\[LP]
    C --&gt;|Hayır| E{Değişkenler yalnızca 0/1 mi?}
    E --&gt;|Evet| F\[BIP]
    E --&gt;|Hayır| G{Karma mı?}
    G --&gt;|Evet| I\[MIP]
    G --&gt;|Hayır| J\[IP]
    H --&gt;|Evet| K\[DP]
    H --&gt;|Hayır| L{Problem büyük ve NP-zor mu?}
    L --&gt;|Evet| M\[Metasezgisel: GA / SA / TS / ACO]
    L --&gt;|Hayır| N\[Kesin yöntem + özel yapı]
</div>

<p>Özet: <strong>önce problem yapısı</strong>, sonra <strong>ölçek</strong>, en sonunda <strong>çözüm süresi tercihi</strong>. Problem doğrusal ve küçük–orta ölçekliyse LP/IP/BIP/MIP her zaman ilk tercih; büyüdükçe ve doğrusallık bozuldukça metasezgisel yaklaşımlar sahneye çıkar. DP ise aşamalı karar yapısı olan problemler için özel bir arşimet noktasıdır.</p>

<p><strong>Pratikte dikkat edilmesi gereken tuzaklar:</strong></p>

<ul>
  <li><em>Yanlış modelleme:</em> Problem doğrusal değilken LP kurmaya çalışmak ya da tersine, kolayca LP kurulabilecek bir problemi metasezgiselle çözmek yaygın hatalardır. “Bu kısıt gerçekten doğrusal mı?” sorusu ilk adımdır.</li>
  <li><em>Ölçek iluzyonu:</em> Küçük test örneğinde saniyede biten bir MIP, üretim ölçeğinde saatlerce çalışabilir. Dallanma sayısı değişken sayısıyla üstel olarak artar.</li>
  <li><em>Parametre hassasiyeti:</em> Metasezgisel yöntemler yanlış parametrelerle optimalin çok uzağında çözümler üretebilir. SA’nın soğutma profili, GA’nın popülasyon çeşitliliği, TS’in tabu liste uzunluğu ve ACO’nun buharlaşma oranı klasik ayar parametreleridir.</li>
  <li><em>Çok amaçlılık:</em> Gerçek hayatta genelde tek amaç yoktur: “en düşük maliyet” ile “en düşük gecikme” çatışabilir. Tek bir ağırlıklı toplam yerine Pareto-optimal cepheyi aramak daha sağlıklı olabilir.</li>
  <li><em>Çözümün uygulanabilirliği:</em> Matematiksel olarak optimal bir çözüm operasyonel olarak imkansız olabilir; modele girmeyen yumuşak kısıtlar çoğu zaman kullanıcı çözümü ilk gördüğünde ortaya çıkar ve modelin iyileştirilmesini gerektirir.</li>
</ul>

<hr />

<h2 id="matheuristic-i̇ki-dünyanın-birleşimi">Matheuristic: İki Dünyanın Birleşimi</h2>

<p>Son yıllarda kesin ve metasezgisel yöntemleri <strong>aynı çatı altında</strong> kullanan hibrit yaklaşımların adı konmuş: <strong>matheuristic</strong>. Modern endüstriyel optimizasyonun büyük kısmı aslında saf bir kesin ya da saf bir metasezgisel değil, ikisinin akıllıca birleştirildiği matheuristic’ler üzerine kuruludur.</p>

<p>Tipik şemalar:</p>

<ul>
  <li><strong>Metasezgisel içinde MIP:</strong> GA’nın her kromozomunun fitness’ı, küçük bir MIP’in optimal çözümü ile hesaplanır. Kromozom yüksek seviye kararları (hangi tesisler açık?), MIP düşük seviye detayları (ürün akışları) çözer.</li>
  <li><strong>MIP içinde metasezgisel:</strong> Büyük bir MIP’in içinde bir metasezgisel “iyi dallanma yönü” önerir; çözücü alt problemleri optimize eder.</li>
  <li><strong>Large Neighborhood Search (LNS):</strong> Mevcut çözümün bir kısmı “yıkılır”, kalan kısım sabit tutularak serbest kısım için küçük bir MIP çözülür.</li>
  <li><strong>Benders decomposition:</strong> Büyük MIP iki parçaya ayrılır: master problem (karmaşık kararlar) ve alt problem (ürün akışları). Alt problemin duali ile master’a yeni kısıtlar eklenir.</li>
  <li><strong>Column generation:</strong> Çok değişkenli problemlerin (örn. VRP) LP gevşetmesine sadece umut vaat eden değişkenler eklenir. Havayolu mürettebat ve uçak çizelgelemede standarttır.</li>
</ul>

<p>Pratikte basit bir LNS şablonu:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>x ← ilk_cozum()            (MIP çözücü ile hızlı başlangıç)
best ← x
for iter = 1..N:
    S ← x'in %k'lık bir alt kümesini seç
    x'in S dışındaki değişkenlerini sabitle
    MIP çözücüye S'yi serbest bırakarak alt problemi çöz
    x' ← yeni çözüm
    if f(x') &lt; f(best):
        best ← x'
        x ← x'
</code></pre></div></div>

<p>LNS, metasezgisel bir dış çerçeve (hangi değişkenler yıkılacak?) içinde kesin bir iç çözücünün (alt problemi optimalleştir) çalışmasıdır. Gurobi ve CPLEX’in “solution improvement heuristic” modülleri benzer mantıkla çalışır ve kullanıcı matheuristic yazmadan çözücüde hazır gelir.</p>

<p>Matheuristic yaklaşımları; üretim planlama, enerji ağ optimizasyonu, lojistik, havayolu operasyonları ve şehir planlama gibi geniş bir yelpazede yaygın olarak kullanılır.</p>

<hr />

<h2 id="belirsizlik-altında-optimizasyon-stokastik-ve-robust">Belirsizlik Altında Optimizasyon: Stokastik ve Robust</h2>

<p>Şu ana kadar tartıştığımız tüm modeller <strong>deterministik</strong>tir; yani tüm parametrelerin (talep, maliyet, süre) tam olarak bilindiğini varsaydık. Gerçek hayatta ise parametreler çoğu zaman belirsizdir: yarının müşteri talebi rastgele, hava durumu rastgele, makine arızaları rastgele. Belirsizlikle baş etmek için iki ana çerçeve vardır.</p>

<p><strong>Stokastik programlama</strong> (stochastic programming): Belirsiz parametreler olasılık dağılımları ile modellenir; amaç fonksiyonu <strong>beklenen değeri</strong> (expected value) optimize eder. En yaygın formu iki aşamalı stokastik programlamadır: önce belirsizlik çözülmeden “burada ve şimdi” kararları verilir (kaç kamyon kiralayalım?), sonra belirsizlik gerçekleştikten sonra “recourse” (telafi) kararları verilir (yarın hangi rotaları kullanacağız?). Senaryolar yeteri kadar çok olursa problem çok büyür; Benders ayrıştırması ve <strong>sample average approximation</strong> (SAA) gibi teknikler bu büyüklüğü yönetir.</p>

<p><strong>Robust optimizasyon:</strong> Parametreler için bir “belirsizlik kümesi” tanımlanır ve çözüm bu kümedeki <strong>en kötü duruma</strong> karşı en iyi olur. 2000’lerde Ben-Tal, Nemirovski ve Bertsimas’ın çalışmalarıyla olgunlaşan bu alan, özellikle finans, enerji ve savunma uygulamalarında tercih edilir: olasılık dağılımını tahmin etmek zorsa ya da “çok ender ama çok kötü” senaryolardan korunmak isteniyorsa robust optimizasyon doğal seçimdir.</p>

<p>Son yıllarda <strong>makine öğrenmesi</strong> ile <strong>OR</strong>‘un kesişimi de hızla büyüyor. <strong>Prediction + optimization</strong> çerçevesi, bir ML modelinin tahminlerinin ardından bir MIP/metasezgisel çözücünün kararları aldığı sıralı boru hattı şeklindedir. “Predict-then-optimize” paradigması ile tahmin hatasının optimizasyon kararı üzerindeki etkisi ortak olarak eğitilir. Bu alan son 5 yılda özellikle perakende talep tahmini, enerji fiyat tahmini ve rotalama gibi uygulamalarda iz bırakmıştır.</p>

<hr />

<h2 id="gerçek-hayatta-or-dikkat-çekici-uygulamalar">Gerçek Hayatta OR: Dikkat Çekici Uygulamalar</h2>

<p>Yöneylem araştırması akademik bir konu olmanın çok ötesinde; neredeyse her büyük operasyonel sistemin arkasında sessizce çalışan bir bilimdir. Birkaç ikonik örnek:</p>

<ul>
  <li><strong>Havayolu şirketleri — Uçak ve mürettebat çizelgelemesi:</strong> Büyük havayolları her gün on binlerce uçuş yapar. Hangi uçak hangi bacağı uçacak (fleet assignment), pilot ve kabin ekibi nasıl gruplanacak (crew pairing), bireysel ekip çizelgeleri (crew rostering) ve yolcular bağlantı kaçırırsa hangi uçağa bindirilecek sorularının hepsi dev ölçekli MIP’lerdir. Set partitioning formülasyonu ve <strong>column generation</strong> bu problemlerin standart çözüm aracıdır.</li>
  <li><strong>Kargo ve lojistik — UPS ORION:</strong> UPS, 2013’te sahaya tam olarak sürdüğü <strong>ORION</strong> (On-Road Integrated Optimization and Navigation) sistemi ile her kuryenin günlük rotasını optimize eder. Sistem yılda milyonlarca dolar yakıt tasarrufu sağladığını açıklamış, ayrıca sürücü başına günlük ortalama kat edilen mesafe düşmüştür. Altında klasik VRP çeşitlemelerinin sezgisel versiyonları yatar.</li>
  <li><strong>E-ticaret — Amazon depo robotları:</strong> Amazon’un depolarında Kiva (sonra Amazon Robotics) robotları raf getirirken gerçek zamanlı rotalama ve çarpışma önleme problemi çözer. Depo yerleşimi, ürün-raf atama ve sipariş toplama rotaları sürekli yeniden optimize edilir.</li>
  <li><strong>Ulaştırma — Netflix içerik önbellekleme:</strong> Netflix, popüler dizi/film bölümlerini hangi ISP sunucusunda hangi saatte önbelleğe alacağını optimize eder. Bu, bir atama + kapasite problemidir ve arka planda büyük bir LP/MIP olarak çözülür.</li>
  <li><strong>Sağlık — Organ transplant ağları:</strong> ABD’deki böbrek takas programları (Kidney Paired Donation), uyumsuz bağışçı-alıcı çiftlerini eşleştirerek çok kişili takas zincirleri oluşturur. Bu bir maksimum ağırlıklı döngü eşlemesi problemidir ve IP ile çözülür; binlerce insanın hayatına dokunmuştur.</li>
  <li><strong>Enerji — Elektrik piyasası optimizasyonu:</strong> Türkiye dahil hemen her ülkede saatlik elektrik piyasası bir MIP (unit commitment) olarak çözülür. Fiyatlar doğrudan dualin gölge fiyatlarından türer; ekonomi ve mühendislik iç içedir.</li>
  <li><strong>Spor — Takım ligi fikstürü:</strong> Büyük futbol ligleri (Premier League, Bundesliga, Süper Lig) takımların deplasman/iç saha dengesini, derbi tarihlerini, yayın haklarını ve stadyum çakışmalarını aynı anda tatmin eden fikstürleri CP/MIP hibrit araçlarıyla oluşturur.</li>
  <li><strong>Afet ve salgın lojistiği — COVID-19 aşı dağıtımı:</strong> 2020-2021’de COVID-19 aşılarının soğuk zincir lojistiği, aşıların hangi depolara gideceği, hangi merkezlere sevk edileceği, öncelikli grupların nasıl randevulanacağı devasa OR problemleriydi. Pfizer-BioNTech ve AstraZeneca’nın tedarik zinciri arkasında MIP modelleri vardı.</li>
</ul>

<p>Bu örnekler OR’un <strong>soyut bir matematik egzersizi değil</strong>, günlük hayatın temel altyapısını şekillendiren bir mühendislik disiplini olduğunu göstermektedir. Çözülen her problemin ardında hem bir iş paydaşı hem de özel olarak ayarlanmış bir model vardır.</p>

<hr />

<h2 id="pratikte-hangi-araçlar-kullanılır">Pratikte Hangi Araçlar Kullanılır?</h2>

<p>Bir OR modelini çözmek için hangi aracı seçeceğiniz, problemin türüne, bütçenize ve kullandığınız programlama diline bağlıdır.</p>

<p><strong>Ticari MIP çözücüleri:</strong></p>

<ul>
  <li><strong>Gurobi:</strong> Günümüzün en hızlı ticari MIP çözücülerinden biri. Akademik lisans ücretsizdir.</li>
  <li><strong>IBM CPLEX:</strong> Uzun yıllardır sektörün referans noktalarından biri.</li>
  <li><strong>FICO Xpress:</strong> Özellikle finans ve enerji sektörlerinde yaygın.</li>
</ul>

<p>Bu araçlar MIP, LP, quadratic programming ve bazı non-linear programming türlerini çözer; C/C++, Python, Java ve başka diller için API sunar.</p>

<p><strong>Açık kaynak çözücüler:</strong></p>

<ul>
  <li><strong>HiGHS:</strong> Modern, açık kaynak LP/MIP çözücüsü; performansı giderek ticari rakiplerine yaklaşıyor.</li>
  <li><strong>COIN-OR (CBC/CLP):</strong> Olgun ve geniş kapsamlı bir koleksiyon.</li>
  <li><strong>Google OR-Tools:</strong> LP, MIP, kısıt programlama ve rotalama için birleşik API.</li>
  <li><strong>SCIP:</strong> Akademik lisanslı, güçlü bir dal-ve-kesme çözücüsü.</li>
  <li><strong>Pyomo, JuMP:</strong> Python ve Julia için modelleme dilleri; arka uçta birçok çözücüye bağlanabilir.</li>
</ul>

<p><strong>Metasezgisel kütüphaneler:</strong></p>

<ul>
  <li><strong>DEAP</strong> (Python): GA ve evrimsel hesaplama için esnek bir çerçeve.</li>
  <li><strong>simanneal</strong> (Python): SA için minimal ve anlaşılır bir kütüphane.</li>
  <li><strong>scikit-opt</strong> (Python): GA, SA, PSO, TSP çözümlerini tek paket altında sunar.</li>
  <li><strong>jMetal</strong> (Java / Python): Çok amaçlı metasezgisellerin referans koleksiyonu.</li>
</ul>

<p>Tipik bir tercih akışı şöyledir: Problem küçük-orta ve LP/MIP yapısındaysa, Pyomo ya da JuMP ile modellenip HiGHS veya akademik Gurobi ile çözülür. Problem büyük ve metasezgisel gerekiyorsa DEAP veya simanneal ile hızlı bir prototip yapılır; çalıştıktan sonra ihtiyaca göre optimize edilir ya da matheuristic’e dönüştürülür.</p>

<hr />

<h2 id="sonuç">Sonuç</h2>

<p>Yöneylem araştırması, üretimden lojistiğe, sağlıktan finansa pek çok gerçek dünya problemini çözen olgun ve kanıtlanmış bir disiplindir. Özetle:</p>

<ul>
  <li><strong>Kesin yöntemler</strong> (LP, IP, BIP, MIP, DP) garantili optimal sağlar ve doğru araçla milyonlarca değişkenli modeller bile rutin olarak çözülebilir. Üretim karışımı, atama, tesis yerleşimi, tedarik zinciri ve aşamalı karar problemlerinde ilk tercih olmalıdır.</li>
  <li><strong>Metasezgisel yöntemler</strong> (GA, SA, TS, ACO) optimallik garantisi vermez ama büyük, NP-zor ya da simülasyon tabanlı problemlerde makul sürede yüksek kaliteli çözümler üretir.</li>
  <li><strong>Matheuristic</strong> yaklaşımlar ise iki dünyanın en iyilerini birleştirir ve modern endüstriyel optimizasyonun büyük kısmı aslında bu hibritler üzerine kuruludur.</li>
</ul>

<p>Pratik öneri: Yeni bir optimizasyon problemiyle karşılaştığınızda önce <strong>modelleyin</strong>. Karar değişkenleri, amaç fonksiyonu ve kısıtları yazın. Model doğrusal/karma-tam sayı yapıya oturuyor ve orta ölçekliyse doğrudan bir MIP çözücü deneyin. Çözücü süre ya da bellek sınırına takılıyorsa matheuristic kurun; hiçbir matematiksel yapı çıkmıyorsa metasezgisel çerçeveyle (GA/SA/TS/ACO) ilerleyin. Her durumda, çözümün iş değeri için “yeterlilik eşiği” (ne kadar yakın optimal yeterli?) en baştan tanımlanmalıdır; bu eşik, yöntem seçimi için amaç fonksiyonundan sonraki en önemli girdidir.</p>

<p>Optimizasyon problemleri gündelik hayatta saklı hâlde karşımıza sürekli çıkar. Formel OR bakış açısı, bu problemleri sezgiyle değil matematikle çözmemizi, çözümlerin kalitesini ölçmemizi ve iş süreçlerinde kanıtlanabilir iyileşmeler yapmamızı sağlar. Bir sonraki “hangi iş önce?”, “hangi rota en iyi?”, “hangi karışımı üretelim?” sorusunu duyduğunuzda, kulağınızın arkasında bu yazıdaki tabloyu hatırlayın.</p>

<hr />

<p><em>Daha fazla okuma için:</em> Richard Bellman’ın <em>Dynamic Programming</em> (1957), David Goldberg’in <em>Genetic Algorithms in Search, Optimization and Machine Learning</em> (1989) ve Marco Dorigo ile Thomas Stützle’nin <em>Ant Colony Optimization</em> (2004) kitapları alanın klasikleri arasındadır. Tarihsel arka plan için Patrick Blackett’ın savaş dönemi OR ekipleri ve George Dantzig’in doğrusal programlamayı geliştirdiği Pentagon yıllarına odaklanan INFORMS’un <em>History of O.R. Excellence</em> serisi güzel bir başlangıçtır.</p>]]></content><author><name>M. Serdar Karaman</name></author><category term="muhendislik" /><category term="yoneylem-arastirmasi" /><summary type="html"><![CDATA[Gündelik hayatın ve iş süreçlerinin pek çok problemi yüzeyde sezgisel bir karar gibi görünse de aslında birer optimizasyon problemidir. Hangi ürünü ne kadar üreteceğiz? Sınırlı kamyon filosuyla siparişleri hangi rotada dağıtacağız? Bir çantaya ağırlık ve değer kısıtları altında hangi eşyaları koyacağız? Bir hastanede hemşire nöbet çizelgesini nasıl yapacağız? Bu soruların ortak paydası şudur: sınırlı kaynakları sınırlı kısıtlar altında bir amaca göre en iyileyecek şekilde dağıtmak.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://karaman.dev/img/og-default.webp" /><media:content medium="image" url="https://karaman.dev/img/og-default.webp" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry xml:lang="tr"><title type="html">MISRA C:2025 ile Neler Değişti?</title><link href="https://karaman.dev/2026/04/05/misra-c-2025-ile-neler-degisti.html" rel="alternate" type="text/html" title="MISRA C:2025 ile Neler Değişti?" /><published>2026-04-05T09:00:00+00:00</published><updated>2026-04-05T09:00:00+00:00</updated><id>https://karaman.dev/2026/04/05/misra-c-2025-ile-neler-degisti</id><content type="html" xml:base="https://karaman.dev/2026/04/05/misra-c-2025-ile-neler-degisti.html"><![CDATA[<p>Emniyet kritik yazılım geliştirme dünyasında MISRA C kuralları, onlarca yıldır en temel referans kaynaklarından biri olma özelliğini koruyor. Otomotivden havacılığa, medikal cihazlardan demiryolu sistemlerine kadar geniş bir yelpazede kullanılan bu kılavuz, Mart 2025’te yeni bir sürümle güncellendi: <strong>MISRA C:2025</strong>.</p>

<p>Bu yazıda MISRA C:2012’den (ve 2023 düzeltme paketi olan MISRA C:2023’ten) bu yana nelerin değiştiğini, yeni eklenen kuralları, kaldırılan ve devre dışı bırakılan kuralları, kod örnekleriyle detaylı şekilde inceleyeceğiz.</p>

<hr />

<h2 id="kısa-bir-tarihçe">Kısa Bir Tarihçe</h2>

<table>
  <thead>
    <tr>
      <th>Sürüm</th>
      <th>Yıl</th>
      <th>C Standardı Desteği</th>
      <th>Kural Sayısı</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>MISRA C:1998</td>
      <td>1998</td>
      <td>C90</td>
      <td>127</td>
    </tr>
    <tr>
      <td>MISRA C:2004</td>
      <td>2004</td>
      <td>C90</td>
      <td>141</td>
    </tr>
    <tr>
      <td>MISRA C:2012</td>
      <td>2013</td>
      <td>C90, C99</td>
      <td>159 (143 kural + 16 direktif)</td>
    </tr>
    <tr>
      <td>MISRA C:2023</td>
      <td>2023</td>
      <td>C90, C99, C11/C18</td>
      <td>221 (200 kural + 21 direktif)</td>
    </tr>
    <tr>
      <td>**MISRA C:2025**</td>
      <td>**2025**</td>
      <td>**C90, C99, C11/C18**</td>
      <td>**225 (201 kural + 22 direktif + 2 silinen)**</td>
    </tr>
  </tbody>
</table>

<p>MISRA C:2025, devrimsel bir değişiklik yerine <strong>evrimsel bir iyileştirme</strong> sunuyor. MISRA C:2023’ün getirdiği çoklu iş parçacığı (multithreading) ve atomik tip desteğinin üzerine, 4 yeni kural, 2 silinen kural, 1 devre dışı bırakılan kural ve 69 diğer düzenleme ile toplam <strong>79 değişiklik</strong> içeriyor.</p>

<hr />

<h2 id="yeni-kurallar">Yeni Kurallar</h2>

<p>MISRA C:2025 ile birlikte 4 yeni kural eklendi. Her birini örneklerle inceleyelim.</p>

<h3 id="kural-818--başlık-dosyalarında-belirsiz-tanımlara-tentative-definition-i̇zin-verilmez">Kural 8.18 — Başlık Dosyalarında Belirsiz Tanımlara (Tentative Definition) İzin Verilmez</h3>

<p><strong>Sınıflandırma:</strong> Required (Zorunlu)</p>

<p>C dilinde, bir değişken herhangi bir ilk değer (initializer) olmadan ve <code class="language-plaintext highlighter-rouge">extern</code> anahtar kelimesi kullanılmadan tanımlanırsa, bu bir <strong>belirsiz tanım</strong> (tentative definition) olarak kabul edilir. Eğer bu tanım bir başlık dosyasında yer alırsa ve bu dosya birden fazla derleme biriminde (<code class="language-plaintext highlighter-rouge">#include</code> ile) dahil edilirse, bağlayıcı (linker) hataları veya beklenmeyen davranışlar ortaya çıkabilir.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cm">/* config.h - başlık dosyası */</span>

<span class="cm">/* Uyumsuz (Non-compliant): Belirsiz tanım */</span>
<span class="kt">int32_t</span> <span class="n">global_counter</span><span class="p">;</span>

<span class="cm">/* Uyumlu (Compliant): extern bildirimi */</span>
<span class="k">extern</span> <span class="kt">int32_t</span> <span class="n">global_counter</span><span class="p">;</span>
</code></pre></div></div>

<p><strong>Neden önemli?</strong> Belirsiz tanımlar, hem tanımlama (definition) hem de bildirim (declaration) gibi davranır. Birden fazla <code class="language-plaintext highlighter-rouge">.c</code> dosyası aynı başlık dosyasını dahil ettiğinde, aynı değişkenin birden fazla kopyası oluşabilir:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cm">/* modul_a.c */</span>
<span class="cp">#include</span> <span class="cpf">"config.h"</span><span class="c1">   /* global_counter burada tanımlanır */</span><span class="cp">
</span>
<span class="cm">/* modul_b.c */</span>
<span class="cp">#include</span> <span class="cpf">"config.h"</span><span class="c1">   /* global_counter burada da tanımlanır! */</span><span class="cp">
</span>
<span class="cm">/* Sonuç: Bağlayıcı hatası veya tanımsız davranış */</span>
</code></pre></div></div>

<p>Doğru yaklaşım, değişkeni yalnızca bir <code class="language-plaintext highlighter-rouge">.c</code> dosyasında tanımlamak ve başlık dosyasında <code class="language-plaintext highlighter-rouge">extern</code> ile bildirmektir:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cm">/* config.h */</span>
<span class="k">extern</span> <span class="kt">int32_t</span> <span class="n">global_counter</span><span class="p">;</span>  <span class="cm">/* Sadece bildirim */</span>

<span class="cm">/* config.c */</span>
<span class="cp">#include</span> <span class="cpf">"config.h"</span><span class="cp">
</span><span class="kt">int32_t</span> <span class="n">global_counter</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>     <span class="cm">/* Gerçek tanım burada */</span>
</code></pre></div></div>

<hr />

<h3 id="kural-819--kaynak-dosyalarında-harici-bildirim-yapılmamalıdır">Kural 8.19 — Kaynak Dosyalarında Harici Bildirim Yapılmamalıdır</h3>

<p><strong>Sınıflandırma:</strong> Advisory (Tavsiye)</p>

<p>Bu kural, <code class="language-plaintext highlighter-rouge">extern</code> bildirimlerinin <code class="language-plaintext highlighter-rouge">.c</code> dosyaları içinde değil, yalnızca başlık dosyalarında yapılması gerektiğini belirtir. Kaynak dosya içinde yapılan <code class="language-plaintext highlighter-rouge">extern</code> bildirimleri, gizli bağımlılıklar oluşturur ve kodun bakımını zorlaştırır.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cm">/* Uyumsuz (Non-compliant): .c dosyasında extern bildirimi */</span>
<span class="kt">void</span> <span class="nf">sensor_oku</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">extern</span> <span class="kt">int32_t</span> <span class="n">kalibrasyon_degeri</span><span class="p">;</span>  <span class="cm">/* Gizli bağımlılık! */</span>
    <span class="kt">int32_t</span> <span class="n">sonuc</span> <span class="o">=</span> <span class="n">ham_deger</span> <span class="o">+</span> <span class="n">kalibrasyon_degeri</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cm">/* Uyumlu (Compliant): Başlık dosyasında bildirim */</span>

<span class="cm">/* kalibrasyon.h */</span>
<span class="k">extern</span> <span class="kt">int32_t</span> <span class="n">kalibrasyon_degeri</span><span class="p">;</span>

<span class="cm">/* sensor.c */</span>
<span class="cp">#include</span> <span class="cpf">"kalibrasyon.h"</span><span class="cp">
</span><span class="kt">void</span> <span class="nf">sensor_oku</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> <span class="p">{</span>
    <span class="kt">int32_t</span> <span class="n">sonuc</span> <span class="o">=</span> <span class="n">ham_deger</span> <span class="o">+</span> <span class="n">kalibrasyon_degeri</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p><strong>Neden önemli?</strong> Bir fonksiyon gövdesi içindeki <code class="language-plaintext highlighter-rouge">extern</code> bildirimi, o değişkenin nereden geldiğini gizler. Kod incelemesi sırasında bağımlılıklar kolayca gözden kaçabilir. Başlık dosyası kullanıldığında ise bağımlılık açıkça görülür ve derleyici tip uyumsuzluklarını yakalayabilir.</p>

<hr />

<h3 id="kural-1111--i̇şaretçiler-dolaylı-olarak-null-ile-karşılaştırılmamalıdır">Kural 11.11 — İşaretçiler Dolaylı Olarak NULL ile Karşılaştırılmamalıdır</h3>

<p><strong>Sınıflandırma:</strong> Advisory (Tavsiye)</p>

<p>C dilinde bir işaretçi, <code class="language-plaintext highlighter-rouge">if</code> koşulunda doğrudan kullanıldığında dolaylı olarak boolean’a dönüştürülür. Bu, işaretçinin <code class="language-plaintext highlighter-rouge">NULL</code> olup olmadığını kontrol eder ama <strong>niyet belirsiz</strong> kalır. MISRA C:2025, işaretçi karşılaştırmalarının açık (explicit) yapılmasını tavsiye eder.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">int32_t</span> <span class="o">*</span><span class="n">ptr</span> <span class="o">=</span> <span class="n">fonksiyon_cagir</span><span class="p">();</span>

<span class="cm">/* Uyumsuz (Non-compliant): Dolaylı karşılaştırma */</span>
<span class="k">if</span> <span class="p">(</span><span class="n">ptr</span><span class="p">)</span> <span class="p">{</span>
    <span class="cm">/* ... */</span>
<span class="p">}</span>

<span class="cm">/* Uyumsuz (Non-compliant): Dolaylı karşılaştırma */</span>
<span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">ptr</span><span class="p">)</span> <span class="p">{</span>
    <span class="cm">/* ... */</span>
<span class="p">}</span>

<span class="cm">/* Uyumsuz (Non-compliant): Dolaylı tür dönüşümü */</span>
<span class="n">bool</span> <span class="n">gecerli</span> <span class="o">=</span> <span class="p">(</span><span class="n">bool</span><span class="p">)</span><span class="n">ptr</span><span class="p">;</span>

<span class="cm">/* Uyumlu (Compliant): Açık karşılaştırma */</span>
<span class="k">if</span> <span class="p">(</span><span class="n">ptr</span> <span class="o">!=</span> <span class="nb">NULL</span><span class="p">)</span> <span class="p">{</span>
    <span class="cm">/* ... */</span>
<span class="p">}</span>

<span class="cm">/* Uyumlu (Compliant): Açık karşılaştırma */</span>
<span class="k">if</span> <span class="p">(</span><span class="n">ptr</span> <span class="o">==</span> <span class="nb">NULL</span><span class="p">)</span> <span class="p">{</span>
    <span class="cm">/* ... */</span>
<span class="p">}</span>
</code></pre></div></div>

<p><strong>Neden önemli?</strong> Açık karşılaştırma, kodun <strong>niyetini</strong> belgeliyor. <code class="language-plaintext highlighter-rouge">if (ptr)</code> yazdığınızda okuyucu, bunun bir boolean değer mi yoksa NULL kontrolü mü olduğunu anlamak için bağlamı incelemeye zorlanır. <code class="language-plaintext highlighter-rouge">if (ptr != NULL)</code> ise amacı doğrudan ifade eder. Bu kural, MISRA’nın <strong>temel tip modeli</strong> (essential type model) ile de uyumludur: işaretçiler boolean değildir.</p>

<hr />

<h3 id="kural-193--bir-union-elemanı-daha-önce-ayarlanmadıysa-okunamaz">Kural 19.3 — Bir Union Elemanı, Daha Önce Ayarlanmadıysa Okunamaz</h3>

<p><strong>Sınıflandırma:</strong> Required (Zorunlu)</p>

<p>Union’lar C dilinde bellekte aynı alanı paylaşan farklı türleri temsil eder. Bir eleman üzerinden yazıp farklı bir eleman üzerinden okumak <strong>tanımsız davranışa</strong> (undefined behavior) yol açabilir, çünkü bellek düzeni platforma bağlıdır.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">union</span> <span class="n">veri</span> <span class="p">{</span>
    <span class="kt">int32_t</span> <span class="n">tamsayi</span><span class="p">;</span>
    <span class="kt">float</span>   <span class="n">ondalik</span><span class="p">;</span>
<span class="p">};</span>

<span class="k">union</span> <span class="n">veri</span> <span class="n">d</span><span class="p">;</span>

<span class="cm">/* Uyumlu (Compliant): Yazılan eleman okunuyor */</span>
<span class="n">d</span><span class="p">.</span><span class="n">tamsayi</span> <span class="o">=</span> <span class="mi">42</span><span class="p">;</span>
<span class="kt">int32_t</span> <span class="n">x</span> <span class="o">=</span> <span class="n">d</span><span class="p">.</span><span class="n">tamsayi</span><span class="p">;</span>      <span class="cm">/* OK: Aynı eleman */</span>

<span class="cm">/* Uyumsuz (Non-compliant): Farklı eleman okunuyor */</span>
<span class="n">d</span><span class="p">.</span><span class="n">tamsayi</span> <span class="o">=</span> <span class="mi">42</span><span class="p">;</span>
<span class="kt">float</span> <span class="n">y</span> <span class="o">=</span> <span class="n">d</span><span class="p">.</span><span class="n">ondalik</span><span class="p">;</span>         <span class="cm">/* Tanımsız davranış! */</span>
</code></pre></div></div>

<p>Bu tür bir kullanım, özellikle <strong>type punning</strong> (tür hilesi) olarak bilinen teknikte karşımıza çıkar:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cm">/* Tehlikeli: IEEE 754 bitlerini okuma girişimi */</span>
<span class="k">union</span> <span class="p">{</span>
    <span class="kt">float</span>   <span class="n">f</span><span class="p">;</span>
    <span class="kt">uint32_t</span> <span class="n">u</span><span class="p">;</span>
<span class="p">}</span> <span class="n">pun</span><span class="p">;</span>

<span class="n">pun</span><span class="p">.</span><span class="n">f</span> <span class="o">=</span> <span class="mi">3</span><span class="p">.</span><span class="mi">14</span><span class="n">f</span><span class="p">;</span>
<span class="kt">uint32_t</span> <span class="n">bits</span> <span class="o">=</span> <span class="n">pun</span><span class="p">.</span><span class="n">u</span><span class="p">;</span>  <span class="cm">/* Uyumsuz: Tanımsız davranış */</span>

<span class="cm">/* Güvenli alternatif: memcpy kullanımı */</span>
<span class="kt">float</span> <span class="n">f</span> <span class="o">=</span> <span class="mi">3</span><span class="p">.</span><span class="mi">14</span><span class="n">f</span><span class="p">;</span>
<span class="kt">uint32_t</span> <span class="n">bits_guvenli</span><span class="p">;</span>
<span class="n">memcpy</span><span class="p">(</span><span class="o">&amp;</span><span class="n">bits_guvenli</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">f</span><span class="p">,</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">bits_guvenli</span><span class="p">));</span>
</code></pre></div></div>

<p><strong>Neden önemli?</strong> Union üzerinden type punning, platformdan platforma farklı sonuçlar üretebilir (endianness, hizalama, padding). <code class="language-plaintext highlighter-rouge">memcpy</code> kullanımı hem taşınabilir hem de derleyici optimizasyonları açısından güvenlidir.</p>

<hr />

<h2 id="silinen-kurallar">Silinen Kurallar</h2>

<p>MISRA C:2025 ile birlikte <strong>2 kural silinmiştir</strong>. Silinen kural numaraları gelecekte yeniden kullanılmayacaktır; bu, eski sürümlerle karışıklığı önlemek için alınmış bilinçli bir karardır.</p>

<p>Silinen kurallardan biri <strong>Kural 21.2</strong>‘dir. Bu kuralın kapsadığı konular artık diğer kurallar tarafından karşılanmaktadır.</p>

<hr />

<h2 id="devre-dışı-bırakılan-kural-155--tek-çıkış-noktası">Devre Dışı Bırakılan Kural: 15.5 — Tek Çıkış Noktası</h2>

<p>MISRA C:2025’in belki de en dikkat çekici değişikliği, uzun süredir tartışmalı olan <strong>Kural 15.5</strong>‘in (tek çıkış noktası — single point of exit) <strong>devre dışı bırakılmasıdır</strong> (disapplied).</p>

<p>Bu kural, bir fonksiyonun yalnızca tek bir <code class="language-plaintext highlighter-rouge">return</code> ifadesi içermesi gerektiğini zorunlu kılıyordu:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cm">/* Eski yaklaşım: Tek çıkış noktası (Kural 15.5'e uyumlu) */</span>
<span class="kt">int32_t</span> <span class="nf">bul</span><span class="p">(</span><span class="k">const</span> <span class="kt">int32_t</span> <span class="o">*</span><span class="n">dizi</span><span class="p">,</span> <span class="kt">size_t</span> <span class="n">boyut</span><span class="p">,</span> <span class="kt">int32_t</span> <span class="n">hedef</span><span class="p">)</span> <span class="p">{</span>
    <span class="kt">int32_t</span> <span class="n">sonuc</span> <span class="o">=</span> <span class="o">-</span><span class="mi">1</span><span class="p">;</span>

    <span class="k">for</span> <span class="p">(</span><span class="kt">size_t</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0u</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">boyut</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">dizi</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">==</span> <span class="n">hedef</span><span class="p">)</span> <span class="p">{</span>
            <span class="n">sonuc</span> <span class="o">=</span> <span class="p">(</span><span class="kt">int32_t</span><span class="p">)</span><span class="n">i</span><span class="p">;</span>
            <span class="k">break</span><span class="p">;</span>
        <span class="p">}</span>
    <span class="p">}</span>

    <span class="k">return</span> <span class="n">sonuc</span><span class="p">;</span>  <span class="cm">/* Tek çıkış noktası */</span>
<span class="p">}</span>
</code></pre></div></div>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cm">/* Yeni yaklaşım: Erken dönüş artık kabul edilebilir */</span>
<span class="kt">int32_t</span> <span class="nf">bul</span><span class="p">(</span><span class="k">const</span> <span class="kt">int32_t</span> <span class="o">*</span><span class="n">dizi</span><span class="p">,</span> <span class="kt">size_t</span> <span class="n">boyut</span><span class="p">,</span> <span class="kt">int32_t</span> <span class="n">hedef</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">for</span> <span class="p">(</span><span class="kt">size_t</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0u</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">boyut</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">dizi</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">==</span> <span class="n">hedef</span><span class="p">)</span> <span class="p">{</span>
            <span class="k">return</span> <span class="p">(</span><span class="kt">int32_t</span><span class="p">)</span><span class="n">i</span><span class="p">;</span>  <span class="cm">/* Erken dönüş */</span>
        <span class="p">}</span>
    <span class="p">}</span>

    <span class="k">return</span> <span class="o">-</span><span class="mi">1</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p><strong>Neden devre dışı bırakıldı?</strong> Modern yazılım geliştirme pratiğinde, erken dönüşlerin kodun okunabilirliğini ve bakımını kolaylaştırdığı yaygın olarak kabul görmektedir. Tek çıkış noktası kuralı, özellikle hata kontrolü gereken fonksiyonlarda gereksiz iç içe geçmelere ve karmaşık kontrol akışlarına neden oluyordu:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cm">/* Tek çıkış noktası ile karmaşık hata kontrolü */</span>
<span class="kt">int32_t</span> <span class="nf">dosya_isle</span><span class="p">(</span><span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">yol</span><span class="p">)</span> <span class="p">{</span>
    <span class="kt">int32_t</span> <span class="n">sonuc</span> <span class="o">=</span> <span class="n">HATA_BILINMEYEN</span><span class="p">;</span>
    <span class="kt">FILE</span> <span class="o">*</span><span class="n">fp</span> <span class="o">=</span> <span class="n">fopen</span><span class="p">(</span><span class="n">yol</span><span class="p">,</span> <span class="s">"r"</span><span class="p">);</span>

    <span class="k">if</span> <span class="p">(</span><span class="n">fp</span> <span class="o">!=</span> <span class="nb">NULL</span><span class="p">)</span> <span class="p">{</span>
        <span class="kt">char</span> <span class="o">*</span><span class="n">tampon</span> <span class="o">=</span> <span class="n">malloc</span><span class="p">(</span><span class="n">TAMPON_BOYUT</span><span class="p">);</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">tampon</span> <span class="o">!=</span> <span class="nb">NULL</span><span class="p">)</span> <span class="p">{</span>
            <span class="k">if</span> <span class="p">(</span><span class="n">fread</span><span class="p">(</span><span class="n">tampon</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="n">TAMPON_BOYUT</span><span class="p">,</span> <span class="n">fp</span><span class="p">)</span> <span class="o">&gt;</span> <span class="mi">0u</span><span class="p">)</span> <span class="p">{</span>
                <span class="n">sonuc</span> <span class="o">=</span> <span class="n">veriyi_isle</span><span class="p">(</span><span class="n">tampon</span><span class="p">);</span>
            <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
                <span class="n">sonuc</span> <span class="o">=</span> <span class="n">HATA_OKUMA</span><span class="p">;</span>
            <span class="p">}</span>
            <span class="n">free</span><span class="p">(</span><span class="n">tampon</span><span class="p">);</span>
        <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
            <span class="n">sonuc</span> <span class="o">=</span> <span class="n">HATA_BELLEK</span><span class="p">;</span>
        <span class="p">}</span>
        <span class="n">fclose</span><span class="p">(</span><span class="n">fp</span><span class="p">);</span>
    <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
        <span class="n">sonuc</span> <span class="o">=</span> <span class="n">HATA_DOSYA</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="k">return</span> <span class="n">sonuc</span><span class="p">;</span>  <span class="cm">/* Derin iç içe geçme! */</span>
<span class="p">}</span>
</code></pre></div></div>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cm">/* Erken dönüş ile aynı fonksiyon — çok daha okunabilir */</span>
<span class="kt">int32_t</span> <span class="nf">dosya_isle</span><span class="p">(</span><span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">yol</span><span class="p">)</span> <span class="p">{</span>
    <span class="kt">FILE</span> <span class="o">*</span><span class="n">fp</span> <span class="o">=</span> <span class="n">fopen</span><span class="p">(</span><span class="n">yol</span><span class="p">,</span> <span class="s">"r"</span><span class="p">);</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">fp</span> <span class="o">==</span> <span class="nb">NULL</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">return</span> <span class="n">HATA_DOSYA</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="kt">char</span> <span class="o">*</span><span class="n">tampon</span> <span class="o">=</span> <span class="n">malloc</span><span class="p">(</span><span class="n">TAMPON_BOYUT</span><span class="p">);</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">tampon</span> <span class="o">==</span> <span class="nb">NULL</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">fclose</span><span class="p">(</span><span class="n">fp</span><span class="p">);</span>
        <span class="k">return</span> <span class="n">HATA_BELLEK</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="kt">int32_t</span> <span class="n">sonuc</span><span class="p">;</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">fread</span><span class="p">(</span><span class="n">tampon</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="n">TAMPON_BOYUT</span><span class="p">,</span> <span class="n">fp</span><span class="p">)</span> <span class="o">&gt;</span> <span class="mi">0u</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">sonuc</span> <span class="o">=</span> <span class="n">veriyi_isle</span><span class="p">(</span><span class="n">tampon</span><span class="p">);</span>
    <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
        <span class="n">sonuc</span> <span class="o">=</span> <span class="n">HATA_OKUMA</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="n">free</span><span class="p">(</span><span class="n">tampon</span><span class="p">);</span>
    <span class="n">fclose</span><span class="p">(</span><span class="n">fp</span><span class="p">);</span>
    <span class="k">return</span> <span class="n">sonuc</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<blockquote>
  <p><strong>Dikkat:</strong> IEC 61508 ve ISO 26262 gibi fonksiyonel güvenlik standartları hâlâ tek çıkış noktası yaklaşımını talep edebilir. MISRA C:2025, bu kuralı silmek yerine <strong>devre dışı bırakarak</strong>, ihtiyaç halinde yeniden etkinleştirilebilir kılmıştır.</p>
</blockquote>

<hr />

<h2 id="mevcut-kurallardaki-önemli-güncellemeler">Mevcut Kurallardaki Önemli Güncellemeler</h2>

<h3 id="i̇şaretçi-dönüşüm-kuralları-113-114-116">İşaretçi Dönüşüm Kuralları: 11.3, 11.4, 11.6</h3>

<p>Bu kurallar, <code class="language-plaintext highlighter-rouge">intptr_t</code> ve <code class="language-plaintext highlighter-rouge">uintptr_t</code> türlerini hesaba alacak şekilde güncellendi. Artık tamsayılar ile adreslerin tamsayı temsili arasında daha fazla dönüşüm imkanı sunuluyor:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include</span> <span class="cpf">&lt;stdint.h&gt;</span><span class="cp">
</span>
<span class="kt">void</span> <span class="o">*</span><span class="n">ptr</span> <span class="o">=</span> <span class="n">get_address</span><span class="p">();</span>

<span class="cm">/* MISRA C:2012'de sorunlu olabilirdi */</span>
<span class="kt">uintptr_t</span> <span class="n">addr</span> <span class="o">=</span> <span class="p">(</span><span class="kt">uintptr_t</span><span class="p">)</span><span class="n">ptr</span><span class="p">;</span>

<span class="cm">/* İşlem yap (örn: hizalama kontrolü) */</span>
<span class="k">if</span> <span class="p">((</span><span class="n">addr</span> <span class="o">&amp;</span> <span class="mh">0x3u</span><span class="p">)</span> <span class="o">!=</span> <span class="mi">0u</span><span class="p">)</span> <span class="p">{</span>
    <span class="cm">/* Hizalanmamış adres */</span>
<span class="p">}</span>

<span class="cm">/* MISRA C:2025'te intptr_t ailesi ile dönüşüm açıkça destekleniyor */</span>
<span class="n">ptr</span> <span class="o">=</span> <span class="p">(</span><span class="kt">void</span> <span class="o">*</span><span class="p">)</span><span class="n">addr</span><span class="p">;</span>
</code></pre></div></div>

<p>Bu değişiklik özellikle düşük seviyeli sistem programlama, <strong>işaretçi etiketleme</strong> (pointer tagging) ve donanım kayıt adresleriyle çalışma gibi senaryolarda önemlidir.</p>

<h3 id="direktif-46--kayan-nokta-türleri-kapsam-dışı">Direktif 4.6 — Kayan Nokta Türleri Kapsam Dışı</h3>

<p>Direktif 4.6, daha önce uygulama tanımlı (implementation-defined) davranışa sahip temel türlerin yerine boyut belirten türlerin (<code class="language-plaintext highlighter-rouge">int32_t</code>, <code class="language-plaintext highlighter-rouge">uint16_t</code> vb.) kullanılmasını öneriyordu. MISRA C:2025’te <strong>kayan nokta türleri bu direktifin kapsamından çıkarılmıştır</strong>. Bunun nedeni, <code class="language-plaintext highlighter-rouge">float</code> ve <code class="language-plaintext highlighter-rouge">double</code> türlerinin IEEE 754 ile zaten standartlaştırılmış olması ve boyut belirten kayan nokta alternatiflerinin yaygın olmamasıdır.</p>

<h3 id="switch-case-yapısında-esneklik">Switch-Case Yapısında Esneklik</h3>

<p>MISRA C:2025’te switch-case yapılarındaki kural güncellemeleriyle, bir case bloğu artık yalnızca <code class="language-plaintext highlighter-rouge">break</code> ile değil, <code class="language-plaintext highlighter-rouge">return</code>, <code class="language-plaintext highlighter-rouge">continue</code> veya <code class="language-plaintext highlighter-rouge">abort()</code> gibi ifadelerle de sonlandırılabilir. Bu, daha önce erişilemez kod (unreachable code) uyarılarına neden olan gereksiz <code class="language-plaintext highlighter-rouge">break</code> ifadelerini ortadan kaldırır:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cm">/* MISRA C:2012: break zorunlu, return sonrası break gereksiz */</span>
<span class="k">switch</span> <span class="p">(</span><span class="n">komut</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">case</span> <span class="n">KOMUT_OKU</span><span class="p">:</span>
        <span class="k">return</span> <span class="n">veri_oku</span><span class="p">();</span>
        <span class="k">break</span><span class="p">;</span>           <span class="cm">/* Erişilemez kod uyarısı! */</span>
    <span class="k">case</span> <span class="n">KOMUT_YAZ</span><span class="p">:</span>
        <span class="n">veri_yaz</span><span class="p">();</span>
        <span class="k">break</span><span class="p">;</span>
    <span class="nl">default:</span>
        <span class="n">abort</span><span class="p">();</span>
        <span class="k">break</span><span class="p">;</span>           <span class="cm">/* Erişilemez kod uyarısı! */</span>
<span class="p">}</span>

<span class="cm">/* MISRA C:2025: return ve abort() yeterli */</span>
<span class="k">switch</span> <span class="p">(</span><span class="n">komut</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">case</span> <span class="n">KOMUT_OKU</span><span class="p">:</span>
        <span class="k">return</span> <span class="n">veri_oku</span><span class="p">();</span>   <span class="cm">/* break gerekmez */</span>
    <span class="k">case</span> <span class="n">KOMUT_YAZ</span><span class="p">:</span>
        <span class="n">veri_yaz</span><span class="p">();</span>
        <span class="k">break</span><span class="p">;</span>
    <span class="nl">default:</span>
        <span class="n">abort</span><span class="p">();</span>             <span class="cm">/* break gerekmez */</span>
<span class="p">}</span>
</code></pre></div></div>

<hr />

<h2 id="temel-tip-modeli-essential-type-model-güncellemesi">Temel Tip Modeli (Essential Type Model) Güncellemesi</h2>

<p>MISRA C’nin temel tip modeli, C dilinin örtük tür dönüşümlerinden kaynaklanan hataları önlemek için tasarlanmıştır. MISRA C:2025 ile bu modele yeni bir kategori eklendi: <strong>“essentially complex floating”</strong> (temel olarak karmaşık kayan nokta).</p>

<p>C11 ile birlikte gelen <code class="language-plaintext highlighter-rouge">_Complex</code> türleri (örneğin <code class="language-plaintext highlighter-rouge">double _Complex</code>) artık temel tip modelinde kendi kategorilerine sahip. Bu, karmaşık sayı işlemlerinde tür dönüşüm kurallarının doğru uygulanmasını sağlıyor.</p>

<p>Ayrıca yukarıda bahsedilen Kural 11.11, temel tip modelini işaretçi-boolean etkileşimlerine genişletiyor. İşaretçiler artık dolaylı olarak boolean gibi değerlendirilemez — bu, modelin kapsamını genişleten önemli bir adım.</p>

<hr />

<h2 id="misra-c2025-ve-rust-addendum-6">MISRA C:2025 ve Rust: Addendum 6</h2>

<p>MISRA C:2025 ile birlikte yayınlanan <strong>Addendum 6 (ADD6)</strong>, dikkat çekici bir şekilde MISRA C kurallarının <strong>Rust</strong> programlama diline uygulanabilirliğini değerlendiriyor. Bu, emniyet kritik sistemlerde Rust’ın artan kullanımına MISRA’nın verdiği ilk resmi yanıttır.</p>

<p>ADD6, MISRA C kurallarından hangilerinin Rust’ta doğal olarak karşılandığını (ownership sistemi, borrow checker sayesinde), hangilerinin alakasız olduğunu ve hangilerinin Rust’ta da dikkat gerektirdiğini haritalıyor. Bu, C’den Rust’a geçiş düşünen emniyet kritik projeler için değerli bir referans belgesi niteliğinde.</p>

<hr />

<h2 id="yapısal-değişiklikler">Yapısal Değişiklikler</h2>

<p>MISRA C:2025, kural organizasyonunda da önemli yenilikler getirdi:</p>

<table>
  <thead>
    <tr>
      <th>Değişiklik Türü</th>
      <th>Sayı</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Yeni kural</td>
      <td>4</td>
    </tr>
    <tr>
      <td>Yeniden numaralandırılan kural</td>
      <td>3</td>
    </tr>
    <tr>
      <td>Silinen kural</td>
      <td>2</td>
    </tr>
    <tr>
      <td>Devre dışı bırakılan kural</td>
      <td>1</td>
    </tr>
    <tr>
      <td>Normatif/teknik güncelleme</td>
      <td>12</td>
    </tr>
    <tr>
      <td>Bilgilendirici/editöryal güncelleme</td>
      <td>57</td>
    </tr>
    <tr>
      <td>**Toplam değişiklik**</td>
      <td>**79**</td>
    </tr>
  </tbody>
</table>

<p>Dikkat çeken yapısal yenilikler:</p>

<ul>
  <li><strong>“Silindi” ve “Devre dışı” kategorileri</strong> ilk kez tanımlandı. Bu, eski kural numaralarının yeniden kullanılmasını engelliyor ve sürümler arası geçişi kolaylaştırıyor.</li>
  <li><strong>Bazı kurallar direktife, bazı direktifler kurala dönüştürüldü</strong> — daha doğru sınıflandırma için.</li>
  <li><strong>3 kural</strong> daha uygun bölümlere taşındı.</li>
  <li><strong>Sürekli yayın modeli</strong> (rolling release) benimsendi. Artık bağımsız düzeltme paketleri (amendment) yerine, güncellemeler doğrudan yeni sürüm numaralarıyla yayınlanacak.</li>
</ul>

<hr />

<h2 id="misra-c2025e-geçiş-stratejisi">MISRA C:2025’e Geçiş Stratejisi</h2>

<p>Halihazırda MISRA C:2012 veya MISRA C:2023 kullanan projeler için geçiş nispeten kolaydır:</p>

<ol>
  <li>
    <p><strong>Statik analiz araçlarınızı güncelleyin.</strong> Perforce QAC, LDRA, Parasoft, Polyspace gibi büyük araç sağlayıcıları MISRA C:2025 desteğini eklemeye başlamıştır.</p>
  </li>
  <li>
    <p><strong>Yeni kuralları değerlendirin.</strong> Özellikle Kural 8.18 ve 19.3 (Required) zorunlu olduğundan, mevcut kodunuzda ihlal olup olmadığını kontrol edin.</p>
  </li>
  <li>
    <p><strong>Kural 15.5 politikanızı gözden geçirin.</strong> MISRA artık tek çıkış noktası gerektirmese de, projenizin bağlı olduğu fonksiyonel güvenlik standardı (IEC 61508, ISO 26262, DO-178C) bunu gerektiriyor olabilir.</p>
  </li>
  <li>
    <p><strong><code class="language-plaintext highlighter-rouge">intptr_t</code> kullanımınızı gözden geçirin.</strong> Kural 11.3, 11.4 ve 11.6’daki değişiklikler, düşük seviyeli donanım erişimi olan kodlarda daha fazla esneklik sağlayabilir.</p>
  </li>
  <li>
    <p><strong>Addendum 6’yı inceleyin.</strong> MISRA C:2025 ADD6, kuralların Rust programlama diline uygulanabilirlik eşlemesini içerir — özellikle C’den Rust’a geçiş düşünen projeler için değerlidir.</p>
  </li>
</ol>

<hr />

<h2 id="sonuç">Sonuç</h2>

<p>MISRA C:2025, köklü bir devrim değil ama önemli bir evrim. Yeni kurallar gerçek dünya sorunlarını hedefliyor: başlık dosyalarındaki belirsiz tanımlar, gizli <code class="language-plaintext highlighter-rouge">extern</code> bağımlılıkları, dolaylı NULL karşılaştırmaları ve union’ların güvensiz kullanımı.</p>

<p>Belki de en önemlisi, <strong>tek çıkış noktası kuralının devre dışı bırakılması</strong>, MISRA’nın modern yazılım geliştirme pratiklerine uyum sağlama iradesini gösteriyor.</p>

<p>C dili, emniyet kritik sistemlerde hâlâ baskın konumda ve MISRA C bu dilde güvenli kod yazmak için en kapsamlı kılavuz olmaya devam ediyor. MISRA C:2025 ile birlikte gelen C23/C24 desteği hazırlığı da, bu kılavuzun geleceğe dönük yol haritasının net olduğunu gösteriyor.</p>

<hr />

<p><em>Kaynaklar:</em></p>
<ul>
  <li><em>MISRA C:2025, Motor Industry Software Reliability Association, Mart 2025</em></li>
  <li><em><a href="https://www.perforce.com/blog/sca/misra-c-2025">Perforce — What Developers Need to Know About MISRA C:2025</a></em></li>
  <li><em><a href="https://ldra.com/ldra-blog/misra-c-2025-the-whys-and-wherefores-of-whats-new/">LDRA — MISRA C 2025: The whys and wherefores of what’s new</a></em></li>
  <li><em><a href="https://www.qt.io/quality-assurance/blog/misra-c-2025">Qt — MISRA C:2025: A closer look at some of the changes</a></em></li>
  <li><em><a href="https://www.parasoft.com/blog/misra-c-2025-rust-challenges/">Parasoft — MISRA C 2025: Safer Embedded Code for AI and Rust</a></em></li>
  <li><em><a href="https://www.sancsoft.com/resources/best-practices/misra-c2025-new-guidelines-for-critical-systems/">Sanctuary Software — MISRA C:2025 New Guidelines for Critical Systems</a></em></li>
</ul>]]></content><author><name>M. Serdar Karaman</name></author><category term="yazilim" /><category term="c-cpp" /><category term="emniyet-kritik" /><summary type="html"><![CDATA[Emniyet kritik yazılım geliştirme dünyasında MISRA C kuralları, onlarca yıldır en temel referans kaynaklarından biri olma özelliğini koruyor. Otomotivden havacılığa, medikal cihazlardan demiryolu sistemlerine kadar geniş bir yelpazede kullanılan bu kılavuz, Mart 2025’te yeni bir sürümle güncellendi: MISRA C:2025.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://karaman.dev/img/og-default.webp" /><media:content medium="image" url="https://karaman.dev/img/og-default.webp" xmlns:media="http://search.yahoo.com/mrss/" /></entry></feed>