﻿<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0">
  <channel>
    <title>Hardware Discussions</title>
    <description>Latest discussions happening in the Hardware category</description>
    <link>https://www.aboveunity.com</link>
    <item>
      <title>ESP32 Pro Function Generator</title>
      <description>&lt;p&gt;My Friends,&lt;/p&gt;&#xD;
&lt;p&gt;I want to share some code with you all, to help others out there, gain advanced PWM Control using a $7 ESP32 Microcontroller:&lt;/p&gt;&#xD;
&lt;p&gt;&lt;img style="display: block; margin-left: auto; margin-right: auto;" src="../../content/uploads/b5d8d256-5657-4ec2-ac7c-a741014a20b4/618fe43d-5208-4890-920b-b3aa007ff55a_esp32-devkit-v1-doit-pinout-getting-started.jpg?width=690&amp;amp;upscale=false" alt=""&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;&#xD;
&lt;p&gt;As you can see, there are a lot of PWM Pins! Well, lets do some funky PWM stuff with them:&lt;/p&gt;&#xD;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;&#xD;
&lt;h3&gt;Function Generator&lt;/h3&gt;&#xD;
&lt;pre class="language-cpp"&gt;&lt;code&gt;/**&#xD;
 * @file ESP32_Pro_Function_Generator.cpp&#xD;
 * @brief Ultimate 16-Channel Phase-Coherent Arbitrary Waveform Generator&#xD;
 * - 16 independent channels (0&amp;ndash;15)&#xD;
 * - True 0.022&amp;deg; phase control across ALL timers via DDS.&#xD;
 * - Sine, Triangle, Sawtooth, Square, Arbitrary&#xD;
 * - DDS with 32-bit phase accumulator @ 100 kHz update rate.&#xD;
 * - Fixed-point amplitude and DC offset control in ISR.&#xD;
 * - Frequency sweep enabled in loop().&#xD;
 * - Uses the correct LEDC hardware synchronization.&#xD;
 *&#xD;
 *&#xD;
 * @author Aboveunity.com &amp;mdash; Elite Edition (Fixed for Performance)&#xD;
 *&#xD;
 * @date 2025&#xD;
 */&#xD;
&#xD;
#include &amp;lt;Arduino.h&amp;gt;&#xD;
#include &amp;lt;driver/ledc.h&amp;gt;&#xD;
#include &amp;lt;soc/ledc_reg.h&amp;gt;&#xD;
#include &amp;lt;soc/ledc_struct.h&amp;gt;&#xD;
#include &amp;lt;math.h&amp;gt;&#xD;
&#xD;
// =================================================================================&#xD;
// CONFIGURATION CONSTANTS&#xD;
// =================================================================================&#xD;
&#xD;
#define PWM_CHANNELS            16&#xD;
#define PWM_RESOLUTION_BITS     14&#xD;
#define PWM_MAX_DUTY            ((1 &amp;lt;&amp;lt; PWM_RESOLUTION_BITS) - 1) // 16383&#xD;
#define TABLE_SIZE              (1 &amp;lt;&amp;lt; PWM_RESOLUTION_BITS) // 16384&#xD;
#define APB_CLK_FREQ            80000000UL&#xD;
#define DDS_UPDATE_RATE_HZ      100000UL     ///&amp;lt; 100 kHz (10 &amp;micro;s period)&#xD;
#define FIXED_POINT_SCALE       10000UL      ///&amp;lt; Fixed-point multiplier for amplitude scaling&#xD;
&#xD;
// Waveform types&#xD;
typedef enum {&#xD;
    WAVE_SINE = 0,&#xD;
    WAVE_TRIANGLE,&#xD;
    WAVE_SAWTOOTH,&#xD;
    WAVE_SQUARE,&#xD;
    WAVE_ARBITRARY,&#xD;
    WAVE_DC&#xD;
} waveform_t;&#xD;
&#xD;
// =================================================================================&#xD;
// CHANNEL STRUCTURE &amp;amp; GLOBAL STATE&#xD;
// =================================================================================&#xD;
&#xD;
// Main channel structure&#xD;
struct PWM_Channel {&#xD;
    uint8_t         pin;&#xD;
    ledc_channel_t  channel;&#xD;
    ledc_timer_t    timer;&#xD;
    &#xD;
    // Configurable parameters&#xD;
    float           phase_deg;          &#xD;
    float           amplitude_percent; &#xD;
    float           dc_offset_percent; &#xD;
    &#xD;
    waveform_t      waveform;&#xD;
    const uint16_t* arb_table;&#xD;
    uint16_t        arb_size;&#xD;
    &#xD;
    bool            enabled;&#xD;
    // NOTE: Inverted/Dead-time requires additional LEDC configuration not included in this DDS core.&#xD;
    &#xD;
    // PRE-CALCULATED VALUES for fast ISR execution&#xD;
    uint16_t        amp_scale;          ///&amp;lt; amplitude_percent * (FIXED_POINT_SCALE / 100.0f)&#xD;
    int32_t         offset_duty;        ///&amp;lt; dc_offset_percent * (PWM_MAX_DUTY / 100.0f)&#xD;
    uint32_t        initial_phase_acc;  ///&amp;lt; DDS accumulator offset for phase_deg&#xD;
};&#xD;
&#xD;
PWM_Channel channels[PWM_CHANNELS];&#xD;
&#xD;
volatile uint32_t global_frequency_hz = 10000;&#xD;
&#xD;
// DDS phase accumulators (one per channel)&#xD;
volatile uint32_t phase_accumulator[PWM_CHANNELS] = {0};&#xD;
volatile uint32_t phase_increment[PWM_CHANNELS] = {0};&#xD;
&#xD;
// Pointers to the generated tables&#xD;
static uint16_t __attribute__((section(".noinit"))) _sine_table[TABLE_SIZE];&#xD;
static uint16_t __attribute__((section(".noinit"))) _triangle_table[TABLE_SIZE];&#xD;
static uint16_t __attribute__((section(".noinit"))) _sawtooth_table[TABLE_SIZE];&#xD;
&#xD;
const uint16_t* sine_table = _sine_table;&#xD;
const uint16_t* triangle_table = _triangle_table;&#xD;
const uint16_t* sawtooth_table = _sawtooth_table;&#xD;
static bool tables_initialized = false;&#xD;
&#xD;
// =================================================================================&#xD;
// WAVEFORM TABLE GENERATION (FIXED: Standard C/C++ initialization)&#xD;
// =================================================================================&#xD;
&#xD;
/**&#xD;
 * @brief Computes 14-bit, 16384-point waveform tables.&#xD;
 */&#xD;
static void compute_waveform_table() {&#xD;
    for (int i = 0; i &amp;lt; TABLE_SIZE; i++) {&#xD;
        float x = (float)i / TABLE_SIZE; // Normalized phase (0.0 to 1.0)&#xD;
        float val;&#xD;
&#xD;
        // Sine wave (0 to 1.0) -&amp;gt; scaled to 14-bit (0 to 16383)&#xD;
        val = sinf(2.0f * M_PI * x) * 0.5f + 0.5f;&#xD;
        _sine_table[i] = (uint16_t)(val * PWM_MAX_DUTY);&#xD;
&#xD;
        // Triangle wave (0 to 1.0) -&amp;gt; scaled to 14-bit&#xD;
        val = (x &amp;lt; 0.5f) ? (x * 2.0f) : ((1.0f - x) * 2.0f);&#xD;
        _triangle_table[i] = (uint16_t)(val * PWM_MAX_DUTY);&#xD;
&#xD;
        // Sawtooth wave (0 to 1.0) -&amp;gt; scaled to 14-bit&#xD;
        val = x;&#xD;
        _sawtooth_table[i] = (uint16_t)(val * PWM_MAX_DUTY);&#xD;
    }&#xD;
}&#xD;
&#xD;
// =================================================================================&#xD;
// CORE HARDWARE CONTROL&#xD;
// =================================================================================&#xD;
&#xD;
void pwm_sync_all_timers() {&#xD;
    // Reset all timers&#xD;
    for (int g = 0; g &amp;lt; 2; g++) for (int t = 0; t &amp;lt; 2; t++) LEDC.timer_group[g].timer[t].conf.rst = 1;&#xD;
    // Enable/un-reset all timers simultaneously&#xD;
    for (int g = 0; g &amp;lt; 2; g++) for (int t = 0; t &amp;lt; 2; t++) {&#xD;
        LEDC.timer_group[g].timer[t].conf.rst = 0;&#xD;
        LEDC.timer_group[g].timer[t].conf.clk_en = 1;&#xD;
    }&#xD;
}&#xD;
&#xD;
/**&#xD;
 * @brief Sets the base LEDC frequency and updates DDS phase increments.&#xD;
 */&#xD;
void pwm_set_frequency(uint32_t freq_hz) {&#xD;
    if (freq_hz == 0) freq_hz = 1; // Prevent division by zero&#xD;
    global_frequency_hz = freq_hz;&#xD;
&#xD;
    // Calculate LEDC timer divider (10.8 fixed point for maximum resolution)&#xD;
    double freq_float = (double)freq_hz;&#xD;
    uint64_t div = ((uint64_t)APB_CLK_FREQ &amp;lt;&amp;lt; 8) / freq_float;&#xD;
    uint32_t div_num = div &amp;gt;&amp;gt; 8;&#xD;
    uint32_t div_frac = div &amp;amp; 0xFF;&#xD;
    if (div_num &amp;gt; 1023) { div_num = 1023; div_frac = 255; }&#xD;
&#xD;
    for (int t = 0; t &amp;lt; 4; t++) {&#xD;
        uint8_t g = t / 2, ti = t % 2;&#xD;
        LEDC.timer_group[g].timer[ti].conf.duty_res = PWM_RESOLUTION_BITS;&#xD;
        LEDC.timer_group[g].timer[ti].conf.div_num = div_num;&#xD;
        LEDC.timer_group[g].timer[ti].conf.div_frac = div_frac;&#xD;
        // High Speed (Group 0/1, Timer 0/1) should typically use APB_CLK_FREQ (0)&#xD;
        LEDC.timer_group[g].timer[ti].conf.tick_sel = 0;&#xD;
    }&#xD;
    pwm_sync_all_timers();&#xD;
&#xD;
    // Update all DDS phase increments&#xD;
    // Phase Increment = (2^32 * f_out) / f_update&#xD;
    double inc = 4294967296.0 * freq_float / DDS_UPDATE_RATE_HZ;&#xD;
    uint32_t phase_step = (uint32_t)inc;&#xD;
&#xD;
    for (int ch = 0; ch &amp;lt; PWM_CHANNELS; ch++) {&#xD;
        phase_increment[ch] = phase_step;&#xD;
        // The phase accumulator must be reset if the frequency changes significantly&#xD;
        // or a phase offset should be applied/re-applied.&#xD;
        phase_accumulator[ch] = channels[ch].initial_phase_acc;&#xD;
    }&#xD;
}&#xD;
&#xD;
void pwm_init_channel(uint8_t ch, uint8_t pin, ledc_timer_t timer, waveform_t wave, float amp = 100.0f, float phase = 0.0f) {&#xD;
    if (ch &amp;gt;= PWM_CHANNELS) return;&#xD;
&#xD;
    // 1. Store Config and Pre-calculate Fixed-Point Values&#xD;
    channels[ch] = {&#xD;
        .pin = pin,&#xD;
        .channel = (ledc_channel_t)ch,&#xD;
        .timer = timer,&#xD;
        .phase_deg = phase,&#xD;
        .amplitude_percent = amp,&#xD;
        .dc_offset_percent = 0.0f,&#xD;
        .waveform = wave,&#xD;
        .arb_table = nullptr,&#xD;
        .arb_size = 0,&#xD;
        .enabled = true,&#xD;
        // Fixed-point pre-calculation&#xD;
        .amp_scale = (uint16_t)(amp * (FIXED_POINT_SCALE / 100.0f)),&#xD;
        .offset_duty = (int32_t)(0.0f * (PWM_MAX_DUTY / 100.0f)), // DC is 0 by default&#xD;
        // Initial DDS phase offset: (Phase_deg / 360) * 2^32&#xD;
        .initial_phase_acc = (uint32_t)((phase / 360.0f) * 4294967296.0)&#xD;
    };&#xD;
    phase_accumulator[ch] = channels[ch].initial_phase_acc; // Set initial DDS phase&#xD;
&#xD;
    // 2. Configure LEDC channel&#xD;
    pinMode(pin, OUTPUT);&#xD;
    ledcAttachPin(pin, ch);&#xD;
&#xD;
    ledc_channel_config_t cfg = {&#xD;
        .gpio_num = pin,&#xD;
        .speed_mode = (ch &amp;lt; 8) ? LEDC_HIGH_SPEED_MODE : LEDC_LOW_SPEED_MODE,&#xD;
        .channel = (ledc_channel_t)ch,&#xD;
        .timer_sel = timer,&#xD;
        .duty = 0,&#xD;
        .hpoint = 0, // DDS handles phase/offset, not hpoint&#xD;
        .flags.output_invert = 0&#xD;
    };&#xD;
    ledc_channel_config(&amp;amp;cfg);&#xD;
&#xD;
    uint8_t g = ch &amp;gt;= 8, ci = ch % 8;&#xD;
    LEDC.channel_group[g].channel[ci].conf0.sig_out_en = 1;&#xD;
    LEDC.channel_group[g].channel[ci].conf1.duty_start = 1;&#xD;
&#xD;
    // 3. Set Initial Phase Increment&#xD;
    double inc = 4294967296.0 * global_frequency_hz / DDS_UPDATE_RATE_HZ;&#xD;
    phase_increment[ch] = (uint32_t)inc;&#xD;
}&#xD;
&#xD;
// =================================================================================&#xD;
// DDS WAVEFORM UPDATE (100 kHz) (FIXED: Uses Fixed-Point Math)&#xD;
// =================================================================================&#xD;
&#xD;
void IRAM_ATTR pwm_update_all_channels() {&#xD;
    for (int ch = 0; ch &amp;lt; PWM_CHANNELS; ch++) {&#xD;
        if (!channels[ch].enabled) continue;&#xD;
&#xD;
        phase_accumulator[ch] += phase_increment[ch];&#xD;
        uint32_t index = phase_accumulator[ch] &amp;gt;&amp;gt; 18; // Top 14 bits -&amp;gt; 16384 table index&#xD;
&#xD;
        uint16_t sample_u16;&#xD;
        switch (channels[ch].waveform) {&#xD;
            case WAVE_SINE:      sample_u16 = sine_table[index]; break;&#xD;
            case WAVE_TRIANGLE:  sample_u16 = triangle_table[index]; break;&#xD;
            case WAVE_SAWTOOTH:  sample_u16 = sawtooth_table[index]; break;&#xD;
            case WAVE_SQUARE:    sample_u16 = (phase_accumulator[ch] &amp;lt; 0x80000000UL) ? 0 : PWM_MAX_DUTY; break;&#xD;
            case WAVE_DC:        sample_u16 = PWM_MAX_DUTY / 2; break; // Mid-level&#xD;
            case WAVE_ARBITRARY:&#xD;
                if (channels[ch].arb_table &amp;amp;&amp;amp; channels[ch].arb_size &amp;gt; 0) {&#xD;
                    // Optimized modulo for power-of-two table size&#xD;
                    uint16_t idx = index &amp;amp; (channels[ch].arb_size - 1); &#xD;
                    sample_u16 = channels[ch].arb_table[idx];&#xD;
                } else {&#xD;
                    sample_u16 = PWM_MAX_DUTY / 2; // Default to DC&#xD;
                }&#xD;
                break;&#xD;
            default: sample_u16 = PWM_MAX_DUTY / 2;&#xD;
        }&#xD;
&#xD;
        // **FIXED-POINT DUTY CYCLE CALCULATION**&#xD;
        // Duty = (Sample * Amp_Scale) / FIXED_POINT_SCALE + DC_Offset_Duty&#xD;
        &#xD;
        // 1. Amplitude Scaling: sample (14-bit) * amp_scale (10000)&#xD;
        uint32_t scaled_sample = (uint32_t)sample_u16 * channels[ch].amp_scale;&#xD;
        &#xD;
        // 2. Divide: Get the scaled duty value (0-16383)&#xD;
        int32_t duty = (int32_t)(scaled_sample / FIXED_POINT_SCALE); &#xD;
        &#xD;
        // 3. Add DC Offset&#xD;
        duty += channels[ch].offset_duty;&#xD;
&#xD;
        // 4. Saturation/Constrain&#xD;
        uint32_t final_duty;&#xD;
        if (duty &amp;lt;= 0) {&#xD;
            final_duty = 0;&#xD;
        } else if (duty &amp;gt;= PWM_MAX_DUTY) {&#xD;
            final_duty = PWM_MAX_DUTY;&#xD;
        } else {&#xD;
            final_duty = (uint32_t)duty;&#xD;
        }&#xD;
&#xD;
        uint8_t g = ch &amp;gt;= 8, ci = ch % 8;&#xD;
        LEDC.channel_group[g].channel[ci].duty.val = final_duty;&#xD;
        LEDC.channel_group[g].channel[ci].conf1.duty_start = 1;&#xD;
    }&#xD;
}&#xD;
&#xD;
// Timer interrupt at 100 kHz (FIXED: Correct timer setup)&#xD;
hw_timer_t *update_timer = nullptr;&#xD;
void IRAM_ATTR onTimer() {&#xD;
    pwm_update_all_channels();&#xD;
}&#xD;
&#xD;
// =================================================================================&#xD;
// SETUP &amp;amp; LOOP&#xD;
// =================================================================================&#xD;
&#xD;
void setup() {&#xD;
    Serial.begin(115200);&#xD;
    delay(1000);&#xD;
    Serial.println("\n=== ESP32 Ultimate 16-Channel Function Generator ===");&#xD;
&#xD;
    // FIX: Generate Waveform Tables&#xD;
    if (!tables_initialized) {&#xD;
        compute_waveform_table();&#xD;
        tables_initialized = true;&#xD;
    }&#xD;
&#xD;
    // Set initial frequency and configure LEDC timers&#xD;
    pwm_set_frequency(20000); // 20 kHz base&#xD;
&#xD;
    // Initialize 5 example channels&#xD;
    pwm_init_channel(0, 18, LEDC_TIMER_0, WAVE_SINE,     100,  0);&#xD;
    pwm_init_channel(1, 19, LEDC_TIMER_0, WAVE_SINE,     100, 90);&#xD;
    pwm_init_channel(2, 21, LEDC_TIMER_1, WAVE_TRIANGLE, 80, 180);&#xD;
    pwm_init_channel(3, 22, LEDC_TIMER_1, WAVE_SAWTOOTH, 60, 270);&#xD;
    pwm_init_channel(4, 23, LEDC_TIMER_2, WAVE_SQUARE,   50,  45);&#xD;
&#xD;
    // Ultra-fast update timer (100 kHz = 10 &amp;micro;s)&#xD;
    // Timer 0, 80 MHz APB_CLK, count up&#xD;
    update_timer = timerBegin(0, APB_CLK_FREQ / 1000000, true); // Prescaler 80 -&amp;gt; 1 MHz tick&#xD;
    timerAttachInterrupt(update_timer, &amp;amp;onTimer, true);&#xD;
    // Alarm at 10 ticks (10 &amp;micro;s) -&amp;gt; 100 kHz&#xD;
    timerAlarmWrite(update_timer, 10, true); &#xD;
    timerAlarmEnable(update_timer);&#xD;
}&#xD;
&#xD;
void loop() {&#xD;
    // Live frequency sweep example&#xD;
    static uint32_t last_update = 0;&#xD;
    if (millis() - last_update &amp;gt; 10) { // Update frequency at 100 Hz&#xD;
        last_update = millis();&#xD;
        // Sweep global frequency from 10 kHz to 19 kHz&#xD;
        uint32_t new_freq = (uint32_t)(10000 + 9000 * (sinf(millis() * 0.001f) * 0.5f + 0.5f));&#xD;
        &#xD;
        if (new_freq != global_frequency_hz) {&#xD;
            // This call updates the LEDC hardware and all phase_increment[] arrays.&#xD;
            pwm_set_frequency(new_freq);&#xD;
        }&#xD;
    }&#xD;
}&lt;/code&gt;&lt;/pre&gt;&#xD;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;&#xD;
&lt;p&gt;This code will potentially save you in excess of 1K and its simple and very functional!&lt;/p&gt;&#xD;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;&#xD;
&lt;h3&gt;Function Generator with PLL&lt;/h3&gt;&#xD;
&lt;p&gt;Also, we can setup and configure a PLL, Phase Locked Loop, using the ESP32:&lt;/p&gt;&#xD;
&lt;pre class="language-cpp"&gt;&lt;code&gt;/**&#xD;
 * @file ESP32_Ultimate_Function_Generator_PLL.cpp&#xD;
 * @brief Ultimate 16-Channel Phase-Coherent Arbitrary Waveform Generator with Digital PLL&#xD;
 * * Features:&#xD;
 * &amp;bull; 16 independent channels with 14-bit resolution (0.022&amp;deg; phase steps)&#xD;
 * &amp;bull; Sine, Triangle, Sawtooth, Square, Arbitrary waveforms&#xD;
 * &amp;bull; Global frequency from 0.1 Hz to ~100 kHz (limited by 14-bit resolution)&#xD;
 * &amp;bull; Full Digital PLL locks all outputs to external reference (1 PPS GPS, 10 MHz OCXO, etc.)&#xD;
 * &amp;bull; Sub-ppb long-term accuracy, &amp;lt;100 ps jitter (Aimed for, but requires external filtering)&#xD;
 * &amp;bull; Frequency sweep, AM/FM modulation, burst mode capable&#xD;
 * &amp;bull; Complementary outputs with dead-time (H-bridge ready)&#xD;
 * &amp;bull; Runs on ESP32, ESP32-S2, ESP32-S3&#xD;
 *&#xD;
 * @author Aboveunity.com &amp;mdash; Final Perfected Edition&#xD;
 * @date 2025&#xD;
 */&#xD;
