Andrey_B, Спасибо. Вот, что советует ИИ DeepSeek.
Рекомендуемый метод: Квадратурное детектирование (I/Q Demodulation)
Почему он лучше подходит для вашего случая:
Высокая точность на фиксированной частоте (1 кГц).
Устойчивость к шумам (фильтрация через синхронное детектирование).
Проще реализовать на STM32, чем полный FFT.
Позволяет сразу получить R и X без сложных расчётов.
Алгоритм расчёта
1. Захват сигналов
Синхронно снимаем:
V_adc[n] (разница двух каналов напряжения)
I_adc[n] (сигнал с шунта)
Буферы: 720 точек (целый период 1 кГц).
2. Генерация опорных сигналов
Создаем 2 массива (на той же частоте 1 кГц):
c
float ref_sin[n] = sin(2 * π * 1000 * n / (720 * fs)); // fs = частота дискретизации
float ref_cos[n] = cos(2 * π * 1000 * n / (720 * fs));
3. Квадратурное детектирование
Умножаем сигналы на опорные sin/cos и усредняем:
c
// Для напряжения (V)
float V_I = 0, V_Q = 0;
// Для тока (I)
float I_I = 0, I_Q = 0;
for (int n = 0; n < 720; n++) {
V_I += V_adc[n] * ref_sin[n];
V_Q += V_adc[n] * ref_cos[n];
I_I += I_adc[n] * ref_sin[n];
I_Q += I_adc[n] * ref_cos[n];
}
// Нормировка (делим на количество точек)
V_I /= 720; V_Q /= 720;
I_I /= 720; I_Q /= 720;

Почему не FFT?
FFT избыточен для одной частоты.
Требует больше ресурсов ЦПУ.
Квадратурный метод даёт ту же точность при меньших вычислениях.
Оптимизации под STM32G431
Используйте DMA для захвата ADC и передачи данных.
Таблицы sin/cos (720 значений) храните в ROM (вместо расчёта в реальном времени).
Аппаратное умножение (STM32G431 имеет FPU — используйте float).
Погрешности и калибровка
Калибровка нуля: Измерьте сигналы при коротком замыкании (вычтите offset).
Калибровка шунта: Учёт точного значения 150 Ом и паразитного RL.
Фазовые сдвиги ADC: Если каналы ADC имеют разную задержку, потребуется коррекция