Pull to refresh
-2
3
Subscribers
Send message

Нет, на Khadas Edge2 будет монстр не в кармане, а в рюкзаке. Не забудьте power bank на 100000 Ah ( это как автомобильный аккумулятор)
Далее уточним что Khadas Edge2 - это не открытая архитектура, а открытая только кое в чем. Прямого доступа к любому железу там не будет, как и в чипах Samsung.
Алгоритмы настоящего подавления возбуждения никто не открывал, то что много есть смешных игрушечных эффектов, не значит что там будет ноухау по повышению разборчивости речи.
Словом будет такая печка за плечами , кое как спобная делать автоматическую регулировку амплитуды и бесполезный эквалайзер. А шумы будет фильтровать постфактум, когда уже остынет место встречи.

Инструмент конечно хороший, но его окупаемость под вопросом.

Если проект под бесплатными GCC или LLVM, то это будет наверно оправдано.
Хотя если с самого начала сидят на бесплатных тулсах, то врядли разработчику купят платный отладчик, да ещё адаптер J-Link стоит немало.

А если проект на IAR, то его C-Spy даст больше преимуществ чем System Viewer.
Чтобы в C-Spy отслеживать события прерывавний в реальном времени не нужно вообще никаких программных вставок в обработчики прерываний. Это сильно упрощает наблюдение за живучестью системы.

С другой стороны то, что в System Viewer показано на демо-скриншотах далеко от реальности.
Не поверю что кто-то вот так сидит и смотрит за таким огромным количеством событий и переменных. А перед этим еще рутинно конфигурирует это.

Нет, смотрят за узкими участками , парочка переменных, желательно видеть сразу все прерывания, и не искаженные программными отладочными вставками. Желательно видеть состояния задач и всех объектов синхронизации (ивенты, семафоры, мьютексы, пайпы и т.д.) Это все есть в C-Spy через аддоны к десятку разных RTOS.

Ну и в последнее время кардинально поменялся сам рабочий процесс отладки. Больше нет глупых ошибок типа: не там запятая, не то имя, неправильное условие в if, пустой указатель, утечка памяти и тому подобные мелочи. Т.е. нет больше тех абсурдных ошибок из-за которых надо было перерывать все исходники сверху до низу. Cloude Opus 4.6 просто не делает таких ошибок в принципе.
Остались только ошибки высокого порядка, когда непонятно как работает API многоуровневых библиотек и плоходокументированная внутреняя периферия микроконтроллера или внешняя переферия. И это решается в основном логами. И самый полезный инструмент тогда RTT Viewer. Но он идет с J-Link и System Viewer для этого не нужен.

Архитектура так себе. Не стоило копировать старые западные образцы.

Можно было бы применить EtherCAT и уйти от этих монструозных и негибких кроссплат.
Очевидно что несмотря на большое количество разъемов объем диагностической информации снимаемой с объектов минимален. А это значит увеличенное время затрачиваемое на ремонт и диагностику. Все еще усложняется этой массой проводов идущих в один ящик.
Дополнительну цену добавляют бесконечные гальваноразвязки. И при этом, как видно по платам, разработчики слабо себе представляют защиту от ЭМИ. Нельзя ставит быстрый чип посреди платы с разъемами со всех сторон. Спасает наверно что там старый медленный DSP на 28 нм.

Не думаю что это хороший пример для подражания.

Ну смотрим что на борту у khadas edge 2

И что на борту у Samsung Buds 3

И ничего не видим подходящего для аудио у Khadas Edge2
Ни FIR ни IIR ни EQ.
Эт значит что на Khadas все это делаться будет программно с выделением кучи тепла. Там надо будет еще радиатор поставить.
Глухим врядли помогут EasyEffects. EasyEffects - довольно примитивный набор операций аудиобработки. Там нет ни beamforming, ни работы с ориентацией.

Так в слуховых и стоит ARM, только многоядерный и еще много ядер DSP.
Забавно то что в Samsung Buds 3 pro стоит еще более мощный чип
Там и акселерометры с гироскопами стоят, чтобы знать куда голова повернута.
И по три микрофона в каждом наушнике: вперед, назад и вниз.