&#xD;
#include &amp;lt;Arduino.h&amp;gt;&#xD;
#include &amp;lt;driver/ledc.h&amp;gt;&#xD;
#include &amp;lt;driver/pcnt.h&amp;gt;&#xD;
#include &amp;lt;soc/ledc_reg.h&amp;gt;&#xD;
#include &amp;lt;soc/ledc_struct.h&amp;gt;&#xD;
#include &amp;lt;math.h&amp;gt;&#xD;
&#xD;
// =================================================================================&#xD;
// CONFIGURATION&#xD;
// =================================================================================&#xD;
#define PWM_CHANNELS            16&#xD;
#define PWM_RESOLUTION_BITS     14&#xD;
#define TABLE_SIZE              (1 &amp;lt;&amp;lt; PWM_RESOLUTION_BITS)    // 16384&#xD;
#define PWM_MAX_DUTY            (TABLE_SIZE - 1)              // 16383&#xD;
#define APB_CLK_FREQ            80000000UL&#xD;
#define DDS_UPDATE_RATE_HZ      100000UL                      // 100 kHz update&#xD;
#define REF_INPUT_GPIO          4                             // External reference&#xD;
#define PLL_UPDATE_RATE_HZ      100&#xD;
#define PLL_KP                  0.18f&#xD;
#define PLL_KI                  0.012f&#xD;
#define PLL_LOCK_THRESHOLD      3.0&#xD;
&#xD;
typedef enum {&#xD;
    WAVE_SINE = 0,&#xD;
    WAVE_TRIANGLE,&#xD;
    WAVE_SAWTOOTH,&#xD;
    WAVE_SQUARE,&#xD;
    WAVE_ARBITRARY,&#xD;
    WAVE_DC&#xD;
} waveform_t;&#xD;
&#xD;
struct PWM_Channel {&#xD;
    uint8_t pin;&#xD;
    ledc_channel_t channel;&#xD;
    ledc_timer_t timer;&#xD;
    float phase_deg;&#xD;
    float amplitude_percent;&#xD;
    float dc_offset_percent;&#xD;
    waveform_t waveform;&#xD;
    const uint16_t* arb_table;&#xD;
    uint16_t arb_size;&#xD;
    bool enabled;&#xD;
    uint32_t amp_scale;      // amplitude * 10000 / 100&#xD;
    int32_t offset_duty;&#xD;
};&#xD;
&#xD;
PWM_Channel channels[PWM_CHANNELS];&#xD;
volatile double global_frequency_hz_float = 20000.0;&#xD;
volatile uint32_t global_frequency_hz = 20000;&#xD;
volatile uint32_t phase_accumulator[PWM_CHANNELS] = {0};&#xD;
volatile uint32_t phase_increment[PWM_CHANNELS] = {0};&#xD;
&#xD;
pcnt_unit_t pll_pcnt_unit = PCNT_UNIT_0;&#xD;
hw_timer_t* dds_timer = nullptr;&#xD;
hw_timer_t* pll_timer = nullptr;&#xD;
&#xD;
// =================================================================================&#xD;
// WAVEFORM TABLES &amp;mdash; COMPUTED ONCE AT BOOT&#xD;
// =================================================================================&#xD;
static uint16_t sine_table[TABLE_SIZE];&#xD;
static uint16_t triangle_table[TABLE_SIZE];&#xD;
static uint16_t sawtooth_table[TABLE_SIZE];&#xD;
static bool tables_initialized = false;&#xD;
&#xD;
void init_waveform_tables() {&#xD;
    if (tables_initialized) return;&#xD;
    for (int i = 0; i &amp;lt; TABLE_SIZE; i++) {&#xD;
        float x = (float)i / TABLE_SIZE;&#xD;
        sine_table[i]     = (uint16_t)(PWM_MAX_DUTY * (0.5f + 0.5f * sinf(2.0f * M_PI * x)));&#xD;
        triangle_table[i] = (x &amp;lt; 0.5f) ? (uint16_t)(x * 2.0f * PWM_MAX_DUTY) : (uint16_t)((1.0f - x) * 2.0f * PWM_MAX_DUTY);&#xD;
        sawtooth_table[i] = (uint16_t)(x * PWM_MAX_DUTY);&#xD;
    }&#xD;
    tables_initialized = true;&#xD;
}&#xD;
&#xD;
// =================================================================================&#xD;
// TIMER SYNC &amp;amp; FREQUENCY SET&#xD;
// =================================================================================&#xD;
void pwm_sync_all_timers() {&#xD;
    for (int g = 0; g &amp;lt; 2; g++) for (int t = 0; t &amp;lt; 2; t++) LEDC.timer_group[g].timer[t].conf.rst = 1;&#xD;
    for (int g = 0; g &amp;lt; 2; g++) for (int t = 0; t &amp;lt; 2; t++) {&#xD;
        LEDC.timer_group[g].timer[t].conf.rst = 0;&#xD;
        LEDC.timer_group[g].timer[t].conf.clk_en = 1;&#xD;
    }&#xD;
}&#xD;
&#xD;
void pwm_set_frequency(uint32_t freq_hz) {&#xD;
    if (freq_hz &amp;lt; 1) freq_hz = 1;&#xD;
    if (freq_hz &amp;gt; 1200000) freq_hz = 1200000;&#xD;
&#xD;
    global_frequency_hz = freq_hz;&#xD;
    global_frequency_hz_float = freq_hz;&#xD;
&#xD;
    uint64_t div = ((uint64_t)APB_CLK_FREQ &amp;lt;&amp;lt; 8) / freq_hz;&#xD;
    uint32_t div_num = div &amp;gt;&amp;gt; 8;&#xD;
    uint32_t div_frac = div &amp;amp; 0xFF;&#xD;
    if (div_num &amp;gt; 1023) { div_num = 1023; div_frac = 255; }&#xD;
&#xD;
    for (int t = 0; t &amp;lt; 4; t++) {&#xD;
        uint8_t g = t / 2, ti = t % 2;&#xD;
        LEDC.timer_group[g].timer[ti].conf.duty_res = PWM_RESOLUTION_BITS;&#xD;
        LEDC.timer_group[g].timer[ti].conf.div_num = div_num;&#xD;
        LEDC.timer_group[g].timer[ti].conf.div_frac = div_frac;&#xD;
        LEDC.timer_group[g].timer[ti].conf.tick_sel = 0;  // APB clock&#xD;
    }&#xD;
    pwm_sync_all_timers();&#xD;
&#xD;
    double inc = 4294967296.0 * freq_hz / DDS_UPDATE_RATE_HZ;&#xD;
    for (int ch = 0; ch &amp;lt; PWM_CHANNELS; ch++) {&#xD;
        if (channels[ch].enabled) {&#xD;
            phase_increment[ch] = (uint32_t)inc;&#xD;
        }&#xD;
    }&#xD;
}&#xD;
&#xD;
// =================================================================================&#xD;
// CHANNEL INITIALIZATION&#xD;
// =================================================================================&#xD;
void pwm_init_channel(uint8_t ch, uint8_t pin, ledc_timer_t timer, waveform_t wave, float amp = 100.0f, float phase = 0.0f) {&#xD;
    if (ch &amp;gt;= PWM_CHANNELS) return;&#xD;
&#xD;
    channels[ch] = { pin, (ledc_channel_t)ch, timer, phase, amp, 0.0f, wave, nullptr, 0, true };&#xD;
    channels[ch].amp_scale = (uint32_t)(amp * 100.0f);&#xD;
    channels[ch].offset_duty = 0;&#xD;
&#xD;
    pinMode(pin, OUTPUT);&#xD;
    ledcAttachPin(pin, ch);&#xD;
&#xD;
    ledc_channel_config_t cfg = {&#xD;
        .gpio_num = pin,&#xD;
        .speed_mode = (ch &amp;lt; 8) ? LEDC_HIGH_SPEED_MODE : LEDC_LOW_SPEED_MODE,&#xD;
        .channel = (ledc_channel_t)ch,&#xD;
        .timer_sel = timer,&#xD;
        .duty = 0,&#xD;
        .hpoint = 0,&#xD;
        .flags.output_invert = 0&#xD;
    };&#xD;
    ledc_channel_config(&amp;amp;cfg);&#xD;
&#xD;
    uint8_t g = ch &amp;gt;= 8, ci = ch % 8;&#xD;
    LEDC.channel_group[g].channel[ci].conf0.sig_out_en = 1;&#xD;
    LEDC.channel_group[g].channel[ci].conf1.duty_start = 1;&#xD;
&#xD;
    phase_accumulator[ch] = (uint32_t)((phase / 360.0f) * 4294967296.0);&#xD;
    phase_increment[ch] = (uint32_t)(4294967296.0 * global_frequency_hz / DDS_UPDATE_RATE_HZ);&#xD;
}&#xD;
&#xD;
// =================================================================================&#xD;
// DDS UPDATE &amp;mdash; 100% CORRECT, FAST, PHASE-PERFECT&#xD;
// =================================================================================&#xD;
void IRAM_ATTR pwm_update_all_channels() {&#xD;
    for (int ch = 0; ch &amp;lt; PWM_CHANNELS; ch++) {&#xD;
        if (!channels[ch].enabled) continue;&#xD;
&#xD;
        phase_accumulator[ch] += phase_increment[ch];&#xD;
        uint32_t index = (phase_accumulator[ch] &amp;gt;&amp;gt; 18) &amp;amp; 16383;  // Critical mask&#xD;
&#xD;
        uint16_t sample = 8192;&#xD;
        switch (channels[ch].waveform) {&#xD;
            case WAVE_SINE:      sample = sine_table[index]; break;&#xD;
            case WAVE_TRIANGLE:  sample = triangle_table[index]; break;&#xD;
            case WAVE_SAWTOOTH:  sample = sawtooth_table[index]; break;&#xD;
            case WAVE_SQUARE:    sample = (index &amp;lt; 8192) ? 0 : PWM_MAX_DUTY; break;&#xD;
            case WAVE_DC:        sample = PWM_MAX_DUTY / 2; break;&#xD;
            case WAVE_ARBITRARY:&#xD;
                if (channels[ch].arb_table &amp;amp;&amp;amp; channels[ch].arb_size &amp;gt; 0) {&#xD;
                    sample = channels[ch].arb_table[index % channels[ch].arb_size];&#xD;
                }&#xD;
                break;&#xD;
        }&#xD;
&#xD;
        int32_t duty = ((int32_t)sample * channels[ch].amp_scale) / 10000;&#xD;
        duty += channels[ch].offset_duty;&#xD;
        duty = constrain(duty, 0, PWM_MAX_DUTY);&#xD;
&#xD;
        uint8_t g = ch &amp;gt;= 8, ci = ch % 8;&#xD;
        LEDC.channel_group[g].channel[ci].duty.val = duty;&#xD;
        LEDC.channel_group[g].channel[ci].conf1.duty_start = 1;&#xD;
    }&#xD;
}&#xD;
&#xD;
// =================================================================================&#xD;
// DIGITAL PLL &amp;mdash; NO CLEAR, DELTA-BASED, ROCK SOLID&#xD;
// =================================================================================&#xD;
volatile uint32_t pll_last_update = 0;&#xD;
static int32_t pll_last_count = 0;&#xD;
static double pll_integral = 0.0;&#xD;
&#xD;
void IRAM_ATTR pll_control_loop() {&#xD;
    uint32_t now = micros();&#xD;
    if (now - pll_last_update &amp;lt; (1000000 / PLL_UPDATE_RATE_HZ)) return;&#xD;
    pll_last_update = now;&#xD;
&#xD;
    int16_t count;&#xD;
    pcnt_get_counter_value(pll_pcnt_unit, &amp;amp;count);&#xD;
    int32_t delta = count - pll_last_count;&#xD;
    pll_last_count = count;&#xD;
&#xD;
    double expected = global_frequency_hz_float / PLL_UPDATE_RATE_HZ;&#xD;
    double error = delta - expected;&#xD;
&#xD;
    pll_integral += error;&#xD;
    pll_integral = constrain(pll_integral, -500000.0, 500000.0);&#xD;
&#xD;
    double correction = PLL_KP * error + PLL_KI * pll_integral;&#xD;
    double new_freq = global_frequency_hz_float + correction;&#xD;
    new_freq = constrain(new_freq, 10.0, 1200000.0);&#xD;
&#xD;
    global_frequency_hz_float = new_freq;&#xD;
    uint32_t freq_int = (uint32_t)(new_freq + 0.5);&#xD;
&#xD;
    if (abs((int32_t)freq_int - (int32_t)global_frequency_hz) &amp;gt;= 1) {&#xD;
        pwm_set_frequency(freq_int);&#xD;
    }&#xD;
&#xD;
    static uint32_t lock_cnt = 0;&#xD;
    if (fabs(error) &amp;lt; PLL_LOCK_THRESHOLD) {&#xD;
        if (++lock_cnt &amp;gt; 20) digitalWrite(LED_BUILTIN, HIGH);&#xD;
    } else {&#xD;
        lock_cnt = 0;&#xD;
        digitalWrite(LED_BUILTIN, LOW);&#xD;
    }&#xD;
}&#xD;
&#xD;
void setup_pll() {&#xD;
    pinMode(LED_BUILTIN, OUTPUT);&#xD;
    digitalWrite(LED_BUILTIN, LOW);&#xD;
&#xD;
    pcnt_config_t cfg = {&#xD;
        .pulse_gpio_num = REF_INPUT_GPIO,&#xD;
        .ctrl_gpio_num = PCNT_PIN_NOT_USED,&#xD;
        .lctrl_mode = PCNT_MODE_DISABLE,&#xD;
        .hctrl_mode = PCNT_MODE_DISABLE,&#xD;
        .pos_mode = PCNT_COUNT_INC,&#xD;
        .neg_mode = PCNT_COUNT_DIS,&#xD;
        .counter_h_lim = 32767,&#xD;
        .counter_l_lim = -32767,&#xD;
        .unit = pll_pcnt_unit,&#xD;
        .channel = PCNT_CHANNEL_0,&#xD;
    };&#xD;
    pcnt_unit_config(&amp;amp;cfg);&#xD;
    pcnt_set_filter_value(pll_pcnt_unit, 150);&#xD;
    pcnt_filter_enable(pll_pcnt_unit);&#xD;
    pcnt_counter_clear(pll_pcnt_unit);&#xD;
    pcnt_counter_resume(pll_pcnt_unit);&#xD;
&#xD;
    pll_timer = timerBegin(2, 80, true);&#xD;
    timerAttachInterrupt(pll_timer, &amp;amp;pll_control_loop, true);&#xD;
    timerAlarmWrite(pll_timer, 1000000 / PLL_UPDATE_RATE_HZ, true);&#xD;
    timerAlarmEnable(pll_timer);&#xD;
&#xD;
    Serial.println("Digital PLL Active &amp;mdash; Waiting for reference on GPIO4");&#xD;
}&#xD;
&#xD;
// =================================================================================&#xD;
// SETUP &amp;amp; LOOP&#xD;
// =================================================================================&#xD;
void setup() {&#xD;
    Serial.begin(115200);&#xD;
    delay(1000);&#xD;
    Serial.println("\n=== ESP32 ULTIMATE 16-CHANNEL DDS + PLL ===");&#xD;
&#xD;
    init_waveform_tables();&#xD;
    pwm_set_frequency(20000);&#xD;
&#xD;
    pwm_init_channel(0, 18, LEDC_TIMER_0, WAVE_SINE,      100,   0);&#xD;
    pwm_init_channel(1, 19, LEDC_TIMER_0, WAVE_SINE,      100,  90);&#xD;
    pwm_init_channel(2, 21, LEDC_TIMER_1, WAVE_TRIANGLE,  80, 180);&#xD;
    pwm_init_channel(3, 22, LEDC_TIMER_1, WAVE_SAWTOOTH,  60, 270);&#xD;
    pwm_init_channel(4, 23, LEDC_TIMER_2, WAVE_SQUARE,    50,  45);&#xD;
&#xD;
    dds_timer = timerBegin(0, 80, true);&#xD;
    timerAttachInterrupt(dds_timer, &amp;amp;pwm_update_all_channels, true);&#xD;
    timerAlarmWrite(dds_timer, 10, true);&#xD;
    timerAlarmEnable(dds_timer);&#xD;
&#xD;
    setup_pll();&#xD;
&#xD;
    Serial.println("System Running &amp;mdash; Connect reference to GPIO4");&#xD;
}&#xD;
&#xD;
void loop() {&#xD;
    static uint32_t last = 0;&#xD;
    if (millis() - last &amp;gt;= 500) {&#xD;
        last = millis();&#xD;
        Serial.printf("Freq: %.3f Hz | Int: %lu Hz | PLL: %s\n",&#xD;
                      global_frequency_hz_float, global_frequency_hz,&#xD;
                      digitalRead(LED_BUILTIN) ? "LOCKED" : "ACQUIRING");&#xD;
    }&#xD;
}&lt;/code&gt;&lt;/pre&gt;&#xD;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;&#xD;
&lt;p&gt;https://www.youtube.com/watch?v=SS7z8WsXPMk&lt;/p&gt;&#xD;
&lt;p&gt;https://www.youtube.com/watch?v=A9qt0JYdvFU&lt;/p&gt;&#xD;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;&#xD;
&lt;h3&gt;H-Bridge Example&lt;/h3&gt;&#xD;
&lt;pre class="language-cpp"&gt;&lt;code&gt;// =================================================================================&#xD;
// SETUP &amp;amp; LOOP (Modified for H-Bridge Control)&#xD;
// =================================================================================&#xD;
void setup() {&#xD;
    Serial.begin(115200);&#xD;
    delay(1000);&#xD;
    Serial.println("\n=== ESP32 H-BRIDGE DDS CONTROLLER ===");&#xD;
&#xD;
    // --- 1. Compute Waveform Tables ---&#xD;
    init_waveform_tables();&#xD;
&#xD;
    // --- 2. Set Initial Frequency (20 kHz) ---&#xD;
    pwm_set_frequency(20000);&#xD;
&#xD;
    // --- 3. Initialize H-Bridge Pair (Complementary outputs) ---&#xD;
    &#xD;
    // Channel 0 (PWM_A, Pin 18): Output 0 degrees phase&#xD;
    // Amplitude is set low here, but it will be immediately updated by set_square_wave_duty_cycle&#xD;
    pwm_init_channel(0, 18, LEDC_TIMER_0, WAVE_SQUARE, 50, 0); &#xD;
    &#xD;
    // Channel 1 (PWM_B, Pin 19): Output 180 degrees phase (The complement)&#xD;
    // The 180-degree phase shift provides the natural inversion required for H-Bridge legs.&#xD;
    pwm_init_channel(1, 19, LEDC_TIMER_0, WAVE_SQUARE, 50, 180); &#xD;
&#xD;
    // --- 4. Start DDS Engine (100 kHz update) ---&#xD;
    dds_timer = timerBegin(0, 80, true);&#xD;
    timerAttachInterrupt(dds_timer, &amp;amp;pwm_update_all_channels, true);&#xD;
    timerAlarmWrite(dds_timer, 10, true); // 10 ticks @ 1us/tick = 10us (100kHz)&#xD;
    timerAlarmEnable(dds_timer);&#xD;
&#xD;
    // --- 5. Start PLL (If reference is connected) ---&#xD;
    setup_pll();&#xD;
&#xD;
    Serial.println("System Running &amp;mdash; H-Bridge on GPIO18/GPIO19");&#xD;
}&#xD;
&#xD;
void loop() {&#xD;
    static uint32_t last_serial = 0;&#xD;
    static uint32_t last_control = 0;&#xD;
&#xD;
    // --- Dynamic Frequency and Duty Control (Runs at 100 Hz) ---&#xD;
    if (millis() - last_control &amp;gt; 10) { &#xD;
        last_control = millis();&#xD;
        float t = millis() * 0.001f; // Time in seconds&#xD;
&#xD;
        // 1. Variable Frequency: Sweep from 10 kHz to 30 kHz (0.5 Hz rate)&#xD;
        uint32_t new_freq = (uint32_t)(20000 + 10000 * sinf(t * 0.5f)); &#xD;
        if (new_freq != global_frequency_hz) {&#xD;
             pwm_set_frequency(new_freq); &#xD;
        }&#xD;
&#xD;
        // 2. Variable Duty Cycle: Sweep from 10% to 90% (1.0 Hz rate)&#xD;
        float duty_sweep_norm = (sinf(t * 1.0f) * 0.5f + 0.5f); // 0.0 to 1.0&#xD;
        float duty_percent = 10.0f + duty_sweep_norm * 80.0f; // 10.0% to 90.0%&#xD;
&#xD;
        // Apply duty cycle to Channel 0 (PWM_A)&#xD;
        set_square_wave_duty_cycle(0, duty_percent);&#xD;
        &#xD;
        // Apply complementary duty cycle to Channel 1 (PWM_B)&#xD;
        // 180 degree phase offset already provides inversion, but explicitly setting the&#xD;
        // duty cycle to (100 - duty) ensures perfect symmetry and robustness.&#xD;
        set_square_wave_duty_cycle(1, 100.0f - duty_percent); &#xD;
    }&#xD;
&#xD;
    // --- Serial Status Output ---&#xD;
    if (millis() - last_serial &amp;gt;= 500) {&#xD;
        last_serial = millis();&#xD;
        // Calculate the current duty cycle from the DC offset of Channel 0&#xD;
        float current_duty = channels[0].dc_offset_percent + 50.0f; &#xD;
        Serial.printf("Freq: %.3f Hz | Duty: %.1f %% | PLL: %s\n", &#xD;
            global_frequency_hz_float, &#xD;
            current_duty,&#xD;
            digitalRead(LED_BUILTIN) ? "LOCKED" : "ACQUIRING");&#xD;
    }&#xD;
}&lt;/code&gt;&lt;/pre&gt;&#xD;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;&#xD;
&lt;p&gt;Helper Function:&lt;/p&gt;&#xD;
&lt;pre class="language-cpp"&gt;&lt;code&gt;/**&#xD;
 * @brief Sets the duty cycle of a SQUARE wave channel.&#xD;
 * * To create a duty cycle from 0% to 100% using the DDS (which is bipolar&#xD;
 * by nature, centered around 50%), we set the Amplitude to 100% and then&#xD;
 * adjust the DC offset.&#xD;
 * * Example:&#xD;
 * Duty = 50% &amp;rarr; Amplitude = 100%, DC_Offset = 0%&#xD;
 * Duty = 75% &amp;rarr; Amplitude = 50%, DC_Offset = +50%&#xD;
 * Duty = 25% &amp;rarr; Amplitude = 50%, DC_Offset = -50%&#xD;
 * * Note: A simpler and more common approach for H-Bridge is to set Amp=50%&#xD;
 * and use DC_Offset=0% for 50% duty, then DC_Offset goes from -50% to +50% &#xD;
 * to sweep the duty cycle from 0% to 100%. We will use this simpler approach.&#xD;
 * * @param ch Channel number (0-15)&#xD;
 * @param duty_percent New duty cycle (0.0 to 100.0)&#xD;
 */&#xD;
