|
| 1 | +import pyCREST_Py_3 as cr |
| 2 | +import numpy as np |
| 3 | +import matplotlib.pyplot as plt |
| 4 | + |
| 5 | +def plot_powerfile(filename): |
| 6 | + """Read a power output file created by create_profiles and plot it. |
| 7 | +
|
| 8 | + The files generated by :func:`create_profiles` are named ``Pfile_<idstring>.dat`` |
| 9 | + where each row corresponds to one dwelling and contains 1440 minute values. |
| 10 | + This helper loads the file and displays the first profile as a simple line plot. |
| 11 | + """ |
| 12 | + # load the data (assumes integer or float values separated by whitespace) |
| 13 | + data = np.loadtxt(filename) |
| 14 | + if data.ndim == 1: |
| 15 | + profile = data |
| 16 | + else: |
| 17 | + profile = data[0] |
| 18 | + |
| 19 | + times = np.arange(len(profile)) / 60.0 # hours |
| 20 | + plt.figure() |
| 21 | + plt.plot(times, profile) |
| 22 | + plt.xlabel('Time (hours)') |
| 23 | + plt.ylabel('Active power demand') |
| 24 | + plt.title(f'Profile from {filename}') |
| 25 | + plt.grid(True) |
| 26 | + plt.show() |
| 27 | + |
| 28 | + |
| 29 | + |
| 30 | +def plot_occupancy_file(filename): |
| 31 | + """Plot an occupancy profile generated by :func:`create_profiles`. |
| 32 | +
|
| 33 | + The occupancy files are created as ``Occfile_<idstring>.dat`` and contain |
| 34 | + 144 ten-minute values for each dwelling representing the occupancy state. |
| 35 | + """ |
| 36 | + data = np.loadtxt(filename) |
| 37 | + # there may be a single row (1D) or multiple rows; use first profile |
| 38 | + if data.ndim == 1: |
| 39 | + profile = data |
| 40 | + else: |
| 41 | + profile = data[0] |
| 42 | + times = np.arange(len(profile)) * 10.0 / 60.0 # hours |
| 43 | + plt.figure() |
| 44 | + plt.plot(times, profile) |
| 45 | + plt.xlabel('Time (hours)') |
| 46 | + plt.ylabel('Occupancy state') |
| 47 | + plt.title(f'Occupancy from {filename}') |
| 48 | + plt.grid(True) |
| 49 | + plt.show() |
| 50 | + |
| 51 | + |
| 52 | +def plot_app_profiles(filename, appliance=None): |
| 53 | + """Plot one appliance's power profile from an AppProfiles file. |
| 54 | +
|
| 55 | + Each line of ``AppProfiles<idstring>.dat`` normally contains: |
| 56 | + ``<index> <P/Q> <name> <1440 values>``. The parser looks for the named |
| 57 | + appliance token and then interprets subsequent tokens as floats. If no |
| 58 | + *appliance* is specified, the first numeric profile encountered is used. |
| 59 | + """ |
| 60 | + lines = open(filename).read().strip().splitlines() |
| 61 | + selected = None |
| 62 | + for line in lines: |
| 63 | + tokens = line.split() |
| 64 | + if not tokens: |
| 65 | + continue |
| 66 | + # find the token that equals the requested appliance (or just the first name) |
| 67 | + if appliance is not None and appliance in tokens: |
| 68 | + idx = tokens.index(appliance) |
| 69 | + elif appliance is None and len(tokens) >= 3: |
| 70 | + # assume third token is name |
| 71 | + idx = 2 |
| 72 | + else: |
| 73 | + continue |
| 74 | + # collect floats after the name token |
| 75 | + vals = [] |
| 76 | + for tok in tokens[idx+1:]: |
| 77 | + try: |
| 78 | + vals.append(float(tok)) |
| 79 | + except ValueError: |
| 80 | + # stop at first non‑numeric (there may not be any) |
| 81 | + break |
| 82 | + if vals: |
| 83 | + name = tokens[idx] |
| 84 | + selected = (name, np.array(vals)) |
| 85 | + break |
| 86 | + if selected is None: |
| 87 | + print(f'no appliance profile found in {filename}') |
| 88 | + return |
| 89 | + name, profile = selected |
| 90 | + times = np.arange(len(profile)) / 60.0 # hours |
| 91 | + plt.figure() |
| 92 | + plt.plot(times, profile) |
| 93 | + plt.xlabel('Time (hours)') |
| 94 | + plt.ylabel(f'{name} power') |
| 95 | + plt.title(f'{name} profile from {filename}') |
| 96 | + plt.grid(True) |
| 97 | + plt.show() |
| 98 | + |
| 99 | + |
| 100 | +if __name__ == "__main__": |
| 101 | + # generate profiles and plot the active power demand |
| 102 | + n=1 |
| 103 | + month=1 |
| 104 | + daytype="weekday" |
| 105 | + cr.create_profiles(n=n,daytype=daytype,month=month) |
| 106 | + |
| 107 | + # construct filename matching create_profiles output and show it |
| 108 | + idstring = f"{n}x_month-{month}_daytype-{daytype}" |
| 109 | + power_filename = f"Pfile_{idstring}.dat" |
| 110 | + print(f"generated {power_filename}") |
| 111 | + # display the plot automatically (will open a window or save a PNG) |
| 112 | + try: |
| 113 | + plot_powerfile(power_filename) |
| 114 | + except Exception as e: |
| 115 | + print(f"plot failed: {e}, saving figure instead") |
| 116 | + # regenerate profile data and save to file |
| 117 | + import matplotlib.pyplot as _plt |
| 118 | + data = np.loadtxt(power_filename) |
| 119 | + times = np.arange(len(data)) / 60.0 |
| 120 | + _plt.figure() |
| 121 | + _plt.plot(times, data if data.ndim==1 else data[0]) |
| 122 | + _plt.savefig(power_filename.replace('.dat', '.png')) |
| 123 | + print(f"saved plot to {power_filename.replace('.dat', '.png')}") |
| 124 | + |
| 125 | + # also plot occupancy and one appliance profile |
| 126 | + occ_filename = f"Occfile_{idstring}.dat" |
| 127 | + try: |
| 128 | + plot_occupancy_file(occ_filename) |
| 129 | + except Exception as e: |
| 130 | + print(f"occupancy plot failed: {e}") |
| 131 | + app_filename = f"AppProfiles{idstring}.dat" |
| 132 | + try: |
| 133 | + plot_app_profiles(app_filename, appliance='LIGHTING') |
| 134 | + except Exception as e: |
| 135 | + print(f"appliance plot failed: {e}") |
| 136 | + |
0 commit comments