OpenSees 면진과 감쇠: 자기가 어디 있는지 신경 쓰지 않는 첫 요소들
손으로 몬 점성재료는 변형률 0.02, 속도 0.3에서 15.0000 을 보고하고 변형률 0.00, 같은 속도에서도 정확히 같은 15.0000 을 보고한다. 대시포트에는 강성도 기억도 없기 때문이다. 지수가 1보다 작으면 1 m/s 미만의 모든 속도에서 힘이 오히려 커지고, C 를 두고 alpha 만 1
이 시리즈의 지금까지 모든 요소는 자기가 어디 있느냐만 신경 썼습니다. 점성 감쇠기는 전혀 신경 쓰지 않습니다. 변형률 0.02에 속도 0.3으로 몰면 15.0000을 보고합니다. 변형률 0.00에 같은 속도로 몰아도 15.0000입니다. 힘은 속도만의 함수이고 그 외 아무것도 아닙니다. 이것이 진짜로 새로운 축입니다. 16부는 상태기계를 시간축으로, 18부는 변형 사슬을 공간축으로 따라갔고, 면진·감쇠 장치는 그 둘이 건드리지 않은 세 번째 의존성을 더합니다.
이 글은 앞선 편들이 빼놓았던 장치군 — 점성 감쇠기, 탄성받침, 마찰진자 — 을 다루며, 방식은 나머지와 같습니다. 모든 수치를 OpenSeesPy 3.8.0에서 측정하고 그것을 만들지 않은 무언가와 대조했습니다. 그리고 쓰는 도중 제가 직접 걸린 조용한 실패 하나를 기록합니다.
1. 속도 의존성을 손으로 몰기
16부에서 1축 재료를 testUniaxialMaterial과 setStrain으로 파이썬에서 직접 몰 수 있다는 것을 보였습니다. 같은 명령이 두 번째 인자를 받고, 그 인자가 변형률 속도입니다.
ops.uniaxialMaterial('Viscous', 1, 50.0, 1.0) # F = C v^alpha ops.testUniaxialMaterial(1) ops.setStrain(strain, rate) # 두 번째 인자가 속도 ops.getStress()
변형률속도getStress()C × 속도
0.00+0.0+0.0000+0.0000
0.01+0.0+0.0000+0.0000
0.00+0.1+5.0000+5.0000
0.00+0.3+15.0000+15.0000
0.02+0.3+15.0000+15.0000
0.00−0.3−15.0000−15.0000
2행과 5행이 요점 전부입니다. 변형률 0.01에 속도 0이면 힘이 0이고, 변형률 0.02에 속도 0.3이면 변형률이 아예 없을 때와 정확히 같은 힘입니다. 순수 대시포트에는 강성도 기억도 없습니다. 이름값 하는 확정상태가 없고, 그래서 16부의 Steel01과 달리 그 전에 무엇을 했든 아무 상관이 없습니다.
α = 0.5, C = 50으로 같은 탐침을 하면 속도 0.1에서 15.81139, 0.3에서 27.38613, 1.0에서 50.00000이 나오고 이는 50·v^0.5와 모든 자리까지 같습니다. 효과의 방향에 주목하십시오. 속도가 1 미만이면 지수가 낮을수록 힘이 작아지는 게 아니라 커집니다. "비선형 감쇠기"라는 말에서 대부분이 갖는 직관과 반대이고, 다음 절에서 그것이 문제가 됩니다.
2. 감쇠 진동자는 자기가 받은 감쇠를 돌려준다
탄성 스프링과 점성 대시포트를 같은 zeroLength 요소 안에 병렬로 넣고, 질량을 붙이고, 20 mm 당겼다가 놓습니다.
ops.element('zeroLength', 1, 1, 2, '-mat', 1, 2, '-dir', 1, 1) # 스프링과 대시포트
Δt최대 |u − 정확해|로그감쇠율에서 얻은 ζ
0.01 s1.942 × 10⁻³ m0.050108
0.002 s3.744 × 10⁻⁴ m0.049983
0.0005 s9.290 × 10⁻⁵ m0.050000
모델에는 ζ = 0.05인 C = 2ζωm을 줬고, 한 사이클에 대해 측정한 감쇠율이 그것을 정확히 돌려줍니다. 대시포트·질량·스프링·적분기를 한 번에 닫는 검증이고, 감쇠가 있는 모델을 믿기 전에 돌려볼 검사입니다. 네 줄이면 됩니다.
3. α가 바뀌면 C는 같은 양이 아니다
α한 사이클 등가 ζ한 사이클 뒤 변위
1.00.05000014.60 mm
0.50.15283410.45 mm
0.30.5176207.64 mm
C를 두고 α만 1.0에서 0.3으로 바꾸자 유효 감쇠가 열 배가 됐습니다. 모델링의 미묘함이 아니라 차원해석입니다. C의 단위가 kN·(s/m)^α이므로 그 숫자는 지수마다 다른 물리량을 뜻합니다. 두 감쇠기를 C 값으로 비교하는 것은 α가 같을 때만 의미가 있습니다.
실무 규칙은 계수가 아니라 설계점을 고정하는 것입니다. 장치가 "0.5 m/s에서 800 kN"으로 규정돼 있다면 C = 800/0.5^α이고, 그것이 모델에 넣을 숫자입니다. 다른 지수에서 가져온 C가 아니라.
4. 마찰진자는 질량을 신경 쓰지 않는다
마찰진자가 매력적인 이유인 성질은 복원강성이 W/R이어서 떠받치는 무게에 비례하고, 따라서 주기가 2π√(R/g) — 질량과 무관 — 이라는 것입니다. 강한 주장이고 정확히 검사할 수 있습니다.
2 pi sqrt(R/g) = 3.002918 s mass 1.0 Mg -> T = 3.002500 s rel err 1.39e-04 mass 10.0 Mg -> T = 3.002500 s rel err 1.39e-04
질량을 10배 바꿔도 측정된 주기가 출력된 모든 자리까지 동일합니다. 닫힌해와의 1.4 × 10⁻⁴ 차이는 남은 마찰과 유한한 초기강성이지 질량이 아닙니다.
마찰은 재중심의 한계도 정합니다. 300 mm에서 놓으면 베어링은 모든 경우에 중심에서 μR 안에 멈춥니다.
μμR20초 뒤 잔류변위
0.0122.4 mm12.94 mm
0.0244.8 mm31.70 mm
0.0489.6 mm57.62 mm
0.06134.4 mm31.64 mm
μR은 복원력 W u/R이 마찰력 μW와 정확히 균형을 이루는 변위입니다. 여기서도 질량이 소거됩니다. 그 띠 안에서 베어링은 그냥 있는 자리에 멈추고, 그래서 잔류변위가 이 장치들에서는 수치적 잡음이 아니라 설계량입니다.
5. 제가 걸린 조용한 실패
베어링 요소는 절점이 겹쳐 있어서 자기 국부축을 추론할 수 없고, -orient가 필수입니다.
ops.element('singleFPBearing', 1, 1, 2, 1, R, kInit, '-P', 2, '-Mz', 2, '-orient', 0.0, 1.0, 0.0, -1.0, 0.0, 0.0) # 국부 x 가 전역 y
이 부분은 시끄럽게 실패합니다 — incorrect dimension of orientation vectors. 다음 부분은 그렇지 않습니다. 저는 ops.fix(2, 0, 1, 1)이라고 써서 베어링 상단 절점을 연직으로 잡았습니다. 수평 운동만 원할 때 자연스럽게 쓰게 되는 형태입니다. 그러면 하중이 그 구속으로 곧장 가고 요소에는 결코 닿지 않습니다. 축력이 없으니 복원강성 W/R도 마찰도 없고, 그래서:
중력 뒤에도, 50 mm 옆으로 민 뒤에도 eleResponse(1, 'force')의 모든 성분이 정확히 0.0000;
나왔어야 할 복원력은 W u / R = 0.2189 kN;
모든 analyze()가 0을 반환했고, 블록은 해석 내내 50.000 mm에 앉아 있었습니다.
고치는 것은 ops.fix(2, 0, 0, 1) — 문자 하나입니다. 일반화하면 이 시리즈가 새 방향에서 계속 도달하는 그 교훈입니다. 자기를 정의하는 양이 자기가 받는 힘인 장치는, 실수로 아무것도 안 받게 만들어두면 불평하는 대신 0을 보고합니다. 검사는 다른 무엇보다 먼저 중력 뒤의 축력을 읽는 것입니다.
6. 면진·감쇠 모델에서 확인할 것
베어링이 실제로 하중을 받는가? 중력 뒤 축력을 읽는다. 0이면 그 아래는 전부 무의미하다.
-orient가 있는가, 그리고 국부 x축이 의도한 그 축인가?
C를 같은 α의 장치 사양에서, 명시된 속도에서 가져왔는가?
자유진동 시험이 의도한 감쇠비를 돌려주는가?
면진 주기가 2π√(R/g) 또는 2π√(m/K_d)가 말하는 값인가?
잔류변위가 μR 안에 있는가, 그리고 그것이 허용 가능한가?
감쇠기 힘이 수렴할 만큼 시간 간격이 작은가 — 16부의 규칙을 변위가 아니라 속도에 적용한 것.
7. 같은 장치를 다섯 단계 깊이로
입문자는 감쇠기를 넣고 응답이 줄어드는 것을 봅니다. 주니어는 감쇠비가 의도한 대로 나왔는지 확인합니다. 실무 해석자는 C와 α가 함께 다닌다는 것을 알고 하나만 옮겨 심지 않습니다. 시니어는 면진 주기를 닫힌해와 대조하고 잔류변위를 설계 출력으로 취급합니다. 전문가는 베어링의 축력을 가장 먼저 읽습니다. 장치의 다른 모든 성질이 그것에 비례하기 때문입니다.
전체 스크립트
이 글의 측정 셋 — 손으로 몬 대시포트, 감쇠 진동자, 마찰진자 — 을 단언과 함께.
# Part 19 - a viscous damper and a friction pendulum # units: kN, m, Mg, s import math import numpy as np import openseespy.opensees as ops # --- 1. drive the viscous material by hand: F = C v^alpha ----------------- C = 50.0 for alpha in (1.0, 0.5): ops.wipe(); ops.model('basic', '-ndm', 1, '-ndf', 1) ops.uniaxialMaterial('Viscous', 1, C, alpha) ops.testUniaxialMaterial(1) print(f'alpha = {alpha}') for strain, rate in ((0.00, 0.3), (0.02, 0.3), (0.00, -0.3)): ops.setStrain(strain, rate) # the second argument is the rate exact = C * abs(rate) ** alpha * (1 if rate >= 0 else -1) print(f' strain {strain:5.2f} rate {rate:+5.2f} -> {ops.getStress():+10.5f}' f' C v^alpha = {exact:+10.5f}') assert abs(ops.getStress() - exact) < 1e-9 # --- 2. a damped oscillator against the exact damped response ------------- M, K, ZETA, U0 = 1.0, 400.0, 0.05, 0.02 W = math.sqrt(K / M); Cd = 2 * ZETA * W * M WD = W * math.sqrt(1 - ZETA ** 2); T = 2 * math.pi / W def free_vibration(dt, tmax=6.0): ops.wipe(); ops.model('basic', '-ndm', 1, '-ndf', 1) ops.node(1, 0.0); ops.node(2, 0.0); ops.fix(1, 1); ops.mass(2, M) ops.uniaxialMaterial('Elastic', 1, K) ops.uniaxialMaterial('Viscous', 2, Cd, 1.0) ops.element('zeroLength', 1, 1, 2, '-mat', 1, 2, '-dir', 1, 1) # in parallel ops.setNodeDisp(2, 1, U0, '-commit') ops.constraints('Plain'); ops.numberer('Plain'); ops.system('BandGeneral') ops.test('NormDispIncr', 1e-12, 50); ops.algorithm('Newton') ops.integrator('Newmark', 0.5, 0.25); ops.analysis('Transient') t, u = [], [] while ops.getTime() < tmax: if ops.analyze(1, dt) != 0: break t.append(ops.getTime()); u.append(ops.nodeDisp(2, 1)) return np.array(t), np.array(u) print(f'\nT = {T:.6f} s, C = {Cd:.4f} kN s/m, zeta given = {ZETA}') for dt in (0.01, 0.002, 0.0005): t, u = free_vibration(dt) exact = U0 * np.exp(-ZETA * W * t) * (np.cos(WD * t) + ZETA / math.sqrt(1 - ZETA ** 2) * np.sin(WD * t)) i1, i2 = int(round(T / dt)), int(round(2 * T / dt)) d = math.log(abs(u[i1] / u[i2])) z = d / math.sqrt(4 * math.pi ** 2 + d ** 2) print(f' dt {dt:7.4f} max |u - exact| {np.max(np.abs(u - exact)):.3e}' f' zeta from decrement {z:.6f}') assert abs(z - ZETA) < 1e-5 # --- 3. a friction pendulum: T = 2 pi sqrt(R/g), whatever the mass -------- G, R_RAD = 9.80665, 2.24 ORI = ('-orient', 0.0, 1.0, 0.0, -1.0, 0.0, 0.0) # local x is global y def fp_period(mass, mu=1.0e-4, u0=0.05, dt=0.0005, tmax=8.0): ops.wipe(); ops.model('basic', '-ndm', 2, '-ndf', 3) ops.node(1, 0.0, 0.0); ops.node(2, 0.0, 0.0) ops.fix(1, 1, 1, 1) ops.fix(2, 0, 0, 1) # NOT fixed vertically: the bearing carries the weight ops.mass(2, mass, mass, 1e-9) ops.frictionModel('Coulomb', 1, mu) ops.uniaxialMaterial('Elastic', 2, 1.0e6 * mass) ops.element('singleFPBearing', 1, 1, 2, 1, R_RAD, 1.0e4 * mass, '-P', 2, '-Mz', 2, *ORI) ops.timeSeries('Constant', 1); ops.pattern('Plain', 1, 1) ops.load(2, 0.0, -mass * G, 0.0) ops.constraints('Transformation'); ops.numberer('Plain'); ops.system('BandGeneral') ops.test('NormDispIncr', 1e-10, 100); ops.algorithm('Newton') ops.integrator('LoadControl', 1.0); ops.analysis('Static'); ops.analyze(1) ops.loadConst('-time', 0.0) ops.timeSeries('Linear', 2); ops.pattern('Plain', 2, 2); ops.load(2, 1.0, 0.0, 0.0) ops.integrator('DisplacementControl', 2, 1, u0); ops.analyze(1) ops.remove('loadPattern', 2); ops.wipeAnalysis() ops.constraints('Transformation'); ops.numberer('Plain'); ops.system('BandGeneral') ops.test('NormDispIncr', 1e-10, 200); ops.algorithm('Newton') ops.integrator('Newmark', 0.5, 0.25); ops.analysis('Transient') t, u = [], [] while ops.getTime() < tmax: if ops.analyze(1, dt) != 0: break t.append(ops.getTime()); u.append(ops.nodeDisp(2, 1)) t, u = np.array(t), np.array(u) zc = [i for i in range(1, len(u)) if u[i - 1] > 0 >= u[i]] return float(np.mean(np.diff(t[zc]))) if len(zc) >= 2 else float('nan') T_x = 2 * math.pi * math.sqrt(R_RAD / G) print(f'\n2 pi sqrt(R/g) = {T_x:.6f} s') for m in (1.0, 10.0): p = fp_period(m) print(f' mass {m:6.1f} Mg -> T = {p:.6f} s rel err {abs(p-T_x)/T_x:.2e}') assert abs(p - T_x) / T_x < 1e-3 print('\nOK the damper follows C v^alpha, the oscillator returns its own zeta,') print(' and the pendulum period is the same for a tenfold change of mass')
실행하면 이렇게 나옵니다.
alpha = 1.0 strain 0.00 rate +0.30 -> +15.00000 C v^alpha = +15.00000 strain 0.02 rate +0.30 -> +15.00000 C v^alpha = +15.00000 strain 0.00 rate -0.30 -> -15.00000 C v^alpha = -15.00000 alpha = 0.5 strain 0.00 rate +0.30 -> +27.38613 C v^alpha = +27.38613 strain 0.02 rate +0.30 -> +27.38613 C v^alpha = +27.38613 strain 0.00 rate -0.30 -> -27.38613 C v^alpha = -27.38613 T = 0.314159 s, C = 2.0000 kN s/m, zeta given = 0.05 dt 0.0100 max |u - exact| 1.942e-03 zeta from decrement 0.050108 dt 0.0020 max |u - exact| 3.744e-04 zeta from decrement 0.049983 dt 0.0005 max |u - exact| 9.290e-05 zeta from decrement 0.050000 2 pi sqrt(R/g) = 3.002918 s mass 1.0 Mg -> T = 3.002500 s rel err 1.39e-04 mass 10.0 Mg -> T = 3.002500 s rel err 1.39e-04 OK the damper follows C v^alpha, the oscillator returns its own zeta, and the pendulum period is the same for a tenfold change of mass
OpenSees 시리즈 전체
각 편은 닫힌해·독립적인 풀이·OpenSees 소스 중 하나와 대조해 검증했다. 순서대로 읽도록 썼지만 각 편이 자기 전제를 스스로 밝힌다.
1부 — 도메인 모델과 해석 조립
2부 — 단면·기하변환·분포하중
3부 — 파이버 단면·모멘트–곡률·푸시오버
4부 — 질량·감쇠·시간적분
5부 — 라이브러리 읽기와 재현 가능한 워크플로
6부 — 철근콘크리트 파이버 단면과 구속
7부 — 실제 지진기록·층간변위·증분동적해석
8부 — 3차원: 강막·비틀림·leaning column
9부 — 수렴하지 않을 때: 실패·알고리즘·한계점
10부 — Tcl 읽기와 공개 스크립트 이식
11부 — 쉘·솔리드·지반: 락킹·메시·부지응답
12부 — 후처리: recorder·질의, 그리고 그림이 증명하는 것
13부 — 좌굴과 한계점: 분기점·스냅백·호장법
14부 — Windows: 설치·파일 형식·조용한 실패
15부 — 검증된 정답이 딸린 연습문제와 한영 용어집
16부 — 어떻게 동작하는가: 시행상태·확정상태·해석 루프
17부 — 커뮤니티가 말하는 것, 측정해보면
18부 — 절점 변위에서 파이버 응력까지
19부 — 면진과 감쇠: 속도 의존 요소와 베어링 — 지금 보는 글
참고 자료
OpenSeesPy, Viscous, ViscousDamper.
OpenSeesPy, singleFPBearing, flatSliderBearing, elastomericBearingPlasticity.
OpenSeesPy, frictionModel — Coulomb 과 속도 의존 모델들.
Zayas, V. A., Low, S. S., Mahin, S. A., "A simple pendulum technique for achieving seismic isolation", Earthquake Spectra 6(2), 1990 — R/g 주기의 출처.
Constantinou, M. C., Symans, M. D. 외, Fluid viscous dampers in applications of seismic energy dissipation, NCEER — F = C v^α 장치군.
Scott, M. H., OpenSees Digital.
출처 확인 2026-09-01. 모든 결과는 OpenSeesPy 3.8.0에서 산출했으며 위 스크립트로 재현할 수 있습니다. 마찰진자 주기는 질량 10배 변화에 대해 검증했습니다. 100배 이상은 여기서 쓴 연직강성으로는 완주하지 않아 보고하지 않습니다. 3절의 등가 감쇠비는 특정한 자유진동의 첫 사이클에서 측정한 값이며 지수의 일반적 성질이 아닙니다. 결과는 프레임워크의 거동을 보여주는 것으로, 프로젝트별 해석이나 설계기준 검토를 대체하지 않습니다.