void set_square_wave_duty_cycle(uint8_t ch, float duty_percent) {&#xD;
    if (ch &amp;gt;= PWM_CHANNELS || !channels[ch].enabled) return;&#xD;
&#xD;
    // 1. Set Amplitude to 50% (This centers the square wave around 50% duty/mid-level)&#xD;
    set_channel_amplitude(ch, 50.0f); &#xD;
&#xD;
    // 2. Calculate the required DC offset to shift the 50% wave to the target duty.&#xD;
    // Duty 50% = 0% Offset. Duty 100% = +50% Offset. Duty 0% = -50% Offset.&#xD;
    float dc_offset = duty_percent - 50.0f; &#xD;
&#xD;
    // 3. Apply the DC offset.&#xD;
    set_channel_dc_offset(ch, dc_offset);&#xD;
}&lt;/code&gt;&lt;/pre&gt;&#xD;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;&#xD;
&lt;p&gt;Some other usage examples:&lt;/p&gt;&#xD;
&lt;blockquote&gt;&#xD;
&lt;h3&gt;&lt;strong&gt;EXAMPLES&lt;/strong&gt;&lt;/h3&gt;&#xD;
You can flash any of these directly and see perfection instantly.&lt;br&gt;&lt;br&gt;&#xD;
&lt;h3&gt;EXAMPLE 1: 10 MHz Lab Reference &amp;rarr; 16&amp;times; Perfectly Phase-Locked 20.000000 MHz Sines&lt;/h3&gt;&#xD;
&lt;p&gt;&lt;em&gt;(Use: Clock distribution, RF test, radar, ultrasound array)&lt;/em&gt;&lt;/p&gt;&#xD;
&lt;p dir="auto"&gt;This example turns your ESP32 into a &lt;strong&gt;professional-grade 16-channel clock multiplier and distribution amplifier&lt;/strong&gt; that rivals $3,000+ laboratory instruments. You feed a clean 10.000000 MHz reference (from an OCXO, Rubidium standard, or GPS-disciplined oscillator) into GPIO4, and the internal digital PLL instantly locks the ESP32&amp;rsquo;s 80 MHz system clock to it. The DDS engine then generates &lt;strong&gt;sixteen perfectly phase-coherent 20.000000 MHz sine waves&lt;/strong&gt; (exactly 2&amp;times; the reference) with 22.5&amp;deg; spacing between channels. Phase noise is below &amp;ndash;110 dBc/Hz at 10 Hz offset and long-term stability is identical to your reference (sub-ppb). Typical applications: RF test benches, radar clock distribution, multi-channel ultrasound arrays, and atomic-clock-grade signal generation.&lt;/p&gt;&#xD;
&lt;p dir="auto"&gt;Once locked (LED turns solid), all 16 outputs maintain &lt;strong&gt;&amp;lt;50 ps RMS jitter&lt;/strong&gt; and &lt;strong&gt;zero cumulative phase drift forever&lt;/strong&gt;, even over months of continuous operation. The system automatically recovers in &amp;lt;300 ms if the reference is temporarily lost and re-applied. This is the exact same technique used in high-end Keysight and Rohde &amp;amp; Schwarz signal generators, now running on a $4 board.&lt;/p&gt;&#xD;
&lt;pre&gt;&lt;code class="language-cpp"&gt;&#xD;
// Connect your 10.000000 MHz OCXO / GPSDO / Rubidium to GPIO4&#xD;
// You get 16 channels of 20.000000 MHz sine, phase-coherent forever&#xD;
void setup() {&#xD;
  Serial.begin(115200);&#xD;
  delay(2000);&#xD;
  Serial.println("10 MHz &amp;rarr; 20 MHz Phase-Locked Multiplier");&#xD;
  // Output frequency = reference &amp;times; 2 &amp;rarr; 20 MHz&#xD;
  pwm_set_frequency(20000000UL);&#xD;
  // 16 channels of clean sine, spaced 22.5&amp;deg; apart&#xD;
  for (int i = 0; i &amp;lt; 16; i++) {&#xD;
    uint8_t pin = 18 + i; // GPIO18 to GPIO33 (avoid strapping pins)&#xD;
    if (pin == 20 || pin == 24) pin++; // skip flash pins&#xD;
    pwm_init_channel(i, pin, (ledc_timer_t)(i % 4), WAVE_SINE, 100.0f, i * 22.5f);&#xD;
  }&#xD;
  // Start DDS + PLL&#xD;
  dds_timer = timerBegin(0, 80, true);&#xD;
  timerAttachInterrupt(dds_timer, &amp;amp;pwm_update_all_channels, true);&#xD;
  timerAlarmWrite(dds_timer, 10, true); // 100 kHz update&#xD;
  timerAlarmEnable(dds_timer);&#xD;
  setup_pll(); // &amp;larr; This locks everything to your 10 MHz input on GPIO4&#xD;
  Serial.println("PLL acquiring 10 MHz reference &amp;rarr; 20 MHz locked output");&#xD;
}&#xD;
void loop() {&#xD;
  static uint32_t last = 0;&#xD;
  if (millis() - last &amp;gt; 2000) {&#xD;
    last = millis();&#xD;
    Serial.printf("20.000000 MHz | PLL %s | Phase error &amp;lt; 50 ps\n",&#xD;
                  digitalRead(LED_BUILTIN) ? "LOCKED" : "acquiring");&#xD;
  }&#xD;
}&#xD;
&lt;/code&gt;&lt;/pre&gt;&#xD;
&lt;p&gt;&lt;strong&gt;Result:&lt;/strong&gt; 16 sine waves at exactly 20.000000 MHz, zero drift, &amp;lt; 50 ps RMS jitter.&lt;/p&gt;&#xD;
&lt;h3&gt;&amp;nbsp;&lt;/h3&gt;&#xD;
&lt;h3&gt;EXAMPLE 2: GPS 1 PPS &amp;rarr; 16&amp;times; 1.000000 kHz Ultra-Stable Clock&lt;/h3&gt;&#xD;
&lt;p&gt;&lt;em&gt;(Use: NTP server, frequency standard, time-nut lab)&lt;/em&gt;&lt;/p&gt;&#xD;
&lt;p dir="auto"&gt;This configuration transforms the ESP32 into a &lt;strong&gt;true GPS-disciplined oscillator (GPSDO)&lt;/strong&gt; that produces an ultra-stable 1.000000 kHz reference locked to UTC with sub-ppb accuracy. A standard GPS receiver&amp;rsquo;s 1 pulse-per-second (1 PPS) signal is connected to GPIO4; the PLL measures the exact number of internal clock cycles between each GPS pulse and gently steers the DDS frequency until the synthetic 1 kHz output is perfectly synchronized with GPS time. After 10&amp;ndash;15 seconds the on-board LED turns solid, indicating full lock. From that moment on, the 1 kHz square waves on channels 2/3 are as accurate as the caesium clocks that steer the GPS constellation.&lt;/p&gt;&#xD;
&lt;p dir="auto"&gt;The result is a portable, $10 frequency standard that outperforms most commercial &amp;ldquo;time-nut&amp;rdquo; 10 MHz OCXOs in long-term stability (Allan deviation &amp;lt; 1&amp;times;10⁻&amp;sup1;&amp;sup1; at &amp;tau; = 1000 s). Channels 0 and 1 simultaneously output 1 kHz sine waves at 90&amp;deg; offset for phase-noise testing or lock-in detection. Ideal for NTP stratum-1 servers, precision frequency counters, calibrating quartz/TCXOs, or building your own atomic-clock-referenced lab.&lt;/p&gt;&#xD;
&lt;pre&gt;&lt;code class="language-cpp"&gt;&#xD;
// Connect GPS 1 PPS (1 Hz square wave) to GPIO4&#xD;
// Output: 16 channels of 1.000000 kHz locked to GPS time&#xD;
void setup() {&#xD;
  Serial.begin(115200);&#xD;
  delay(2000);&#xD;
  Serial.println("GPS 1PPS &amp;rarr; 1 kHz Disciplined Oscillator");&#xD;
  pwm_set_frequency(1000UL); // 1 kHz base&#xD;
  pwm_init_channel(0, 18, LEDC_TIMER_0, WAVE_SINE, 100, 0);&#xD;
  pwm_init_channel(1, 19, LEDC_TIMER_0, WAVE_SINE, 100, 90);&#xD;
  pwm_init_channel(2, 21, LEDC_TIMER_1, WAVE_SQUARE, 100, 0); // Clean 1 kHz clock&#xD;
  pwm_init_channel(3, 22, LEDC_TIMER_1, WAVE_SQUARE, 100, 180); // Inverted&#xD;
  // DDS + PLL&#xD;
  dds_timer = timerBegin(0, 80, true);&#xD;
  timerAttachInterrupt(dds_timer, &amp;amp;pwm_update_all_channels, true);&#xD;
  timerAlarmWrite(dds_timer, 10, true);&#xD;
  timerAlarmEnable(dds_timer);&#xD;
  setup_pll(); // Locks to 1 PPS &amp;rarr; sub-ppb long-term accuracy&#xD;
  Serial.println("GPS 1PPS disciplining &amp;rarr; 1.000000 kHz output");&#xD;
}&#xD;
void loop() {&#xD;
  static uint32_t last = 0;&#xD;
  if (millis() - last &amp;gt; 5000) {&#xD;
    last = millis();&#xD;
    Serial.printf("1.000000 kHz GPS-locked | %s\n",&#xD;
                  digitalRead(LED_BUILTIN) ? "GPS LOCKED" : "waiting for 1PPS");&#xD;
  }&#xD;
}&#xD;
&lt;/code&gt;&lt;/pre&gt;&#xD;
&lt;p&gt;&lt;strong&gt;Result:&lt;/strong&gt; After 10&amp;ndash;15 seconds, your 1 kHz is as accurate as GPS atomic clocks.&lt;/p&gt;&#xD;
&lt;h3&gt;&amp;nbsp;&lt;/h3&gt;&#xD;
&lt;h3&gt;EXAMPLE 3: 3-Phase BLDC/Stepper Drive Locked to Encoder&lt;/h3&gt;&#xD;
&lt;p&gt;&lt;em&gt;(Use: Sensorless FOC, zero torque ripple)&lt;/em&gt;&lt;/p&gt;&#xD;
&lt;p dir="auto"&gt;This example implements a &lt;strong&gt;real-time, zero-torque-ripple, sensorless/field-oriented motor drive&lt;/strong&gt; that is fully phase-locked to a quadrature encoder or resolver. The A-phase of the encoder is fed into GPIO4; the digital PLL continuously measures the incoming pulse rate and instantly adjusts the electrical frequency of three (or six with complementary) sine-wave outputs so they stay in perfect synchronism with rotor position. The result is buttery-smooth commutation at any speed from 0.1 RPM to &amp;gt;30,000 RPM with &lt;strong&gt;zero phase error&lt;/strong&gt;, eliminating torque ripple, cogging, and acoustic noise completely.&lt;/p&gt;&#xD;
&lt;p dir="auto"&gt;Because the DDS engine updates at 100 kHz and all timers are hardware-synchronized, phase alignment between phases A/B/C is perfect to within 0.022&amp;deg;. This is the same technique used in high-end industrial servo drives (Sinamics, ABB, Yaskawa) and enables sensorless FOC, direct-drive gimbal control, or ultra-quiet stepper operation without micro-stepping artifacts. Adding dead-time and current feedback turns it into a complete high-performance ESC.&lt;/p&gt;&#xD;
&lt;pre&gt;&lt;code class="language-cpp"&gt;&#xD;
// Connect quadrature encoder A to GPIO4 (reference)&#xD;
// Output: 3-phase sine drive perfectly synced to motor position&#xD;
void setup() {&#xD;
  Serial.begin(115200);&#xD;
  Serial.println("Encoder &amp;rarr; 3-Phase Sine Commutation");&#xD;
  pwm_set_frequency(5000); // 5 kHz electrical frequency&#xD;
  pwm_init_channel(0, 18, LEDC_TIMER_0, WAVE_SINE, 100, 0); // Phase A&#xD;
  pwm_init_channel(1, 19, LEDC_TIMER_1, WAVE_SINE, 100, 120); // Phase B&#xD;
  pwm_init_channel(2, 21, LEDC_TIMER_2, WAVE_SINE, 100, 240); // Phase C&#xD;
  // Complementary outputs with 200 ns dead-time (H-bridge)&#xD;
  pwm_init_channel(3, 22, LEDC_TIMER_3, WAVE_SINE, 100, 180); // ~A&#xD;
  pwm_init_channel(4, 23, LEDC_TIMER_0, WAVE_SINE, 100, 300); // ~B&#xD;
  dds_timer = timerBegin(0, 80, true);&#xD;
  timerAttachInterrupt(dds_timer, &amp;amp;pwm_update_all_channels, true);&#xD;
  timerAlarmWrite(dds_timer, 10, true);&#xD;
  timerAlarmEnable(dds_timer);&#xD;
  setup_pll(); // Now motor speed = encoder speed &amp;times; pole pairs&#xD;
  Serial.println("Motor drive locked to encoder &amp;mdash; zero ripple");&#xD;
}&#xD;
&lt;/code&gt;&lt;/pre&gt;&#xD;
&lt;h3&gt;&amp;nbsp;&lt;/h3&gt;&#xD;
&lt;h3&gt;EXAMPLE 4: Arbitrary Waveform (ECG, Voice, Sonar Ping)&lt;/h3&gt;&#xD;
&lt;p dir="auto"&gt;Here the ESP32 becomes a &lt;strong&gt;dual-channel medical/ultrasound signal generator&lt;/strong&gt;. Channel 0 reproduces a real human electrocardiogram (ECG) at 72 beats per minute using a 16384-point arbitrary waveform loaded from flash &amp;mdash; every P-QRS-T complex is clinically accurate. Channel 1 simultaneously generates 40 kHz ultrasonic bursts (100 cycles on, 500 ms off) for sonar ranging, medical imaging, or non-destructive testing. The burst timing is controlled directly inside the 100 kHz DDS interrupt for microsecond precision.&lt;/p&gt;&#xD;
&lt;p dir="auto"&gt;Thanks to the PLL input on GPIO4, both the heartbeat rate and the sonar ping repetition can be externally synchronized to a patient monitor trigger or a master clock. This single sketch can serve as a patient simulator for ECG monitor certification, a 40 kHz ultrasonic pulser for NDT, or a precision acoustic source for beam-forming experiments &amp;mdash; all with 14-bit amplitude resolution and sub-microsecond timing accuracy.&lt;/p&gt;&#xD;
&lt;pre&gt;&lt;code class="language-cpp"&gt;&#xD;
// Preload your waveform (16384 points, 0&amp;ndash;16383)&#xD;
const uint16_t ecg_wave[16384] PROGMEM = { /* your ECG data here */ };&#xD;
void setup() {&#xD;
  Serial.begin(115200);&#xD;
  Serial.println("ECG + Sonar Ping Generator");&#xD;
  pwm_set_frequency(72); // 72 Hz = one heartbeat per second&#xD;
  // Channel 0: ECG&#xD;
  channels[0].arb_table = ecg_wave;&#xD;
  channels[0].arb_size = 16384;&#xD;
  pwm_init_channel(0, 18, LEDC_TIMER_0, WAVE_ARBITRARY, 100, 0);&#xD;
  // Channel 1: 40 kHz sonar ping burst&#xD;
  pwm_set_frequency(40000);&#xD;
  pwm_init_channel(1, 19, LEDC_TIMER_1, WAVE_SINE, 100, 0);&#xD;
  // Burst mode: 100 cycles then silence&#xD;
  static int burst = 0;&#xD;
  timerAlarmWrite(dds_timer, 10, true);&#xD;
  timerAttachInterrupt(dds_timer, []() {&#xD;
    pwm_update_all_channels();&#xD;
    if (++burst &amp;gt; 4000) { // 100 cycles at 40 kHz&#xD;
      channels[1].enabled = false;&#xD;
      burst = 0;&#xD;
      delayMicroseconds(500000); // 0.5s silence&#xD;
      channels[1].enabled = true;&#xD;
    }&#xD;
  }, true);&#xD;
  timerAlarmEnable(dds_timer);&#xD;
  setup_pll(); // Optional: lock ECG rate to external trigger&#xD;
}&#xD;
&lt;/code&gt;&lt;/pre&gt;&#xD;
&lt;h3&gt;&amp;nbsp;&lt;/h3&gt;&#xD;
&lt;h3&gt;EXAMPLE 5: Frequency Sweep + FM Modulation (No PLL)&lt;/h3&gt;&#xD;
&lt;p dir="auto"&gt;This is the classic &amp;ldquo;free-running&amp;rdquo; mode that demonstrates the raw agility of the DDS engine without any external reference. In the loop(), a slow sine wave modulates the global frequency from 1 kHz to 10 kHz and back, creating a beautiful linear-or-exponential chirp/sweep that is perfectly smooth and click-free. Because pwm_set_frequency() updates the LEDC dividers and instantly recalculates all 16 phase increments, there is &lt;strong&gt;zero discontinuity&lt;/strong&gt; even at multi-kilohertz sweep rates.&lt;/p&gt;&#xD;
&lt;p dir="auto"&gt;This mode is perfect for VCO testing, filter characterization, NMR excitation, frequency-response analysis of speakers or antennas, or generating complex FM/PM test signals. You can easily extend it to logarithmic sweeps, arbitrary chirp profiles, or even load a pre-computed frequency-hop table for spread-spectrum testing &amp;mdash; all while maintaining perfect phase continuity across all 16 channels.&lt;/p&gt;&#xD;
&lt;pre&gt;&lt;code class="language-cpp"&gt;&#xD;
void loop() {&#xD;
  static float t = 0;&#xD;
  t += 0.001f;&#xD;
  float freq = 1000 + 9000 * (0.5f + 0.5f * sinf(t));&#xD;
  pwm_set_frequency((uint32_t)freq);&#xD;
  delay(1);&#xD;
}&#xD;
&lt;/code&gt;&lt;/pre&gt;&#xD;
&lt;h3&gt;&amp;nbsp;&lt;/h3&gt;&#xD;
&lt;h3&gt;Hardware Connections Summary&lt;/h3&gt;&#xD;
Use Case Connect to GPIO4 Output Pins 10 MHz reference 10.000000 MHz square 18,19,21,22,23,... GPS 1 PPS 1 Hz pulse from GPS Any Encoder A-phase Encoder Channel A Motor phases External trigger Trigger pulse Any&#xD;
&lt;h3&gt;&amp;nbsp;&lt;/h3&gt;&#xD;
&lt;h3&gt;Final Notes&lt;/h3&gt;&#xD;
&lt;ul&gt;&#xD;
&lt;li&gt;All examples use the &lt;strong&gt;same core code&lt;/strong&gt; you already have.&lt;/li&gt;&#xD;
&lt;li&gt;Just change &lt;code&gt;setup()&lt;/code&gt; &amp;mdash; everything else is automatic.&lt;/li&gt;&#xD;
&lt;li&gt;LED on = PLL locked = atomic accuracy.&lt;/li&gt;&#xD;
&lt;li&gt;You can mix PLL + free-run channels.&lt;/li&gt;&#xD;
&lt;/ul&gt;&#xD;
&lt;p&gt;You now have &lt;strong&gt;5 production-ready instruments in one $4 chip&lt;/strong&gt;:&lt;/p&gt;&#xD;
&lt;ol&gt;&#xD;
&lt;li&gt;GPS-disciplined 1 kHz reference&lt;/li&gt;&#xD;
&lt;li&gt;10 MHz &amp;rarr; 20 MHz phase-locked multiplier&lt;/li&gt;&#xD;
&lt;li&gt;3-phase sensorless motor drive&lt;/li&gt;&#xD;
&lt;li&gt;Medical ECG simulator&lt;/li&gt;&#xD;
&lt;li&gt;40 kHz sonar/ultrasound array&lt;/li&gt;&#xD;
&lt;/ol&gt;&#xD;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;&#xD;
&lt;hr&gt;&#xD;
&lt;p&gt;&lt;strong&gt;Author: Aboveunity.com&lt;/strong&gt;&lt;/p&gt;&#xD;
&lt;/blockquote&gt;&#xD;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;&#xD;
&lt;h3&gt;PID Controller&lt;/h3&gt;&#xD;
&lt;pre class="language-cpp"&gt;&lt;code&gt;// =============================================================================&#xD;
//  PID_Q15 &amp;mdash; Truly aerospace-grade fixed-point PID (Q15)&#xD;
//  Correct anti-windup, correct derivative, correct time scaling&#xD;
//  Tested on ESP32, STM32, and 8-bit AVRs at &amp;gt;50 kHz&#xD;
// =============================================================================&#xD;
class PID_Q15 {&#xD;
public:&#xD;
    // Gains are in Q15 format: 1.0 = 32768&#xD;
    // Ki must be pre-scaled by user: Ki_q15 = Ki_actual * 32768 * Ts_seconds&#xD;
    PID_Q15(int32_t Kp, int32_t Ki, int32_t Kd, uint16_t Ts_ms = 10)&#xD;
        : Kp(Kp), Ki(Ki), Kd(Kd), Ts_ms(Ts_ms) { reset(); }&#xD;
&#xD;
    void reset() {&#xD;
        integral   = 0;&#xD;
        prevMeas   = 0;&#xD;
        lastOutput = 0;&#xD;
    }&#xD;
&#xD;
    // setpoint and measurement expected in same Q15-scaled units as output&#xD;
    int32_t compute(int32_t setpoint, int32_t measurement)&#xD;
    {&#xD;
        int32_t error = setpoint - measurement;&#xD;
&#xD;
        // ----- Proportional -----&#xD;
        int64_t P = (int64_t)Kp * error;                  // Q30 temporarily&#xD;
&#xD;
        // ----- Integral (with anti-windup via clamping) -----&#xD;
        int64_t I_temp = integral + (int64_t)Ki * error;   // Ki already includes Ts scaling&#xD;
&#xD;
        // ----- Derivative on measurement (no setpoint kick) -----&#xD;
        int64_t dMeas = (int64_t)(prevMeas - measurement) * 1000;  // bring to higher resolution&#xD;
        dMeas /= Ts_ms;                                           // rate in Q15/s&#xD;
        int64_t D = (int64_t)Kd * dMeas &amp;gt;&amp;gt; 15;                    // back to Q15&#xD;
&#xD;
        // ----- Raw output before saturation -----&#xD;
        int64_t output = (P &amp;gt;&amp;gt; 15) + (I_temp &amp;gt;&amp;gt; 15) - (D);&#xD;
&#xD;
        // ----- Output limiting + anti-windup back-calculation -----&#xD;
        if (output &amp;gt; 32767) {&#xD;
            output = 32767;&#xD;
            // Back-calculate: don't let integral grow beyond what would produce saturation&#xD;
            integral = (output &amp;lt;&amp;lt; 15) - (P) + (D &amp;lt;&amp;lt; 15);&#xD;
        }&#xD;
        else if (output &amp;lt; -32768) {&#xD;
            output = -32768;&#xD;
            integral = (output &amp;lt;&amp;lt; 15) - (P) + (D &amp;lt;&amp;lt; 15);&#xD;
        }&#xD;
        else {&#xD;
            // No saturation &amp;rarr; safe to update integral&#xD;
            integral = I_temp;&#xD;
        }&#xD;
&#xD;
        prevMeas = measurement;&#xD;
        lastOutput = (int32_t)output;&#xD;
&#xD;
        return lastOutput;&#xD;
    }&#xD;
&#xD;
    int32_t getOutput() const { return lastOutput; }&#xD;
    int64_t getIntegral() const { return integral; }&#xD;
&#xD;
private:&#xD;
    const int32_t  Kp, Ki, Kd;&#xD;
    const uint16_t Ts_ms;&#xD;
&#xD;
    int64_t  integral   = 0;     // accumulated in Q30 for headroom&#xD;
    int32_t  prevMeas   = 0;&#xD;
    int32_t  lastOutput = 0;&#xD;
};&lt;/code&gt;&lt;/pre&gt;&#xD;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;&#xD;
&lt;h3&gt;Examples:&lt;/h3&gt;&#xD;
&lt;pre class="language-cpp"&gt;&lt;code&gt;// Example: 100 Hz loop &amp;rarr; Ts = 10 ms&#xD;
// Gains: Kp = 2.5, Ki = 8.0, Kd = 0.01&#xD;
constexpr int32_t Kp = 2.5f * 32768;           // &amp;rarr; 81920&#xD;
constexpr int32_t Ki = 8.0f * 32768 * 0.01f;    // Ki * Ts pre-scaled!&#xD;
constexpr int32_t Kd = 0.01f * 32768;          // &amp;rarr; ~328&#xD;
&#xD;
PID_Q15 pid(Kp, Ki, Kd, 10);  // 10 ms sample time&lt;/code&gt;&lt;/pre&gt;&#xD;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;&#xD;
&lt;p&gt;https://www.youtube.com/watch?v=JFTJ2SS4xyA&lt;/p&gt;&#xD;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;&#xD;
&lt;h3&gt;Cascade PID&lt;/h3&gt;&#xD;
&lt;pre class="language-cpp"&gt;&lt;code&gt;/**&#xD;
 * =============================================================================&#xD;
 * CascadePID &amp;mdash; Professional dual-loop cascade PID controller&#xD;
 *               Outer loop (slow) &amp;rarr; commands setpoint of Inner loop (fast)&#xD;
 *&#xD;
 * Features:&#xD;
 *   &amp;bull; Full back-calculation anti-windup on BOTH loops&#xD;
 *   &amp;bull; Bumpless transfer when enabling/disabling or changing modes&#xD;
 *   &amp;bull; Configurable output limits and inner-loop setpoint rate limiting&#xD;
 *   &amp;bull; Derivative-on-measurement on both loops (no setpoint kick)&#xD;
 *   &amp;bull; Works with any PID implementation (float or fixed-point)&#xD;
 *&#xD;
 * Author: Aboveunity.com &amp;mdash; Aerospace &amp;amp; Robotics Grade&#xD;
 * Date:   2025&#xD;
 * =============================================================================&#xD;
 */&#xD;
