{"id":25854771,"url":"https://github.com/jchristopherson/spectrum","last_synced_at":"2026-02-02T07:01:56.869Z","repository":{"id":166008616,"uuid":"614052732","full_name":"jchristopherson/spectrum","owner":"jchristopherson","description":"Spectrum is a library containing signal analysis routines.","archived":false,"fork":false,"pushed_at":"2025-01-22T20:14:24.000Z","size":3140,"stargazers_count":2,"open_issues_count":1,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-06-04T06:16:22.286Z","etag":null,"topics":["cross-spectral-density","filter","filtering","fir-filter","fortran","gaussian-filter","iir-filters","numerical-differentiation","periodogram","power-spectral-density","psd","total-variation-filter","total-variation-regularization","transfer-function"],"latest_commit_sha":null,"homepage":"","language":"Fortran","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jchristopherson.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2023-03-14T19:48:47.000Z","updated_at":"2025-05-16T16:23:08.000Z","dependencies_parsed_at":null,"dependency_job_id":"d14db629-67ae-46c2-9dde-895203dbb7b0","html_url":"https://github.com/jchristopherson/spectrum","commit_stats":{"total_commits":99,"total_committers":1,"mean_commits":99.0,"dds":0.0,"last_synced_commit":"1c4ad2142ecff8dd6d1fb5346f02daf6a0228e9e"},"previous_names":[],"tags_count":7,"template":false,"template_full_name":null,"purl":"pkg:github/jchristopherson/spectrum","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jchristopherson%2Fspectrum","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jchristopherson%2Fspectrum/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jchristopherson%2Fspectrum/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jchristopherson%2Fspectrum/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jchristopherson","download_url":"https://codeload.github.com/jchristopherson/spectrum/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jchristopherson%2Fspectrum/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":262407351,"owners_count":23306355,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cross-spectral-density","filter","filtering","fir-filter","fortran","gaussian-filter","iir-filters","numerical-differentiation","periodogram","power-spectral-density","psd","total-variation-filter","total-variation-regularization","transfer-function"],"created_at":"2025-03-01T16:18:05.801Z","updated_at":"2026-02-02T07:01:56.862Z","avatar_url":"https://github.com/jchristopherson.png","language":"Fortran","readme":"# spectrum\nSpectrum is a library containing signal analysis routines with a focus towards spectral routines.\n\n## Status\n[![CMake](https://github.com/jchristopherson/spectrum/actions/workflows/cmake.yml/badge.svg)](https://github.com/jchristopherson/spectrum/actions/workflows/cmake.yml)\n[![Actions Status](https://github.com/jchristopherson/spectrum/workflows/fpm/badge.svg)](https://github.com/jchristopherson/spectrum/actions)\n\n## Available Operations\n- Spectral Estimators (power spectral density, cross spectral density, etc.)\n- Short Time Fourier Transform (STFT)\n- Windowing\n- Convolution\n- Offset Removal (Mean Removal)\n- Filtering\n    - Low-Pass, High-Pass, Band-Pass, \u0026 Band-Stop\n    - Total Variation\n    - Gaussian\n    - Moving Average\n- Upsampling \u0026 Downsampling\n- Transfer Function Estimation\n- Differentiation \u0026 Integration\n\n## Documentation\nThe documentation can be found [here](https://jchristopherson.github.io/spectrum/).\n\n## Building Spectrum\n[CMake](https://cmake.org/)This library can be built using CMake.  For instructions see [Running CMake](https://cmake.org/runningcmake/).\n\n[FPM](https://github.com/fortran-lang/fpm) can also be used to build this library using the provided fpm.toml.\n```txt\nfpm build\n```\nThe SPECTRUM library can be used within your FPM project by adding the following to your fpm.toml file.\n```toml\n[dependencies]\nspectrum = { git = \"https://github.com/jchristopherson/spectrum\" }\n```\n\n## External Libraries\nThe SPECTRUM library depends upon the following libraries.\n- [FERROR](https://github.com/jchristopherson/ferror)\n- [BLAS](http://www.netlib.org/blas/)\n- [LAPACK](http://www.netlib.org/lapack/)\n- [LINALG](https://github.com/jchristopherson/linalg)\n\n## Examples\nSpectrum contains a large selection of signal processing routines.  The following examples illustrate some of the spectral capabilities in addition to some of the filtering options available.\n\n## Filtering \u0026 PSD Example\nThis example illustrates some available filtering options on a randomly generated signal by comparing the power spectrums of the unfiltered vs. filtered signals.  This example utilizes the [fplot](https://github.com/jchristopherson/fplot) library for plotting.\n```fortran\nprogram example\n    use iso_fortran_env\n    use spectrum\n    use fplot_core\n    implicit none\n\n    ! Parameters\n    integer(int32), parameter :: winsize = 1024\n    integer(int32), parameter :: n = 10000\n    real(real64), parameter :: fs = 1.0d3\n    real(real64), parameter :: fc1 = 1.0d2\n    real(real64), parameter :: fc2 = 3.0d2\n\n    ! Local Variables\n    integer(int32) :: i\n    real(real64) :: df, x(n), xlp(n), xhp(n), xbp(n), xbs(n)\n    real(real64), allocatable, dimension(:) :: freq, p, plp, php, pbp, pbs\n    type(hamming_window) :: win\n\n    ! Plot Variables\n    type(multiplot) :: freqPlot\n    type(plot_2d) :: plt, pltlp, plthp, pltbp, pltbs\n    class(terminal), pointer :: term\n    type(plot_data_2d) :: pd, pdlp, pdhp, pdbp, pdbs\n\n    ! Build the signal and remove the mean\n    call random_number(x)\n    x = remove_mean(x)\n\n    ! Filter the signals\n    xlp = sinc_filter(fc1, fs, x, ftype = LOW_PASS_FILTER)\n    xhp = sinc_filter(fc1, fs, x, ftype = HIGH_PASS_FILTER)\n    xbp = sinc_filter(fc1, fs, x, ftype = BAND_PASS_FILTER, fc2 = fc2)\n    xbs = sinc_filter(fc1, fs, x, ftype = BAND_STOP_FILTER, fc2 = fc2)\n\n    ! Compute PSD's\n    win%size = winsize\n    p = psd(win, x, fs = fs)\n    plp = psd(win, xlp, fs = fs)\n    php = psd(win, xhp, fs = fs)\n    pbp = psd(win, xbp, fs = fs)\n    pbs = psd(win, xbs, fs = fs)\n\n    ! Build a corresponding array of frequency values\n    df = frequency_bin_width(fs, winsize)\n    allocate(freq(size(p)))\n    freq = (/ (df * i, i = 0, size(p) - 1) /)\n\n    ! Create the plot\n    call freqPlot%initialize(5, 1)\n    call plt%initialize()\n    call pltlp%initialize()\n    call plthp%initialize()\n    call pltbp%initialize()\n    call pltbs%initialize()\n    term =\u003e freqPlot%get_terminal()\n    call term%set_window_height(900)\n    \n    call plt%set_title(\"Original Signal\")\n    call pltlp%set_title(\"Low Pass Filtered Signal\")\n    call plthp%set_title(\"High Pass Filtered Signal\")\n    call pltbp%set_title(\"Band Pass Filtered Signal\")\n    call pltbs%set_title(\"Band Stop Filtered Signal\")\n\n    call pd%define_data(freq, p)\n    call plt%push(pd)\n    call freqPlot%set(1, 1, plt)\n\n    call pdlp%define_data(freq, plp)\n    call pltlp%push(pdlp)\n    call freqPlot%set(2, 1, pltlp)\n\n    call pdhp%define_data(freq, php)\n    call plthp%push(pdhp)\n    call freqPlot%set(3, 1, plthp)\n\n    call pdbp%define_data(freq, pbp)\n    call pltbp%push(pdbp)\n    call freqPlot%set(4, 1, pltbp)\n\n    call pdbs%define_data(freq, pbs)\n    call pltbs%push(pdbs)\n    call freqPlot%set(5, 1, pltbs)\n\n    call freqPlot%draw()\nend program\n```\nThis example produces the following plot.\n\n![](images/filter_comparison.png?raw=true)\n\n## Transfer Function Example\nThis example illustrates the calculation of a single-input/single-output (SISO) transfer function from a signal stored in a CSV file.  This example utilizes the [fplot](https://github.com/jchristopherson/fplot) library for plotting and the [fortran-csv-module](https://github.com/jacobwilliams/fortran-csv-module) library for reading the CSV file.\n```fortran\nprogram example\n    use iso_fortran_env\n    use spectrum\n    use fplot_core\n    use csv_module\n    implicit none\n\n    ! Parameters\n    integer(int32), parameter :: winsize = 1024\n    integer(int32), parameter :: nxfrm = winsize / 2 + 1\n    real(real64), parameter :: pi = 2.0d0 * acos(0.0d0)\n    complex(real64), parameter :: j = (0.0d0, 1.0d0)\n    real(real64), parameter :: zeta = 1.0d-2\n    real(real64), parameter :: fn = 2.5d2\n    real(real64), parameter :: wn = 2.0d0 * pi * fn\n\n    ! Local Variables\n    logical :: ok\n    integer(int32) :: i\n    real(real64) :: dt, fs, df, freq(nxfrm)\n    real(real64), allocatable, dimension(:) :: t, x, y, mag, phase, maga, pa\n    complex(real64), allocatable, dimension(:) :: tf, s, tfa\n    type(hamming_window) :: win\n    type(csv_file) :: file\n\n    ! Plot Variables\n    type(multiplot) :: mplt\n    type(plot_2d) :: plt, plt1, plt2\n    type(plot_data_2d) :: pd, pda\n    class(plot_axis), pointer :: xAxis, yAxis\n    class(legend), pointer :: lgnd\n\n    ! Import time history data\n    call file%read(\"files/chirp.csv\", status_ok = ok)\n    call file%get(1, t, ok)\n    call file%get(2, y, ok)\n    call file%get(3, x, ok)\n\n    ! Determine the sample rate\n    dt = t(2) - t(1)\n    fs = 1.0d0 / dt\n    print 100, \"Sample Rate: \", fs, \" Hz\"\n\n    ! Compute the transfer function\n    win%size = winsize\n    tf = siso_transfer_function(win, y, x)\n\n    ! Compute the frequency, magnitude, and phase\n    df = frequency_bin_width(fs, winsize)\n    freq = (/ (df * i, i = 0, nxfrm - 1) /)\n    mag = 2.0d1 * log10(abs(tf))    ! Convert to dB\n    phase = atan2(aimag(tf), real(tf))\n    call unwrap(phase, pi / 2.0d0)\n\n    ! Compare to the analytical solution\n    s = j * (2.0d0 * pi * freq)\n    tfa = (2.0d0 * zeta * wn * s + wn**2) / \u0026\n        (s**2 + 2.0d0 * zeta * wn * s + wn**2)\n    maga = 2.0d1 * log10(abs(tfa))\n    pa = atan2(aimag(tfa), real(tfa))\n    call unwrap(phase, pi / 2.0d0)\n\n    ! Set up the plot objects\n    call plt%initialize()\n    xAxis =\u003e plt%get_x_axis()\n    yAxis =\u003e plt%get_y_axis()\n\n    ! Plot the time signal\n    call xAxis%set_title(\"t\")\n    call yAxis%set_title(\"x(t)\")\n\n    call pd%define_data(t, x)\n    call pd%set_line_width(2.0)\n    call plt%push(pd)\n    call plt%draw()\n\n    ! Plot the transfer function\n    call mplt%initialize(2, 1)\n    call plt1%initialize()\n    call plt2%initialize()\n\n    ! Plot the magnitude component\n    xAxis =\u003e plt1%get_x_axis()\n    yAxis =\u003e plt1%get_y_axis()\n    lgnd =\u003e plt1%get_legend()\n    call xAxis%set_title(\"f [Hz]\")\n    call xAxis%set_autoscale(.false.)\n    call xAxis%set_limits(0.0d0, 5.0d2)\n    call yAxis%set_title(\"|X / Y| [dB]\")\n    call lgnd%set_is_visible(.true.)\n\n    call pd%define_data(freq, mag)\n    call pd%set_name(\"Computed\")\n    call plt1%push(pd)\n\n    call pda%define_data(freq, maga)\n    call pda%set_name(\"Analytical\")\n    call pda%set_line_style(LINE_DASHED)\n    call pda%set_line_width(2.5)\n    call plt1%push(pda)\n\n    ! Plot the phase component\n    xAxis =\u003e plt2%get_x_axis()\n    yAxis =\u003e plt2%get_y_axis()\n    call xAxis%set_title(\"f [Hz]\")\n    call xAxis%set_autoscale(.false.)\n    call xAxis%set_limits(0.0d0, 5.0d2)\n    call yAxis%set_title(\"{/Symbol f} [deg]\")\n\n    call pd%define_data(freq, phase * 1.8d2 / pi)\n    call plt2%push(pd)\n\n    call pda%define_data(freq, pa * 1.8d2 / pi)\n    call plt2%push(pda)\n\n    call mplt%set(1, 1, plt1)\n    call mplt%set(2, 1, plt2)\n    call mplt%draw()\n\n    ! Formatting\n100 format(A, F6.1, A)\nend program\n```\nThis example produces the following plots.\n\n![](images/siso_tf_example_time_history.png?raw=true)\n![](images/siso_tf_example_bode.png?raw=true)\n\n## STFT Example\nThis example illustrates the STFT capabilities.\n```fortran\nprogram example\n    use iso_fortran_env\n    use spectrum\n    use fplot_core\n    implicit none\n\n    ! Parameters\n    integer(int32), parameter :: window_size = 512\n    real(real64), parameter :: fs = 2048.0d0\n    real(real64), parameter :: f0 = 1.0d2\n    real(real64), parameter :: f1 = 1.0d3\n    real(real64), parameter :: duration = 50.0d0\n    real(real64), parameter :: pi = 2.0d0 * acos(0.0d0)\n\n    ! Local Variables\n    integer(int32) :: i, npts\n    integer(int32), allocatable, dimension(:) :: offsets\n    real(real64) :: k, df\n    complex(real64), allocatable, dimension(:,:) :: rst\n    real(real64), allocatable, dimension(:) :: t, x, f, s\n    real(real64), allocatable, dimension(:,:) :: mag\n    real(real64), allocatable, dimension(:,:,:) :: xy\n    type(hann_window) :: win\n    type(stft_result) :: z\n\n    ! Plot Variables\n    type(surface_plot) :: plt\n    type(surface_plot_data) :: pd\n    class(plot_axis), pointer :: xAxis, yAxis\n    type(rainbow_colormap) :: map\n\n    ! Create the exponential chirp signal\n    npts = floor(duration * fs) + 1\n    t = linspace(0.0d0, duration, npts)\n    k = (f1 / f0)**(1.0 / duration)\n    x = sin(2.0d0 * pi * f0 * (k**t - 1.0d0) / log(k))\n\n    ! Determine sampling frequency parameters\n    df = frequency_bin_width(fs, window_size)\n\n    ! Define the window\n    win%size = window_size\n\n    ! Compute the spectrogram of x\n    z = stft(win, x)\n    rst = z%stft\n    offsets = z%offsets\n\n    ! Compute the magnitude, along with each frequency and time point\n    mag = abs(rst)\n\n    allocate(f(size(mag, 1)))\n    f = (/ (df * i, i = 0, size(f) - 1) /)\n\n    allocate(s(size(mag, 2)))\n    do i = 1, size(s)\n        if (i == 1) then\n            s(i) = offsets(i) / fs\n        else\n            s(i) = i * (offsets(i) - offsets(i-1)) / fs\n        end if\n    end do\n    xy = meshgrid(s, f)\n\n    ! Plot the results\n    call plt%initialize()\n    call plt%set_colormap(map)\n    call plt%set_use_map_view(.true.)\n    xAxis =\u003e plt%get_x_axis()\n    yAxis =\u003e plt%get_y_axis()\n\n    call xAxis%set_title(\"Time [s]\")\n    call yAxis%set_title(\"Frequency [Hz]\")\n    call yAxis%set_autoscale(.false.)\n    call yAxis%set_limits(0.0d0, f(size(mag, 1)))\n    \n    call pd%define_data(xy(:,:,1), xy(:,:,2), mag)\n    call plt%push(pd)\n    call plt%draw()\nend program\n```\nThis example produces the following plot.\n\n![](images/spectrogram_example_1.png?raw=true)\n\n## References\n1. Welch, P.D. (1967). The Use of Fast Fourier Transform for the Estimation of Power Spectra: A Method Based on Time Averaging Over Short, Modified Periodograms. IEEE Transactions on Audio and Electroacoustics, AU-15 (2): 70-73.\n2. Stoica, Petre, and Randolph Moses. Spectral Analysis of Signals. Upper Saddle River, NJ: Prentice Hall, 2005.\n3. William H. Press, Saul A. Teukolsky, William T. Vetterling, and Brian P. Flannery. 2007. Numerical Recipes 3rd Edition: The Art of Scientific Computing (3rd. ed.). Cambridge University Press, USA.\n4. Millioz, Fabien \u0026 Martin, Nadine. (2011). Circularity of the STFT and Spectral Kurtosis for Time-Frequency Segmentation in Gaussian Environment. Signal Processing, IEEE Transactions on. 59. 515 - 524. 10.1109/TSP.2010.2081986. \n5. Wikipedia Contributors. (2022, February 9). Welch’s method. Wikipedia; Wikimedia Foundation. https://en.wikipedia.org/wiki/Welch%27s_method\n6. Spectral density. (2023, April 9). Wikipedia. https://en.wikipedia.org/wiki/Spectral_density#Cross-spectral_density\n7. Wikipedia Contributors. (2019, April 12). Short-time Fourier transform. Wikipedia; Wikimedia Foundation. https://en.wikipedia.org/wiki/Short-time_Fourier_transform\n8. Window function. (2020, December 12). Wikipedia. https://en.wikipedia.org/wiki/Window_function\n9. Wikipedia Contributors. (2019, March 22). Gaussian filter. Wikipedia; Wikimedia Foundation. https://en.wikipedia.org/wiki/Gaussian_filter\n10. Selesnick Andilker Bayram, I. (2010). Total Variation Filtering. https://eeweb.engineering.nyu.edu/iselesni/lecture_notes/TV_filtering.pdf\n11. Unavane, T., \u0026 Panse. (2015). New Method for Online Frequency Response Function Estimation Using Circular Queue. INTERNATIONAL JOURNAL for RESEARCH in EMERGING SCIENCE and TECHNOLOGY, 2. https://ijrest.net/downloads/volume-2/issue-6/pid-ijrest-26201530.pdf\n\n‌","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjchristopherson%2Fspectrum","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjchristopherson%2Fspectrum","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjchristopherson%2Fspectrum/lists"}