Announcement

Collapse
No announcement yet.

Announcement

Collapse
No announcement yet.

Back to the roots at 50: Introducing Spectral-G4 (AI meets VLF)

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • #31
    Originally posted by Repwoc View Post

    OK - so are you saying that "nanosecond-precision Dead-Time control" is no longer needed?
    The whole control scheme is handled by the STM32's HRTIM peripheral. In the firmware, I configure the dead-time parameters between the TX_PWM_A and TX_PWM_B signals with immense resolution.

    Comment


    • #32
      Originally posted by Repwoc View Post

      I'm not sure why you need the 220 uF cap to decouple the gate driver (and is it the right way round?). Did you mean for this to decouple the supply to the mosfets?
      You're absolutely right, that 220uF capacitor is meant to decouple the MOSFET supply, not the gate driver. And thanks for pointing that out - I just noticed the polarity is wrong on the schematic as well.

      Comment


      • #33
        Originally posted by Taktyk View Post

        The whole control scheme is handled by the STM32's HRTIM peripheral. In the firmware, I configure the dead-time parameters between the TX_PWM_A and TX_PWM_B signals with immense resolution.
        Yes, but you have the gates for the high- and low-side mosfets tied together. So when the signal flips one mosfet will turn off and the other will turn on. There's no way to control the dead time. If both mosfets end up being switched on during the transition you will get shoot-through.

        Comment


        • #34
          Originally posted by Repwoc View Post

          Yes, but you have the gates for the high- and low-side mosfets tied together. So when the signal flips one mosfet will turn off and the other will turn on. There's no way to control the dead time. If both mosfets end up being switched on during the transition you will get shoot-through.
          As I mentioned before, this approach works fine in commercial detectors just take a look at Carl Moreland's fundamental patent US20180372904A1. It's a standard bridge topology. To improve the switching characteristics, you could simply add a 4.7R - 20R resistor to each gate.

          However, this was just an early schematic from the very beginning of the project. I've actually abandoned this design, as well as the approaches used in detectors like the XP DEUS II. I'm currently using the DRV8872 motor driver, and it's completely sufficient for this application.

          Comment


          • #35
            Never mind.

            Originally posted by Taktyk View Post
            I've actually abandoned this design,
            Perhaps you could have mentioned that when I asked "Are you still using this design?".

            Comment


            • #36
              Originally posted by Repwoc View Post
              Never mind.



              Perhaps you could have mentioned that when I asked "Are you still using this design?".
              Just experimenting with different concepts - the kind of thing I drop one day and might come back to the next

              There are a few newer ICs that could potentially bring some benefits, but it's often the case that the more complex the part - like the DRV8872 I mentioned -- the more it becomes a source of trouble. I've just read that the DRV8872 has jitter problems (Carl mentioned it in one of the threads), and I managed to observe exactly that myself today. So tonight I'm going back to the simple, original solution ))

              On the software side, today I added a new feature to MDS - TX Bench - shipped in v0.12.0-beta. It's a calculator / sandbox that lets you enter the real coil parameters (inductance and DC resistance), the bridge supply voltage and an optional series capacitor. It then draws the full complementary H-bridge and computes the coil current peak-to-peak, peak and RMS directly from the actual switched Vbus waveform, with a per-harmonic breakdown for multi-frequency drive. In practice it lets me size the transmitter, compare single vs multi-frequency operation, try different frequency ratios (e.g. the Equinox 1:3:15), and check the current and thermal headroom before ever touching the hardware.

              Cheers,​

              Click image for larger version

