%23%20%2F%2F%2F%20script%0A%23%20requires-python%20%3D%20%22%3E%3D3.11%22%0A%23%20dependencies%20%3D%20%5B%0A%23%20%20%20%20%20%22yohou%5Bplotting%5D%22%2C%0A%23%20%5D%0A%23%20%2F%2F%2F%0A%0Aimport%20marimo%0A%0A__generated_with%20%3D%20%220.23.14%22%0Aapp%20%3D%20marimo.App(width%3D%22medium%22)%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_()%3A%0A%20%20%20%20import%20marimo%20as%20mo%0A%0A%20%20%20%20return%20(mo%2C)%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_()%3A%0A%0A%20%20%20%20from%20yohou.datasets%20import%20fetch_electricity_demand%0A%20%20%20%20from%20yohou.plotting%20import%20plot_phase%2C%20plot_spectrum%2C%20plot_time_series%0A%20%20%20%20from%20yohou.preprocessing%20import%20NumericalFilter%0A%0A%20%20%20%20return%20(%0A%20%20%20%20%20%20%20%20NumericalFilter%2C%0A%20%20%20%20%20%20%20%20fetch_electricity_demand%2C%0A%20%20%20%20%20%20%20%20plot_phase%2C%0A%20%20%20%20%20%20%20%20plot_spectrum%2C%0A%20%20%20%20%20%20%20%20plot_time_series%2C%0A%20%20%20%20)%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%20Signal%20Processing%0A%0A%20%20%20%20This%20notebook%20shows%20how%20to%20apply%20Butterworth%20low-pass%20filtering%20with%20frequency%20spectrum%20analysis%20and%20phase%20shift%20inspection%20on%20half-hourly%20electricity%20demand%20data%20using%20Plotly.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(fetch_electricity_demand)%3A%0A%20%20%20%20vic%20%3D%20fetch_electricity_demand().frame%0A%20%20%20%20%23%20Take%2030%20days%20(1440%20half-hours)%20for%20readable%20plots%0A%20%20%20%20vic_short%20%3D%20vic.head(1440)%0A%20%20%20%20return%20(vic_short%2C)%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%201.%20Raw%20Demand%20Signal%0A%0A%20%20%20%20%5B%60plot_time_series%60%5D(%2Fpages%2Fapi%2Fgenerated%2Fyohou.plotting.exploration.plot_time_series%2F)%20renders%20the%20raw%20demand%20values%20against%20the%20time%20axis.%0A%20%20%20%20The%2030-day%20window%20shows%20a%20clear%20daily%20cycle%20(period%20of%20approximately%0A%20%20%20%2048%20half-hour%20samples)%20plus%20short-term%20noise%20that%20the%20filter%20will%20remove.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(plot_time_series%2C%20vic_short)%3A%0A%20%20%20%20plot_time_series(%0A%20%20%20%20%20%20%20%20vic_short%2C%0A%20%20%20%20%20%20%20%20columns%3D%22vic__demand%22%2C%0A%20%20%20%20%20%20%20%20title%3D%22Raw%20Demand%20-%2030-day%20Window%22%2C%0A%20%20%20%20)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%202.%20Applying%20a%20Low-Pass%20Filter%0A%0A%20%20%20%20%5B%60NumericalFilter%60%5D(%2Fpages%2Fapi%2Fgenerated%2Fyohou.preprocessing.signal.NumericalFilter%2F)%20applies%20causal%20IIR%20filters%20to%20polars%20DataFrames.%0A%20%20%20%20Here%20a%20**4th-order%20Butterworth**%20low-pass%20filter%20with%20%60cutoff_frequency%3D0.05%60%0A%20%20%20%20(relative%20to%20Nyquist)%20keeps%20only%20the%20slowest%20oscillations%2C%20roughly%0A%20%20%20%20the%20daily%20cycle%2C%20and%20removes%20everything%20faster.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(NumericalFilter%2C%20vic_short)%3A%0A%20%20%20%20lowpass%20%3D%20NumericalFilter(%0A%20%20%20%20%20%20%20%20design%3D%22butterworth%22%2C%0A%20%20%20%20%20%20%20%20mode%3D%22lowpass%22%2C%0A%20%20%20%20%20%20%20%20order%3D1%2C%0A%20%20%20%20%20%20%20%20cutoff_frequency%3D0.05%2C%0A%20%20%20%20)%0A%20%20%20%20temp_df%20%3D%20vic_short.select(%22time%22%2C%20%22vic__demand%22)%0A%20%20%20%20lowpass.fit(temp_df)%0A%20%20%20%20temp_filtered%20%3D%20lowpass.transform(temp_df)%0A%20%20%20%20%23%20Combine%20raw%20and%20filtered%20for%20side-by-side%20comparison%0A%20%20%20%20combined%20%3D%20temp_df.rename(%7B%22vic__demand%22%3A%20%22Raw%22%7D).join(%0A%20%20%20%20%20%20%20%20temp_filtered.rename(%7B%22vic__demand%22%3A%20%22Filtered%22%7D)%2C%0A%20%20%20%20%20%20%20%20on%3D%22time%22%2C%0A%20%20%20%20)%0A%20%20%20%20return%20combined%2C%20temp_df%2C%20temp_filtered%0A%0A%0A%40app.cell%0Adef%20_(combined%2C%20plot_time_series)%3A%0A%20%20%20%20plot_time_series(%0A%20%20%20%20%20%20%20%20combined%2C%0A%20%20%20%20%20%20%20%20columns%3D%5B%22Raw%22%2C%20%22Filtered%22%5D%2C%0A%20%20%20%20%20%20%20%20title%3D%22Demand%20-%20Raw%20vs.%20Low-Pass%20Filtered%22%2C%0A%20%20%20%20)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%203.%20Power%20Spectrum%20Comparison%0A%0A%20%20%20%20%5B%60plot_spectrum%60%5D(%2Fpages%2Fapi%2Fgenerated%2Fyohou.plotting.signal.plot_spectrum%2F)%20computes%20the%20one-sided%20power%20spectral%20density%20via%20FFT.%0A%20%20%20%20The%20raw%20signal%20shows%20energy%20at%20many%20frequencies%3B%20after%20filtering%2C%20only%20the%0A%20%20%20%20low-frequency%20band%20retains%20power.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(plot_spectrum%2C%20temp_df)%3A%0A%20%20%20%20plot_spectrum(%0A%20%20%20%20%20%20%20%20temp_df%2C%0A%20%20%20%20%20%20%20%20columns%3D%22vic__demand%22%2C%0A%20%20%20%20%20%20%20%20title%3D%22Power%20Spectrum%20-%20Raw%20Demand%22%2C%0A%20%20%20%20)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(plot_spectrum%2C%20temp_filtered)%3A%0A%20%20%20%20plot_spectrum(%0A%20%20%20%20%20%20%20%20temp_filtered%2C%0A%20%20%20%20%20%20%20%20columns%3D%22vic__demand%22%2C%0A%20%20%20%20%20%20%20%20title%3D%22Power%20Spectrum%20-%20After%20Low-Pass%20Filter%22%2C%0A%20%20%20%20)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(plot_spectrum%2C%20temp_df)%3A%0A%20%20%20%20plot_spectrum(%0A%20%20%20%20%20%20%20%20temp_df%2C%0A%20%20%20%20%20%20%20%20columns%3D%22vic__demand%22%2C%0A%20%20%20%20%20%20%20%20log_scale%3DTrue%2C%0A%20%20%20%20%20%20%20%20title%3D%22Power%20Spectrum%20-%20Raw%20(Log%20Scale)%22%2C%0A%20%20%20%20)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(plot_spectrum%2C%20temp_filtered)%3A%0A%20%20%20%20plot_spectrum(%0A%20%20%20%20%20%20%20%20temp_filtered%2C%0A%20%20%20%20%20%20%20%20columns%3D%22vic__demand%22%2C%0A%20%20%20%20%20%20%20%20log_scale%3DTrue%2C%0A%20%20%20%20%20%20%20%20title%3D%22Power%20Spectrum%20-%20Filtered%20(Log%20Scale)%22%2C%0A%20%20%20%20)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%204.%20Phase%20Plot%20Comparison%0A%0A%20%20%20%20The%20**phase**%20angle%20at%20each%20frequency%20reveals%20the%20signal's%20timing%0A%20%20%20%20structure.%20%60unwrap%3DTrue%60%20(default)%20produces%20continuous%20phase%3B%0A%20%20%20%20%60angle_unit%3D%22degree%22%60%20converts%20from%20radians.%20Notice%20how%20the%20filter%0A%20%20%20%20shifts%20the%20phase%20at%20higher%20frequencies%20that%20are%20attenuated.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(plot_phase%2C%20temp_df)%3A%0A%20%20%20%20plot_phase(%0A%20%20%20%20%20%20%20%20temp_df%2C%0A%20%20%20%20%20%20%20%20columns%3D%22vic__demand%22%2C%0A%20%20%20%20%20%20%20%20title%3D%22Phase%20-%20Raw%20Demand%22%2C%0A%20%20%20%20)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(plot_phase%2C%20temp_filtered)%3A%0A%20%20%20%20plot_phase(%0A%20%20%20%20%20%20%20%20temp_filtered%2C%0A%20%20%20%20%20%20%20%20columns%3D%22vic__demand%22%2C%0A%20%20%20%20%20%20%20%20title%3D%22Phase%20-%20After%20Low-Pass%20Filter%22%2C%0A%20%20%20%20)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(plot_phase%2C%20temp_df)%3A%0A%20%20%20%20plot_phase(%0A%20%20%20%20%20%20%20%20temp_df%2C%0A%20%20%20%20%20%20%20%20columns%3D%22vic__demand%22%2C%0A%20%20%20%20%20%20%20%20angle_unit%3D%22degree%22%2C%0A%20%20%20%20%20%20%20%20title%3D%22Phase%20-%20Raw%20(Degrees)%22%2C%0A%20%20%20%20)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(plot_phase%2C%20temp_filtered)%3A%0A%20%20%20%20plot_phase(%0A%20%20%20%20%20%20%20%20temp_filtered%2C%0A%20%20%20%20%20%20%20%20columns%3D%22vic__demand%22%2C%0A%20%20%20%20%20%20%20%20unwrap%3DFalse%2C%0A%20%20%20%20%20%20%20%20title%3D%22Phase%20-%20Filtered%20(Wrapped)%22%2C%0A%20%20%20%20)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(plot_phase%2C%20temp_df)%3A%0A%20%20%20%20plot_phase(%0A%20%20%20%20%20%20%20%20temp_df%2C%0A%20%20%20%20%20%20%20%20columns%3D%22vic__demand%22%2C%0A%20%20%20%20%20%20%20%20angle_unit%3D%22degree%22%2C%0A%20%20%20%20%20%20%20%20unwrap%3DFalse%2C%0A%20%20%20%20%20%20%20%20title%3D%22Phase%20-%20Raw%20(Wrapped%20Degrees)%22%2C%0A%20%20%20%20)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%205.%20Higher-Order%20and%20Bandpass%20Filters%0A%0A%20%20%20%20Changing%20the%20filter%20parameters%20lets%20you%20isolate%20different%20frequency%0A%20%20%20%20bands.%20A%20**bandpass**%20filter%20around%20the%20daily%20cycle%20(period%20%E2%89%88%2048%0A%20%20%20%20samples%20%E2%86%92%20normalised%20frequency%20%E2%89%88%200.04)%20extracts%20just%20that%0A%20%20%20%20component.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(NumericalFilter%2C%20plot_time_series%2C%20temp_df)%3A%0A%20%20%20%20bandpass%20%3D%20NumericalFilter(%0A%20%20%20%20%20%20%20%20design%3D%22butterworth%22%2C%0A%20%20%20%20%20%20%20%20mode%3D%22bandpass%22%2C%0A%20%20%20%20%20%20%20%20order%3D3%2C%0A%20%20%20%20%20%20%20%20cutoff_frequency%3D(0.03%2C%200.06)%2C%0A%20%20%20%20)%0A%20%20%20%20bandpass.fit(temp_df)%0A%20%20%20%20temp_bp%20%3D%20bandpass.transform(temp_df)%0A%20%20%20%20plot_time_series(%0A%20%20%20%20%20%20%20%20temp_bp%2C%0A%20%20%20%20%20%20%20%20columns%3D%22vic__demand%22%2C%0A%20%20%20%20%20%20%20%20title%3D%22Bandpass%20Filtered%20-%20Daily%20Cycle%20Extracted%22%2C%0A%20%20%20%20)%0A%20%20%20%20return%20(temp_bp%2C)%0A%0A%0A%40app.cell%0Adef%20_(plot_spectrum%2C%20temp_bp)%3A%0A%20%20%20%20plot_spectrum(%0A%20%20%20%20%20%20%20%20temp_bp%2C%0A%20%20%20%20%20%20%20%20columns%3D%22vic__demand%22%2C%0A%20%20%20%20%20%20%20%20log_scale%3DTrue%2C%0A%20%20%20%20%20%20%20%20title%3D%22Power%20Spectrum%20-%20Bandpass%20(Log%20Scale)%22%2C%0A%20%20%20%20)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%20Next%20Steps%0A%0A%20%20%20%20-%20%5BApply%20Signal%20Processing%5D(%2Fpages%2Fhow-to%2Fapply-signal-processing%2F)%20for%20the%20full%20guide%0A%20%20%20%20-%20%5BUse%20Preprocessing%20Transformers%5D(%2Fpages%2Fhow-to%2Fuse-preprocessing-transformers%2F)%20for%20related%20techniques%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20app.run()%0A
c1855d2e5b23a66649838d92076cb4bf