Но проблему возбуждений и свистов почему-то никто не может решить до конца.
Прежде чем Buds успеет подавить свист проходит где-то полсекунды. Но через секунду снова засвистеть может.
Линукс для аудиообработки вообще не при чем, там просто распределенные многоядерные вычисления, никакой операционной среды не нужно, все на прерываниях можно сделать.
На BLE стоит отдельное ядро и FreeRTOS будет достаточно.
Тут еще удивлятся надо почему слуховые апараты не греют уши. Линукс бы знатно подогрел затылок.

Ну прям точь в точь описан Oticon Intent 1 miniRITE
Только он стоил 5000 евро. Носил как-то.
Да , там в качестве наворота предлагался просто блютус к телефону чтобы слушать музыку.
И да он возбуждался только от того что подносил ладонь к уху. И да, на ветру просто все глохло. Акуумулятры были встроены. Заряжать надо было каждый день!

К некторым слуховым аппаратам делают анатомические вставки в каждое ухо индивидуально и менять их не надо. Но и они не убирают акустическую обратную связь. Все равно свисят от каждого чиха.

Словом купил Samsung Buds 3 pro и получил мощнее DSP, тот же эквалайзер только с большим количеством частот и лучшим качеством звука.

Правда Oticon предлагает докторам некое приложение, где прицизионно можно настраивать АЧХ под слух пациента. Доктора приложением не делятся. Оно видать очень дорогое и залоченное.
Но вы бы видели чем доктора измеряют слух пациента в коммерческих кабинетах! Это какие-то допотопные дедовские приставки, неизолированные от шума помещения , прямо у них за канцелярским столом где за окном шумит улица.
Что-то не так в этой индустрии, это точно.

Интересность темы только в том, что предложена юридическая чистота.
Но в судебной системе основанной на прецедентах быстро создадут новый прецедент.

В ответственных встраиваемых системах все сорсы должны быть открыты. И либы стоимостью многие тысячи абсолютно открыты для сторонних разработчиков. Вот где бы силы приложить и все отрефакторить. Но есть барьер - новые пересозданные сорсы надо будет заново сертифицировать. Ну все, идее конец.

А так, конечно, берем и рефакторим все что под руку попадается. Потому что опенсор просто перегружен многоплатформенностью. Простая чистка его от многоплатформенности уже делает его значительно проще и понятней.

Это какое-то просто недоразумение - слову  "интеллектуальный" приписать такое унизительное значение.
Однако могу уверенно сказать, что этот модуль легко убить просто оторвав один провод от нагрузки во время работы.
И вот тут и нужен был бы интеллект. Чтобы понять какой провод оторвали, что убито в модуле, как это быстро починить.
Суперинтеллект - это когда модуль знает к какой нагрузке он подключен и оценивает постоянно риск обрыва провода, о чем заранее предупреждает и отключается.

Это немного странно.

Claude пишет программы намного лучше меня, они у него гораздо надёжней и понятней, чем мои собственные. Он прекрасно понимает мой стиль по прошлым сорсам и строго его придерживается. Ведущие программисты уже перестали писать код руками, модели выигрывают олимпиады по математике, сдают медицинские экзамены.

А вот с обычными текстами вдруг всё, приехали: ни шаблоны уловить не может, ни стилю следовать. Код - пожалуйста, а пару абзацев связного текста - непосильная задача. И это от моделей, которые сами себя называют языковыми. Как так-то?

А ведь можно пойти дальше: не просто писать как человек, а писать для конкретного человека. Проанализировать, как он сам пишет, что лайкает, какой тон ему ближе - и генерировать текст, который именно ему зайдёт.

Подозреваю, что автор просто перестала различать, где пишет AI, а где человек.

⚠️ Режим персонификации здесь еще не включен.

Вот этот пункт остался нераскрытым

ВСМ, имеющие в своем составе драйвер, датчики напряжения, тока и температуры и полный набор защитных и сервисных функций, – полностью защищают транзисторный преобразователь от всех аварийных ситуаций в его аппаратном обеспечении и ошибок в ПО, благодаря чему вывести его из строя практически невозможно.

Защиты сами по себе не есть высокоинтеллектуальные функции. А бы сказал - это базовый минимум. Как без них в принципе сделать надежный дивайс?
Защита сработала - дивайс отключился. При чем тут интеллект?

Как все же эти защиты "полностью защищают"?
Есть какие-то AI алгоритмы ? Проактивность? Идентификация предаварийных состояний?
Там какой мощности процессор-то стоит? Он имеет связные интерфейсы какие-нибудь?