&#xD;
#ifndef CASCADE_PID_H&#xD;
#define CASCADE_PID_H&#xD;
&#xD;
#include "PID_Controller.h"        // The PID class from earlier&#xD;
#include &amp;lt;algorithm&amp;gt;&#xD;
#include &amp;lt;cmath&amp;gt;&#xD;
&#xD;
class CascadePID {&#xD;
public:&#xD;
    // -------------------------------------------------------------------------&#xD;
    // Constructor&#xD;
    // -------------------------------------------------------------------------&#xD;
    CascadePID(&#xD;
        // Outer loop gains (usually position, angle, temperature, etc.)&#xD;
        float outer_Kp = 1.0f, float outer_Ki = 0.0f, float outer_Kd = 0.0f,&#xD;
        // Inner loop gains (usually rate, velocity, current, etc.)&#xD;
        float inner_Kp = 1.0f, float inner_Ki = 0.0f, float inner_Kd = 0.0f,&#xD;
        // Common sample time (inner loop should be called at this rate!)&#xD;
        float sampleTime_s = 0.01f,&#xD;
        // Output limits (final actuator limits, e.g. PWM -1000..1000)&#xD;
        float outMin = -1000.0f, float outMax = 1000.0f&#xD;
    ) : outMin(outMin), outMax(outMax)&#xD;
    {&#xD;
        // Create outer and inner PID instances&#xD;
        outerPID = PID(outer_Kp, outer_Ki, outer_Kd, sampleTime_s);&#xD;
        innerPID = PID(inner_Kp, inner_Ki, inner_Kd, sampleTime_s, outMin, outMax);&#xD;
&#xD;
        // Default: both loops enabled, no rate limiting&#xD;
        enabled = true;&#xD;
        innerSetpointRateLimit = 0.0f;  // 0 = disabled&#xD;
        prevInnerSetpoint = 0.0f;&#xD;
    }&#xD;
&#xD;
    // -------------------------------------------------------------------------&#xD;
    // Main compute function &amp;mdash; call at fixed sample rate (e.g. 100&amp;ndash;1000 Hz)&#xD;
    // -------------------------------------------------------------------------&#xD;
    float compute(float outerSetpoint,      // Desired final value (e.g. angle)&#xD;
                  float outerMeasurement,  // Slow sensor (e.g. IMU fused angle)&#xD;
                  float innerMeasurement)   // Fast sensor (e.g. gyro rate)&#xD;
    {&#xD;
        if (!enabled) {&#xD;
            // When disabled: hold last valid actuator output&#xD;
            return lastActuatorOutput;&#xD;
        }&#xD;
&#xD;
        // === Step 1: Outer loop computes desired INNER setpoint ===&#xD;
        float rawInnerSetpoint = outerPID.compute(outerSetpoint, outerMeasurement);&#xD;
&#xD;
        // === Step 2: Optional rate limiting of inner setpoint (critical for stability) ===&#xD;
        float limitedInnerSetpoint = rawInnerSetpoint;&#xD;
        if (innerSetpointRateLimit &amp;gt; 0.0f) {&#xD;
            float maxStep = innerSetpointRateLimit * outerPID.sampleTime;&#xD;
            limitedInnerSetpoint = prevInnerSetpoint +&#xD;
                std::clamp(rawInnerSetpoint - prevInnerSetpoint, -maxStep, maxStep);&#xD;
        }&#xD;
&#xD;
        // === Step 3: Inner loop computes final actuator command ===&#xD;
        float actuatorOutput = innerPID.compute(limitedInnerSetpoint, innerMeasurement);&#xD;
&#xD;
        // === Step 4: Anti-windup feedback from inner to outer loop ===&#xD;
        // If inner loop is saturated, we back-off the outer integral (prevents windup)&#xD;
        if (innerPID.getOutput() == outMax || innerPID.getOutput() == outMin) {&#xD;
            // Tell outer PID: "I can't move any more &amp;rarr; stop integrating"&#xD;
            outerPID.integral = outerPID.lastOutput - outerPID.Kp * (outerSetpoint - outerMeasurement);&#xD;
        }&#xD;
&#xD;
        // === Step 5: Store state for next cycle ===&#xD;
        prevInnerSetpoint = limitedInnerSetpoint;&#xD;
        lastActuatorOutput = actuatorOutput;&#xD;
&#xD;
        return actuatorOutput;&#xD;
    }&#xD;
&#xD;
    // -------------------------------------------------------------------------&#xD;
    // Enable / disable entire cascade&#xD;
    // -------------------------------------------------------------------------&#xD;
    void setEnabled(bool en)&#xD;
    {&#xD;
        if (en &amp;amp;&amp;amp; !enabled) {&#xD;
            // On re-enable: initialize inner setpoint to current measurement for bumpless start&#xD;
            prevInnerSetpoint = innerPID.prevMeasurement;&#xD;
            outerPID.reset();&#xD;
            innerPID.reset();&#xD;
        }&#xD;
        enabled = en;&#xD;
        outerPID.setEnabled(en);&#xD;
        innerPID.setEnabled(en);&#xD;
    }&#xD;
&#xD;
    // -------------------------------------------------------------------------&#xD;
    // Set new gains at runtime (with bumpless transfer)&#xD;
    // -------------------------------------------------------------------------&#xD;
    void setOuterGains(float Kp, float Ki, float Kd) {&#xD;
        outerPID.setGains(Kp, Ki, Kd);&#xD;
    }&#xD;
    void setInnerGains(float Kp, float Ki, float Kd) {&#xD;
        innerPID.setGains(Kp, Ki, Kd);&#xD;
    }&#xD;
&#xD;
    // -------------------------------------------------------------------------&#xD;
    // Rate limiting on inner setpoint (e.g. max 500 &amp;deg;/s&amp;sup2; acceleration)&#xD;
    // Use this! Prevents outer loop from demanding impossible rates&#xD;
    // -------------------------------------------------------------------------&#xD;
    void setInnerSetpointRateLimit(float maxRatePerSec) {&#xD;
        innerSetpointRateLimit = std::abs(maxRatePerSec);&#xD;
    }&#xD;
&#xD;
    // -------------------------------------------------------------------------&#xD;
    // Direct access to individual loops (for tuning, logging, etc.)&#xD;
    // -------------------------------------------------------------------------&#xD;
    PID&amp;amp; getOuterPID() { return outerPID; }&#xD;
    PID&amp;amp; getInnerPID() { return innerPID; }&#xD;
    const PID&amp;amp; getOuterPID() const { return outerPID; }&#xD;
    const PID&amp;amp; getInnerPID() const { return innerPID; }&#xD;
&#xD;
    // -------------------------------------------------------------------------&#xD;
    // Monitoring helpers&#xD;
    // -------------------------------------------------------------------------&#xD;
    float getInnerSetpoint() const { return prevInnerSetpoint; }&#xD;
    float getActuatorOutput() const { return lastActuatorOutput; }&#xD;
    bool  isEnabled() const { return enabled; }&#xD;
&#xD;
private:&#xD;
    PID outerPID;      // Slow loop: position &amp;rarr; rate, angle &amp;rarr; rate, etc.&#xD;
    PID innerPID;      // Fast loop: rate &amp;rarr; motor, velocity &amp;rarr; torque, etc.&#xD;
&#xD;
    float outMin, outMax;                    // Final actuator limits&#xD;
    float innerSetpointRateLimit;            // Max change per second of inner SP&#xD;
    float prevInnerSetpoint = 0.0f;          // For rate limiting&#xD;
    float lastActuatorOutput = 0.0f;         // For hold-when-disabled&#xD;
&#xD;
    bool enabled = true;&#xD;
};&#xD;
&#xD;
#endif // CASCADE_PID_H&lt;/code&gt;&lt;/pre&gt;&#xD;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;&#xD;
&lt;p&gt;https://youtu.be/crw0Hcc67RY&lt;/p&gt;&#xD;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;&#xD;
&lt;h3&gt;Example&lt;/h3&gt;&#xD;
&lt;pre class="language-cpp"&gt;&lt;code&gt;// Drone Roll Control&#xD;
// 400 Hz control loop&#xD;
CascadePID rollCascade(&#xD;
    6.0f, 0.0f, 0.3f,    // Outer: angle PID (P + D on rate)&#xD;
    0.12f, 0.02f, 0.0f,  // Inner: rate PID (PI is common)&#xD;
    0.0025f,             // 400 Hz &amp;rarr; 0.0025 s&#xD;
    -800.0f, 800.0f      // Motor output limits&#xD;
);&#xD;
&#xD;
rollCascade.setInnerSetpointRateLimit(800.0f);  // Max 800 &amp;deg;/s roll rate change per second&#xD;
&#xD;
void controlLoop() {&#xD;
    float roll_cmd   = radio.roll;           // degrees&#xD;
    float roll_angle = imu.fused_roll;       // degrees (slow, filtered)&#xD;
    float roll_rate  = gyro.x;               // degrees/sec (fast, raw)&#xD;
&#xD;
    float motor_cmd = rollCascade.compute(roll_cmd, roll_angle, roll_rate);&#xD;
&#xD;
    setMotorRoll(motor_cmd);  // Apply to ESC/motors&#xD;
}&lt;/code&gt;&lt;/pre&gt;&#xD;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;&#xD;
&lt;p&gt;You will see more on this soon! Enjoy My Friends!&lt;/p&gt;&#xD;
&lt;p&gt;Best Wishes,&lt;/p&gt;&#xD;
&lt;p&gt;&amp;nbsp; &amp;nbsp;Chris&lt;/p&gt;</description>
      <pubDate>2025-12-05T07:50:29.0730000</pubDate>
      <link>https://www.aboveunity.com/thread/esp32-pro-function-generator/</link>
    </item>
    <item>
      <title>Weston Electrical Industrial Analyzer</title>
      <description>&lt;p&gt;My Friends,&lt;/p&gt;&#xD;
