ai: репозиторий переименован в eumirts5-dds; задание разделено на часть A (сборка DDS-стенда) и B (исследование интегратора, дифференциатора, RC-фильтра); stub синхронизирован с РПД (добавлен PIO-генератор); README с расшифровкой названия и картой пинов

This commit is contained in:
mss
2026-10-27 20:23:07 +04:00
parent 5087d1b348
commit 2c81de5d76
6 changed files with 1685 additions and 250 deletions
+102 -88
View File
@@ -1,116 +1,130 @@
# Лабораторная: интегратор и дифференциатор на ОУ (АЧХ/ФЧХ + Monte Carlo + автосвип) # ЭУМиРТС5-ДДС
Комплект к теме `topics/lab5-peredatochnaya-funkciya-na-ou.md` Репозиторий студента для одной лабораторной работы.
(«Электронные устройства мехатронных и робототехнических систем»,
Б1.В.06, 5 семестр, 4 ч).
> AI-сгенерировано (2026-10-26), требует проверки преподавателем **Дисциплина:** Электронные устройства мехатронных и робототехнических
> перед использованием на стенде. систем (ЭУМиРТС), Б1.В.06
**Специальность:** 15.03.06 «Мехатроника и робототехника»
**Семестр:** 5 · **Объём:** 4 часа
## Контракт Название репозитория расшифровывается так:
Оформлено по контракту `labs/`: | Часть | Значение |
|---|---|
| `eumirts` | ЭУМиРТС — электронные устройства мехатронных и робототехнических систем |
| `5` | пятый семестр |
| `dds` | Direct Digital Synthesis — генератор на RP2040, который вы собираете |
> Черновик. Требует проверки преподавателем перед выдачей студентам.
---
## О чём работа
Работа состоит из двух частей:
**A. Стенд.** Вы собираете DDS-генератор на RP2040 (Raspberry Pi Pico) и
скрипт автоматического снятия АЧХ. Готового лабораторного генератора со
свипом не оказалось, поэтому измерительный прибор делается своими руками.
**B. Исследование.** Этим стендом вы снимаете характеристики трёх схем —
интегратора на ОУ, дифференциатора на ОУ и пассивного RC-фильтра — и
сравниваете эксперимент с расчётом по передаточным функциям.
Полное задание — в **[task.md](task.md)**.
---
## Что в репозитории
``` ```
labs/lab5-peredatochnaya-funkciya-na-ou/ eumirts5-dds/
├── meta.yaml ← контракт ├── README.md ← этот файл
├── task.md ← задание студенту ├── task.md ← задание (части A и B)
├── method.md ← методичка преподавателю ├── stub/ ← заготовки: генераторы и скрипт
├── README.md ← этот файл │ ├── 01-dds-generator-rp2040.ino ← вариант 1: Arduino C++
├── print/ ← брошюры DOCX (rpd methodical) │ ├── 01-dds-generator-rp2040-circuitpython.py ← вариант 2: CircuitPython
└── stub/ │ ├── 04-dds-pio-rp2040.py ← вариант 3: PIO + DMA
├── 01-dds-generator-rp2040.ino ← генератор-свип (Arduino RP2040; │ ├── 02-izmerenie-achh.py ← автоснятие АЧХ (на ПК)
│ оба ядра: earlephilhower и mbed) │ └── 03-blank-otchyota.md ← бланк отчёта
├── 01-dds-generator-rp2040-circuitpython.py └── print/ ← брошюра задания (DOCX)
│ ← то же на CircuitPython (code.py)
├── 02-izmerenie-achh.py ← автоснятие АЧХ по Serial
└── 03-blank-otchyota.md ← бланк отчёта студента
``` ```
## Новое относительно `topics/lab5-peredatochnaya-funkciya-na-ou.md` ### Какой вариант генератора выбрать
1. **Monte Carlo по допускам** (`.step param`) — новый для курса анализ | Файл | Кому | Особенности |
в симуляторе: разброс K и f_c при ±5 % на компонентах, доля годных. |---|---|---|
2. **Генератор-свип на RP2040** — автономный генератор для натурной | `01-...ip2040.ino` | есть Arduino IDE | программный DDS, работает на обоих ядрах |
части: прямоугольник (ШИМ) и синус (DDS), логарифмический свип, | `01-...-circuitpython.py` | есть CircuitPython | то же, но медленнее (интерпретатор) |
синхроимпульс для осциллографа, измерение амплитуды на ADC0. | `04-dds-pio-rp2040.py` | **рекомендуется** | аппаратный PIO + DMA, точная частота, CPU свободен |
3. **Хост-скрипт автоснятия АЧХ** — управление генератором по Serial,
сбор точек, экспорт CSV, построение графика.
4. **Явное разделение практики и лаборатории:** симуляция — на практическом
занятии (2 ч), железо — на лабораторном (4 ч), отчёт — СРС.
## Предупреждения по стенду Для варианта на PIO нужна библиотека `adafruit_pioasm` в папке `/lib`
на плате.
- **ADC0 RP2040: 0…3,3 В.** Сигнал с выхода исследуемой цепи ≥ 3,3 В ---
подавать **только через делитель** или пиковый детектор.
- **Питание ОУ:** LM358 работает при однополярном +5…+12 В, TL081 —
при ±12 В. Уточнить по фактическому стенду.
- **Синус DDS:** качество зависит от внешнего ФНЧ после ШИМ (см. схему
ниже). Без фильтра на выходе будет меандр переменной скважности,
а не синус.
## Схема DDS-генератора (внешняя обвязка) ## Быстрый старт
ШИМ сам по себе даёт **меандр переменной скважности**, а не синус. 1. **Прошить генератор.** Файл переименовать в `code.py` (для CircuitPython)
Синус получается выделением огибающей фильтром. Поэтому на выходе или открыть в Arduino IDE (для `.ino`).
GP15 нужен внешний **ФНЧ**: 2. **Открыть консоль**, ввести `HELP` — увидеть список команд.
3. **Собрать ФНЧ** на выходе генератора (схема в `HELP`):
``` ```
GP15 (ШИМ 62,5 кГц) ──[R1 1к]──┬──[R2 1к]──┬──────► OUT (вход DUT) GP15 ──[R1 1к]──┬──[R2 1к]──┬──► к схеме
│ │ │ │
[C1 47н] [C2 47н] [C1 47н] [C2 47н]
│ │ │ │
GND GND GND GND
``` ```
Пассивный ФНЧ 2-го порядка, **f_c ≈ 3,4 кГц**: 4. **Проверить сигнал:** `W S` (синус), `F 1000`, посмотреть осциллографом
(период ≈ 1 мс).
5. **Калибровать частоту**, если нужно: ввести `CAL <измеренное_значение>`.
6. **Снять АЧХ** скриптом `02-izmerenie-achh.py` (запускается на ПК).
- подавление несущей: `(62,5 / 3,4)² ≈ 338 ≈ 50 дБ` → пульсации ≈ 10 мВ; ---
- рабочий диапазон генератора: **≈ 1 Гц … 1 кГц** (для звена
с f_c = 16…34 Гц — с запасом).
### Две оговорки ## Основные команды генератора
1. **Согласование сопротивлений.** Выход фильтра ≈ 1 кОм, вход | Команда | Что делает |
интегратора — R1 = 10 кОм → делитель 10/11, просадка ≈ 9 %. |---|---|
Если нужна точность — поставить буфер-повторитель на ОУ | `HELP` или `?` | подробная справка со всеми командами и схемой |
(**Sallen–Key**: тот же 2-й порядок + низкое выходное). | `I` | текущие настройки: частота, факт, потолок, `CPC` |
| `W S` / `W Q` | режим синуса / прямоугольника |
| `F <Гц>` | частота |
| `M <0..127>` | амплитуда синуса |
| `D <0..255>` | скважность прямоугольника |
| `A` | измерить размах на ADC0 (GP26) |
| `SWEEP f0 f1 n мс` | логарифмический свип |
| `B <1..8>` | число бит порта |
| `N <16..4096>` | длина периода в сэмплах |
| `O <1..64>` | точек на сэмпл |
| `CLC <1..8>` / `CAL <Гц>` | калибровка `CPC` вручную / автоматически |
| `FN <имя>` / `FP <выражение>` | форма сигнала из набора / своя формула |
2. **Постоянная составляющая.** При скважности 50 % среднее = `Uпит/2` ---
= 1,65 В, синус смещён. Где смещение недопустимо — разделительный
`C = 1 мкФ` последовательно + `R = 47 кОм` на землю (ФВЧ ≈ 3,4 Гц),
либо уменьшить амплитуду командой `M`.
### Варианты фильтра под другую несущую ## Пины стенда
| SAMPLE_HZ | R | C | f_c | | Пин | Назначение |
|---|---|---|---| |---|---|
| 62,5 кГц | 1 кОм | 47 нФ | 3,4 кГц | | GP8..GP15 | выход генератора (данные выровнены по старшему биту, MSB → GP15) |
| 62,5 кГц | 2,2 кОм | 22 нФ | 3,3 кГц | | GP15 | ШИМ в режиме прямоугольника (`W Q`) |
| 31,25 кГц | 2,2 кОм | 47 нФ | 1,5 кГц | | GP16 | синхроимпульс для осциллографа |
| GP26 (A0) | вход измерения ADC |
## Как использовать **Внимание:** на вход ADC подавать не более **3,3 В**. Сигнал больше —
только через делитель.
1. `task.md` + `stub/03-blank-otchyota.md` — студенту. ---
2. `stub/01-dds-generator-rp2040.ino` — прошить в RP2040 заранее
(или дать студенту в задании 4); альтернатива — `...-circuitpython.py`
на Pico с прошивкой CircuitPython (как `code.py`).
3. `stub/02-izmerenie-achh.py` — запускается на ПК студента (нужен pyserial).
4. `method.md` — только преподавателю.
5. Брошюры: `uv run rpd methodical lab5-peredatochnaya-funkciya-na-ou`.
## Связи ## Порядок сдачи
- **Практика** `pr5-raschet-analogovyh-ustrojstv` — расчётная часть 1. Собрать и откалибровать стенд (часть A).
(K, R1, R2, фильтры) выполняется там. 2. Снять характеристики трёх схем (часть B).
- **Лекция** `le5-metody-modelirovaniya` — типы анализа; Monte Carlo 3. Заполнить `stub/03-blank-otchyota.md`.
и `.step` — прямое применение. 4. Ответить на контрольные вопросы (в конце `task.md`).
- **Лекция** `le5-proektirovanie-analogovyh-ustrojstv` — топология ОУ.
- **ТАУ** (`b1-o-23`) — передаточные функции и типовые звенья идут
параллельно в 5 семестре; эта работа даёт им физическую реализацию.
## Статус Баллы по заданиям — в `task.md`, раздел «Оформление и оценивание».
Зачёт при **6 и более** баллах из 10.
Черновик (draft). Тема `lab5-peredatochnaya-funkciya-na-ou` существует
в `topics/`; комплект в `labs/` — подготовлен для интеграции после
проверки преподавателем и согласования сквозной работы по мехатронике.
+56 -4
View File
@@ -30,7 +30,7 @@
# M <0..127> — амплитуда синуса (127 = максимум) # M <0..127> — амплитуда синуса (127 = максимум)
# A — однократно измерить размах на ADC0 -> "A <мВ>" # A — однократно измерить размах на ADC0 -> "A <мВ>"
# SWEEP <f0> <f1> <n> <dwell_ms> # SWEEP <f0> <f1> <n> <dwell_ms>
# — логарифмический свип; "P <Гц> <мВ>" + импульс на GP14 # — логарифмический свип; "P <Гц> <мВ>" + импульс на GP16
# STOP — прервать свип # STOP — прервать свип
# #
# ─── СХЕМА СИНУСА (обязательна: ШИМ даёт меандр, а не синус) ─── # ─── СХЕМА СИНУСА (обязательна: ШИМ даёт меандр, а не синус) ───
@@ -55,7 +55,10 @@ import pwmio
import supervisor import supervisor
PIN_OUT = board.GP15 # выход сигнала (синус — через RC-фильтр) PIN_OUT = board.GP15 # выход сигнала (синус — через RC-фильтр)
PIN_TRIG = board.GP14 # синхроимпульс (для осциллографа) PIN_TRIG = board.GP16 # синхроимпульс. НЕ GP14: он входит в
# диапазон PIO (GP8..GP15) в варианте
# 04-dds-pio-rp2040.py; GP16 — единая
# разводка стенда для всех трёх вариантов
PIN_ADC = board.GP26 # ADC0 = A0 — вход измерения (через делителем) PIN_ADC = board.GP26 # ADC0 = A0 — вход измерения (через делителем)
CARRIER_HZ = 125000 # несущая ШИМ — много выше f_s, биений нет CARRIER_HZ = 125000 # несущая ШИМ — много выше f_s, биений нет
@@ -221,6 +224,52 @@ def trigger_pulse():
trig.value = False trig.value = False
def print_help():
"""Подробная справка по командам с форматами и примерами."""
lines = [
"# ─────────── DDS-генератор: команды ───────────",
"# Обозначения: <..> — обязательный аргумент.",
"# Команда вводится строкой, Enter — конец строки.",
"#",
"# РЕЖИМ И ЧАСТОТА",
"# W Q — режим прямоугольника (аппаратный ШИМ)",
"# W S — режим синуса (программный DDS -> ШИМ -> ФНЧ)",
"# F <Гц> — частота прямоугольника, 1..200000",
"# пример: F 1000",
"# SF <Гц> — частота СИНУСА, 1..f_s/2 (защита от алиасинга)",
"# пример: SF 25",
"#",
"# ФОРМА СИГНАЛА",
"# D <0..255> — скважность прямоугольника (128 = 50 %)",
"# пример: D 64 (25 % включено)",
"# M <0..127> — амплитуда синуса (127 = максимум)",
"# пример: M 32 (четверть шкалы)",
"#",
"# ИЗМЕРЕНИЕ И СВИП",
"# A — размах на ADC0 (GP26), мВ -> ответ 'A <мВ>'",
"# SWEEP <f0> <f1> <n> <dwell_ms>",
"# логарифмический свип f0..f1 за n точек,",
"# пауза dwell_ms на точку; печатает 'P <Гц> <мВ>',",
"# в конце 'DONE'",
"# пример: SWEEP 10 100000 25 150",
"# STOP — прервать свип",
"#",
"# СПРАВКА",
"# HELP | ? — этот текст",
"#",
"# ─── СХЕМА (синус: ШИМ даёт меандр, нужен ФНЧ) ───",
"# GP15 --[R1]--+--[R2]--+--> во вход схемы",
"# | |",
"# [C1] [C2] R1=R2=1к, C1=C2=47н",
"# | | (f_c подобрать под вашу f_s)",
"# GND GND",
"# Постоянная составляющая при 50% = Uпит/2. ADC0 — до 3.3 В (делитель!).",
"# ─────────────────────────────────────────────",
]
for ln in lines:
print(ln)
def handle(line, phase): def handle(line, phase):
"""Выполнить команду. Возвращает (ok, phase). Любые ошибки — внутрь.""" """Выполнить команду. Возвращает (ok, phase). Любые ошибки — внутрь."""
line = line.strip() line = line.strip()
@@ -229,7 +278,9 @@ def handle(line, phase):
parts = line.split(None, 1) # позиционно: sep=None, maxsplit=1 (в CP нет kwargs!) parts = line.split(None, 1) # позиционно: sep=None, maxsplit=1 (в CP нет kwargs!)
cmd = parts[0].upper() cmd = parts[0].upper()
a = parts[1] if len(parts) > 1 else "" a = parts[1] if len(parts) > 1 else ""
if cmd == "F": if cmd in ("HELP", "?"):
print_help()
elif cmd == "F":
cmd_f(a) cmd_f(a)
elif cmd == "SF": elif cmd == "SF":
cmd_sf(a) cmd_sf(a)
@@ -266,7 +317,8 @@ def calibrate_fs(phase):
# ─────────────────────────── main ───────────────────────────── # ─────────────────────────── main ─────────────────────────────
def main(): def main():
global fs_eff global fs_eff
print("# DDS generator ready (CircuitPython). help: F/W/D/A/SWEEP/STOP") print("# DDS generator ready (CircuitPython). Подробный хелп: HELP или ?")
print_help()
phase = 0 phase = 0
try: try:
fs_eff, phase = calibrate_fs(phase) fs_eff, phase = calibrate_fs(phase)
+55 -3
View File
@@ -80,7 +80,10 @@
// ─────────────────────────── пины ─────────────────────────── // ─────────────────────────── пины ───────────────────────────
#define PIN_OUT 15 // выход сигнала (прямоугольник — прямо; синус — через RC) #define PIN_OUT 15 // выход сигнала (прямоугольник — прямо; синус — через RC)
#define PIN_TRIG 14 // синхроимпульс (для осциллографа) #define PIN_TRIG 16 // синхроимпульс (для осциллографа)
// ВАЖНО: не GP14 — он попадает в диапазон PIO в
// варианте 04-dds-pio-rp2040.py; для единой разводки
// стенда синхро держим на GP16 во всех вариантах
#define PIN_ADC 26 // ADC0 = A0 — вход измерения (выход DUT через делитель!) #define PIN_ADC 26 // ADC0 = A0 — вход измерения (выход DUT через делитель!)
// ─────────────────────── параметры DDS ────────────────────── // ─────────────────────── параметры DDS ──────────────────────
@@ -269,12 +272,60 @@ static void runSweep(float f0, float f1, int n, uint32_t dwell_ms) {
setFrequency((uint32_t)f0); // вернуться к началу setFrequency((uint32_t)f0); // вернуться к началу
} }
// ─────────────────────── подробный хелп ──────────────────────
static void printHelp() {
Serial.println(F("# ─────────── DDS-генератор: команды ───────────"));
Serial.println(F("# Обозначения: <..> — обязательный аргумент."));
Serial.println(F("# Все команды вводятся строкой, Enter — конец строки."));
Serial.println(F("#"));
Serial.println(F("# РЕЖИМ И ЧАСТОТА"));
Serial.println(F("# W Q — режим прямоугольника (аппаратный ШИМ)"));
Serial.println(F("# W S — режим синуса (DDS -> ШИМ -> внешний ФНЧ)"));
Serial.println(F("# F <Гц> — частота выхода, 1..500000"));
Serial.println(F("# в режиме Q — частота прямоугольника;"));
Serial.println(F("# в режиме S — то же (для совместимости)"));
Serial.println(F("# пример: F 1000"));
Serial.println(F("# SF <Гц> — частота синуса с защитой от алиасинга"));
Serial.println(F("# ограничена SAMPLE_HZ/2 (см. шапку файла)"));
Serial.println(F("# пример: SF 25"));
Serial.println(F("#"));
Serial.println(F("# ФОРМА СИГНАЛА"));
Serial.println(F("# D <0..255> — скважность прямоугольника (128 = 50 %)"));
Serial.println(F("# пример: D 64 (25 % включено)"));
Serial.println(F("# M <0..127> — амплитуда синуса (127 = максимум)"));
Serial.println(F("# пример: M 32 (четверть шкалы)"));
Serial.println(F("#"));
Serial.println(F("# ИЗМЕРЕНИЕ И СВИП"));
Serial.println(F("# A — размах на ADC0 (GP26), мВ -> ответ 'A <мВ>'"));
Serial.println(F("# SWEEP <f0> <f1> <n> <dwell_ms>"));
Serial.println(F("# логарифмический свип от f0 до f1 за n точек,"));
Serial.println(F("# пауза dwell_ms на точку; на точку печатает"));
Serial.println(F("# 'P <Гц> <мВ>', в конце 'DONE'"));
Serial.println(F("# пример: SWEEP 10 100000 25 150"));
Serial.println(F("# STOP — прервать свип"));
Serial.println(F("#"));
Serial.println(F("# СПРАВКА"));
Serial.println(F("# HELP | ? — этот текст"));
Serial.println(F("#"));
Serial.println(F("# ─── СХЕМА (синус: ШИМ даёт меандр, нужен ФНЧ) ───"));
Serial.println(F("# GP15 --[R1]--+--[R2]--+--> во вход схемы"));
Serial.println(F("# | |"));
Serial.println(F("# [C1] [C2] R1=R2=1к, C1=C2=47н"));
Serial.println(F("# | | (f_c ~ 3.4 кГц)"));
Serial.println(F("# GND GND"));
Serial.println(F("# Постоянная составляющая при 50% = Uпит/2: нужен разделительный"));
Serial.println(F("# конденсатор, если смещение мешает. ADC0 — до 3.3 В (делитель!)."));
Serial.println(F("# ─────────────────────────────────────────────"));
}
// ─────────────────────── разбор команд ────────────────────── // ─────────────────────── разбор команд ──────────────────────
static void handleLine(char *line) { static void handleLine(char *line) {
char *cmd = strtok(line, " \t"); char *cmd = strtok(line, " \t");
if (!cmd) return; if (!cmd) return;
if (!strcasecmp(cmd, "F")) { if (!strcasecmp(cmd, "HELP") || !strcmp(cmd, "?")) {
printHelp();
} else if (!strcasecmp(cmd, "F")) {
char *a = strtok(nullptr, " \t"); char *a = strtok(nullptr, " \t");
if (a) setFrequency((uint32_t)strtoul(a, nullptr, 10)); if (a) setFrequency((uint32_t)strtoul(a, nullptr, 10));
Serial.print("OK F "); Serial.println(g_freq); Serial.print("OK F "); Serial.println(g_freq);
@@ -323,7 +374,8 @@ void setup() {
startSampleClock(); startSampleClock();
setMode(MODE_SQUARE); setMode(MODE_SQUARE);
setFrequency(1000); setFrequency(1000);
Serial.println("# DDS generator ready (RP2040). help: F/W/D/A/SWEEP/STOP"); Serial.println("# DDS generator ready (RP2040). Подробный хелп: HELP или ?");
printHelp();
} }
void loop() { void loop() {
File diff suppressed because it is too large Load Diff
+212 -155
View File
@@ -1,188 +1,240 @@
# Лабораторная работа # Лабораторная работа: DDS-стенд и исследование фильтров
## Интегратор и дифференциатор на ОУ: передаточная функция, АЧХ/ФЧХ и разброс по допускам ## Электронные устройства мехатронных и робототехнических систем
**Дисциплина:** Электронные устройства мехатронных и робототехнических **Дисциплина:** Электронные устройства мехатронных и робототехнических
систем (Б1.В.06, очная форма) систем, Б1.В.06
**Семестр:** 5 · **Объём:** 4 часа · **Тема:** `lab5-peredatochnaya-funkciya-na-ou` **Специальность:** 15.03.06 «Мехатроника и робототехника»
**Форма:** черновик — в учебный план пока не привязана **Семестр:** 5 · **Объём:** 4 часа
**Стенд:** RP2040 (Raspberry Pi Pico) + макетная плата
> AI-сгенерировано (2026-10-26), требует проверки преподавателем. > Черновик. Требует проверки преподавателем перед выдачей студентам.
--- ---
## 1. Легенда ## 1. Зачем эта работа
В мехатронном модуле сигнал датчика проходит через аналоговую обработку: В мехатронном модуле сигнал датчика проходит аналоговую обработку:
фильтрацию, интегрирование, выделение скорости (дифференцирование). фильтрацию помех, интегрирование, выделение скорости (дифференцирование).
Каждое такое звено описывается передаточной функцией, и от его параметров Каждое такое звено описывается передаточной функцией, и от его параметров
(K, τ) зависит поведение всей системы управления. (K, τ) зависит поведение всей системы управления.
**Задача работы:** убедиться, что аналоговое звено на операционном Чтобы **проверить звено на железе**, нужен генератор с известной частотой
усилителе действительно реализует расчётную передаточную функцию — сначала и амплитудой. Готового лабораторного генератора со свипом под рукой не
в симуляторе, затем на макетной плате. И понять, как **допуски** оказалось — поэтому в первой части работы вы **сами делаете стенд**:
резисторов и конденсаторов влияют на параметры звена в серии. DDS-генератор на RP2040 и скрипт автоматического снятия АЧХ.
Работа состоит из двух частей: Во второй части вы этим стендом **исследуете фильтры** — интегратор,
дифференциатор и RC-фильтр — и сравниваете эксперимент с расчётом.
- **Симуляция** (LTSpice): АЧХ/ФЧХ и **новый анализ — Monte Carlo** по допускам; ### Две части работы
- **Железо** (макет + генератор): переходные процессы и **автоматическое
снятие АЧХ** генератором-свипом на RP2040. | Часть | Что делаем | Результат |
|---|---|---|
| **A. Стенд** | собираем и настраиваем DDS-генератор | работающий прибор: частота, амплитуда, свип |
| **B. Исследование** | снимаем характеристики фильтров | АЧХ/ФЧХ, сравнение с расчётом |
Часть A без части B бессмысленна: прибор делается, чтобы им измерять.
Часть B без части A невозможна: нечем снимать АЧХ.
--- ---
## 2. Теория кратко ## 2. Теория кратко
**Интегратор на ОУ** (R1 на входе, C1 в ООС): ### 2.1. Что должен делать генератор (часть A)
**DDS** (Direct Digital Synthesis) — синтез сигнала из заранее
посчитанного массива значений. Идея:
1. считаем один период нужной формы — например синуса — в массив
из `m` точек;
2. подаём массив в PIO по кругу через DMA;
3. PIO выводит точки в порт с частотой `f_пио`;
4. частота выходного сигнала: `f_вых = f_пио / (CPC · m)`,
где `CPC` — число тактов PIO на один сэмпл.
Чем больше `m`, тем точнее форма и выше разрешение уровня, но тем ниже
максимальная частота.
### 2.2. Точность уровня: битность ≠ разрешение
- **Битность** `B` — сколько бит выводится в порт сразу (мгновенный код).
- **Эффективная разрядность** — сколько уровней различает **среднее**
после фильтра: `(2^B − 1)·m + 1`.
При `B = 4` и `m = 256` порт даёт 4 бита, но среднее различает
3841 уровень (~11.9 бит). Так работает дельта-сигма: соседние коды
чередуются во времени, а ФНЧ усредняет.
### 2.3. Интегратор на ОУ
**Идеальный** (R1 на входе, C1 в ООС):
```
W(s) = −1 / (R1·C1·s) W(s) = −1 / (R1·C1·s)
```
**Реальный интегратор** (резистор утечки R2 параллельно C1) — это На постоянном токе усиление бесконечно, поэтому **реальный** интегратор
всегда содержит резистор утечки R2 параллельно C1 — это превращает его в
**апериодическое звено первого порядка**: **апериодическое звено первого порядка**:
```
W(s) = −R2 / (R1 · (1 + R2·C1·s)) = −K / (τ·s + 1) W(s) = −R2 / (R1 · (1 + R2·C1·s)) = −K / (τ·s + 1)
K = R2/R1, τ = R2·C1, f_c = 1/(2π·τ)
```
где K = R2/R1, τ = R2·C1, f_c = 1/(2π·τ). ### 2.4. Дифференциатор на ОУ
**Дифференциатор** (C1 на входе, R1 в ООС): C1 на входе, R1 в ООС:
```
W(s) = −R1·C1·s W(s) = −R1·C1·s
```
**Модель для работы:** K = −10, τ = 10 мс, f_c ≈ 16 Гц На высоких частотах усиление растёт, поэтому на практике вход
(R1 = 10 кОм, R2 = 100 кОм, C1 = 0,1 мкФ). ограничивают резистором последовательно с C1.
### 2.5. RC-фильтр нижних частот
Пассивный ФНЧ первого порядка:
```
K(f) = 1 / √(1 + (f/f_c)²), f_c = 1/(2π·R·C)
наклон за f_c: −20 дБ/дек
```
--- ---
## 3. Задания ## 3. Часть A. Сборка и настройка стенда
### Задание 1 (1 ч). Симуляция: АЧХ и ФЧХ ### Задание A1 (0,5 ч). Прошивка генератора и первый запуск
В LTSpice собрать интегратор с резистором утечки: R1 = 10 кОм, В папке `stub/` три варианта генератора — **выберите один**:
R2 = 100 кОм, C1 = 0,1 мкФ (R2 || C1 в ООС).
1. Задать анализ `.ac dec 20 1 100k`. | Файл | Платформа | Как формируется синус |
2. Снять АЧХ в децибелах и ФЧХ. |---|---|---|
3. По графику определить: | `01-...ip2040.ino` | Arduino C++ | программный DDS + ШИМ |
- усиление на плоском участке (должно быть ≈ 20 дБ, т. е. K = 10); | `01-...-circuitpython.py` | CircuitPython | программный DDS + ШИМ |
- частоту сопряжения f_c (где спад −3 дБ); | `04-dds-pio-rp2040.py` | CircuitPython | **аппаратный PIO + DMA** |
- наклон спада (ожидается −20 дБ/дек).
4. Сравнить с расчётом по формулам из п. 2.
### Задание 2 (1 ч). Симуляция: Monte Carlo по допускам ⭐ **Рекомендуется вариант на PIO** — он даёт точную частоту и не грузит CPU.
**Новый анализ.** Реальные резисторы и конденсаторы имеют допуск ±5 % 1. Залейте файл на Pico (CircuitPython: переименовать в `code.py`).
(ряд E24 — не лучше). Оценим разброс параметров звена. 2. Откройте консоль, введите `HELP` — увидите список команд.
3. Введите `I` — генератор покажет текущие настройки, включая
**фактическую** частоту и потолок `f_max`.
4. Соберите внешний ФНЧ на выходе (схема — в `HELP`):
1. Задать разброс: `.step param tol list -5 -2.5 0 2.5 5` и применить ```
его к номиналам (например `{100k*(1+tol/100)}` для R2, аналогично R1 и C1). GP15 ──[R1 1к]──┬──[R2 1к]──┬──► выход
Либо, для полноценного статистического анализа, использовать │ │
`.step param run 1 100 1` с генератором случайных отклонений. [C1 47н] [C2 47н]
2. Прогнать **не менее 100 прогонов**. │ │
3. Для каждого прогона зафиксировать K (усиление на плоском участке) и f_c. GND GND
4. Построить гистограммы распределения K и f_c. ```
5. Посчитать **долю экземпляров**, укладывающихся в полосу ±10 % от
номинального значения K и f_c.
6. Сделать вывод: **какой компонент** вносит наибольший вклад в разброс
и почему.
### Задание 3 (1 ч). Железо: переходные процессы **Проверка:** подать `W S` (синус), `F 1000`, посмотреть осциллографом.
Период должен быть ≈ 1 мс.
Собрать на макетной плате: ### Задание A2 (0,5 ч). Калибровка частоты
**3.1. Интегратор** (R1 = 10 кОм, C1 = 0,1 мкФ): Частота зависит от `CPC` — числа тактов PIO на сэмпл. Оно может отличаться
на разных прошивках.
- подать прямоугольник 1 кГц (от RP2040-генератора или лабораторного); 1. Поставьте `F 1000`, измерьте период осциллографом.
- наблюдать пилообразный сигнал на выходе; 2. Если факт отличается от запроса — введите `CAL <измеренное_значение>`,
- замерить размах пилы и сравнить с например `CAL 500` при запросе 1000. Генератор подстроит `CPC` сам.
U_m = U_вх · T / (2 · R1 · C1); 3. Повторите замер — теперь должно совпасть.
- убедиться, что при росте частоты размах падает обратно пропорционально. 4. **Запишите** подобранное `CPC` (видно командой `I`) — оно нужно для
расчёта погрешности в отчёте.
**3.2. Дифференциатор** (C1 = 0,1 мкФ на входе, R1 = 10 кОм в ООС): > Если частота вообще не достижима, генератор скажет
> `! ЗАПРОС ВЫШЕ ПОТОЛКА: факт ... Гц`. Это значит `m` слишком велико:
> уменьшите `N` или `O`.
- подать пилу 1 кГц; ### Задание A3 (0,5 ч). Автоматическое снятие АЧХ
- наблюдать импульсы в моменты перепада;
- сравнить амплитуду с U_m = R1·C1 · dU_вх/dt.
**3.3. Роль резистора утечки:** собрать интегратор с R2 = 100 кОм 1. Соберите на макетной плате простой RC-фильтр (см. часть B, задание B3).
параллельно C1 и без него; объяснить, что меняется на постоянном токе. 2. Подключите: выход генератора → вход фильтра; выход фильтра →
вход измерения (ADC0, GP26). **Если сигнал больше 3,3 В — через делитель.**
3. Запустите хост-скрипт:
### Задание 4 (1 ч). Железо: автоматическое снятие АЧХ ```
python 02-izmerenie-achh.py --port /dev/ttyACM0 \
--f0 10 --f1 100000 --n 25 --dwell 150 --uin 500 --out achh.csv --plot
```
Использовать подготовленный генератор-свип: 4. Получите CSV с точками «частота → амплитуда». Это ваш измерительный
прибор на вторую часть работы.
- **`stub/01-dds-generator-rp2040.ino`** — прошить в RP2040 (Raspberry Pi **Результат части A:** работающий стенд, калиброванная частота, скрипт,
Pico) в Arduino IDE (работает в обоих ядрах: earlephilhower и официальном дающий АЧХ в CSV.
mbed). Прямоугольник (ШИМ) и синус (DDS) + логарифмический свип
+ измерение амплитуды на ADC0.
- **`stub/01-dds-generator-rp2040-circuitpython.py`** — альтернатива без
Arduino: положить файл на Pico с прошивкой CircuitPython (переименовать
в code.py). Протокол команд тот же.
- **`stub/02-izmerenie-achh.py`** — хост-скрипт: запускает свип по Serial,
собирает точки, строит АЧХ.
Порядок: ---
1. Прошить генератор, проверить команды `F`, `W S`, `M`, `A` в мониторе ## 4. Часть B. Исследование фильтров
порта.
2. **Собрать внешний ФНЧ** на выходе генератора (без него будет меандр,
а не синус):
``` Все три задания выполняются **одним и тем же стендом**, меняется только
GP15 ──[R1 1к]──┬──[R2 1к]──┬──────► вход схемы исследуемая схема. Для каждой схемы:
│ │
[C1 47н] [C2 47н]
│ │
GND GND
```
Это пассивный ФНЧ 2-го порядка, f_c ≈ 3,4 кГц; он подавляет несущую 1. рассчитать параметры (K, τ или f_c) по формулам из п. 2;
ШИМ 62,5 кГц примерно на 50 дБ. **Зарисовать фильтр в отчёт.** 2. собрать схему на макетной плате;
3. снять АЧХ стендом (частичный диапазон вокруг f_c, 8–12 точек);
4. наложить экспериментальные точки на расчётную кривую;
5. оценить расхождение и объяснить его.
3. Выход фильтра → вход схемы; выход схемы → вход измерения (ADC0). ### Задание B1 (1 ч). Интегратор на ОУ
**Если сигнал превышает 3,3 В — только через делитель.**
4. Запустить:
```
python 02-izmerenie-achh.py --port /dev/ttyACM0 \
--f0 10 --f1 100000 --n 25 --dwell 150 --uin 500 --out achh.csv --plot
```
5. Импортировать CSV, нанести точки на модельную кривую из задания 1.
6. Объяснить расхождения.
> **Смещение:** при скважности 50 % среднее на выходе ШИМ = `Uпит/2` **Схема:** R1 = 10 кОм на вход, R2 = 100 кОм ‖ C1 = 0,1 мкФ в ООС.
> = 1,65 В, поэтому синус смещён относительно земли. Если это мешает
> измерению — поставьте разделительный `C = 1 мкФ` + `R = 47 кОм`
> на землю, либо уменьшите амплитуду командой `M`.
> Свип-генератор — студенческая заготовка (черновик). Если на стенде - Рассчитать: `K = R2/R1`, `τ = R2·C1`, `f_c = 1/(2π·τ)`.
> есть серийный функциональный генератор с режимом свипа/логарифмической - Снять АЧХ в диапазоне **1 Гц … 10·f_c**.
> развёртки — можно использовать его, принцип тот же. - Определить по графику плоский участок, частоту сопряжения, наклон.
- **Проверить форму во времени:** подать прямоугольник, увидеть пилу.
Размах пилы `U_m = U_вх·T/(2·R1·C1)`.
### Задание 5 (СРС / отчёт). Сведение результатов **Контрольный вопрос:** почему `f_c` определяется `R2·C1`, а не `R1·C1`?
Свести в одну таблицу «**расчёт / симуляция / железо**» параметры ### Задание B2 (1 ч). Дифференциатор на ОУ
K, τ, f_c. Построить совмещённый график АЧХ (три кривые).
**Схема:** C1 = 0,1 мкФ на вход, R1 = 10 кОм в ООС.
- Рассчитать `W(s) = −R1·C1·s`, ожидаемый наклон **+20 дБ/дек**.
- Снять АЧХ в диапазоне, где схема ещё устойчива.
- **Проверить во времени:** подать пилу — увидеть импульсы в моменты
перепада. Амплитуда `U_m = R1·C1·dU_вх/dt`.
- Объяснить, почему реальный дифференциатор требует ограничения входа.
**Контрольный вопрос:** чем отличается идеальный дифференциатор от
реального и почему вход ограничивают резистором?
### Задание B3 (0,5 ч). Пассивный RC-фильтр
**Схема:** R = 1 кОм, C = 0,1 мкФ (или по вашему варианту).
- Рассчитать `f_c = 1/(2π·R·C)`, ожидаемый наклон −20 дБ/дек.
- Снять АЧХ стендом в диапазоне **0,1·f_c … 100·f_c** (10–12 точек).
- Наложить на расчётную кривую `K(f) = 1/√(1+(f/f_c)²)`.
- Сравнить расхождение с допусками компонентов (±5 %).
**Контрольный вопрос:** почему реальная АЧХ за `f_c` уходит круче
−20 дБ/дек? (подсказка: паразитные параметры, вход ADC)
### Задание B4 (0,5 ч). Сравнение и отчёт
Свести результаты трёх схем в таблицу:
| Схема | f_c расчёт | f_c опыт | Расхождение | Наклон расчёт | Наклон опыт |
|---|---|---|---|---|---|
| Интегратор | | | | −20 дБ/дек | |
| Дифференциатор | | | | +20 дБ/дек | |
| RC-фильтр | | | | −20 дБ/дек | |
Сделать выводы: Сделать выводы:
- причины расхождения расчёта и симуляции; - какой разброс дали допуски компонентов;
- причины расхождения симуляции и железа; - где опыт расходится с расчётом сильнее всего и почему;
- что даёт анализ Monte Carlo для реального проектирования. - какую роль сыграла калибровка генератора (задание A2).
---
## 4. Варианты
| № | R1, кОм | R2, кОм | C1, мкФ | K | τ, мс | f_c, Гц |
|---|---------|---------|---------|---|-------|---------|
| 1 | 10 | 100 | 0,1 | 10 | 10 | 15,9 |
| 2 | 10 | 47 | 0,1 | 4,7 | 4,7 | 33,9 |
| 3 | 4,7 | 100 | 0,1 | 21 | 10 | 15,9 |
| 4 | 10 | 100 | 0,047 | 10 | 4,7 | 33,9 |
| 5 | 1 | 47 | 1,0 | 47 | 47 | 3,4 |
| 6 | 22 | 220 | 0,022 | 10 | 4,84 | 32,9 |
*Примечание. Номиналы приведены к ряду E24. Вариант 2 и 4 дают одинаковую
f_c при разном K — удобно для сравнения вклада параметров.*
--- ---
@@ -190,51 +242,56 @@ f_c при разном K — удобно для сравнения вклад
Отчёт содержит: Отчёт содержит:
1. Схему интегратора и дифференциатора (KiCad или от руки). 1. Схемы: ФНЧ стенда, интегратор, дифференциатор, RC-фильтр.
2. АЧХ и ФЧХ из LTSpice. 2. Настройки генератора из `I` (включая `CPC` после калибровки).
3. Гистограммы Monte Carlo (K и f_c) + доля годных. 3. Осциллограммы: синус с генератора, пила интегратора, импульсы
4. Осциллограммы переходных процессов (пила, импульсы). дифференциатора.
5. CSV-точки автоматического свипа + совмещённый график АЧХ. 4. Три графика АЧХ с наложенными расчётными кривыми.
6. Итоговую таблицу «расчёт / симуляция / железо». 5. Итоговую таблицу из задания B4.
7. Выводы. 6. Выводы по расхождениям.
| Задание | Баллы | | Задание | Баллы |
|---------|-------| |---|---|
| 1. Симуляция АЧХ/ФЧХ | 2,0 | | A1. Прошивка и первый запуск | 1,0 |
| 2. Monte Carlo | 2,5 | | A2. Калибровка частоты | 1,0 |
| 3. Железо: переходные процессы | 2,0 | | A3. Автоснятие АЧХ | 2,0 |
| 4. Железо: автоснятие АЧХ | 2,0 | | B1. Интегратор | 2,0 |
| 5. Отчёт: сведение | 1,5 | | B2. Дифференциатор | 2,0 |
| B3. RC-фильтр | 1,0 |
| B4. Сводка и выводы | 1,0 |
| **Итого** | **10** | | **Итого** | **10** |
Зачёт — при **6 и более** баллах. Расхождение с эталоном ±10 % Зачёт — при **6 и более** баллах.
(допуски компонентов).
--- ---
## 6. Контрольные вопросы ## 6. Контрольные вопросы
1. Чему равна передаточная функция идеального интегратора и почему без **По стенду (часть A):**
резистора утечки она нереализуема на практике?
2. Как по АЧХ отличить идеальный интегратор от апериодического звена 1. Чему равна частота выходного сигнала DDS и какие величины её задают?
первого порядка? 2. Что такое `CPC` и почему его приходится калибровать?
3. Почему частота сопряжения определяется R2·C1, а не R1·C1? 3. Чем битность порта отличается от эффективной разрядности?
4. Как связаны наклон АЧХ в дБ/дек и порядок звена? 4. Почему для синуса нужен внешний ФНЧ после ШИМ?
5. Какой компонент даёт наибольший вклад в разброс f_c при допуске ±5 %
и почему? **По фильтрам (часть B):**
6. Как на форме переходного процесса сказывается конечная полоса
пропускания операционного усилителя? 5. Чему равна передаточная функция идеального интегратора и почему без
резистора утечки её нельзя реализовать?
6. Как по АЧХ отличить идеальный интегратор от апериодического звена?
7. Почему наклон АЧХ звена первого порядка равен −20 дБ/дек?
8. Как допуски R и C влияют на `f_c` и что даёт анализ Monte Carlo?
--- ---
## 7. Литература ## 7. Литература
1. Хоровиц П., Хилл У. Искусство схемотехники. 3-е изд. М.: Бином, 2014. 1. Хоровиц П., Хилл У. Искусство схемотехники. 3-е изд. М.: Бином, 2014.
Гл. 4. Гл. 4 (ОУ в линейном режиме).
2. Титце У., Шенк К. Полупроводниковая схемотехника. 12-е изд. М.: ДМК 2. Титце У., Шенк К. Полупроводниковая схемотехника. 12-е изд. М.: ДМК
Пресс, 2008. Т. 1, гл. 11. Пресс, 2008. Т. 1, гл. 11 (частотные характеристики).
3. Бесекерский В.А., Попов Е.П. Теория систем автоматического 3. Бесекерский В.А., Попов Е.П. Теория систем автоматического
регулирования. М.: Наука, 2010. Гл. 2. регулирования. М.: Наука, 2010. Гл. 2 (типовые звенья).
4. LTSpice XVII User Guide. Analog Devices. 4. LTSpice XVII User Guide. Analog Devices.
5. LM358 / TL081 datasheet. Texas Instruments. 5. RP2040 Datasheet. Raspberry Pi Ltd (PIO, DMA, ADC).
6. RP2040 Datasheet. Raspberry Pi Ltd. 6. LM358 / TL081 datasheet. Texas Instruments.