<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="https://bipinmaharjan7.com.np/feed.xml" rel="self" type="application/atom+xml" /><link href="https://bipinmaharjan7.com.np/" rel="alternate" type="text/html" /><updated>2026-11-12T12:01:46+05:45</updated><id>https://bipinmaharjan7.com.np/feed.xml</id><title type="html">Bipin Maharjan</title><subtitle>Electrical engineer in Kathmandu working on grid-forming inverter control — Koopman operator methods, model predictive control and reinforcement learning — alongside hydropower governor commissioning and PLC/SCADA work.</subtitle><author><name>Bipin Maharjan</name></author><entry><title type="html">What a grid-forming inverter is actually doing</title><link href="https://bipinmaharjan7.com.np/writing/what-a-grid-forming-inverter-is-actually-doing/" rel="alternate" type="text/html" title="What a grid-forming inverter is actually doing" /><published>2026-07-23T00:00:00+05:45</published><updated>2026-07-23T00:00:00+05:45</updated><id>https://bipinmaharjan7.com.np/writing/what-a-grid-forming-inverter-is-actually-doing</id><content type="html" xml:base="https://bipinmaharjan7.com.np/writing/what-a-grid-forming-inverter-is-actually-doing/"><![CDATA[<p>Ask what separates a grid-following inverter from a grid-forming one and you’ll often
get an answer about control loops or firmware. The hardware is frequently identical.
The difference is a modelling assumption, and it decides everything downstream.</p>

<p>A grid-following inverter treats voltage and frequency as given. It locks onto them
with a phase-locked loop and injects the current it was asked to inject. It is a
current source that happens to be polite about phase. Remove the grid and it has
nothing to lock onto — the PLL has no reference, and the inverter shuts down.</p>

<p>A grid-forming inverter treats voltage and frequency as things it produces. It behaves
like a voltage source behind an impedance, and it decides its own angle. That’s the
whole shift: from “what does the grid want from me” to “what should the grid look
like.”</p>

<h2 id="where-droop-comes-from">Where droop comes from</h2>

<p>Once an inverter forms its own voltage, two of them on the same bus have a problem.
Nothing keeps their angles aligned, and even a small angle difference between two stiff
voltage sources pushes enormous circulating current between them.</p>

<p>Droop control solves this by making each unit’s frequency depend on the real power it’s
delivering, and its voltage on the reactive power. Take on more load, run slightly
slower. Because every unit on the microgrid ultimately settles at one common frequency,
this quietly forces them to share load in proportion to their droop coefficients — with
no communication link at all.</p>

<p>It’s a beautiful mechanism, and it costs you something: the settled frequency is not
the nominal frequency. Droop is a proportional controller, so it leaves steady-state
error by construction.</p>

<h2 id="which-is-where-secondary-control-comes-in">Which is where secondary control comes in</h2>

<p>Something has to push frequency back to nominal after droop has done the sharing. In a
conventional system that’s a slow integral controller sitting above the droop loop.</p>

<p>That layer is where my thesis lives. The plant it acts on is nonlinear — power flow
involves sines of angle differences, and the LCL filter and dynamic loads add their own
dynamics — so the conventional answer is a PI controller tuned around one operating
point and hoped to be adequate at the others.</p>

<p>The alternative I’m testing is to learn a linear predictor for the lifted dynamics and
put constrained MPC on top of it. Same job, better excursions, and honest constraint
handling instead of anti-windup patches.</p>

<p>More on how that turns out as the results come in.</p>]]></content><author><name>Bipin Maharjan</name></author><category term="inverters" /><category term="microgrids" /><category term="droop" /><summary type="html"><![CDATA[Ask what separates a grid-following inverter from a grid-forming one and you’ll often get an answer about control loops or firmware. The hardware is frequently identical. The difference is a modelling assumption, and it decides everything downstream.]]></summary></entry><entry><title type="html">The affine lift that fixed my Koopman model</title><link href="https://bipinmaharjan7.com.np/writing/the-affine-lift-that-fixed-my-koopman-model/" rel="alternate" type="text/html" title="The affine lift that fixed my Koopman model" /><published>2026-07-20T00:00:00+05:45</published><updated>2026-07-20T00:00:00+05:45</updated><id>https://bipinmaharjan7.com.np/writing/the-affine-lift-that-fixed-my-koopman-model</id><content type="html" xml:base="https://bipinmaharjan7.com.np/writing/the-affine-lift-that-fixed-my-koopman-model/"><![CDATA[<p>For weeks my EDMDc model was accurate enough to look promising and wrong enough to be
useless. One-step prediction was fine. Roll it forward thirty steps — the horizon the
MPC actually needs — and the multi-step NRMSE sat around 16.8%. The trajectory shape
was right. The level was not.</p>

<p>The fix was one observable: a constant. Setting the first entry of the lifted state to
1 for every sample.</p>

<h2 id="why-a-constant-matters">Why a constant matters</h2>

<p>EDMDc fits a linear map from lifted state and input to next lifted state. Every term in
that map is proportional to something in the data. If the true dynamics have any offset
that doesn’t scale with the state — an equilibrium that isn’t at the origin, a bias in
the measurement, a load contribution the input doesn’t see — a purely linear map has no
way to express it. It can only approximate the offset by bending the state-dependent
terms, and those bends compound every time you roll the prediction forward.</p>

<p>Including a constant observable gives the regression an affine term. The identified
model becomes</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>z(k+1) = A z(k) + B u(k) + c
</code></pre></div></div>

<p>with <code class="language-plaintext highlighter-rouge">c</code> absorbed into <code class="language-plaintext highlighter-rouge">A</code> through the constant entry. Now the offset is represented
once, explicitly, instead of being smeared across the state matrix.</p>

<p>Multi-step NRMSE dropped to 2.25%.</p>

<h2 id="the-part-thats-easy-to-miss">The part that’s easy to miss</h2>

<p>Rescaling the inputs and outputs to comparable magnitudes mattered almost as much. Real
power setpoints live in the hundreds of watts; frequency deviations live in hundredths
of a hertz. Handed to a least-squares solve unscaled, the DC gain of the identified
model is conditioned badly enough that the controller’s steady-state behaviour is
essentially arbitrary — not unstable, just quietly wrong.</p>

<p>Neither of these is a contribution. Both are the difference between a pipeline that
produces a result and one that produces a plot you have to apologise for.</p>

<h2 id="what-id-check-first-next-time">What I’d check first next time</h2>

<ul>
  <li>Does the lifted dictionary include a constant?</li>
  <li>Are inputs and outputs on comparable scales before the regression?</li>
  <li>Is multi-step error being reported at the MPC horizon, not at one step?</li>
</ul>

<p>The third one is the trap. One-step error flatters every model ever fitted.</p>]]></content><author><name>Bipin Maharjan</name></author><category term="koopman" /><category term="edmdc" /><category term="mpc" /><summary type="html"><![CDATA[For weeks my EDMDc model was accurate enough to look promising and wrong enough to be useless. One-step prediction was fine. Roll it forward thirty steps — the horizon the MPC actually needs — and the multi-step NRMSE sat around 16.8%. The trajectory shape was right. The level was not.]]></summary></entry></feed>