Что наблюдается: в симуляции (и на реальной плате) положительный и отрицательный пик выходного сигнала не равны по модулю. Например, при Ra=150Ω/Rf=2100Ω/R_TIA=249Ω/I_FS=4мА: +13.7В против −14.9В (см. Figure_3, прогон от 2026-07-06).
Почему это не баг Ra/Rb. Rb в calculation.py считается по формуле
Rb = Ra*Rf/(Ra+Rf) — это согласование входных токов смещения (bias current
matching), устраняет офсет по постоянному току. Оно НЕ участвует в AC-контуре
усиления и не может исправить разницу коэффициентов.
Для топологии "один резистор ОС Rf на инвертирующем входе, прямое включение неинвертирующего входа через Ra_p/Rb":
A_v(инв.) = -Rf/Ra
A_v(неинв.) = 1 + Rf/Ra
Разница между ними всегда ровно 1 по модулю — независимо от выбора Ra/Rf/Rb. Это топологическое свойство схемы с одним резистором ОС, а не следствие конкретных номиналов.
Статус: признано в пределах допуска для задачи (HiPIMS-генератор, V_out_amp=14В, запас до шины ±16В) и осознанно не компенсируется. Если когда-нибудь потребуется — компенсировать через смещение целевого A_v (эффективно — целиться не в 14В строго, а в середину между будущими +/- пиками), а не через игру с Ra/Rb, которые для этого не предназначены.
Реальная плата: резисторы R20/R21/R22 (в терминах платы; в терминах модели
— Rb/Ra/Rf) исторически подобраны без строгой формулы Rb=Ra||Rf
(отклонение ~14.6% от неё) — вероятно, это была ручная эмпирическая коррекция
той же асимметрии на месте, ещё до того как в calculation.py появилась
регулярная формула. Стоит явно решить, нужно ли переносить эту эмпирику
обратно в скрипт (см. Rf_target в конфиге) или считать её устаревшей и
перепаивать плату под номиналы из calculation.py.
.asy файлы символов (в отличие от .asc/.net, которые обычно в
UTF-8/CP1251) сохраняются LTspice в UTF-16LE. asy_parser.py уже это
учитывает и пробует кодировки по очереди — но если добавляешь свои .asy
руками (не через LTspice), проверь кодировку, если парсер вдруг не находит
пины.
.param RaVal=50 / RfVal=702 и т.п. в теле .asc — это то, что осталось
после последнего РУЧНОГО прогона в LTspice IDE. LTspiceRunner.run() всегда
подменяет их перед реальным запуском через editor.set_parameter(...) /
editor.set_component_value(...). Реальные использованные номиналы — всегда
смотреть в report.txt, а не в теле .asc.