J-Link предлагает лучше чем светодиод - RTT
Это как тысяча светодиодов.

Самое замечательное что с ИИ такие эксперименты можно делать за 5 мин, пока чистишь зубы.


Вот что ответил Claude Opus 4.6

Но я вижу проблемы в своих паролях:

  1. ❌ Цифра 0 вообще не используется — алфавит фактически 67, а не 68

  2. ❌ Некоторые буквы (e, i, o) почти не встречаются — распределение неравномерное

  3. ❌ Спецсимволы всегда ровно 4 на пароль — предсказуемая структура

  4. ❌ Паттерны в позициях — спецсимволы тяготеют к определённым местам

  5. ❌ Прописные буквы встречаются чаще строчных — перекос

Реалистичная оценка:

Из-за неравномерного распределения и паттернов, энтропия Шеннона будет примерно ~5.5–5.8 бит/символ, что даёт:

H_total ≈ 88–93 бита вместо теоретических 97.4


Меня устраивает.
Еще удобство в том что с ИИ структуру паролей можно кастомизировать
Типа такие

  1. koShka-Oblako-42-zamOk

  2. ryBa-molNiya-Lev-noch7

  3. Veter-knIga-soLnce-19

  4. gorOd-Ptica-rEka-sNeg3

  5. Kamen-zvEzda-dOzhd-81

  6. More-deRevo-Ogon-lUna5

  7. Pesok-grOza-Trava-zIma

  8. holOd-Muzyka-sVet-Dom2

  9. Rybak-Oblako-klYuch-77

  10. Zamok-tiGr-Volna-Les49

Рекомендации:

  • 4 слова (~52 бита) — достаточно для большинства сайтов

Да , не читал. Я не читаю мусор.
Но согласен, что использованный вами ИИ очень уж примитивен.
Вот даю вам интерактивный движок для изучения PID с автоматичеким расчетом оптимальных параметров.
Из него вы узнает, что для ваших идеальных игровых объектов всегда можно найти идеальные коэфициенты PID без этих танцев с бубном.
И смысла играться нет, всегда можно рассчитать не прибегая к понятиям.
Проблема совсем в другом месте и там понятия не помогают.

Скрытый текст
import sys
import numpy as np
import matplotlib
try:
    matplotlib.use('TkAgg')
except ImportError:
    try:
        matplotlib.use('Qt5Agg')
    except ImportError:
        pass

import matplotlib.pyplot as plt
from matplotlib.widgets import Slider, Button
import matplotlib.patches as mpatches
import matplotlib.gridspec as gridspec

print(f"Matplotlib backend: {matplotlib.get_backend()}")


class PIDController:
    def __init__(self, kp=1.0, ki=0.0, kd=0.0):
        self.kp = kp
        self.ki = ki
        self.kd = kd
        self.reset()

    def reset(self):
        self.integral = 0.0
        self.prev_error = 0.0
        self.p_hist = []
        self.i_hist = []
        self.d_hist = []
        self.error_hist = []

    def update(self, error, dt):
        p = self.kp * error
        self.integral += error * dt
        i = self.ki * self.integral
        d = self.kd * (error - self.prev_error) / dt if dt > 0 else 0.0
        self.prev_error = error
        self.p_hist.append(p)
        self.i_hist.append(i)
        self.d_hist.append(d)
        self.error_hist.append(error)
        return p + i + d


def simulate(kp, ki, kd, setpoint, mass, damping, stiffness,
             duration=12.0, dt=0.005, disturbance_t=None, disturbance_amp=0.0):
    pid = PIDController(kp, ki, kd)
    n = int(duration / dt)
    t = np.linspace(0, duration, n)
    x, v = 0.0, 0.0
    x_hist = np.zeros(n)
    u_hist = np.zeros(n)
    for i in range(n):
        error = setpoint - x
        u = pid.update(error, dt)
        dist = 0.0
        if disturbance_t is not None and t[i] >= disturbance_t:
            dist = disturbance_amp
        a = (u + dist - damping * v - stiffness * x) / mass
        v += a * dt
        x += v * dt
        x_hist[i] = x
        u_hist[i] = u
    return (t, x_hist, u_hist,
            np.array(pid.p_hist), np.array(pid.i_hist),
            np.array(pid.d_hist), np.array(pid.error_hist))


