Skip to content

Commit a516536

Browse files
committed
transform wip
1 parent c3e69b7 commit a516536

1 file changed

Lines changed: 27 additions & 21 deletions

File tree

src/dsp/fourier_from_finite_sequences.clj

Lines changed: 27 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -653,7 +653,7 @@ z-rotated
653653
;; assumption of periodicity, so it requires multiple basis frequencies to approximate.
654654
;;
655655
;; **Solutions**:
656-
;; 1. **Windowing**: Apply Hann/Hamming window to reduce sidelobes
656+
;; 1. **Windowing**: Apply Hann/Hamming window to reduce sidelobes (we'll explore this technique later)
657657
;; 2. **Zero-padding**: Increase FFT size to create finer frequency bins
658658
;; 3. **Interpolation**: Use parabolic interpolation to estimate true peak location
659659
;;
@@ -664,11 +664,19 @@ z-rotated
664664
;; Before we see how the DFT computes its coefficients, we need one key mathematical idea:
665665
;; **How do we measure if two patterns "align"**?
666666
;;
667-
;; The answer is the **inner product** (also called dot product):
667+
;; The answer is the **inner product** (also called dot product). For complex numbers,
668+
;; we use the **conjugate** of the first pattern:
668669
;;
669-
;; **$\langle a, b \rangle = \sum_{n} a_n \cdot b_n$**
670+
;; **$\langle a, b \rangle = \sum_{n} \overline{a_n} \cdot b_n$**
670671
;;
671-
;; Multiply corresponding elements and add them up. This simple operation has deep geometric meaning:
672+
;; The bar over $a_n$ means complex conjugate: flip the sign of the imaginary part.
673+
;;
674+
;; For real numbers, the conjugate does nothing, so this reduces to ordinary multiplication.
675+
;; For complex numbers (rotations), conjugating reverses the rotation direction—this
676+
;; "counter-rotation" makes matching frequencies "stand still," turning them into
677+
;; something easy to measure.
678+
;;
679+
;; This operation has deep geometric meaning:
672680
;;
673681
;; - **Aligned patterns** (move together): large positive sum
674682
;; - **Perpendicular patterns** (unrelated): sum ≈ 0
@@ -704,22 +712,19 @@ z-rotated
704712
:inner-product (format "%.2f" inner-opposite)
705713
:meaning "Patterns move inversely"}])
706714

707-
;; **This is exactly correlation**: measuring whether two sequences "march together."
715+
;; **This is similar to correlation**: measuring whether two sequences "march together."
716+
;; (Correlation also involves standardization, but the core idea is the same.)
708717
;;
709718
;; **Key insight**: The magnitude of the inner product tells you how strongly the patterns align.
710719
;; Large absolute value = strong relationship, small value = unrelated patterns.
711-
;;
712-
;; **A clever trick we'll use:** To measure if your signal contains rotation at frequency k,
713-
;; we'll multiply by the **opposite rotation** (backward/clockwise). This counter-rotation
714-
;; makes the matching frequency "stand still," turning it into something easy to measure—like
715-
;; running on a backwards treadmill to check your speed.
716720

717721
;; ### Why N Specific Frequencies?
718722

719723
;; Here's the key mathematical fact: the N rotation speeds we use **don't interfere with each other**.
720724
;; They're like independent directions—mathematicians call this "orthogonal."
721725
;;
722-
;; Let's see this concretely. Create two rotations at different frequencies and compute their inner product:
726+
;; Let's see this concretely. Take the real parts (cosine components) of two rotations
727+
;; at different frequencies and compute their inner product:
723728

724729
(def freq-1-rotation (dfn/cos (dfn/* 2.0 Math/PI 1.0 (dfn// (range 8) 8.0))))
725730
(def freq-2-rotation (dfn/cos (dfn/* 2.0 Math/PI 2.0 (dfn// (range 8) 8.0))))
@@ -799,16 +804,17 @@ inner-product-diff-freq
799804

800805
(def manual-k1 (manual-dft-component temperatures 1))
801806

802-
(kind/hiccup
803-
[:div
804-
[:p [:strong "Manual computation of DFT[1]:"]]
805-
[:ul
806-
[:li (str "Real part: " (format "%.4f" (:real manual-k1)))]
807-
[:li (str "Imaginary part: " (format "%.4f" (:imag manual-k1)))]
808-
[:li (str "Magnitude: " (format "%.4f"
809-
(Math/sqrt (+ (* (:real manual-k1) (:real manual-k1))
810-
(* (:imag manual-k1) (:imag manual-k1))))))]]
811-
[:p "Compare with library result: " (format "%.4f" (:magnitude (nth temp-analysis 1)))]])
807+
(kind/table
808+
[{:component "Real part"
809+
:value (format "%.4f" (:real manual-k1))}
810+
{:component "Imaginary part"
811+
:value (format "%.4f" (:imag manual-k1))}
812+
{:component "Magnitude"
813+
:value (format "%.4f"
814+
(Math/sqrt (+ (* (:real manual-k1) (:real manual-k1))
815+
(* (:imag manual-k1) (:imag manual-k1)))))}
816+
{:component "Library result (for comparison)"
817+
:value (format "%.4f" (:magnitude (nth temp-analysis 1)))}])
812818

813819
;; The formula is doing exactly what we said: measuring how well the signal matches each rotation.
814820
;; ## Windowing and Edge Effects: The Implicit Assumption

0 commit comments

Comments
 (0)