Compare commits
2 commits
b5e449c1f4
...
f8efb09284
Author | SHA1 | Date | |
---|---|---|---|
f8efb09284 | |||
7fa1639a8d |
|
@ -8,15 +8,20 @@
|
|||
border-radius: 16px;
|
||||
box-shadow: 0 4px 30px rgba(0, 0, 0, 0.1);
|
||||
backdrop-filter: blur(8px);
|
||||
animation: backdropShift 10s linear infinite;
|
||||
-webkit-backdrop-filter: blur(8px);
|
||||
border: 1px solid rgba(18, 47, 101, 0.35);
|
||||
padding: 2rem;
|
||||
margin-bottom: 2rem;
|
||||
position: relative;
|
||||
filter: saturate(0.9);
|
||||
filter: saturate(0.7) brightness(0.8);
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.toc:has(#TableOfContents) {
|
||||
background-color: rgba(25, 25, 35, 0.45);
|
||||
border-radius: 10px;
|
||||
max-height: 70vh;
|
||||
}
|
||||
|
||||
.background-container {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
|
@ -40,15 +45,30 @@
|
|||
filter: blur(4px) saturate(0.65);
|
||||
}
|
||||
|
||||
/* Lead Styling */
|
||||
.prose :where([class~="lead"]):not(:where([class~="not-prose"],[class~="not-prose"] *)) {
|
||||
color: rgb(209, 182, 164);
|
||||
}
|
||||
|
||||
/* Header Page Name Styling */
|
||||
nav > div > a {
|
||||
font-size: 1.5rem;
|
||||
text-shadow: 0 0 6px rgba(0, 0, 0, 0.7);
|
||||
}
|
||||
|
||||
/* Header Button Styling */
|
||||
header nav ul li a,
|
||||
header nav ul li button {
|
||||
display: inline-block;
|
||||
padding: 0.5rem 1rem;
|
||||
background-color: rgba(25, 25, 35, 0.25);
|
||||
background: rgba(18, 47, 101, 0.25);
|
||||
border-radius: 8px;
|
||||
border: 1px solid rgba(25, 25, 35, 0.35);
|
||||
transition: all 0.3s ease;
|
||||
backdrop-filter: blur(4px);
|
||||
animation: backdropShift 10s linear infinite;
|
||||
-webkit-backdrop-filter: blur(8px);
|
||||
filter: saturate(0.9) brightness(0.9);
|
||||
}
|
||||
|
||||
header nav ul li a:hover,
|
||||
|
@ -61,10 +81,14 @@ header nav ul li button:hover {
|
|||
/* Search button specific styling */
|
||||
header button[id^="search-button"] {
|
||||
padding: 0.5rem 1rem;
|
||||
background-color: rgba(25, 25, 35, 0.25);
|
||||
background: rgba(18, 47, 101, 0.25);
|
||||
border-radius: 8px;
|
||||
border: 1px solid rgba(25, 25, 35, 0.35);
|
||||
transition: all 0.3s ease;
|
||||
backdrop-filter: blur(4px);
|
||||
animation: backdropShift 10s linear infinite;
|
||||
-webkit-backdrop-filter: blur(8px);
|
||||
filter: saturate(0.9) brightness(0.9);
|
||||
}
|
||||
|
||||
header button[id^="search-button"]:hover {
|
||||
|
@ -73,18 +97,14 @@ header button[id^="search-button"]:hover {
|
|||
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
@keyframes gradientShift {
|
||||
@keyframes backdropShift {
|
||||
0% {
|
||||
filter: saturate(0.9) hue-rotate(-15deg);
|
||||
backdrop-filter: blur(8px) hue-rotate(-10deg);
|
||||
}
|
||||
50% {
|
||||
filter: saturate(0.9) hue-rotate(15deg);
|
||||
backdrop-filter: blur(8px) hue-rotate(10deg);
|
||||
}
|
||||
100% {
|
||||
filter: saturate(0.9) hue-rotate(-15deg);
|
||||
backdrop-filter: blur(8px) hue-rotate(-10deg);
|
||||
}
|
||||
}
|
||||
|
||||
article.glass {
|
||||
animation: gradientShift 30s linear infinite;
|
||||
}
|
|
@ -16,7 +16,7 @@ copyright = "This website is open source. You can find the source code **[here](
|
|||
name = "Jeremy Karst"
|
||||
image = "img/sd_eye_icon.webp"
|
||||
headline = "I see patterns where others see noise"
|
||||
bio = "Seeming smart is easy when you learn for fun."
|
||||
bio = "People think you are smart when you learn for fun."
|
||||
links = [
|
||||
{ email = "mailto:DataScienceDIY@proton.me" },
|
||||
{ github = "https://code.karsttech.com" },
|
||||
|
|
|
@ -16,4 +16,4 @@ Markdown has been my go-to format for note taking for years now. While searching
|
|||
|
||||
This website will be a central place to share my projects, thoughts, and ideas, as well as a landing page for KarstTech. If you would like to see how it is built, I decided to make the source code available at [code.karsttech.com](https://code.karsttech.com).
|
||||
|
||||

|
||||

|
BIN
content/personal-blog/first-post/karsttech_logo_horiz.png
Normal file
After Width: | Height: | Size: 238 KiB |
After Width: | Height: | Size: 196 KiB |
|
@ -1,9 +1,9 @@
|
|||
+++
|
||||
title = 'USM Magnetics'
|
||||
title = 'USM Magnetics - Sensor Fusion'
|
||||
date = 2025-02-27T07:17:00-05:00
|
||||
draft = false
|
||||
categories = ['references']
|
||||
tags = ['USM', 'magnetics', 'data science', 'KarstTech', 'UUV']
|
||||
tags = ['USM', 'magnetics', 'data science', 'KarstTech', 'UUV', 'sensor fusion']
|
||||
+++
|
||||
|
||||
## Getting Started
|
||||
|
@ -24,10 +24,15 @@ Before we can even attempt to detect targets, we need to convert the vehicle ref
|
|||
|
||||
)")
|
||||
|
||||
While the Earth's scale magnetic field is complex, many people assume that on the local scale, the magnetic field is constant. This is not the case, and local variations can be large enough to throw off the vehicle's orientation estimate.
|
||||
While the Earth's scale magnetic field is complex, many people assume that on the local scale, the magnetic field is constant. This is not the case, and local variations can be large enough to throw off the vehicle's orientation estimate. In a surface vehicle, this can be mitigated by using GPS to correct for long term drift of the compass / magnetic measurements, but underwater it becomes much more complicated without a detailed map of local magnetic anomalies. Designing a method for planning underwater missions which can correct for these local variations is a problem that is being addressed in the near future, but in short it involves some calibration using surface data, and then using that calibration to improve underwater navigation.
|
||||
|
||||

|
||||
|
||||
The sensor fusion process attempts to take the best aspects of each sensor and combine them in a way that provides the most accurate estimate of the vehicle's orientation and position. For Gyroscopes, which are very accurate at measuring short term rotations, but suffer from drift over time, we can use the magnetometer to correct for the drift. We can use accelerometers to correct for quick movements, and to measure the long term orientation relative to gravity, while using GPS to provide long term movement and position data. Magnetometers are immune to the errors introduced into accelerometers by quick movements, especially in surface waves, and so they provide a very accurate measurement of the vehicle's orientation, but are subject to small errors due to local magnetic anomalies, and due to magnetic interference from the vehicle itself.
|
||||
|
||||
The exact method used to fuse the data is highly platform specific and needs to be tuned for the physical characteristics of the vehicle, and its sensors. The diagram below shows the general process, but the exact implementation details will not be discussed here.
|
||||
|
||||
|
||||
{{< mermaid >}}
|
||||
flowchart TD
|
||||
subgraph "Input Sensors"
|
||||
|
@ -94,8 +99,5 @@ flowchart TD
|
|||
MAG_CORR --> TARGET
|
||||
{{< /mermaid >}}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Once the vehicle know's it's own position and orientation through sensor fusion, we can use that information to convert the location of detected objects near the vehicle into the Earth's reference frame. This allows combining measurements from multiple passes over the same area, by multiple vehicles, or even on different days.
|
||||
|
||||
|
|
36
layouts/_default/list.html
Normal file
|
@ -0,0 +1,36 @@
|
|||
{{ define "main" }}
|
||||
<article class="prose max-w-full dark:prose-invert glass">
|
||||
{{ with .Title }}
|
||||
<header>
|
||||
<h1>{{ . | emojify }}</h1>
|
||||
</header>
|
||||
{{ end }}
|
||||
<section>{{ .Content | emojify }}</section>
|
||||
<section>
|
||||
{{ if .Data.Pages }}
|
||||
{{ if $.Params.groupByYear | default ($.Site.Params.list.groupByYear | default true) }}
|
||||
{{ range (.Paginate (.Pages.GroupByDate "2006")).PageGroups }}
|
||||
<h2 class="mt-12 text-2xl font-bold text-neutral-700 first:mt-8 dark:text-neutral-300">
|
||||
{{ .Key }}
|
||||
</h2>
|
||||
<hr class="w-36 border-dotted border-neutral-400" />
|
||||
{{ range .Pages }}
|
||||
{{ partial "article-link.html" . }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
{{ else }}
|
||||
{{ range (.Paginate .Pages).Pages }}
|
||||
{{ partial "article-link.html" . }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
{{ partial "pagination.html" . }}
|
||||
{{ else }}
|
||||
<section class="prose mt-10 dark:prose-invert">
|
||||
<p class="border-t py-8">
|
||||
<em>{{ i18n "list.no_articles" | emojify }}</em>
|
||||
</p>
|
||||
</section>
|
||||
{{ end }}
|
||||
</section>
|
||||
</article>
|
||||
{{ end }}
|
15
layouts/partials/background-images.html
Normal file
|
@ -0,0 +1,15 @@
|
|||
{{ $images := slice }}
|
||||
{{ range readDir "static/backgrounds" }}
|
||||
{{ if in .Name ".webp" }}
|
||||
{{ $images = $images | append .Name }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
|
||||
<div class="background-container">
|
||||
<img id="background-image" alt="Background" class="background-image">
|
||||
<script>
|
||||
const images = {{ $images }};
|
||||
const randomImage = images[Math.floor(Math.random() * images.length)];
|
||||
document.getElementById('background-image').src = `/backgrounds/${randomImage}`;
|
||||
</script>
|
||||
</div>
|
|
@ -1,2 +1,2 @@
|
|||
<link rel="shortcut icon" href="web-app-manifest-192x192.png">
|
||||
<link rel="apple-touch-icon" sizes="192x192" href="/web-app-manifest-192x192.png">
|
||||
<link rel="shortcut icon" href="/android-chrome-192x192.png">
|
||||
<link rel="apple-touch-icon" sizes="192x192" href="/android-chrome-192x192.png">
|
|
@ -1,5 +1,5 @@
|
|||
<div class="background-container">
|
||||
<img src="/neuron-purple.webp" alt="Background" class="background-image">
|
||||
<img src="/Apophysis-071008-64.webp" alt="Background" class="background-image">
|
||||
</div>
|
||||
<article class="prose max-w-full dark:prose-invert glass">
|
||||
{{ with .Title }}
|
||||
|
|
3
layouts/partials/scripts.html
Normal file
|
@ -0,0 +1,3 @@
|
|||
{{ if .Params.showTableOfContents | default (.Site.Params.article.showTableOfContents | default false) }}
|
||||
<script src="/js/scrollspy.js"></script>
|
||||
{{ end }}
|
37
layouts/personal-blog/list.html
Normal file
|
@ -0,0 +1,37 @@
|
|||
{{ define "main" }}
|
||||
{{ partial "background-images.html" . }}
|
||||
<article class="prose max-w-full dark:prose-invert glass">
|
||||
{{ with .Title }}
|
||||
<header>
|
||||
<h1>{{ . | emojify }}</h1>
|
||||
</header>
|
||||
{{ end }}
|
||||
<section>{{ .Content | emojify }}</section>
|
||||
<section>
|
||||
{{ if .Data.Pages }}
|
||||
{{ if $.Params.groupByYear | default ($.Site.Params.list.groupByYear | default true) }}
|
||||
{{ range (.Paginate (.Pages.GroupByDate "2006")).PageGroups }}
|
||||
<h2 class="mt-12 text-2xl font-bold text-neutral-700 first:mt-8 dark:text-neutral-300">
|
||||
{{ .Key }}
|
||||
</h2>
|
||||
<hr class="w-36 border-dotted border-neutral-400" />
|
||||
{{ range .Pages }}
|
||||
{{ partial "article-link.html" . }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
{{ else }}
|
||||
{{ range (.Paginate .Pages).Pages }}
|
||||
{{ partial "article-link.html" . }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
{{ partial "pagination.html" . }}
|
||||
{{ else }}
|
||||
<section class="prose mt-10 dark:prose-invert">
|
||||
<p class="border-t py-8">
|
||||
<em>{{ i18n "list.no_articles" | emojify }}</em>
|
||||
</p>
|
||||
</section>
|
||||
{{ end }}
|
||||
</section>
|
||||
</article>
|
||||
{{ end }}
|
67
layouts/personal-blog/single.html
Normal file
|
@ -0,0 +1,67 @@
|
|||
{{ define "main" }}
|
||||
{{ partial "background-images.html" . }}
|
||||
{{- $images := .Resources.ByType "image" }}
|
||||
{{- $cover := $images.GetMatch (.Params.cover | default "*cover*") }}
|
||||
{{- $feature := $images.GetMatch (.Params.feature | default "*feature*") | default $cover }}
|
||||
<article class="prose max-w-full dark:prose-invert glass">
|
||||
<header class="max-w-prose">
|
||||
{{ if .Params.showBreadcrumbs | default (.Site.Params.article.showBreadcrumbs | default false) }}
|
||||
{{ partial "breadcrumbs.html" . }}
|
||||
{{ end }}
|
||||
<h1 class="mb-8 mt-0 text-4xl font-extrabold text-neutral-900 dark:text-neutral">
|
||||
{{ .Title | emojify }}
|
||||
</h1>
|
||||
{{ if or
|
||||
(.Params.showDate | default (.Site.Params.article.showDate | default true))
|
||||
(and (.Params.showDateUpdated | default (.Site.Params.article.showDateUpdated | default false)) (ne (partial "functions/date.html" .Date) (partial "functions/date.html" .Lastmod)))
|
||||
(and (.Params.showWordCount | default (.Site.Params.article.showWordCount | default false)) (ne .WordCount 0))
|
||||
(and (.Params.showReadingTime | default (.Site.Params.article.showReadingTime | default true)) (ne .ReadingTime 0))
|
||||
(.Params.showEdit | default (.Site.Params.article.showEdit | default false))
|
||||
}}
|
||||
<div class="mb-10 text-base text-neutral-500 dark:text-neutral-400 print:hidden">
|
||||
{{ partial "article-meta.html" (dict "context" . "scope" "single") }}
|
||||
</div>
|
||||
{{ end }}
|
||||
{{ with $feature }}
|
||||
<div class="prose">
|
||||
{{ $altText := $.Params.featureAlt | default $.Params.coverAlt | default "" }}
|
||||
{{ $class := "mb-6 rounded-md" }}
|
||||
{{ $webp := $.Page.Site.Params.enableImageWebp | default true }}
|
||||
{{ partial "picture.html" (dict "img" . "alt" $altText "class" $class "lazy" false "webp" $webp) }}
|
||||
{{ with $.Params.coverCaption }}
|
||||
<figcaption class="-mt-3 mb-6 text-center">{{ . | markdownify }}</figcaption>
|
||||
{{ end }}
|
||||
</div>
|
||||
{{ end }}
|
||||
</header>
|
||||
<section class="prose mt-0 flex max-w-full flex-col dark:prose-invert lg:flex-row">
|
||||
{{ if and (.Params.showTableOfContents | default (.Site.Params.article.showTableOfContents | default false)) (in .TableOfContents "<ul") }}
|
||||
<div class="order-first px-0 lg:order-last lg:max-w-xs lg:ps-8">
|
||||
<div class="toc pe-5 lg:sticky lg:top-10 print:hidden">
|
||||
{{ partial "toc.html" . }}
|
||||
</div>
|
||||
</div>
|
||||
{{ end }}
|
||||
<div class="min-h-0 min-w-0 max-w-prose grow">
|
||||
{{ .Content | emojify }}
|
||||
</div>
|
||||
</section>
|
||||
<footer class="max-w-prose pt-8 print:hidden">
|
||||
{{ partial "author.html" . }}
|
||||
{{ partial "sharing-links.html" . }}
|
||||
{{ partial "article-pagination.html" . }}
|
||||
{{ if .Params.showComments | default (.Site.Params.article.showComments | default false) }}
|
||||
{{ if templates.Exists "partials/comments.html" }}
|
||||
<div class="pt-3">
|
||||
<hr class="border-dotted border-neutral-300 dark:border-neutral-600" />
|
||||
<div class="pt-3">
|
||||
{{ partial "comments.html" . }}
|
||||
</div>
|
||||
</div>
|
||||
{{ else }}
|
||||
{{ warnf "[CONGO] Comments are enabled for %s but no comments partial exists." .File.Path }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
</footer>
|
||||
</article>
|
||||
{{ end }}
|
BIN
static/backgrounds/Abstract_Lobster.webp
Normal file
After Width: | Height: | Size: 390 KiB |
BIN
static/backgrounds/AllSeeingEye_Neon.webp
Normal file
After Width: | Height: | Size: 318 KiB |
BIN
static/backgrounds/Apophysis_061231-00.webp
Normal file
After Width: | Height: | Size: 300 KiB |
BIN
static/backgrounds/Apophysis_071008-64.webp
Normal file
After Width: | Height: | Size: 245 KiB |
BIN
static/backgrounds/Beautiful_Poison.webp
Normal file
After Width: | Height: | Size: 287 KiB |
BIN
static/backgrounds/Blood_Rose_2_00068.webp
Normal file
After Width: | Height: | Size: 119 KiB |
BIN
static/backgrounds/Containment_Background.jpg
Normal file
After Width: | Height: | Size: 334 KiB |
BIN
static/backgrounds/Galaxy_In_Motion.webp
Normal file
After Width: | Height: | Size: 360 KiB |
BIN
static/backgrounds/Neuron_2.webp
Normal file
After Width: | Height: | Size: 249 KiB |
Before Width: | Height: | Size: 124 KiB After Width: | Height: | Size: 124 KiB |
BIN
static/backgrounds/Plague.webp
Normal file
After Width: | Height: | Size: 496 KiB |
BIN
static/backgrounds/Poison_Rose.webp
Normal file
After Width: | Height: | Size: 227 KiB |
BIN
static/backgrounds/Surgery.webp
Normal file
After Width: | Height: | Size: 172 KiB |
BIN
static/backgrounds/Tendrillia.webp
Normal file
After Width: | Height: | Size: 102 KiB |
BIN
static/backgrounds/Triangly_2.webp
Normal file
After Width: | Height: | Size: 160 KiB |
BIN
static/backgrounds/Unending_Spiral.webp
Normal file
After Width: | Height: | Size: 215 KiB |
BIN
static/backgrounds/name_me.webp
Normal file
After Width: | Height: | Size: 106 KiB |