def draw_block_diagram(ax):
    ax.clear()
    ax.set_xlim(0, 20)
    ax.set_ylim(0, 5)
    ax.axis('off')

    box_kw = dict(boxstyle="round,pad=0.5", linewidth=2)
    cy = 3.0

    ax.annotate("", xy=(2.2, cy), xytext=(0.4, cy),
                arrowprops=dict(arrowstyle='->', lw=2.5, color='green'))
    ax.text(0.2, cy, 'SP', fontsize=14, color='green', fontweight='bold',
            ha='center', va='center')

    circle = plt.Circle((3.0, cy), 0.4, fill=False, lw=2.5, color='black')
    ax.add_patch(circle)
    ax.text(3.0, cy, 'Σ', fontsize=18, ha='center', va='center', fontweight='bold')
    ax.text(2.7, cy + 0.3, '+', fontsize=12, ha='center', va='center', color='green')
    ax.text(2.7, cy - 0.35, '−', fontsize=14, ha='center', va='center', color='red')

    ax.annotate("", xy=(5.2, cy), xytext=(3.4, cy),
                arrowprops=dict(arrowstyle='->', lw=2.5))
    ax.text(4.3, cy + 0.35, 'e(t)', fontsize=12, ha='center', va='center',
            color='#555', style='italic')

    pid_box = mpatches.FancyBboxPatch((5.2, cy - 0.8), 4.0, 1.6,
                                       **box_kw, facecolor='#DDEEFF',
                                       edgecolor='#3366AA')
    ax.add_patch(pid_box)
    ax.text(7.2, cy + 0.3, 'PID-регулятор', fontsize=13, ha='center',
            va='center', fontweight='bold', color='#3366AA')
    ax.text(7.2, cy - 0.3, r'$K_p e + K_i\!\int\!e\,dt + K_d \frac{de}{dt}$',
            fontsize=12, ha='center', va='center', color='#333')

    ax.annotate("", xy=(10.8, cy), xytext=(9.2, cy),
                arrowprops=dict(arrowstyle='->', lw=2.5))
    ax.text(10.0, cy + 0.35, 'u(t)', fontsize=12, ha='center', va='center',
            color='#555', style='italic')

    plant_box = mpatches.FancyBboxPatch((10.8, cy - 0.8), 4.5, 1.6,
                                         **box_kw, facecolor='#FFF3DD',
                                         edgecolor='#CC8800')
    ax.add_patch(plant_box)
    ax.text(13.05, cy + 0.3, 'Объект управления', fontsize=13, ha='center',
            va='center', fontweight='bold', color='#CC8800')
    ax.text(13.05, cy - 0.3, r'$m\ddot{x}+b\dot{x}+kx=u$', fontsize=12,
            ha='center', va='center', color='#333')

    ax.annotate("", xy=(17.5, cy), xytext=(15.3, cy),
                arrowprops=dict(arrowstyle='->', lw=2.5, color='blue'))
    ax.text(18.3, cy, 'x(t)', fontsize=14, color='blue', fontweight='bold',
            ha='center', va='center')

    ax.annotate("", xy=(13.05, cy - 0.8), xytext=(13.05, 0.6),
                arrowprops=dict(arrowstyle='->', lw=2, color='purple',
                                linestyle='dashed'))
    ax.text(13.05, 0.3, 'Возмущение d(t)', fontsize=11, ha='center',
            va='center', color='purple', style='italic')

    ax.plot([16.8, 16.8], [cy, 1.2], lw=2, color='red')
    ax.plot([16.8, 3.0], [1.2, 1.2], lw=2, color='red')
    ax.annotate("", xy=(3.0, cy - 0.4), xytext=(3.0, 1.2),
                arrowprops=dict(arrowstyle='->', lw=2, color='red'))
    ax.text(10.0, 0.85, 'Обратная связь (feedback)', fontsize=11,
            ha='center', va='center', color='red', style='italic')


