' pid_controller.pb — PID controller simulation
#COMPILE EXE
#DIM ALL

FUNCTION PBMAIN() AS LONG
    LOCAL setpoint AS DOUBLE
    LOCAL processVar AS DOUBLE
    LOCAL errorVal AS DOUBLE
    LOCAL prevError AS DOUBLE
    LOCAL integral AS DOUBLE
    LOCAL derivative AS DOUBLE
    LOCAL outputVal AS DOUBLE
    LOCAL kp AS DOUBLE
    LOCAL ki AS DOUBLE
    LOCAL kd AS DOUBLE
    LOCAL dt AS DOUBLE
    LOCAL i AS LONG
    LOCAL j AS LONG
    LOCAL numSteps AS LONG
    LOCAL overshoot AS DOUBLE
    LOCAL settlingTime AS LONG
    LOCAL steadyStateError AS DOUBLE
    LOCAL maxOutput AS DOUBLE
    LOCAL minOutput AS DOUBLE
    LOCAL stepResponse(200) AS DOUBLE
    LOCAL timeVal AS DOUBLE
    LOCAL pTerm AS DOUBLE
    LOCAL iTerm AS DOUBLE
    LOCAL dTerm AS DOUBLE
    LOCAL iter AS LONG
    LOCAL stepIdx AS LONG

    setpoint = 100.0
    kp = 1.0
    ki = 0.1
    kd = 0.05
    dt = 0.1
    numSteps = 100

    PRINT "=== PID Controller ==="
    PRINT "Setpoint: " + STR$(setpoint)
    PRINT "kp=" + STR$(kp) + " ki=" + STR$(ki) + " kd=" + STR$(kd)

    processVar = 0.0
    integral = 0.0
    prevError = 0.0
    maxOutput = 0.0
    minOutput = setpoint

    FOR i = 1 TO numSteps
        errorVal = setpoint - processVar
        integral = integral + errorVal * dt
        derivative = (errorVal - prevError) / dt

        pTerm = kp * errorVal
        iTerm = ki * integral
        dTerm = kd * derivative

        outputVal = pTerm + iTerm + dTerm

        IF outputVal > 150 THEN outputVal = 150
        IF outputVal < 0 THEN outputVal = 0

        processVar = processVar + (outputVal - processVar * 0.1) * dt
        stepResponse(i - 1) = processVar

        IF outputVal > maxOutput THEN maxOutput = outputVal
        IF outputVal < minOutput THEN minOutput = outputVal

        prevError = errorVal

        IF i / 10 * 10 = i THEN
            PRINT "  t=" + STR$(i * dt) + " PV=" + STR$(processVar) + " Out=" + STR$(outputVal)
        END IF
    NEXT i

    steadyStateError = setpoint - processVar
    IF steadyStateError < 0 THEN steadyStateError = 0 - steadyStateError

    FOR i = 1 TO numSteps - 1
        IF stepResponse(i - 1) < setpoint AND stepResponse(i) >= setpoint THEN
            settlingTime = i
        END IF
    NEXT i

    overshoot = 0
    FOR i = 0 TO numSteps - 1
        IF stepResponse(i) > setpoint + overshoot THEN
            overshoot = stepResponse(i) - setpoint
        END IF
    NEXT i

    PRINT "--- Tuning Results ---"
    PRINT "Final PV: " + STR$(processVar)
    PRINT "Steady-state error: " + STR$(steadyStateError)
    PRINT "Overshoot: " + STR$(overshoot)
    PRINT "Settling time: " + STR$(settlingTime * dt) + "s"
    PRINT "=== End PID ==="
    FUNCTION = 0
END FUNCTION