Name:	mds_v12.png
Views:	60
Size:	206.0 KB
ID:	450665

              Comment


              • #37
                Metal Detector Studio - v0.13.0-beta out.

                A quick update on my bench/lab suite for developing VLF detectors. What's new in this beta:

                - Coil design tab - design a search coil before you wind it: DD / concentric / mono, both TX and RX windings (each with its own turns and wire gauge), and it gives you inductance, DC resistance, Q, wire length and self-resonance, plus a per-winding wire-gauge trade-off table. A D-shaped leg has no closed-form inductance, so it uses an equal-enclosed-area circle approximate (~ 20 %), the wound coil still gets measured. It hands the coil's L/R straight to the TX bench.
                - TX bench - enter the coil L/R/supply and it draws the full complementary H-bridge and computes the coil current (pk-pk / peak / RMS, per-harmonic) from the actual switched waveform. New: a measured-vs-model overlay punch in the tone currents from a scope FFT of the shunt and it back-solves your real per-tone drive weighting.
                - Filter Lab - synced to my firmware's current DSP (multi-freq motion band-pass with the REACT alpha table, the reworked fast channel, etc.); impulse + frequency response with the actual coefficients.

                Still a work-in-progress beta, but the design side is coming together nicely. Cheers.

                Click image for larger version