def calc_metrics(t, x, setpoint):
    overshoot = max((np.max(x) - setpoint) / setpoint * 100, 0) if setpoint != 0 else 0
    idx_90 = np.where(x >= 0.9 * setpoint)[0]
    rise_time = t[idx_90[0]] if len(idx_90) > 0 else float('inf')
    band = 0.02 * abs(setpoint)
    settle_time = t[-1]
    for i in range(len(t) - 1, -1, -1):
        if abs(x[i] - setpoint) > band:
            settle_time = t[min(i + 1, len(t) - 1)]
            break
    tail = x[int(0.9 * len(x)):]
    steady_error = abs(setpoint - np.mean(tail))
    return overshoot, rise_time, settle_time, steady_error


# ═══════════════════════════════════════════════════════════════
#  Автоподбор PID — минимизация ITAE (интеграл |t·e(t)|)
#
#  Цель: максимально быстрый и точный выход на уставку,
#         минимальная статическая ошибка, без оглядки на
#         возмущение.
#
#  Метод: грубый перебор по сетке → уточнение Нелдера-Мида
#         по критерию ITAE + штраф за перерегулирование.
# ═══════════════════════════════════════════════════════════════
def auto_tune_pid(mass, damping, stiffness):
    """
    Числовая оптимизация Kp, Ki, Kd для быстрого выхода
    на уставку с минимальной ошибкой.
    """
    dt = 0.005
    duration = 12.0
    setpoint = 1.0
    n = int(duration / dt)
    t = np.linspace(0, duration, n)

    def cost(params):
        kp, ki, kd = params
        if kp < 0 or ki < 0 or kd < 0:
            return 1e12

        pid = PIDController(kp, ki, kd)
        x, v = 0.0, 0.0
        total = 0.0
        for i in range(n):
            error = setpoint - x
            u = pid.update(error, dt)
            a = (u - damping * v - stiffness * x) / mass
            v += a * dt
            x += v * dt

            # ITAE: ∫ t·|e|·dt  — штрафует за долгую ошибку
            total += t[i] * abs(error) * dt

        # Штраф за перерегулирование (мягкий — не запрещаем,
        # но стараемся минимизировать)
        peak = max(pid.error_hist)  # макс. выход ≈ setpoint - min(error)
        # error_hist хранит (setpoint - x), значит x_max = setpoint - min(error_hist)
        x_max = setpoint - min(pid.error_hist)
        overshoot_frac = max(x_max - setpoint, 0) / setpoint
        total += overshoot_frac * 5.0  # умеренный штраф

        # Штраф за статическую ошибку
        x_final = setpoint - pid.error_hist[-1]
        total += abs(setpoint - x_final) * 50.0

        return total

    # ── Фаза 1: грубый перебор по сетке ──
    best_cost = 1e15
    best_params = (2.0, 1.0, 0.5)

    # Диапазоны зависят от параметров объекта
    omega0 = np.sqrt(max(stiffness, 0.1) / mass)
    kp_range = np.linspace(0.5, max(20, mass * 30), 8)
    ki_range = np.linspace(0.1, max(10, mass * 15), 6)
    kd_range = np.linspace(0.0, max(5, mass * 8), 6)

    for kp in kp_range:
        for ki in ki_range:
            for kd in kd_range:
                c = cost((kp, ki, kd))
                if c < best_cost:
                    best_cost = c
                    best_params = (kp, ki, kd)

    # ── Фаза 2: Нелдер-Мид (симплекс) уточнение ──
    try:
        from scipy.optimize import minimize
        result = minimize(cost, best_params, method='Nelder-Mead',
                          options={'maxiter': 500, 'xatol': 0.01,
                                   'fatol': 1e-6, 'adaptive': True})
        if result.fun < best_cost:
            best_params = tuple(result.x)
    except ImportError:
        # Если scipy нет — ручной симплекс-спуск
        params = list(best_params)
        step = [0.5, 0.3, 0.2]
        for iteration in range(200):
            improved = False
            for dim in range(3):
                for direction in [1, -1]:
                    trial = list(params)
                    trial[dim] += direction * step[dim]
                    trial[dim] = max(trial[dim], 0.0)
                    c = cost(trial)
                    if c < best_cost:
                        best_cost = c
                        params = trial
                        improved = True
            if not improved:
                step = [s * 0.7 for s in step]
                if max(step) < 0.005:
                    break
        best_params = tuple(params)

    kp, ki, kd = best_params
    kp = max(round(kp, 2), 0.01)
    ki = max(round(ki, 2), 0.01)
    kd = max(round(kd, 2), 0.00)

    return kp, ki, kd