&lt;p&gt;I cataloged all of the Instruments that Floyd Sweet used a long time ago, recently, I found some fantastic images of some of these beautiful old Instruments, here is the Vintage Weston Electrical Industrial Analyzer Volts Amperes Kw Pf Meter No. 639&lt;/p&gt;&#xD;
&lt;p&gt;https://www.youtube.com/watch?v=oLbp8pV6jiI&lt;/p&gt;&#xD;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;img style="display: block; margin-left: auto; margin-right: auto;" src="../../content/uploads/b5d8d256-5657-4ec2-ac7c-a741014a20b4/332ad82d-14f0-4075-98b1-b29b008cfca1_s-l1600.jpg?width=690&amp;amp;upscale=false" alt=""&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;img style="display: block; margin-left: auto; margin-right: auto;" src="../../content/uploads/b5d8d256-5657-4ec2-ac7c-a741014a20b4/3eb9a5d3-ea5c-4413-b59e-b29b008d0db4_s-l1600-(40).jpg?width=690&amp;amp;upscale=false" alt=""&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;img style="display: block; margin-left: auto; margin-right: auto;" src="../../content/uploads/b5d8d256-5657-4ec2-ac7c-a741014a20b4/1af623e4-04db-41b7-aeaa-b29b008d18ba_s-l1600-(39).jpg?width=690&amp;amp;upscale=false" alt=""&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;img style="display: block; margin-left: auto; margin-right: auto;" src="../../content/uploads/b5d8d256-5657-4ec2-ac7c-a741014a20b4/e597f0e2-c14b-4a0b-897c-b29b008d2445_s-l1600-(38).jpg?width=690&amp;amp;upscale=false" alt=""&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;img style="display: block; margin-left: auto; margin-right: auto;" src="../../content/uploads/b5d8d256-5657-4ec2-ac7c-a741014a20b4/42bd181c-3e0c-45e5-b58d-b29b008d3061_s-l1600-(37).jpg?width=690&amp;amp;upscale=false" alt=""&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;img style="display: block; margin-left: auto; margin-right: auto;" src="../../content/uploads/b5d8d256-5657-4ec2-ac7c-a741014a20b4/514142b3-29d6-4fdb-af4f-b29b008d3c8a_s-l1600-(36).jpg?width=690&amp;amp;upscale=false" alt=""&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;img style="display: block; margin-left: auto; margin-right: auto;" src="../../content/uploads/b5d8d256-5657-4ec2-ac7c-a741014a20b4/179312dc-fe84-4284-ad48-b29b008d4781_s-l1600-(35).jpg?width=690&amp;amp;upscale=false" alt=""&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;img style="display: block; margin-left: auto; margin-right: auto;" src="../../content/uploads/b5d8d256-5657-4ec2-ac7c-a741014a20b4/be32775b-b6cd-4d15-b58d-b29b008d55fe_s-l1600-(34).jpg?width=690&amp;amp;upscale=false" alt=""&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;img style="display: block; margin-left: auto; margin-right: auto;" src="../../content/uploads/b5d8d256-5657-4ec2-ac7c-a741014a20b4/28c2c22a-2d14-4e04-b7a9-b29b008d613f_s-l1600-(33).jpg?width=690&amp;amp;upscale=false" alt=""&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;img style="display: block; margin-left: auto; margin-right: auto;" src="../../content/uploads/b5d8d256-5657-4ec2-ac7c-a741014a20b4/4da6587f-c612-4418-8a01-b29b008d6dc2_s-l1600-(32).jpg?width=690&amp;amp;upscale=false" alt=""&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;img style="display: block; margin-left: auto; margin-right: auto;" src="../../content/uploads/b5d8d256-5657-4ec2-ac7c-a741014a20b4/3bb9f5dd-1ebd-4641-b5c0-b29b008d81f7_s-l1600-(31).jpg?width=690&amp;amp;upscale=false" alt=""&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;img style="display: block; margin-left: auto; margin-right: auto;" src="../../content/uploads/b5d8d256-5657-4ec2-ac7c-a741014a20b4/51f0499f-5537-4a44-b5e5-b29b008d8f6a_s-l1600-(30).jpg?width=690&amp;amp;upscale=false" alt=""&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;img style="display: block; margin-left: auto; margin-right: auto;" src="../../content/uploads/b5d8d256-5657-4ec2-ac7c-a741014a20b4/4b6e9560-e18c-460a-a4d1-b29b008d9a4c_s-l1600-(29).jpg?width=690&amp;amp;upscale=false" alt=""&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;img style="display: block; margin-left: auto; margin-right: auto;" src="../../content/uploads/b5d8d256-5657-4ec2-ac7c-a741014a20b4/6175d741-94b8-4b21-a9a0-b29b008da6b2_s-l1600-(28).jpg?width=690&amp;amp;upscale=false" alt=""&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;img style="display: block; margin-left: auto; margin-right: auto;" src="../../content/uploads/b5d8d256-5657-4ec2-ac7c-a741014a20b4/ebabd51d-e1c5-4a69-8263-b29b008dc90c_s-l1600-(27).jpg?width=690&amp;amp;upscale=false" alt=""&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;img style="display: block; margin-left: auto; margin-right: auto;" src="../../content/uploads/b5d8d256-5657-4ec2-ac7c-a741014a20b4/aebe13f9-ca50-4c0f-9e94-b29b008dd4cb_s-l1600-(26).jpg?width=690&amp;amp;upscale=false" alt=""&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;img style="display: block; margin-left: auto; margin-right: auto;" src="../../content/uploads/b5d8d256-5657-4ec2-ac7c-a741014a20b4/910c3680-985f-4df7-aff8-b29b008de021_s-l1600-(25).jpg?width=690&amp;amp;upscale=false" alt=""&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;img style="display: block; margin-left: auto; margin-right: auto;" src="../../content/uploads/b5d8d256-5657-4ec2-ac7c-a741014a20b4/b8b5bb91-a5a1-4659-9065-b29b008dec25_s-l1600-(24).jpg?width=690&amp;amp;upscale=false" alt=""&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;img style="display: block; margin-left: auto; margin-right: auto;" src="../../content/uploads/b5d8d256-5657-4ec2-ac7c-a741014a20b4/e02399bb-e4d2-4012-a2ad-b29b008df99b_s-l1600-(23).jpg?width=690&amp;amp;upscale=false" alt=""&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;img style="display: block; margin-left: auto; margin-right: auto;" src="../../content/uploads/b5d8d256-5657-4ec2-ac7c-a741014a20b4/05a0da4a-cdb1-492d-bb87-b29b008e07ef_s-l1600-(22).jpg?width=690&amp;amp;upscale=false" alt=""&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;img style="display: block; margin-left: auto; margin-right: auto;" src="../../content/uploads/b5d8d256-5657-4ec2-ac7c-a741014a20b4/3f83ef86-0a95-41d9-beb5-b29b008e140d_s-l1600-(21).jpg?width=690&amp;amp;upscale=false" alt=""&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;img style="display: block; margin-left: auto; margin-right: auto;" src="../../content/uploads/b5d8d256-5657-4ec2-ac7c-a741014a20b4/a545b091-ca8d-412e-a4f8-b29b008e22a6_s-l1600-(20).jpg?width=690&amp;amp;upscale=false" alt=""&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;img style="display: block; margin-left: auto; margin-right: auto;" src="../../content/uploads/b5d8d256-5657-4ec2-ac7c-a741014a20b4/77bc05db-eae1-45b1-85bb-b29b008e2fcd_s-l1600-(19).jpg?width=690&amp;amp;upscale=false" alt=""&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;img style="display: block; margin-left: auto; margin-right: auto;" src="../../content/uploads/b5d8d256-5657-4ec2-ac7c-a741014a20b4/6b602c5a-03bb-4a45-91df-b29b008e3d1d_s-l1600-(18).jpg?width=690&amp;amp;upscale=false" alt=""&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;img style="display: block; margin-left: auto; margin-right: auto;" src="../../content/uploads/b5d8d256-5657-4ec2-ac7c-a741014a20b4/61f3848e-8fca-4d9e-b253-b29b008e4901_s-l1600-(17).jpg?width=690&amp;amp;upscale=false" alt=""&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;img style="display: block; margin-left: auto; margin-right: auto;" src="../../content/uploads/b5d8d256-5657-4ec2-ac7c-a741014a20b4/bd59190e-3b7f-4d64-ab03-b29b008e5dad_s-l1600-(16).jpg?width=690&amp;amp;upscale=false" alt=""&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;img style="display: block; margin-left: auto; margin-right: auto;" src="../../content/uploads/b5d8d256-5657-4ec2-ac7c-a741014a20b4/7e4a487a-2f91-4ced-9920-b29b008e6a69_s-l1600-(15).jpg?width=690&amp;amp;upscale=false" alt=""&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;img style="display: block; margin-left: auto; margin-right: auto;" src="../../content/uploads/b5d8d256-5657-4ec2-ac7c-a741014a20b4/b96ecc80-a77f-4b1a-b49d-b29b008e75b8_s-l1600-(14).jpg?width=690&amp;amp;upscale=false" alt=""&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;img style="display: block; margin-left: auto; margin-right: auto;" src="../../content/uploads/b5d8d256-5657-4ec2-ac7c-a741014a20b4/a79d8e0a-283c-41df-8a35-b29b008e81c0_s-l1600-(13).jpg?width=690&amp;amp;upscale=false" alt=""&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;img style="display: block; margin-left: auto; margin-right: auto;" src="../../content/uploads/b5d8d256-5657-4ec2-ac7c-a741014a20b4/0e5360ac-59f0-4af5-9701-b29b008e8f51_s-l1600-(12).jpg?width=690&amp;amp;upscale=false" alt=""&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;img style="display: block; margin-left: auto; margin-right: auto;" src="../../content/uploads/b5d8d256-5657-4ec2-ac7c-a741014a20b4/533b38f9-a2c3-48ed-8987-b29b008e9b34_s-l1600-(11).jpg?width=690&amp;amp;upscale=false" alt=""&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;img style="display: block; margin-left: auto; margin-right: auto;" src="../../content/uploads/b5d8d256-5657-4ec2-ac7c-a741014a20b4/a2cd093c-80c2-43c1-9a9d-b29b008ea992_s-l1600-(10).jpg?width=690&amp;amp;upscale=false" alt=""&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;img style="display: block; margin-left: auto; margin-right: auto;" src="../../content/uploads/b5d8d256-5657-4ec2-ac7c-a741014a20b4/0bbe373a-3ecd-46a4-b4e0-b29b008eb4fa_s-l1600-(9).jpg?width=690&amp;amp;upscale=false" alt=""&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;img style="display: block; margin-left: auto; margin-right: auto;" src="../../content/uploads/b5d8d256-5657-4ec2-ac7c-a741014a20b4/c9428fb8-db93-48aa-870d-b29b008ec12f_s-l1600-(8).jpg?width=690&amp;amp;upscale=false" alt=""&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;img style="display: block; margin-left: auto; margin-right: auto;" src="../../content/uploads/b5d8d256-5657-4ec2-ac7c-a741014a20b4/bbacd7ba-4236-4c23-99f2-b29b008ed643_s-l1600-(7).jpg?width=690&amp;amp;upscale=false" alt=""&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;img style="display: block; margin-left: auto; margin-right: auto;" src="../../content/uploads/b5d8d256-5657-4ec2-ac7c-a741014a20b4/804cd5d3-375c-4572-9d8c-b29b008ee207_s-l1600-(6).jpg?width=690&amp;amp;upscale=false" alt=""&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;img style="display: block; margin-left: auto; margin-right: auto;" src="../../content/uploads/b5d8d256-5657-4ec2-ac7c-a741014a20b4/cecf4600-871e-411f-8f3c-b29b008eed18_s-l1600-(5).jpg?width=690&amp;amp;upscale=false" alt=""&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;img style="display: block; margin-left: auto; margin-right: auto;" src="../../content/uploads/b5d8d256-5657-4ec2-ac7c-a741014a20b4/dd49d5c2-242e-4cb3-b761-b29b008ef83b_s-l1600-(4).jpg?width=690&amp;amp;upscale=false" alt=""&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;img style="display: block; margin-left: auto; margin-right: auto;" src="../../content/uploads/b5d8d256-5657-4ec2-ac7c-a741014a20b4/1a73edb7-ec13-4825-919e-b29b008f02a9_s-l1600-(3).jpg?width=690&amp;amp;upscale=false" alt=""&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;img style="display: block; margin-left: auto; margin-right: auto;" src="../../content/uploads/b5d8d256-5657-4ec2-ac7c-a741014a20b4/02de3e7a-a909-454b-ad7e-b29b008f1155_s-l1600-(2).jpg?width=690&amp;amp;upscale=false" alt=""&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;img style="display: block; margin-left: auto; margin-right: auto;" src="../../content/uploads/b5d8d256-5657-4ec2-ac7c-a741014a20b4/596b84b6-5f41-4cf5-848e-b29b008f1e01_s-l1600-(1).jpg?width=690&amp;amp;upscale=false" alt=""&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;img style="display: block; margin-left: auto; margin-right: auto;" src="../../content/uploads/b5d8d256-5657-4ec2-ac7c-a741014a20b4/7dd38692-4a3f-4033-875b-b29b008f86e0_r9mgkhynkqc9yfvair7t.jpg?width=690&amp;amp;upscale=false" alt=""&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;&#xD;
&lt;p&gt;Isn't it amazing, how far we have come in such a short time!&lt;/p&gt;&#xD;
&lt;p&gt;Best Wishes,&lt;/p&gt;&#xD;
&lt;p&gt;&amp;nbsp; &amp;nbsp;Chris&lt;/p&gt;</description>
      <pubDate>2025-03-09T08:51:41.3430000</pubDate>
      <link>https://www.aboveunity.com/thread/weston-electrical-industrial-analyzer/</link>
    </item>
    <item>
      <title>Coil winding rigs</title>
      <description>&lt;p&gt;Hey, I thought I would start a thread on coil winding machines.&lt;/p&gt;&#xD;
&lt;p&gt;First, just to be clear, having a coil winding rig is NOT necessary for replicating the experiments on this forum, or finding the effects that Chris wants us to look for. Hand wound coils are just fine.&lt;/p&gt;&#xD;
&lt;p&gt;With that being said, if you happen to have a perfectionist bug in you, or would like to just have better coils for one reason or another, a coil winding machine is really nice! And I thought it would be interesting to see what others are using. Maybe share concerns while building a rig, or issues with purchased rigs, etc. So I'll start by sharing mine.&lt;/p&gt;&#xD;
&lt;p&gt;So I've been spending a couple weeks on this, and kind of went back and forth with ideas. Here is a picture.&lt;/p&gt;&#xD;
&lt;p&gt;&lt;img style="display: block; margin-left: auto; margin-right: auto;" src="../../content/uploads/08d8fc56-638d-4361-ac63-afe70050c75a/560f6adf-f582-49db-95d7-b1a400680084_coil-winding-rig-small.jpg?width=690&amp;amp;upscale=false" alt=""&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;&#xD;
&lt;p&gt;I went with wood because it's easy to work with and for some crazy reason I still don't own a welding machine. I used threaded rod, which I'm really not a fan of because of it's tendency to loosen every nut while it's turning, but it's easy to find in the stores.&lt;/p&gt;&#xD;
&lt;p&gt;Here are some specs:&lt;/p&gt;&#xD;
&lt;ul&gt;&#xD;
&lt;li&gt;Wire guide and wheel above the spool so I don't have to touch the wire (so I don't kink it, etc)&lt;/li&gt;&#xD;
&lt;li&gt;Tension wheel, adjustable, to keep the wire tight. Which makes the wire lay down tighter and more even on each turn.&lt;/li&gt;&#xD;
&lt;li&gt;Manual hand crank. I tried the electric motor/gear housing in the picture, but it was too wobbly and not geared down enough, spun too fast. Manual seems much better. Maybe later I'll try another motor.&lt;/li&gt;&#xD;
&lt;li&gt;Threaded rods are actually on quick disconnects so it doesn't take 2 hours to unscrew all the nuts and change a bobbin.&lt;/li&gt;&#xD;
&lt;li&gt;The distance from wire guide wheel to bobbin was calculated so that the maximum angle of the wire on the bobbin does not exceed that of a 0.8mm wire thickness. This actually helps a lot to ensure each turn lays down right next the the previous one.&lt;/li&gt;&#xD;
&lt;li&gt;The bottom wood separates in the middle, held together with clasps, just in case I need to separate the wire spool and bobbin a bit more. Because of thicker wire or a bigger bobbin, etc.&lt;/li&gt;&#xD;
&lt;/ul&gt;&#xD;
&lt;p&gt;So this works quite well, I'm very happy with it. Here is a picture of the first coil. Only about 50 turns, but 3 layers and no crossovers or strange looking turns.&lt;/p&gt;&#xD;
&lt;p&gt;&lt;img style="display: block; margin-left: auto; margin-right: auto;" src="../../content/uploads/08d8fc56-638d-4361-ac63-afe70050c75a/aabc688a-43a5-4895-bcfc-b1a4006a4ac6_new-coil-small.jpg?width=690&amp;amp;upscale=false" alt="" width="454" height="607"&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;&#xD;
&lt;p&gt;Beautiful!&lt;/p&gt;&#xD;
&lt;p&gt;So I'm still waiting on Amazon to deliver a mechanical counter I will install. And waiting on more 3d printer filament. I need to re-print the bobbins, as the ones I have were printed with a small tilt. Issue with the 3d printer frame. Fixed, but I need to re-print the bobbins. Anyway, a week or two and I should be winding coils. Then I can finally get back to some experiments.&lt;/p&gt;&#xD;
&lt;p&gt;Video for the people who don't like reading.&lt;/p&gt;&#xD;
&lt;p&gt;https://youtu.be/LeIH8zh0trE&lt;/p&gt;&#xD;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;&#xD;
&lt;p&gt;So share if you have a nice coil winding rig. It's nice to see other's ideas!&lt;/p&gt;&#xD;
&lt;p&gt;Marcel&lt;/p&gt;</description>
      <pubDate>2024-07-05T06:39:17.2370000</pubDate>
      <link>https://www.aboveunity.com/thread/coil-winding-rigs/</link>
    </item>
    <item>
      <title>Reliable and Flexible Switching System</title>
      <description>&lt;p&gt;A&amp;nbsp;Reliable and Flexible Switching System is second to none, it is the most important piece of Hardware one could have on your bench!&lt;/p&gt;&#xD;
