diff --git a/src/crop/aquacrop.jl b/src/crop/aquacrop.jl
index ba18b485137e45a6b4f3b027e6285a5d5a8f8734..1bcbd985b2baed87ea294d28cfb2def2bbac4142 100644
--- a/src/crop/aquacrop.jl
+++ b/src/crop/aquacrop.jl
@@ -5,9 +5,11 @@ module AquaCropWrapper
 const CROPFILE = "crop_data.csv"
 
 import AquaCrop
+using AquaCrop: ton
 import CSV
 using Dates: Date
 using DataFrames: DataFrame
+using Unitful: @u_str
 
 using Persefone:
     AbstractCropState,
@@ -183,7 +185,13 @@ end
 
 croptype(cs::CropState) = cs.croptype
 cropname(cs::CropState) = cropname(croptype(cs))
-cropheight(cs::CropState) = cs.height  # TODO: calculate from AquaCrop state info
+function cropheight(cs::CropState)
+    biomass = get_aquacrop_biomass(cs)
+    # TODO: linear model, fixed params
+    a = 20cm
+    b = 18u"cm * ha" / ton
+    return a + b * biomass
+end
 cropcover(cs::CropState) = AquaCrop.canopycover(cs.cropstate)
 cropyield(cs::CropState) = AquaCrop.dryyield(cs.cropstate)  # TODO: there is also freshyield
 function isharvestable(cs::CropState)
@@ -204,6 +212,11 @@ function get_aquacrop_stage(cs::CropState)
     length(stages) > 0 ? last(stages) : missing
 end
 
+function get_aquacrop_biomass(cs::CropState)
+    biomasses = cs.cropstate.dayout.Biomass
+    length(biomasses) > 0 ? last(biomasses) : missing
+end
+
 """
     stepagent!(cropstate, model)
 
diff --git a/test/crop_tests.jl b/test/crop_tests.jl
index f35ec56dd592b57c26db65d2198d7b9d3259866d..d7b79fbb6c0ee99cc0afc8a74ca777651eba2b46 100644
--- a/test/crop_tests.jl
+++ b/test/crop_tests.jl
@@ -70,7 +70,9 @@ end
     @test fp.cropstate isa PsAC.CropState
     @test croptype(fp) isa PsAC.CropType
     @test cropname(fp) isa String
-    @test cropheight(fp) isa Length{Float64}
+    # TODO: better testing for cropheight
+    ch = cropheight(fp)
+    @test ismissing(ch) || Unitful.dimension(ch) == Unitful.𝐋
     @test cropcover(fp) isa Float64
     @test Unitful.dimension(cropyield(fp)) == Unitful.𝐌 * Unitful.𝐋^-2
 end