def main():
    mass_init  = 1.0
    damp_init  = 0.3
    stiff_init = 0.5

    print("Оптимизация PID под параметры объекта...")
    kp_init, ki_init, kd_init = auto_tune_pid(mass_init, damp_init, stiff_init)
    print(f"Результат: Kp={kp_init}, Ki={ki_init}, Kd={kd_init}")

    init = dict(kp=kp_init, ki=ki_init, kd=kd_init,
                sp=1.0, mass=mass_init, damp=damp_init, stiff=stiff_init,
                dist_t=6.0, dist_a=-2.0)

    fig = plt.figure(figsize=(19, 14))
    fig.patch.set_facecolor('#F8F8F8')
    fig.suptitle("Интерактивная демонстрация PID-регулятора",
                 fontsize=16, fontweight='bold', y=0.99)

    gs = gridspec.GridSpec(3, 3, height_ratios=[1.0, 1.0, 1.0],
                           hspace=0.55, wspace=0.30,
                           left=0.06, right=0.97,
                           top=0.95, bottom=0.40)

    ax_schema = fig.add_subplot(gs[0, :])
    ax_out    = fig.add_subplot(gs[1, 0:2])
    ax_comp   = fig.add_subplot(gs[1, 2])
    ax_err    = fig.add_subplot(gs[2, 0:2])
    ax_info   = fig.add_subplot(gs[2, 2])

    draw_block_diagram(ax_schema)

    slider_h = 0.013
    gap = 0.032

    col1_left,  col1_width = 0.10, 0.28
    col2_left,  col2_width = 0.55, 0.28

    slider_top = 0.31

    slider_defs_left = [
        ("Kp",          0.0, 20.0, init['kp'],    '#CC3333'),
        ("Ki",          0.0, 10.0, init['ki'],     '#22AA44'),
        ("Kd",          0.0, 5.0,  init['kd'],     '#2277CC'),
        ("Уставка SP",  0.1, 3.0,  init['sp'],     '#888888'),
    ]
    slider_defs_right = [
        ("Масса m",     0.1, 5.0,  init['mass'],   '#CC8800'),
        ("Демпф. b",    0.0, 5.0,  init['damp'],   '#AA6600'),
        ("Жёстк. k",    0.0, 5.0,  init['stiff'],  '#886600'),
        ("t возм., с",  0.0, 11.0, init['dist_t'], '#8844AA'),
        ("Ампл. возм.", -5.0, 5.0, init['dist_a'], '#8844AA'),
    ]

    sliders = {}

    fig.text(col1_left + col1_width / 2, slider_top + 0.022,
             "▸ Параметры PID", ha='center', fontsize=10,
             fontweight='bold', color='#333')
    fig.text(col2_left + col2_width / 2, slider_top + 0.022,
             "▸ Объект и возмущение", ha='center', fontsize=10,
             fontweight='bold', color='#333')

    for idx, (label, vmin, vmax, vinit, color) in enumerate(slider_defs_left):
        y = slider_top - idx * gap
        ax_s = fig.add_axes([col1_left, y, col1_width, slider_h],
                            facecolor='#EEEEEE')
        sliders[label] = Slider(ax_s, label, vmin, vmax, valinit=vinit,
                                color=color, valstep=0.01)

    for idx, (label, vmin, vmax, vinit, color) in enumerate(slider_defs_right):
        y = slider_top - idx * gap
        ax_s = fig.add_axes([col2_left, y, col2_width, slider_h],
                            facecolor='#EEEEEE')
        sliders[label] = Slider(ax_s, label, vmin, vmax, valinit=vinit,
                                color=color, valstep=0.01)

    # ── Кнопки ──
    btn_w, btn_h = 0.06, 0.025

    ax_auto = fig.add_axes([col2_left + col2_width + 0.04,
                            slider_top - 0.5 * gap,
                            btn_w, btn_h])
    btn_auto = Button(ax_auto, 'Авто', color='#DDEEFF', hovercolor='#BBDDFF')

    ax_reset = fig.add_axes([col2_left + col2_width + 0.04,
                             slider_top - 2.5 * gap,
                             btn_w, btn_h])
    btn_reset = Button(ax_reset, 'Сброс', color='#DDDDDD', hovercolor='#FFCCCC')

    # Индикатор автоподбора
    auto_text = fig.text(col2_left + col2_width + 0.04,
                         slider_top - 4 * gap, '',
                         fontsize=8, color='#2266AA', family='monospace')

    def update(val=None):
        kp    = sliders["Kp"].val
        ki    = sliders["Ki"].val
        kd    = sliders["Kd"].val
        sp    = sliders["Уставка SP"].val
        mass  = sliders["Масса m"].val
        damp  = sliders["Демпф. b"].val
        stiff = sliders["Жёстк. k"].val
        dt_   = sliders["t возм., с"].val
        da    = sliders["Ампл. возм."].val

        t, x, u, p, i_c, d_c, err = simulate(
            kp, ki, kd, sp, mass, damp, stiff,
            duration=12.0, dt=0.005,
            disturbance_t=dt_ if da != 0 else None,
            disturbance_amp=da)

        ax_out.clear()
        ax_out.plot(t, x, 'b-', lw=1.8, label='Выход x(t)')
        ax_out.axhline(sp, color='green', ls='--', lw=1.2,
                       label=f'Уставка = {sp:.2f}')
        ax_out.fill_between(t, sp * 0.98, sp * 1.02, alpha=0.12,
                            color='green', label='±2% зона')
        if da != 0:
            ax_out.axvline(dt_, color='purple', ls=':', lw=1, alpha=0.7,
                           label=f'Возмущение t={dt_:.1f}с')
        ax_out.set_title("Выход системы", fontsize=10, fontweight='bold')
        ax_out.set_xlabel("Время, с")
        ax_out.set_ylabel("x(t)")
        ax_out.legend(fontsize=7, loc='upper right')
        ax_out.grid(True, alpha=0.25)
        ax_out.set_xlim(0, 12)

        ax_comp.clear()
        ax_comp.plot(t, p,   'r-', lw=1.2, label='P', alpha=0.85)
        ax_comp.plot(t, i_c, 'g-', lw=1.2, label='I', alpha=0.85)
        ax_comp.plot(t, d_c, 'b-', lw=1.2, label='D', alpha=0.85)
        ax_comp.plot(t, u,   'k--', lw=1.0, label='u=P+I+D', alpha=0.6)
        ax_comp.set_title("Составляющие P, I, D", fontsize=10, fontweight='bold')
        ax_comp.set_xlabel("Время, с")
        ax_comp.legend(fontsize=7)
        ax_comp.grid(True, alpha=0.25)
        ax_comp.set_xlim(0, 12)

        ax_err.clear()
        ax_err.plot(t, err, 'm-', lw=1.2, label='Ошибка e(t)')
        ax_err.plot(t, u,   'k-', lw=1.0, alpha=0.6, label='Управление u(t)')
        ax_err.axhline(0, color='gray', ls='-', lw=0.5)
        ax_err.set_title("Ошибка и управляющее воздействие",
                         fontsize=10, fontweight='bold')
        ax_err.set_xlabel("Время, с")
        ax_err.legend(fontsize=7, loc='upper right')
        ax_err.grid(True, alpha=0.25)
        ax_err.set_xlim(0, 12)

        # ── Метрики ──
        ax_info.clear()
        ax_info.axis('off')
        overshoot, rise_t, settle_t, ss_err = calc_metrics(t, x, sp)

        col_l = 0.05
        y0 = 0.97
        dy = 0.08

        def put(row, txt, color='#333', size=9.5, weight='normal'):
            ax_info.text(col_l, y0 - row * dy, txt,
                         transform=ax_info.transAxes,
                         fontsize=size, color=color, fontweight=weight,
                         family='monospace', va='top')

        put(0,    "── Метрики качества ──",              '#333',   10, 'bold')
        put(1,    f"Перерегулир.:  {overshoot:6.1f} %",  '#CC3333')
        put(2,    f"Время нараст.: {rise_t:6.3f} с",     '#2266AA')
        put(3,    f"Время устан.:  {settle_t:6.3f} с",   '#2266AA')
        put(4,    f"Стат. ошибка:  {ss_err:6.4f}",       '#22AA44')
        put(5.3,  "── Параметры PID ──",                 '#333',   10, 'bold')
        put(6.3,  f"Kp = {kp:.2f}",                      '#CC3333')
        put(7.3,  f"Ki = {ki:.2f}",                      '#22AA44')
        put(8.3,  f"Kd = {kd:.2f}",                      '#2277CC')
        put(9.6,  "── Объект ──",                        '#333',   10, 'bold')
        put(10.6, f"Масса m = {mass:.2f}",               '#CC8800')
        put(11.6, f"Демпф. b = {damp:.2f}",              '#AA6600')
        put(12.6, f"Жёстк. k = {stiff:.2f}",             '#886600')

        fig.canvas.draw_idle()

    def auto_tune(event):
        """Кнопка «Авто» — оптимизировать PID под текущий объект."""
        mass  = sliders["Масса m"].val
        damp  = sliders["Демпф. b"].val
        stiff = sliders["Жёстк. k"].val

        auto_text.set_text("Оптимизация...")
        fig.canvas.draw_idle()
        fig.canvas.flush_events()

        kp, ki, kd = auto_tune_pid(mass, damp, stiff)
        print(f"Авто: Kp={kp}, Ki={ki}, Kd={kd} "
              f"(m={mass}, b={damp}, k={stiff})")

        auto_text.set_text(f"Готово!\nKp={kp}\nKi={ki}\nKd={kd}")

        sliders["Kp"].set_val(kp)
        sliders["Ki"].set_val(ki)
        sliders["Kd"].set_val(kd)

    for s in sliders.values():
        s.on_changed(update)

    def reset(event):
        auto_text.set_text('')
        for s in sliders.values():
            s.reset()

    btn_reset.on_clicked(reset)
    btn_auto.on_clicked(auto_tune)
    update()

    print("Окно открывается...")
    plt.show()