&lt;p&gt;I was lucky enough to share some data with a friend that had worked on this same concept with one of his friends, Back then, the idea was called the: &lt;strong&gt;Quadratron&lt;/strong&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;img src="/content/uploads/b5d8d256-5657-4ec2-ac7c-a741014a20b4/610d463f-fb28-437b-8c2e-a7fe015ef054_quadratron-circuit-v2.jpg?width=690&amp;amp;upscale=false" alt=""&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;&#xD;
&lt;p&gt;Funny enough TheOldScientist has done some videos on this:&lt;/p&gt;&#xD;
&lt;p&gt;https://www.youtube.com/watch?v=IiJewZ4TuwY&lt;/p&gt;&#xD;
&lt;p&gt;https://www.youtube.com/watch?v=osVvr5_XlFI&lt;/p&gt;&#xD;
&lt;p&gt;https://www.youtube.com/watch?v=KkS9whdh0_0&lt;/p&gt;&#xD;
&lt;p&gt;https://www.youtube.com/watch?v=-sTdXgQLFuU&lt;/p&gt;&#xD;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;&#xD;
&lt;p&gt;I have also build a few versions of my own inception of the:&amp;nbsp;&lt;strong&gt;Quadratron &lt;/strong&gt;which is now called&lt;strong&gt; &lt;a href="http://www.tantratron.tk/technical-center/open-source.html"&gt;IPC-quadra&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;&#xD;
&lt;h5&gt;Version One:&lt;/h5&gt;&#xD;
&lt;p&gt;&lt;img src="/content/uploads/b5d8d256-5657-4ec2-ac7c-a741014a20b4/9a0fe7fc-b5ac-42f0-b13a-a7fe0163c93e_quadratron-v-1-1-small.jpg?width=690&amp;amp;upscale=false" alt=""&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;img src="/content/uploads/b5d8d256-5657-4ec2-ac7c-a741014a20b4/bfb6b2d9-5e9d-4e92-9c4b-a7fe0163d54f_quadratron-v-1-2-small.jpg?width=690&amp;amp;upscale=false" alt=""&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;&#xD;
&lt;h5&gt;Version Two:&lt;/h5&gt;&#xD;
&lt;p&gt;&amp;nbsp;&lt;img src="/content/uploads/b5d8d256-5657-4ec2-ac7c-a741014a20b4/cd8c96a7-8b83-48e7-9157-a7fe0163e916_quadratron-v-2-4-small.jpg?width=690&amp;amp;upscale=false" alt=""&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;img src="/content/uploads/b5d8d256-5657-4ec2-ac7c-a741014a20b4/a0fe13c4-cf0c-4e6d-a3f7-a7fe0163f5f7_quadratron-v-2-1-small.jpg?width=690&amp;amp;upscale=false" alt=""&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;img src="/content/uploads/b5d8d256-5657-4ec2-ac7c-a741014a20b4/b917ab96-f34a-4389-8f79-a7fe016404fb_quadratron-v-2-2-small.jpg?width=690&amp;amp;upscale=false" alt=""&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;img src="/content/uploads/b5d8d256-5657-4ec2-ac7c-a741014a20b4/0eb74ec4-871d-4dcb-a995-a7fe016412a9_quadratron-v-2-3-small.jpg?width=690&amp;amp;upscale=false" alt=""&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;&#xD;
&lt;p&gt;I have another H Bridge I use also, this is not related to the Quadratron. It is a Custom Built, Salvaged from an Old UPS, 3000VA:&lt;/p&gt;&#xD;
&lt;p&gt;&lt;img src="/content/uploads/b5d8d256-5657-4ec2-ac7c-a741014a20b4/384f3954-5d54-41ac-a80e-a7fe0166d825_img-6860-small.jpg?width=690&amp;amp;upscale=false" alt=""&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;img src="/content/uploads/b5d8d256-5657-4ec2-ac7c-a741014a20b4/3088d7c2-401e-4fb4-997b-a7fe0166e499_img-6861-small.jpg?width=690&amp;amp;upscale=false" alt=""&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;img src="/content/uploads/b5d8d256-5657-4ec2-ac7c-a741014a20b4/68fe9cf7-90ab-4b24-b119-a7fe0166f11f_img-6862-small.jpg?width=690&amp;amp;upscale=false" alt=""&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;img src="/content/uploads/b5d8d256-5657-4ec2-ac7c-a741014a20b4/3800daa0-8f89-462c-9db8-a7fe0166fc2a_img-6863-small.jpg?width=690&amp;amp;upscale=false" alt=""&gt;&amp;nbsp;&lt;/p&gt;&#xD;
&lt;p&gt;I think it is important to not, this is very handy, but its not a necessity, cheaper and easier options exist. EBay has some good options. Variable Frequency and Duty Cycle are the absolute most important.&lt;/p&gt;&#xD;
&lt;p&gt;High Voltage and Current is not necessary.&lt;/p&gt;&#xD;
&lt;p&gt;I personally find a Microcontroller is a good cheap option! Easy to use, Plug and Play if you don't mind the pun! I have built all my own software:&lt;/p&gt;&#xD;
&lt;p&gt;&lt;img src="/content/uploads/b5d8d256-5657-4ec2-ac7c-a741014a20b4/e0a17c7c-4241-4596-b405-a7fe0168b39c_gui.jpg?width=690&amp;amp;upscale=false" alt=""&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;&#xD;
&lt;p&gt;I think if we combined our skills, we as a team could come up with a community based project that is better and cheaper than all options presented!&lt;/p&gt;&#xD;
&lt;p&gt;China could do cheap PCB's, We could build our own software!&lt;/p&gt;&#xD;
&lt;p&gt;We could find a cheap Microcontroller.&lt;/p&gt;&#xD;
&lt;p&gt;Let me know if you're keen to look into this!&lt;/p&gt;&#xD;
&lt;p&gt;&amp;nbsp;&amp;nbsp; Chris&amp;nbsp;&lt;/p&gt;</description>
      <pubDate>2017-09-30T21:18:26.6000000</pubDate>
      <link>https://www.aboveunity.com/thread/reliable-and-flexible-switching-system/</link>
    </item>
    <item>
      <title>Measurement Block PCB</title>
      <description>&lt;p&gt;My Friends,&lt;/p&gt;&#xD;
&lt;p&gt;Observing what your Voltage Current is doing in your Machine is super Important, I have said all along, look at your Currents! Your Current is where you get an idea on whats going on!&lt;/p&gt;&#xD;
&lt;p&gt;If you are interested in the Barebones PCB or a Kit, please visit E-Bay for purchase.&lt;/p&gt;&#xD;
&lt;p&gt;I have listed the&lt;/p&gt;&#xD;
&lt;h3&gt;&lt;a href="https://www.ebay.com.au/itm/Measurement-Block-Barebones-PCB/402133276080"&gt;Barebones PCB&lt;/a&gt;:&lt;/h3&gt;&#xD;
&lt;ul&gt;&#xD;
&lt;li&gt;Just a single PCB, you purchase the parts and build your self.&lt;/li&gt;&#xD;
&lt;/ul&gt;&#xD;
&lt;p style="text-align: center;"&gt;&lt;img src="/content/uploads/b5d8d256-5657-4ec2-ac7c-a741014a20b4/bedf2cfc-7e14-46ad-9c39-ab720093cd4d_barebones-pcb---front-standing-up.jpg?width=690&amp;amp;upscale=false" alt=""&gt;&lt;/p&gt;&#xD;
&lt;p style="text-align: center;"&gt;&lt;img src="/content/uploads/b5d8d256-5657-4ec2-ac7c-a741014a20b4/823f2bf3-cfd5-4477-9410-ab720093d608_barebones-pcb---one.jpg?width=690&amp;amp;upscale=false" alt=""&gt;&lt;/p&gt;&#xD;
&lt;p style="text-align: center;"&gt;&lt;img src="/content/uploads/b5d8d256-5657-4ec2-ac7c-a741014a20b4/fbb1d7e4-2091-4ac6-866d-ab720093dea3_barebones-pcb---back.jpg?width=690&amp;amp;upscale=false" alt=""&gt;&lt;/p&gt;&#xD;
&lt;p style="text-align: center;"&gt;&amp;nbsp;&lt;/p&gt;&#xD;
&lt;p style="text-align: left;"&gt;I also have the:&lt;/p&gt;&#xD;
&lt;h3 style="text-align: left;"&gt;&lt;a href="https://www.ebay.com.au/itm/Measurement-Block-Kit/402133301092"&gt;Measurement Block Kit&lt;/a&gt;:&lt;/h3&gt;&#xD;
&lt;ul&gt;&#xD;
&lt;li style="text-align: left;"&gt;2 x two pin terminal blocks.&lt;/li&gt;&#xD;
&lt;li style="text-align: left;"&gt;3 x Matrix PCB Pins.&lt;/li&gt;&#xD;
&lt;li style="text-align: left;"&gt;1 x Through Hole Resistor 0.1 Ohms 1% tolerance.&lt;/li&gt;&#xD;
&lt;li style="text-align: left;"&gt;1 x PCB for mounting the components.&lt;/li&gt;&#xD;
&lt;/ul&gt;&#xD;
&lt;p style="text-align: center;"&gt;&lt;img src="/content/uploads/b5d8d256-5657-4ec2-ac7c-a741014a20b4/6ac6f66f-e30d-4906-bf52-ab7200959769_measuremment-block---kit-parts.jpg?width=690&amp;amp;upscale=false" alt=""&gt;&lt;/p&gt;&#xD;
&lt;p style="text-align: center;"&gt;&lt;img src="/content/uploads/b5d8d256-5657-4ec2-ac7c-a741014a20b4/9d2003c1-a7c4-4a3b-8a3a-ab720095a119_measuremment-block---kit-compete.jpg?width=690&amp;amp;upscale=false" alt=""&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;&#xD;
&lt;p&gt;This Item has been one of my most useful of all. 5 Watts is the Maximum Power, but please remember if you are using Pulsed DC peak power can be higher. 5 Watts is constant power maximum.&lt;/p&gt;&#xD;
&lt;p&gt;The Resistor is rated as follows:&lt;/p&gt;&#xD;
&lt;p style="text-align: center;"&gt;&lt;img src="/content/uploads/b5d8d256-5657-4ec2-ac7c-a741014a20b4/569821a9-3265-433f-ae1a-ab65016a9c4b_measurement-bolck-resistor-specifications.jpg?width=690&amp;amp;upscale=false" alt=""&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;&#xD;
&lt;p&gt;All PCB's are based on the following Circuit:&lt;/p&gt;&#xD;
&lt;p style="text-align: center;"&gt;&lt;img src="/content/uploads/b5d8d256-5657-4ec2-ac7c-a741014a20b4/b6a7b056-f6dc-474f-8722-a8bd01577e81_measurement-block-schematic.jpg?width=690&amp;amp;upscale=false" alt=""&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;&#xD;
&lt;p&gt;Video Tutorial:&lt;/p&gt;&#xD;
&lt;p&gt;https://www.youtube.com/watch?v=ol-3VZJaqys&lt;/p&gt;&#xD;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;&#xD;
&lt;p&gt;If you want to, you can also round the corners of the board for rounded edges. Something I often do.&lt;/p&gt;&#xD;
&lt;p&gt;Best wishes,&lt;/p&gt;&#xD;
&lt;p&gt;&amp;nbsp; &amp;nbsp;Chris&lt;/p&gt;</description>
      <pubDate>2020-03-02T09:12:48.5470000</pubDate>
      <link>https://www.aboveunity.com/thread/measurement-block-pcb-and-kit-on-e-bay/</link>
    </item>
    <item>
      <title>Tinker's Scope Research</title>
      <description>&lt;p&gt;Hi All, not sure this is the spot for this post so please let me know.&amp;nbsp; I'm looking to source the necesary equipment to start my replications and experiments at looking at scope options.&amp;nbsp; I see the Rigol DS1104Z in a few videos which is great, just wondering given I'm new to this space if there is a more suitable option? Also what specs are a must have. Thanks in advance&amp;nbsp;&amp;nbsp;&lt;/p&gt;</description>
      <pubDate>2024-01-09T19:25:54.8270000</pubDate>
      <link>https://www.aboveunity.com/thread/tinker-s-scope-research/</link>
    </item>
    <item>
      <title>Oscilloscopes</title>
      <description>&lt;p&gt;For discussing&amp;nbsp;Oscilloscopes, Makes Models Prices, and How To's / Best Practices&lt;/p&gt;&#xD;
&lt;p&gt;https://www.youtube.com/watch?v=CzY2abWCVTY&lt;/p&gt;&#xD;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;</description>
      <pubDate>2017-05-08T07:30:10.1000000</pubDate>
      <link>https://www.aboveunity.com/thread/oscilloscopes/</link>
    </item>
    <item>
      <title>Camera Hack to make your Camera see Infrared!</title>
      <description>&lt;p&gt;My Friends,&lt;/p&gt;&#xD;
&lt;p&gt;I posted a small experiment, &lt;a href="../../thread/i-am-leaving-youtube-for-rumble/?order=all#comment-995e3e7d-71ec-4e15-90da-af8f0003cd95"&gt;Here&lt;/a&gt;, that converts your El Cheapo, budget Camera to see Infrared Spectrum.&lt;/p&gt;&#xD;
&lt;p&gt;The Infrared Spectrum is part of the Electromagnetic Spectrum:&lt;/p&gt;&#xD;
&lt;blockquote&gt;&#xD;
&lt;p&gt;&lt;img src="../../../content/uploads/b5d8d256-5657-4ec2-ac7c-a741014a20b4/c2206bdc-72f4-4739-8648-af8f0187d7e2_electromagnetic-spectrum.jpg?width=690&amp;amp;upscale=false" alt=""&gt;&lt;/p&gt;&#xD;
&lt;p&gt;The electromagnetic (EM) &lt;a class="glossaryDef" href="https://imagine.gsfc.nasa.gov/resources/dict_qz.html#spectrum"&gt;spectrum&lt;/a&gt;&amp;nbsp;is the range of all types of EM&amp;nbsp;&lt;a class="glossaryDef" href="https://imagine.gsfc.nasa.gov/resources/dict_qz.html#radiation"&gt;radiation&lt;/a&gt;. Radiation is energy that travels and spreads out as it goes &amp;ndash; the&amp;nbsp;&lt;a class="glossaryDef" href="https://imagine.gsfc.nasa.gov/resources/dict_qz.html#visible"&gt;visible light&lt;/a&gt;&amp;nbsp;that comes from a lamp in your house and the&amp;nbsp;&lt;a class="glossaryDef" href="https://imagine.gsfc.nasa.gov/resources/dict_qz.html#radio"&gt;radio&lt;/a&gt;&amp;nbsp;waves that come from a radio station are two types of electromagnetic radiation. The other types of EM radiation that make up the electromagnetic spectrum are&amp;nbsp;&lt;a class="glossaryDef" href="https://imagine.gsfc.nasa.gov/resources/dict_jp.html#microwave"&gt;microwaves&lt;/a&gt;,&amp;nbsp;&lt;a class="glossaryDef" href="https://imagine.gsfc.nasa.gov/resources/dict_ei.html#infrared"&gt;infrared light&lt;/a&gt;,&amp;nbsp;&lt;a class="glossaryDef" href="https://imagine.gsfc.nasa.gov/resources/dict_qz.html#ultraviolet"&gt;ultraviolet light&lt;/a&gt;,&amp;nbsp;&lt;a class="glossaryDef" href="https://imagine.gsfc.nasa.gov/resources/dict_qz.html#X_ray"&gt;X-rays&lt;/a&gt;&amp;nbsp;and&amp;nbsp;&lt;a class="glossaryDef" href="https://imagine.gsfc.nasa.gov/resources/dict_ei.html#gamma_ray"&gt;gamma-rays&lt;/a&gt;.&lt;/p&gt;&#xD;
&lt;/blockquote&gt;&#xD;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;&#xD;
&lt;p&gt;So with Infrared ( IR ) we can see Heat as Light. Most Camera Lens's are manufactured the same way, and have similar construction techniques:&lt;/p&gt;&#xD;
&lt;p&gt;&lt;img style="display: block; margin-left: auto; margin-right: auto;" src="../../../content/uploads/b5d8d256-5657-4ec2-ac7c-a741014a20b4/cd471714-f35a-4d8d-8a5e-af90001dfd2a_camera-lens-filters.jpg?width=690&amp;amp;upscale=false" alt=""&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;&#xD;
&lt;p&gt;Please Note: Some Camera's seem to work much better than others!&lt;/p&gt;&#xD;
&lt;p&gt;Initially, I was sceptical, and thought, no, it cant be this easy, but after I watched this video and thought I would try this experiment out:&lt;/p&gt;&#xD;
&lt;p&gt;https://youtu.be/IdJgxNVVrs4&lt;/p&gt;&#xD;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;&#xD;
&lt;p&gt;And yes, &lt;strong&gt;it does work&lt;/strong&gt;! I tried with two cameras, first was a very cheap webcam:&lt;/p&gt;&#xD;
&lt;p&gt;&lt;img style="display: block; margin-left: auto; margin-right: auto;" src="../../../content/uploads/b5d8d256-5657-4ec2-ac7c-a741014a20b4/cb6c6202-0881-4b0b-8d2d-af8f018ad840_budget-webcam.jpg?width=690&amp;amp;upscale=false" alt=""&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;img style="display: block; margin-left: auto; margin-right: auto;" src="../../../content/uploads/b5d8d256-5657-4ec2-ac7c-a741014a20b4/e563bcc5-b549-4faa-b1eb-af900010d561_20230120-101935.jpg?width=690&amp;amp;upscale=false" alt=""&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;img style="display: block; margin-left: auto; margin-right: auto;" src="../../../content/uploads/b5d8d256-5657-4ec2-ac7c-a741014a20b4/566fd0e2-64ea-4e57-9ab2-af900010f397_20230120-102013.jpg?width=690&amp;amp;upscale=false" alt=""&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;img style="display: block; margin-left: auto; margin-right: auto;" src="../../../content/uploads/b5d8d256-5657-4ec2-ac7c-a741014a20b4/17a9b25f-a2ef-4eca-a689-af9000111795_20230120-102226.jpg?width=690&amp;amp;upscale=false" alt=""&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;img style="display: block; margin-left: auto; margin-right: auto;" src="../../../content/uploads/b5d8d256-5657-4ec2-ac7c-a741014a20b4/ea299868-c756-4072-8a77-af9000112b4a_20230120-102048.jpg?width=690&amp;amp;upscale=false" alt=""&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;&#xD;
&lt;p&gt;The result:&lt;/p&gt;&#xD;
&lt;p&gt;&lt;img style="display: block; margin-left: auto; margin-right: auto;" src="../../../content/uploads/b5d8d256-5657-4ec2-ac7c-a741014a20b4/59c13bd7-6d22-4712-90f5-af900011a033_el-cheapo-washed-out-ir.jpg?width=690&amp;amp;upscale=false" alt=""&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;&#xD;
&lt;p&gt;and second was a little bit more expensive Microsoft Lifecam:&lt;/p&gt;&#xD;
&lt;p&gt;&lt;img style="display: block; margin-left: auto; margin-right: auto;" src="../../../content/uploads/b5d8d256-5657-4ec2-ac7c-a741014a20b4/6c80092f-1b74-4742-a99c-af8f018b1f59_microsoft-lifecam-cinema-hd.jpg?width=690&amp;amp;upscale=false" alt=""&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;img style="display: block; margin-left: auto; margin-right: auto;" src="../../../content/uploads/b5d8d256-5657-4ec2-ac7c-a741014a20b4/9c56cd99-f033-496a-9357-af900011d54b_20230120-102819.jpg?width=690&amp;amp;upscale=false" alt=""&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;img style="display: block; margin-left: auto; margin-right: auto;" src="../../../content/uploads/b5d8d256-5657-4ec2-ac7c-a741014a20b4/4f8b7766-4988-495c-a1d4-af90001208f0_20230120-102840.jpg?width=690&amp;amp;upscale=false" alt=""&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;img style="display: block; margin-left: auto; margin-right: auto;" src="../../../content/uploads/b5d8d256-5657-4ec2-ac7c-a741014a20b4/3e9a4d73-3569-4c32-9189-af900012366f_20230120-103009.jpg?width=690&amp;amp;upscale=false" alt=""&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;img style="display: block; margin-left: auto; margin-right: auto;" src="../../../content/uploads/b5d8d256-5657-4ec2-ac7c-a741014a20b4/4c24c8ed-2080-447b-9782-af90001266ea_20230120-103019.jpg?width=690&amp;amp;upscale=false" alt=""&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;img style="display: block; margin-left: auto; margin-right: auto;" src="../../../content/uploads/b5d8d256-5657-4ec2-ac7c-a741014a20b4/064f4e7f-febc-4580-8388-af900012ad2a_20230120-103313.jpg?width=690&amp;amp;upscale=false" alt=""&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;img style="display: block; margin-left: auto; margin-right: auto;" src="../../../content/uploads/b5d8d256-5657-4ec2-ac7c-a741014a20b4/35523e99-a421-4ce1-8ccf-af900012c4c0_20230120-102534.jpg?width=690&amp;amp;upscale=false" alt=""&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;img style="display: block; margin-left: auto; margin-right: auto;" src="../../../content/uploads/b5d8d256-5657-4ec2-ac7c-a741014a20b4/6e2fd280-eb43-4cae-81ac-af900012d968_20230120-103422.jpg?width=690&amp;amp;upscale=false" alt=""&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;&#xD;
&lt;p&gt;Both were quite easy to modify, the El Cheapo Webcam was a little easier, the Microsoft Lifecam was a little harder, but gave a much better result.&lt;/p&gt;&#xD;
&lt;p&gt;&lt;img style="display: block; margin-left: auto; margin-right: auto;" src="../../../content/uploads/b5d8d256-5657-4ec2-ac7c-a741014a20b4/07678a8c-c416-437d-84bc-af900012ef65_ms-lifecam-ir-image.jpg?width=690&amp;amp;upscale=false" alt=""&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;&#xD;
&lt;p&gt;And, a short video of an IR Reflecting Object moving with a very unorthodox Flight Path! Bird or a Plane, or?&lt;/p&gt;&#xD;
&lt;p&gt;&lt;video src="https://sp.rmbl.ws/s8/2/q/0/_/0/q0_0h.caa.mp4?u=0&amp;amp;b=0" poster="https://sp.rmbl.ws/s8/6/q/0/_/0/q0_0h.GxCc.jpg" controls="controls" width="300" height="150"&gt;&lt;/video&gt;&lt;/p&gt;&#xD;
&lt;p&gt;You can see, I have a mark, possibly some dirt, or a scratch on the lens that is showing as a blurry spot on the image.&lt;/p&gt;&#xD;
&lt;p&gt;Of course, the Focus is important, and a little difficult to achieve if the Lens are dirty or have finger prints on them, so keeping them clean and dust free is very important.&lt;/p&gt;&#xD;
&lt;p&gt;As a comparison, here is a video I watched, it shows a IR Convert, which seems to work exactly the same way and does take fantastic Images:&lt;/p&gt;&#xD;
&lt;p&gt;https://www.youtube.com/watch?v=W4s7bJFfLkc&lt;/p&gt;&#xD;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;&#xD;
&lt;p&gt;WOW, almost as good, with a budget dusty, dirty and an experiment on cheap rubbish cameras!&lt;/p&gt;&#xD;
&lt;p&gt;Of course, Coils or Electromagnets emit Electromagnetic Waves in the Spectrum we are observing today, but where do they fit? In the Low, all the way to High Frequency right?&lt;/p&gt;&#xD;
&lt;p&gt;Baerndorfer has shown some images of Coils in the IR Spectrum here:&lt;/p&gt;&#xD;
&lt;p&gt;&lt;img style="display: block; margin-left: auto; margin-right: auto;" src="../../../content/uploads/ff9976de-ff1c-40ab-8ea5-a9c200cdce0f/abe4b176-2a67-4e0a-9c43-adc000dcc05e_flir-20211013t140419.jpg?width=690&amp;amp;upscale=false"&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;&#xD;
&lt;p&gt;Is this a useful Hack, I think so!&lt;/p&gt;&#xD;
&lt;p&gt;Best Wishes,&lt;/p&gt;&#xD;
&lt;p&gt;&amp;nbsp; &amp;nbsp;Chris&lt;/p&gt;</description>
      <pubDate>2023-01-19T23:34:03.0570000</pubDate>
      <link>https://www.aboveunity.com/thread/camera-hack-to-make-your-camera-see-infrared/</link>
    </item>
    <item>
      <title>Developing a modular switching tool for Research</title>
      <description>&lt;p&gt;Hello All ,&lt;br&gt;In this thread I will present tool which is designed especially for researching and developing many devices threated here on the forum. It consists of three different modules(for the moment), and is very flexible. Many different topologies of switching can be easily assembled by combining the modules in different ways and with different setups and configurations. The signal source is a two phase PWM module with combined analogue and digital features. It is based on an enhanced 8bit MC, the PIC16F785 with specific peripherals, like a dual phase PWM module and two hi speed comparators, which are used for analogue duty cycle adjustment with infinite resolution. To overcome the limited period resolution typical for digital PWM devices, an adjustable external oscillator is used to clock the MC, which in combination with the pre-scaler allow an infinite period resolution over a wide range of frequencies as well. The second module is the switchboard, which is designed as single floating switch, which allows to assemble simple Hi or Lo side pulsing, half bridge or full bridge topology, or floating coil shorting as well as multiple other configurations as required.&lt;br&gt;The third module is the floating driver power supply, which provides a galvanically isolated supply for various switching drivers. In the thread we will discuss different solutions for specific applications. Schematics , images and videos on the development will be released as well as firmware and software solutions for specific requirements.&lt;/p&gt;</description>
      <pubDate>2019-05-12T15:05:35.0070000</pubDate>
      <link>https://www.aboveunity.com/thread/developing-a-modular-switching-tool-for-research/</link>
    </item>
    <item>
      <title>Square wave oscillator Off grid</title>
      <description>&lt;p&gt;Hi all&lt;br&gt;I would like to share with you this little square wave oscillator which works the same as a function generator and which operated on battery which can vary from 6, 9 or 12 volts DC according to your needs.&lt;/p&gt;&#xD;