Name:	coil_v13.png
Views:	68
Size:	215.0 KB
ID:	450682

                Comment


                • #38
                  Quick update on the multi-frequency VLF I've been posting about (STM32G4 base, 3 simultaneous tones at 7.8 / 23.4 / 39 kHz via SHE-PWM). The coil/analog side is still a couple of months out, so instead of sitting on my hands I built a physics simulator and I'm developing the whole "spectral fingerprint" discriminator entirely in software first.

                  The idea: I don't need real dirt to work on discrimination logic. I need realistic target responses. So each target is modelled as a single-time-constant eddy-current responder, X(ω) = jωτ/(1+jωτ), with a ferro term for the magnetic side.

                  The synthetic data generation is the fun part. From a catalogue of ~13 seed targets I sample thousands of labelled examples, varying: depth (secondary field ~1/d³, magnitude only - phase is the discrimination cue and it doesn't move with depth), a per-unit spread on τ / permeability / coupling, added ground mineralisation, and per-harmonic I/Q noise on top. The nice thing is that deep targets come out unclassifiable for free - the coupling shrinks the response toward a fixed noise floor, so low-SNR fingerprints emerge from the physics rather than being faked. I get a clean labelled feature set: [normalised magnitude ×3, phase ×3], depth/size-invariant so the classifier learns the shape across frequency, not one operating point.

                  Then a small MLP (6→16→16→classes, sized to run on the G4's FP32 FPU) trains on it. What I care about isn't a headline accuracy number - it's the honest picture:
                  • Accuracy vs signal strength: near-chance for targets buried in the noise floor, climbing as they surface. Exactly how a real machine behaves.
                  • Multi- vs single-frequency, same net, same split: three harmonics beat one harmonic's phase by a measurable margin. That's the whole reason to do multi-freq, quantified instead of assumed.
                  • The ceiling is physical: pull-tab and mid-conductivity coins share a fingerprint across all three tones, so no classifier separates them. The real dig-it-up problem, measured rather than hidden.

                  The trainer exports the trained weights straight to a self-contained sf_classify() C header - the exact function the firmware will call on live feature frames, verified bit-for-bit against the Python model. And I can render synthetic "swings" (coil passing over a target) as recordings my bench studio replays, so the hodograph / FFT / DSP tabs all light up on simulated targets - no coil required.

                  When the hardware finally shows up, the pipeline doesn't change: I swap the synthetic τ / ferro seeds for measured signatures, regenerate, retrain, re-export. The discrimination brain will already be built, characterised and living in the firmware - the real data just makes it honest.

                  Happy to share the physics model / feature design if anyone's poking at multi-frequency discrimination too. Cheers.

                  https://www.youtube.com/watch?v=6IRH2vY0ldg

                  Comment


                  • #39
                    I'm working on a MF design with a similar tx to yours. I've chosen different frequencies to start off with - I've gone for 3 kHz, 9 kHz and 27 kHz - using SHE PWM to generate them, ie 3 kHz fundamental and 3rd and 9th harmonics. 5th, 7th and 11th harmonics are nulled. I'm using a full H-bridge to drive the Tx coil. The FFT is from the left and right ends of the bridge (ie across the Tx coil):

                    Click image for larger version  Name:	Differential FFT.png Views:	0 Size:	31.6 KB ID:	450757
                    I'm also using a STM32G474 mcu, but I haven't use the HRTIM. I would be interested in how you have configured the HRTIM to get high resolution with such a low fundamental frequency (because I couldn't figure out how to do it :-( ).

                    The problem I'm currently trying to overcome is the large noise on the Rx. It looks like switching noise because it coincides pretty much exactly with the Tx signal:
                    Click image for larger version  Name:	Rx noise.png Views:	0 Size:	39.2 KB ID:	450758
                    CH1 and CH2 (yellow and teal) traces are left and right sides of the bridge and CH3 (red) is off the Rx coil.

                    And if I present a target to the coil:
                    Click image for larger version  Name:	Rx noise with target.png Views:	0 Size:	45.0 KB ID:	450759
                    So if I can get rid of the switching noise I think it looks pretty good. If anyone has any ideas how to do that I'd be grateful for them.
                    Last edited by Repwoc; Yesterday, 08:49 PM. Reason: Spelling.

                    Comment


                    • #40
                      Originally posted by Repwoc View Post
                      I'm working on a MF design with a similar tx to yours. I've chosen different frequencies to start off with - I've gone for 3 kHz, 9 kHz and 27 kHz - using SHE PWM to generate them, ie 3 kHz fundamental and 3rd and 9th harmonics. 5th, 7th and 11th harmonics are nulled. I'm using a full H-bridge to drive the Tx coil. The FFT is from the left and right ends of the bridge (ie across the Tx coil):

                      Click image for larger version Name:	Differential FFT.png Views:	0 Size:	31.6 KB ID:	450757
                      I'm also using a STM32G474 mcu, but I haven't use the HRTIM. I would be interested in how you have configured the HRTIM to get high resolution with such a low fundamental frequency (because I couldn't figure out how to do it :-( ).

                      The problem I'm currently trying to overcome is the large noise on the Rx. It looks like switching noise because it coincides pretty much exactly with the Tx signal:
                      Click image for larger version Name:	Rx noise.png Views:	0 Size:	39.2 KB ID:	450758
                      CH1 and CH2 (yellow and teal) traces are left and right sides of the bridge and CH3 (red) is off the Rx coil.

                      And if I present a target to the coil:
                      Click image for larger version Name:	Rx noise with target.png Views:	0 Size:	45.0 KB ID:	450759
                      So if I can get rid of the switching noise I think it looks pretty good. If anyone has any ideas how to do that I'd be grateful for them.
                      Have you tried changing the Dead Time in the timer settings ? maybe that would help.

                      Comment


                      • #41
                        Hi Repwoc and Marchel,

                        Marchel is spot on with the dead-time suggestion. If the dead time is too short, you get shoot-through currents in the H-bridge, causing large current spikes from the supply. These spikes easily couple into the RX path as broadband noise.

                        Besides optimizing the dead time, I would also try:

                        - Slowing down the MOSFET edges with the gate resistors, and doing it asymmetrically: a larger resistor (e.g. 22 Ω) for turn-ON, with an anti-parallel diode so turn-OFF stays fast. This reduces dV/dt (less coupled noise) without increasing the shoot-through risk.
                        - An RC snubber across the bridge or the TX coil to damp high-frequency ringing.
                        - Reviewing the PCB layout and current return paths. Common impedance coupling between the H-bridge and the analog front-end is very often the real culprit with this type of noise.

                        One more thought that may reframe the problem: since your noise is exactly synchronous with the TX, after synchronous demodulation it does not look like noise at all. It becomes a constant offset vector in I/Q. If it is stable, your nulling / baseline subtraction removes it entirely. What actually hurts you is its jitter (another reason why clean dead-time and stable switching instants matter) and its thermal drift. It also helps to sync the ADC sampling to the TX grid, so the sampling instants never land on the switching edges.

                        Regarding HRTIM at a 3 kHz fundamental:

                        The period register is 16-bit, so you cannot keep the full DLL high-resolution mode (184 ps, x32) over a 333 µs period; that would need about 1.8 M counts. But you do not need it. At CKPSC = div1 the counter tick is 1/170 MHz = 5.88 ns, and your 3 kHz period is 56,667 counts, which fits in 16 bits with a timing granularity of about 1/57,000 of the period. For SHE-PWM that is overkill in the good direction. The dead-time generator has its own prescaler, so dead-time granularity stays fine independently.

                        For the pulse pattern itself:

                        - If your SHE pattern has only a few switching angles (up to 4 edges per output per period), you can do it with no DMA at all: each timer haseset crossbar.
                        - For more edges, use the feature the reference manual calls Burst DMA (RM0440, HRTIM chapter). You pre-calculate the switching instants pare registers from that table onevery Repetition/Update event. With preload enabled, the new values are taken over glitch-free at the period boundary.

                        In pseudocode:

                        Code:
                        /* fHRTIM = 170 MHz, CKPSC = div1 -> 1 tick = 5.88 ns */
                        #define PERIOD_TICKS (170000000 / 3000) /* 56667 ticks = 333.3 us */
                        
                        /* SHE switching instants precomputed offline (in ticks),
                        * grouped per period; each group reloads CMP1..CMP4 */
                        static const uint16_t she_table[N_GROUPS][4] = {
                            { 4200, 11300, 17800, 24100 }, /* edge set for segment 1 */
                            { 32500, 39100, 45600, 52200 }, /* edge set for segment 2 */
                        /* ... */
                        };
                        
                        void tx_init(void)
                        {
                            /* Timer A: period, preload, update on repetition event */
                            hrtim_set_period(TIMER_A, PERIOD_TICKS);
                            hrtim_enable_preload(TIMER_A, UPDATE_ON_REPETITION);
                            hrtim_set_deadtime(TIMER_A, rising_ns(120), falling_ns(120));
                        
                            /* output waveform = crossbar events:
                            * TA1: SET on CMP1, RESET on CMP2
                            * TA2: complementary with dead-time inserted by hardware */
                            hrtim_output_set_source(TA1, SET_ON_CMP1, RST_ON_CMP2);
                        
                            /* Burst DMA: register list = {CMP1, CMP2, CMP3, CMP4};
                            * circular DMA feeds the list from she_table[] on every
                            * update event, so the pattern plays with zero CPU load */
                            hrtim_burst_dma_config(TIMER_A, REGS(CMP1, CMP2, CMP3, CMP4));
                            dma_start_circular(she_table, HRTIM_BDMADR,
                            N_GROUPS * 4, TRIGGER_TIMA_UPDATE);
                        
                            hrtim_outputs_enable(TA1 | TA2);
                            hrtim_start(TIMER_A);
                        }
                        ​​

                        From the timer's point of view it just executes a sequence of SET/CLEAR events at precisely defined moments. If the whole pattern repeats every period, the table stays small and DMA runs in circular mode, so the CPU does nothing during transmission.

                        That is exactly the route I am taking on the Spectral-G4: right now I have the baseline HRTIM config running (complementary pair with dead-time at f0 = 7.8125 kHz), the SHE switching angles are computed offline (equal power in the 1st/3rd/5th harmonic comes from the pulse pattern, not from exotic frequency choices), and Burst DMA playback of that pattern is the next step once the power stage is on the bench.

                        Hope this helps!​

                        Comment


                        • #42
                          I wanted to show how I actually work on this project day to day, because the workflow itself might be more interesting to some of you than the schematics.

                          1. Firmware in VS Code with the STM32 extension

                          The entire firmware (STM32G474 main board + STM32G071 probe) lives in a single Git repository as CubeMX/CMake projects. I work in VS Code with the STM32 extension and STM32CubeCLT (arm-gcc, CMake/Ninja, CubeProgrammer, ST-LINK gdb-server). One shortcut builds, another flashes the Nucleo. No proprietary IDE.

                          The most important habit: every DSP/UI module is written as portable C with no HAL dependency (demodulation, CORDIC, ground balance, VDI, mode filters, menu engine, LCD framebuffer, telemetry protocol). Every module has a small host test compiled with plain GCC on the PC. This allowed the entire digital pipeline (synthetic samples -> demod -> ground balance -> VDI -> display/audio/telemetry) to be written and verified before the analog board even existed. When the hardware arrives, bring-up is simply connecting proven modules to the pins.

                          2. Documentation as part of the repository

                          Decisions live next to the code: a project context file, a single task board with the roadmap, and design documents (SHE-PWM switching pattern with calculated switching angles, telemetry schema, UI concept, datasheets). The telemetry contract is a schema.json file in the repository. The PC side builds its parser from it, so firmware protocol changes never get out of sync with the tooling.

                          3. Aether, the project memory

                          A separate project of my own: a local, private AI agent (FastAPI + PydanticAI, Qdrant vector memory + SQLite, Next.js/Electron frontend) that serves as the brain of the project's documentation. All project documents are stored in its knowledge base and indexed not as flat RAG vectors but as a graph of connected concepts. It also has two capabilities that a typical chatbot does not: a nightly cycle that consolidates the day's logs and files after work and greets me in the morning with a brief saying "what was decided yesterday and what follows from it", and an active world model that connects facts in the background and proactively suggests observations ("this ADC decision conflicts with what you assumed for the sampling strategy"). Nothing ever leaves my local machine.

                          The best part is the integration: Aether exposes an MCP (Model Context Protocol) server, so the coding agent in VS Code has direct access to the same long-term knowledge. A question like "why did we reject delta-sigma in favor of SAR six months ago?" gets an answer immediately.

                          4. Metal-detector-studio (MDS), the PC lab bench

                          A separate open project: a FastAPI backend that communicates with the detector over USB-CDC, streams telemetry over WebSockets, and provides an XY hodograph (I/Q vector per harmonic), a virtual oscilloscope, live FFT, and session recording with replay. Every recording can later be replayed exactly as if the device were connected live. This is where ground balance and discrimination are tuned while looking at the actual vectors.

                          5. Spectral-sim, physics before hardware

                          The newest component. A physics-based simulator where every target is represented by a single time constant responder X(w) = jwt/(1+jwt), with a magnetic term for iron. This simple grey-box model already reproduces the classic VLF picture (iron on the opposite phase side, gold overlapping foil, pull tabs overlapping mid-value coins) across my three harmonics: 7.8, 23.4, and 39 kHz.

                          The point of all this is that when the analog board finally reaches the bench, I simply replace synthetic data with measured signatures, while the entire pipeline (dataset -> training -> C export -> validation in Studio) has already been exercised end to end.

                          6. Working with an AI pair engineer

                          I do all of this together with Claude Code (Anthropic's coding agent) running in the terminal and VS Code. It has direct access to the repositories, builds and runs tests on its own, reads datasheets from the repository, keeps the task board and documentation synchronized with the code, and through MCP accesses Aether's memory, so it knows the project's decision history, not just the current code. A typical session starts with me deciding the topology, frequencies, and engineering trade-offs. It drafts the module together with its host test, we iterate until the test passes and the target build stays green, and then it writes the commit. It catches my mistakes in DSP corner cases, and I catch its occasional overconfidence, which makes for a fair partnership. The multi-frequency demodulator, menu engine, telemetry protocol, and the entire simulator were built this way, each verified by tests rather than trust.

                          None of this replaces bench work. A metal detector is ultimately won or lost in the analog front end and the coil. But it does mean that by the time I pick up the soldering iron, the software is no longer a pile of TODOs, but a tested pipeline waiting for real signals.

                          Happy to answer questions about any part of this workflow.

                          Click image for larger version  Name:	project workflow.webp Views:	0 Size:	102.1 KB ID:	450782

                          Comment


                          • #43
                            Originally posted by Taktyk View Post
                            I wanted to show how I actually work on this project day to day, because the workflow itself might be more interesting to some of you than the schematics.

                            1. Firmware in VS Code with the STM32 extension

                            The entire firmware (STM32G474 main board + STM32G071 probe) lives in a single Git repository as CubeMX/CMake projects. I work in VS Code with the STM32 extension and STM32CubeCLT (arm-gcc, CMake/Ninja, CubeProgrammer, ST-LINK gdb-server). One shortcut builds, another flashes the Nucleo. No proprietary IDE.

                            The most important habit: every DSP/UI module is written as portable C with no HAL dependency (demodulation, CORDIC, ground balance, VDI, mode filters, menu engine, LCD framebuffer, telemetry protocol). Every module has a small host test compiled with plain GCC on the PC. This allowed the entire digital pipeline (synthetic samples -> demod -> ground balance -> VDI -> display/audio/telemetry) to be written and verified before the analog board even existed. When the hardware arrives, bring-up is simply connecting proven modules to the pins.

                            2. Documentation as part of the repository

                            Decisions live next to the code: a project context file, a single task board with the roadmap, and design documents (SHE-PWM switching pattern with calculated switching angles, telemetry schema, UI concept, datasheets). The telemetry contract is a schema.json file in the repository. The PC side builds its parser from it, so firmware protocol changes never get out of sync with the tooling.

                            3. Aether, the project memory

                            A separate project of my own: a local, private AI agent (FastAPI + PydanticAI, Qdrant vector memory + SQLite, Next.js/Electron frontend) that serves as the brain of the project's documentation. All project documents are stored in its knowledge base and indexed not as flat RAG vectors but as a graph of connected concepts. It also has two capabilities that a typical chatbot does not: a nightly cycle that consolidates the day's logs and files after work and greets me in the morning with a brief saying "what was decided yesterday and what follows from it", and an active world model that connects facts in the background and proactively suggests observations ("this ADC decision conflicts with what you assumed for the sampling strategy"). Nothing ever leaves my local machine.

                            The best part is the integration: Aether exposes an MCP (Model Context Protocol) server, so the coding agent in VS Code has direct access to the same long-term knowledge. A question like "why did we reject delta-sigma in favor of SAR six months ago?" gets an answer immediately.

                            4. Metal-detector-studio (MDS), the PC lab bench

                            A separate open project: a FastAPI backend that communicates with the detector over USB-CDC, streams telemetry over WebSockets, and provides an XY hodograph (I/Q vector per harmonic), a virtual oscilloscope, live FFT, and session recording with replay. Every recording can later be replayed exactly as if the device were connected live. This is where ground balance and discrimination are tuned while looking at the actual vectors.

                            5. Spectral-sim, physics before hardware

                            The newest component. A physics-based simulator where every target is represented by a single time constant responder X(w) = jwt/(1+jwt), with a magnetic term for iron. This simple grey-box model already reproduces the classic VLF picture (iron on the opposite phase side, gold overlapping foil, pull tabs overlapping mid-value coins) across my three harmonics: 7.8, 23.4, and 39 kHz.

                            The point of all this is that when the analog board finally reaches the bench, I simply replace synthetic data with measured signatures, while the entire pipeline (dataset -> training -> C export -> validation in Studio) has already been exercised end to end.

                            6. Working with an AI pair engineer

                            I do all of this together with Claude Code (Anthropic's coding agent) running in the terminal and VS Code. It has direct access to the repositories, builds and runs tests on its own, reads datasheets from the repository, keeps the task board and documentation synchronized with the code, and through MCP accesses Aether's memory, so it knows the project's decision history, not just the current code. A typical session starts with me deciding the topology, frequencies, and engineering trade-offs. It drafts the module together with its host test, we iterate until the test passes and the target build stays green, and then it writes the commit. It catches my mistakes in DSP corner cases, and I catch its occasional overconfidence, which makes for a fair partnership. The multi-frequency demodulator, menu engine, telemetry protocol, and the entire simulator were built this way, each verified by tests rather than trust.

                            None of this replaces bench work. A metal detector is ultimately won or lost in the analog front end and the coil. But it does mean that by the time I pick up the soldering iron, the software is no longer a pile of TODOs, but a tested pipeline waiting for real signals.

                            Happy to answer questions about any part of this workflow.

                            Click image for larger version Name:	project workflow.webp Views:	0 Size:	102.1 KB ID:	450782
                            It's a nice project and I've emailed you a few times about collaborating but haven't received any response.

                            Comment


                            • #44
                              Originally posted by Marchel View Post

                              It's a nice project and I've emailed you a few times about collaborating but haven't received any response.
                              I don't see any messages from you in my DMs. You can also email me at: [email protected]

                              Comment


                              • #45
                                Originally posted by Taktyk View Post

                                I don't see any messages from you in my DMs. You can also email me at: [email protected]
                                I wrote to [email protected], so you probably have a typo there.

                                Comment

                                Working...
                                X