if __name__ == "__main__":
    try:
        main()
    except Exception as e:
        print(f"\nОшибка: {e}")
        print(f"Backend: {matplotlib.get_backend()}")
        import traceback
        traceback.print_exc()
        print("\nПопробуйте: pip install PyQt5  или  sudo apt install python3-tk")

А, то есть это вообще для игр, а не для инженеров.
Тут обратная связь даже не предусматривалась.
Робототехника только чтобы побольше аудиторию охватить?

Ну так этот симулятор с ИИ и был сделан.
Это и есть тот самый мусор. Только по другому завернутый.
На практике важно знать что PID поломает шумная или медленная или нелинейная обратная связь и еще куча нюансов.
Но об этом помалкивают такие статьи, потому что проблема пока неподвластна ИИ и требует исследований.

Между тем Claude Opus 4.6 Fast mode подорожал в 30 раз! по сравнению с Claude Sonnet
Еще вчера было только 3 раза.
Что бы это могло значить?

Дал графики Microsoft на анализ Клоду
И вот что он нашел по поводу провалов у Microsoft

Самое большое падение пока еще не сегодня , были и большие падения.
Это ж капитализм. Фиксация прибыли и все такое.

Тут еще неделю назад также удачно некоторые срубили цену на золото.
Так что все идет по плану.