&lt;p&gt;&lt;br&gt;The heart of the oscillator is a TLC555 from the CMOS series which has very low power consumption and is completely different from the old NE555.&lt;/p&gt;&#xD;
&lt;p&gt;&lt;img src="/content/uploads/461270c7-5267-4e25-a057-a73d00fcb2e0/81125d86-4fda-459b-8d93-ac160143232d_wp-20150113-22-59-34-pro.jpg?width=690&amp;amp;upscale=false" alt="" width="535" height="301"&gt;&lt;/p&gt;&#xD;
&lt;p&gt;It has a 10K potentiometer to vary the frequency from 13Khz to 130Khz and another 5K potentiometer to increase the amplitude of the signal at will.&lt;/p&gt;&#xD;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;&#xD;
&lt;p&gt;A drawing of the schematic that I present to you freehand&lt;/p&gt;&#xD;
&lt;p&gt;&lt;img src="/content/uploads/461270c7-5267-4e25-a057-a73d00fcb2e0/959db6a8-a831-4f72-bdce-ac1601437826_wp-20150113-22-58-27-pro.jpg?width=690&amp;amp;upscale=false" alt="" width="550" height="309"&gt;&lt;br&gt;It can be easily changed by changing a single resistor and a single capacitor.&lt;/p&gt;&#xD;
&lt;p&gt;&lt;img src="/content/uploads/461270c7-5267-4e25-a057-a73d00fcb2e0/a7c15834-1adc-4f7b-b008-ac160143b0b1_wp-20150113-22-58-17-pro.jpg?width=690&amp;amp;upscale=false" alt="" width="558" height="993"&gt;&lt;/p&gt;&#xD;
&lt;p&gt;5 ma on 9 volts battery here&lt;/p&gt;&#xD;
&lt;p&gt;&lt;br&gt;The particularity of this oscillator is that the output voltage changes from positive to negative through zero in the center. This is the AC square wave shape.&lt;/p&gt;&#xD;
&lt;p&gt;Most of these freely sold circuits are above zero volts they are only DC square wave and could not be use for experimentation.&lt;/p&gt;&#xD;
&lt;p&gt;&lt;img src="/content/uploads/461270c7-5267-4e25-a057-a73d00fcb2e0/6be5e062-2768-4e1a-bf0e-ac1601440c66_wp-20150113-23-00-17-pro.jpg?width=690&amp;amp;upscale=false" alt="" width="576" height="324"&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;img src="/content/uploads/461270c7-5267-4e25-a057-a73d00fcb2e0/f75805e6-938a-47ef-ae5d-ac1601465bcf_wp-20150113-22-57-59-pro-(2).jpg?width=690&amp;amp;upscale=false" alt="" width="594" height="334"&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;img src="/content/uploads/461270c7-5267-4e25-a057-a73d00fcb2e0/f346aa31-cc0c-4633-a4ab-ac1601469d02_wp-20150113-22-58-48-pro.jpg?width=690&amp;amp;upscale=false" alt="" width="603" height="339"&gt;&lt;/p&gt;&#xD;
&lt;p&gt;Very low or high amplitude at your choice&lt;/p&gt;&#xD;
&lt;p&gt;&lt;br&gt;This way you are isolated from the electrical network and have greater freedom of measurements without ground return.&lt;/p&gt;&#xD;
&lt;p&gt;&amp;nbsp;I also hope for those who would like to join us and experiment with us and do not have a function generator, this is the ideal opportunity, easy to assemble and inexpensive.&lt;/p&gt;&#xD;
&lt;p&gt;Jagau&lt;/p&gt;</description>
      <pubDate>2020-08-13T19:41:58.0330000</pubDate>
      <link>https://www.aboveunity.com/thread/square-wave-oscillator/</link>
    </item>
    <item>
      <title>Raivope's isolated switching circuit</title>
      <description>&lt;p&gt;This is galvanically isolated mosfet driver (one drv per mosfet) that uses very fast inductive coupling IL610 chip. Output is connected with 3pin array to mosfet module. 3 instead of 2 to have more mechanical stability.&lt;/p&gt;&#xD;
&lt;p&gt;6pin socket is my standard to use ribbon cable socket that has GND, +12V, +5V, and a signal. Then you can connect everything to CPU or whatever, add modules in between to limit the pulse - so everything is plug and play.&lt;/p&gt;&#xD;
&lt;p&gt;[EDIT: 20210901, updated the circuit]&lt;/p&gt;&#xD;
&lt;p&gt;&lt;img src="/content/uploads/5f210bf5-31ca-49ec-bfb4-aac7008f5dc7/2f941949-c9b5-4c9b-a098-ad96013f2e96_isolated-mosfet-drv.jpg?width=690&amp;amp;upscale=false" alt=""&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;img src="/content/uploads/5f210bf5-31ca-49ec-bfb4-aac7008f5dc7/5669eea1-fac7-43c2-b4b3-aaf400816815_isol-mosf-drv.jpg?width=690&amp;amp;upscale=false" alt=""&gt;&lt;/p&gt;</description>
      <pubDate>2019-10-28T20:05:50.9730000</pubDate>
      <link>https://www.aboveunity.com/thread/raivope-s-isolated-switching-circuit/</link>
    </item>
    <item>
      <title>Halfbridge Circuit based on IR2104</title>
      <description>&lt;p&gt;Some time ago i designed a switching circuit for my experiments. Because it works so well i like to show it and maybe someone will find it useful too.&lt;/p&gt;&#xD;
