<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>modeling &amp;mdash; The Solar Ledger</title>
    <link>https://solar-ledger.blog/tag:modeling</link>
    <description>Rigorous data, system architectures, and real analysis for modern solar</description>
    <pubDate>Sun, 13 Sep 2026 20:49:07 +0000</pubDate>
    <image>
      <url>https://i.snap.as/rDn516Zy.jpg</url>
      <title>modeling &amp;mdash; The Solar Ledger</title>
      <link>https://solar-ledger.blog/tag:modeling</link>
    </image>
    <item>
      <title>Plug-in Solar: Building an Open Data Pipeline and Modeling Cost Impact</title>
      <link>https://solar-ledger.blog/plug-in-solar-building-an-open-data-pipeline-and-cost-impact-modeling?pk_campaign=rss-feed</link>
      <description>&lt;![CDATA[To evaluate the true financial returns of plug-in solar and battery storage, generalized assumptions must be replaced with high-resolution empirical data. Minute-by-minute data would enable excellent modeling, however this requires specialized equipment installed in the breaker box and a dedicated data capture system. Fortunately, most utilities offer 30-minute utility meter interval readings you can download from your account. With this data , plus past bills, meteorological data, and a physics-based photovoltaic (PV) simulation, I was able to create an excellent model of the actual utility power offset and the projected impact to my bill.&#xA;&#xA;1. Data Extraction: Navigating Utility Export Limitations&#xA;The utility industry established the Green Button Energy Service Provider Interface (ESPI) XML standard to allow consumers to download energy usage data. However, data collection from my utility revealed two critical limitations in Green Button XML exports:&#xA;&#xA;UI Restrictions &amp; Date Limits: The customer portal&#39;s XML export tool enforces a restriction limiting downloads strictly to the trailing 13 months, blocking access to historical multi-year data.  &#xA;Low Data Precision: Green Button XML exports round consumption readings to whole integer kilowatt-hours (1 kWh resolution), obscuring subtle household power dynamics.&#xA;&#xA;To overcome this, I chose to build my data pipeline using my utility’s &#34;Download Detailed Data&#34; Excel (.xlsx) export option. This format provides continuous 30-minute interval readings at three decimal places of precision (0.001 kWh). An automated Python ETL script parses these workbooks, aligns intervals chronologically, and ingests them into a local DuckDB time-series database.&amp;nbsp;&#xA;&#xA;2. Bill Parsing &amp; Tariff Structure Regression&#xA;Standard solar calculators assume an average flat electricity rate, but real utility tariffs consist of complex, multi-tiered line items. To model financial savings accurately, I created a Python script to extract the 21 meaningful line items from the monthly PDF bill statements. I used ordinary least squares (OLS) linear regressions with the data to classify fee behavior into three structural categories:&#xA;  &#xA;Strictly Proportional Charges: Generation, transmission, fuel, deferred fuel cost, sales/use surcharge, and state/local consumption taxes scale linearly down to zero with lower kWh usage.  &#xA;  &#xA;Partially Proportional Charges: Distribution service charges consist of a fixed monthly base customer fee of $11.23 plus a variable per-kWh rate.  &#xA;  &#xA;Capped Non-Proportional Charges: The local utility tax consists of a \$0.60 base fee plus a variable rate capped at a maximum of \$4.00/month.&#xA;  &#xA;When solar generation reduces grid energy consumption, fixed customer base fees and tax caps remain untouched while variable supply and distribution rates scale down proportionally.&#xA;&#xA;3. Satellite Solar Irradiance &amp; Performance Modeling&#xA;&#xA;Solar generation potential was derived using historical meteorological data retrieved from the Open-Meteo API for my county. The dataset provides 30-minute resolution Global Horizontal Irradiance (GHI), Direct Normal Irradiance (DNI), Diffuse Horizontal Irradiance (DHI), ambient temperature, and wind speed.&#xA;&#xA;Photovoltaic DC output was calculated using the physics-based PVWatts DC model implemented via Python&#39;s pvlib library (utilizing benchmarks established by my favorite National Lab \- the National Laboratory of the Rockies, formerly NREL):&#xA;&#xA;System DC Rating: 1,200, 1,300, 1,400, and 1,500 W  &#xA;Array Orientation &amp; Tilt: Fixed South-facing (Azimuth \= 180°), 38.85° tilt angle (equal to site latitude)  &#xA;Temperature Coefficient: \-0.0047 / °C  &#xA;Inverter Conversion Efficiency: 95.0% DC-to-AC  &#xA;Battery Round-Trip Efficiency: 95.0%&#xA;    &#xA;4. Interval Simulation &amp; Split-Phase Logic&#xA;For each 30-minute block, AC solar generation is calculated:&#xA;&#xA;$$\text{Solar AC (kWh)} = \left(\frac{\text{DC Power (W)} \times 0.5\text{ hrs}}{1000}\right) \times \text{Inverter Efficiency}$$&#xA;Net grid energy draw is then evaluated under an assumed 50/50 split-phase load across two 120 V legs (while this is not an ideal assumption, it’s the the best approximation I can make given the data I have available):&#xA;&#xA;Solar-Only Configuration (Single-Phase Injection): Solar offsets Leg 1 only. Any generation exceeding Leg 1&#39;s simultaneous load ($0.5 \times \text{Grid Demand}$) cannot cross phases and flows back to the utility grid uncredited. As a result, the maximum possible power offset is limited to 50% of Grid Demand:&#xA;&#xA;$$\text{Grid Draw} = \max(0, 0.5 \times \text{Grid Demand} - \text{Solar AC}) + 0.5 \times \text{Grid Demand}$$&#xA;&#xA;Solar + Battery Configuration: A 2.0 kWh modular LiFePO₄ battery buffers excess generation on Leg 1 before it reaches the main service panel, eliminating single-phase export losses and discharging to offset aggregate household demand over time:&#xA;&#xA;$$\text{Grid Draw} = \text{Grid Demand} - (\text{Solar AC} \times \text{Battery Efficiency})$$&#xA;&#xA;Tags: #Solar #PlugIn #Balcony #BatteryStorage #Modeling]]&gt;</description>
      <content:encoded><![CDATA[<p>To evaluate the true financial returns of plug-in solar and battery storage, generalized assumptions must be replaced with high-resolution empirical data. Minute-by-minute data would enable excellent modeling, however this requires specialized equipment installed in the breaker box and a dedicated data capture system. Fortunately, most utilities offer 30-minute utility meter interval readings you can download from your account. With this data , plus past bills, meteorological data, and a physics-based photovoltaic (PV) simulation, I was able to create an excellent model of the actual utility power offset and the projected impact to my bill.</p>

<h4 id="1-data-extraction-navigating-utility-export-limitations">1. Data Extraction: Navigating Utility Export Limitations</h4>

<p>The utility industry established the Green Button Energy Service Provider Interface (ESPI) XML standard to allow consumers to download energy usage data. However, data collection from my utility revealed two critical limitations in Green Button XML exports:</p>
<ul><li><strong>UI Restrictions &amp; Date Limits:</strong> The customer portal&#39;s XML export tool enforces a restriction limiting downloads strictly to the trailing 13 months, blocking access to historical multi-year data.<br/></li>
<li><strong>Low Data Precision:</strong> Green Button XML exports round consumption readings to whole integer kilowatt-hours (1 kWh resolution), obscuring subtle household power dynamics.</li></ul>

<p>To overcome this, I chose to build my data pipeline using my utility’s “Download Detailed Data” Excel (<code>.xlsx</code>) export option. This format provides continuous 30-minute interval readings at three decimal places of precision (0.001 kWh). An automated Python ETL script parses these workbooks, aligns intervals chronologically, and ingests them into a local DuckDB time-series database. </p>

<h4 id="2-bill-parsing-tariff-structure-regression">2. Bill Parsing &amp; Tariff Structure Regression</h4>

<p>Standard solar calculators assume an average flat electricity rate, but real utility tariffs consist of complex, multi-tiered line items. To model financial savings accurately, I created a Python script to extract the 21 meaningful line items from the monthly PDF bill statements. I used ordinary least squares (OLS) linear regressions with the data to classify fee behavior into three structural categories:</p>
<ol><li><p><strong>Strictly Proportional Charges:</strong> Generation, transmission, fuel, deferred fuel cost, sales/use surcharge, and state/local consumption taxes scale linearly down to zero with lower kWh usage.</p></li>

<li><p><strong>Partially Proportional Charges:</strong> Distribution service charges consist of a fixed monthly base customer fee of $11.23 plus a variable per-kWh rate.</p></li>

<li><p><strong>Capped Non-Proportional Charges:</strong> The local utility tax consists of a \$0.60 base fee plus a variable rate capped at a maximum of \$4.00/month.</p></li></ol>

<p>When solar generation reduces grid energy consumption, fixed customer base fees and tax caps remain untouched while variable supply and distribution rates scale down proportionally.</p>

<h4 id="3-satellite-solar-irradiance-performance-modeling">3. Satellite Solar Irradiance &amp; Performance Modeling</h4>

<p>Solar generation potential was derived using historical meteorological data retrieved from the <a href="https://open-meteo.com/">Open-Meteo</a> API for my county. The dataset provides 30-minute resolution Global Horizontal Irradiance (GHI), Direct Normal Irradiance (DNI), Diffuse Horizontal Irradiance (DHI), ambient temperature, and wind speed.</p>

<p>Photovoltaic DC output was calculated using the physics-based PVWatts DC model implemented via Python&#39;s <a href="https://pypi.org/project/pvlib/">pvlib library</a> (utilizing benchmarks established by my favorite National Lab - the National Laboratory of the Rockies, formerly NREL):</p>
<ul><li><strong>System DC Rating:</strong> 1,200, 1,300, 1,400, and 1,500 W<br/></li>
<li><strong>Array Orientation &amp; Tilt:</strong> Fixed South-facing (Azimuth \= 180°), 38.85° tilt angle (equal to site latitude)<br/></li>
<li><strong>Temperature Coefficient:</strong> -0.0047 / °C<br/></li>
<li><strong>Inverter Conversion Efficiency:</strong> 95.0% DC-to-AC<br/></li>
<li><strong>Battery Round-Trip Efficiency:</strong> 95.0%
<br/></li></ul>

<h4 id="4-interval-simulation-split-phase-logic">4. Interval Simulation &amp; Split-Phase Logic</h4>

<p>For each 30-minute block, AC solar generation is calculated:</p>

<p>$$\text{Solar AC (kWh)} = \left(\frac{\text{DC Power (W)} \times 0.5\text{ hrs}}{1000}\right) \times \text{Inverter Efficiency}$$
Net grid energy draw is then evaluated under an assumed 50/50 split-phase load across two 120 V legs (while this is not an ideal assumption, it’s the the best approximation I can make given the data I have available):</p>
<ul><li>Solar-Only Configuration (Single-Phase Injection): Solar offsets Leg 1 only. Any generation exceeding Leg 1&#39;s simultaneous load ($0.5 \times \text{Grid Demand}$) cannot cross phases and flows back to the utility grid uncredited. As a result, the maximum possible power offset is limited to 50% of Grid Demand:</li></ul>

<p>$$\text{Grid Draw} = \max(0, 0.5 \times \text{Grid Demand} – \text{Solar AC}) + 0.5 \times \text{Grid Demand}$$</p>
<ul><li>Solar + Battery Configuration: A 2.0 kWh modular LiFePO₄ battery buffers excess generation on Leg 1 before it reaches the main service panel, eliminating single-phase export losses and discharging to offset aggregate household demand over time:</li></ul>

<p>$$\text{Grid Draw} = \text{Grid Demand} – (\text{Solar AC} \times \text{Battery Efficiency})$$</p>

<p><strong>Tags:</strong> <a href="https://solar-ledger.blog/tag:Solar" class="hashtag"><span>#</span><span class="p-category">Solar</span></a> <a href="https://solar-ledger.blog/tag:PlugIn" class="hashtag"><span>#</span><span class="p-category">PlugIn</span></a> <a href="https://solar-ledger.blog/tag:Balcony" class="hashtag"><span>#</span><span class="p-category">Balcony</span></a> <a href="https://solar-ledger.blog/tag:BatteryStorage" class="hashtag"><span>#</span><span class="p-category">BatteryStorage</span></a> <a href="https://solar-ledger.blog/tag:Modeling" class="hashtag"><span>#</span><span class="p-category">Modeling</span></a></p>
]]></content:encoded>
      <guid>https://solar-ledger.blog/plug-in-solar-building-an-open-data-pipeline-and-cost-impact-modeling</guid>
      <pubDate>Sun, 13 Sep 2026 15:58:29 +0000</pubDate>
    </item>
  </channel>
</rss>