Нет формулы, посмотрите внимательнее. Есть матрицы.
Матрица - не формула. Или покажите мне эту формулу.
Sensor Fusion - вообще магия, и какие сенсоры в этот fusion включать агенты отлично понимают в отличие от людей.
Я решал руками ту же задачу с 3D и траекторией. И маджвика имплементировал тоже.
И несмотря что тут кто-то что-то выкладывал, Claude решает это лучше.
И идите мне скажите, что задача подбора сенсоров для fusion решена.

Я бы применил линейный абсолютный энкодер с кодами на основе битовых последовательнотей полученых алгоритмом вacktracking.
Такие применяются в лифтах с высокой надежностью позиционирования.

Прикол в том что фильтр Калмана это не КИХ какой-нибудь , у него нет формулы.
Это конструкция матриц, выливающаяся при раскрытии в совершенно разные наборы формул.
Поэтому говорить про 100 строк это так себе аргумент, подозрительный я бы сказал.
Обычные фильтры Claude Sonnet вообще как орехи щелкает, абсолютно безошибочно (ну несколько я проверял)
Там еще сплайны я генерил и S-кривые для механики. Тоже идеально. Еще и в моих страрых сорсах ошибки с кривыми находил и исправлял.
Так что там у вас с нерешенными задачами? Подкинете?

1
23 ...

Information

Rating
5,241-st
Registered
Activity

Specialization

Инженер встраиваемых систем, Инженер электронных устройств
Ведущий