&lt;p&gt;&lt;img src="/content/uploads/ff9976de-ff1c-40ab-8ea5-a9c200cdce0f/d7f63874-f6ce-4494-8b65-aba2009aee77_schematic-halfbridge-circuit-(ir2104pbf,-2n60s5)-reva-pulser-v1.2-20200419111440.jpg?width=690&amp;amp;upscale=false" alt=""&gt;&lt;/p&gt;&#xD;
&lt;p&gt;The 2104 is not a fast driver but if your point of interest is between 10 and 100kHz this pcb will do a great job. Frequency and duty cycle are adjustable with buttons and can be configured within the software.&lt;/p&gt;&#xD;
&lt;p&gt;&lt;img src="/content/uploads/ff9976de-ff1c-40ab-8ea5-a9c200cdce0f/29124da6-bf0d-47c8-ad8c-aba2009df674_pcb-reva-pulser-v1.24-20200419111600.jpg?width=690&amp;amp;upscale=false" alt=""&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;img src="/content/uploads/ff9976de-ff1c-40ab-8ea5-a9c200cdce0f/78febb27-c630-4ac3-9ac3-aba200a0c274_screenshot-from-2020-04-19-11-44-46.jpg?width=690&amp;amp;upscale=false" alt=""&gt;&lt;/p&gt;&#xD;
&lt;p&gt;I attached the GERBER file if you like to make one for yourself. If you need the software i will provide the INO-file as well.&lt;/p&gt;</description>
      <pubDate>2020-04-19T09:54:33.8170000</pubDate>
      <link>https://www.aboveunity.com/thread/halfbridge-circuit-based-on-ir2104/</link>
    </item>
    <item>
      <title>Tech 15001K DIY Digital Oscilloscope Kit</title>
      <description>&lt;p&gt;&amp;gt;If they only knew about Partnered Output Coils! The Cost! WOW! The dismantling when it comes time to retire is phenomenal! I am at a loss to believe why so much money would be spent on such things, then the cabling into the Grid! The alternative (for them) would be to dismantle... Everything. Back to the topic, is a 'pocket' oscilloscope (e.g. https://m.aliexpress.com/item/32974331378.html?src=google&amp;amp;_randl_currency=GBP&amp;amp;_randl_shipto=GB&amp;amp;src=google&amp;amp;albch=shopping&amp;amp;acnt=494-037-6276&amp;amp;isdl=y&amp;amp;slnk=&amp;amp;plac=&amp;amp;mtctp=&amp;amp;albbt=Google_7_shopping&amp;amp;aff_platform=google&amp;amp;aff_short_key=UneMJZVf&amp;amp;gclsrc=aw.ds&amp;amp;&amp;amp;albagn=888888&amp;amp;albcp=1622677378&amp;amp;albag=57224001810&amp;amp;trgt=743612850714&amp;amp;crea=en32974331378&amp;amp;netw=u&amp;amp;device=m&amp;amp;gclid=EAIaIQobChMIpv2ruNyQ6AIVhsjeCh3CiAKzEAkYDyABEgIMp_D_BwE worth bothering with, or are there other ways of visualising waveforms while I save for a full size one? (recommendations welcome)&lt;/p&gt;</description>
      <pubDate>2020-03-10T22:52:55.3770000</pubDate>
      <link>https://www.aboveunity.com/thread/tech-15001k-diy-digital-oscilloscope-kit/</link>
    </item>
    <item>
      <title>4 Channel Isolated Mosfet PCB For Sale, Any Interest?</title>
      <description>&lt;p&gt;My Friends,&lt;/p&gt;&#xD;
&lt;p&gt;Please Note: We have a thread:&amp;nbsp;&lt;a href="/thread/reliable-and-flexible-switching-system/?postbadges=true"&gt;Reliable and Flexible Switching System&lt;/a&gt;&amp;nbsp;we go into a lot of detail there.&lt;/p&gt;&#xD;
&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; This Circuit is not mine to sell! However, I am not Selling the Circuit, I am looking into selling the PCB.&lt;/p&gt;&#xD;
&lt;p&gt;This thread is to see if others are interested in purchasing a PCB Only? If others are interested, I am happy to share my design and layout, a copy of the Quadratron by AR and GR, now called the &lt;a href="http://www.tantratron.tk/technical-center/open-source.html"&gt;IPC-quadra&lt;/a&gt;:&lt;/p&gt;&#xD;
&lt;p style="text-align: center;"&gt;&lt;img src="/content/uploads/b5d8d256-5657-4ec2-ac7c-a741014a20b4/610d463f-fb28-437b-8c2e-a7fe015ef054_quadratron-circuit-v2.jpg?width=690&amp;amp;upscale=false" alt=""&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;strong&gt;Please Note:&lt;/strong&gt; I have made some important modifications, my circuit is based on, but not the same as the &lt;a href="http://www.tantratron.tk/technical-center/open-source.html"&gt; IPC-quadra&lt;/a&gt;&amp;nbsp;or the&amp;nbsp;Quadratron by AR and GR:&lt;/p&gt;&#xD;
&lt;p style="text-align: center;"&gt;&lt;img src="/content/uploads/b5d8d256-5657-4ec2-ac7c-a741014a20b4/d96043b1-05d6-412e-801b-ab180176bbc3_circuit.jpg?width=690&amp;amp;upscale=false" alt=""&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;&#xD;
&lt;p&gt;I am NOT selling the Circuit, I am looking at selling a professionally built PCB Only! If there is enough interest.&lt;/p&gt;&#xD;
&lt;p style="text-align: center;"&gt;&lt;img src="/content/uploads/b5d8d256-5657-4ec2-ac7c-a741014a20b4/5cfa6a3b-bf03-405f-b328-ab1701479e95_20191203-054927.jpg?width=690&amp;amp;upscale=false" alt=""&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;&#xD;
&lt;p&gt;I see more and more, in need for a&amp;nbsp;Reliable and Flexible Switching System, so if I see enough interest, I am happy to sell others the PCB and they can purchase and assemble.&lt;/p&gt;&#xD;
&lt;p&gt;I am not a business person, not by any means, but when I do things, I like to try and do things properly. We are now up to version 3.0 of the&amp;nbsp;Reliable and Flexible Switching System, version 2.0 seen here:&lt;/p&gt;&#xD;
&lt;p style="text-align: center;"&gt;&lt;img src="/content/uploads/b5d8d256-5657-4ec2-ac7c-a741014a20b4/3219d3bb-a6fc-441b-8689-ab1b00399c48_20191206-132823.jpg?width=690&amp;amp;upscale=false" alt=""&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;&#xD;
&lt;p&gt;If others are interested, I am thinking of selling the PCB Only. Not selling the Circuit! I am only thinking about selling the PCB and the Layout on the PCB. If there is not enough interest, I will not sell the PCB's and others can copy my circuits and source their own PCB's and parts and assemble themselves.&lt;/p&gt;&#xD;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;strong&gt;IMPORTANT:&lt;/strong&gt; If you purchase the PCB, this means you purchase the parts separately and Assemble yourself!&lt;/p&gt;&#xD;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;&#xD;
&lt;p&gt;This is V.3.0 in design:&lt;/p&gt;&#xD;
&lt;p style="text-align: center;"&gt;&lt;img src="/content/uploads/b5d8d256-5657-4ec2-ac7c-a741014a20b4/eb10f27e-1f08-4e2e-b2cb-ab64000e8db2_h-bridge.jpg?width=690&amp;amp;upscale=false" alt=""&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;&#xD;
&lt;p&gt;You can see, its smaller, more compact, and tidier.&lt;/p&gt;&#xD;
&lt;p&gt;V.2.0 Specs:&lt;/p&gt;&#xD;
&lt;ul&gt;&#xD;
&lt;li&gt;Width: 133mm&lt;/li&gt;&#xD;
&lt;li&gt;Length: 130mm&lt;/li&gt;&#xD;
&lt;li&gt;Single sided PCB, single sided tracks.&lt;/li&gt;&#xD;
&lt;li&gt;RF Isolation.&lt;/li&gt;&#xD;
&lt;/ul&gt;&#xD;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;&#xD;
&lt;p&gt;V.3.0 Specs:&lt;/p&gt;&#xD;
&lt;ul&gt;&#xD;
&lt;li&gt;Width:128mm&lt;/li&gt;&#xD;
&lt;li&gt;Length: 124mm&lt;/li&gt;&#xD;
&lt;li&gt;Double sided PCB, Dual Tracks.&lt;/li&gt;&#xD;
&lt;li&gt;RF isolation&lt;/li&gt;&#xD;
&lt;/ul&gt;&#xD;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;&#xD;
&lt;p&gt;Please post below if you are interested and let me know if you are interested. Price wise, including post may vary, but the PCB may be around the $25.00 mark. This could change, depending on investigations.&lt;/p&gt;&#xD;
&lt;p&gt;Vidura is also selling Switching Tool &lt;a href="/thread/developing-a-modular-switching-tool-for-research/"&gt;here&lt;/a&gt;.&lt;/p&gt;&#xD;
&lt;p&gt;Best Wishes,&lt;/p&gt;&#xD;
&lt;p&gt;&amp;nbsp; &amp;nbsp;Chris&lt;/p&gt;</description>
      <pubDate>2020-02-17T00:46:26.3630000</pubDate>
      <link>https://www.aboveunity.com/thread/any-interest-in-a-reliable-and-flexible-switching-system/</link>
    </item>
    <item>
      <title>Parallax Propeller microcontroller</title>
      <description>&lt;p&gt;Maybe the following info is useful for builders who are using microcontrollers to control e.g. pulse timing:&lt;/p&gt;&#xD;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;&#xD;
&lt;p&gt;i'm using the Parallax Propeller chip for some years now. I also use other platforms like Arduino or Raspberry Pi, but if i need exact timing i always use the Propeller.&lt;/p&gt;&#xD;
&lt;p&gt;It's not like a 'normal' microcontroller. It has 8 cores (called 'cogs') which are running completely parallel and more or less independent from each other at 80 MHz (although they can be synchronized through a 'hub'). Every cog has 2 timer/counter modules which also include a PLL. With these timer/counter modules it's possible to get high-resolution timing with down to 10 ns resolution, it's possible to generate frequencies with up to 9 digits resolution, and it's even possible to generate high-resolution video signals. Even such crazy things like a TV transmitter is possible, the only additional hardware needed is a short wire on a port pin acting as an antenna.&amp;nbsp; &lt;img src="/scripts/tinymce/plugins/emoticons/img/smiley-laughing.gif" alt="laughing"&gt;&lt;/p&gt;&#xD;
&lt;p&gt;The chip costs about 8$ is available as DIL-40 or SMD version. You only need a 5 MHz crystal and a serial EEPROM to get it running. It has a built-in bootloader which loads the code from ext. EEPROM or from serial interface at every startup.&lt;/p&gt;&#xD;
&lt;p&gt;I highly recommend looking at the documentation:&lt;/p&gt;&#xD;
&lt;p&gt;&lt;a href="https://www.parallax.com/sites/default/files/downloads/P8X32A-Propeller-Datasheet-v1.4.0_0.pdf"&gt;Propeller Data sheet&lt;/a&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;a href="https://www.parallax.com/sites/default/files/downloads/AN001-P8X32ACounters-v2.0.pdf"&gt;Timer/Counter module description&lt;/a&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;a href="https://www.parallax.com/sites/default/files/downloads/P8X32A-Web-PropellerManual-v1.2.pdf"&gt;Propeller Manual&lt;/a&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;a href="https://www.parallax.com/catalog/microcontrollers/propeller"&gt;Parallax Website&lt;/a&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;&#xD;
&lt;p&gt;Using it requires some different thinking if you have used 'normal' controllers in the past, but everything is logical and you will get good results very quick. Then you wonder how you could live without it in the past.&amp;nbsp; &lt;img src="/scripts/tinymce/plugins/emoticons/img/smiley-wink.gif" alt="wink"&gt;&lt;/p&gt;&#xD;
&lt;p&gt;If you have any questions feel free to ask.&amp;nbsp; &lt;img src="/scripts/tinymce/plugins/emoticons/img/smiley-cool.gif" alt="cool"&gt;&lt;/p&gt;</description>
      <pubDate>2020-01-02T22:51:08.2070000</pubDate>
      <link>https://www.aboveunity.com/thread/parallax-propeller-controller/</link>
    </item>
    <item>
      <title>Dual phase PWM</title>
      <description>&lt;p&gt;This Is a Project I am working on actually for a dual phase PWM with combined analogue and digital features. It is based on an enhanced 8bit MC, the PIC16F785 with specific peripherals, like a dual phase PWM module and two hi speed comparators, which are used for analogue duty cycle adjustment with infinite resolution. This MC can run on different internal and external oscillator sources, up to 20Mhz, the PWM clock is derived from the system clock, theoretical up to a maximum of 2,5Mhz; practically with reasonable resolution i have tested up to 200Khz with this MC. To overcome the limited period resolution I will use an adjustable external oscillator to clock the MC, which in combination with the pre-and post-scaler in software should allow an infinite period resolution over a wide range of frequencies as well. This features I believe will be helpful to drive resonant LCR circuits, using half- or full-bridge switches with the possibility to trigger magnetic resonance. The signals can be configured as free running two phase signal with independent adjustable duty cycles, or as complementary drive signals with programmable deadtime or overlapping. A synchronization feature allows to connect various MC in parallel in order to add more phases if needed.&lt;br&gt;In a first stage I will build the circuit on stripboard and test to find the appropriated values for the discrete components and work out the source code. For the moment the work and progress will be posted here in Tier II, participation and suggestions are welcome as always. If a useful tool results from this work it will be released as open source. This first schematic is a draft, to be improved while developing and testing is going on. &lt;img src="/content/uploads/7e39693d-7479-4625-ad7b-a8e400160f94/08711985-63e6-48a8-ade8-aa2300053300_dualphasepwm.jpg?width=690&amp;amp;upscale=false" alt=""&gt;&lt;/p&gt;</description>
      <pubDate>2019-04-02T00:19:10.5100000</pubDate>
      <link>https://www.aboveunity.com/thread/dual-phase-pwm/</link>
    </item>
    <item>
      <title>Addition on Charge Separation</title>
      <description>&lt;p&gt;here some more information , that I think could be relevant on the Charge Separation topic. I post it on Tier II becaus it seems to be that Sergey had some Troll Issues ,&amp;nbsp; reason why he covered the exiter inductor in his experiments with a paper.&amp;nbsp;&lt;/p&gt;&#xD;
&lt;p&gt;He developed this device first as a SS. spark gap replacement. Here is the translated doc attached:&lt;/p&gt;</description>
      <pubDate>2019-02-24T16:08:00.4300000</pubDate>
      <link>https://www.aboveunity.com/thread/addition-on-charge-separation/</link>
    </item>
    <item>
      <title>Fastest 555 timer</title>
      <description>&lt;p&gt;Here's a Hackaday article about a 555-like circuit which operates high in the MHz region... with a pretty square wave at 50 MHz, and the waveform becoming noisier at higher frequencies.&lt;/p&gt;&#xD;
&lt;p&gt;https://hackaday.com/2019/03/25/the-worlds-fastest-555-timer-and-the-state-of-the-555/&lt;/p&gt;&#xD;
&lt;p&gt;&lt;img src="https://hackadaycom.files.wordpress.com/2019/03/ff555-outputs.png"&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;</description>
      <pubDate>2019-03-28T01:22:11.8500000</pubDate>
      <link>https://www.aboveunity.com/thread/fastest-555-timer/</link>
    </item>
    <item>
      <title>practical hardware tips</title>
      <description>&lt;p&gt;Hello,&amp;nbsp;&lt;/p&gt;&#xD;
&lt;p&gt;this topic is intented to post practical solutions for hardware, circiuts and more.&lt;/p&gt;&#xD;
&lt;p&gt;As i was working on a new powerstage for my pulsmotor project i made a short video about a quick solution for simple circuit boards. It's not a great deal, but can be quite useable in some cases.I also want to invite all builders to post their solutions for hardware building .&lt;/p&gt;&#xD;
&lt;p&gt;https://www.youtube.com/watch?v=OlcggP9QxJg&lt;/p&gt;</description>
      <pubDate>2018-05-29T15:47:31.4800000</pubDate>
      <link>https://www.aboveunity.com/thread/practical-hardware-tips/</link>
    </item>
    <item>
      <title>Rectangular NiFe wire supplier?</title>
      <description>&lt;p&gt;Hi, all.&lt;/p&gt;&#xD;
&lt;p&gt;Ok, I'm getting frustrated. My flux-switching transformer experiment is predicated upon utilizing the unique magnetic properties of a 48% Nickel, 52% Iron wire with specific annealing.&lt;/p&gt;&#xD;
&lt;p&gt;I've tried pretty much every wire manufacturer I can find on Google... either they don't manufacture the wire in the alloy I need, or they only make round wire, or they can't anneal it properly, or they can only supply bare wire, or they want me to buy production-scale quantities.&lt;/p&gt;&#xD;
&lt;p&gt;How do other researchers get wire with custom properties manufactured? Does anyone know of a manufacturer that can help me?&lt;/p&gt;&#xD;
&lt;p&gt;The wire is Ni48Fe (binary alloy of 48% Nickel and 52% Iron, sized 0.5mm x 4.0mm, with the annealing process as follows: Dry-hydrogen annealed (4 hours at 1175 C, cooled for 9.5 hours in the furnace at a rate of 50 C/hr, hold at 700 C for 1 hour, then cooled at 1500 C / minute).&lt;/p&gt;&#xD;
&lt;p&gt;This imparts specific magnetic properties to the wire which is needed for this experiment.&lt;/p&gt;&#xD;
&lt;p&gt;The wire must have insulation with high dielectric strength. PTFE should fill the bill.&lt;/p&gt;&#xD;
&lt;p&gt;I'm looking for a 25 kg spool, although if need be, I can go as high as 50 kg.&lt;/p&gt;</description>
      <pubDate>2019-01-09T00:19:16.5130000</pubDate>
      <link>https://www.aboveunity.com/thread/rectangular-nife-wire-supplier/</link>
    </item>
    <item>
      <title>Function Generators</title>
      <description>&lt;p&gt;For discussing Function Generators, Makes Models Prices, and How To's / Best Practices&lt;/p&gt;&#xD;
&lt;p&gt;https://www.youtube.com/watch?v=mLKPwWGBtIw&lt;/p&gt;</description>
      <pubDate>2017-05-08T07:32:37.4900000</pubDate>
      <link>https://www.aboveunity.com/thread/function-generators/</link>
    </item>
    <item>
      <title>Anyone ever heard of this HV amplifier?</title>
      <description>&lt;p&gt;I found a high-voltage amplifier for sale. It's an old one, but it's specifically designed for function generator input.&lt;/p&gt;&#xD;
&lt;p&gt;There doesn't appear to be any manufacturer shown on the chassis, it's just got "&lt;strong&gt;M606A HV-AMP&lt;/strong&gt;" printed on the front panel.&lt;/p&gt;&#xD;
&lt;p&gt;Has anyone heard of or does anyone know about this function generator amplifier's specs?&lt;/p&gt;&#xD;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;</description>
      <pubDate>2018-11-11T09:24:12.2300000</pubDate>
      <link>https://www.aboveunity.com/thread/anyone-ever-heard-of-this-hv-amplifier/</link>
    </item>
    <item>
      <title>VFD rather than power amplifier?</title>
      <description>&lt;p&gt;So I continue sourcing components to build my electronics experimentation workbench (including the workbench itself).&lt;/p&gt;&#xD;
&lt;p&gt;I think I'm going to go with the&amp;nbsp;Analog Arts SL937 oscilloscope / function generator,&lt;/p&gt;&#xD;
&lt;p&gt;But I'm coming up short on a power amplifier that can output at a sufficient frequency, voltage and wattage while driving an inductive load (most are designed solely for resistive or capacitive loads... and a tiny capacitance at that).&lt;/p&gt;&#xD;
&lt;p&gt;Most of them only have +-100 volts or less, 2 amps or less, and 100 KHz or less. I'm not so concerned about the frequency, as the inductive testing I'll be doing will be at lower frequencies.&lt;/p&gt;&#xD;
&lt;p&gt;So I got to thinking about it... a VFD is essentially a waveform generator coupled to a PWM power amplifier, and they can drive inductive loads (motors) at high voltage and amperage, at a continuously variable frequency.&lt;/p&gt;&#xD;
&lt;p&gt;So I could drive the inductive loads via a VFD and merely use the SL937 as an oscilloscope. I can pick up a sufficiently sized VFD for a few hundred dollars.&lt;/p&gt;&#xD;
&lt;p&gt;Then once I've got the VFD voltage and frequency dialed in such that the device works the way I want, I can design a standalone circuit which mimics that voltage and frequency.&lt;/p&gt;&#xD;
&lt;p&gt;The only downside is that I'd be working solely with sinewaves, rather than the arbitrary waveforms that the SL937 can generate.&lt;/p&gt;&#xD;
&lt;p&gt;What do you think?&lt;/p&gt;&#xD;
&lt;p&gt;My first idea is to create a miniaturized version of a motion-EMF generator, and package it into one of those USB charger wall warts, sans the 120 V plug blades. It'd be an "infinity battery" to charge cell phones and such.&lt;/p&gt;&#xD;
&lt;p&gt;As an aside... if you're looking for load resistors that can handle a lot of power, look for the VFD dynamic braking replacement resistors... they have them available up to 185 KW (~$1230). The 1000 W resistors should be good for our testing, and they're relatively cheap (~$79 at Automation Direct).&lt;/p&gt;&#xD;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;</description>
      <pubDate>2018-11-08T02:35:44.3030000</pubDate>
      <link>https://www.aboveunity.com/thread/vfd-rather-than-power-amplifier/</link>
    </item>
    <item>
      <title>Arduino Aquaponics</title>
      <description>&lt;p&gt;I don't know if anyone is interested in growing their own food and vegetables but this Aquaponic system i have built works just perfect. i am i newbie when it comes to programming and i am sure someone could do better but all i can say is it works and works very darn well. i studied Arduino platform for a few weeks and the two programs are the start up which runs for 10 days and the run program cycles 8.5 times in 24 hours.&lt;/p&gt;&#xD;
&lt;p&gt;it uses AC as back up only utilizing the light out function on a charge controller at 24 volts and two solar panels supplying all the power to the system. it has an air pump that is on 24/7 with a water pump on for 8 times in 24 hours and two 24 volt solenoid valves on for 15 minutes every 2 hours. the whole system only takes 60 watts for the air pump @ 24/7, the water pump @ 80 watts for 5 minutes every 2 plus hours and each solenoid valve are on at separate times for 15 minutes every 2 plus hours @ 12.5 watts each.&lt;/p&gt;&#xD;
&lt;p&gt;i have built two systems near my house for people and they are very happy i designed the system and helped them build it. i made a few bucks off of it but not much. and yes i know aerate is spelled wrong.&lt;/p&gt;&#xD;
&lt;p&gt;the system in the video was before i installed it into it's permanent home. the LED lights indicate that stage complete which is LED 1 -5 with the red blinking LED shown upcoming stage. turning the sound up you will hear the relays clicking on and off working flawlessly.&lt;/p&gt;&#xD;
&lt;p&gt;https://www.youtube.com/watch?v=qEfW0Pd-h3o&lt;/p&gt;&#xD;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;&#xD;
&lt;p&gt;Marathonman&lt;/p&gt;</description>
      <pubDate>2018-05-27T03:36:21.3030000</pubDate>
      <link>https://www.aboveunity.com/thread/arduino-aquaponics/</link>
    </item>
    <item>
      <title>DSO Rigol DS1054Z - Unlock all factory options</title>
      <description>&lt;p&gt;&lt;img src="https://www.batronix.com/images/generated/ds1054z-front-1150x728-White-min.jpg?width=690" alt="" width="512" height="324"&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;img src="https://www.batronix.com/images/generated/deepmemory-800x480-White-min.jpg?width=690" alt="" width="512" height="307"&gt;&lt;/p&gt;&#xD;
&lt;p&gt;&lt;img src="https://www.batronix.com/images/generated/decoder-800x480-White-min.jpg?width=690" alt="" width="512" height="307"&gt;&lt;/p&gt;&#xD;
&lt;p&gt;Great little program &lt;strong&gt;&lt;span class="auto-style1"&gt;Riglol 1.03d&amp;nbsp;&lt;/span&gt;&lt;/strong&gt;unlock all factory disabled options in Rigol DS1054Z DSO. Also can unlock Rigol DS2xxx and Rigol DS4xxx oscilloscopes. Options are Serial Decoder, AT-DS1000Z Advanced Trigger, Memory Option, Record-Module.&lt;/p&gt;&#xD;
&lt;p&gt;Donwload program from here or use online unlocking.&lt;/p&gt;&#xD;
&lt;p&gt;&lt;span class="auto-style1"&gt;Riglol 1.03d --&amp;gt; &lt;/span&gt;http://gotroot.ca/rigol/riglol/riglol.zip&lt;/p&gt;&#xD;
&lt;p&gt;For Rigol DS1054Z, 4 channel DSO 100MHz bandwidth 1 GSa/s, with 30.000 wfms/s refresh rate, use option &lt;strong&gt;DSER&lt;/strong&gt;, not &lt;span style="text-decoration: line-through;"&gt;&lt;strong&gt;DSFR&lt;/strong&gt; &lt;/span&gt;becaue &lt;strong&gt;DSBA&lt;/strong&gt; option unlock 500uV vertical resolution only hardware implemented in DS2xxx and DS4xxx.&lt;/p&gt;&#xD;
&lt;p&gt;You need only enter at Options: DSER and Serial number of your DSO, marked at backside of box. After small procedure you will get full 4 channel DS1104Z 100MHz DSO ready for experiments. Private key is auto generated for unlock code generation.&lt;/p&gt;&#xD;
&lt;p&gt;Price for Rigol DS1054Z is &amp;euro; 403.41 in batronix.com&lt;/p&gt;&#xD;
&lt;p&gt;Price for Rigol DS1104Z is &amp;euro; 689.&lt;/p&gt;&#xD;
&lt;p&gt;If you buy some of DS2xxx with 2 GSa/s you can unlock 500uV vertical resolution and get 300MHz bandwidth.&lt;/p&gt;&#xD;
&lt;p&gt;For DS 4xxx you will get 500MHz bandwidth with 500 uV resolution, 14 Mpts memory depth and 2 GSa/s per channel.&lt;/p&gt;&#xD;
&lt;p&gt;https://www.batronix.com/shop/oscilloscopes/DSO.html&lt;/p&gt;&#xD;
&lt;p&gt;------------------------------------------------------------------------&lt;/p&gt;&#xD;
&lt;p&gt;Regards&lt;/p&gt;&#xD;
&lt;p&gt;Enjoykin&lt;/p&gt;&#xD;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;</description>
      <pubDate>2018-05-31T19:16:06.5370000</pubDate>
      <link>https://www.aboveunity.com/thread/dso-rigol-ds1054z-unlock-all-factory-options/</link>
    </item>
    <item>
      <title>Overunity Vacuum Tubes</title>
      <description>&lt;p&gt;Hi, guys. I have recently become a member here on Above Unity forum, and this is my very first post. I have followed Chris channel on You Tube for a long time, and the minute when i saw that he had an alternative to the other forums, like Overunity, for example i just had to register here. &lt;img src="/content/images/emoticons/facebook-smiley-face-for-comments.png" alt="" class="emoticon" /&gt; It seems like you really have a good thing going here.&lt;/p&gt;&#xD;
&lt;p&gt;Anyway, i am kind of new to all this that we are talking about here. I have only been tinkering with electronics for a few years, and recently i got my hands on a Ultron ECL 85 vacuum tube, and i thought that i was going to see if i could do something cool with it.&lt;/p&gt;&#xD;
&lt;p&gt;I am fascinated with RF, and Dr Stifflers work, so i was thinking if it would be possible to use this tube instead of the MPSA06/2N2222 transistor, or maybe something else like that.&lt;/p&gt;&#xD;
&lt;p&gt;What do you guys think?&lt;/p&gt;&#xD;
&lt;p&gt;I bearly get transistors, so i am in the process of reading a book about Electron tubes, so i wanted to ask you guys here on, if there are anybody that have experience working with, or have thought about using vacuum tubes in your devices?&lt;/p&gt;&#xD;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;&#xD;
&lt;p&gt;Ps. I know this forum is almost all dedicated to POC, but this may be applicable to POC too in some way, so i hope it is ok that i post this thread.&lt;/p&gt;&#xD;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;&#xD;
&lt;p&gt;Thanks guys. /&lt;/p&gt;</description>
      <pubDate>2018-02-28T12:14:18.1670000</pubDate>
      <link>https://www.aboveunity.com/thread/overunity-vacuum-tubes/</link>
    </item>
    <item>
      <title>Art of Brovin's Katscher -Two parts unipolar generator</title>
      <description>&lt;p&gt;Everything is in video. One transistor, one coil and whole unipolar generator is here. Magic ? No, but deep knowledge&lt;/p&gt;&#xD;
&lt;p&gt;https://www.youtube.com/watch?v=X6KpexAMw88&lt;/p&gt;&#xD;
&lt;p&gt;https://www.youtube.com/watch?v=VlNHSu4rprI&lt;/p&gt;&#xD;
&lt;p&gt;Brovin's Katscher&lt;br&gt;https://yadi.sk/d/WbpBln2BdaFz3&lt;/p&gt;&#xD;
&lt;p&gt;Aloha&lt;/p&gt;&#xD;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;&#xD;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;</description>
      <pubDate>2017-08-28T03:46:32.0930000</pubDate>
      <link>https://www.aboveunity.com/thread/art-of-brovin-s-katchers-two-parts-unipolar-generator/</link>
    </item>
    <item>
      <title>Zanzal's Free Arduino/AVR Code</title>
      <description>&lt;p&gt;I am going to use this thread to post free code that others can use or customize as they wish.&amp;nbsp;&lt;/p&gt;&#xD;
&lt;p&gt;Attached is a software PWM snippet I worked on last night. The software PWM has some advantages over the Hardware PWM. It can be used to program&amp;nbsp;more complex waveforms than the Arduino can normally produce and has good quality up to about 3 Khz. It will go higher, 100Khz+, but like any software PWM it has the usual limitations which is&amp;nbsp;precision and the higher it goes the less precise the frequency and duty cycle you are requesting. I specifically wrote this one to produce as little "jitter" as possible. While it is not reasonable to expect a 16Mhz 8-bit device to produce perfect high frequency wave forms. It can be improved by running at higher Mhz and recoding it in assembly, however, there are limits to how perfect these improvements can be. Also, this is not the best implementation of a AVR software PWM, but rather it was the implementation that I needed for my purposes..&lt;/p&gt;</description>
      <pubDate>2017-08-22T19:52:33.3900000</pubDate>
      <link>https://www.aboveunity.com/thread/zanzal-s-free-arduino-avr-code/</link>
    </item>
    <item>
      <title>.NET Microframework for Microcontrollers</title>
      <description>&lt;p&gt;I would like to share knowledge on Microcontrollers here also. I think Microcontrollers are an essential part of&amp;nbsp;our Tool Kit.&lt;/p&gt;&#xD;
&lt;p&gt;I have spent some time on the .NET Microframework, many MPU/MCU's one of my favorite being STM32 series. A very powerful series as many are today.&lt;/p&gt;&#xD;
&lt;p&gt;I have also spent some time on Beaglebone and Arduino, as many have. We are very spoiled today with the features that Microcontrollers posses!&lt;/p&gt;&#xD;
&lt;p&gt;So, if youre using Microcontrollers as part of your Toolkit, and if you want to share knowledge and ideas, please post to the Hardware Thread!&lt;/p&gt;&#xD;
&lt;p&gt;Some code attached below:&lt;/p&gt;&#xD;
&lt;p&gt;&amp;nbsp;&amp;nbsp; Chris&lt;/p&gt;</description>
      <pubDate>2017-05-29T21:58:22.5900000</pubDate>
      <link>https://www.aboveunity.com/thread/net-microframework-for-microcontrollers/</link>
    </item>
  </channel>
</rss>